Apple Push Notifications Toolkit for Ruby 4

Posted by Ben Poweski Thu, 17 Sep 2009 14:56:00 GMT

Lately I’ve been working on an iPhone application that utilizes Push Notifications extensively. While Apple provides great documentation there is still a fair amount of work left up to the developer to send push notification in ordinance to their usage policy.

Since I’m using Rails for the backend I needed a way to maintain a single open SSL connection to prevent setup and tear down for every notification sent. To accomplish this I created an Event Machine based server deamon that that proxies all requests send by Rails application over a local, non SSL socket.

The proxy queues and sends each notification to the Apple notification servers. Additionally I’ve created a command line script to send notifications for testing purposes. My project Apn Server is hosted on Github.

You can add it to your Rails application via

config.gem "bpoweski-apnserver", :lib => 'apnserver', 
  :source => "http://gems.github.com"

You can use either a direct connection to Apple or one through the apnserverd proxy included in the gem. To configure directly to Apple’s server (and also setting up and tearing down a new connection each time). Add the following to your environment.rb.

  ApnServer::Config.pem = '/path/to/pem'
  ApnServer::Config.host = 'gateway.push.apple.com'
  ApnServer::Config.port = 2195

To use the non SSL apnserverd proxy simply drop the PEM configuration option

  ApnServer::Config.host = 'localhost'
  ApnServer::Config.port = 22195

To send a notification from Ruby

  notification = ApnServer::Notification.new
  notification.device_token = Base64.decode64(apns_token)
  notification.alert = message
  notification.badge = 1
  notification.sound = 'default'
  notification.push

You can also send notifications via the line with

  $ apnsend --server gateway.push.apple.com --port 2195 \
     --pem key.pem \
     --b64-token j92f12jh8lqcAwcOVeSIrsBxibaJ0xyCi8/AkmzNlk8= \
     --sound default \
     --alert Hello

Security on Rails

Posted by Ben Poweski Mon, 06 Jul 2009 15:18:00 GMT

Security on Rails goes Beta!

Remove Bevel and Gloss Effect From iPhone Icon 1

Posted by Ben Poweski Sat, 27 Dec 2008 18:40:00 GMT

After search for this a bit, it is a simple property inside of your Info.plist. To remove the bevel and gloss effect set the following property:

UIPrerenderedIcon true

For more properties check out the Info.plist reference.

Finding the Perfect Espresso Machine 1

Posted by Ben Poweski Wed, 29 Oct 2008 21:52:00 GMT

Buying an espresso machine isn’t an easy endeavor. I started with a DeLonghi EC140B, it is one of the least expensive non steam espresso machines available. While it makes a decent cup of espreso, unfortunately its stamina is lacking.

In takes roughly 90 seconds between brewing a shot of espresso and when the boiler arrives at the correct temperature for steaming. For some this isn’t a big inconvenience, but after the 3rd or 4th drink it becomes a bit of a pain. If you are having friends over, you might as well put it in a cabinet as you’ll be spending most of your time in the kitchen. On top of that, after 5 months of moderate use the boiler went out.

What is one to do? Since I’ve already pledged my desire to espresso, it is time to find a new machine. The question is: which one?

The best information I’ve found on the internet regarding espresso machines is at Coffee Geek. But even on coffeegeek you’re inundated with options!

So far i’ve found serveral choices:

Bezzera BZ02S

The Bezzera BZ02S retails for $1,399.00 USD but can be found from various retailers for roughly $950-$1000 dollars. It contains a 1 gallon water reservoir and boasts zero recovery time between espresso shots.

Pasquini Livia 90

The Pasquini Livia 90 is a closely related tot he Bezzera BZ02S, allegedly made in the same factory. It sells for anywhere between $1,349.00 and $1,700. It sports a shiny chrome outer casing.

Rancilio Silvia

The Rancilio is one of the most common home machines for the espresso enthusiast. Read the full write up on Coffeegeek.

I still haven’t made a decision, the Bezzera BZ02S is the current contender.

Thoughts?

I Hate You Gmail

Posted by Ben Poweski Wed, 28 May 2008 15:26:00 GMT

While manually creating a contact to store a phone number (at work, so no Mac…yet), I decided to do some early summer cleaning of my contacts. To my despair, Gmail only allows you to delete 20 contacts at a time! What the is this? I’m disappointed in you Google.

Sniff sniff.

Parsing CSS with ANTLR 4

Posted by Ben Poweski Fri, 23 May 2008 18:28:00 GMT

For a project I”m working on, we’ve used CSS syntax to describe styling on application objects. To accomplish this we created a parser using Antlr. Here is our implementation of the CSS core syntax. Unicode support is left out as it was not needed for our use case, but it should be pretty easy to add in.

grammar CssCore;
options { language=Java; }

/*

Grammar taken from
http://www.w3.org/TR/REC-CSS2/syndata.html#tokenization

*/

//stylesheet  : [ CDO | CDC | S | statement ]*;
stylesheet
    :   (CDO|CDC|statement)*
    ;


//statement   : ruleset | at-rule;
statement
    :   ruleset
    |   atRule
    ;

//at-rule     : ATKEYWORD S* any* [ block | ';' S* ];
atRule  :   ATKEYWORD any* (block | SEMICOLON)
    ;

//block       : '{' S* [ any | block | ATKEYWORD S* | ';' ]* '}' S*;
block   :   LBRACE (any|block|ATKEYWORD|SEMICOLON)* RBRACE 
    ;

//ruleset     : selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*;

selector:   '*'
    |   '*'? (IDENT|'>'|'+'|CLASS|HASH)+
    ;


ruleset :   selector? LBRACE declaration? ( SEMICOLON declaration? )* RBRACE
    ;

//selector    : any+;

//declaration : property ':' S* value;
declaration
    :   property COLON value
    ;

//property    : IDENT S*;
property:   IDENT
     ;

//value       : [ any | block | ATKEYWORD S* ]+;
value   :   (any|block|ATKEYWORD)*
          ;

//any         : [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING
//              | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES
//              | FUNCTION | DASHMATCH | '(' any* ')' | '[' any* ']' ] S*;
any :   (   IDENT|NUMBER|PERCENTAGE|DIMENSION|STRING|
            HASH|INCLUDES|
            FUNCTION|DASHMATCH
            // TODO UNICODE_RANGE|DELIM|URI| '(' any* ')' | '[' any* ']' ] S*;
        )
    ;


/* Tokens */

//IDENT     {ident}
IDENT   :   F_IDENT
    ;

//ATKEYWORD     @{ident}
ATKEYWORD
    :   '@' F_IDENT
    ;

//STRING    {string}
STRING  :   F_STRING
    ;

//HASH  #{name}
HASH    :   '#' F_NAME
    ;

//NUMBER    {num}
NUMBER  :   F_NUM
    ;

//PERCENTAGE    {num}%
PERCENTAGE
    :   F_NUM '%'
    ;

//DIMENSION     {num}{ident}
DIMENSION
    :   F_NUM F_IDENT
    ;

//URI   url\({w}{string}{w}\)
//|url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\)
//UNICODE-RANGE     U\+[0-9A-F?]{1,6}(-[0-9A-F]{1,6})?


//CDO   <!--
CDO :   '<!--'
    ;

//CDC   -->
CDC :   '-->'
    ;


//;     ;
SEMICOLON
    :   ';'
    ;   

COLON   :   ':'
    ;   


//{     \{
LBRACE  :   '{'
    ;

//}     \}
RBRACE  :   '}'
    ;

//(     \(
LPAREN  :   '('
    ;

//)     \)
RPAREN  :   ')'
    ;

//[     \[
LBRACKET:   '['
    ;

//]     \]
RBRACKET:   ']'
    ;

//S     [ \t\r\n\f]+
S   :   (' '|'\t'|'\r'|'\n'|'\f')+
        { $channel=HIDDEN; }
    ;

//COMMENT   \/\*[^*]*\*+([^/][^*]*\*+)*\/
COMMENT :   '/*' (options {greedy=false;} : .)*   '*/'
        { $channel=HIDDEN; }
    ;

//FUNCTION  {ident}\(
FUNCTION:   F_IDENT '('
    ;

//INCLUDES  ~=
INCLUDES:   '~='
    ;

//DASHMATCH     |=
DASHMATCH
    :   '|='
    ;

//DELIM     any other character not matched by the above rules

CLASS   :   '.' F_IDENT
    ;


//ident     {nmstart}{nmchar}*
fragment
F_IDENT :   F_NMSTART F_NMCHAR*
    ;

//name  {nmchar}+
fragment
F_NAME  :   F_NMCHAR+
    ;

//nmstart   [a-zA-Z]|{nonascii}|{escape}
fragment
F_NMSTART
    :   (F_LETTER)
// TODO add nonascii, escaped
    ;

//nonascii  [^\0-\177]
//unicode   \\[0-9a-f]{1,6}[ \n\r\t\f]?
//escape    {unicode}|\\[ -~\200-\4177777]

//nmchar    [a-z0-9-]|{nonascii}|{escape}
fragment
F_NMCHAR:   (F_LETTER|F_DIGIT|'-')
// TODO add nonascii, escaped
    ;

//num   [0-9]+|[0-9]*\.[0-9]+
fragment
F_NUM   :   ('0'..'9')+
    |   ('0'..'9')* '.' ('0'..'9')+
    ;


//string    {string1}|{string2}
fragment
F_STRING:   F_STRING1
    |   F_STRING2
    ;

//string1   \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\"
fragment
F_STRING1
    :   '"' ('\t'|' '|'!'|'#'|'$'|'%'|'&'|'\''|'.'|F_LETTER|F_DIGIT)* '"' 
    ;
//string2   \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\'
fragment
F_STRING2
    :   '\'' ('\t'|' '|'!'|'#'|'$'|'%'|'&'|'.'|F_LETTER|F_DIGIT)* '\'' 
    ;

//nl    \n|\r\n|\r|\f
fragment
F_NL    :   '\n'
    |   '\r\n'
    |   '\r'
    |   '\f'
    ;

fragment
F_LETTER:   'a'..'z'
    |   'A'..'Z'
    ;

fragment
F_DIGIT :   '0'..'9'
    ;

//w     [ \t\r\n\f]*
fragment
F_W :   (' '|'\t'|'\r'|'\n'|'\f')*
    ;

Securing Data wtih OpenSSL and Ruby: Part One 1

Posted by Ben Poweski Thu, 24 Apr 2008 14:53:00 GMT

For the most part Ruby has fantastic APIs. While there is an occasional wart here and there (I”m speaking to you DateTime). In general, it doesn’t suck. The OpenSSL bindings for Ruby are no exception.

Bob, meet Alice

To begin our cultural learnings of OpenSSL and Ruby, let’s take a look at source repository for the interpreter. In the samples directory are some nice examples how the bindings work. It seems that some of the original code examples were never migrated from the RubyPKI project, but thats ok, you can still access them here.

The OpenSSL Digest Class

One of the most common things you’ll most likely need is to create a digest of a string of data. We can do this using by instantiating a Digest class then invoking the hexdigest method.

irb(main):001:0> require 'openssl'
=> true
irb(main):002:0> @sha1 = OpenSSL::Digest::SHA1.new("fooooo")
=> 58c00efa9bed725721b29f4b5f7864f0f191cad5
irb(main):003:0> @sha1.hexdigest
=> "58c00efa9bed725721b29f4b5f7864f0f191cad5"
irb(main):005:0>

Simple enough. But what is the deal with ‘digest’ versus ‘openssl/digest’? According to the ‘digest’ module is only used for backwards compatibility, so use the openssl version when possible.

Available Digest Algorithms

According to the source, the Digest algorithms available are dependent upon the version of OpenSSL compiled with Ruby.

module OpenSSL
  class Digest

    alg = %w(DSS DSS1 MD2 MD4 MD5 MDC2 RIPEMD160 SHA SHA1)
    if OPENSSL_VERSION_NUMBER > 0x00908000
      alg += %w(SHA224 SHA256 SHA384 SHA512)
    end
    ...

Replacing JavaScript with Java?

Posted by Ben Poweski Wed, 16 Apr 2008 19:07:00 GMT

Why? I admit, at first glance the idea of developing a highly usable Ajax web application using the Google Web Toolkit is intriguing. Java, after all, is our modern day COBOL. We get IDE support, have countless vendors to point fingers at and can bury grown men using the Java selection alone at our local B&N.

What does this have to do with Google Web Toolkit? Probably not a whole lot, but Google did ditch a powerful dynamic language (JavaScript) in exchange for a statically typed language (Java). They have built some fantastic software using it…but I agree with Justin, when I say, they’ve pushed it too far with this one.

  • Debugging JavaScript errors in Java proves to be an interesting exercise.
  • While we get out of the box widgets….all of my GWT apps look like they’re made in Google, complete with the kindergarten color scheme. Your mileage may vary.
  • HTML, CSS and Javascript are relegated to bottom feeders of the view. No longer do we have separation of content and style, but a munge of both.

Something about this whole framework doesn’t feel right. But damn, some of their applications are neat.

Refactoring HTML and CSS

Posted by Ben Poweski Thu, 27 Mar 2008 14:46:00 GMT

As web application developers all too often HTML and CSS markup are the bastard, unmaintained children of our projects. We take the time to refactor our Ruby, Java and Python code but when it comes to cleaning up the HTML markup, we somehow manage to find excuses to ignore it. We love to praise DRYing up our code, but for HTML….it never seems to become a reality.

Case 1: Google Registration HTML

The following snippet was taken from the URL https://www.google.com/accounts/Login.

  <table width="100%" border="0" cellpadding="2" cellspacing="0">
  <tr>
  <td colspan="2"><img width="1" height="2" alt="" /></td>
  </tr>
  <tr>
  <td valign="top" width="1%">
  <a href='https://www.google.com/accounts/'>
  <img src='https://www.google.com/accounts/googleaccountslogo.gif'
       border="0"
       align="left"
       alt="Google" />
  </img>

  </a>
  </td>
  <td valign="top">
  <table width="100%" border="0" cellpadding="0" cellspacing="0">
  <tr>
  <td colspan="2"><img width="1" height="15" alt="" /></td>
  </tr>
  <tr bgcolor="#3366cc">
  <td><img height="1" width="1" alt="" /></td>

  </tr>
  <tr bgcolor="#e5ecf9">
  <td style="padding-left: 4px; padding-bottom:3px; padding-top:2px; font-family:arial,sans-serif;">
  <b>Google Accounts</b>
  </td>

While there is no DOCTYPE declaration for this page, one can assume the intentions were to render on as many browsers as possible in the most consistent manner. One technique is to forgo all of our fancy new (well newer) approaches and use the oldest subset of HTML available. Font tags and all. Unfortunately, all of the nasty HTML tricks we resorted to in the late 90’s also apply. The point of this is not to bash on Google, but show how we can improve this code and not repeat ourselves.

How can we improve this?

  1. We can start by setting a root class for the table. This will be the point in which we apply relative style rules.

  2. Since the CSS rule background-color doesn’t work as expected, we’ll need to use a descendant selector on the td elements.

  3. Move the the HTML attributes to a CSS declaration.

We might end up with something like the following:

 
.registration_table { width: 100%; border: none; }
.registration_table td { background-color: #e5ecf9; }
.registration_table tr.odd td { background-color: #3366cc; }

 <table class="registration_table" cellpadding="0" cellspacing="0">
  <tr>
  <td colspan="2"><img width="1" height="15" alt="" /></td>
  </tr>
  <tr class="odd">
  <td><img height="1" width="1" alt="" /></td>
  </tr>
  <tr>
  <td style="padding-left: 4px; padding-bottom:3px; padding-top:2px; font-family:arial,sans-serif;">
  <b>Google Accounts</b>
  </td>

While this isn’t perfect it provides us fewer points of modification if we wanted to do something like…change a color or reuse this style in a common file.

Case 2: Google Registration CSS

A similar situation exits in the CSS style rules for this page. Here we see redundant blocks of rule content. The font declarations font-family, font-size, and font-weight are repeated for the style rules: .gaia.sub.el, .gaia.sub.pl and .gaia.sub.rpl.

  .gaia.sub.el { font-family: arial, sans-serif; font-size: smaller; font-weight: bold;}
  .gaia.sub.pl { font-family: arial, sans-serif; font-size: smaller; font-weight: bold; }
  .gaia.sub.rpl { font-family: arial, sans-serif; font-size: smaller; font-weight: bold; }
  .gaia.sub.es { font-family: arial, sans-serif; font-size: smaller; font-style: italic; }
  .gaia.sub.seex { font-family: arial, sans-serif; font-size: smaller; color: #6f6f6f; }
  .gaia.sub.pc { font-family: arial,sans-serif; font-size: smaller; color: #6f6f6f; }

We could improve this by using a comma delimited declaration such as:

  .gaia.sub.el,
  .gaia.sub.pl, 
  .gaia.sub.rpl  { font-family: arial, sans-serif; font-size: smaller; font-weight: bold;}

The point is illustrate that HTML and CSS are code too! They suffer from many of the same issues that our application code bases suffer from…and can utilize the same techniques.

Excel Series Decoder in Ruby

Posted by Ben Poweski Tue, 04 Mar 2008 23:16:00 GMT

A co-worker of mine was writing a little script to parse an excel file that contained various network addresses and run various test cases against it. He was stumped on the algorithm how to decoded excel headers to specific indexes. While at first glance this looks like a simple problem, it ended up being more difficult than we thought. My co-worker approached the problem using a procedural approach, this ended up yielding a few nasty loops…far from elegant. The end result ended up being rather easy once the approach was modified to use recursion.

My Solution

require 'test/unit'

def to_excel(i)
  case i
  when 0
    return ''
  when 1..26
    return ('A'..'Z').to_a.at(i - 1)
  else
    q, r = (i - 1).div(26), (i - 1) % 26
    return "#{to_excel(q)}#{to_excel(r + 1)}"
  end
end

class ExcelNumberSeriesTest < Test::Unit::TestCase
  def test_simple
    assert_equal 'A', to_excel(1)
    assert_equal '', to_excel(0)
    assert_equal 'Z', to_excel(26)
  end

  def test_doubles
    assert_equal 'AA', to_excel(27)
    assert_equal 'AB', to_excel(28)
    assert_equal 'AZ', to_excel(52)
  end
end

Older posts: 1 2