Tag: Internet

Take Me Somewhere Rework

May 26, 2009 » Geek

Over the weekend I knocked out a new code base for TakeMeSomewhere.org. It’s not much, just a new look and feel as well as some back end work so that I can get fancy later.

Check It Out

Amarok REST API

January 1, 2009 » Geek

I’ve been working on the guts of a REST API for Amarok though PHP and DCOP. Thought I’d share my JSON format because I’m proud of it. Also because I’m bound to lose the format file sooner or later.

There are two basic things you can do with Amarok: take an action and ask for information. So that’s how I broke it down, action and info blocks in every request.

Rather than codify it in any formal way I’m just going to show examples.

Action – Toggle play/pause condition
Request

{
  'action': {
    '0': {
      'name':'playPause',
      'params': false
    }
  }
}

Response

{
  'action': {
    '0': {
      'name':'playPause',
      'error':false
    }
  }
}

Action – Play and set the equalizer
Request

{
  'action': {
    '0': {
      'name':'play',
      'params': false
    },
    '1': {
      'name':'setEqualizer',
      'params': {
        '0':'20',
        '1':'30',
        '2':'40',
        '3':'10',
        '4':'20',
        '5':'30',
        '6':'40',
        '7':'10',
        '8':'20',
        '9':'30',
        '10':'40',
        '11':'10',
      }
    }
  }
}

Response

{
  'action': {
    '0': {
      'name':'playPause',
      'error':false
    },
    '1': {
      'name':'setEqualizer',
      'error':false
    }
  }
}

Info – Get playing track album name
Request

{
  'info': {
    '0': {
      'name':'album',
      'params': false
    }
  }
}

Response

{
  'info': {
    '0': {
      'name':'album',
      'value':'Doppleganger'
    }
  }
}

Info – Get playing track album name, artist and title.
Request

{
  'info': {
    '0': {
      'name':'album',
      'params':false
    },
    '1': {
      'name':'artist',
      'params':false
    },
    '3': {
      'name':'title',
      'params':false
    }
  }
}

Response

{
  'info': {
    '0': {
      'name':'album',
      'value':'Doppleganger'
    },
    '1': {
      'name':'artist',
      'value':'The Fall of Troy'
    },
    '3': {
      'name':'title',
      'value':'F.C.P.R.E.M.I.X'
    }
  }
}

Both – Go to next track, get that track artist.
Note: I have decided that when both action and info are present they will alternate execution starting on action (i.e. action 0 then info 0 then action 1 and so on.) Thus we will probably want to create a NOP at some point.
Request

{
  'action': {
    '0': {
      'name':'next',
      'params': false
    }
  },
  'info': {
    '0': {
      'name':'artist',
      'params':false
    }
  }
}

Response

{
  'action': {
    '0': {
      'name':'playPause',
      'error':false
    }
  },
  'info': {
    '0': {
      'name':'artist',
      'value':'Far-Less'
    }
  }
}

Gmail Attachment Gets Stuck Scanning For Virus

December 26, 2008 » Geek

I’ve been having trouble with Gmail for my domain getting stuck scanning for viruses on my attachments, which means I can’t download them, which is annoying.

I got fed up with waiting for Gmail, so I just got them through the old fashioned means.

Here’s how…


Attachment is stuck…


View the original message…


What that looks like (click image for bigger view)


Find the base64 encoded contents of your attachment (click image for bigger view)

Then you just copy and paste that into a file and run it through base64, a la $ base64 -d getImage.raw > getImage.php

Move Subversion repository without svnadmin

November 12, 2008 » Geek

Update (2008-11-13)
Okay, so I did actually end up finding a way to move from SF.net for real. It seems they provide read-only rsync access straight to the repository directory. So here is what I did instead.

$ rsync -av blowpass.svn.sourceforge.net::svn/blowpass/* blowpass
$ svnadmin dump blowpass/ > blowpass.dump
$ svnadmin create clearpass
$ svnadmin load clearpass < blowpass.dump

Update (2008-11-12)
Made a small performance change then ran it on the ClearPass repository. Worked flawlessly.

I have been having a terrible time trying to figure out how I can get the Subversion repository for ClearPass out of SourceForge. I could not find a single reference to svnadmin on the SourceForge and no examples of exporting without it. So I took matters into my own hands. Below is a quick and dirty shell script that exports and imports a repository one revision at a time, using common Linux command line tools and the svn command. I'm going to do more testing before using it for real, but so far it has done well. Hope this helps someone else in my position.

Download it: svncrossload

#!/bin/sh

################################################################################
# LICENSE
################################################################################
# Copyright 2008 John Hobbs
################################################################################
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
################################################################################

################################################################################
# ABOUT
################################################################################
#
# Home: http://www.velvetcache.org/
#
# This is a script to cross load subversion repositories (kind of) keeping history
# intact without access to svnadmin.  Import into a FRESH repository only, and
# be sure to do a comprehensive diff at the end.
#
# Also be sure to do this in an empty directory. Temp files get added and removed
# without sincere thought put into them.
#
# Log messages get eaten and re-inserted as shown below. Edit to taste.
#   $ svn log -r 1
#   ------------------------------------------------------------------------
#   r1 | jmhobbs | 2008-11-12 18:19:43 -0600 (Wed, 12 Nov 2008) | 7 lines
#
#   Imported from file:///srv/svn/scs using svncrossload
#
#     |r1 | jmhobbs | 2008-10-27 17:32:44 -0500 (Mon, 27 Oct 2008) | 2 lines
#     |
#     |Initial import.
#     |
#
#   ------------------------------------------------------------------------
#   $

echo "Checking out initial revisions"
svn co $2 importing > /dev/null
svn co -r 0 $1 updateme > /dev/null

echo "Getting most recent revision number"
LATESTREVISION=$(svn info $1 | grep Revision | sed 's/^Revision: *\([0-9]*\)/\1/')

for i in $(seq 1 $LATESTREVISION); do

  echo -e "\nCopying revision $i"

  cd updateme
  svn update -r $i > ../_update
  echo -e "Imported from $1 using svncrossload\n" > ../_log
  # The '\-\-\-\-\...' looks ridiculous, but it works.
  svn log -r $i | grep -v '\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-' | sed 's/\(.*\)/   |\1/'  >> ../_log
  cd ..

  cat _update | grep -E '^A' | sed 's/^A *//' > _update_add
  cat _update | grep -E '^D' | sed 's/^D *//' > _update_del
  cat _update | grep -E '^U' | sed 's/^U *//' > _update_mod

  echo "$(wc -l _update_add | sed 's/^\([0-9]*\).*/\1/') Files To Add"
  echo "$(wc -l _update_mod | sed 's/^\([0-9]*\).*/\1/') Files To Modify"
  echo "$(wc -l _update_del | sed 's/^\([0-9]*\).*/\1/') Files To Delete"

  # Copy
  for j in $(cat _update_add | tr ' ' '@'); do
    if [ -d "updateme/${j//@/ }" ]; then
      mkdir "importing/${j//@/ }"
    else
      cp -f "updateme/${j//@/ }" "importing/${j//@/ }"
    fi
    cd importing
    # We send cerr to null because it warns when we add existing stuff
    svn add "${j//@/ }" 2> /dev/null
    cd ..
  done

  # Modify
  for j in $(cat _update_mod | tr ' ' '@'); do
    if [ -f "updateme/${j//@/ }" ]; then
      cp -f "updateme/${j//@/ }" "importing/${j//@/ }"
    fi
  done

  # Delete
  for j in $(cat _update_del | tr ' ' '@'); do
    cd importing
    svn rm "${j//@/ }"
    cd ..
  done

  echo "Committing"
  cd importing
  svn commit -F ../_log
  cd ..

done

echo "Cleaning up"
rm -rf importing _log _update _update_add _update_del updateme _update_mod
echo "Done!"

Better libcurl from C++

October 24, 2008 » Geek

I’ve been a longtime fan of libcurl. But I’m a C++ author and so the c level of that is not where I want to be (and cURLpp looks ungainly for my minor usage).

Firing up google on “libcurl C++” yields “Using libcurl from C++ | Luckyspin.org” as the #1 entry. This article show a good starting example, but it’s not quite there. Here’s a cleaned up snippet:

// Write all expected data in here
static string buffer;
  
// This is the writer call back function used by curl  
static int writer(char *data, size_t size, size_t nmemb, std::string *buffer) {
  int result = 0;  
  if (buffer != NULL) {
    buffer->append(data, size * nmemb);  
    result = size * nmemb;
  }
  return result;
}
.
.
.
int main(int argc, char* argv[]) {
.
.
.
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
.
.
.

Now that is a totally legitimate use and it works fine. But do you see the problem?
Yep, the data (buffer) is global, as is the writer but that isn’t as big a deal. This
is not good for many applications and is not good C++.

So let’s encapsulate that bad boy shall we? It’s really not all that hard, so here’s some example code.

#include 
#include 
#include 

class MyCurlObject {
  public:
    MyCurlObject (std::string url) {
      curl = curl_easy_init();
      if(!curl)
        throw std::string ("Curl did not initialize!");

      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &MyCurlObject::curlWriter);
      curl_easy_setopt(curl, CURLOPT_WRITEDATA, &curlBuffer);
      curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
      curl_easy_perform(curl);
    };

    static int curlWriter(char *data, size_t size, size_t nmemb, std::string *buffer) {
      int result = 0;
      if (buffer != NULL) {
        buffer->append(data, size * nmemb);
        result = size * nmemb;
      }
      return result;
    }

    std::string getData () { return curlBuffer; }

  protected:
    CURL * curl;
    std::string curlBuffer;
};

int main (int argc, char ** argv) {
  try {
    MyCurlObject mco ("http://www.google.com/");
    MyCurlObject moco ("http://www.yahoo.com/");
    std::cout << moco.getData() << std::endl;
    std::cout << "--------------------------------------------" << std::endl;
    std::cout << mco.getData() << std::endl;
  }
  catch (std::string & s) {
    std::cerr << "Oops! " << s << std::endl;
  }
}

Now that example has all kinds of missing things and the object is useless beyond one request but that is not the point, it's a contrived example. The point is that your buffer is no longer global and it's protected by your class. You can make multiple requests without having to grab the data off by yourself. That's the big deal.

I don't want this to seem like I am putting down LuckySpin. It's a good example, I feel this is just a step better.