Notice! This content describes the deprecated Altus 1.0 (non-ARC) Engine features and data tools. These are superseded by Altus 2.0 and Altus Server tools. They are currently being tested with select groups. If you're interested please contact us at [email protected].
If you have any questions about the Altus Mapping Engine, any feature requests or suggestions for improving the Altus Mapping Engine, please send them to [email protected].

  1. What is the BA3 Altus Mapping Engine?

    The BA3 Altus Mapping Engine is a professionally developed, high-performance mapping library for the iOS, Android, Windows 8 and OSX platforms. Altus will allow you and your developers to radically improve the performance and capabilities of your mapping apps.

  2. What are the benefits of the BA3 Altus Mapping Engine?

    Please see the Key Benefits page.

  3. How can I try out the BA3 Altus Mapping Engine?

    The SDKs for the Altus Mapping Engine are available online for immediate download and experimentation. Go to our Products page to access the SDKs.

  4. How does licensing work?

    You can email [email protected] to get a license agreement. Once you sign a licensing agreement we will send you license key. This key can be set in the API immediately after starting the mapping engine. On iOS this looks like:

                    [self.mapViewController setLicenseKey:@"Your license key here."];
                  
  5. What offline map formats does the mapping engine support?

    The easiest way to do offline maps is to use an MBTiles file and download the file to the device. This tutorial describes how to set that up: http://www.ba3.us/tutorials-android-5.php.

    Next easiest would be raster files. You take raster files (e.g. FAA charts, aerial photos, geoTIFFs, geoPDFs, etc.) and run them through METool. This tutorial covers its use: http://wiki.ba3.us/index.php/Using_metool. Download the output of METool to the device, then display the file on the map.

    Or you can create vector files and download them to the device. This page shows you how: http://www.ba3.us/blog/?p=529. It takes an hour or so to set it up, but once that's done it is straightforward.

  6. What is a tile server?

    Think about what you see on the screen when you go to a place like Apple Maps. Whether you are viewing a map in a web browser or an app, you see a graphical representation of the map on the screen. The graphical representation might be just roads, or a satellite image, or terrain, or some combination.

    The way that this graphical representation gets onto the screen is with a collection of small images called tiles. A tile might be a 256x256 pixel JPG or PNG image. A typical screen might need 15 or 20 tiles to paint the whole screen. If you have a bad internet connection, you can see these tiles as small square images that appear on the screen one by one over the course of 10 or 15 seconds.

    A tile server provides the tiles. There are hundreds of tile servers on the Internet. OSM has a tile server for its tiles, MapBox has one, Mapquest, etc. The BA3 Altus Mapping Engine requests tiles from a server one by one and displays them on the screen. The BA3 Altus Mapping Engine can work with any Tile Server, including WMS tile servers.

  7. What is an MBTiles map?

    MB stands for MapBox. MapBox has the capability to act as a tile server (see above). To use a tile server, you need to be connected to the Internet. What if you want to use the tiles without a connection? An MBTiles map gives you a way to take a group of tiles for a map from the server and package them as a single file for offline use. There are limits—the more levels you include in an MBTiles map, the bigger the file.

  8. How do I create my own MBTiles file like the one used in Tutorial 1? How big is a file like this?

    The mbtiles in the tutorials was created with TileMill available from MapBox here: http://mapbox.com/tilemill/.

    The map in the tutorial, which is extremely low resolution and shows no streets or place names, is 12.7 MB compressed.

    A much higher resolution vector map in Altus Mapping Engine format with labels for all political boundaries is about 18 MB compressed.

  9. I need to store my map on-device. It will have no connection to the Internet once the maps are loaded (alternative form: I want to be able to load maps onto the device with an SD card). What options does BA3 support for downloaded, on-device maps?

    The easiest way is MBTiles. This tutorial describes how to set that up: Tutorial 5 — Offline Maps: MBTiles. Put the MBTiles file on the SD card.

    Next easiest would be raster files. You take raster files (e.g. FAA charts, aerial photos, geoTIFFs, geoPDFs, etc.) and run them through METool. This tutorial covers its use: Using METool. The output of METool could go on your SD card.

    Or you can create vector files and put them on the SD card. This page shows you how: Learn about OpenStreetMap data, and create your own vector maps, by playing with BA3′s MapShop. It takes an hour or so to set it up, but once that's done it is straightforward.

  10. What is a marker on a map?

    A marker is a small graphical element (chosen by the developer) that appears on the map at a specific lat/lon coordinate. In the BA3 Altus Mapping Engine, you can choose any png file you like to act as the marker. Markers can rotate or change. Very large numbers of markers can appear on a map—clients have created marker layers with up to 200,000 markers and the performance is excellent.

  11. What is a raster image when used in the mapping context?

    Here is an example: Imagine that you take a paper FAA chart for pilots and you scan the whole thing into a PNG or JPG file. The PNG or JPG file is known as a raster image. Now you would like to lay this chart onto the earth at the correct lat/lon position so it displays properly in the BA3 Altus Mapping Engine. The BA3 Altus Mapping Engine makes this kind of thing very easy to do, and the performance is excellent.

  12. How do I prepare a raster file for use in METool and the Altus Mapping Engine

    This document guides you through the process of taking an arbitrary image (chart, map, aerial photograph, etc.) and converting it into content that can be rendered by the BA3 Altus Mapping Engine on iOS.

    You will convert your source image into an image with an alpha channel, then convert that into a geo-referenced TIFF image (geotif) that can be processed by the BA3 Altus Mapping Engine Tool (METool - see Question 2). Once processed, the file is ready for use in the BA3 Altus Mapping Engine.

    Prerequisites on OS X

    Then, from a command line, execute this command to put the binaries from these packages on your path:

    # cd ~/
    # echo 'export PATH=/opt/local/bin:$PATH' > ~/.profile
    # . .profile

    Step-By-Step Instructions

    Step 1

    Convert your source image into a PNG (.png) image. Other formats may work, but PNG has been thoroughly tested. For this example, name the image myimage.png.

    Step 2

    Look at your image in an image editor and find several landmarks on the image that correspond to landmarks with known geographic locations. You can get known geographic locations by looking at other maps, online (Bing Maps or Open Street Maps), or using other software.

    Step 3

    Note the geographic coordinate (latitude and longitude) that corresponds to a pixel coordinate of the image. Consider the origin pixel (x=0, y=0) of your source image to be its top left pixel. Collect several points from around your image and their corresponding geographic coordinate. The more points you collect, the more accurately the image can be warped. In this example, we are georeferencing the subway map for the San Francisco area, so the points and lat/lon locations might be:

    x:828 y:2346 = lon:-122.5097898379812 lat:37.78062053164073
    x:6072 y:1873 = lon:-122.3885018331454 lat:37.78811453911737
    x:2494 y:5243 = lon:-122.4720624930206 lat:37.72683034536965
    x:4284 y:5685 = lon:-122.4299839425239 lat:37.71814655820412
    x:6566 y:4475 = lon:-122.3768717974501 lat:37.74019797177258

    Step 4

    Open a command prompt and convert your image to a .tif using gdal_translate:

    # gdal_translate -b 1 -b 2 -b 3 myimage.png myimage.tif

    Step 5

    Now use gdal_translate to create a set of instructions (.vrt) by executing a command like this:

    # gdal_translate -a_srs EPSG:4326 \
    -gcp 828 2346 -122.5097898379812 37.78062053164073 \
    -gcp 6072 1873 -122.3885018331454 37.78811453911737 \
    -gcp 2494 5243 -122.4720624930206 37.72683034536965 \
    -gcp 4284 5685 -122.4299839425239 37.71814655820412 \
    -gcp 6566 4475 -122.3768717974501 37.74019797177258 \
    -of VRT myimage.tif myinstructions.vrt

    The parts that say "-gcp (x) (y) (lon) (lat)" are repeated for each of your reference points. The result is a file named myinstructions.vrt, a chunk of XML that describes the geographic orientation of the image, without actually touching the image itself. gdal_translate should output something like this:

    Input file size is 7350, 6838

    Step 6

    Now you will execute gdalwarp to perform the actual warping and bending of the image to its new shape:

    # gdalwarp -r cubic -t_srs EPSG:4326 -dstalpha myinstructions.vrt  mygeorefimage.tif

    Step 7

    Open the created image, mygeorefimage.tif, in an image viewer to verify it has the colors you desire. If the image is grayscale go back through the steps above and make sure you didn’t miss anything. The image will likely appear transformed in some way, this is OK, as it has been reprojected. This image will then be fed into METool to generate a .map and .sqlite file that is compatible with the BA3 Altus Mapping Engine.

    Step 8

    Execute METool to process your geotif into content for the mapping engine:

    ./metool -geotif -inputfile mygeorefimage.tif -outputpath /Users/MyName/MEMaps -mapname mymap -complete -level 16

    This tells METool that your input is a geotif and that you want to use the complete image to generate a map named mymap down to detail level 16.

    This process can take some time, but you can start looking at the highest level generated tiles pretty early on and stop the process if you’re not liking the detail level.The level dictates the depth to which tiles are generated and generally depends on your map content. If you have very small fonts or very granular detail for a small geographic area you’d need a higher level (i.e. subway map) than if you were using less pixels for a larger geographic area (i.e. aviation map). The intermediate tile images will be generated and you can look at the highest level tiles to see if they meet your quality needs. You can experiment with this level setting as needed. The higher the level, the more tiles, and the bigger the map, but once you go past a certain point (where you are oversampling the data) there is nothing to gain and you will be wasting space. A good rule of thumb is to find a font on a high-detail tile to see how readable it is.

    Once all tiles are generated, the fully opaque ones will be converted to high-quality .jpg images and any around the border will use PNG with an alpha channel. These will then be packaged into the .map file. Empty tiles (those with no lit pixels) will be optimized out. Data structures and meta-data needed by the mapping engine will be put in the corresponding .sqlite file. Both files are needed to display the map. In the future we may combine all of this into a single file.

  13. How well does the Altus Mapping Engine handle battery consumption?

    Please see the blog post, Increasing Battery Life with the BA3 Altus Mapping Engine.

  14. How much of the CPU is used by the BA3 Altus Mapping Engine? Why is there CPU utilization even when the engine should be idle?

    Similar to a game engine (and most other state-of-the art map renderers out for iOS and Android), the BA3 Altus Mapping Engine is designed to display a fluid animation when panning, zooming, fading in/out markers, or animating vector markers like the animated circle or animated reticle. By default it tries to run at a consistent 60 frames per second.

    When nothing is displayed (blank screen), the Altus Mapping Engine is still running through its main processing loop, checking to see if there is work, and then clearing and filling the screen with the current fill color. It going to try to do this 60 times per second. This can take CPU and GPU time, but it will be minimal because there is little to do.

    Much more typical is the case where work needs to be done because of panning, zooming, on-screen animations, change in GPS coordinates, etc. The architecture of the engine is such that in its main update loop, it tries to do a ‘reasonable’ amount of work and exit the loop to allow the rest of the application and the operating system to do work. This loop is driven by a displayLink timer object that is part of the GLKViewController system on iOS. As such, the target frame-rate can be adjusted by changing the preferredFramesPerSecond setting to a lower number. This can potentially free up CPU and GPU time. This setting can be dynamically adjusted by the application based on the current scenario or demands from the user. However, if you set it too low, it is possible that animations will be less fluid and the illusion of smooth animation will be lost.

    The application may also simply pause the Altus Mapping Engine and it will not update at all. This could be needed, for example, if the application wanted to support some type of hibernate mode, to conserve battery power, or to free up the CPU to perform some other work.

    Our reference application for iOS, for example, pauses the Altus Mapping Engine when it is downloading maps.

    Somewhat counter-intuitively, when the Altus Mapping Engine begins requesting tiles from tile providers and determines that it is ‘waiting’ on something else (this can be adjusted by changing the maxTilesInFlight setting BTW) it is possible it sometimes appear that the Altus Mapping Engine is doing less CPU work. And this will vary whether you are looking at CPU usage on the simulator or hardware.

    If you are not displaying any high-frequency animations (circle, reticle) and you know the user isn’t interacting with the display, or you are doing low-frequency animations (like animated weather), you can drop the perferredFramesPerSecond down to something lower than 60, which will reduce CPU load.

    It is possible for us to implement the logic in the engine to try to detect if it can auto-throttle down to conserve CPU power and we have discussed it internally. But a few simple tests running without any throttling have shown that the amount of battery power savings may not be very high. The optimization work already done in the main update loop makes the engine quite efficient.

  15. What does "zoom independence" mean?

    Zoom independence means that the content of the raster tiles at lower levels is created by down-sampling the raster data from higher levels. This, for example, would be the case with FAA VFR charts. They are zoom independent: the data shown is the same raster image at each zoom level.

    With a tile set like those from MapBox, they are zoom dependent. They show different data at different zoom levels.

    This is mainly just a hint to the rendering engine that may or not be used for anti-alilasing. If the tiles are zoom independent we can use an in-between level sampling technique to make the images on screen smoother.

  16. How can I programmatically zoom the map so a well-defined region is shown?

    You would say something like this in Java:

                    mapView.setLocationThatFitsCoordinates(
                    new Location(14.0805,100.6121),
                    new Location(14.081,100.6126),
                    0, 0);
                  

    In other words, you are passing two lat/lon pairs that specify the area of the map you would like to see on the screen.

  17. I can’t zoom in as much as I want. Is this a limitation?

    The functions setMinimumZoom and setMaximumZoom control the min and max zoom levels that your app allows. There is a default setting for setMinimumZoom built into the engine, but you can override it. You can set it as low as 0.000001, maybe lower, but it may get dicey as you approach the limits of precision.

  18. What is tile biasing?

    For zoom-dependent raster maps like those from MapBox, since the content is different at different zoom levels, if different levels were shown on the screen they would appear to be disjointed. Depending on where the user is looking and their virtual altitude, multiple levels might be shown. Enabled tile-biases will tell the mapping engine to lean one way or the other, so that the same X,Y,Z tile set is shown at all times. This is not without a memory cost however, since invariably you will be showing more tiles.

    If all of your content was zoom-independent, for example FAA sectionals, you would not need tile biasing.

    Another setting, tileBiasSmoothing, has recently been added which will ‘hold onto’ the biases level for a certain pan distance. This prevents the user from ‘flashing’ back and forth between levels during back-and-forth panning in an area with a tile level switch would occur.

  19. How does the BA3 Altus Mapping Engine manage cache memory?

    Some general points:

    1. The engine has 2 cache sizes: low-end and high-end. Low end is 60MB, high end is 90MB. High-end is used when a device has 2 cores.
    2. Whenever a request is made to load any resource (marker or tile etc.), if our internal tracking says the cache size would be exceeded, we eject the oldest loaded thing form the cache to make room for the new thing.
    3. If that 'old thing' is still being displayed, then it will get re-requested. Which will force another ejection. This results in the familiar problem of 'cache-thrashing' which sometimes appears as flashing to the user (as things are ejected / reloaded)
    4. How we measure memory may be different than the actual memory needed by the OS. For example we look at a 256x256 RGBA8888 tile as 256x256x4 bytes. However, it may take more actual memory (OS / OpenGL overhead) once that texture reaches the GPU. So...our cache sizes are set based on experimentation of what we've seen the devices capable of handling and leaving some memory for the app.
    5. The on-screen tile defaults to from 190 to 380 pixels (this is configurable, doubling this number quadruples the number of tile requests). This means we render the 256x256 tile at from between 190x190 to 380x380 pixels in a given 'level' before switching the next level up or down. You can do a rough approximation of memory pressure like so:

    Consider iPad 1 or iPad 2 at 1024 x 768 resolution.

    • height 1024 / 190 rounded up = 6
    • width 768 / 190 rounded up = 5 (You have to round up because a fraction of at tile means we have to load the whole tile)
    • worst case number of tiles = 6 x 5 = 30 tiles
    • Assume an RGBA4444 texture (2 bytes per pixel)
    • Bytes required = 256 x 256 x 2 bytes = 131072 bytes
    • Total bytes for a screenful of tiles: 30 * 131072 bytes = 3,932,160 bytes

    That's about 3.9 MB per layer in terms of our cache size for a 2-byte layer (like weather). 4x that for iPad 3.

    So...to think about how many frames you could have:

    • Assume terrain is always on: On iPad 1, our terrain layer is currently double this size at 7.8 MB.
    • And let's assume the user always has a another map turned on and some markers so add another 8 MB.
    • So basically you have 60 MB - 16 MB = 44 MB for whatever else you want to load.

    But the best thing is just to experiment with it.

  20. How do I get the the base map to show at the outer zoom levels (1-3 or 1-4)?

    Your base map should have tiles for all zoom levels, if it is tile based. If using one of our base maps, they have this. The tile provider for the map on top will simply return a tile response of kTileResponseTransparentWithChildren for requests from the outer zoom levels.

  21. How do you use the kTileResponseTransparentWithoutChildren feature at the lower levels?

    Set the maximum zoom level of the virtual map to your maximum data level for the map. In areas where you want the engine to overzoom where there is no data for a given tile, use: kTileResponseTransparentWithChildren.

    If you know there is not going to be data for a given tile and it has no children, use kTileReponseTransparentWithoutChildren.

    A reverse-parent search will be used up to the max you set in these cases.

    Our mapping engine does not request higher level children when data is not available for the requested level. However your tile provider can implement this like so: When we request a tile, and you know that you have data 1 level higher (which would be 4 tiles of data), your tile provider can take those 4 tiles and downsample them into 1 tile and provide them to the engine.

    As for min / max zoom. The tile provider is given the zoom level for each request, so it can choose to do the right thing based on the content. In fact, a common use case is to just set the maximum zoom level to 20 so the engine just plays dumb and the tile provider does what it needs to based on the content available.

  22. How do I get the base map to show through properly where/if there are missing tiles?

    Check your zorder. First step: add a base map with a lower z-order than the map on top of it. For example, the base map will have zorder 1, the map above it, zorder 2. Each map can be a virtual map that uses a tile provider, or use the base map from the tutorial or mapviz.

  23. Why do I see vector maps flickering or markers loading and unloading?

    It is likely that maps are exceeding the cache size. Possible remedies include reducing map complexity, increasing cache size, or both.

  24. There is a demo that uses the library "ASIHTTPRequest". If Automatic Reference Counting is enabled in the project, then the library will not compile. I can't seem to get the streaming tile server stuff to work when ARC is enabled. How do I fix this?

    The Altus Mapping Engine does work with ARC. No problems. However, ashtttp request library that is in the reference app is not ARC compatible. You can set compiler flags on the reference app to build it in ARC if you want, and you can use the mapping engine in any app with those same compiler flags. We don't need ARC in the mapping engine, but do not do anything to disrupt it.

  25. Is there any way to make the GPS marker in Tutorial 5 more obvious to the user?

    Tutorial 5 demonstrates the addition of an own-ship marker to show the current GPS position. If there are many layers visible on the map, however, it is easy for the user to lose the marker. The easy way to solve this problem in the Altus Mapping Engine is to add an animated own-ship beacon to the own-ship marker. To do this, need to add the two functions shown here to ViewController.m in Tutorial 5:

                    //////////////////////////////////////////////////////////////////
                    //This demonstrates  how to add an animated pulsing circle beacon
                    //Under the hood, the engine will add a dynamic vector marker layer
                    //named beacon.name and use that layer to animate a dynamically
                    //tesselated circle with each drawn frame.
                    - (void) addOwnshipBeacon
                    {	
                    	//Create an animated vector circle object and set up all of its properties
                    	MEAnimatedVectorCircle* beacon = [[[MEAnimatedVectorCircle alloc]init]autorelease];
                    	[email protected]"ownship_beacon";
                    	beacon.lineStyle = [[[MELineStyle alloc]initWithStrokeColor:[UIColor whiteColor]
                    			strokeWidth:2]autorelease];
                    	UIColor* lightBlue = [UIColor colorWithRed:30.0/255.0
                    			green:144.0/255.0
                    			blue:255.0/255.0
                    			alpha:1.0];
                    	beacon.outlineStyle = [[[MELineStyle alloc]initWithStrokeColor:lightBlue
                    			strokeWidth:4]autorelease];
                    	beacon.minRadius = 5;
                    	beacon.maxRadius = 75;
                    	beacon.animationDuration = 2.5;
                    	beacon.repeatDelay = 0;
                    	beacon.fade = YES;
                    	beacon.fadeDelay = 1.0;
                    	beacon.zOrder= 998;
                    	//Add the animated vector circle
                    	[self.meMapViewController addAnimatedVectorCircle:beacon];
                    }
                    //Update the location of the pulsing beacon
                    - (void) updateOwnshipBeaconLocation:(CLLocationCoordinate2D) location
                    {
                    	//Update position of beacon
                        [self.meMapViewController updateAnimatedVectorCircleLocation:@"ownship_beacon" newLocation:location animationDuration:1.0];
                    }
                  

    Now call addOwnshipBeacon at the bottom of Tutorial 5's addOwnShipMarker method like this:

                    //Add a beacon
                    [self addOwnshipBeacon];
                  

    And call updateOwnshipBeaconLocation at the bottom of Tutorial 5's updateOwnShipMarkerLocation method like this:

                    [self updateOwnshipBeaconLocation:location];
                  

    To remove the animated beacon, add this call to removeOwnshipMarker:

                    [self.meMapViewController removeAnimatedVectorCircle:@"ownship_beacon"];
                  

    Build and run the app. The beacon should be visible as an animated circle.

  26. On what Android devices will the BA3 Altus Mapping Engine run?

    Please see the full list here.

  27. What is MapShop?

    MapShop is a desktop application that solves one of OSM’s thorniest problems in a most elegant way, making it incredibly simple to work with the OSM database and create your own customized vector maps.

    Imagine that you want to create an app that uses maps on iOS or Android, and you want to do it using vectors from places like OSM, Esri Shape files, GeoJSON, etc. What you need is a tool that will let you bring the data onto the screen easily so that you can select what you want to see, and then the tool needs to create a compact vector file containing your data.

    Please also see the blog posts, BA3 Announces MapShop – A new era in easy OpenStreetMap (OSM) vector file definition and publishing and MapShop documentation and binaries are now publicly available.

    You may also want to look over the MapShop tutorials.

  28. We have created a vector map with MapShop but if flickers when we load it. What is wrong?

    The flickering is probably occurring because the vector map has too much data in it for the device to render. One possible cause: you are not filtering out 'tiny' things that are hardly visible, but create a lot of geometry for the engine to process. Whenever there is flashing it means the map assets are exceeding our LRU cache size (so adjusting the cache size is sometimes a possibility depending on the platform - see the FAQ for one perspective). The tiny things can be eliminated by adjusting the queries for the map design.

    For example, try to filter out tiny islands at lower levels of detail. One good way to do this is in your vector design database add a query in the features table like:

    select geom from land_table  WHERE ST_Area(Geography(geom)) > PIXEL_AREA * 4

    PIXEL_AREA is a constant used by MapShop and METool that is the estimated area of one "pixel" in a tile. So this scales depending on what tile is being viewed in MapShop or generated by METool. The constant scale "4" can be anything. We have used 1-4 depending on the map.

    Also, an easy way to get the appropriate level of detail for those low levels is to use a data set already built for that level. The 1:50m or 1:110m datasets from Natural Earth are good for levels ~ 7 as long as small islands are filtered: http://www.naturalearthdata.com/downloads/

  29. How do I load OpenStreetMap data into MapShop?

    This page shows how to load, style and visualize OSM data in MapShop: Learn about OpenStreetMap data, and create your own vector maps, by playing with BA3′s MapShop

  30. I am creating a map with MapShop that should not be very big, but it is taking many hours to generate the vector file and the final file is gigantic compared to what I expect. Do you have any idea what I am doing wrong?

    It is likely that your queries in the feature table are pulling in too much detail at too many levels. Try these tips:

    1. Zoom out to the highest altitude, so you see the whole planet as a small sphere. At this level, all you need to see are coastlines. So set your feature queries so that only coastlines are visible at this level, and look at it in Mapshop to confirm. Now zoom in a level - Maybe all you need to see is coastlines again. Set that up. Zoom in. Now maybe you want to add country boundaries. Zoom in again, and so on. Be sure to set your queries so that you only include the details of the map that you need at each level. If you have small roads being included at all zoom levels, it adds a lot of geometry to the map that is useless because you cannot see it. This invisible geometry takes up space and increases the time to create the map file.

    2. Try to filter out things like tiny islands at lower levels of detail. One good way to do this is in your vector design database add a query in the features table like:

      select geom from land_table  WHERE ST_Area(Geography(geom)) > PIXEL_AREA * 4

      PIXEL_AREA is a constant used by MapShop and metool that is the estimated area of one "pixel" in a tile. So this scales depending on what tile is being viewed in Mapshop or generated by metool. The constant scale "4" can be anything. We have used 1-4 depending on the map.

    3. Use a "highest detail only" vector map.



If you have questions about Altus products and services, the demonstration code or licensing, please contact us at: [email protected]. Also, any feedback, comments or suggestions that you have are always greatly appreciated.