Uncategorized

New RocDubs Forum Theme

by Matt Danger on Mar.18, 2010, under Uncategorized

Every once in while I like to flex my design muscles. When I moved to Rochester last November I joined up with the local european car group RocDubs. These kids have been a lot of fun to hang out with. Like most car groups we have a forum (vBulletin) and we needed a personalized flavor so I took on the task of making a theme. Today I launched it.

Leave a Comment more...

Making database changes to Drupal multi-sites

by Matt Danger on Dec.21, 2009, under Uncategorized

The company I work for hosts over 150 Drupal sites in a multi-site configuration and every so often I need to publish a change to the code that requires a database change. The large number of sites we host means that performing manual changes would require too much time and carries a chance of error. I’ve come up with a simple solution.

I first create a PHP script that bootstraps Drupal. Here is an example of a script that will rebuild the menu router tables.

// Bootstrap
require_once('includes/bootstrap.inc');
require_once('includes/common.inc');
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
 
// Rebuild menus
menu_rebuild();
print 'Menu rebuild complete\n';

I name this script rebuild_menus.php and upload it to my Drupal directory. Then, I create a text file on my desktop that contains a list of all the Drupal websites. This is an abbreviated example:

http://example1.com
http://example2.com
http://example3.com
http://example4.com

Finally, I execute the script on all the sites by running the following command:

for url in `cat list.txt`; do echo "Running script on $url"; curl $url/rebuild_menus.php; echo; done

Leave a Comment :, , , , more...

Control Adium from the Terminal

by Matt Danger on May.27, 2009, under Uncategorized

I heart Adium with its beautiful interface, extensive plugins, and scriptability. I use the app so much that I often forget to sign out when I leave home or work. This creates OTR private key conflicts when someone messages me. AIM (and maybe the other networks) will alert you if you’re signed on from multiple locations and will even let you kill the other sessions. I want to be able to remotely sign on and off from Adium and also want the ability to remotely change my account status message.

Fortunately, Adium has good Applescript support that can be extended via a shell script. I wrote this bash script that does exactly that. It is command line driven so I can SSH into my home or work computer and execute it.

#!/bin/sh
 
# Copyright Matt West  5/23/2009
 
#
# Usage
#
usage() {
    echo "Usage $0  [command]
 
Options
    -a account
        Account screen name
    -l
        Display the current account status and away message
    -m message
        Set account as away with a message
    -t type
        Status type: available, away, invisible, offline
"
    exit 0
}
 
#
# Grab our environment
#
. /etc/profile
 
#
# Define
#
APP="Adium"
 
#
# Get opts
#
while getopts "a:lm:t:" OPTIONS; do
  case $OPTIONS in
    a)  ACCOUNT=$OPTARG
        ID=`osascript -e 'tell application "'$APP'" to get id of accounts whose name is "'$ACCOUNT'"'`
        ;;
 
    l)  # Display the current account status
        STATUS=`osascript -e 'tell application "'$APP'" to get status type of account '$ID`
        MESSAGE=`osascript -e 'tell application "'$APP'" to get status message of account '$ID`
 
        if [[ $STATUS == 'away' ]]; then
            echo $ACCOUNT is currently away with the message \"$MESSAGE\" #"
        else
            echo $ACCOUNT is currently $STATUS
        fi
        exit 0
        ;;
 
    m)  MESSAGE=$OPTARG;;
 
    t)  STATUS=$OPTARG;;
  esac
done
 
# An account is required
if [[ -z $ACCOUNT ]]; then
    usage
else
    if [[ -z $ID ]]; then
        echo "Error: Couldn't find the account $ACCOUNT"
        exit 1
    fi
fi
 
# Set the status type
if [[ -n $STATUS ]]; then
    osascript -e 'tell application "'$APP'" to set status type of account '$ID' to '$STATUS
fi
 
# Update the away message
if [[ -n $MESSAGE ]]; then
    osascript -e 'tell application "'$APP'" to set status type of account '$ID' to away'
    osascript -e 'tell application "'$APP'" to set status message of account '$ID' to "'"$MESSAGE"'"'
fi

To use, copy and paste this code into an empty text file and name it adiumcontrol (or whatever you’d like). Then make the file executable:

chmod +x adiumcontrol

Then try it out. You control each IM account independently. In this example ‘habitcky’ is my AIM screen name:

./adiumcontrol -a habitcky -l
habitcky is currently available

Set your away message:

./adiumcontrol -a habitcky -m "I am currently unavailable"

Sign yourself offline:

./adiumcontrol -a habitcky -t offline

Sign yourself back online:

./adiumcontrol -a habitcky -t available

Leave a Comment more...

Tips For Your Summer of Code Application

by Matt Danger on Mar.26, 2009, under Uncategorized

Google began accepting applications for the Summer of Code yesterday and we’ve been busy on the Geeklog IRC channel answering student questions and reading proposals.

Here are some things to remember when writing a proposal for the Summer of Code:

Understand the organization you’re applying to work with
Before you spend any time writing a proposal you need to understand the organization, software, and problem you’re working on. Download the latest version of the code and read through some of it. Install and use it. Look at the documentation. See what the software can and can’t do and how it applies to your project.

Write a good proposal!
After you’ve looked through the code and feel you have a good understanding of the problem then you can sit down and start writing. Your proposal should include all the points of the problem, why they’re a problem, how you’re going to address the problem, and how your solution to the problem will benefit the organization.

Only write a few proposals
A good proposal takes a long time to write. You need to fully understand the problem and the organization before writing a good proposal. You may think that writing a bunch of proposals for many different organizations will increase your odds of being selected, but instead you’re just decreasing the quality of your proposals and reducing your chances of being selected.

Ask questions
Mentors are hanging out on IRC all day waiting for you to ask them questions. We’re excited to do it because we get to see the interest in our organization. We’d also be glad to look over your proposal and provide feedback before you submit it to the SoC.

To give students an example of what a proposal should look like I’m going to post my proposal from last year. Unfortunately, I can’t find the one from 2007 that I think is a little better.

Abstract

The Geeklog installation wizard makes setting up a new, or upgrading an
existing, Geeklog site a quick and painless process. However, there are
two situations where a website administrator must still perform tasks
manually: managing plugins and migrating from a backup. My proposal is
to add a plugin management utility that will be rolled into the
installation process and will allow direct control of plugins as well as
a migration utility that will give the user the ability to restore
Geeklog from a backup seamlessly.

PROJECT DETAILS – PLUGIN FEATURE

The plugin installation process will be made steamless for the user. An
“Advanced Installation Options” link will appear underneath what is
currently the install configuration options form on page 2 of the
installation and when clicked will take the user to a separate page to
manage plugins (and migration, which will be discussed in the next
section). The list of plugins will be populated by listing the contents
of Geeklog’s plugins directory. A file upload form will give the user a
simpler method of uploading the plugin, which will require the plugins
directory be write-able by the web server. By default all of the plugins
inside the plugins directory will be installed, unless the user chooses
to not install them. The plugins that are selected for install will be
sent with the rest of the form data from step 2 to step 3 of the
installation wizzard where each plugin’s installation script is executed.

The plugin installation during the upgrade process will be similar to
the new installation process described in the previous paragraph. If a
newer version of an installed plugin exists the plugin will be
automatically upgraded. The user will still be given the ability to
install new plugins during the upgrade in the same way as a fresh install.

In addition to the installation wizard, the plugin management panel
inside the administration area will be modified to add the ability to
upload a plugin which will make adding new plugins quicker.

For users who wish to create a custom Geeklog distribution with their
own favorite plugins a simple stand alone utility will be developed.
This will consist of a single PHP shell script that downloads and
decompresses the Geeklog tarball and lists the contents in the plugins
directory. The user will be have the ability to deselect and remove any
of the listed plugins and also given the ability to add additional
plugins by either copying a plugin tarball, or directory, from another
directory on the local machine or specifying a URL to the plugin tarball
on a remote server. After the user makes selects the plugins they want
the entire geeklog directory will be recompressed with the new plugins.
All the plugins in the plugins directory will be installed by default,
unless unselected by the user, during install.

PROJECT DETAILS – MIGRATION ASSISTANT FEATURE

Geeklog currently has a backup feature which creates a SQL table scheme
and data file. This file will be used as a restore point for the
migration feature.

The option to migrate from backup will be added to the “Advanced
installation options” area proposed above for plugin installation. In
this area a checkbox to “Import from backup” will appear with the option
to select an existing backup from the backups/ directory or to upload a
backup file. A message will be displayed to users to warn them about
possible timeout issues when uploading large files and that they may
want to upload their file via FTP to the backups directory instead.

Once a backup file is selected the migration process will import the
database table schema and data from the backed up SQL file. Some
additional analysis will need to be taken during this step so that large
database imports do not exceed the web server’s maximum script runtime.
A possible solution would be to perform a staggered import, where the
import process is broken into smaller pieces. Dirk has suggested a
utility called BigDump which does this for MySQL. We might be able to
simply implement that utility with a modification to allow it to also
work with MS SQL.

After the database has been imported the script will query the
‘conf_values’ table to ensure the stored paths match the new system
paths. If they do not they will be updated based on the data from the
installation form or the user will be prompted to define the path. This
is similar to a fresh installation where all paths must be set. The last
step will be any remaining checks to ensure all necessary database
information exists, that required plugins exist (if they don’t they will
be disabled in the database until the user installs them) and the
correct system files are in place.

Finally, the Geeklog upgrade documentation makes a strong recommendation
that the user backup their database before attempting to upgrade, so why
don’t we offer to do this for them? An option will be added during the
upgrade process to ask the user if they’d like us to backup their
existing installation. This will not be selected by default because of
the time it would add to an upgrade. If selected a backup of the
database will be saved to the backups directory before updates are performed.

BENEFITS

- Plugin installation steps will be reduced and will require no command
line access of file editing resulting in fewer sources of user error.
- Migration feature would give users the ability to easily and reliabily
restore from backups without remote shell access.
- Automatic backup option before performing an upgrade will create a
quick and simple restore option for users that experience a problem in
the upgrade process.

TIMELINE

Week 1: Checkout latest GL package and start evaluating the code base
Week 2: Final plugin installation and migration assistant format design
Week 3-4: Code furiously, develop unhealthy caffeine and energy drink
dependence
Week 5: Rough working plugin installation feature
Week 7: Rough working migration assistant feature
Week 8: Midterm, submit code for evaluation
Week 9: Make revisions based on any mentor suggestions
Week 11: Major work complete on plugin installation feature, submit to CVS
Week 12: Major work complete on migration assistant feature, submit to CVS
Week 13: Begin to complete documentation and testing
Week 14: Iron out final bugs
Week 15: Submit all deliverables for evaluation

DELIVERABLES

- Plugin installation/management added into installation script
- Plugin installation/management added to administration panel
- Stand alone command line utility to create custom Geeklog distributions
- Migration feature added into installation script
- Additional English localization entries
- Additional install documentation

ABOUT ME

I am a 23 year old graduate student at D’Youville College in Buffalo,
NY, USA. I enjoy programming for the web but more importantly I love
creating a rich experience for those who use my software. I have
previously worked with Geeklog in the 2007 Summer of Code program and
the experience was invaluable. I had an incredible time and hope to be a
participant again this year! I believe I am the best applicant for this
project because I wrote and am deeply familiar the current installation
wizard script.

Leave a Comment more...

My Growing Duck Army

by Matt Danger on Mar.12, 2009, under Uncategorized

It’s getting a little out of control..

Leave a Comment : more...

Facebook-Status-2.0 announced!

by Matt Danger on Feb.10, 2009, under Perl, Shell Scripting, Uncategorized, Unix, terminal

I have updated my original Facebook status script to work with Facebook 2.0.

Why is this interesting? Until recently the Facebook Developer Platform didn’t allow the changing of user status messages. This does and can be implemented in other utilities, which I may do in the future. Enjoy!

Leave a Comment :, , , more...

Adjust Mac OS X display brightness from the Terminal

by Matt Danger on Dec.17, 2008, under Mac OS X, Uncategorized

One of the classrooms I maintain is comprised of 2.4Ghz iMacs (MB323LL/A) that are dual booted with Windows XP and Mac OS X. Sometimes when the workstations are restarted from XP to OS X the display brightness gets changed to its dim power saver setting. This requires the user manually increase the display brightness by pressing the F2 key, which is inconvenient. I haven’t been able to determine the cause of this issue so I wanted to create a login hook to increases the brightness as a temporary fix.

OS X doesn’t ship with a command line utility that let’s you change display brightness. Fortunately, Nicholas Riley has written a utility that uses OS X frameworks to accomplish this quickly and easily. Here’s the code:

#include <stdio.h>
#include <unistd.h>
#include <IOKit/graphics/IOGraphicsLib.h>
#include <ApplicationServices/ApplicationServices.h>
 
const int kMaxDisplays = 16;
const CFStringRef kDisplayBrightness = CFSTR(kIODisplayBrightnessKey);
const char *APP_NAME;
 
void errexit(const char *fmt, ...) {
  va_list ap;
  va_start(ap, fmt);
  fprintf(stderr, "%s: ", APP_NAME);
  vfprintf(stderr, fmt, ap);
  fprintf(stderr, "\n");
  exit(1);
}
 
void usage() {
  fprintf(stderr, "usage: %s [-m|-d display] [-v] <brightness>\n", APP_NAME);
  fprintf(stderr, "   or: %s -l [-v]\n", APP_NAME);
  exit(1);
}
 
int main(int argc, char * const argv[]) {
  APP_NAME = argv[0];
  if (argc == 1)
    usage();
 
  int verbose = 0;
  unsigned long displayToSet = 0;
  enum { ACTION_LIST, ACTION_SET_ALL, ACTION_SET_ONE } action = ACTION_SET_ALL;
  extern char *optarg;
  extern int optind;
  int ch;
 
  while ( (ch = getopt(argc, argv, "lmvd:")) != -1) {
    switch (ch) {
    case 'l':
      if (action == ACTION_SET_ONE) usage();
      action = ACTION_LIST;
      break;
    case 'v':
      verbose = 1;
      break;
    case 'm':
      if (action != ACTION_SET_ALL) usage();
      action = ACTION_SET_ONE;
      displayToSet = (unsigned long)CGMainDisplayID();
      break;
    case 'd':
      if (action != ACTION_SET_ALL) usage();
      action = ACTION_SET_ONE;
      errno = 0;
      displayToSet = strtoul(optarg, NULL, 0);
      if (errno == EINVAL || errno == ERANGE)
	errexit("display must be an integer index (0) or a hexadecimal ID (0x4270a80)");
      break;
    default: usage();
    }
  }
 
  argc -= optind;
  argv += optind;
 
  float brightness;
  if (action == ACTION_LIST) {
    if (argc > 0) usage();
  } else {
    if (argc != 1) usage();
 
    errno = 0;
    brightness = strtof(argv[0], NULL);
    if (errno == ERANGE)
      usage();
    if (brightness < 0 || brightness > 1)
      errexit("brightness must be between 0 and 1");
  }
 
  CGDirectDisplayID display[kMaxDisplays];
  CGDisplayCount numDisplays;
  CGDisplayErr err;
  err = CGGetActiveDisplayList(kMaxDisplays, display, &numDisplays);
  if (err != CGDisplayNoErr)
    errexit("cannot get list of displays (error %d)\n", err);
 
  CFWriteStreamRef stdoutStream = NULL;
  if (verbose) {
    CFURLRef devStdout =
      CFURLCreateWithFileSystemPath(NULL, CFSTR("/dev/stdout"),
				    kCFURLPOSIXPathStyle, false);
    stdoutStream = CFWriteStreamCreateWithFile(NULL, devStdout);
    if (stdoutStream == NULL)
      errexit("cannot create CFWriteStream for /dev/stdout");
    if (!CFWriteStreamOpen(stdoutStream))
      errexit("cannot open CFWriteStream for /dev/stdout");
  }								  
 
  for (CGDisplayCount i = 0; i < numDisplays; ++i) {
    CGDirectDisplayID dspy = display[i];
    CFDictionaryRef originalMode = CGDisplayCurrentMode(dspy);
    if (originalMode == NULL)
      continue;
 
    if (action == ACTION_LIST) {
      printf("display %d: ", i);
      if (CGMainDisplayID() == dspy)
	printf("main display, ");
      printf("ID 0x%x\n", (unsigned int)dspy);
      if (verbose) {
	CFStringRef error = NULL;
	CFPropertyListWriteToStream(originalMode, stdoutStream,
				    kCFPropertyListXMLFormat_v1_0, &error);
	if (error != NULL)
	  errexit("failed to write display info (%s)",
		  CFStringGetCStringPtr(error,
					CFStringGetFastestEncoding(error)));
      }
    }
 
    io_service_t service = CGDisplayIOServicePort(dspy);
    switch (action) {
    case ACTION_SET_ONE:
      if ((CGDirectDisplayID)displayToSet != dspy && displayToSet != i)
	continue;
    case ACTION_SET_ALL:
      err = IODisplaySetFloatParameter(service, kNilOptions, kDisplayBrightness,
				       brightness);
      if (err != kIOReturnSuccess) {
	fprintf(stderr,
		"%s: failed to set brightness of display 0x%x (error %d)",
		APP_NAME, (unsigned int)dspy, err);
	continue;
      }
      if (!verbose) continue;
    case ACTION_LIST:
      err = IODisplayGetFloatParameter(service, kNilOptions, kDisplayBrightness,
				       &brightness);
      if (err != kIOReturnSuccess) {
	fprintf(stderr,
		"%s: failed to get brightness of display 0x%x (error %d)",
		APP_NAME, (unsigned int)dspy, err);
	continue;
      }
      printf("display %d: brightness %f\n", i, brightness);
    }
  }
 
  return 0;
}

You can compile your own utility by saving this code to a file named brightness.c and doing:

gcc -std=c99 -o brightness brightness.c -framework IOKit -framework ApplicationServices

You can also download the precompiled binary.

You can create a login hook to automatically increase the brightness by chmoding the downloaded ‘brightness’ file to 755 and running the following command as root in Terminal:

defaults write com.apple.loginwindow LoginHook "/path/to/brightness 1"

7 Comments :, , more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Send me a message on AIM!

Friends

Read what I read...