Speed up the drawing of a moving waveform

New to FreeBASIC? Post your questions here.
12val12newakk
Posts: 35
Joined: Nov 14, 2019 17:04

Speed up the drawing of a moving waveform

Post by 12val12newakk »

How to significantly speed up the drawing of a moving waveform,
in which new samples are displayed on the right and the oldest one is removed.

Code: Select all

sub Shift_buff  ()
   '   SCreen 21 
  '  Buff_back_Tenzo    shared  global array
  '  Buff_back_Opto     shared  global array
  '  Buff_back_Filter   shared  global array
  '  RX_UART(001)       shared  global 
  '  RX_UART(002)       shared  global  
  ' Out_filter          shared  global 
    dim as   short count 
    dim as   short Y_tenzo_new,Y_tenzo_old
    dim as   short Y_Opto_new,Y_Opto_old
    dim as   short Y_Filtr_new,Y_Filtr_old
    dim as   short Zero_pset
    
    Buff_back_Tenzo(1279)=600-Ky*(RX_UART(001)-2047)  '  <- input sample  right
    Buff_back_Opto (1279)=600-Ky*(RX_UART(002)-2047)  '  <- input sample  right
    Buff_back_Filter(1279)=600-Ky*(Out_filter-2047)   '  <- input sample  right

    ScreenLock()
         Line (0+Tshift,1023)-(1280+Tshift,190),0000,bf ' clear area 
         Y_tenzo_new=Buff_back_Tenzo(0) 
         Y_Opto_new =Buff_back_Opto (0)
         Y_Filtr_new=Buff_back_Filter(0)
       for  count =1  To 1279 
        Y_tenzo_old =  Y_tenzo_new
        Y_Opto_old  =  Y_Opto_new
        Y_Filtr_old =  Y_Filtr_new
         Buff_back_Tenzo (count-1)=Buff_back_Tenzo(count)
        Buff_back_Opto  (count-1)=Buff_back_Opto (count)    
        Buff_back_Filter  (count-1)= Buff_back_Filter(count) 
        Y_tenzo_new=Buff_back_Tenzo (count)  
        Y_Opto_new =Buff_back_Opto  (count)
        Y_Filtr_new=Buff_back_Filter(count) 
        line (count-1+Tshift,Y_tenzo_old)-(count+Tshift,Y_tenzo_new),14  
        line (count-1+Tshift, Y_Opto_old)-(count+Tshift, Y_Opto_new),11 
        line (count-1+Tshift, Y_Filtr_old)-(count+Tshift, Y_Filtr_new),10  
    next  
      Zero_pset=  600
      line (0,Zero_pset)-(1279,Zero_pset),4
     ScreenunLock()
      
 end sub  
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: Speed up the drawing of a moving waveform

Post by D.J.Peters »

Here with ScrollOnePixel(byval img as any ptr=0) you can scroll the current screen or any image by one pixel to the left.

All video and image modes are supported (1,2,4,8,15,16,24,32 bits per pixel)

scroll the active screen
ScrollOnePixel()

or any image
ScrollOnePixel(myBackground)

NOTE: if you will display wave forms in realtime like an oscilloscope you have to use one of my posted fast copy/scale stuff !
PutResize(dst,src)
viewtopic.php?p=216249

PutResize(dst,src,x,y,w,h)
viewtopic.php?p=216903

PutResize(dst,x,y,w,h,src,x,y,w,h)
viewtopic.php?p=216258

mirror:
viewtopic.php?t=27323
...

Joshy

Code: Select all

sub ScrollOnePixel(byval img as any ptr=0)
  dim as long w=any,h=any,bytes=any,pitch=any
  dim as any ptr Pixels
  dim as boolean mustLock=any
  if img=0 then
    Pixels = screenptr()
    if Pixels = 0 then exit sub
    mustLock = true
    screeninfo w,h,,bytes,pitch
  else
    if imageinfo(img,w,h,bytes,pitch,Pixels) then exit sub
    mustLock=false
  end if
  if mustLock then screenlock()
  select case as const bytes
  case 1 : dim as ubyte ptr pixel, row = Pixels : pitch shr=0
    for y as integer = 1 to h
      pixel=row
      for x as integer = 0 to w-2 : pixel[x]=pixel[x+1] : next
      row += pitch
    next          
  case 2 : dim as ushort ptr pixel, row = Pixels : pitch shr=1
      for y as integer = 1 to h
      pixel=row
      for x as integer = 0 to w-2 : pixel[x]=pixel[x+1] : next
      row += pitch
    next  
  case 4 : dim as ulong  ptr pixel, row = Pixels : pitch shr=2
    for y as integer = 1 to h
      pixel=row
      for x as integer = 0 to w-2 : pixel[x]=pixel[x+1] : next
      row += pitch
    next  
  end select
  if mustLock then screenunlock()
end sub
'
' test of ScrollOnePixel()
'
dim as single oldAmp=239,newAmp,w1,w2
screenres 640,480
while inkey()=""
  newAmp=239+sin(w1)*200+sin(w2)*50:w1+=0.01:w2+=0.1
  line (639,0)-step(0,479),1:pset(639,239),7
  line (638,oldAmp)-(639,newAmp),2
  oldAmp=newAmp
  ScrollOnePixel()
  sleep(1)
wend
12val12newakk
Posts: 35
Joined: Nov 14, 2019 17:04

Re: Speed up the drawing of a moving waveform

Post by 12val12newakk »

D.J.Peters Thank you this is what I need
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Speed up the drawing of a moving waveform

Post by dodicat »

Since trig functions are circular, you could do this with a moving image.
Once you get the plotting parameters you have it.
You would hardly notice when the image resets.

Code: Select all

Sub createimage(i As Ubyte Ptr,xres As Long,yres As Long)
      #define map(a,b,x,c,d) ((d)-(c))*((x)-(a))/((b)-(a))+(c)
      Dim As Double w1,w2
      Line i,(0,yres\2)-(xres*2,yres\2),7
      Do
            Var y=Sin(w1)*200+Sin(w2)*50: w1+=0.01:w2+=0.1
            Var ypos=map(-247.6318606562745,247.6318606562745 ,y,5,yres-5)'max and min circular range for w1 in[0,6.3]
            Var xpos=map(0,6.283,w1,0,xres)
            If w1=.01 Then Pset i,(xpos,ypos),3 Else Line i, -(xpos,ypos),3 
      Loop Until  w1>6.283*2
End Sub

Screenres 640,480
windowtitle "USE ARROW KEYS TO ALTER SPEED, ESC TO END."
Dim As Long xres,yres
Screeninfo xres,yres
Dim As any ptr im=Imagecreate(xres*2,yres,1)
createimage(im,xres,yres)
Dim As Single delta,k=1
Do
      delta-=k
      If delta<-xres Then delta=0
      Screenlock
      Put(delta,0),im,Pset
      Screenunlock
      Sleep 1
    If MultiKey(&h48) then k+=.05  'arrow up
    if multikey(&h50) then k-=.05  'arrow down
    if k<.2 then k=.2
Loop Until multikey(&h01)          'Esc
Imagedestroy im

 
12val12newakk
Posts: 35
Joined: Nov 14, 2019 17:04

Re: Speed up the drawing of a moving waveform

Post by 12val12newakk »

D.J.Peters
In subScrollOnePixel() Integer for 64bit Windows maybe -->long ?
Your sub works at the pixel level, but is it possible at the vertical line level? line(x) -> line(x-1) (DMA copy ?)
I need sub only for screen21 mode/
Last edited by 12val12newakk on Jul 21, 2022 6:38, edited 1 time in total.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: Speed up the drawing of a moving waveform

Post by D.J.Peters »

12val12newakk wrote: Jul 21, 2022 4:39In subScrollOnePixel() Integer for 64bit Windows maybe -->long ?
Do you talk about the for loop counters as integer ?
In this case NO integer is the native/fastes datasize of the CPU 32/64 bit !

Here are the shorter version with memcpy()

Joshy

Code: Select all

#include "crt.bi"
sub ScrollOnePixel(byval img as any ptr=0)
  dim as long w=any,h=any,bytes=any,pitch=any
  dim as ubyte ptr row
  dim as boolean mustLock
  if img=0 then
    row = screenptr() : if row = 0 then exit sub
    screeninfo w,h,,bytes,pitch : mustLock = true
  else
    if imageinfo(img,w,h,bytes,pitch,row) then exit sub
  end if
  if mustLock then screenlock()
  for y as integer = 1 to h : memcpy(row,row+1,pitch) : row += pitch : next  
  if mustLock then screenunlock()
end sub
'
' test of ScrollOnePixel()
'
dim as single oldAmp=239,newAmp,w1,w2
screenres 640,480
while inkey()=""
  newAmp=239+sin(w1)*200+sin(w2)*50:w1+=0.01:w2+=0.1
  line (639,0)-step(0,479),1:pset(639,239),7
  line (638,oldAmp)-(639,newAmp),2
  oldAmp=newAmp
  ScrollOnePixel()
  sleep(1)
wend
12val12newakk
Posts: 35
Joined: Nov 14, 2019 17:04

Re: Speed up the drawing of a moving waveform

Post by 12val12newakk »

You answered my new question before I wrote it ..cool
UEZ
Posts: 988
Joined: May 05, 2017 19:59
Location: Germany

Re: Speed up the drawing of a moving waveform

Post by UEZ »

Here another similar way:

Code: Select all

'Coded by UEZ
#Include "fbgfx.bi"
Using FB

#Define PixelSetScrn(_x, _y, colour)	*Cptr(Ulong Ptr, pScrn2 + (_y) * pitch + (_x) Shl 2) = (colour)
Const w = 1920 Shr 1, h = 1080 Shr 1, w2 = w Shr 1, h2 = h Shr 1, _t = 1 / 60
Screenres w, h, 32, 2, GFX_ALPHA_PRIMITIVES Or GFX_NO_SWITCH
Screenset 1, 0
Color &hFF, &hFF000000
Cls

Dim As Long pitch
Dim As Any Ptr pScrn2 = Screenptr()
ScreenInfo , , , , pitch
Dim As Ulong Ptr pScrn = Screenptr()
Dim As Double t = 0
Dim As Long x, y, yy1
Do
	PixelSetScrn(1, cInt(h2 + Sin(t) * 50), &hFFFFFFFF)
	For y = h - 1 To 0 Step -1
		yy1 = y * w
		For x = w - 2 To 0 Step -1
			pScrn[yy1 + x + 1] = pScrn[yy1 + x]
		Next
	Next
	t += _t
	Flip
	Sleep (1)
Loop Until Len(Inkey())
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Speed up the drawing of a moving waveform

Post by dodicat »

UEZ
For a more complicated trig function, something that requires a bit of cpu to draw it, because trig functions are circular on 2*pi, you should only need to draw one 360 degree cycle to an image and let the image flow past.
So, using the pixel exchange method in this thread, I tried it on an image.

Code: Select all


function Trigfn(x as double)as double 
    dim f as double
    for n as double=1 to 50 step 2
        f=f+sin(n*x)/n
    next n
    f=.5-(2/3.142)*f
    return f
end function

Sub createimage(i As Any Ptr,xres As Long,yres As Long,colour As Ulong=3,linecolour as ulong =7)
      #define map(a,b,x,c,d) ((d)-(c))*((x)-(a))/((b)-(a))+(c)
      Const pi2=8*Atn(1)
      Dim As Double max=-1e6,min=1e6
      For x As Double=0 To xres
            Var y=Trigfn(x)
            If max<y Then max=y
            If min>y Then min=y
      Next x
      Dim As Double st=.001, w1=-8*st
      Line i,(0,0)-(xres,yres),1,bf
      Line i,(0,yres\2)-(xres,yres\2),linecolour
      Do
            Var y=  Trigfn(w1) 
            Var ypos=map(min,max ,y,5,yres-5)
            Var xpos=map(0,pi2,w1,0,xres)
            If w1=-8*st Then Pset i,(xpos,ypos),colour Else Line i, -(xpos,ypos),colour
            w1+=st
      Loop Until  w1>pi2
End Sub

#macro Sweep(p,sz)
Scope
      Var f=p[32]
      For z As Long =33 To (sz)
            p[z-1]=p[z]
      Next z
      p[sz-1]=f
End Scope
#endmacro


Screenres 800,600,8
Dim As Long xres,yres,size
Screeninfo xres,yres
Dim As any Ptr i=Imagecreate(xres,yres,1)

Imageinfo i,,,,,,size

createimage(i,xres,yres)

Do
      Screenlock
      Sweep(cptr(ubyte ptr,i),size)
      Put(0,0),i,Pset
      Screenunlock
      Sleep 1
Loop Until Len(Inkey)
imagedestroy(i)


 
Can you notice an annoying thing near the little gap on the vertical(ish) bit of the square wave?
My sweep function seems to cycle OK, leaving the first 32 image header bytes intact.
VIZ:

Code: Select all


#macro Sweep(p,sz,start)
scope
      var f=p[start]
For z as long =start+1 To (sz)
    p[z-1]=p[z]
Next z
 p[sz-1]=f
end scope
#endmacro

dim as string g="(111111111111111111111111111111)"+"abcdefghijklmnopqrstuvwxyz"
do
      locate 5,5,0
print g
sweep(g,len(g),32)
sleep 200
loop until len(inkey)
 
UEZ
Posts: 988
Joined: May 05, 2017 19:59
Location: Germany

Re: Speed up the drawing of a moving waveform

Post by UEZ »

@dodicat: surely it is reasonable for recurring functions, like sine / cosine or your function, to draw them only once and only blit the bitmap accordingly or move the content, like your example. I was primarily concerned with scrolling and not efficiency, but in retrospect my example was very similar to DJ Peter's example.

Your example is approx. 1.25x faster than my example.
Can you notice an annoying thing near the little gap on the vertical(ish) bit of the square wave?
To be honest, no. :?
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Speed up the drawing of a moving waveform

Post by dodicat »

UEZ
I was trying to scroll an image by it's pointer with the Sweep macro, but it is not quite right.
Scrolling the screen by the same method (Sweep) is still not quite right.
Your code adjusted.

Code: Select all

'Coded by UEZ
#Include "fbgfx.bi"
Using FB

#Define PixelSetScrn(_x, _y, colour)	*Cptr(Ulong Ptr, pScrn2 + (_y) * pitch + (_x) Shl 2) = (colour)
const pi=4*atn(1)
const w = 360*pi, h = 1080 Shr 1, w2 = w Shr 1, h2 = h Shr 1, _t = 1 / 60

Screenres w, h, 32, 2, GFX_ALPHA_PRIMITIVES Or GFX_NO_SWITCH
Screenset 1, 0
Color &hFF, &hFF000000
Cls

Dim As Long pitch
Dim As Any Ptr pScrn2 = Screenptr()
ScreenInfo , , , , pitch
Dim As Ulong Ptr pScrn = Screenptr()
Dim As Double t = 0
Dim As Long x, y, yy1

#macro Sweep(p,sz,start)
scope
      var f=p[start]
For z as long =start+1 To (sz)
    p[z-1]=p[z]
Next z
 p[sz-1]=f
end scope
#endmacro

var size=h*pitch\4

Do
	PixelSetScrn(w, cInt(h2 + Sin(t) * 50), &hFFFFFFFF)
      
      sweep(pScrn,size,0)

	'For y = h - 1 To 0 Step -1
		'yy1 = y * w
		'For x = w - 2 To 0 Step -1
			'pScrn[yy1 + x + 1] = pScrn[yy1 + x]
		'Next
	'Next
	t += _t
	Flip
	Sleep (1)
Loop Until Len(Inkey()) 
UEZ
Posts: 988
Joined: May 05, 2017 19:59
Location: Germany

Re: Speed up the drawing of a moving waveform

Post by UEZ »

Here my version scrolling a bitmap image.

Code: Select all

'Coded by UEZ
#include "file.bi"
#Include "fbgfx.bi"
Using FB


#Define LZFX_H

#Ifndef NULL
    # define NULL				0
#Endif

/' Hashtable size (2**LZFX_HLOG entries) '/
#Ifndef LZFX_HLOG
    # define LZFX_HLOG			16
#Endif

/' Predefined errors. '/
#Define LZFX_ESIZE				-1      /' Output buffer too small '/
#Define LZFX_ECORRUPT			-2      /' Invalid Data For decompression '/
#Define LZFX_EARGS				-3      /' Arguments invalid (NULL) '/


#Define LZFX_HSIZE				(1 Shl (LZFX_HLOG))

/' Define the hash Function '/
#Define LZFX_FRST(p)			(((p[0]) Shl 8) Or p[1])
#Define LZFX_NEXT(v,p)			(((v) Shl 8) Or p[2])
#Define LZFX_IDX(h)				((( h Shr (3*8 - LZFX_HLOG)) - h ) And (LZFX_HSIZE - 1))

/' These cannot be changed, As they are related To the compressed Format. '/
#Define LZFX_MAX_LIT			(1 Shl 5)
#Define LZFX_MAX_OFF			(1 Shl 13)
#Define LZFX_MAX_REF			((1 Shl 8) + (1 Shl 3))

/' This macro To reproduce   !a    in c'/
#Define MY_NOT(value)			Iif ( value = 0, 1, 0 )

/'Get uncompressed size from compressed ibuf buffer '/
Private Function lzfx_getsize(Byval ibuf As Ubyte Ptr , Byval ilen As UInteger , Byref olen As UInteger) As Long
    If ( ibuf = NULL Or ilen = 0) Then 
        olen = 0
        Return LZFX_EARGS
    End If
    Dim As Ubyte Ptr ip = ibuf
    Dim As Ubyte Ptr in_end = ip + ilen
    Dim As UInteger tot_len = 0

    While(ip < in_end)
        Dim As UInteger ctrl = *ip
        ip += 1
        If (ctrl < (1 Shl 5)) Then
            ctrl += 1
            If (ip + ctrl > in_end) Then Return LZFX_ECORRUPT
            tot_len += ctrl
            ip += ctrl
        Else
            Dim As UInteger len1 = (ctrl Shr 5)
            If(len1=7) Then    /' i.e. Format #2 '/
                len1 += *ip
                ip += 1
            End If
            len1 += 2    /' Len Is Now #octets '/
            If (ip >= in_end) Then Return LZFX_ECORRUPT
            ip+=1 /' skip the ref Byte '/
            tot_len += len1
        End If
    Wend
    olen = tot_len
    Return 0
End Function

Private Function lzfx_decompress(Byval ibuf As Ubyte Ptr , Byval ilen As UInteger , Byval obuf As Ubyte Ptr , Byref olen As UInteger) As Long
    Dim As Ubyte Ptr ip = ibuf
    Dim As Ubyte Ptr in_end = ip + ilen
    Dim As Ubyte Ptr op = obuf
    Dim As Ubyte Ptr out_end = op + olen
    Dim As UInteger remain_len = 0
    Dim As Long rc

    If(olen = 0) Then Return LZFX_EARGS
    If(ibuf = NULL) Then
        If(ilen <> 0) Then Return LZFX_EARGS
        olen = 0
        Return 0
    End If
    If(obuf = NULL)Then
        If(olen <> 0) Then Return LZFX_EARGS
        Return lzfx_getsize(ibuf, ilen, olen)
    End If
    #Macro my_guess()   'used by lzfx_decompress (better than Gosub)
		rc = lzfx_getsize(ip, ilen - (ip-ibuf), remain_len)
		If rc>=0 Then olen = remain_len + (op - obuf)
		Return rc
	#Endmacro
    Do
        Dim As UInteger ctrl = *ip
        ip+=1
        /' Format 000LLLLL: a literal Byte String follows, of length L+1 '/
        If(ctrl < (1 Shl 5)) Then
            ctrl+=1
            If(op + ctrl > out_end) Then
               ip -=1      /' Rewind To control Byte '/
               my_guess()
            End If
            If(ip + ctrl > in_end) Then Return LZFX_ECORRUPT
            Do
               *op= *ip : op+=1 : ip+=1
               ctrl -= 1
            Loop While(ctrl <> 0)
            /'  Format 	#1 [LLLooooo oooooooo]: backref of length L+1+2
                            ^^^^^ ^^^^^^^^
                            A      B
                        #2 [111ooooo LLLLLLLL oooooooo] backref of length L+7+2
                            ^^^^^          ^^^^^^^^
                            A               B
               In both cases the location of the backref Is computed from the
               remaining part of the Data As follows:
                  location = op - A*256 - B - 1
            '/
        Else
            Dim As UInteger len1 = (ctrl Shr 5)
            Dim As Ubyte Ptr ref = op - ((ctrl And &h1f) Shl 8) -1
            If(len1=7) Then
               len1 += *ip
               ip+=1    /' i.e. Format #2 '/
            End If
            len1 += 2    /' Len Is Now #octets '/
            If(op + len1 > out_end)Then
               ip -= Iif(len1 >= 9, 2 , 1)   /' Rewind To control Byte '/
               my_guess()
            End If
            If(ip >= in_end) Then Return LZFX_ECORRUPT
            ref -=  *ip  : ip += 1
            If(ref < obuf) Then Return LZFX_ECORRUPT
            Do
               *op = *ref : op+= 1 : ref+=1
               len1 -=1
            Loop While (len1 <> 0 )
        End If
    Loop While (ip < in_end)
    olen = op - obuf
    Return 0
End Function

'original code by D.J.Peters
Function Base64Decode(sString As String, Byref iBase64Len as Uinteger) As Ubyte Ptr
	#Define P0(p) InStr(B64, Chr(sString[n + p])) - 1
	Dim As String*64 B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
	Dim As String sDecoded
	Dim As Long nChars = Len(sString) - 1
	If nChars < 0 Then Return 0
	For n As Long = 0 To nChars Step 4
		Var b = P0(1), c = P0(2), d = P0(3)
		If b >-1 Then
			Var a = P0(0)
			sDecoded += Chr((a Shl 2 + b Shr 4))
		End If
		If c > -1 Then sDecoded += Chr((b Shl 4 + c Shr 2))
		If d > -1 Then sDecoded += Chr((c Shl 6 + d      ))
	Next
	iBase64Len = Len(sDecoded)
    
    'workaround For multiple embedded file other crash will occure
    Static As Ubyte aReturn(0 To iBase64Len - 1)
    Redim aReturn(0 To iBase64Len - 1) As Ubyte
	
	For i As ULong = 0 to Len(sDecoded) - 1 'convert result string to ascii code values
		aReturn(i) = Asc(sDecoded, i + 1)
	Next
	Return @aReturn(0) 'return pointer to the array
End Function

If Fileexists("Wall.bmp") = 0 Then 
	Dim As UInteger iLines, iCompression, iFileSize, iCompressedSize
	Dim As String sBaseType, sBase64, aB64(1)

	Restore __Label0:
	Read iLines
	Read iCompression
	Read iFileSize
	Read iCompressedSize
	Read sBaseType

	For i As Ushort = 0 To iLines - 1
	   Read aB64(0)
	   sBase64 &= aB64(0)
	Next
	Dim As UInteger l 
	Dim As Ubyte Ptr aBinary = Base64Decode(sBase64, l)

	Dim As Boolean bError = False
	If iCompression Then 
	   If iCompressedSize <> l Then bError = TRUE
	Else
	   If iFileSize <> l Then bError = TRUE
	Endif
	If bError <> False Then 
	   ? "Something went wrong"
	   Sleep
	   End
	End If

	Dim As Integer hFile
	hFile = Freefile()
	Open "Wall.bmp" For Binary Access Write As #hFile

	If iCompression Then
	   Dim as Ubyte Ptr aBinaryC = Allocate(iFileSize) 
	   lzfx_decompress(aBinary, iCompressedSize, aBinaryC, iFileSize)
	   Put #hFile, 0, aBinaryC[0], iFileSize
	   Deallocate(aBinaryC)
	Else
	   Put #hFile, 0, aBinary[0], iFileSize
	Endif
	Close #hFile
	aBinary = 0
Endif


#Define PixelSetScrn(_x, _y, colour)	*Cptr(Ulong Ptr, pScrn2 + (_y) * pitch + (_x) Shl 2) = (colour)
Const w = 600, h = 221, w2 = w Shr 1, h2 = h Shr 1, _t = 1 / 120
Screenres w, h, 32, 2, GFX_ALPHA_PRIMITIVES Or GFX_NO_SWITCH
Screenset 1, 0
Color &hFF, &hFF000000
Cls

Dim As Long pitch
Dim As Any Ptr pScrn2 = Screenptr()
ScreenInfo , , , , pitch
Dim As Ulong Ptr pScrn = Screenptr()
Dim As Double t = 0
Dim As Long x, y, yy1, p = w - 1
Dim As Ulong iFPS, cfps = 0
Dim As Double fTimer = Timer

Dim pImage As Any Ptr = ImageCreate(w, h)
BLoad "Wall.bmp", pImage

Do
	Put (w - 1, 0), pImage, (p, 0) - (p, h), Pset
	p -= 1
	p = Iif(p < 0, w - 1, p)
	For y = h - 1 To 0 Step -1
		yy1 = y * w
		For x = 1 To w
			pScrn[yy1 + x - 1] = pScrn[yy1 + x]
		Next
	Next
	
	Line (1, 0) - (w, 14), &hFF000000, BF
	Draw String(4, 4), iFPS & " fps", &hFFFFFFFF

	Flip
	cfps += 1
	If Timer - fTimer > 0.99 Then
		iFPS = cfps
		cfps = 0
		fTimer = Timer
	End If
	Sleep (1)
Loop Until Len(Inkey())
Imagedestroy(pImage)
End
'Code below was generated by: FB File2Bas Code Generator v1.06 build 2022-02-23 beta

'Wall.bmp
__Label0:
Data 89,5,66418,33589,"Base64"
Data "BUJNcgMBAEAAAHYgBAAoIAMEWAIAAN0gBwIBAAQgBQMAAPwCgB9AAAAQQAQgAB9OXVcAQU1IAH5/fwA7REAASFZQADU7NwAhHhwALTAtAB95dXYAWWliAHFpagBpWlsAYEpMAGV5cAB+mo8ArdXHABGqna2tqamZmwAAkACZkJmZmpkgAAWpra2tmZkgDwGQsGACBZCQCQsACSAFAAAgJgBEIAQFAAAECQCZ4AEAAAlACgEJkCAHIEJABiAEIA8DkJkAACAaAZraQAADrdqZmSAHBd2t3dnd2WBmICtAACAhQACADQGQkCCIIGUACaBfoBygB2AjA5qd3Z0gRgPa2trZoFoA2iBaQGogomApQIkgDACZQAQgESAC4AAAAgAJAGAAAwRAkABAZAOQCQCwIGtA5iDrA5mQCZmBEAOamamaIDgAkCAsAAkhFSAUAaqdIRYH2tmbm5CQCwshGxMJqamp2amanZramtmZCQkJC5CwsCBDISkgBgKZ"
Data "CbBAECErBQQEBAAJBCCGIJRAJiCjIAAgDUASIA0gCSAXQBkGBAQJuZqa2CDaAKkhfgKa3Y1A4gTana2pmSAAQW1AJSAKAZmZIF4gBSCeAAsgzSCNAAsgQiAAAQmwoAdgBiAxAJ0guQLa2dkgUQKtrd0hKwCaIYkF2NqbmakEIWEgeCADAgmQm0AFIJUgD0CFAJBAAACZQFwACSEbAEAgAAQAAUCQCyDUBgmQALkLALkg1wOQuQsLQCgBma0gqgOZmamdIS0BsJlAiAIJm5ogFAHaqSAVCJua2traqqqt2SB4AIogfwStmt2qmUAAIJjgAgAAuWALIGBAACCXIAIgawSZkLCZmyAbALnAAWAMIHcAkCAJAJkgFCAAALAgSEA9AQRAgPAgAACQIRogtyAJBJkJAJAAIAABCQlhKgKZBEQjHCAAAkRERGAQAJBCMAIAQABB3SDsAJAgcQW5kJmbm5lAAAIJlEBgJCIOAJuACCCMAbCbYCEgCUCU"
Data "IAYAmSCKIAIBCwlBhQAEQLcgACANIJZAACBhIAAhXUAAIlcgAAKa3a0iSAKt2tgirwPdqaqtIAogTCBmgB4DmZBEQCHkIAAACSDEQ49g2CF3YF4ACSAAAJlAJAZEBEALBABAQHIgwGEx4AAAIckAmSDyAZCZQAAgQ0AAAwmwAJBABwIAQEAgO2ACIAAABCKcAAAg0gKQBBEgAAMTETExIAYKEUFERBQRQUBAALAjIgBBIAoCRERBQBcCETETQAYBFAlBnQAAIUYBBEQgTSACQAABBACAAACQIDVAACFMAJkg2ACQoAABsADgAAAABCBVILQABCAAAAAgRQJAREAgKQCZQLRAnQAAJGQg4AAJIA8AAEAEAJlAAAAAJHFABwGbmSOoA5kJCwBAAEB4AQREID+gACA5AwALkJBAqiCnYMkAESC5AkERFCAaAgAAuSBxAkAAQCAAAAAgZ0B6QAAgEUAGoAAACSENBQAABEREESBFABMgReAAACBO"
Data "IA4hCwIUAAQgCCEqoSwgDAEREUBDIJQgNGA1ADEgAEAhBRExFACwBCFMID4gJyBDwABACgAUILsAAEAAgHUhCiAAAEEgAARERBQUFCAFAAAgigIEAAwh5gVAAMAAwAshcQYUFBREFEQRQGYgYQcREzERQAmbkICz4AIAAAQgMSAAIXUhAAAR4AEAQIQh42DZAEEgtUBJIJwAEyAQQJEDNVMzU0B1AEBBiSB6BEBAQEREYSoBDAQghUEsAUAAwTkCRAQEIfQgUUIvQGYg8UCTIEkDMTMTMyCcA1VTSUFAPSBE4AIAAACAAABE4AEAAQREIEggTQBJIAggNgITEzEgQyAAADFAACHCIAAAESAXARQEIIQARIA/Yq8EFBEUFBEgACDhAUFEIlQABCAAAAAgsoD9AEFA0WCNCTUzUzMzERM1NAkh2iAxQLMgXCAcgABgDyGNABFABCAAIucgAAARIAAAEyAmIS8BFEEhyEJFBAQEBEBEgAAAESAA"
Data "DEFAAABAnZCZndBJkEAiXCE24AcAAARAbyBGABGAAAEUACAAAECgmiCEAxMxMRQg/AEAACNVAUOdIAfgBQDBa+AIAAFBSWASIIyAoWCtARExII8gAIAMABEgc0C7ABQhMwVEREFEQUFABgVBRBQUFEQixQBAIS4hTGB8IRagAGFXICsDERMQsCMFIXUiZ2BPADEgSwETMSU5AERgF4LzAQQAIAhgAEJDIB0AACBLAkFEQGDm4AEAAERAACCbCkSd2Z2d2QmZkEBAZXrgBgBAoABEw88AAEAwAwAEEEFgWiCFAREUIMpgAARDQAlBneEIawEBQEOCAUnQYCLgAAADBJkAQSNfgAAABEIqATEzYFEAEYCkIP8AREAAgAUFQUBBQUERISQBREAgACEfITdB9wBEISkldyAs4AMAAUREIBwAQSAjABAjgCCrBAREQTMxISZCvgATIUEpHwAARBMAQGDKAQFAIgYgyAAzIZdBgEAAISsBAETCNmBE"
Data "AAkgDwFEFENlApnZ2SUHBpmZQEDZAEBALOADAABBIcMgeQJEQAlB7SAKIBwDBBRDESAAADEhvwEEAKAAB5ATFAkDDZmUoA7AAAEEEEAJ4QcrAgANBOEBK0AAIN8AESC0AhETRGHQARQUIg8AECWLgAAggwBE4AFpRL4ktAAAZ1ooDeAIsyKrAxQUBBEpc4AAAQQRI0MAMyQqQGEAEGB4Q1xDUyDeABFivwAUIXfAACVHAwAUQJlBGuACACEEAgAASShfAJlAAAJAANnhCCohgSRQILkANECiITIAACAABAQUExAEoAvAAAAEIekCAQLdwA7AACJXIADhCSsAkECyYEzAACBQAkQAEYErIgwgXgGQBGJsAjMTE0UH4AQAIQwjDwWamp2dmZ0m3eAIAAQEQAERQOcCNUBdABEhFARBExQRSSIqI6SAfQIBFBEixSEF4AMABRREQEQJ2UcR4AIAAAQjQAQESdmdmSAAAp2QQMJ34AMAAUExKUgh"
Data "huAD1yQTARkE4AMkIAAGBEFACQFCLUAWQAPAAMEr4AM+IAACDdkBI4MgtOADAAKQBAkj0+ADEQBEYTSEWeAEAAAEIxAEQJqZ2ZkgACC34AkAAkABQeIAV+AAACYHKLxBKwIAAEAgAyAAAwERMQngByhBFSSYAkAEneADySPZINkAnSwDIAAAqSmToEHgAgABERTkCcThDCsFFEAEAQLtQF1AA8AAg4MBTdDAD6AAAQ3ZQlfiB8YABCPm4QQrgAABBBPgCJYhmQIEQJ0kOQKanZriC1cBCUQh3+IDV2AABAkESQERoSugAAJBERHBNuABAAJEFEkhK+ABD2AARMUBAAklHy0DAdmZRJPgCAACQRQJ4AipAJElIuIGtiGMBEBEBELt4Ac/glcBTdTgBhcDndpBCyOZ4AZZAAQguuEeKyjcAEklYQGZmSMP4AeKQAAkbOIHLiAAAgRJA+EKK2VS4AIAJE5BK+AGnAABJB4DBABJnS79Ap2Z2Sr6"
Data "4AIxoAAhd+AIAEJXAADiBioFBBQQAAQY4QgrglcADeEHKwEN2iODAEnhBysAkOMHg4AAAAHiClcBEEAkOwHZmSHjLKOAJuAEAARAAANJsOAEEUAAAAQkxgERGeAC5QAJJ9DjCIMkzWODQDHgAQAhQSA/AgCdLWOF5wAn4AMAAUMR6AgHISsCE0mZ4QZ3IqICCQFI4QkrA0AEAMDiC1cAAeIJVy2HABHiClcBCQEnEuAGAAIEEERCVwGpmSEs4gtXIwsAA4nA4AQAA5BJATHjB4MAMSFtgCThABwAFCODAK3gBt9CVyP3BgmZ3ZmZ2dniDVcBQzQkxIBFAQQAoAAiVyEroAygAAMEFEFA4QsrABAgNQEEDeIHhAGdreIKVyQL4QIrIDeAAAIJARHjByUhKwIAREkvCzA+IleAnuAEAEJXoQLgAgABmQ0hKwAZ4AOMJL/BKwAJ4AAXJ5ABRJrgBt8g4CJtAAAl3AWdmZmS7RTgCl0CABMU4Qdg"
Data "IDZCVwDd4AWhKJQDCQRN7eAHnySvAARBK+AFLCSvISsADeAGFSC0LqIgX+AGAACU4gpXAhSQRCGuJDgl3yDB4AoAAUNA4AkUAZmZIRvoBMAl2yB2YCkBSSnAMYJXYBSAACezQlcz5yHPBpmp2ZjtEU3gBrxAAAFDEOABNMBLIlcAQOEIKyASAgQN4oB2YABgLUJXAEAnB2AM4AEAIlcDCwBNIOAHFeEDK+AAGwFJ0OELKwGZBCaNAJlBLQCk4gtXAADjDIMhKy9T4gA/IAAhOwEJneACtCAAAJ0krwAJ4glXSDMq/knSIAADQQqkAOAIAAETEOABWsC+AgERE+EIKyrpAwkBCe7gBXZBjSKG4QoVQ4PhDCsAESA0YADAbCMb4QwrAQFJKC8DmZmakCJX4AAr4AIAAQNJQg3gBQABmdBBK+ADoyXbAUnZ4AMQBAAE3QREJwcA2oIiNE2gACxaI/cAmUAABKnZqQEK7AehIAABQxDiBxMgTiEr"
Data "AJ3jB4MCFBALISsABCAe4AMAJwcu4+cIBwOdqgEA4QgrIeDjC4PiDVchmADZIlcBmdnkDa8CAARD5QrbAZnZQSuBBYAAI4MAQOwGbABA4g1XAARErzaUYlgA2eEMKwETEOQJryK4ARSd4AUWAAniD1cCQAQE4glXAQkJRwfiCVcAlC5nAADgBwAACeILVwIRCQEkrwCpJwkCmdAUIN7gCAADBEFJC+AIFAEN0EEb4QYrAEnhBitIMwAJJwcgCOIDcClfAQQEKdABnZlBogGRDeILVwAZQDTgBQAhKwBE4gpXJPoA7uAFKC5DIGACBABC4gebY4MASeQIrwGUEegKM+IMVwQRmQEJ2UgyK7cCFEBAIGngBAAwGLH04AQALC4kr+AD0GOD4AQjIAAAQSErAZ2pIAjgAwAAQTM1Jk8hniqNAdmU4wuDABPhDCsCMRDZ4gVXRK8BALHkAa/EKyJXBABEAE0kICDgAwACmd0BOXHhCCsB1BHkAa/g"
Data "AQAA2eQLryODAZnZI4IAqSJXAEDhCCsiG+4KD+IOV+ELKwBApK/gAQAwlwEERDBnAJ0gAQLZmZTiC1fhDSsCERDd4QcrMOIBAZviCFcBBBQvd+oJiwCZRdvnAaSgAAIN0BPhAyuhAQAJ4QsrYlciVEMPAEThCSsACSIGoD7gAwABCdnjCYMCE03ZOsfvBIAiQeEJKwABIZICRBCdISoCotmZ4Q8r5wEHoABMKAEQ2uEJKwILAZrnCQcuJSEr4gZBBQmdrZEACeEIKwKd0BEhKyc54AUA4QwrBAoBmamZISkjECDEAADgBwAEkEEEQLDkA25gAAEJ3SOD6QIEdRUBTYkgG+AEKiFmAUDd4gdtMLgARDBdA52amZIizACQ4g1X4QcrTVQAEyJXIGHgAwAi8wEBmOEKKwAEMQnhBysiVwAELOPpAPygAIJX4QcrAEnhCysCFA0EIeEBmp0hLeEMKyIb4QlAAgQJjSJX5wLYT6wAM2ErICzhAS4E"
Data "QUALQJ3gCN8BQQQgyQGZnSnSIAABAJ3lCtsAE+EIK4JXAN3gAVqAADK/AAThCisBRATiDVcDlAkJSeIHmgKdoBHiDVfrCMwEBBENlJ0hKAGZmiSyA0RAQADgBwAiV+gKMwEJjSdo4QQrAxEREUqBFcVhIABCV+QFrwEEnUODKXcj9wCZIHIBmQThCisABOEJKwAERwcAEOcJaANAAAHS4glXIYsAROIJVwENrSGWAEDhBysADWEr4Aj4ANnnCRxhKwqZqdmZmQmpmUFAROAINAGQQSrEIPbgBQAkrwExQeEEKyJn5QnbAxRECUnhCCtWyAHBGSPyLoQp0+ELK+4FamAAJK8CExDa4glXApBEkuEKKyAAAEDoBx0FCZ3alAsJ4QgrAArkDK8AQOENKwCRIeMCmanUM/ECQUBA4QgrAAAhKwGwAOAHACErJpboAcBErwETCegHHTRIAADhBisgKQBEWM0CQJnZISoCnZoJ4gxXAREd5AevOvEy"
Data "BOEKKwEABOEJKwVBREQEBETuCGgBna1eWTDB4AQAAJpBKwFAQOAEEyAAANnjCYMFABENpDDZJK4/ZwCaIGMgJeAGACEr4AkAJK8BMRHhBisDMQ2JBOAGKQJEQAvhACvgAKMCARREM+ACmZndJLAC2QCU4gpXAwETTaDgBknhDys9HQKS7tDgBiwCBBREIADwCMABndo/P+UCTYAAAprZESoq4AL4g0UB3RPrB8wACSODISsCmZmdIAIAnUODAASAQcAAKDM/g+IH+kErIlfjA/oDERERDUcH4AAAIH03DgIAANquJeAAQy87AkRBCTo4Is0DmZRAmoAYgKEgACAOISsA0CAJPWbgAgAgcOMJ5CXbAQCS8QOTIHAAACBhJRECRAkEIArgAwAAmSKWALBAX+AEAAAKSP7gBBEguQMAAK1B4AMUYJ0HBBQKlDCdnZ0jEAKamQEyb+AHAAGUEeEJikErLHLoBzPhBCtZviErLYShK2DFQABCVwFE"
Data "CSUkBp3ZmdmRFJkhHAAA4QIXAEBVYwEdoCAHQALgAQAhKwEZjeABDoAAKDMCQJktYEGAAGEfQY0mPgCU4AByYAAACSErLa3gAixgAACaQSvgBClBKwBAIlfgAxRAEwUAEZmUMJoxIAOZ2ZnaQStgbOACAEEr5AqvAt0BE+EDKyBHAhERneIDVwEN4iEAAkFAsCOD4AadRdsBEJkhngGZnSJXABSiV2CMQAAgCCrWQlfgBQAhKwFJLibI4AQABUFJBETd2fYGcAMERBFEIADpB0lBKwAJIfjhAwICAAAE4QkrYAAB3UMhKwAEwCtgCAEEFCErJDghKgHZnUSv4QcrAgQUCYKB4AQABQndkRERFIgjYAAziQIUDYnAWkAAIMAiVwIAAKqCOOAAAAEJQSBmBESZmd2ZJwgB2ZAiV2ByYASgAABB5AqvISsCMUne7QfiBQFJCQHv+aA24AAAoSsB7pHgABFAADL9A5QLCwDhBisjg1wL4AN+YAAA"
Data "2j+6YAjAACANBUSalBDZmTJIAtmtlCGO4Ag0ApEQmSK44AYAAgQJ3UEcIQ7AAEAOAA3nBAcARCGzABQy4gHameAGhz3mAEEoKTVFAZCdKv8BmaAgJECJgABEGQJBEUnlCNsgFAMRQtgpIhjgAwAIQUkJAy/+QACQ4gS7AEEgyAZERBAv4xAA4AAABAmQAJnYKosgCCD14AAAJmMALSam4AMSQIECAEDZQlfgAABgwgiQQKmUMNrd3Z0jEwJDFEThCSsBARAnaOAEiUAAYSsANOUE2wQTFN6pmeAFyjtQAgtA3UdiQDPAAABBI4QKQQ1BQJkJmQ3d2REgHgPa3a2ZIABgpCAzIlf2BJ5AAFzxAzEOKZlAAOECGAdBEACz3u8kCSAWAQkAYAAAQCAFAwQUREEgAQEP/sWedrEHmZmikQsEQEmI6QCQNH0gEgWZmZ0uATH/BI9hFwAAISs4ikBNLRwgAAGtrSooA5mUNJ0jJgMEAAEzIY6AHKAA"
Data "AgkJkCJXAdAA4gZYCZCZkJmO0RERFOLgAC0ERAQxETQhK0AAJBIAAIAABkFBEJBALZlgAMATAAAwZycHAUARMa8AkC0AO4YHma2I2IiK2togIzhsIIIDQRFNoKBaIAYBBAAy7k1EAhOe2yCRIAAAmWAAAwmQkJlTfgKdn+BgD0AAAJBhRwEERCBhBTEUMP/hAKElYAACCa2RNgQCAJkJIAFAAgCQIEBAyiamA0AAQEQvcAIEBACBKQMEQN1BIBQ7UyMeCZmamtiI2I2NqZAgmQYURBETExMRQSsAROAB0yUMIAAAkCr+4gK1AAmgfAeu1DETEQ7RAEAAKJwAQCgzAjTiuSC+oB8gAAUJmQRBNJA1LCALwAACCQkAQfUCRBQRIAAAFECOIHwhHSS6Qbg1myAfAgATMSODBAmdnZ2Z4AMACUEzDtnd3d2t2Z0gGAHZmWAcBpBBCQQNne4gEgLd3dkgAUAAAZmQI+UGFEExREMe/UAPQDQB3dkg"
Data "IjK/VNggAAHZmUAPIBAFnd3d2S4DOOFhPIAAANkghgUAAKkRMxAhqCCZAN0gcwCpIB8lBiZfISeAAAFEQS1g4QAPYAAGkA3QCbQQCeEBAgCQIAADmQmy5CnAAx3pRAQlMmAABpATMe69KN0gAACdQAAHmZ2ZmZmQBDQ3dQCdIHtAlKAAAJloMwAR4AEAABNAACLSAAA2Vxet2t3ZmZlBER0u4t3d2trY3d2N2t2pmpkgSwREQRQO7oAAA9LtLd0g5ACZIAAhKwMO7v8tIDUCnZ3doAABBBQkTAAUIAQDQN3e3UAAAJ0gjAXd3S7/4gSBKwAJQBQD3tLe7oAAAQQRMPYhrSNnAd3dIHIF3a3d0uItP1cAmSA1AK0xCyKoCUERExETMREUFBHAAAREREQUCeAAcwvd3Z2Z2d3d1ACUEJkgACD/QABg9gctviEzEJmQ4iF2ApmamSAAJ6cAFKB7Au3t3UAAAJkgAACQJOwD3v/u3SAMANkgSWAA"
Data "BNkEQRRBOA4AEYAAAMEjyyAJAjEzMSKoD0RACZuZqtqtkE3u7u3Z2dlKrQCZK/AECQAABDMnaCBZAd7dYABAGyAABZARCwSd7mBgAJkgLUH9JDdoliH1LIuB4yAaAZ3dIJ4ClAsBYMogAADdYAAgTQHe7Tj1ATQAQACEwAOZrdndIH4AECE6PTMiTSNxAhMTESAAA0EREcFArGAAAMQlEmF0IACBjAPe7/7QgSsBkJ0gFAHd7SBxYAAA1CM8AQDSI8oBmgBAAEZLAJ0gyqAAAdmZQAABCQQkrwPe7u3dQwAgEgGQkCK0IAMgZQARIIEEwRHBHBEgAEAFAEFggwITEzEhuybWAUDdIVMFRAREREQUIANF70KJBEREQAAEITYDAEREAIAAAAE8agMAABSZYAAkKiAMIAAEkAFEQUEqpgAAR4wgTQCZYAAAkEArAQQUICIgGCAaAECATQBBIFkCFBEAQGsBQUSgACEDANAnnSAZABEhwUAAABQg"
Data "BAHBESCuQAQh3wDBJEEAQCOhINBBYQTZnZmZ3SFhIDUAFGAQA5mZnd3AAAbtlEERM0CdQHUAREDCABEiHgBETjpAyCTAIAApNyamIeQBSZlgAAAAYAAABCAFAUFBIDwhLGAAAMFgBWAAADEgBQATImIhxCCiBTETMzMzMSAUCURBMzMTUxQRNAAzw+AHAAAAJg4gtAAAIAcBREAgXAFARCDyBBRDMUQRI4Q+4GASYCBCbUAl4AYAIFQgdwUxETMxREEgfAMxMTMRIAslvAEzEyN2ABHgCAABHBEh0iAXAERAdiBdQAAlm0AAIT0nxCBsAQkAIAAARICQIAciGSYoIA8CRBQTYNFXywEEBEAQ4AIAAEAm9QEUACAAIBhCEwNAQEREQMUgLSThIIsBMREgACB54QIyQcJgEiAAABNBLwgUQ1dVV3dTEzHCTSAAAARAagBAIFNBDkbBAkREBCCkAQBAQU4BERQgVwAUIoYBREBAE0ArICIAREdO"
Data "A0AEBERAFgEEAOAAAARAQTMRMyAAADEm5SedIAAg20CSQAAgBwAxQKMh0SAKIJch4wITEJkiGwFBQUAsAEBAAAAAIHsBQAAhFQARIKEARCAAAEEgAyAAYAYFQEBAkBERYfkBFBMgayAAAjEzNEAu4AEAYJMhtGEeIABATQAEInUgFwARIHMGDZ2akTEzEDxmIABAawAMIMUAQSl7ABHAACCWIAAh6iAJADUhKSD7AAQlHwG5mSAAI1YgAgAJSEIDAJCQsCimAJkgACreIxYBCbAiYCHdI/EAmyAtAZCQICoAkD3KAAkgAAALIAMjIwGQmSACAJsgAQC5ICQARCAuQJIGFEBEFERERECGABGAAEVVABQgEwAMKEMBwMCAFQcAMzExnZ3dAyGLAUFEIC0BQAAgACDcAUBEIAwCBAQAQAgBQABgFWAAIJEBBEShjABAIDEBEREgxyFcAACFHQGbmSAAICMJAAALkJALmZCwkCCbIABABQGbmyAj"
Data "NPgEMJ2Zmdko7QHZESAAAgALAOACACT6ImYgmQMzM1MzgAAiuSGkJEHgAwAAsCA2YKoiS+AAmyQHBAmUEUCQISsBABNAMCC4gAAAQCG1ICYBRAAs5+AEADFHAAAsdwNERERBJLsgd2AAABwgBQAxIC/gAQAHkAMRERE52UFAuASZkDEQACGKAAkg0ACQQN4oGkAAA7mwkLlg/mAAYAohCEGMARQRJeAARCGNQJkhGSC+gAAkQyGOAhFEESCEQKLgAHMBwARAlSDGBA3Z2dmdN4oAmTaLAjGwAOAEAAARYAACwRERJDXAAAVVNEE1MRFAEgMxMTEzQAABExNABQQ0FAEzMUABQA1AAyQPAxVTMUEgAAEzVUAUAVVTIWglASA1JjgCBBQzIAAgC0AABBExExMRYAAAEKBzIACAESB8IAAhDuACAABAIwMKE02QCdndmdnd3QMgHABBRqhgAAAEQOgBREQ35SG+IAhBFCUtQAAAC0AEIAAiUyrH"
Data "IAAAMTXiABGAZyDJA1VVVXWAAgIUGRMgDwETM0AAAzUzU1UgAAJTVTMhvAGdmSEpBNmZREkDIJwAACha4AIAYEvgBAAGEzM1UUQ1UUSFIf0AREc1Re8gIwMxQAMzQPFkVEAAKuAAMSAYIcYhCyBoIAtAACAfQIlitAMTMzMxJ3cBQUEgviMTJIEBEAAl0IAAADGABiAAPGQAAOADAAEQASDhCwlESd3dmt2ZnZEUQSGEIEpgACByABMnxAIzMxklvQBVYPtgAAFTU0GnIAAAQMKvIEMAQCZMABNCZSZEQAACNVVTQ6QBFEkkdRMxM1NTUzMzM1M1NVUzNTVTMRERESwvAJkiyQZASUMRMTEEIaPgAAAhoiHlARMR4AUAAkE0RCJXoLwBCQAgAiLLJKYAFGNaAEQgAQAAYABAPSgYARQRItggECMAYABB6gIAQEAkKAAQJLlAO8AZIAxmpAABQJUgyCADQAACMRHDJcFgTaAAAZAULjcAEyxn"
Data "AJkn0QITSaEgKyAsIZMgAAIUETMgACAPAhMZRCmNAzVVVXUgDwEzMyVqQYoDMRM0CSM/IAABHBEhgiNaePgutmAAAARG/Sp1IG4ARDCDIAAqgQdEFEFEQEREASALAZBEYqIFRAADMxE05AFuIABADAQTERMTMyB7KiMBExMiTQETECA6ATUxIFNhJgAA4AHpKUUAkCAP4AEAQA1gcAAUQCvgAQAgOCFhAAshYcAAAAkgAUAuIC1BqwMTETExRmwgdgAxQHsCERSSKPXgAgAu8wEzMSAsJHoDE1VUkSKz5wFNRzohcwEURCEAJiwDERExREAAAUFBIAUAQCAzAhGdQSAFISkBMTMh1CAKQHEABC77IA1AAAAJQc17LwBEoABgGQAEQFcAESpeQBQhGAAR+AYEIBJAEyAdABFB8CL4Jo4j7SN0ABRBCOAEAAAJQjzgCAAgiyC44AgWQABAXSEzIAPgAAAgLUC5I9kBEREgNCAEAEQgACCWAZKQ"
Data "4ARdAAQsOgAQICwicwIRM1OALEAAIqgAkEETQAAAFCt+KDsooQIEBERAAEEtQFICDQQJJrMAMSjIAgAAACKgoSOAAEDWAQFEIgngBwAAASj+JzcABCAAAAAhPARAABMwAOAEACmHABM2uOAFAAVEQUEzMTT0AlygAAABRuvgBwAAASWbAMEg9uAJAFvB4AYAAQnUOWVAreAFAAEBEyErAEDgBRNCEwJBERElE0Te9wOQAEQlzCAWAkExAOQET0NVAUFBIrICEZ3QIiRBikAAAQQRa6TgBAABAUE1VOAHAAABI9ECFBFAQAAARCF8AkBAQyGJ4AMABEAAADExIBAkjSAFoAAFQURBNTMx/QhLAQAE+QitIAAlOyAAIEfgCAAAmYJX4AMAAQ2RSAngAixidAWQATEUAtBCBOACACWVIRMCREQEIl0kq+ADYQAESVogeABJ4AhgARFBIlcDE57QAOABACMr4ghEIlfnAFXgAAAr5wARIGZgACBg"
Data "AgBAEeECEoAAAARhK+AEACSvAjMzEW1T4AQAAAHgCWAi4wARIAAAE2P+4AYAAdlEYQngAwAAnUErk//gAwAEARE0DdTgAxAgAAGREEgPAEAh4wMREzMUwiXgAgACBDEJ4QcrJJQiT4ErwHsgn+QITiEr4AjdAQkEIlcgZgBAoAABBAQy4wAA4AUA4QorglfgCE0CAAQN4QOwgAAACSCLAsERw+ELKwHdBIAi4AIAQlcAGeAJRCErAALhBisCQJEwIdwhKSJXRuPiA1egAAERCfoGPCErABRC5gAO4ANhAwE8ETDhB50pfOAJ3QBBK/EgZqAAAAThDSvkCGwARCSv4wyD4QorIOdAAOEgKwIxERnlCggEMTEClADgBAADQJE0BKAAL1gAMSDEAADgBwABMQ3gBjNBKwCQICrgBEshywA04QcrLZXhDSsCHDEEYAAAACg6AATgCDYBAJHjCYNiV+UK2+ERK+YFaoAAAEDiC1cA0eELKwAJN1EA"
Data "kuAG9wFAlDDpYAAkrwAVIQDhHCsCRBDQICoAQuIDoyEr4gpXISvgB1AAFOIDVyYoAgM51OAHIuMKgyJXAVM14QorAADiC1cnnQARISvlCAcAAOMLg0cH4g1XAJIgMOADAAJA2TEuVWAAABFBK+EKjQExDeAHdAEEFGEr5AT74QsrAQFBISsAAOAGAABEQSvCVzA5AgM9JOEOK0rIwAAl2+EMK+ILVwAJa4NvOeAHAOIKV0ErADnjAYM/2QCUR5gjg+EHKwIQLVNI5iAAAkQRMeMNgwERDeIIG4JX5gSCAgEUE+IJVwBEISvhBwjkAa8BBARPVwJDOYDgByKiV+cDVyErADPiC1fhCyviFFfGi+AAAEEr4gNXAASJIuEKKwNA2TNAQLQgAAERMSOD4glXAAThCStCVy6Z4QUrABHhCSsgJwDd4ghXYSuiV0AAAUM56APcYADhCSsACSEr4iBXIOcBETw78+AIeiSv5AaCIAAADSqLADnpBLhq"
Data "TuEKKwBJQStgAIEr8QWyYADhCSsAACODKrnhBysAEOIByYAAAgFBEOUJ22SvI/hgAAAEOuAAGeEIKyCnAAAgAOoDCWErAFTgB2AhFisQ4AgAID8DExMRGeEJKyOD4gfDglfhBStAIzHq4wGDgEkESdAzEAQgACg2ARFT4g1XABPjCIMiLyErABPiBM7iDlfhCSsAQSlfAjExRCBzgAAAFeEAKwFAAKAApwfpAwsFAURDUzUw4QgrAQlE5QrbRK8y+uEiKwAw4QgrIEPhASugmAJJ0BNhKyAAAhF1FTp3oBfgAgDiClckrwMzEROd4AIkLScBExDoBzMAROIKVwEERCErIr4iUoAA4Qoro4PhCCsAUOEIKwAA4QsrQD8nB+oKYAFJ3WIz4AQAAAkn0uIGV0Af4gNXoRMCSdkV4QArAFUiV+kJwSSv4QcDAgQUFCErABHmBFQAA+EKK0OD4whgQlcwsgAEwAABM0nAIgFAAKAA4QsrABQiV+EM"
Data "K+EJPyA/IrnhISsAMyJXYR/gAwDhAyukDAIJ2RPKjAIRVTUnCeADL4AA4gtXARTZLdTlBLcAQzLn4QdTAkRBMOELKwBDMioAQMAAAgQ1SaMA4QHyJG8AAOAGAABBQSvmCQUiV+EKK3Tl4QsrAA3iClcBSdkqi+EKK+MCg6ErAg3ZQ+EAKwA1NHnsCFwiRAGdkEhw4AIAIlcEmRMUMZnmAlQz9yCc4gAZgAAAAeENKz7v5AGvAQEzwSsAkeAAPQAEOn/gBQABCUFEr+kCBsAAAkQN6eAANuABADdaADMgjuABEKAAI4PgBsol2wDZ4gBXpYBiYyJXANIgHWAA4QIrAQBAQAAs4wAVIGMAAOAHAAAEL93gBmA4egCZIldYouAAAAJDETPiCFchKwCS4Qf2IDs1TjvqAEAgAAAEOwMCMwndgO3iAleBK2CzoABBKwBV8AoOAhQNKYA94AQAVv8gjuAEE0AAAkntAeAGyiAAIyLiC1fuAn3hACsA"
Data "A6jrBQExMxVRMeENK+oDFSAAIlcgYAEUCeICVyErARNJ4gdXAwRDMN7hBytA9SRNAEDF3AMBMw0tgO0AAYAGIAACkTM0IAXgBABBKwA34wqDAREC4gtXKDICExMd4QkrAAnhCiskhQIRMC2Bl4AFYAAgg6CXILIgAyAAAk0tA6jrAEEhKwExE+EMKwDQ4QcrAEEhKwIxE0nrA5MiVwBJ4AecAAHhDSsAQSXbAEDAAAMBMQ3tgbf3AQoAAeEKK4SvAADgBgAABOENKwQzMTExM+sDjKAAA0niATCgCuAAAEErARAtgILgAgACBDM0ou8hK4HFAgjtATT3IwsDQEARMygz4QsrAZ7Q5AbFQlcjSAAZ4QIrRK/hCCsAROELKzPrI+ogcmAALI8BCO1AigEEQGG9ZDIgpwAA4AYAIlcBMzfgCf0DkDGS6eAGKSAAAAQ6gicHpjPgAgAhK+MIgwBNIyIAMOELKwAxQStAjwEJAToAIAACTegBILch"
Data "KQBAN/wiV+EGFUAA4QorJwcAQyY94QErAEDiDFcAQeEKKwAEKDNHB0ByQAAEQzGSKQDgAQBjiOILVwNEQzM16gC14AEA4QsrKkc14gAz4Q4ri4PgAQBCVwE0IuIKV27eAAHgASgEBA0okTElYkAAABEwZwETMUFI4AQAAAQhK+MHgwEUFCc+ARNJ9AMDKDPkCK9hK+QD1EAAAUFEIr4CM0QEgAAAACEr4wO6YSviC1cAFCJX5AmvAQQx5AuvAAQiuCOD6AkI4gtXAEkiVwE04uELKwDpIoNi7KAABATSkTNAdRYBQBEhKwAz7gkPQSviBm02G0JX5AKvQlcBMQngA/RAAEErANDhBsciVwAVO38DQEBARGABA0NRktQgPuACAAAE4gtXARFBKoviC1cCDuBA4AI7gAABATEgAAEzOeEMK+QIr4Er5QLVgAADBDNU/+EFQABAISsCU0BEYLgFQREVMzEzgCngAgAABDYr4QYrYlcCMRMC4gVX"
Data "ATOd4AMPQADhCytCVwEzEz0cAUQEIAA5xQA0ISshwOABAOENKwIURVPhCisBBDThCyspnwEzEyODAATgAVSAAAJJ7gThHysEADNT7+Mgi+ABAAJAANIhKwBAQLgldAE1E+UO2+UG8SErAJ3hBStCVwEVDfQG4AUEFEUw3tAgG+ADAKJXATQEIAAgdgVEQzSYlARgDQAAoACBKwBAoA2gAAMRFBNVUJHgBRYEQAQwnuDgBhMgAJ47ADDhCCsDBEnukOYINSJXAhNRLuIFQiAAIW8BT/ThAMMAQCjiBjQEmJQzQEQhLQYEREQTUxMzXC7gBQDjCoMIBBQRnUMRFQIE4AApISsAMS3YNOY+t+AAAgVBQxnekAknZOABEiBOAUQVPwIAUyASJlIHRAAVMJ0EAVMgSAAEIAAAACASIBYCAzMwIDJAACAPIAAgZySvAXUzRK8gDOADAgEwkiODQBBgBCAuIAIgP0AAATHdIEpADyASgAIqiwGQMGBj"
Data "4AIXMpUDMzEuQUAWIAAgGUAAAAAiVwIxEP7eTkFJBgNUBA2QNUBkrwMEBBVTY4NALyAygAIAACDcAp7ZQeAFFCJXBJlDMTWdQEKAAAdEAEUzM0kJkMAnYBUABGErIPVLkUASIQsEBAAUFDUkrwMzFEERPwsABEErBikARJnZmZkr0iEUQEEEAzMQAEBgQmAGIBUCBDNBISssGGAWIJtAGCALAwQwDekgNSH1ISwgKABAICBhKyBiAjWdkCDDICsgAiGJBkBAREQZ7QBCV0BQAAAgACBAIDYI2TMzUe7VNAAEIJwAQCAAIAYgBwcAEzNEL+SZmSbrC0RACZmZnQRADS2QNTBoB0RBERRENVMzQlcgRiACIC8gAwAEIDhhK2AOIBGAAgJEEQknwiErYCgABDq3BgBDMzNNkQkgCwVAQEREBEQgKDx3BBUZntQEIUEBBAQgEiAWAEAgugIRRDdAZwIzMzU+SA4RQTU5me6Z3Z2dnd3d3dkhcwEA"
Data "ACKjk1NAAAMAQEBAIAMBAXVBKwE52SBXBURERAREBEAYIAQCQzBOJq0AQCAAIBQgGiB8IRkBAzMgAAQxU52dlCAoAERAAEB5IAADGe5AM0A2IAoABCAAIAcCBAQZISsCVN7u6AMcIXg0gwgzBE3u7u4t3dIgBAud3dmd2Z7pmRUxQRMjfANTM1UzIAADEAQABCAAIHsEBEREREAgfQRD3plDACDkAAQgWwBEIKgABCAVBjGdRTM3ntFYPQEEACzLYSsBHe3IvCApAAAgAQdBVUCf4ABACSEtIAAgOEACAREUYZOAACE1DTmRnQQAmZnZ3Sgi3ZkAYAAAQyOhMEIgc0B3IEkicgdBQVUzMC6RQCAVICMABGABBQAENRAe+SH0QAAACSIBIAIq1CISQAAFNUnZBAAANNM/7KAjBU3+EDUwACBQIJwhU0ADEkSeIDM1MJnv/QmZ2Z2ZmdnZ2Zki4gBAIpwTU0BBnd3ZkA3dLi7t3ZmZkAQNkZkh"
Data "3wEzUyC0gAAi/QBAQShAA0GNAAQhKwKQQxQgsSX9AUQEIAEgHgoBPe0TM1MS4FNAACAAAEBAAQkBUzM079Gd2ZCQQJgBAAAhGgYAQ3VAn+3ZIIAAmUAAAgmQkCC5BEQRQVczYAAANSABIl0JVNBJkJmZmqmQBCLbCxETERERFBU0BAREQCBtIZ5AACB6AABBKwxRnulAmd3ZmQkJRERAQBgIADUwDv7d7e3dIAADmdmdmUAAILkBNTNAAAA1JdxBIwWdmZ2dnd0gAAPt7d7+I/MAACAAAwQAAEAgAABEIAEB7tE1cASZnv4J2UBBAJAgiwqQkJBEBEQENRRBNSHMBhETMRFAmaohQASQQNRTM4BbgAAANCEhAABgAAAJIe1AAAaU35BDUQBAIS0BAAAiIUEKApTf5CPkBUHdRAQEAEB2IRkhKwIUDu0gyQXZnZ2ZnZkvRiQ/BlMJ3uLu7t0gAATZmZnZ2SAEBJkEERNXQZgAU4B0C1MzU5iq"
Data "qQCaBBM1VSAAAlNTUyG6BjUQAABAQAAgBCJdAEQhXQBBPUoiVwQzTeIJ3bM1LpMIERERNTAN7d3dIfWgAAGQkCGmAgQEM0AAAzRBCZQhn0EuYAAEnd3d3e0uKgQREUERRCZVILQg1QWS7UNTMzAqcwAUIR87kEAAINIBRAAoNCCKAjNTVUAACVMUCqAJqqiTUzNAAKC7ADUs8UBdAJ0gAQHZ3SAABO3t7e6ZI2MgVgMA2Z3dIAFAAAjuQRMzUQRN0AAgAECzB0QAAVNVMBEtZQYAkCI+AQQRIAAIEzMQni3ZndmZYAABCZlBsyCOJkMj7yElIAAiWAUQQRNVM1UhJgAzIABC4ANVNTREgAAy6SAgICoCM1MxICQFUxGdlAQUQcIDkABDVUAAIC4ARCAAIpEgBS16QAAARCISADMgNgAwKJ4CFBQUIWcgAAFBESZJABQtKABVQAAANWUqIR0EBEDdkRMg9CGpAFMhFUAWICdgAAVBNTVVNVVA"
Data "KgFTVSAaAlM1U0fBIIwDU1MzMyBAAjMzMSLCIlFBLoAACd3d2d6ZE1MxERExhAAAIQUijAUATSEQNTMiawCUIBQEEVMzM1MgyiAFAAQgp0CVAxE1U1WAAAZTMUERQUQxgIAAEUAAAhQRRCHIAjM0FSB2QHMANUC9ATNVItwBVEEhQiAAA1MzMzMgMCBQBTM1VVU1NSHFQMgANSAWAFMo1SBRIGoCU1VTYAABVVVACCAFAVUzgD0CVTVTIB4gDAI1NTMgAwBVIAAgDQBTIAZAQQVVVVNTVTVgFUAAAzMzMxNgXABVIBwBNTMgJgQ1VVNTM2elABMgBkAAADFGgEBbADUgPEEqICYCU1MzIAIAUTX4QQAAEcD2AEEiQSHpAFVAACAfABEgxSAAARQDIDIBERUgYSAAIBYgiyD0ADEgDCCOoAAAUyGLIHogF0AAAjUzNUAGIAcgAANTVR1FQHYAUyBzATU1IBoAMyASABAgeMAAD0REQEVVNVUz"
Data "NTVVV1dVdXVABARVVVEVVWAAAFNBugZBQUEUFEQRYYEBExPAdyFaBFVVVTNTIFkBNVUgCABVQA4gBwEzMUC6BBEUQURBIoQIFBQREREzMzNVIGMBUxEhPSA3AFUgAABTIAAgCwNTVUBE4AAABkBAAAAVNTMgAAdTNTU1MzVTUyDSAlNTMyAOIAMgQCAAIDRAAAAzQHMCNTVVIa9ADiAAAVMzIAAhvQBVIIJgNkAvAFMhGQA0ICVhCwARIVABFERAAABBIJkgAAATQJZgAGBEIHIAMSA+ATNToAAANWAAWd/gAgAAFSBbBVVXd3d1V2AABVUzM3dRATgSAAAguwYACwCwsAAAQAIEsLkLCwBAAAIEBEQi0wYzNTNTMzM1QAAAU0AIADMhHwBEYO8gMwALIAAgNCAvALAgByAGCkABVVNRBDUxEREzgAACU1VVQMEAVSAzyGcARCAAIIshhCDtAzU1URUgBKAAAlVVVUAwQAADMzMzEWAA6gC+"
Data "ABEisYAfAjQVNSAAAVU1ICwAM0AABxERE1VAQ1NVKHKAkgTADADAsMAAAwsADAAgyibmIZRAACHvIMtACUAAIWkgAGIhQAAOMRETEzE1czUzNXVTMzMxQBJgAAM3UUFTJWVCfgETMyAYADEgGj1jB8RBRMRMRMRAJn0gAAAVYdeAAAZVVVUQDACwIBkABCAhYb5APQIzExNAPQoRERFMEVVVMUA1ECEQQR1BbCDHAzVVEVMgC+ABAAEUQ0ChILAFU1NVcRU1QAABM1NAACE9IPmBiwCw4AAAAAQlOQHEREAAAEEn9AVTU0AVUxFgsQAzZVwARCZCYSsCMUEcIOkAMyAAADEgAAARIAAJREFETERMQETAwCE+AAQinmAAIAcgaGAKAFMgCUAPAERArgARwAAEF1QVU1dgQKAAAxMRFzElCEBbAFVAAAFTMyAAATVVIAABUxNgC0AAARFEIBEhiQA1YAAgKAM0ERMzwAABE1VAAAExMyAAAFVA"
Data "AAJTMzMgEwJRRBUgouACAABFIN0AVSAPII6AAgBBJWEANSU2IAQANSG+QKwCNTVVIAMgvwRVVAAAACGGARwRQAAAFCEdJa0AVSAAAFcgAwRTMzMzdyPQAUVUICJgACGUIAALEUQzRBVVMRMzMzVVQAAAM0AAAFVAAABR4ADKAjExESAQgB8gbSEgYAsAUybTIlsh8wBBQsFmuQEUESb4AlUREyAGoAIBNTE0igBVRyEBQUQkqCDGIc8CFVVVI5bBYQMTMTExYH5gViAAA1MzExOEqCAAKS4gLEEFINtEHUBsBgQ1U0QTFBNHLkAAAEQgACJEiKZAZSCMJRcBRVUgrEMSgFkgrAFVdSBMBFNVVVVRI/YJdXV1VVVVV3UzVUAHAFMgGQJVV3cgAAlXVVVVM3VVTQU0oK4ARIAAAjNEMSErQMEAFCABITpAAAA1IGMDdTETMyAAARMTIAYAMSBYIBIAUyElIAYAVSAAAjNVNWT6AVNVIKAgOEAD"
Data "QMgARCxLBVVTQRERQSWOYAIEQzE1MUMiJyEqgAAgIwRERXNVMUD54AIAARQTIFsANSAAIKcgOOABAEEIAjVVdSAHIAlAqCNyAEQsRCXrAjNEFCEVIAQBQRQzKCCKYHJAAABBQAAw4yCfAFUgAEElILBgC2AFBjMxMTMzUzOAAAsRN3VVVVU0QRERERMgAw0RMTExERE3VU0DNEM0RMAAAxQUFBMg5gEVVSGQQJ8AFEDuIbcgWgQRMzMzESAyYAMgAClMgAAAU0AGAVdEQAUBVVNADCCmAUERIAIBFBRAAgBBQx5gvqC3MMggEgAxQBsBFBFAACHvAhQVVSGeQDhAACAHABFFWyKmYAADVEREFCBMAEHgAABO8gBVYC4gFkAtIEIiVwIRFDFAIiAQIBcgBSGjIAkgHABBIE5AAEBmIAAANSADQKiAAEAJAFMgbgAUJ4wAESEbJWUg6AM1VVc0IA5A8AIREUEgFwcxN1UdAxQVFCAAAUREIMog"
Data "ziLGLegg74DHQABAEAA1IbUCMxMz4AEAABMgUgNVVVU1IANABABXQHFAAAB1IPQgW0CjIAAhMyA2JEogC4AAIHYFMTMxE1cxINIgWEAAIAcCERFDQT0gByAAgD9ACCFBQAABCQEgE0ACoAAgJwE1UyAFQCNgBiJRABEg7wIRQTEgEmBPIAcAESErQB4gLUAGYACgUKAAAVN3oAgAVUKHYDMnSAETMyAAJhkAM2AQAEFAACAFoSuD5EEqIL8BQRMgawE1dWBggABAdiBkgAwAEyR1ADOgAOQBsyAAoHZD/QARoAAAMWBEKpgBdVRL/UBcQBEAQSErABUjg4DEYAAgcgIVV1EgaCCVQCJAAANBEUM0gNoCdQkTIBBAHSFFIAJADABXI+lAQUAMIAAgFUHfABEirSANIA5AbQIUVXNADCANAUExYBAAEcF8wACgtANVUAERICBgAoAABBMzFVUQIC+gXyAaBRMzN1cZQyErIw8j5iADIGJAlyWM"
Data "4AYAADUnGOABEgAxQS8CNTFV4AkAAnMDdUEG4AMAADMgO+IBVyAAQSsAdSCJ4AQAABVi8uAEAAQTMRV1VSAAAFdhK+AEACLS4AQPIAAAV0ARADEgCOAAAAIUNXNMaeADAAI1dVXgCwACMAMR4AUABDMzV1Uw4ALwIm4DMVdXOSErQXkj32GSIKECERQ3IxDgBQAANecE9iAAARMzJ8lgeQBXgAaAACJXAnUxEeAEAAMzM3UxQlfgAAABMzOBteAEAAIVVzBBpeAFAIJXAXcJ4AS1YAABV3VgBuACAAA1QBHgBXoCNXVA4AY5YXwgo+AFAAN1MEUR4AUAISsAd+EGKwEzVyErAREzQCci3CJdIAlAsQI3dTHgAHVADwAR4QIrABMiVWCTCDUzV1V1V1dXVSAG4AAAAVd34QErgCYFMVM1dTSUQE8BMRNAAiGNAFMqnCHxIA9AAAATIAcEMRETdzA/8iBbICRAFWAdATV1QAABd0k7hwARIBfA"
Data "AiBCAFckiiAAYLpAAEjEQCIgNyAOgCggPgFAlCAOgA0gBUbLAFcgsAE1dyAFQAABVXVgAAJXMEMg5YACgAAg2wN3EBMTQIQAMSBSIBpAEQA5IBCAH0EtQAAgDiLPADElvUACADEgASjuADUhPeAAAAATYAAgPYAAAFVAcmAKAFVACwF3MWA4YGkgCQUTNTV3NARAEyBpABMl6QcTMzUzNXdEMWAMQCAAMyCSADMhKwIBMRMgACAMIBRgHSDsIAAEV3VJQzFAAAATIAAgHUBCAhFXcyFjQFRAKyCgJXoCdTNAQA0AEyAEICUgACHyAQmRIByAACATADEjRwRXV1VXdUCwQAAAV6AAISsgHCnAIEkgAAAzIc1BKyAyIBZgyQMxNTM34QErQlNAACC2QuEgIUAAAhExM2AJADdhASAbQABAPiEDIpWAAEGnAHVAAAF3V0AAAVETYAAge2AHBVM1d1QBMUAAgIkCMTVTImoAFKAMQABAJwQVd1kD"
Data "M8AMQAAAMSAAAjd3VyAABFVJQzMTIAAAMSAAIDUAM0CbAld1E+AGACErAElgIiAAICVAAAI3d5mAeEAAYBMGV3V1dXdXd+EAJKAAAjQTMWAAYGZA5ARTU3d3FCAIoBEgBwMzUzdnJCUhhgARgAACExMTIK8AMyCJAjMxM6AAADFACQExNzUDADEgAWAAABMgBU8zAld1d0ACAXd1IAAGd1d3d1V3Z0APAVMzYAAAE2AFBjMzNVV3NAEgBwAzIDNAAAYxNTVTVXdEQAqAAEBgImkAWUl4wCRgAEDaAHcgXiErQABAUGArADFgoeAFAAAxQSsANaATYCUgEgJ3nQOgESANQAMFV3V3V1dXYLUAdSAKAHVgBAJ3d1RAWiAAYAYAMSAGBFVTV3cUIAlAAkAABxMzNVNXdjATIA8CExMRQAACMTETIAAgGAJXdTMgAOEAGyAAIlcgBWAAIAggAgEzMyNbAXdXIAEBdXUgBAB3IAQBV3dgBgJ3UxNA"
Data "UyAABzEzMxMzM1VXIlcAM0AMoAAFVVVVN3dAYBtAH0AAIIsCdTBDIAkgMiAAQAUgOSMIAHcgYQF1GUFFQA9AF2AIATN3YKEgEAATIAFAFgYxV3dRADVTQCUgEYAC4QArICAgGCAFA1d3dXcgAAB1IAEAV0ExAHdABAFXV0ErICBAAIAGAlNVViEroAAAMUAHADUgswAwIHADMTMTEyNtABEg4yAAAFMgo4CJ4AIAAVd34AIMgAACVVV3QAAAV2AEBHV3d3U1QAkgAAFzM+AEACAnAFQhK+ABAAZ3VVVXdwA14AEQQAAhKwBFQAfgBABAWyDeARAV4AQVQAAgoQBEIKjgAgAhkQGQNeAFegJXd51Bf+ACAAB3IKYAdSCrQAAgXKAJAXd04AZgAzVVU1Yl2wAz4AIABVVVV2dUMyEcBTEzMTExEyAGARMTImzhALUAUyABAjMzNSADA1M3d1NgCEAAAVM1YBcDVVd3VyB6IAOgAMErAHVAKWAu"
Data "QAQBNVUh8QABoDNgAAFXVSASIlcANSANQANAUCODAjAVU2AvIBUgOGAZQGAgAAE5RSAZAFMgAQA1IAFAAkChAVMEIBRAOiAwILIhGAFUlFH/IAAgn2AUISuhBCA8QDsBNXehHaAGwAcAcSAmIDFAAEAGAlM1VSJXATADQAtAACBeIBIhKwc1M1UzMzEzMSACQBcAM0BvAXd3IUcDVVNTVSA0AlU1NSACI1kgDmAAAFMgCCAXQQPgBAAAVcANAXU1QDIgNCAjIAkhGAFRQSAIIDNAAABTTFkFd3dEE1VTIA5AFQA1IAAnxwBQIREgC0AVAFMgBCAZwXwBOQUgEAA1QANAHSAYAFUjgwFTAaAQIA8gWiRgA1GUVXMgOECxICcHU1NTV2edFVVAAGApIEDAUOAHAAJzExMgImAAIE1ACgR1dncwBWBMYQdAEgRXZ1E1M4NwAjExMyAAADVBKyBSADVAAABVQLtAdgBVIO8gkEATIAAgjAFTUyAT"
Data "AVZ34AYAAFeADwB1IBsAU0AgYAQBNXUhZy2aIDWAACErAHVhK4BFgGACNTd3TNGgciAGAFMgLwE3d4AAAFk2hiCKIB1AM0C8A1N2dVNUL0AQYA8hgSErAFdAH0A6IC0gQwJXZw0gOUAAIBcgKiDF4A0AAnUzFSAhYAAgTSBnAFcg3AAwoDsgSSARClV1V3ZRNTV1M1MzoAAiZAE1dSHPAWdVQAAgOEAAQAYBV3dACYAAADWABgJXdncgAABnIAOAAAJnZVdgCAF2d2AxgAQgLAV1d2dzQVVACaAAAVd1IBIBRDNgDUBbYAACV3cx4AIiADUgEwA1oGEDd2dQRSAOQABAFoAyA3d3VQMgEQBTID8gAiAAJGAAcSErYACAESA/QO/gAgABNTdgsqAAAGWgBwJ3d3YkNQBVoACAOwB1QlfAdSBJB1VVV1V3dnE1IAsCNTUzgABBUyAaIO7gBgAAV4E94AMAIE4CZ2dnQAMAZmAFINQAdkAAIMYg"
Data "AAB1IAMAVyADJdkDV2d1ESAH4AAAAXd3IWYAFCB34AQAAGfgBCNgAABXYFcBZ3bhACvgAQADd2VVQ0Bi4AEAIZEBkVfgCBIAFUAgYIdAGqBQYAADdmd3dqAAJHLgBo0EV1d3ZzBgO8AAAFch3yErAnU1VYEsISkgMwB1IN7hCBmBAOAEAAB3QG1CVwR2ZzdndmB4YA0AduAAPGCjQGQBdTPgAzkBd3chZgARIGmgAEKyIVAAE6AO4AEAIFMh9AN3ZlAX4AEToAAhzSErAVd1YGJgAAN3dnORQEngAABAeABTIyVCE6AAAVd2IKcAd0BTIKogCyCvYLk2H+AFAAB3IBoAMOABoSAAAFcgNUErIngBNVMgACAHIABBKwR3VVdVdUAAA1dXV3VAACE9IJcAdWADIAABV1dCkwBnYAADZnZxF0AIgH4AZiCLICcAdSAuAFchniAmIHYAdSCyAHUgPCBUAFUhiSB2AWcRS+xgACErIAMCV2cTYFXA"
Data "YUAAQMogAAN2cBd1IAAgPCBCQEcgCgNWZ1cTIAcgp6AAIlcCdZR3IHYgQSAkIAMmbAJnMUFAHiCHYDYCdVdnIAAhzIAAAHbAAAN3Z1NXIDAgVgB1QAAgCiChBGZQN1dXIGAAdUAAAFchBgB2gSsEVVVTU1MgAwBVQAADdXV1Zit/wABALgBXIMogLeADACBGAWZ2YAABd2cgRqAAQN0BZmdAQsB4BXd3d1Z2dUFwbFkgDkASBHZ3MTV1oAAgEARXVWdXZyl3YBEBd1dgACFuAHchh0AAAXBHIE0Bd3VgAKAdAHYnbQB1IQ4AV+AAACCGISsAdyGZAFUgBSBKAHYgPwNRmTd3IF8AdSA2IBGBKyPU4AIAAXdnQABBK+ADAAB3IEYAUCAyIjQAdYAABXd3d2ZzN6PkAjU1VSJoItUguSNGIF2AACAlIIcsvSAAAHUgFQB1QAADd3dXV6ErIGwAZqE1QAAiVwF2VyAAAHcgAABXIAAAdyGiAHZK"
Data "pgBXIDFADSC6AHcjtgFRN0ARQAABVXUgAAN3V2Y1ITVAYIAAIBHhAIIBZEcgNKAWoAADdmd1NyAiQCaAACARAXcBIJYAd0ADYEYgZQNmcw2TISEgE2AAAVdXgKgAZ+AIAEGJgDUgAAB1ID4Dd3ZmUSEMYOggAEAIAnd2YyByJC1j6QA1IBUBVXUgFySJ4AEAAFdAfYARAFcgs2AAIEMhZwBnIAAAZoEyAGciAkACIAAl6SAAQMUgBkAABGZmdzQ1QAhASCBDIBchjCAg4AQAAGfgAFxAACEHIAYg2gBnIFkCY0d3wABAFSAAQRkgUiCGIAJgAEHPAEAg8qBgIAAOV3VnZ2cZoBMTMTMzVVVXIAAiLCBNQFJAACBcIABABgNnZzF3QDegACAnAHcgoQF3ZyAJAHUgCoHeIT0BdVchNCAAA1VVNVUgAABXIAAgFgFnd2AAIAoAdaApIBEgDSAAIncgBSAGAXdmIlAgAyBuIHABZ3ZACCAEIAYg"
Data "M8AAIApAEQFxAWA0oAAAZyAsKjuByCATQAMAd2ARoABgECctIXcgYwFnZyNI4AEAYBwgoQFUViBcYACBZQNmdzsVYA4gWCB3ICYKdmZncwsTVTMzMTEhLQFVVSBkIBIBZnYgkUAIIFojESBjBWZnADdnd4AAoFMmUSBAgACACAB2KDMjCwF1dSEqQAAhNwB3IAAAVyCJ4AYA4AkRIHggxSBvAGdgASB9QAggBoJX4AEAIBMw4AI1d1UgAAB1YF8Dd3Z2Z3YfAFcgAAB3QAAAdSBNAVFFQAngAwBATAFmdiAsATVVIAABV3fgAgAgjwBx4AUvIBECdEN3oGBgACNxAWd3I+tAACHhID8gm0CkIJEgWkACQAQgEQJnO4AgHeADAChSAVAH4AMQAXdnJK8DE3d3VyAAAFUgAABXIAAgVQB3QHfgBgAgdeAHAABnQHMhLuEDKkASI5bgBAAAdiCYA3dTNVUgAABXIAFB3gN2dmZ1MBgBd3fgAtoC"
Data "ZnMBJsZgAAB3wAAgOgF2ZiBjAFWKLABXQO+AACLHAXczgAogrgJ3d2chbCt+ADMzVCAQgAAAdiA7IAkgGuAAAABnIExAowB2IAEiYABmQAsgCAZmcaigNTNVIAAAV8BiA2dmcKuFyaBQISsBd3Ni4ABXJKgGVVVVdXV1dyAAIhoAZyMoAHfgAAAhZuAAC+AAAAB2IGkgeWBsgABAfiAVJd8AZ0ABgBQgACHPAHZATQBnIFRAB0TCQG5AcAFVd2AAAXZmZxokZWCBYAABdmYgAEAEICMAVaAAAHeAACAuYEigACCdgBFIuWAEI0QghyADQAAAZ2B3QI8gAyACQBdgA0ALIAMIZndQsEERwRFVQAAAd0AAIB4BdUrJ1gFXdyA7QStphwFXVSAAAHfgAAAgPGAAINgAZ2AAQIlgCIB0YI0hUQBmYAAAdkAFAHZgAUAAYA7gAwCgJuAGAAB2IAAgaOABLSbZAHcgAAB2IAABZ2agAGAIQWlADwB3"
Data "gAAAdkAGAGaAGoAAAHZAAABm4B4AgChAWIAJIAAAZyEIAHVBAwBXQAABdXchGgB2IHQAcyEjYABhviVjAGco/GN3And3Z0BAwAAAdsAIwAAAd4AAAGcgJQF2ZuACAGA0YATgCQDgBCjgBgAAZyBI4AUAiH7gGAAgNwB24ARYIOrgDn/gDgDgAj3gCDgCZ2d3QADgBRchvOACMyAjIDcAduAChAB34AMMQAAlY0AG4EAAAHfAAAB2QFngAnngHAAhHgB2QAAAd6AAAGbgQgAjI+EDGiAAKFYgBYAAAGcgACB7IBDAJAJ3Z3dgAEHsIBogGeBKACBWA3Z2dndgAMB44B4AAHegAABnIJ3gTQAAdiCbAndnd6AAwT0hCwFmdiAMQd8gDOABAAFnZiATIS4AdySc4OcAAWd3IPglUQB24Aj4YRXgCBXg/wDgAwBhKSlCAHYgAABm4P8A4A0AIR8AdiAAAGbg/wDg/wDgBwDifSEAdeAHluBoAOEO"
Data "BwBn4AOI6DNsAXZnK5oAdyAEAGbgDgCn4uAAAABm4AIA7wCtIAABZnDgAikAZuAXAOAQbuAP8OAaADHlwAAAV+gAY0AAAXZm4AEAS6XgAwDgAxvgBAAAdsAAAGbAAAFnVyAALZUwewFXdihAAHcnOSAH4AEA4AKAYAAAdeADHQCTYBJgAAJ1dmHyAXXgEYHAAOAEsuADcUCB4AMAIJOsegBm4BcAAHPRogJ3dTfANEAAAnU3ZuABAG/C4AMAAGbgAgAAZ2B9LO4ANzNuYAAwaABmQAAHdnZ3d3EzUzVgAgAzT7Ev3gIzUzMgADf5AHegAGAP4AIAoLlBMgFh0+ACHAI3ZdDgAQ1AYIB4oAAAZ6AHoAACZzNV4AQAAHfgAAACcTVV4AMAAFc11QFVdWAR4AdD4AMAQW0DZzRDM6AAAjE3ZaAJQAADMRdnZuAAjQM0DUMxQBTAANz0A2dndVMgEwBTIAQEN3d1Q1PBFgAzMZczKiCGAlcwEaAA"
Data "BTERETdXVEAMIAkgAAAzImkCdXVXNHkAMS+QAcERQAAAHCABABFQAS5cQN4DaSMRE6ABBTERE3eSM6AMAhMRFyBbIOPgEAACdxEz4AIAAjU1VTSCIAMgAgFUE+ACGCAAA3VVVRUgBiAAIB3gAwAAV+ADDABVIVQFdRkBMRERIHwEETEQF3EgBwATIAkgmAMxNAV3II4CV1dVIAAMV3FN0ACQsAAAAEREESAAAzV1VXUgAANXdTMRoAAGMRFBdXUBAEBKIAACMRNEIQMgAAV1VVVARBSAAAVBQUQVVRBADSADBUFEREQENSAAA1VVVXUgJQA1IAdAAAFTMyKbAFUgEQs1U1UzdXVt00FEQcRAAQYUxBRBdwmUIGgMRMFEQUQURXdTU1VVNUAnADUgKz2/QAUAU2APQAUCUwQR4AIAARMzICRAFiAxAVRDIBhBgYAABRNVVTNBMWALADVAIiAhYEAgBwFVNSA1oAQFVVVVV3MJII0gxiADBkkX"
Data "VEQURBygAQREk3dXUyAuQMsDdXdVMWGnAFUgEAE1NTjtIAAgBwIURERAtyAABkQUQFVVkNkgCUAAA0FEQBUzgSI0ETNT3URARAQExARMQEBANVHQBCANIA8JQEREQEADUzM1MSC1BBMzM1NTIGuAAAJTExEgwAAzIAADNVdf9SAnAERAAyA0BkA3Tu7d2QRBZgREBAN1M+AFAGAx4AEAAlOQEeAEAAE1M8AABVCRERERFCABgAADQzMzNEARIBMCNVMz4AMA4AYOBDM1dC7RYHwFREAACRcQQJIARCCJIAMBSZVjXgUzVVMRERNBfCAAIXQAU0CTIBAAESBXAlHZREAAIPggyQQJNTWZ3UAKBgQEQEBECQMg6QFVVyAsBtIQBAAAQAAgAARABDNZ4EAHIA8gEwUAQAEzMzEgD6AAAgRUlKAJIAAAQyBeBTMzN3//FCBbAEAgAAAAIAAHFx/p0u7i3ZAgCgFAAWAg4AIA4AYPA1PdNETgAQAC"
Data "QREz4AAAAlDRREHhgPUBRERhK0H0A0REFTPgBADhAV6AAA01UJLpmZCZmZAJmZnZN2CRQOsEQAQEDQcg6CAAAVEAgAAABCIfAZM0gAtAACBjAVDZYDAgBAtAAEAJFTUJ3gQAAAQgDAIEAEnhAisBAEAgHiAABAAEU3LkQAdADwMEBAQAIO8hHyA+gAABUJTgAQsickAABVXv7d2dmUAAAEAg1QRVVJRERCCnIA8AkCA74AUAgK3gAAADU94BQeACAOECKwI0IBQgACPGgAAEEzMzMAGgCuEFb+EHKxAzNATSLi7d3d2ZkEAEVVFERCD0AAlhOQCQoHwBUQDgAQABkRCACyDsBgCTMzNZ3UAhVQAAIPUgBAEJRSErAJQgC0EYAgRJk6JXAVMtYlcABCFEBASQU37kITEgLEFQAAChKwAEoAACADDUYAsgXQBAwjYGNWcQmQCQREEnQAABV3VABQRTMUQEQSDi4AUA4AXZBDU13dERI1YAFEEU"
Data "AkFEEeACLgQ17RFBESAAAEGgAAYzMxEEFBFEICXiBpvgBVFAAAQUFEQRNSSGA1VVV1VAAAJTMREgYwQABDVTM2AAAFGAvCAABAQAkxAEYAAg02ErAZ6UISUhOEAiBQkDNU3ekCEoIQgiV+EAKwPuFABEIqoIRERARJRVP+RAIC4gAkAxQRABNJAgDCAAIDcEAFDgQABgCCAAolckAgJVVTMgAwJVMxEgqCNLABEmXAM1VTUzQJ0BNVMgAAEzU0AKADMgDCADAzNTNTMgAQZTNTUzPZ2ZIZ8AQWEWAhQRESAhoAADN+4ARCBnJPcAFCAAAkQEMyCEAERAAABBIWEAM2jUATUzQACCLABTIEwgACBdIAoCU1VVIRwAQSCFQIsCEzVVQAAAUyaRgAABVJBCEyDcIN4AkyJXQNVA00JXAZ6UYBggGQkABAmRVR2SkERAIPsgAgAJYSsg4QQ0n+BJCSKqAQkJIooDVT8hBCDAIKkheGODAVDUQAwg"
Data "DiBDAjHtECA5gA/DYgExEYAA4wL8AQAAJOdGFAMTEzUzIR0GMzVXd3d3VyAEAXVVIAALURERE1NTMzNRCZCQIHcgAAUAmZBEEzPgAAAJNy/u3d3Z2dkACSAhC5CQABMzMd2Z2ZAEQCJhATNTID4BEVUgAAN1d3d1IAMBd3VBOAo1MzMzMTExNTMzM+AFiCf+IYcAEcGJAFQjnCDIINwAQCODQAolpCAGgSsAACDdYBAIAECRUzCe6UAAgAANCZMxE1UzNzMRNO7tkAAgkQiQmZkJkzdPBUAgACA9IEMBAAQhEAFZ1CAMIDwAACAEAVPuIYogGUADIBpgAAARoAAhaeABACIKADNgGWCnBBERF2d3IAAHVVVXdXV3V1Eg6wF1VUAAADMgAAMxQUREIkJA7QBTIA5gAAE90CJxAQAAQFIgAwEEFSBLATNTJKsBNVUgACnsABMgRQVXV1V1V3cgAAFlEeABAAETM+EGKwAJImFgAAAzgAABUNAg"
Data "1QAAIMJDWAA5QAsgCSEfISsCUJnRIONA6QBAITMHkVNRnvkJ2ZkgAAbQAAkDERM3IKEEEROf/uIhxwrdnZAACQU37/4URCAAAkBEQCF8AQQDJPIiV2BAAUBAISsAQEBYAAAgUUTKYAABMRGAAACZQC8gACAcIo8AMyDe4AEAARQ3O+5gAABVIOEAcyC4YegFExMxMzNXIBcJVXd3V1VVVVdTM4AABVUzNTMzE0D5ADEgKSEAAVN3IBgAEyAIIG4BEzNdkwF1dSEqYAABZxHgAgACEzMzJVQAQCCrIAMgAAIJARGAAAAzYAABNT0lcUAaIAQCSZM5I5AgCSCvQ4MDU53gESAAAEEhuxJEQACUVTOZ7i7i3S0t3dmZmUMRIyEiVwURGe6d3ZmAAAQzNZ7/7SZFIxsAAEAAAEVBKwAEIFggAyEFAlHfkGF0IS0nMgAzYAAAEaAAAAkgdUAAIKYggAAz4QQrBBEWZ1dXISUAdSIPBVVVcxExEeAB"
Data "AAVDUzETEzEgEQQxMRNzMyA2IAMAEyADBDMzU1MzITNDYQIzM1HCH0AAATFFIXMBV3WAAAF3Z+ADGgAVYLAgn0ADIAbiBlcBNT0kkySOIAMEAEmRWSAh30CwCQQAkTMzMwLuLSIhGkEbI/EDNTNACSa1AAAjcgIJmRFCVySvARERKlsPREREExQzNVNVVRDd0uLi3UE8ApCQBCEJQldBBiEDAgFUn2JkYF8AACDJADEgAQARoAAACSAlQAAgoCFIADFCEOABAAIXdVWAACBgBDVzERREJdEAFCADABEm8AEwBCtfAkQEBCYWAVMTJ/UgCWAABBERMUAEIAUFExMzEQEwYCwBFBQgAibpBBVzNVVVIAJAAAJXdRHgAgADExMTOSCjAEBDRkAD4QArBhMTMTMzMxUiVyH3YBoBSZEmqiCqAABgLQWQMRM0nu5AAAHt3SD9AQQRLBsANSd8AEQgqgITERFLewA1gOsAEyAAADRmOys+AhRAAI0o"
Data "BRE1UREREIJXQQIEAVQO1JkhaWAAAJmAOeAAAAANIUEhriCJQAMgS+AAGSAAAhV1M+ABAABRQVcAAGAABERAAENQwFEBAEEgUgAQoA1BcAAwYAsBQEQnjwFZlEcaoAAiiwFTM8AAIXrgAgAAECMmQLAABCCvII0BBAngAhsgAAEVEkODIBshIwNJk1TQILFAsAQEBFGdEyUPQAAhyABEKO8gBkGeBDERMTERQACjg4AAABNlTkAAQSgEMxMTETFBTwERNCBQIHoAQCGLBQFTntCZmSJvIpcBAAlgHeABAABNIJ5AdyB+IIgCERNA4AEaIXQn6OAAAAJTEZ0gIWBRIAACAzAEQABADkHAABQoomAMIHQAGUB6YAABBFAmk2BZAEAghwkRFVMzUzU1NTNTIAAANeIEV2ErAAAgJSENQAPhCCsA0SA/AEAgAwAEJbABNNQgaiBWII0CU5mTIjsCETExJQ0DFEREAKAAAAlOmWAAhdvAACl5IKQg"
Data "OkAA4QEIAhUtVCKzQQgGQAE379EACScvIAAB3d3gAEZgAAITHtRAnkBCIHoiV+EEKwQVd1MzM0ACADUiyQBRISsgIyEMIG8BQAMhFYACAQAEIHUiVyAVIAsgHCErQAAABCAKATEtIFogGEA1AABIcgA1IE4AUyBMATV34QkrICggUiDKAQQEJGngAwAFE07pAEFEIB8iTgYNAzTuQRREYA0EADWZlDEgfSAAAhNAACB9ID1AAABJIUGAAOIEVwE0kEBCQYwgBwAA4QEIAxff5ERgACErBTNP/tkAnS1xAwkJIt1CouACAAFe4WCgIM1ARAMRE0Qx4AIcBDV2d1VTIS0g4QBTI9giVwBAICUg/iBpIwEgDQAEIAAAACODABRGmyAPILGCVyAMIFgCQ9JEIBJACyAGISsgSEJXAzM1V3bhCCsA0yBXIFJAAwAA7wafBRUO7d3ZkCELK3sEmUMx7+kmxwAELhsECVUJmTMgAAMxERERgD0gZyAA"
Data "AACPsyAA4gRXADAi8IBfICfhAisHET7+0tLd2ZkjewqRM1Tv//4i2ZkJnSAO4QYrAz0jREAgAEIwIG0hngAR4AIABxV2d3dXVVUzIAAANSErAQIEQK6BJAJDAAAgdyAzAUAAQs0AECosIAogAwBAQSsgBUAKAgBDAkyAQAsgBCErISwCMzNVKo8AdeIIVwI57UEl/yIwBUREQEDQEeAEABQVDtnd7u0t3ZmZmZ2UUTSd3d0tLdkgDASUVbmZRC7CBDMREREAIY1BCAQEAAAEQOEBKwE1M0gzgAABMNQglyAeAAAgmwAE4QMrAjNJACTKJaoBMzMzFggC7d0u7u7u2ZCLDuABAAE5/THLA0BAQERABgAB4gZXBBV2dXV3IAADVVVVMyODAZJAIABgkwIAADGEoGCeARERglcCBAQAQAEAOSG+oJICQx3UIJchKEA1AEExQgVTVVVXV3chKgF2cyA14AAAADAlYAMuLd3dQdwn8gIJ1BHgBAAG"
Data "E1RAABRAkEt3A0E1MTMm2QAxLmcCRACTIlcIE5mZ0DMREROdYGVBwCB7AJFCaUAA4gRXKBtAiCEnIAYgjuABAAAzQJgAVSAFLC8rPwAUIfYgEwAz4AEgYAADMf7e4mGwAgmZmUA+AEAmTmAYQAAHE1Z3V3V1dXdiXQMxE95EYGQgjAJABDRiMCAIIJ0gMAAQQSQhOUCHABAhvkE3IA4CAVnkQBEgJyA5AxMRVVVASwB1IFEDV3dREeAAAAFERCLNAhQR0iEsBtLd3Z3d3d3iABegAAAVQo0CVTFBQxQAQSIrFDM1VVU1U1MzdcEzXFmZmRUzMzOeQCB0AgBAQEB2AUDR4QAr4gNXISsgjSCwICcAAEC14AQAARQA4AEAAAQo8CIAIAPgAwAFExmZ2dmZIAAqyCXaAhM0RCC6AUREQCYCFBETI4PgAAAEUUGdMARAAAAAIAABATQg4CByIAIjaSiiANAjPQEERCRPBkQAMO1BQUQgACRQAgQ0"
Data "7iFEIAsgLQQAFEN3dyEkgAACdlERQAAwhCAAABFVPwFEACI5BQkAAJAAkOQGroAABEERSZQA4AAABgQTV8fFVXwgBAdQmZkDEJQxnmHIII8ABCCg4g1XAj2RQCFPIB9AJkIY4AQAAUkAIMoAQCADQB4h/uALAAAzwmsBExEgAAETMyAOABQt6gBEITABM1Nhz0IOBHVVMQROMfgACTJYJWUBQQ4vFABEJ6VAdg8REREw7tkAmQmQCQCQCQQ0MxsA2TCMIPcEQBGe6d0gAACZIrQEkEBDVVUgR0AAIhgBUzQhXSoSAEGAciAAADEgASAAoAbgCgABTdQgySEJAAQgABKZMVXGx8fGx8bGzExMTBnQU55EIZUgjiADAETiDVcCEw7SIDoBREAhLwAAICUBARHgBAABEwki+wEEACEpAEDgCRzgAgBhJeACAAITEzEgDQITFDEiXgFEFCAEQAAGFBMd7ZmZmSEhIOQAEUaZANkhAUAAABEhK0M9"
Data "AN0gECAgAhGd3SNNIAAEmZmZARFKuAYJ2Z2dkAQToEgAEUBRK8pAYwIRMxHgIAACFE3hIOsEAEBAQAAqrQQTXGxsfEAACnV8fFfJmTWdBAREIAABQEQ2hwAJ4g1XAD4uCIdOICjiBzohKyBXAEBhKQAE4Acc4BQAYMfA24AABBQxExAEIgUDVVU1MyJ7AEEsJwCZIAAgtwARIAAAREAAoDAAM0ABADMgQi2BAVNVQAAAUWwQoB6gACZ2IAAgJeAgAAFJJCH3AEBCOyqSI4OAAArMfHx8e5lFTuBJmSAAAd2QIAQCAAMRoAAAE+QDrwcz7t3SIt3ZmSAAIxsBExHgBAADEwlEQEEoIYwgYwEBEeAhAGDCgM3AACIHABMgX0DwQ6ggAAJTUxEiJABBIAQEERExNVUgAAJ3V1cgBeAAAAAxI+AFMREREUFRIAQlC0AF4AAAQEggNyAD4B4AARQAK7AgyiACBABASRV8IlcCbHx8YAMOXJkDXv7e"
Data "7u7uIi3d3d2QTXWAAOcEBwATOqIphwCZIAAC2d2U4AZ5ABM5nCR7AERAYTh1ABHgIAAAE0ApABPhBSuBPwARIkhBgABEJM6AkqBzAxVTNVRT1CJ2BTVVUzdTMyAAAxQJQEAgLChhABFAAIAFwAChZOAhAAM0CSlEIAAAQCAABUQESUVXx+AAAAfGxQmRUO3ZmSAAAQAAVH7gAGniBFcgAAETMyAAJAQBREAmkOAEAAQT3u7u7W82I8wBBAHgBBvgFABhKwAU4AYwYIAAE5k2YAAAAWARwAACNTUdYKYAMTCrARMRK58ENTU5kACAAGBP4AYAADRgXuALGeAPAAEN7mNgJjQFkJkJFVd84AIAAQmUgR8CMzEzgAigAOIEV8AAIKEAMeAEJWAABjSZ3d3ZCZlAAAGQkIMs4BwAYMEARGAF4AEAgRkA2UPUAEBABOEGKwYzVU1EQAAAIZYgBAADK6IDNVNQ0CP6AUAEyyOAQMAAABNiWOAGY+AI"
Data "D+ADAAlA3i7u7u4tLZAAJQgCM3fH4AIAAcCQIPwAM2kV4AQAABPkA6/gBQDgCHkCVVVTJmkAFCa5AABGruAHAMAvARMTJa3gBgAAFMAc4AQAML9hJyQ0AEDiBVcCETeSI+ghHCEuNFIGNTUzMRDQBCEoIBOBpuEFK+MI4yARATMxoCMBExMgDuAHAChhQAAp9wEzMy99AFNF1iADIAICfMCZ4Awx4g1X4BMAMLEAM8CE4AUAPJygEAAxIJ5zVwAxIAAAEUAAgN/gAgBgFgIx7kQqcCQwIj0AQ2AR4AAAABUqDkJFIBoBBAQt+SX3ANlNPieL4AhLYACl6wIxMTMgnwAzIH4CMRMRgAAioOAKMkHRIACAJAU1dlPMfMchJ0ACA8fAnUPhCe0gAOIiV2AAADFgBeAGAABEKgQvKaEqABNAJKCqADEgAAARIACAkuAIAAHvIC+OKnQgAAADYCfgAAACE54EISYCQAAAInQABHW5SqFgAGSaQGPg"
Data "CgABExNAaSCBQE3BLQAUZOIARKCe4AYAQCgDETNXxSElAMwgAyACA1zBEENgP+AHAOQBr4AeYDqgAAAzIHQhAyAD4AAAJaJAITE1QaoAGSDpQBoAFENiBRN3d3ZJMS3MQJRND0DTAURBS4igRIBJIMggEGAABRSS2d2dmUAAAADhBysBEZ0j6CNwIAAABFbGAxERFN1YEiOuQFeAAIBQgTeACwBAQHxgfSmoRCw1IwNXd3dxIIEjbiAAoLIpzwCUIA0BETEg0DSGAnPFxUJVQSkGx8zHxcXDxSAVYACCeICxglcAEyAXQF0CEUmQYX0ANWIjATEUNFIBFEAgdSAAATQAQR4viCCqAxMEU1UvzQERQCRIAFEgGwl3d3cRERV1VVcQIFQDVTMQQ0CmBEEAMREVNxggLyDBIVoBFARXOkAMJekBSQlDGAAzIG0jMAIzMzHiAPQAMSABQI8DntFEQEAAIl0g8CAAQCUiASAJMTMBkJAohAFERES7"
Data "AkREREChYAwENAFEFDUhHiATIFkCBBM1IDECEFVXOQoCETd3T2EFE1U1MxARKswCVVNQQJIACTmeBhETmAPMfMwgAiJUIAIIfMXFxcMzRBURIAAARFL9ARNEIfcuZWJXATExIGABQREgWQIzMRMg/AIUBENKGQczM1QBETQEE0ALWV8gGQIXdVNMsgMDd3dUIGMBlHdggAIRV1U78AMTdXV1Ib8EV3V3dUFAmQh3UDERV3d3dxRKWSBaIqZM5gITFEAuaiEbQFUgYqMoABMgG1HiAhQEFCEaIQMs98gkQQpgAAATKEFhLDZABTExAABARGANADFAkgk1VVVVETBXd1d3MWIAdyAABBERF3d1IAwglwBXIGsCV1VXIThB1gB5K4gDQXV3dCAGPR40JgMVPDxcIlYgAkEwITEhMAIzEUQh5CEMAjMxEeEAHCcHBDV1dVZRI0IgTAJ3d3cyCwIVVXcgZCAMAXUBIHBAEUNhQAcBN1dzVwIXVVUh"
Data "KwIRRXUw2yAbAXVXK1VCVwRTEUN1VUCUAzdVdVcgIQBXIAwhSgB1cTUAVyBcADFhRQJTMRUgCwURERAFVVUgxgIRAUQ5FQEJQSIqCRFAE1EQQROdAREh8ij4L0ICmQABSBAiJyAAIHEAUyE6IIYCcxE1IFAg6SAFIjECE1dXISUCNDdVQJEDQXV1VyB3IAxhwwBVQlcCV1V1IetAEwBzIlABQXVBJAMUN3d1IEEARUSpISAhKSAJISgFfMfFMzV1IJlApgBRQGEJcRF3N3VzNzU1MyBZAVETID0AMSAEQFdangAxIZAAVSErABVgEUAMIBIDFFdVVSI7AhRXVyCEIQQBVXU+AUAbIHEAFSCgAFEgLiAGAzEUN1VAIQEUNyAhAFNApgBVIKcgsyDAIEEgLSBVAFcu8QBFQAsDERQXVyF6AQN1QLcKQXdXcxETlHVVUxMiLQATIy0FREQQAEEUUeMgACD+A3MBETAgBgB1IHAAVYGWwRECV1EV"
Data "IH0hjyDGAXVVIJ4AVyB+QUVg02AFIWUAVyISIBtAOkAoQA0BfFwjeyEsAHwhLQDMIAAEx8zMczVAjSH/ILkBVVUh0QB3Ip1iVyARQgkhKwBXIKogkUAoARN1QHAgMyJpQDVAVSB8ISsgICBCQHBgFCElQSsAd0CFAhV3dyHfIJJgISBUAVVzQnYDV1QERCA7AnUUESFEIVJAEyHeADWAQAA1QEYAAyAqABFClyAFAZF3QHQMSUE3URQBExEZR3cxQCD7IAAhJEGyARdVIYIgQyBKIY8EV1cwRAEguQFVUUDbICgAEyGvQZYBdXcifgIRV1dABSAaIFggwEBrJLdArCAoIEEDETFzzCEkISBgAGg7AHw6GyBIAkV1dSCIAVdXPIAAVSFrCDc1NTF3d3cQRSDjAxRBd3UicwERN2C2ABUgFgE0FCAFAnFBEVNaBXUUREQ3d0AfQpUjYSLCBXd1REREQyAUBgREABVVcwAzNgozVVVEQDd1d1c0"
Data "RCAgAFcgPQB3IAAIUEAAV3d1dQADIAQBdzQiuQB1QxIBV1dDvSG4IT4ANWARATVVIJwBEwFAgCJdCldRMEd3dRlHVzExIY0gAAI3V1chsgATIDYKdRFBN3V1dXEAR3UgvQIABHcgAABRIIklIAEURCDcBndEQBVVMzMnkAVFVVMQREQlYgVxREREF3cgxwARIr4AdyCFAhFDVyANBEQRdcXMgAAhMGJYA8zMdTVCoAARIL8AVCD0D1dzADd3d1E1MRMUEzNTAAQgBQRAABNVUya0IEIAMCBdA1M1VUAlWAEzMCECBABDMzQAK10CMzEAIAAFQzM1EEQEV4AAECANJYwERBQEQJAkSAEzFCtmAEQuTAlTNXcxFEBDNVU1OkwFMzMTEEBAIDQHUQQBVTVVUQRzqQAwIM0Bd1UmCCUYIYEDd1d3UEFdNTMCQUV1QgoiKwAxI+4BUUQgqgAXNnYDEREUFSAYA0RERFcj1EBEDDVVVABDVTMxQEBA"
Data "ExMgkwQAFVNTMSCWAVdzIGoBREQ1HQJBEzEk+irVISACQAAAIM4CERQEKwAAMyA0AQAAKKkENABEHMUjdSJWIAJAACg1Asx8wyViAEQiBiEPKyYFQUBARTMzP5YANUBqAADgBAABQTMmrCEnAEAz+SAYQAOgADlAABFIETXeMM8ABD2dADEgAQYREJQ0QARBIJxQNyCRABQgsCLiABRbiQBEIBMBAEQhQAAAQAC1nSq+ICYAACl/IAYBETMopCW8IAsBQzMhsQMAAVVVIaAiCgxAAXV3EAATNAADV1NEIJMABC/UAAQ+nUBpKWpAC0AAAUREQbkgrQAEKJIAESAAAhRAASJRQI0AACioJ3gBMJRHRSCrIAw5mwBEIAACQRERIUcEAAAAHMzgCQAhgAAA4AQALDQAQSOBAnVTMyFmCDEzVTMTMUERRCAAAAAgTwBEQN0ggwFAQCfBJ5YARCARISYAADBqAAQhKQMERAQzJ1gBCZkqjwOd3SLt"
Data "Kk4AmTTPBy3d3dnd3d0QIAMB3dlU9wAR4AYAABQg5gBEISkAEWAAARQzIAAjEiAVIAIgXgBAITMhjSAmKscCNVMUIg4xnAc1VVVXdzMTE2AsIAAgFQBEIAABBARLBOAEAAVEREAJmd0gAAXRDd3d2Z1a0AHd2TBNAZLiMooAmSCrIewAMyM0Ib8g5QCZIA4DERE8zOAFAEJYA8UQAEQgAAFBESD6BDUzMTEzIAAAVSgXAgkJkCGwAhEUmUJHAQAAIOEgqiG6AERgBCHGIRggwiAVAAAgfAHZ3WAABtnZBBmd3S4gABji7uLi7SLiLdLi4uIi0iIiIi4uLR3i7u7icysAmSAAANkgAwGZnSFkIAAARDKrIAMAQHMlILtAWwAEQJMAREAAIJtm+gFERCM7IBIgdABBKZYAQCCVAgCQBCFmAQmZYAAiMSCcIEgAACAAoBNgZgDdIR0BIi4gfBLgTeLiLiIiItIuIu4i3e4i3i4uIKkBLuI6aAOQ"
Data "EA3dgABAywKQQTzEruABAAB8KVMhdUCdBQRACQERQSBoNsQBCS0gWkAAAy7u4uJATAAiIPEE3S3SLS0iIzUmBd3S0t4i4iEGAyLi3e4gAEEBAtnZmTVgABkhFAMtLSLSOlsB0u4gngvZvMwMzMTAwLFEFT4gD2AAAOIgsQDuQAAB7d2gAADZQNRApACdoBBAAAKdmZ2ADwGZ2SAAAN0iEiFbICgA3SAJIAPgCgAE2dmdmdlBGmAAAtIu7iAAAuIi4iGjgAAN7VNEEMwMTEzAzLC50u4g2wDdIMhA1AMuLtBJQL9AV0FVA+4tnMzgCAAEZ1Gd0tIhCEC9AC4g2gDuYAADLS6JgmAIYAAALiAAAeLSQHQgCAQuLiIt0iAFBS4i7SLe0iDsIDWgAAUuItLdnQFADwHe2SCDBiIi3ZAEQ8zgAQACyoguoAAF7u7tCZmdIoEA4iFuQX5AAAAiIXgC4iLiIAOgEQMtLS3SIEcC3d0tIKABLiIgAATi"
Data "LS0iIkKqQAAirkG1IAAgHyA1AN4gfyGzAZ3dIAAgJiDKAd3dIVwEAu7u7i4griADAiiKzOABABAxQAmdIiItLd3dLt7u7u7RnSEIAOIgCIAAAS3M4AkAA3c5nS4hGiAAICcBLu6AAAriiYK7u7uIiIiO7uAEAADtwCAgAALa3a0gBSAAAbzMQAACy4iKgCwB7O5AAAXi7iqt3czAAADDwAgGzMzJra2q2iJwAes8IAxAABC6rdjY7oqoju6+jd3dra2NrSADANiASoAAgAsBKKggHgXdrd2O6I1AIkAABNqN3Y3oQJEA4kASEajditrY2N3qvu6Kio7ora3azIAACjzC7u7q2tra3dvM4AcAIJYCmtrYIKtAAAAsQAQF7u6KiKzMQNEBy8zgCQADx3We7uAEAAOIiIi7IADAKwCqIABAj2AAAazMYAACy6qrYAdgAAC6YAWAAAmoioqqzCqKqKiqgA8AwyAB4A4AIEoAPCCr4AEA4AJS4DQA"
Data "AMpA6cAAYZDgAxCAAOAGlwnKqKqKgiy6qKiI4AIqoAoDvLy7y8ELAcw84QArAiqqisKjAsvMy+ACIgjMzLqqqqju7uIgCeDkAAHLy2EqBLy7u7y8YPgFzu7uKoqqoglgACFKAbu7ICYAy2AN4OsAAMtAACEGA8vLu7yBCiEOAszMzEAD4AMAALwgAAC7QCMCy7zL4e4tAcvMIPogAAC74AEAALwiYSSYAcvM4AMAQCUAu0AAIBwAy+AGG+AvAMGOIqnACuBqACB9gAAhCuAThwC8QAACu8u7IRsBu7siVsAAAMsgAAHMvOAARUAKAcvLYCdAAEJ5Ary8zOATAADL4AkcIBJBcGAAIGoioiAFQAAAvEAAIq6AAADLQChABCAJQAIgA+ACACCVIAIAzIB8QAmAAOACL0AUICABy8tACKAA4AYeYAAAvGAAgHYAu2AAYAyAEKAAAcvMoAAgS2AAArvLu0AC4AEAQBEgAwC8IAAgcCAAIAUgD+AA"
Data "JEDlIMJgAGDOAMwgAADLICXAACAsAcy7wAwhWCB/IALgAQBgG0EpAMuAAGAQYAQgAEAHIBgAvOABAAC7IAAgcwC7IBkAvCB3AMwgBEAKICQhv2AdQA/gAgDgAA4Au4AA4AAPgAAAu0AAALxgAECWQAMg6CAAgApgDyAAAMsg9iB3oBUgAAC7QACABQK7u6sgA4AAwJhAMCB6ID+AYQG7ukAfQC9AFYAeIAAAuyFtgBAgAAC7QAoBu7wgAiAk4AgCIHoggAC7gEMgB2AAIAggKWAKQDBAA0AoAMtAAUBXoXogUyAOIB7ACQDLIAAgHAC8IA8gP+AAAkAAALxAESFXQAJgAECPQANAGSAAIFogAGAGIFHgBABADyB6ALwgQUADIDlAAgC7IBcgBKAAAau6QAAAu8AAYDIgLwDLQAAAu2AAArq7uoAfYA8gaKACIJBADWAjIBsBvLugAiAAYBigJmAWIBFAAuAKAIAlYB0gBUAAILFATyAAIDug"
Data "CWAKQmaACSAKIAAgJmAhIAAgCkAAIAbAEYAAIIRAi6AwIAAgECAkIBTgBgAgFIACgBugJkATgAACururoAAAuiAAALugAGJMAMtgDGAFAaur4AEeINiAFKAAYJgAyyHxALvgAgBAJOBEAAC8IAFAAmAAAMsgBeAEbuBLAEBk4AFyAru7q4EDYAAAqyAAAbq6wS5A7CFYgAAgFwG7qiAaAaurgA8gAEC74Fiu4IAAQlEGurq6q6q6qmAAAbqqIAwBq7sgAuAGAAC6IBcDqqq6qiAp4Aod4CQAIHAgQuAEACAQIAIAu0AB4GAAIGwCuru64AoAIBngCQAgFSC3QksBqrpBByEyIAgBq6sgDgC7IAUBurvgAAAAq0AAIUYCqquqQB0gAOALUCBMIBYgNyBWQANAACAQALoiuiAVIApAACBFIBvgCAAgFAC6IADgDxogP+ALGkAAALrgEABgNCAF4A0AALpgkSAF4AIAQGPADmA9QLhAFGAAILoB"
Data "uqogAGAEwAAgEgC6YEkgaWAqIA3gASBADOADACBUgAAAuyAvQDZAA0AKIA8gCwC6QANACwC6YAAgFCBBAKsgACBzYAcgACAIQA3gAwAgJ+AIAEBGIBgAuiCUYAbgCiDgIQAAq2H1IIuAACCAYBAgBeACAEBxYMRAAAGrqiAAALogA+ABACASgDWAKEAqIA8gSwCqQAAgHSAe4AwAIHcgF0AeIAkgWQC6IAAAqyAAQAhAQUAAAaqqQRegcSCpIA8gACAiIAJAGQCrwABgNKAEIAdgAiBEoAigMUAAAKtAFUAFIAcgA+ACAKAsALogAKAL4AAAQD9AHiAzwABAmkADIBcgnyBRQDggH0AKIAsAqkAAgAXgBwBgTaAAICogD+ABAKBRQIBgACBJQAAgVSAJIAWgUUAGICogEWAFIARAAMAdQGBgACAdQCkgBCAGoCQgAEAJIBogB4AFIAhAEoAnIBIgLCACIAAgBSAYIAUgGmAF4AAAQCWAZiCX"
Data "QAjgAR4gMUANQAZgGyCkIBAgDkAGIAnAbiAXIBRAACAHIBWgADJgMmLgAgBAJEBhQAegJgCooB4gEkS7oBUgRkAAgA1ABcA1ICYgAiARgAUgJyALQAzgDgAgJiAAQD0gJ4AMIAiAMUAIYNYgAEALIAwgAkAkIFYgESAbQBkgBsACwAAgD8AKQBtgK0AxgAPgCwBA2yAAQDggOiAGQGbgAAABioqBKiAGAKrgAQAhp0C4QDBAAAKKqqjhBU1ArSAhQACAToAF4AcAIGkgAuC9AAKKiKggAACK4AEAAKrgCwAAqGAAIU0AquDuAEJNAIpBAACKITABiKggBGAAAKrgCAAiUDYKQCAgM+AIHeAkAEBKAKhAAACKYAAgdULNYFThLYfgLDUgxyDRIHkgAECDIIZgAiAXIAIAquAIAEAYIC0DioiIqEACIAhACkAAAYqK4AQuAKggKQCINnkgIiBRQAAAquALAGECIAUAqiBUIARAAiADIAAAqEAH"
Data "IAQgPAGKiCAdgAAAqGAAIC9AACBfAIqAACBkIGugAACK4AEAIClAAEAGIANAUaAAAKggVEACwAfgAj5gAOABDyAJIAIgVACIoEFgH0BKQA8giaCbQCIgBCAAIBNgAACKYAAhHyEFAKghBwCIIAADioiIiuABAAKoqqogLWAAgCHgBR7gAgCgrMBa4AMAQEIgGEAAoAYAioAuYDNACkAAIISgACBDAaqKwAAAqOATAOAAJiAJIAIg3mA7IAXgBADgAQ8gCSACIFSkd0ECIIVAAyAGIPoAiOAEOEApAKggKyAAAKggACAjIAMhCCApIAAAqCAsIAYAiuACAIArQE8CqIiIIBkgA+AB1+AAAAGqimAAIHHgCABALWAEIAVACyBkICYgAkADIAZgDyAYIAhgu2ASIAxgAiAEYBVgLOAHACA0QAAg4aAzYJwgBSASQBiAAMAPICSAWyAQIB5ADkDSIAggEGAaIBIgiCAVAIogACAGgHlACCAhIAcA"
Data "iOAJAEA9QAQAqGAAICMgQUBPoAAgQUANYFCAACALQDBAACB0IFIgb2ADYAQgG0AgIAYgMgCIIAsgQSAG4AMAIBIgHyAVQAJAcSBHgAIgBkAxIAAgDyBAICEgBqADQE0gACAjQAJgBCAwYCOgGiAA4AAPIBMgHUA6QIdAIGBtQCIgA0AMQAAgRoALICkgAkAPIB4gMiAcQAPgCQAgYOAAW0EpAIpAEOABACANQEdAACBZwClAACBYYBxB64AIIChAaSB1QCogDSAKIAZAd0AkQA1AGKADQAbgBQAgQCCqQDwgCSBeQD+gAyDzQBMAiIAAwAcgACAKAIqgAACIQABAD0AHYAAgDICAQEUgACBTQA8gZSARQAAgIACoIG8gqiACQB6AO4AF4AgAIBYgAiAzQCkgBEAJ4AIAwA4AqCAAwB1AL0Ba4BQAICTgFAAgHyACIFMgAyClIANAAuAZAEAxQABAB2A1IAXAAOABD0AJQCGBGeASAIAk4AQA"
Data "IJbgAQABKIJAAAKIKIjgAgCA++ACOQCC4AAcYhLAAOAEDODXAAIoKCghJgAoITDhBSzgBQAhRwCC4QEt4DYAYEggdWAH4HYAQIMgAyCN4BUAAIIg/yADYS4gBQCCQAAgFOAIACAZgCMgBuAIHOAjACBIIEIhnCAAIAwgVCADIAIBiIggdiGuIAWACeBIACBkIRFAAGAGQOYgEAAoIAAAgmCSIB8gAyAFYB7gBQAgLOAAIwAiIApAAOABNgCI4AQAID8AKIAAYDIg0+AEUCBgAIggACBRYO5g8CAjQAMgEWAWQAdAACATIEogBiAAYAUAgkBRYAlABUAMIACAD4AAoD5hQSAXIHhgWICTQBDgHgCAMGAAAIIgAMCFwHEgECACIADgAAUgCGACIARgCEAHgAADIoIoImAJYBMgSSADAIhAAACCIAAgZyAAICNgHEAOICAgA2DHIAAgCkAAIAYAgmAAAYgiYAZALUATQN1ACCAAAYKCYZDgBgAg"
Data "TaAgoDKAAOAADEBQIBIgJyACIBZgAECUQDggBCAKwAIgHsAKgAiAAACCQEtABSAAQDQgCyAGQAPgAgAAImCoYCXgAkOAEGAAIQFAAiADIAAAKGAAAIIgWEAtYAAgUqAAQQBgCiAeYEAgBWALYAhACkAIIANAB0AGwHAgECALQD5gAAAiIAoAKCAAIZ5gA8AAwCDAD4AAQBVAxSBBwAAgCkAC4AEoQCPgKwAgOECCIABABoAD4AMAYGXgAGdAZQAoQLwAIkDCIAQgCCA0gAAAguAAAEAnICUgAkAKACjAACBL4AcAoCJgJmAsoABAaCAAAChAAEAXIAAgE0AJQAQgAGAgIAXACiAA4AK8YCigAKBiACiAHoAZgAYgBUADIAbgAQJgAEBcQC5gAAAoQAAgNkAQQAcAIkDXgIZAJ0AfIAdgA0AigABAH0AnAIIgBUAsQBkgAwAoIAMAguAGACEDIFMgR2BjIAUgCiATQLYgGyA1IACAHoAOIBIg"
Data "AkAAQAagAwAiQGQgAEAiIAAgQEAJQAYAIkCGIABAD4AK4AFaYBRABUASQAMAiCAJYDVAB6AZYAYgBUADIAbgAALAECB7QWNgAACCQAVA/KAlACggHSBHIDQgXiAAIB8gZkAPQFVAAyCSIB1AEkAAIBEgIGADIBZAAwCCICVgAKA7ACIgWiADYA5AEkAeIAQgQSANQBkgBCBiIBIgAyAJYAYgAECUQBEgDwAoIFoAgiAAACLgCAAAgiAAACggAEAlAIJAUyAJQDBAD2AEIAxASIAUIGogjmAPgB1gHmAn4AEJoA9AJiAZIHtAPGAAIAggRyAGACJgACBKwABAJkAYIB5hA0DPICcAKCAT4AkAQBwgXiJoQCwAImAAYCqgC4AHIEpAPSCsIBZABSBPIAAgBiAPYACgB0AXICBADSCYQAbgDADgEBhAAOADHCBEIA8gVSAYQFgg2yAJILAgA4AA4AEJYABAKmASgCfgBgAgvmAc4AEA4AIOIDGB"
Data "DYAAICtAAOADEkCLYDBA+QCCYAAAIoAAIDuAlGAIQCdAKKAM4AAAQEtAViCkIALAFkAl4AAMQDpAJiAUYCPgAhjgBgAgIeACAEANwFMgOOAAAEAXIERgBiAAYT8gDCAC4BsAYCbhA3dgAECfYAAh/+AAn+AAFCASQDGgAOADi+AAK+AOAOACH2B44AgAIBUgAkAAQGHgAi7gAQBgGGCLYAlgBWAzYAQgBWEk4A464AAAIEGAACAoIAJgM2AAgEUgViASQGVAAyAO4AwAQBsgPCAAgAUgACA4IAXgHwDgAisgd+ABO4AXQcogheACTKALYCvgMwBAR+AFWUDjQBWAAIAJgAXgEADgFh7gEgDgGjlgIkFfQANB1eAKAOE4BuD/AOD/AOD/AOD/AOD/AOD/AOD/AOD/AOD/AOD/AOD/AOAHAAEiIg=="
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Speed up the drawing of a moving waveform

Post by dodicat »

Thanks UEZ.
Quite a large bitmap to load from the code block.
It must be a very good compressor, it compresses well with zip (about 1/3), to give in excess of 20 kb, so your lzfx_compress must be even better to get it to fit into the forum.
Anyway, nice moving wall, thanks.
I am still working on getting my own image sweeper to work properly (one line out at each full sweep), but I am up against a brick wall at the moment!
UEZ
Posts: 988
Joined: May 05, 2017 19:59
Location: Germany

Re: Speed up the drawing of a moving waveform

Post by UEZ »

dodicat wrote: Jul 25, 2022 14:12 Thanks UEZ.
Quite a large bitmap to load from the code block.
It must be a very good compressor, it compresses well with zip (about 1/3), to give in excess of 20 kb, so your lzfx_compress must be even better to get it to fit into the forum.
Anyway, nice moving wall, thanks.
I am still working on getting my own image sweeper to work properly (one line out at each full sweep), but I am up against a brick wall at the moment!
Since the forum does not support attachments, you have to get creative and find workarounds to attach files up to a certain size. Unfortunately FB natively supports only the bitmap format, otherwise you could have used PNG or JPG.
I had to reduce the image to 16 colors (4 bit), otherwise it is over 300kb in size.
If I had used Base128 encoding, the file would certainly have been smaller, but unfortunately this does not make it compatible with the character in the forum, so converting it back to binary format causes problems.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Speed up the drawing of a moving waveform

Post by dodicat »

Base 128 is OK (Experimenting a few years ago).
But it is very sensitive to the browser, If I remember correctly firefox added one character at the end which completely ruined the transfer.
Also if I remember correctly one character had to be changed.
viewtopic.php?f=7&t=25744&p=233594&hili ... 2A#p233594
This was experimenting with different bases using gmp to change the whole file to a different base mathematically.(a bit slower of course)
I remember you were also involved later on with base 91 conversions.
Anyway I have fixed my image pointer cycler.
Drawing a moving waveform:
1) The pointer methods all discussed here.
2) Moving an image along the screen and flipping back to the start (circular trig functions)
3) Rotating the waveform in front of the user's eyes, like a huge roundabout.
Some old code for method 3

Code: Select all


Type V3
    As Single x,y,z
    As Ulong col
End Type

Type Angle 'to optimize rotating many points
    As Single sx,sy,sz
    As Single cx,cy,cz
    Declare Static Function construct(As Single,As Single,As Single) As Angle
End Type

'all the sines and cosines are pre calculated and sent to rotate 
Function Angle.construct(x As Single,y As Single,z As Single) As Angle
    Return   Type (Sin(x),Sin(y),Sin(z), _
    Cos(x),Cos(y),Cos(z))
    'sx=sin(x), sy=sin(y) ... e.t.c.
End Function

Function Rotate(c As V3,p As V3,a As Angle,scale As V3=Type(1,1,1)) As V3
    'note; no trig done, all trig is in parameter angle
    Dim As Single dx=p.x-c.x,dy=p.y-c.y,dz=p.z-c.z
    Return Type<V3>((scale.x)*((a.cy*a.cz)*dx+(-a.cx*a.sz+a.sx*a.sy*a.cz)*dy+(a.sx*a.sz+a.cx*a.sy*a.cz)*dz)+c.x,_
    (scale.y)*((a.cy*a.sz)*dx+(a.cx*a.cz+a.sx*a.sy*a.sz)*dy+(-a.sx*a.cz+a.cx*a.sy*a.sz)*dz)+c.y,_
    (scale.z)*((-a.sy)*dx+(a.sx*a.cy)*dy+(a.cx*a.cy)*dz)+c.z,p.col)
End Function 

Function perspective(p As V3,eyepoint As V3) As V3
    Dim As Single   w=1+(p.z/eyepoint.z)
    Return Type<V3>((p.x-eyepoint.x)/w+eyepoint.x,_
    (p.y-eyepoint.y)/w+eyepoint.y,_
    (p.z-eyepoint.z)/w+eyepoint.z,p.col)
End Function 

Function ShortSpline(p() As V3,t As Single) As V3
    #macro set(n)
    0.5 *(     (2 * P(2).n) +_
    (-1*P(1).n + P(3).n) * t +_
    (2*P(1).n - 5*P(2).n + 4*P(3).n - P(4).n) * t*t +_
    (-1*P(1).n + 3*P(2).n- 3*P(3).n + P(4).n) * t*t*t)
    #endmacro
    Dim As V3 G
    G.x=set(x):G.y=set(y):G.z=set(z)
    Return G
End Function

Sub GetSpline(v() As V3,outarray() As V3,arraysize As Integer=1000)
    Dim As V3 p(1 To 4)
    Redim outarray(0)
    Dim As Single stepsize=(Ubound(v)-1)/(arraysize)
    If stepsize>1 Then stepsize=1
    For n As Integer=Lbound(v)+1 To Ubound(v)-2
        p(1)=v(n-1):p(2)=v(n):p(3)=v(n+1):p(4)=v(n+2)
        For t As Single=0 To 1 Step stepsize
            Redim Preserve outarray(1 To Ubound(outarray)+1)
            outarray(Ubound(outarray))=ShortSpline(p(),t)
        Next t
    Next n
End Sub


Sub createpoints(a() As v3) 'set up points in a ring
    Var numpts=200
    Redim a(1 To 2*numpts)
    Const pi=4*Atn(1)
    Dim As Long r,count,zval
    r=200
    For z As Single=0 To 2*pi Step 2*pi/numpts
        count+=1
        a(count).x=400+r*Cos(z)
        a(count).y=300-r*Sin(z)
        a(count).z=(Rnd*5-Rnd*5)*2
        a(count).col=Rgb(255,255,0)
        Pset(a(count).x,a(count).y),a(count).col
    Next
    Redim Preserve a(1 To count+3)
    a(count+3)=a(3)
    a(count+2)=a(2)
    a(count+1)=a(1)
    Return
End Sub

Function Regulate(Byval MyFps As Long,Byref fps As Long) As Long
    Static As Double timervalue,_lastsleeptime,t3,frames
    frames+=1
    If (Timer-t3)>=1 Then t3=Timer:fps=frames:frames=0
    Var sleeptime=_lastsleeptime+((1/myfps)-Timer+timervalue)*1000
    If sleeptime<1 Then sleeptime=1
    _lastsleeptime=sleeptime
    timervalue=Timer
    Return sleeptime
End Function
'============================  ==========================      
Screen 19,32,,64

Redim As v3 a(0)
createpoints a()


Locate 1
Print "Initial array points"
Sleep 1000
Line(0,0)-(800,600),Rgba(0,0,0,190),bf 'fade out the initial points

Dim As Double pi=4*Atn(1)
Dim As v3 screencentre = Type(400,300,0)

'PART 1                  (x  y   z)
Dim As Angle A3d=Angle.construct(0,pi/2,0)   
For n As Long=Lbound(a) To Ubound(a)                        
    a(n)=rotate(screencentre,a(n),A3D)                  'rotate all points by pi/2 around the y axis
    Pset(a(n).x,a(n).y),a(n).col                           'draw the points
Next
Locate 1
Print "Points are all rotated by 90 degrees around the vertical (y) axis"
Sleep 1000

Redim As V3 rot()'to hold all rotated points(a working array) 
Dim As String key
Dim As Long fps
Dim As V3 ang 
Dim As v3 eyepoint      =Type(400,300,4000) 'for perspective
Redim As v3 catmul()
GetSpline(a(),catmul(),10000)
Redim rot(Lbound(catmul) To Ubound(catmul))


'PART 2 
ang.z=pi/2  'offset .z by 90 degrees 
ang.y=-pi/100 'start off with a tilt, optional
dim as long t=1
Do
    key=Inkey
    If key=Chr(255)+"K" Then ang.z-=.005     'left
    If key=Chr(255)+"M" Then ang.z+=.005     'right
    If key=Chr(255)+"P" Then ang.y-=.005     'down
    If key=Chr(255)+"H" Then ang.y+=.005     'up 
    If key=Chr(32) Then ang.z=pi/2:ang.y=-pi/100 'space
    
    ang.x+=.001  'the rotating speed 
    If ang.x>=2*pi Then ang.x=0
    'use ang and construct parameter 3 for rotate()
    A3D=Angle.construct(ang.x,ang.y,ang.z)' ... get the six rotate components (sines, coses .. for rotate())
    Screenlock
    Cls
    Print "fudged axis (x and y apparently interchanged, z has a 90 degree offset)"
    Print "X angle ";Int(ang.x*180/pi);Tab(20);" degrees"
    Print "Y angle ";Int(ang.y*180/pi);Tab(20);" degrees"
    Print "z angle ";Int(ang.z*180/pi);Tab(20);" degrees"
    Draw String(50,130),"Framerate "&fps
    Draw String(50,150),"Use the arrow and space keys "
    Draw String(50,170),"Toggle F10 key "
    if multikey(&h44) then t=-t:sleep 100
    Var s=10
    For n As Long=Lbound(catmul) To Ubound(catmul)
        rot(n)=rotate(screencentre,catmul(n),A3D,Type(s,s,s))'scale up by 10  for nicer size
        rot(n)=perspective(rot(n),eyepoint)
    Next

    For n As Long=Lbound(rot) To Ubound(rot)-1
        var condition=iif(t=1,rot(n).z<0,rot(n).z)
          if condition  then  line(rot(n).x,rot(n).y)-(rot(n+1).x,rot(n+1).y),rgb(255,255,255)
    Next
    
    Screenunlock
    Sleep regulate(64,fps),1
Loop Until key=Chr(27)

        
Post Reply