Integrating Foundation 5 with SASS and GRUNT with website

Recently several clients have requested that websites is built using Foundation. For those of you who don’t what that is click here.

It basically is a responsive-design framework that is built mobile-first, meaning mobile-view is designed first and then expanded up to bigger screens.

If you want to install Foundation with SASS support in your website do the following:

# Go to project root in terminal

sudo gem install foundation
sudo npm install -g bower grunt-cli
foundation new MY_PROJECT

This installs bower and grunt for your project and also creates a new foundation-installation with the name MY_PROJECT. Your foundation SASS-files are now located at “MY_PROJECT/scss/”.

Now we need to edit a few files to get it working. Edit “MY_PROJECT/scss/app.scss” like this:

@import "../bower_components/foundation/scss/foundation/components/_global";
@import "settings";
@import "../bower_components/foundation/scss/foundation";

// Or selectively include components
// @import
// "../bower_components/foundation/scss/foundation/components/accordion",
// "../bower_components/foundation/scss/foundation/components/alert-boxes",
// "../bower_components/foundation/scss/foundation/components/block-grid",
// "../bower_components/foundation/scss/foundation/components/breadcrumbs",
// "../bower_components/foundation/scss/foundation/components/button-groups",
// "../bower_components/foundation/scss/foundation/components/buttons",
// "../bower_components/foundation/scss/foundation/components/clearing",
// "../bower_components/foundation/scss/foundation/components/dropdown",
// "../bower_components/foundation/scss/foundation/components/dropdown-buttons",
// "../bower_components/foundation/scss/foundation/components/flex-video",
// "../bower_components/foundation/scss/foundation/components/forms",
// "../bower_components/foundation/scss/foundation/components/grid",
// "../bower_components/foundation/scss/foundation/components/inline-lists",
// "../bower_components/foundation/scss/foundation/components/joyride",
// "../bower_components/foundation/scss/foundation/components/keystrokes",
// "../bower_components/foundation/scss/foundation/components/labels",
// "../bower_components/foundation/scss/foundation/components/magellan",
// "../bower_components/foundation/scss/foundation/components/orbit",
// "../bower_components/foundation/scss/foundation/components/pagination",
// "../bower_components/foundation/scss/foundation/components/panels",
// "../bower_components/foundation/scss/foundation/components/pricing-tables",
// "../bower_components/foundation/scss/foundation/components/progress-bars",
// "../bower_components/foundation/scss/foundation/components/reveal",
// "../bower_components/foundation/scss/foundation/components/side-nav",
// "../bower_components/foundation/scss/foundation/components/split-buttons",
// "../bower_components/foundation/scss/foundation/components/sub-nav",
// "../bower_components/foundation/scss/foundation/components/switches",
// "../bower_components/foundation/scss/foundation/components/tables",
// "../bower_components/foundation/scss/foundation/components/tabs",
// "../bower_components/foundation/scss/foundation/components/thumbs",
// "../bower_components/foundation/scss/foundation/components/tooltips",
// "../bower_components/foundation/scss/foundation/components/top-bar",
// "../bower_components/foundation/scss/foundation/components/type",
// "../bower_components/foundation/scss/foundation/components/offcanvas",
// "../bower_components/foundation/scss/foundation/components/visibility";

Also edit your “MY_PROJECT/scss/_settings.scss” and update the import to this:

@import "../bower_components/foundation/scss/foundation/functions";

I usually like having SASS and CSS files in distinct folders so I have one folder at /sass for SASS and one folder for CSS at /css.

Open up your main sass file (i.e. /sass/style.scss) for edit:

// Import Foundation with settings
@import "../MY_PROJECT/scss/app";

// Other stuff here
// …

To install GRUNT, make a grunt folder and create a file named ‘package.json’ like this:

{
"name": "MyProject",
"version": "0.0.1",
"description": "Node for grunt, compile scss",
"private": true,
"license": "MIT",
"devDependencies": {
"grunt": "~0.4.2",
"grunt-contrib-watch": "*",
"grunt-contrib-compass": "*",
"grunt-contrib-concat": "*",
"grunt-contrib-uglify": "*",
"grunt-contrib-jshint": "*",
"grunt-rem-to-pixels": "^0.2.0"
}
}

For more information visit npm Documentation.

Visit grunt folder and execute:

npm install

Now create a GRUNT file named ‘gruntfile.js’ like this:

module.exports = function(grunt) {

    var tfThemeDir = "../";

    // Project configuration.
    grunt.initConfig({
        pkg: grunt.file.readJSON(‘package.json’),
        compass: {
          dist: {
            options: {
              cssDir: tfThemeDir + "/css",
              sassDir: tfThemeDir + "/sass",
              imagesDir: tfThemeDir + "/images",
              javascriptsDir: tfThemeDir + "/js",
              outputStyle: ‘compressed’
            }
          }
        },
        rem_to_px: {
            options: {
                baseFontSize: 16,
                removeFontFace: true
            },
            dist: {
                src: [ tfThemeDir + ‘/css/**/*.css’ ],
                dest: tfThemeDir + ‘/stylesheet-fallbacks/’
            }
        },
        jshint: {
          files: [ tfThemeDir +‘/js/scripts.js’]
        },
        watch: {
          css: {
            files: [ tfThemeDir +‘/sass/**/*.scss’],
            tasks: [‘compass’]
          },
          js: {
            files: [ tfThemeDir +‘/js/**.js’],
            tasks: [‘uglify’]
          }
        },
        uglify: {
          dist: {
              files: [ tfThemeDir + ‘/js/scripts.min.js’ ]
          }
        }
    });

    // Load the plugin that provides the "uglify" task.
    grunt.loadNpmTasks(‘grunt-contrib-watch’);
    grunt.loadNpmTasks(‘grunt-contrib-compass’);
    grunt.loadNpmTasks(‘grunt-contrib-jshint’);
    grunt.loadNpmTasks(‘grunt-contrib-concat’);
    grunt.loadNpmTasks(‘grunt-contrib-uglify’);

    /** @link https://github.com/lohmander/grunt-rem-to-px */
    grunt.loadNpmTasks(‘grunt-rem-to-pixels’);

};

For more information visit Grunt Documentation.

Now compile your sass file by executing:

grunt compass

SASS files in /sass/ are compiled into CSS files in /css/.

Now you should have running Foundation installation with compiled CSS from SASS via GRUNT. You can add your other stylesheets as neccesary below the Foundation import. Settings for Foundation are specified at “MY_PROJECT/scss/_settings.scss”.

The good thing of doing a installation like this is that you can use bower to update your Foundation installation in isolation and still you include Foundation and it’s settings in your project. Do this to update your Foundation installation:

cd MY_PROJECT
bower update

Hope you found this guide useful.

PHP Profiling Time and Memory with OSX 10.10 and Xdebug

First you need to have installed Xdebug, to install Xdebug on Linux debian click here.

Configure XDEBUG for time specific profiling:

mkdir /var/log/xdebug-profiling-output/
chmod -R 777 /var/log/xdebug-profiling-output/
nano /etc/php5/apache2/conf.d/xdebug.ini

xdebug.profiler_output_dir=/var/log/xdebug-profiling-output/
xdebug.profiler_enable=0
xdebug.profiler_enable_trigger=1

These settings mean that time profiling outputs will be stored in /var/log/xdebug-profiling-output/, profiling will be disabled by default and only activated using trigger. Having profiling on as default is not recommended because it drains the system resources.

Now reboot Apache2:

/etc/init.d/apache2 graceful

To generate a profiling log, append ?XDEBUG_PROFILE=1 to your site-url, like this: http://www.mywebsite.com/index.php?XDEBUG_PROFILE=1

To be able to parse the output in OSX 10.10 you need Graphviz installed, install it using Homebrew by running:

brew install qcachegrind

Generate a log on your website and then remember the filename path. Copy it over to your OSX machine using:

scp root@mywebsite.com:/var/log/xdebug-output/cachegrind.out.4852 ~/Downloads/

Now open this file in the application qcachegrind to analyze the profiling. You can also analyze the Xdebug profiling output using Php Storms built-in Xdebug Profiler Snapshot analyzer if you have it.

Configure XDEBUG for memory specific profiling:

mkdir /var/log/xdebug-trace-output/
chmod -R 777 /var/log/xdebug-trace-output/
nano /etc/php5/apache2/conf.d/xdebug.ini

xdebug.auto_trace=0
xdebug.trace_enable_trigger=1
xdebug.trace_output_dir=/var/log/xdebug-trace-output/
xdebug.collect_params=0
xdebug.trace_format=1
xdebug.show_mem_delta=1
xdebug.collect_assignments=1

These settings means that memory profiling will be disabled by default to save resources, profiling logs will be generated in the folder /var/log/xdebug-trace-output/.

Now reboot Apache2

/etc/init.d/apache2 graceful

To generate a profiling log, append ?XDEBUG_TRACE=1 to your site-url, like this: http://www.mywebsite.com/index.php?XDEBUG_TRACE=1

Check generate filename and copy trace log from remote host to OSX.

scp root@mywebsite.com:/var/log/xdebug-trace-output/trace.2043925204.xt ~/Downloads/

Now you can open the log in text-editor.

PHP serializing and unserializing with circular references

In Aomebo Framework, which is my PHP MVC framework. Runtimes can be serialized and unserialized to improve speed.

Runtimes could contain a list of Routes, which is used for URL routing and URL generation. The Routes contain a reference to the Runtime that they are associated with.

So we have the following relationships.

Runtime -> Routes, Route -> Runtime = Runtime <-> Route

In order to improve the speed of the framework I was implementing a serializing and unserializing feature. Serializing Runtimes without Routes worked from scratch. When a Runtime contain at least one Route, the php execution stopped without any notice (Fatal Error). Was hard to debug.

I solved it by doing the following.

Serializing:
1. Runtime Routes are stored outside of Runtimes.
2. Serialize all Runtimes without their Routes.
3. Replace the references to Runtimes in Routes with class-name strings only.
4. Serialize all Routes.

Unserializing:
1. Unserialize all Runtimes (no Routes were stored in Runtimes).
2. Unserialize all Routes, references are only class-name strings now.
3. Iterate through Routes and replace reference class-name strings with instanciated Runtimes based on class-name.

Now it works as expected, and with high improve in speed and resources.

Building a ajax spinner in SVG

So you get a SVG static image delivered from your client.

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="50px" height="50px" viewBox="0 0 49.715 49.718" enable-background="new 0 0 49.715 49.718" xml:space="preserve"><circle fill="#111111" cx="24.857" cy="4.495" r="4.496"></circle><circle fill="#333333" cx="45.219" cy="24.858" r="4.496"></circle><circle fill="#555555" cx="39.122" cy="10.486" r="4.496"></circle><circle fill="#777777" cx="4.496" cy="24.858" r="4.496"></circle><circle fill="#999999" cx="24.858" cy="45.222" r="4.496"</circle><circle fill="#BBBBBB" cx="10.487" cy="10.574" r="4.496"></circle><circle fill="#CCCCCC" cx="10.487" cy="39.209" r="4.496"></circle><circle fill="#EEEEEE" cx="39.123" cy="39.209" r="4.496"></circle></svg>

And it looks like this:

To make it animated, we need to add the following line within all circle tags:

<animateTransform attributeName="transform" attributeType="XML" type="rotate" values="0 25 25; 45 25 25; 90 25 25; 135 25 25; 180 25 25; 225 25 25; 270 25 25; 315 25 25" dur="1s" repeatCount="indefinite" additive="replace" calcMode="discrete" fill="freeze"/>

Like this:

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="50px" height="50px" viewBox="0 0 49.715 49.718" enable-background="new 0 0 49.715 49.718" xml:space="preserve"><circle fill="#000000" cx="24.857" cy="4.495" r="4.496"><animateTransform attributeName="transform" attributeType="XML" type="rotate" values="0 25 25; 45 25 25; 90 25 25; 135 25 25; 180 25 25; 225 25 25; 270 25 25; 315 25 25" dur="1s" repeatCount="indefinite" additive="replace" calcMode="discrete" fill="freeze"/></circle><circle fill="#222222" cx="45.219" cy="24.858" r="4.496"><animateTransform attributeName="transform" attributeType="XML" type="rotate" values="0 25 25; 45 25 25; 90 25 25; 135 25 25; 180 25 25; 225 25 25; 270 25 25; 315 25 25" dur="1s" repeatCount="indefinite" additive="replace" calcMode="discrete" fill="freeze"/></circle><circle fill="#444444" cx="39.122" cy="10.486" r="4.496"><animateTransform attributeName="transform" attributeType="XML" type="rotate" values="0 25 25; 45 25 25; 90 25 25; 135 25 25; 180 25 25; 225 25 25; 270 25 25; 315 25 25" dur="1s" repeatCount="indefinite" additive="replace" calcMode="discrete" fill="freeze"/></circle><circle fill="#666666" cx="4.496" cy="24.858" r="4.496"><animateTransform attributeName="transform" attributeType="XML" type="rotate" values="0 25 25; 45 25 25; 90 25 25; 135 25 25; 180 25 25; 225 25 25; 270 25 25; 315 25 25" dur="1s" repeatCount="indefinite" additive="replace" calcMode="discrete" fill="freeze"/></circle><circle fill="#888888" cx="24.858" cy="45.222" r="4.496"><animateTransform attributeName="transform" attributeType="XML" type="rotate" values="0 25 25; 45 25 25; 90 25 25; 135 25 25; 180 25 25; 225 25 25; 270 25 25; 315 25 25" dur="1s" repeatCount="indefinite" additive="replace" calcMode="discrete" fill="freeze"/></circle><circle fill="#AAAAAA" cx="10.487" cy="10.574" r="4.496"><animateTransform attributeName="transform" attributeType="XML" type="rotate" values="0 25 25; 45 25 25; 90 25 25; 135 25 25; 180 25 25; 225 25 25; 270 25 25; 315 25 25" dur="1s" repeatCount="indefinite" additive="replace" calcMode="discrete" fill="freeze"/></circle><circle fill="#CCCCCC" cx="10.487" cy="39.209" r="4.496"><animateTransform attributeName="transform" attributeType="XML" type="rotate" values="0 25 25; 45 25 25; 90 25 25; 135 25 25; 180 25 25; 225 25 25; 270 25 25; 315 25 25" dur="1s" repeatCount="indefinite" additive="replace" calcMode="discrete" fill="freeze"/></circle><circle fill="#EEEEEE" cx="39.123" cy="39.209" r="4.496"><animateTransform attributeName="transform" attributeType="XML" type="rotate" values="0 25 25; 45 25 25; 90 25 25; 135 25 25; 180 25 25; 225 25 25; 270 25 25; 315 25 25" dur="1s" repeatCount="indefinite" additive="replace" calcMode="discrete" fill="freeze"/></circle></svg>

Then we get a animated SVG like this:

Get DPI from JPG/JPEG and PNG images with PHP and Imagick

Add these functions to a class, then just call $class::getImageDpi($filename) to get the DPI returned. DPI is searched both in the image header-data and the EXIF data. Use these functions according to MIT license.

/**
     * @param string $filename
     * @return array
     * @throws Exception
     */

    public static function getImageDpi($filename)
    {
        if (!empty($filename)
            && file_exists($filename)
        ) {

            $fileMime = self::getFileMimeType($filename);

            if ($fileMime == ‘image/jpeg; charset=binary’
                || $fileMime == ‘image/jpg; charset=binary’
                || $fileMime == ‘image/jpeg2; charset=binary’
            ) {
                return self::getImageJpgDpi($filename);
            } else if ($fileMime == ‘image/png; charset=binary’) {
                return self::getImagePngDpi($filename);
            } else {
                return array(
                    ‘x’ => 72,
                    ‘y’ => 72,
                );
            }

        } else {
            Throw new \Exception(‘Invalid parameters’);
        }
    }

    /**
     * Uses unix command file -bi for determining file typ.
     *
     * jpeg = image/jpeg; charset=binary
     * gif = image/gif; charset=binary
     * pdf = application/pdf; charset=binary
     *
     * @static
     * @param string $absolutePath
     * @throws Exception
     * @return string|bool
     */

    public static function getFileMimeType($absolutePath)
    {
        if (!empty($absolutePath)) {
            if (file_exists($absolutePath)) {
                if ($return = exec(
                    ‘file -bi — ‘ . escapeshellarg($absolutePath))
                ) {
                    return $return;
                }
            }
        } else {
            Throw new Exception(
                ‘Invalid parameters for ‘ . __FUNCTION__
                . ‘ in ‘ . __FILE__);
        }
        return false;
    }

    /**
     * @param string $filename
     * @return array
     * @throws Exception
     */

    public static function getImageJpgDpi($filename)
    {
        if (!empty($filename)
            && file_exists($filename)
        ) {

            $dpi = 0;
            $fp = @fopen($filename, ‘rb’);

            if ($fp) {
                if (fseek($fp, 6) == 0)
                {
                    if (($bytes = fread($fp, 16)) !== false)
                    {
                        if (substr($bytes, 0, 4) == "JFIF")
                        {
                            $JFIF_density_unit = ord($bytes[7]);
                            $JFIF_X_density = ord($bytes[8])*256 + ord($bytes[9]);
                            $JFIF_Y_density = ord($bytes[10])*256 + ord($bytes[11]);

                            if ($JFIF_X_density == $JFIF_Y_density)
                            {
                                if ($JFIF_density_unit == 1) {
                                    $dpi = $JFIF_X_density;
                                } else if ($JFIF_density_unit == 2) {
                                    $dpi = $JFIF_X_density * 2.54;
                                }
                            }
                        }
                    }
                }
                fclose($fp);
            }

            if (empty($dpi)) {
                if ($exifDpi = self::getImageDpiFromExif($filename)) {
                    $dpi = $exifDpi;
                }
            }

            if (!empty($dpi)) {
                return array(
                    ‘x’ => $dpi,
                    ‘y’ => $dpi,
                );
            } else {
                return array(
                    ‘x’ => 72,
                    ‘y’ => 72,
                );
            }

        } else {
            Throw new \Exception(‘Invalid parameters’);
        }
    }

    /**
     * @static
     * @param string $filename
     * @return array
     * @throws Exception
     */

    public static function getImagePngDpi($filename)
    {
        if (!empty($filename)
            && file_exists($filename)
        ) {

            $fh = fopen($filename, ‘rb’);

            if (!$fh) {
                return false;
            }

            $buf = array();

            $x = 0;
            $y = 0;
            $units = 0;

            while(!feof($fh))
            {
                array_push($buf, ord(fread($fh, 1)));
                if (count($buf) > 13)
                    array_shift($buf);
                if (count($buf) < 13)
                    continue;
                if ($buf[0] == ord(‘p’) &&
                    $buf[1] == ord(‘H’) &&
                    $buf[2] == ord(‘Y’) &&
                    $buf[3] == ord(‘s’))
                {
                    $x = ($buf[4] << 24) + ($buf[5] << 16) + ($buf[6] << 8) + $buf[7];
                    $y = ($buf[8] << 24) + ($buf[9] << 16) + ($buf[10] << 8) + $buf[11];
                    $units = $buf[12];
                    break;
                }
            }

            fclose($fh);

            if ($x != false
                && $units == 1
            ) {
                $x = round($x * 0.0254);
            }

            if ($y != false
                && $units == 1
            ) {
                $y = round($y * 0.0254);
            }

            if (empty($x)
                && empty($y)
            ) {
                if ($exifDpi = self::getImageDpiFromExif($filename)) {
                    $x = $exifDpi;
                    $y = $exifDpi;
                }
            }

            if (!empty($x)
                || !empty($y)
            ) {
                return array(
                    ‘x’ => $x,
                    ‘y’ => $y,
                );
            } else {
                return array(
                    ‘x’ => 72,
                    ‘y’ => 72,
                );
            }

        } else {
            Throw new \Exception(‘Invalid parameters’);
        }
    }

    /**
     * Read EXIF data.
     *
     * @static
     * @param string $filename
     * @throws \Exception
     * @return bool|float
     */

    public static function getImageDpiFromExif($filename)
    {

        if (!empty($filename)
            && file_exists($filename)
        ) {
            if (function_exists(‘exif_read_data’)) {
                if ($exifData = exif_read_data($filename)) {
                    if (isset($exifData[‘XResolution’])) {
                        if (strpos($exifData[‘XResolution’], ‘/’) !== false) {
                            if ($explode = explode(‘/’, $exifData[‘XResolution’])) {
                                return (float) ((int) $explode[0] / (int) $explode[1]);
                            }
                        } else {
                            return (int) $exifData[‘XResolution’];
                        }
                    } else if (isset($exifData[‘YResolution’])) {
                        if (strpos($exifData[‘YResolution’], ‘/’) !== false) {
                            if ($explode = explode(‘/’, $exifData[‘YResolution’])) {
                                return (float) ((int) $explode[0] / (int) $explode[1]);
                            }
                        } else {
                            return (int) $exifData[‘YResolution’];
                        }
                    }
                }
            } else {
                Throw new \Exception(‘Incompatible system.’);
            }
        } else {
            Throw new \Exception(‘Invalid parameters.’);
        }

        return false;

    }

Convert white in image to transparency with Imagick and PHP

Here is a snippet I made which takes a path to an image and if the image doesn’t have any transparency it replaces all white color with 100% transparency.

/**
     * @static
     * @param string $oldPath
     * @param string|null [$newPath = null]
     * @throws \Exception
     * @return bool
     */

    public static function createShirtImage($oldPath, $newPath = null)
    {
        if (isset($oldPath)
            && file_exists($oldPath)
        ) {

            if ($resource = new imagick($oldPath)) {

                $whitePixel = new ImagickPixel(‘white’);

                // Does image not have any transparency?
                if (!$resource->getimagealphachannel()) {

                    $resource->painttransparentimage(
                        $whitePixel,
                        0.0,
                        5000
                    );

                }

                $resource->setimagecolorspace(imagick::COLORSPACE_RGB);
                $resource->setimageformat(‘png’);

                if (empty($newPath)) {
                    $newPath = $oldPath;
                }

                if (file_exists($newPath)) {
                    unlink($newPath);
                }

                if ($resource->writeimage($newPath)) {

                    return true;

                }

            }

        } else {
            Throw new Exception(‘Invalid parameters’);
        }

        return false;

    }

Install Xdebug on Linux Debian

First you need the follow packages installed:
* php5-dev
* php-pear
* make

Install them by running:

apt-get update
apt-get install php5-dev php-pear make

Then to install xdebug type:

pecl install xdebug

Now, DON’T add anything to php.ini but do this instead:

find / -name "xdebug.so"

Copy the location of xdebug.so.

Start editing a new file like this:

nano /etc/php5/conf.d/xdebug.ini

Enter your configuration, usually something like this:

zend_extension="LOCATION OF XDEBUG.SO ABOVE"

[debug]
xdebug.remote_enable=1
xdebug.remote_host=YOUR IP ADDRESS
xdebug.remote_port=9000
xdebug.remote_mode="req"
xdebug.idekey="YOUR IDE KEY"
xdebug.remote_autostart=0
xdebug.remote_handler="dbgp"
xdebug.remote_connect_back=0
xdebug.extended_info=1
xdebug.remote_log=/var/log/xdebug.remote_log.log

Now restart apache2 by running

/etc/init.d/apache2 restart

You can see if your xdebug is loaded in PHP by looking after xdebug in this output:

Also in terminal you can do this:

php -i | grep xdebug

Now to start a debug session your go to your site and append query string like this:
?XDEBUG_SESSION_START=YOUR_IDE_KEY

And to end a debug session you do this:
?XDEBUG_SESSION_STOP=YOUR_IDE_KEY

Read more about XDEBUG here.

PHP Gogobot integration

Since I couldn’t find any documentation on how to integrate Gogobot in PHP I decided to make a blog post about it.

1. Get Client id and Client Secret from Gogobot.

2. Replace $clientId and $clientSecret below with your credentials.

$clientId = ‘MY ID’;
$clientSecret = ‘MY SECRET’;

$queryParameters = array();
$queryParameters[‘query’] = $query;
$queryParameters[‘lat’] = $lat;
$queryParameters[‘lng’] = $lng;
$queryParameters[‘https’] = (!empty($https) ? 1 : 0);
$queryParameters[‘client_id’] = $clientId;

ksort($queryParameters);

// Calculate payload
$payload = ;

foreach ($queryParameters as $key => $value)
{
    $payload .= $key;
    $payload .= $value;
}

$payload .= $clientSecret;

// Generate signature
$signature = hash_hmac(‘sha256’, $payload, $clientSecret, true);
$signature = base64_encode($signature);

$queryParameters[‘signature’] = $signature;

// Generate HTTP
$http = ‘http://api.gogobot.com/api/v3/search/nearby_search/?’;

$queryParameterIndex = 0;
foreach ($queryParameters as $key => $value)
{
    if ($queryParameterIndex > 0) {
        $http .= ‘&’;
    }
    $http .= $key . ‘=’ . rawurlencode($value);
    $queryParameterIndex++;
}

3. After this just make a cURL request and the integration is ready.

Setup Youtrack Stand-alone on Linux Debian

Install java (version 7 minimum) by executing:

apt-get update
apt-get install openjdk-7-jre
apt-get install openjdk-7-jdk

Check your java version by running

java -version

If your default version is not 7 or higher change by running and selecting another version as default.

update-alternatives –config java

Download YouTrack Stand-alone from JetBrains. Or download by using console:

mkdir /var/web/youtrack
wget http://download.jetbrains.com/charisma/youtrack-5.1.2.jar /var/web/youtrack/youtrack-5.1.2.jar

Make a new init script like this

nano /etc/init.d/youtrack
#!/bin/bash

### BEGIN INIT INFO
# Provides:          youtrack
# Required-Start:    $local_fs $remote_fs $network
# Required-Stop:     $local_fs $remote_fs $network
# Should-Start:      $named
# Should-Stop:       $named
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Starts YouTrack.
# Description:       Starts YouTrack tracking system.
### END INIT INFO

java -Xmx1g -XX:MaxPermSize=1g -Djava.awt.headless=true -jar /var/web/youtrack/youtrack-5.1.2.jar 8088 &

Modify permissions like this

chmod -R 755 /etc/init.d/youtrack

Then install your init-script by running:

insserv /etc/init.d/youtrack

YouTrack server will now launch every time system boots and is accessed on port 8088. Notice this guide is for Youtrack 5.1.2 so if you download a newer version just change the path in the init script.

To launch YouTrack for this first-time do this:

/etc/init.d/youtrack

To integrate with Apache2 as a HTTPS site do this, otherwise you are done.

Activate modules needed for SSL proxy.

a2enmod ssl
a2enmod proxy
a2enmod proxy_http
a2enmod headers

Add a Apache2 site by doing this:

nano /etc/apache2/sites-available/default-ssl

Add following to the file:

<VirtualHost *:443>

SSLEngine on
SSLCertificateFile /etc/apache2/apache.pem

ServerAdmin admin@locahost
ServerName mydomain.com
DocumentRoot /var/web/youtrack/

<Location />
SSLRequireSSL
Header edit Location ^http: https:
</Location>

RequestHeader set X-Forwarded-Proto "https"

ProxyRequests Off
ProxyPass / http://mydomain.com:8088/
ProxyPassReverse / http://mydomain.com:8088/

ErrorLog /var/web/youtrack/error.log
LogLevel warn
CustomLog /var/web/youtrack/access.log combined

</VirtualHost>

Activate site by

a2ensite default-ssl

Restart Apache2 configuration

/etc/init.d/apache2 graceful

If all went good your YouTrack installation should be accessible at https://mydomain.com

Read more

Read more about install YouTrack stand-alone here.
Read more about install Java on Debian here.

Finally disabled that backspaces triggers Back-event in Firefox

I finally did the search for how to disable the behavior in Firefox where clicking on Backspaces triggers a ‘Back’-event in the browser.

According to https://support.mozilla.org/sv/questions/924490:

“You can set the Integer pref browser.backspace_action to 2 on the about:config page to disable the backspace action. BTW Shift + Backspace does the reverse: going Forward if possible, so that is taken as well. ”

It works great, I should have done this earlier to prevent all the frustration of breaking web forms.