This tutorial is heavily based on Rupert’s article here. However, the steps in this article are very different on some points. There are some steps that I had to figure out using other sources.
Generating OpenStreetMap tiles database
We’re going to use downloadosmtiles.pl to download OSM tiles for a specific region.
wget http://search.cpan.org/CPAN/authors/id/R/RO/ROTKRAUT/Geo-OSM-Tiles-0.04.tar.gz
tar -xf Geo-OSM-Tiles-0.04.tar.gz
cd Geo-OSM-Tiles-0.04
perl Makefile.PL # make sure there are no errors/warnings
make
make test
make install # you might have to use sudo
If you get errors like this on Makefile.PL: “Warning: prerequisite YAML 0 not found.“, install the missing Perl libraries first before continuing.
Determine the region you want to download. You can use OSM: go to http://openstreetmap.org and select Export from the top menu. You should be able to see 4 fields specifying the selected region coordinates. Click on Manually select a different area to define your own region.
Execute downloadosmtiles.pl with the coordinates and your desired zoom levels to download the tiles:
When specifying values for lat and long, enter the lowest value first. Call downloadosmtiles.pl help to see more options.
The destination folder should now contain image files organized like this:
Download and run map2sqlite to convert the tile set to a sqlite database. You can download the source here and compile it in XCode. Or you can download the compiled binary here. We’ll use the compiled binary in this example.
wget http://shikii.net/blog/downloads/map2sqlite-bin.zip
tar -xf map2sqlite-bin.zip
./map2sqlite -db /your/mymap.sqlite -mapdir /your/tiles/folder
Using the offline map in Route-Me
For a quick example, we’ll use a sample project included in route-me.
Open the sample project at samples/SimpleMap/SimpleMap.xcodeproj. Select the SimpleMap scheme and test to make sure it runs before we do anything to it.
Add the map database you just created to the project’s resources. Make sure that it is also added to the Copy Bundle Resources.
In MapViewViewController.m, add an import for RMDBMapSource.h.
Add this to the bottom of -viewDidLoad of MapViewViewController.m:
// Use the bundled database as our map source
RMDBMapSource *mapSrc = [[[RMDBMapSource alloc] initWithPath:@"mymap.sqlite"] autorelease];
[[[RMMapContents alloc] initWithView:mapView tilesource:mapSrc] autorelease];
// Constrain our map so the user can only browse through our exported map tiles
[mapView setConstraintsSW:CLLocationCoordinate2DMake(mapSrc.bottomRightOfCoverage.latitude, mapSrc.topLeftOfCoverage.longitude)
NE:CLLocationCoordinate2DMake(mapSrc.topLeftOfCoverage.latitude, mapSrc.bottomRightOfCoverage.longitude)];
// Move to the center of our exported map
[mapView moveToLatLong:mapSrc.centerOfCoverage];
The first 2 lines instruct the map view (RMMapView) to use the offline map as the map source. The -setConstraintsSW:NE call is not necessary but I think it’s a good idea to only show the map region that we have exported. The user will see empty gray spaces for regions that we don’t have map tiles for without the constraints.
In Android, if you provide custom background images for buttons, you will lose the pressed and disabled image effects. The common way to fix that is to provide additional images for those states. I’m lazy and I find this inconvenient especially during the prototyping phase of app development.
I’ve always liked the way iOS automatically handles pressed and disabled states for custom button backgrounds so I made a Button subclass that automatically darkens the background image when the button is pressed, and makes the background transparent when it is disabled. This is done by using a custom LayerDrawable for the button that contains the original background Drawable. The LayerDrawable has to be stateful and should change the background properties depending on the current state in onStateChange(). The full source explains it better:
package net.shikii.widgets;
import android.content.Context;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LightingColorFilter;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
import android.widget.Button;
/**
* Applies a pressed state color filter or disabled state alpha for the button's background
* drawable.
*
* @author shiki
*/
public class SAutoBgButton extends Button {
public SAutoBgButton(Context context) {
super(context);
}
public SAutoBgButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SAutoBgButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void setBackgroundDrawable(Drawable d) {
// Replace the original background drawable (e.g. image) with a LayerDrawable that
// contains the original drawable.
SAutoBgButtonBackgroundDrawable layer = new SAutoBgButtonBackgroundDrawable(d);
super.setBackgroundDrawable(layer);
}
/**
* The stateful LayerDrawable used by this button.
*/
protected class SAutoBgButtonBackgroundDrawable extends LayerDrawable {
// The color filter to apply when the button is pressed
protected ColorFilter _pressedFilter = new LightingColorFilter(Color.LTGRAY, 1);
// Alpha value when the button is disabled
protected int _disabledAlpha = 100;
public SAutoBgButtonBackgroundDrawable(Drawable d) {
super(new Drawable[] { d });
}
@Override
protected boolean onStateChange(int[] states) {
boolean enabled = false;
boolean pressed = false;
for (int state : states) {
if (state == android.R.attr.state_enabled)
enabled = true;
else if (state == android.R.attr.state_pressed)
pressed = true;
}
mutate();
if (enabled && pressed) {
setColorFilter(_pressedFilter);
} else if (!enabled) {
setColorFilter(null);
setAlpha(_disabledAlpha);
} else {
setColorFilter(null);
}
invalidateSelf();
return super.onStateChange(states);
}
@Override
public boolean isStateful() {
return true;
}
}
}
To use this, just replace your original button declarations like this:
<Button
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/button_blue_bg"
android:text="Button with background image" />
To this:
<net.shikii.widgets.SAutoBgButton
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/button_blue_bg"
android:text="Button with background image" />
I discovered this by accident. It’s probably been there for a long time but I just noticed it now. Normally, if you have very few rows in your table, it would look like this:
Notice that I only have 2 rows. The other empty ones still have empty separator lines. Sometimes that’s not what you want, especially if you have custom row designs. To remove those lines, you just have to supply a value for tableFooterView. An empty UIView will work fine:
We have switched from Apache to Nginx a month ago. PHP is running on FastCGI using PHP-FPM. I have just recently tried to debug our app using FirePHP and got a 502 Bad Gateway response from Nginx. It looks like Nginx by default limits the header output. This is the error in Nginx’s error log:
2011/09/21 09:36:16 [error] 816#0: *5 upstream sent too big header while reading response header from upstream,
client: 192.168.56.1, server: v.piclyf.com, request: "GET /pics HTTP/1.1",
upstream: "fastcgi://127.0.0.1:9000", host: "v.piclyf.com", referrer: "http://v.piclyf.com/dashboard"
The fix that I found is to increase the values of fastcgi_buffer_size and fastcgi_buffers. Add these 2 directives to your PHP FastCGI config in Nginx (i.e. /etc/nginx/sites-available/default):
location ~ \.php$ {
root /your/site/root;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
# set these two:
fastcgi_buffer_size 16k;
fastcgi_buffers 4 16k;
}
I was working on a utility class and was playing with the idea of using the id of an object (e.g. NSObject) as a key in NSDictionary. Setting it directly doesn’t work though:
NSObject *obj = [[[NSObject alloc] init] autorelease]; // we'll use this as the key
NSMutableDictionary *dict = [[[NSMutableDictionary alloc] init] autorelease];
[dict setObject:@"a value" forKey:obj]; // won't work
The above will lead to an exception like this:
NSInvalidArgumentException, reason: '-[NSObject copyWithZone:]: unrecognized selector
sent to instance 0x7ca6160'
The solution I arrived at was to use the string representation of the object. Simply casting the object to NSString will not work though:
[dict setObject:@"a value" forKey:(NSString *)obj]; // same exception
Using a new NSString instance will work however:
NSString *key = [NSString stringWithFormat:@"%@", (NSString *)obj]; // use a new NSString
[dict setObject:@"a value" forKey:key]; // works!
Update
curthard89 from Forrst pointed out that it would be better to use [NSObject hash] instead of typecasting to string. The reason is NSDictionary and NSArray string representations can get really long and would be inefficient. I’m now using this technique:
So I was able to partition a Macbook Pro 2010 (Snow Leopard) using Boot Camp in order to install Windows 7. I just want to point out this possible solution when you get this error when trying to create a partition:
Your Disk Cannot Be Partitioned Because Some Files Cannot Be Moved
Back up the disk and use Disk Utility to format the disk as a single Mac OS Extended (Journaled) volume. Restore your information to the disk and try using Boot Camp Assistant again.
Note that I said this is a possible solution. That means that this may not work for you. Most of the solutions I found on the Internet point to using defrag tools like iDefrag. I didn’t want to go that way cause I really don’t have the money to buy those tools.
Here’s what I did to fix this error:
Clean up the hard drive. Move large files to an external backup disk. There are tools like OmniDiskSweeper to that can help in finding large files.
Reboot and boot up using your Mac OS X Install DVD. (Press C when after the startup sound to boot using the DVD)
Choose Utilities > Disk Utility in the menu and Repair the hard drive.
Restart and try partitioning using Boot Camp again.
I’m not ultimately sure if Step 1 is really required but I don’t have time to test it again.
This is a quick fix for PHP errors like these on a Media Temple DV:
Warning: include_once() [function.include-once]: open_basedir restriction in effect.
I got this a few days ago when trying to setup an app. There are instructions in Media Temple’s site on how to fix this but this set of steps is what worked for me.
Edit or create a vhost.conf file inside this folder: /var/www/vhosts/YOURDOMAIN.COM/conf/. Replace YOURDOMAIN.COM with the domain you wish to configure.
You can get the friends of a Facebook user using this FQL query:
SELECT uid FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1 = $userId)
This request requires the access token of the user whose friends you want to access. Here’s an example using the Facebook SDK for PHP:
$client = new Facebook(array('appId' => 'YOUR_APP_ID', 'secret' => 'YOUR_APP_SECRET'));
$userId = 123;
$fql = "SELECT uid, first_name, last_name FROM user "
. "WHERE uid in (SELECT uid2 FROM friend where uid1 = $userId)";
$friends = $client->api(array(
'method' => 'fql.query',
'access_token' => 'USER_ACCESS_TOKEN',
'query' => $fql,
));
// we now have an array containing the friends of the user
print_r($friends);
You can look at the user table reference for other fields besides first_name and last_name. Note that there are some fields such as email that require user specific permissions. If the user/friend has not given your app email permissions, chances are you won’t be able to get the email address. For instances like these, you can opt to filter just the friends who have given your app permissions. This can be done using the is_app_user field:
SELECT uid, first_name, last_name FROM user
WHERE is_app_user = 1 AND uid IN (SELECT uid2 FROM friend WHERE uid1 = $userId)
The case with email addresses
From my tests, it looks like it’s more reliable to get the email addresses of friends if you don’t put in any user access token when calling $client->api(). Here’s a complete example of getting a list of friends and getting all their email addresses:
$appId = 'YOUR_APP_ID';
$appSecret = 'YOUR_APP_SECRET';
$userId = 'A_FACEBOOK_USER_ID';
$userAccessToken = 'THE_FACEBOOK_USER_ACCESS_TOKEN';
$client = new Facebook(array('appId' => $appId, 'secret' => $appSecret));
// get all friends who has given our app permissions to access their data
$fql = "SELECT uid, first_name, last_name, email FROM user "
. "WHERE is_app_user = 1 AND uid IN (SELECT uid2 FROM friend WHERE uid1 = $userId)";
$friends = $client->api(array(
'method' => 'fql.query',
'access_token' => $userAccessToken,
'query' => $fql,
));
// make an array of all friend ids
$friendIds = array();
foreach ($friends as $friend) {
$friendIds[] = $friend['uid'];
}
// get info of all the friends without using any access token
$friendIds = implode(',', $friendIds);
$fql = "SELECT uid, first_name, last_name, email FROM user WHERE uid IN ($friendIds)";
$friends = $client->api(array(
'method' => 'fql.query',
'query' => $fql,
// don't use an access token
));
// we should now have a list of friend infos with their email addresses
print_r($friends);
This was tested on CentOS 5.6 on a fresh MediaTemple (dv) setup. I figure it should be the same for any CentOS install. This set of instructions is a result of hours spent on installation troubleshooting; google searches; and trial and errors. Hopefully this can help other people.
Install dependencies
These are needed to enable GraphicsMagick add-ons. In here, I only included what I think are commonly required. But feel free to include other libraries that you need.
We will need to download and compile GraphicsMagick ourselves. It looks like it is not available in yum yet. MediaTemple users are advised to use chroot to prevent noexec and /tmp related errors. Execute these on the console:
# work on a temporary dir of your preference
cd /root/tmp
# download source tarball. See here for other versions: ftp://ftp.graphicsmagick.org/pub/GraphicsMagick/
wget ftp://ftp.graphicsmagick.org/pub/GraphicsMagick/1.3/GraphicsMagick-1.3.9.tar.gz
# extract and open the extracted folder
tar -xvf GraphicsMagick-1.3.9.tar.gz
cd GraphicsMagick-1.3.9
./configure --enable-shared
Using --enable-shared above has helped prevent errors like this when installing gmagick through pecl:
Build Error: /usr/bin/ld: /usr/local/lib/libGraphicsMagickWand.a(drawing_wand.o):
relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object;
recompile with -fPIC
After ./configure is done, make sure that the Configured value of the add-ons you need are set to Yes. Also make sure that enable-shared is set to Yes. You can see this at the end part of configure‘s output. It should look like this:
Option Configure option Configured value
------------------------------------------------------------------
Shared libraries --enable-shared=yes yes
Static libraries --enable-static=yes yes
GNU ld --with-gnu-ld=yes yes
Quantum depth --with-quantum-depth=8 8
Delegate Configuration:
BZLIB --with-bzlib=yes no
DPS --with-dps=yes no
FlashPIX --with-fpx=no no
FreeType 2.0 --with-ttf=yes yes
Ghostscript None gs (8.70)
Ghostscript fonts --with-gs-font-dir=default /usr/share/fonts/default/Type1/
Ghostscript lib --with-gslib=no no
JBIG --with-jbig=yes no
JPEG v1 --with-jpeg=yes yes
JPEG-2000 --with-jp2=yes no
LCMS --with-lcms=yes no
Magick++ --with-magick-plus-plus=yes yes
PERL --with-perl=no no
PNG --with-png=yes yes
TIFF --with-tiff=yes yes
TRIO --with-trio=yes no
Windows fonts --with-windows-font-dir= none
WMF --with-wmf=yes no
X11 --with-x= no
XML --with-xml=yes no
ZLIB --with-zlib=yes yes
Next, compile and install:
make
make install
You can then test if GraphicsMagick has been successfully installed by executing commands like:
gm version
Install Gmagick PHP extension
We’ll install gmagick using PECL. MediaTemple users are still advised to use chroot.
pecl install gmagick
If you get an error about gmagick not having a stable version, you can specify the version instead:
pecl install gmagick-1.0.8b2
Next, add extension=gmagick.so to php.ini and restart Apache if necessary. This is outside the scope of this article though. Please Google it if you don’t know how.
And we’re done!
P.S. If you’re having trouble, it might help to look/search for solutions using “ImageMagick” instead. There are fewer resources for GraphicsMagick compared to ImageMagick. I found some articles for ImageMagick that can be used for GraphicsMagick too.
To integrate libraries using namespaces into a Yii Framework project, you can simply use Yii::setPathOfAlias to have the classes autoloaded by Yii when needed. Just specify the root namespace as the alias and the physical location of that root alias as the path.
Using Predis as an example, if we put the code in:
/vendors/predis/lib/Predis
We’ll add it to Yii as an alias named Predis so classes under it can be autoloaded:
Now when we call new Predis\Client(), Yii will look for a file named Client.php in /vendors/predis/lib/Predis. The same holds true for other classes under subfolders (e.g. Predis\Commands\Append).