2012
11th October, 2012 - Posted by david
I’ve been working on building the mobile version of CarsIreland.ie lately and one of the features we want is to offer directions from a user’s current location to any of our car dealerships, assuming we have their latitude and longitude co-ordinates. Getting the directions and displaying them on a map are ridiculously simple, thanks to Google’s Direction Service API. Going into the detail of getting this working is beyond the scope of this post, but what I hope to show here is how to resolve an issue in mobile (and possibly desktop) Safari, and maybe even some other browsers.
When you have instantiated your new google.maps.DirectionsService()
and called it’s route
function, passing your source and destination (among other things) as parameters, you’re supposed to give a callback function with response
and status
parameters. Assuming the call to route
was successful, the response
parameter should be a big JSON block of at least one route and step by step guides detailing how to get from source to destination. Conveniently, Google also provide a very handy object called a DirectionsRenderer
, which has a function called setDirections
, which can generate a nicely formatted HTML table of directions. See https://google-developers.appspot.com/maps/documentation/javascript/examples/directions-panel for an example.
The problem I experienced and am aiming to solve here is that some of the directions (in Ireland at least) involve very long motorway/freeway names, where each junction is separated by a ‘/’, but with no spaces. This can lead to very long strings of the format ‘Long/And/Winding/Junction/Name’. Add in the fact that they also include the Irish/Gaelic translation for some words and it gets even longer! When viewing this steps on Android’s Dolphin or even a desktop Firefox, the browser recognizes that it can split the line at the ‘/’ and thus doesn’t widen the page. Safari unfortunately doesn’t do this and forces very wide page widths, which makes the page look awful. So, today I figured a way to resolve this.
What I did was traverse the response
object you get back from Google, looking at each instruction step, trying to find one of these long strings, and replacing the ‘/’ with ‘ / ‘, i.e. a space character on either side, so Safari will then break the lines and not force a wide page. Doing a simple string replace wasn’t sufficient, as some of the instructions contain HTML tags, which can have ‘/’ in them that we ideally want to keep.
So first up is the Javascript regular expression to find matching instances of “long/string”. In simple terms, it’s any alpha-numeric character, followed by a ‘/’, followed by another alpha-numeric character. In Javascript I came up with:
1
| var patt = /([a-z0-9]{1})\/([a-z0-9]{1})/gi; |
The gi
at the end of the pattern means global search (i.e. don’t stop at the first match), case insensitive (hence no ‘A-Z’ is required).
Now, all we have to do is cycle through the response, looking for routes
, legs
, steps
and instructions
and replacing as necessary, via a string’s replace function:
1 2 3
| // e.g.
var repl = "$1 / $2";
instruction = instruction.replace(patt, repl); |
So, to loop through the response and do the replacing, we need a few nested for
loops, our pattern and our replace sequence, as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| if (typeof response['routes'] != 'undefined') {
var patt = /([a-z0-9]{1})\/([a-z0-9]{1})/gi;
var repl = "$1 / $2";
// cycle through each route
for (var i=0; i<response['routes'].length; i++) {
var route = response['routes'][i];
if (typeof route['legs'] != 'undefined') {
// cycle through each leg in that route
for (var j=0; j<route['legs'].length; j++) {
var leg = route['legs'][j];
if (typeof leg['steps'] != 'undefined') {
// cycle through each step in that leg
for (var k=0; k<leg['steps'].length; k++) {
var instructions = leg['steps'][k]['instructions'];
// if we've found an instruction with a matching pattern
if (instructions.match(patt)) {
// do the replace
response['routes'][i]['legs'][j]['steps'][k]['instructions'] = instructions.replace(patt, repl);
}
}
}
}
}
}
} |
So, hopefully this well help people experiencing the same problem I was having with the long strings caused by a lack of spaces between ‘/’ characters! As an alternative, one may just wish to only have a space after the ‘/’, in which case, the replace pattern becomes "$1/ $2"
.
Read more...
2nd August, 2012 - Posted by david
So, I recently started a new job as Lead Developer on carsireland.ie and one of the first things I was tasked with was moving the codebase from a simple PC running Linux to the cloud, so that it could be accessed remotely, outside the office. Now, while I do prefer Git, SVN is still reasonably popular, especially with websites older than a few years, hence the CTO wanted to stick with it, for the time being at least! Needless to say, most of the following is best done as root, or at least with sudo privileges. Also, this is done on Ubuntu, hence the use of apt-get
.
1. Setting up Apache for HTTPS
Apache was already running on the server, but it had to be enabled for HTTPS. Firstly You need to generate self-signed SSL certificates. You’ll be asked for a passphrase; enter one and note it down:
1 2 3
| openssl genrsa -des3 -out server.key 2048
openssl req -new -key server.key -out server.csr
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt |
Move the certificates to somewhere that Apache expects to find it:
1 2
| cp server.crt /etc/ssl/certs
cp server.key /etc/ssl/private |
Enable SSL for Apache
1 2 3 4 5
| a2enmod ssl
a2ensite default-ssl
/etc/init.d/apache2 stop; sleep 2; /etc/init.d/apache2 start
# this last step is how I restart Apache.
# I don't trust the 'restart' option. There's probably other/better ways of doing this |
2. SVN
Install SVN and it’s Apache module
1
| apt-get install subversion libapache2-svn |
Create a new folder for the code (we’ll call the folder ‘svn’):
Create the repository:
1
| svnadmin create /home/svn |
Tell Apache about the repository:
1
| nano /etc/apache2/sites-available/default-ssl |
This opens up the pretty simple nano editor. At the bottom of the file, before the final <VirtualHost>
, add:
1 2 3 4 5 6 7 8
| <location svn="">
DAV svn
SVNPath /home/svn
AuthType Basic
AuthName "Your repository name"
AuthUserFile /etc/subversion/passwd
Require valid-user
</location> |
You may need to enable your SSL site, so if the files /etc/apache2/sites-enabled/000-default-ssl
or /etc/apache2/sites-enabled/default-ssl
don’t exist, do:
1
| ln -s /etc/apache2/sites-available/default-ssl /etc/apache2/sites-enabled/000-default-ssl |
For Apache to be able to read/write to the repository, we need to change it’s owner to www-data:
1
| chown -R www-data:www-data /home/svn |
Next, we need to add some login details for users, i.e. developers (you’ll be asked to enter a password):
1 2 3
| htpasswd -c /etc/subversion/passwd user_name
# user_name should correspond with the username of some one you want to have access to the repository.
# The password entered can be different from their normal login password and is used to access the repository at all times. |
For subsequent users, drop the -c
flag above.
Restart Apache (however you want to do it). Following from above:
1
| /etc/init.d/apache2; sleep 2; /etc/init.d/apache2 start |
You should now be able to view the initial empty repository at http://server.locaton/svn
where ‘server.location’ is either an IP address or a domain, depending on how you’ve set-up the server.
If you have an SVN dump of your repository and you want to load it into the new one, you can simply do:
1
| svnadmin load --force-uid /home/svn > dumpfile |
At this point, your SVN server should be up and running and ready to take commits. You may need to play around with the permissions of your /home/svn
directories, making certain ones executable/writeable to Apache. If I’ve left anything else out, please let me know in the comments.
Read more...
12th May, 2012 - Posted by david
The Problem
Where I work, our tool supports 6 different languages, where translations are contained in various sets of language files. One of these sets consists of the translations stored in Javascript files as JSON blocks
Read more...
15th March, 2012 - Posted by david
When it comes to coding and debugging, I generally keep things simple, opting for a basic text editor (Sublime Text 2 with Vim key-bindings being my current choice) and simple debug output statements when trying to track down a bug. With my current job, I deal with an API over AJAX so it’s not easy to send debug statements to the browser, hence had been using a combination of PHP’s error_log
and print_r($var, 1)
to get the value of a variable on the server. When debugging this way, I’d usually be doing a tail -f
on my error log file, monitoring changes to that as I go.
This was all fine, but got very frustrating when dealing with arrays, objects and even strings with newline characters. The reason for this frustration was that newline characters were being displayed in the error log as \n
and no new line, so something like
1 2
| $var = array('zero' => 0, 'one' => 1);
error_log(print_r($var, 1)); |
would produce:
1
| Array\n(\n [zero] => 0\n [one] => 1\n) |
instead of the nicer:
1 2 3 4 5
| Array
(
[zero] => 0
[one] => 1
) |
Not too bad for small arrays but for large objects it’s a nightmare! Googling around didn’t have an easy answer. I’m sure it’s some setting deep in php.ini or my Apache config, but I managed to come up with a pretty neat solution, which I’m going to document here.
I started by creating my own error log in /tmp/derror
(David’s Error = derror!) and letting any one write to it (I realise this could be slightly cleaner/more secure):
1 2
| touch /tmp/derror
chmod 766 /tmp/derror |
Next I needed a nice debug function to write to this file. I wrote one that’ll take any number of parameters and for each one, output the current time along side a dump of their value. If it’s an object or class, use print_r, otherwise just display the value:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function derror() {
$f = fopen('/tmp/derror', 'a');
foreach (func_get_args() as $obj) {
fwrite($f, date('Y-m-d G:i:s')."\n");
if (is_array($obj) || is_object($obj)) {
fwrite($f, print_r($obj,1)."\n\n");
}
else {
fwrite($f, $obj."\n\n");
}
}
fclose($f);
}
// called like
derror($var1, $var2); |
So, that function works fine but after a while I realised by doing my tail -f
on my new error file, I was missing out on the real server errors. So, I had 2 different terminal tabs open, flipping between them both, which got annoying after about 2 errors! Luckily, I quickly thought of a way around this: route PHP’s error logging to my new file. The way Apache and virtual hosts are set-up this was quite easy and you can even log to 2 different files, thus preserving your ‘normal’ error file too. so, in your /etc/apache/sites-available/default
or whatever, in the <Virtualhost:*.80>
block for your site, copy the line for CustomLog
and point that to your error file, i.e.
1
| CustomLog /tmp/derror combined |
This should now route all Apache errors to your new file, so you have the best of both worlds!
To prevent the file getting to big over time, I set-up a cron job to simply delete the file and create a new one every Monday morning.
Read more...