refer to the previous post on this subject

Using analytics.data.qa.get doesn’t work as desired, so instead you need to do something like:

visitCount = client.execute(analytics.to_h["analytics.data.ga.get"], {
                              :ids=>"ga:" + YOUR_PROFILE_NUMBER,
                              "start-date" => "2012-06-12",
                              "end-date" => "2012-07-01",
                              :metrics => "ga:visits"}
                            )

Note the part of using to_h['analytics.data.ga.get"] to get the right signature to pass onto the APIClient execute method. That will work and works well. To make it easier to formulate queries against GA, I’d recommend using Google’s query explorer tool here http://ga-dev-tools.appspot.com/explorer/

 
  1. Goto https://code.google.com/apis/console
  2. Create a new project
  3. Under services, select Google Analytics
  4. Goto API Access of a new project
  5. generate a new oAuth credential, selecting “service account”.
  6. Download your p12 cert file

 

In Google analytics, use the service account email address and assign it as a new administrator to the desired GA profile.

On ALL servers destined to use the service account to GA, install and syncronized with ntp.  If your even 500ms off, you’re going to have a bad time with “Grant_invalid” messages.

In a testbed project, make 2 files: Gemfile & testbed1.rb ( you’re going to create a lot of these testbed files on your own ).

Gemfile

source "http://rubygems.org"
gem 'google-api-client'
gem 'pry'

testbed1.rb

require 'pry'
require 'rubygems'
require 'google/api_client'
 
keyFile = "SOME_KEY_GOES_HERE-privatekey.p12"
 
cID = "YOUR_SOOPA_SECRET_SA"
 
scope = 'https://www.googleapis.com/auth/analytics.readonly'
email = 'YOUR_EMAIL_GOES_HERE@developer.gserviceaccount.com'
 
 
#Normally it would be bad to put the passphrase here, but aftet talking to several dozen devs, everyone's pass phrase is not a secret
key = Google::APIClient::PKCS12.load_key(keyFile, "notasecret")
 
asserter = Google::APIClient::JWTAsserter.new(
   email,
   scope,
   key)
 
puts asserter.authorize()
 
binding.pry

If all goes well, the JWTAsserter instance will get a valid token and no exceptions/errors will be thrown. If you’ve followed all of the steps listed earlier and things are still breaking, troubleshooting paths are: Verify your machine time is correct, verify your service account email address is bound to google analytics, and lastly you might need to wait until Google platform catches up with the changes. For myself, it took 9 hours until my account finally authenticated through. Google has potentially a million or more servers organized into cells, the fact that they seem to cooperate well doesn’t mean they’re perfectly in sync at all times.

Otherwise if all else fails, I recommend stalking this guy Nick https://groups.google.com/d/msg/google-analytics-data-export-api/maa_fyjD2cM/sT8tDDh0wNsJ – It seems like he’s a Google employee on the service account dev/implementation team and generally stuff gets fixed if he says it’s getting fixed.

As I run into any more troubles, I will update and add more notes.

 Permalink  Uncategorized  Comments Off
Jul 092012
 

My business DSL connection was out this evening, so I wrote up a quick script to track how long exactly it was out for.

import envoy
import time
 
roller = 0
Limit = 50
while Limit > 0:
    rs = envoy.run("ping google.com")
    if rs.status_code != 1:
        print "PING %s" % time.ctime()
        Limit -= 1
        time.sleep(10)        
 
    roller += 1
    if roller % 100:
        print "PONG %s" % time.ctime()

Envoy is probably one of my favorite utility libraries after the Http Request library. Github repo is here https://github.com/kennethreitz/envoy/blob/master/README.rst

 

sudo apt-get install ia32-libs
sudo apt-get install gcc-multilib g++-multilib libsdl1.2-dev texinfo libcrypto++-dev libssl-dev lib32ncurses5-dev m4 libelf-dev

This is about 300Mb of stuff, some of it can be culled but I didn’t feel like messing around with that.

Allows for pepper 19 examples to be compiled successfully.

 

The other month/week I resumed some dabbling/hacking experiments in working with HTML5′s canvas. This go around, I decided to give CraftyJS a try.

The short version of my experiments, CraftyJS has a lot of potential if it can get it’s memory leaks under control, which might be a daunting task.

Here’s the example Pong game implementation that can be found on CraftyJS’s website:

 
Crafty.init(600,300);
Crafty.background("rgb(127,127,127)");
 
//Paddles
Crafty.e("Paddle, 2D, DOM, Color, Multiway")
    .color('rgb(255,0,0)')
    .attr({ x: 20, y: 100, w: 10, h: 100 })
    .multiway(4, { W: -90, S: 90 });
 
Crafty.e("Paddle, 2D, DOM, Color, Multiway")
    .color('rgb(0,255,0)')
    .attr({ x: 580, y: 100, w: 10, h: 100 })
    .multiway(4, { UP_ARROW: -90, DOWN_ARROW: 90 });
 
//Ball
Crafty.e("2D, DOM, Color, Collision")
    .color('rgb(0,0,255)')
    .attr({ x: 300, y: 150, w: 10, h: 10,
            dX: Crafty.math.randomInt(2, 5),
            dY: Crafty.math.randomInt(2, 5) })
    .bind('EnterFrame', function () {
        //hit floor or roof
        if (this.y <= 0 || this.y >= 290)
            this.dY *= -1;
 
        if (this.x > 600) {
            this.x = 300;
            Crafty("LeftPoints").each(function () {
                this.text(++this.points + " Points") });
        }
        if (this.x < 10) {
            this.x = 300;
            Crafty("RightPoints").each(function () {
                this.text(++this.points + " Points") });
        }
 
        this.x += this.dX;
        this.y += this.dY;
    })
    .onHit('Paddle', function () {
    this.dX *= -1;
})
 
//Score boards
Crafty.e("LeftPoints, DOM, 2D, Text")
    .attr({ x: 20, y: 20, w: 100, h: 20, points: 0 })
    .text("0 Points");
Crafty.e("RightPoints, DOM, 2D, Text")
    .attr({ x: 515, y: 20, w: 100, h: 20, points: 0 })
    .text("0 Points");

Now I will break this down.

Crafty.init(600,300);
Crafty.background("rgb(127,127,127)");

Relatively straight forward; this generates a HTML5 canvas element of 600×300 pixels, sets the color to a neutral color range.

Crafty.e("Paddle, 2D, DOM, Color, Multiway")
    .color('rgb(255,0,0)')
    .attr({ x: 20, y: 100, w: 10, h: 100 })
    .multiway(4, { W: -90, S: 90 });

Part of Crafty’s cleverness is in it’s component based entity system. The first line tells the Crafty library that you’re defining a new entity called “Paddle” which is a 2D, DOM behavior like, color’d objected that reacts to multiple user inputs. Break down:

.color(…) defines the paddles color
.attr(…) defines the entities dimensions AND position.
.multiway(…) is a clear API method which states
the entities movement speed, and then which direction a triggered keyboard input will send the entitiy. So in the above case W is north, and S is south.

Skipping the other paddle, we come to the ball in a pong game.

Crafty.e("2D, DOM, Color, Collision")
    .color('rgb(0,0,255)')
    .attr({ x: 300, y: 150, w: 10, h: 10,
            dX: Crafty.math.randomInt(2, 5),
            dY: Crafty.math.randomInt(2, 5) })
    .bind('EnterFrame', function () {
        //hit floor or roof
        if (this.y <= 0 || this.y >= 290)
            this.dY *= -1;
 
        if (this.x > 600) {
            this.x = 300;
            Crafty("LeftPoints").each(function () {
                this.text(++this.points + " Points") });
        }
        if (this.x < 10) {
            this.x = 300;
            Crafty("RightPoints").each(function () {
                this.text(++this.points + " Points") });
        }
 
        this.x += this.dX;
        this.y += this.dY;
    })
    .onHit('Paddle', function () {
    this.dX *= -1;
})

Something I glossed over, Crafty’s e(…) function is actually a Javascript prototype class generator. It’s important to note that because of the interplay between .attr() and every other post e(…) method call.

In the above

.attr({ x: 300, y: 150, w: 10, h: 10,
            dX: Crafty.math.randomInt(2, 5),
            dY: Crafty.math.randomInt(2, 5) })

defines additional properties of the entity. x/y & w/h are already used by the 2D and DOM components to determine the entities position on but in the later .bind(“EnterFrame”) notice that the logic involved is referencing this attributes.

So inside the EnterFrame handler for the Ball are two crucial sections.

if (this.x > 600) {
            this.x = 300;
            Crafty("LeftPoints").each(function () {
                this.text(++this.points + " Points") });
        }
        if (this.x < 10) {
            this.x = 300;
            Crafty("RightPoints").each(function () {
                this.text(++this.points + " Points") });
        }
<pre>
 
These two if clauses handle bounds check's and then depending on position award the appropriate side a point.
 
Notice the Crafty("") calls.  In this case Crafty("LeftPoints") calls up the appropriate entity or entities ( in this case there are only 1 per side ) and applies a closure to increment the winning side's this.points and body text.
 
 
The other crucial section is the 2 line closure 
 
<pre lang="javascript">
.onHit('Paddle', function () {
    this.dX *= -1;
}

A fairly cool concept in Crafty is that collision detection between almost any entity is dealt with by Crafty, so to determine if the Ball hits a paddle, you just have to ask Crafty.

Summary

I was fairly impressed with CraftyJS, it is very much the spiritual relative of jQuery for a dirt simple and comfortably clever API. Unfortunately Crafty can blind side you with it’s cleverness if you’re not careful. What I mean is that in experimenting with CraftyJS I found it fairly easy to create non-obvious memory leaks and or abuse closures to much.

Still it’s a fairly nice library and though this post is slightly long, I am only covering a thin scratch of the depth that is in CraftJS. This could be a fantastic building stage for making a slew of quick and dirty games.

 

So far really not impressed with Apple’s APN service, especially it’s sandbox/development tier.

To get started, I recommend reading the Founder/CTO of Server Density’s recipe/guide to getting started with APN, here ( http://blog.serverdensity.com/2009/07/10/how-to-build-an-apple-push-notification-provider-server-tutorial/ )

Because of how many times I had to clean slate my dev. environment, I tried to streamline the process of converting the APN certificate and my private key. In the process of converting the private key to pem format, you do have to provide a pass phrase.

echo "Convert certificate"
openssl pkcs12 -clcerts -nokeys -out apns-dev-cert.pem -in apns-dev-cert.p12
 
echo "Converting key"
echo "You must provide a PEM phrase, it will be stripped out in next step"
openssl pkcs12 -nocerts -out apns-dev-key.pem -in apns-dev-key.p12
 
echo "Stripping off PEM phrase"
openssl rsa -in apns-dev-key.pem -out apns-dev-key-noenc.pem
 
echo "Concatenating keys"
cat apns-dev-cert.pem apns-dev-key-noenc.pem > apns-dev.pem

One SERIOUS word of warning about APN is a scenario where you *known* beyond a shadow of a doubt that your APN requests are properly formed and the TLS connection works as expected but nothing happens. To repeat, everything looks like it works but you don’t get any APN’s to your device. My advice is to delete your APN certificate from your keychain and re-download the APN certificate, convert it again, and try again.

To verify your key is correct, the command line openssl utility is somewhat invaluable

 openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert apns-dev-cert.pem -key apns-dev-key-noenc.pem

There should be no errors and the console should hang immediately after the — line until you type in some garbage.

Apple: Anti-developer

As I said earlier, I am really not impressed with APN for one specific reason. I lost about 4-5 hours of my life yesterday trying various different APN libraries for PHP, Ruby, Python, and objective-c. My payload to APN was correct, my token ID was triple verified, and I was sure I was sending the data down the wire. Meanwhile I got no error messages or warnings that my certificate was out of date/order and because of that my APN requests were being ignored.

The worst technology on the planet isn’t that what gives ambigious/cryptic error messages but that which just silently fails with no means to diagnose the problem. Hell it’s worse that the infamous “There was an error, somewhere, sometime.” joke.

Apr 052012
 
  1. Find a good tutorial to setup the CLI Dropbox agent – This one is the most concise IMO
  2. Grab this http://www.dropbox.com/download?dl=packages/dropbox.py
  3. `dropbox.py exclude add` is the command you need

Say I’ve got 30+ directories in my dropbox but I only want “md”

  find -maxdepth 1 -type d | cut -b3 | grep -v md | xargs python md/dropbox.py exclude add

That will add everything else to the exclusion list AND clean out the local Dropbox path for you. One point to note is that .dropbox-cache/ gets hoovered into the exclusion list, which is redundant and doesn’t appear to cause any harm.

I’ve increasingly been using Dropbox as a low-security transfer protocol ( critical things like ssh keys, password dictionaries, and certificates are handled separately ) and now with the selective sync it’s becoming fairly trivial to keep my horde of virtual servers both in house and running on AWS synced. One thing I’ve been trying out is using the autostart functionality to kick on when I login to a box. I am not sure but if Dropbox could kick on only when I am logged in would be fairly nice.

Mar 092012
 

Graph Processing in Python
Scalability at YouTube
Practical Machine Learning in Python
LUNCH
Code Generation in Python: Dismantling Jinja
The Magic of Metaprogramming
Throwing Together Distributed Services With Gevent
Putting Python in PostgreSQL

And I think that ends day 1 of the conference. Mostly I am hoping to combine what I learn in the Graph processing and Practical ML talks, while having an overview of code generation might be a solution ( or a new problem ) to my current client’s issues. As for metaprogramming, gevent, and postgreSQL; those just seem fun.

Off to PyCon 2012

 Uncategorized  Comments Off
Mar 082012
 

Still trying to figure out what presentations I want to go to, but I am genuinely excited to be attending another PyCon, this time around in California. Also looking forward to seeing startup row to see what wonderful things are being built with Python this year around.

 

I have a few forked repo’s, either because I needed to make some unique and custom change to the project or because I wanted a safe snapshot in time of the project.

Occasionally I’d like to update these forks against their master and the Google has provided a very concise blog post here(http://bradlyfeeley.com/2008/09/03/update-a-github-fork-from-the-original-repo/). Kudo’s to Bradly Feeley.

© 2012 Refactored scope Suffusion theme by Sayontan Sinha