Monday, March 10, 2014

Your development log files in Rails is probably huge

I always forget to truncate my development logs, and when I need to debug or dig into the logs, they are dead slow to work with.

Use this simple gist to truncate your logs automagically. It will only touch your development.log, as I do note like when initializers pull production or staging logs into the mix, as that might be a security risk when you just needed to test a part of your app on your production environment.




Wednesday, January 15, 2014

SVGs in browsers (Firefox is the new IE)

Intro

SVGs in browsers are fun, and if you say goodbye to IE8 and older, it is almost working cross-browser.

I'm working on a basic editor-like application that involves a lot of SVG hacking, but it's quite fun due to the great Snap.svg lib by Dmitry Baranovskiy (working for Adobe).

My main development browser is Chrome, due to the powerful debugging features, and everything works quite well. I wrote a lot of tests, and I was going to fire them up i Firefox, and expected them to work. 5 out of 43 tests passsed, where 43 of 43 passwed in Chrome, Safari, IE10, IE11 and Opera.

I told myself: keep calm, it's probably nothing.

After digging further into SVG in Firefox, there are some issues specific to Firefox.
  1. Mouse coordinates relative to the SVG
  2. getIntersectionList and getEnclosureList is not implemented
  3. getBoundingClientRect

Mouse coordinates

The usual hack for not having offsetX and offsetY in events in FF is something like this:
offsetXY = function(event) {
  var br;
  var evt = event;
  if (evt.offsetY !== void 0 && evt.offsetX !== void 0) {
    return evt
  } else {
    var br = event.target.getBoundingClientRect();
    evt.offsetX = evt.pageX - br.left;
    evt.offsetY = evt.pageY - br.top;
  }
  return evt;
};

However, when you are using SVG's, getBoundingClientRect does NOT provide the actual box around the SVG DOM element, but instead it gives a "close-bounding-box" around the elements inside the SVG. Basically the usual FF hack to get offsetX/Y does not work.

Solution:
Create a svg like this:
<svg id="testsvg" style="height: 500px; width: 500px;">
  <defs>
    <rect height="100%" id="mouse_calc" width="100%" x="0" y="0"></rect>
  </defs>
</svg>

You now have a rectangle where you can find the correct coordinates calling getBoundingClientRect on the rectangle By putting the element in the defs area, it's hidden from view, but not clickable, so you still need to do the click handler on the actual SVG. The new code will look like this:
offsetXYSVG = function(event) {
  var br;
  var evt = event;
  if (evt.offsetY !== void 0 && evt.offsetX !== void 0) {
    return evt
  } else {
    var br = document.getElementByID("mouse_calc").getBoundingClientRect();
    evt.offsetX = evt.pageX - br.left;
    evt.offsetY = evt.pageY - br.top;
  }
  return evt;
};

Nice one FF, two different hacks to get correct offsets...

Note: layerX and layerY does NOT give you the correct values for the mouse click on SVG, due to getBoundingClientRect working differently than in the rest of the current browsers. 

 
getIntersectionList and getEnclosureList

These to functions are essential to figure out if any objects are intersecting or if one object is within an enclosure when working with selections of gui elements. getIntersectionList can be implemented using the Separating Axis Theorem and getEnclosureList can be implemented with simple checking of x/y and x+width/y+height is within a given rectangle. However, performance for getIntersectionList in JS compared to Separating Axis Theorem implemented directly in the C++ core of the browser is a performance killer when working with many objects.

getBoundingClientRect

As mentioned, this basically fails for SVG elements.
Here is how the bounding rect is calculated for a svg with elements going outside forced 500x500 px svg size: The dotted line shows what FF gives as getBoundingClientRect, and the red line shows the actual SVG. Chrome, Safari, IE 11 and Opera gives the red line for both.

 Same as above, but without the two circles on the outside:
As you can see, the problem for calculating your SVG size and therefore finding mouse coords in FF is currently a bit "hackish".

Even though this might be correct when reading the W3C standard for SVG, I think it is better to do the same as all the other browsers to make it easier to develop SVG based applications for the browser.

Conclusion

For SVG, Firefox is the new IE, and that is not a good thing.

Wednesday, January 8, 2014

iTunes connect screenshot and icon details

Some simple guidelines on the sizes/resolution for screenshots and icons for iTunes connect, when you submit your app.

For all images

  • Minimum 72 DPI
  • RGB color space

Large app icon

  • 1024x1024 (cannot be scaled up, but can be scaled down)
  • File format: jpg tif or png 
  • Keep it "flat" as in the new guidelines. Avoid rounded corners.

3.5" Retina Screenshots

  • Portrait: 960x640 or 960x600
  • Landscape: 640x960 or 640x920
  • File format: jpg or png

4" Retina Sreenshots 

iPhone 5/iPod touch (5th gen)
  • Portrait: 1136x640 or 1136x600
  • Landscape: 640x1136 or 640x1096
  • File format: jpg or png

iPad Screenshots

  • Portrait: 1024x768, 1024x748, 2048x1536 or 2048x1496 
  • Landscape: 768x1024, 768x1004, 1536x2048, or 1536x2008
  • File format: jpg or png
Do the screenshots on a device and you should be all good to go.

Thursday, October 24, 2013

Remember to have a "catch-all" in your nginx configuration when using virtual domains

I got a bit stressed when I saw that a beta for a service I am working on was out in the open. I checked every config file and firewalls, and could not see why the site would respond to a different domain and the ip, when the server_name in nginx was set.

I cannot stress this enough: You need a catch-all in your nginx config!

If you do not have a server config block to catch all "none-virtual" domains, nginx just picks the first available configuration. Quite different from what I was used to with apache. And if you have private and public sites on a mixed box, that might be mission-critical if sensitive data gets out...

So do yourself a favor and throw this into your nginx config before the virtual hosts are loaded:

 server {
  root /usr/share/nginx/www;
  index index.html index.htm;

  location / {
    try_files $uri $uri/ /404.htm =404;
  }
 }


 ##
 # Virtual Host Configs
 ##
        # .... 

Without the above settings, your site will be accessible on any domain pointing to the server, and any IP the server hosts.

Monday, October 14, 2013

Get the dot notation of a embedded Mongoid element

I needed to get the dot notation for embedded documents to perform queries using the given dot notation.

I could not find a "standard" way of doing just that, so here are some helper methods I use in a class. (Part of soon-to-come BoxCMS)

This Gist uses Mongoid metadata and reflect_on_all_associations, so it might break for newer versions of mongoid at some point.

Using dot notation queries in mongoid, makes it easy to dig for even the deepest "weird" embedded structures you might have.

Example of query:
»  Box::Page.where("rows.boxes.box_items.is_template_object" => false).first

Dot notations in mongodb are a powerful tool, but use it wisely unless you are indexing "more than you should".
Basic usage: Call dot_notation_for_element(embedded_element) to get the dot notation all the way up to the parent document, excluding the parent documents name/embedded name.

Wednesday, August 14, 2013

Setting up your own S3 storage on VPS servers

After using Amazon S3 for a while, and seeing that the performance in Northern Europe is basically crap (even with CloudFront), it was time to try setting up an alternative on VPS servers that were closer to "home". I chose only to look at S3 API compatible storage as I already had apps running using S3 storage as a backend, and I wanted to move the storage for the apps to servers running in Northern Europe.

The requirements


Easy to scale
Replication
S3 Compatible API
Must run as an application on top of Ubuntu 12.04 LTS
Must use the storage available on a VPS
Can limit disk usage per node. (This is not an absolute requirement, but a nice-to-have requirement)
Can work on low to medium latency connections

The contenders

Riak CS


Runs on top of Riak
Riak is a database (Key/value store) and therefore runs on top of the majority of *nix based distributions
Easy to add nodes using command line tools to a Riak cluster
Has S3 compatible API
Replication is a must for a Riak cluster
No node is master/slave, all are equal (good for HA)
Has a nice web administration tool

Eucalyptus Walrus


Medium difficult to add nodes
Has addons for S3 compatible apis
Can use a normal folder for storage, but not if replication is used
Must have a block device to replicate
Easy to limit usage on a node
Difficult to configure replication
Must have a Cloud Controller, and for HA, a secondary controller

OpenStack Swift


Medium difficult to scale
Can have problems with medium latency connections, due to writing on a majority of nodes
S3 compatible API as an addon
Must have block devices
Easy to limit usage on a node
Syncs through rsync. (I never liked rsync...)

Cloudian


Has a community Edition, but documentation is sign-up only (Vmware/citrix anyone?)
Claims to be OSS, but in reality: no.
Read up on the docs, but the documentation is sparse and it does not feel "production-ready"

Apache Cloudstack


Has S3 API
Not usable as it requires a management server and a host/hypervisor system

Ceph


Is a distributed file system.
Easy to add nodes
Replicates across nodes
Does have a S3 compatible API, although some limitations (http://ceph.com/docs/next/radosgw/s3/)
Has a nice deploy-tool
Requires block devices for storage

Wrap up


Basically this gives two different directions.
Setting up Riak CS directly on the system or choosing Ceph, Walrus or Swift and setting up a file as a block device.

After reading up on the docs, I am considering both Ceph and Riak CS, and will start by testing Riak CS. The

Both provide good chef cookbooks, so for large scale deployments, use time to setup chef properly. It will save you time when you need that next node if you plan to grow.

However, this is most likely going to be more expensive than using cloud storage, so do consider if you want to use your time on this or just pay for cloud storage.

Other openstack options would work fine as well, since the client library I am using supports both.

Thursday, August 8, 2013

wicked_pdf and stylesheets

There are several articles showing how to use wicked_pdf on a Ruby on Rails application, so I am not going to exlain that here. Setup is quite simple, and the gem is just awesome.

There are however a few things to notice:

Outputs on osx and ubuntu can be inconsistent

If you are using wkhtmltopdf-binary-11 on osx in development and the same binary in production on a ubuntu system the output of the pdf is most likely to be quite different. Solution: Develop on your local computer, fine-tune using an Ubuntu machine in Virtualbox.

Stylesheets don't 'behave'

You might get mixed results when using linked stylesheets. The simple solution is to inline your pdf or print stylesheet. Put this in your pdf layout file:
<style type="text/css">
<%= Rails.application.assets.find_asset('pdf_print.css').to_s.html_safe %>
</style>
This way your stylesheet will be inline, and all linking issues with wkhtmltopdf is resolved. If you have full paths for your assets, that will sometimes work as well. (e.g. if they are hosted on a cdn), but to my experience, inline CSS is more consistant when using wkhtmltopdf.

After writing this blog post, I found this repository:
https://github.com/jwo/railsdotpdf
It is a fully working example of generating pdf with linking to the assets instead of inline css. It is a fairly basic example, but it shows how to setup wicked_pdf with linked stylesheets.