Popular Posts

Sorry. No data so far.

Ben McCann

Co-founder of Connectifier.
Investor at C3 Ventures.
Google and CMU alum.

Ben McCann on LinkedIn Ben McCann on AngelList Ben McCann on Twitter

openSUSE 11.2 Setup and Review

11/23/2009

openSUSE is my favorite Linux distribution.  Linux in general has some usability frustrations as a desktop user, so I hope to share some of the ways they can be dealt with.  If you have questions of your own leave a comment.

Fix horrible bug that breaks buttons

GDK has a horrible debilitating bug that was not caught before release and at the time of writing the fix has not been backported as an online update.  This makes buttons in both Flash and Eclipse unresponsive to clicking.  You need to “export GDK_NATIVE_WINDOWS=true” in order for things to work correctly.  I added this in my ~/.bashrc file:

# .bashrc

# User specific aliases and functions
alias untargz="tar zxvf"

export GDK_NATIVE_WINDOWS=true
export PATH=/usr/local/eclipse/eclipse-3.5:$PATH

# Source global definitions
if [ -f /etc/bashrc ]; then
********. /etc/bashrc
fi

1-click installers – Setup graphics card, multimedia, and fonts

An easy way to install most of the software you need is to use a 1-click installer.  If you have an NVIDIA or ATI graphics card, then you’ll want to install the drivers using one of these installers.  I also recommend installing “Codecs pack for KDE”, “VLC Media Player”, and “Fonts with subpixel hinting enabled”.

Install Chrome

Download it from Google.

Setup multimedia

This is a perennial setup step on Linux distributions.  We’ll install the codecs needed to watch videos on Linux.

  1. YaST > “Software” > “Software Repositories”
  2. Click “Add”
  3. Select “Community Repositories”
  4. Select “Packman Repository” if it is not already
  5. YaST > “Software” > “Software Management”
  6. Install libxine1-codecs.

Setup time synchronization

NTP (Network Time Protocol) can be used to synch your system’s clock to a server on the internet.

  1. YaST > “System” > “Date and Time”
  2. Click “Change…”
  3. Select “Synchronize with NTP Server”
  4. Add the server for your region from pool.ntp.org (e.g. I used 0.us.pool.ntp.org since I’m in the United States)
  5. Check the “Save NTP Configuration”
  6. If you hit “Configure…” you can also add backup servers (e.g. 1.us.pool.ntp.org , 2.us.pool.ntp.org , etc.)

Setup a static IP address

This step is optional and is meant for people that know what a static IP is and want to set one up.  Having a static IP address is very nice when you want to remote desktop to your server or access it in some other way without worrying about what the IP address is.  There may also need to be some configuration done on your router for this one.  Or you may prefer to investigate DHCP reservations if your router supports them.

  1. YaST > “Network Devices” > “Network Settings”
  2. Under Hostname/DNS, you may change your hostname and Domain Name if you prefer
  3. Under Global Options, switch to “Traditional Method with ifup”
  4. Under “Overview”, select your network card and click “Edit”
  5. Enter your static IP (besure to also enter DNS and gateway information)
  6. Hit save

Setup a network file share (NFS) using Samba

Another optional step, Samba allows you to share files on your computer with others on the network.

  1. YaST > “Software” > “Software Management”
  2. Install “samba”
  3. YaST > “Network Services” > “Samba Server”
  4. Choose “Not a domain controller”, start during boot, and tell it to unblock the firewall
  5. Change sharing settings as you’d like and hit “Finish”
  6. Add a user to Samba by running “smbpasswd -a username” where username is the user you’d like to create.
  7. Connect from your Windows machine by right clicking “My Computer” and browsing your network.  If you have trouble connecting you might also try opening a “Run…” dialog off the start menu and typing in your IP address with two leading slashes e.g. “\\192.168.10.2”

Setup remote desktop through NX

The two main remote desktop softwares for Linux are VLC and NX.  NX is much faster and is what I would recommend.  Unfortunately, I have not been able to get desktop sharing to fully work.  If you get desktop shadowing to work properly then please let me know.  In addition to installing NX, we’ll also open the corresponding port in the firewall so that we can connect from another machine.

  1. Download the NX Linux packages
  2. Run “rpm -iv nxclient-3.4.0-5.x86_64.rpm”, “rpm -iv nxnode-3.4.0-5.x86_64.rpm”, and “rpm -iv nxserver-3.4.0-5.x86_64.rpm”
  3. Run “/usr/NX/scripts/setup/nxserver –install”
  4. Run “/usr/NX/bin/nxserver –keygen”
  5. In your NX client, open “Configure…” > “General” tab > “Key …”
  6. Copy the contents of “/usr/NX/share/keys/default.id_dsa.key” into the key window and save it
  7. Open “/usr/NX/etc/server.cfg”
  8. Uncomment ‘EnableSessionShadowingAuthorization = “1” and change the value to “0” which will enable you to select “Shadow” in the client under the General > Desktop if you’d like to do desktop sharing.
  9. YaST > “Security and Users” > “Firewall” > “Allowed Services”
  10. Allow “Secure Shell Server”

Upgrade to the ext4 file system

ext4 is the new default file system on openSUSE 11.2.  If you did a clean install, you will be running ext4 by default.  However, if you have a drive you did not reformat when installing the OS then you may be running ext3.  For example, I have two drives: 1 60 gig drive I use as my root partition and a 500 gig drive I use as my home directory.  When I installed openSUSE 11.2, I wiped the root partition and reformatted it as ext4, but I wanted to keep the data on my home directory, so I couldn’t reformat it and left it as ext3.

  1. Run “df -T” to see your file system types.  For me it showed /dev/sdb1 as ext4 mounted on /home
  2. Run init 1 to switch runlevels
  3. Unmount the drive:  e.g. “umount /home”
  4. Run e2fsck on the drive : e.g. e2fsck /dev/sdb1
  5. Run tune2fs: e.g. tune2fs -O extents,uninit_bg /dev/sdb1
  6. Edit /etc/fstab to change ext3 to ext4 on the drive
  7. Run “mount -a” to remount the drive

Review: The Problem with Linux is Usability and Resource Allocation

openSUSE is as good a Linux desktop as you’ll find.  Unfortunately that’s not saying as much as I’d like.  There are so many broken things on the system and yet so much effort was put into developing things that average person doesn’t give a rat’s ass about. There’s a whole load of crap that comes with the system that’s a waste.  It’s incredibly frustrating to me to see so many resources go into this software that few people care about.  I don’t need Marble when the far superior Google Earth is available on Linux.  I don’t need Kaffeine when VLC is a better alternative.  Most of the games are a waste and can’t hold a candle to the hundreds of Flash games available online.   I’ve never used digiKam, but have to assume that at best it’s Picasa‘s ugly stepsister.  There are dozens of programs I’d rather use than KDE PIM: GMail, Thunderbird, LinkedIn, etc.  The list goes on, and on, and on.  Why are we building this stuff?  The single biggest improvement in openSUSE 11.2 is that Firefox is now the default browser.  This took way too long, but is a welcomed change.  I wish VLC would replace Kaffeine.  Someone at Novell, Canonical, et. al. needs to do some user testing.  Any 12-year-old kid would tell you you’re crazy if you think people would rather use Marble than Google Earth.  Linux distros have done an absolutely horrifyingly awful job of picking the best software to be the default.  Instead of wasting all this time, how about we come together and decide to make an operating system that just works?  There are so many usability frustrations that I’d like to see solved instead.  Novell, Canonical, and the other leaders in this area need to step up.

As mentioned, there are a lot of usability problems.  For example, Flash was unusable in full screen mode after install.  It turned out this was because I hadn’t yet installed my NVIDIA driver.  But this is a big problem.  How would any casual user know they had to do this?  My parents, brother, or sister would not have known to do this despite being reasonably computer savvy.  I knew because I’ve used Linux for many years, but if it requires a computer science degree to watch a YouTube video then you’ve failed.  And when I did realize I needed to install the driver, I needed to know which of three drivers I wanted.  Are you serious?  I could just imagine asking my mom what graphics card she has.  That would be a fun conversation.  It’s 2009.  And you don’t have the ability to detect my hardware?  I understand that there are licensing issues, but once I’ve said I want to install a graphics driver you should be able to tell me which one I need.  I want to get rid of the “Recently Used” option on the Kicker menu like I can with classic, but there’s no option to.  I don’t understand why YaST has a “Media Check” option.  Can’t you tell there’s no CD/DVD in my drive?  I tried to edit my network settings with YaST and it told me to use NetworkManager or change the setup method to Traditional with ifup.  How do I do either of those things?  I don’t know what NetworkManager is or how to open it.  There’s nothing in any of the menus called NetworkManager.  When I started Firefox it asked me if I wanted to use Flash, gnash, or swfdec.  But I tried gnash and swfdec and neither could play a Hulu video, so are you insane?  Of course I don’t want to use either of those.  Why are you confusing me?  Flash on Linux is a big problem.  The controls on the Hulu just stop working with frustrating frequency.  I can’t figure out why Amarok and Kaffeine are both broken.  I could go on, but you get my point.  Let’s fix these problems instead of building more crap no one asked for.  I know how much of this work has been done by volunteers and am extremely grateful for it.  I’ve contributed to several open source projects myself and know what it’s like, so I hope those reading know I am thankful to have this amazing free software.  I’m happy for what’s been done and am hoping the leaders of KDE and openSUSE will make some hard choices about what’s worth investing in and supporting, so that these projects can become successful in the mainstream world because as it stands now, even as great as it is, Linux simply isn’t ready.

Looking to register some domains for your website?  Get a free domain with your Network Solutions hosting package.

Case Study: Usable and Unusable APIs

07/25/2009

It was the best of times, it was the worst of times…

It was the age of wisdom, it was the season of light.  A great library called dom4j was written with its users in mind.  It included a quick start guide and a cookbook for people that actually wanted to get things done.  Converting a document to a String took 15 characters: document.asXML().  But there were too many competing XML parsing implementations, so a standard was created.  And sadly, dom4j has not been updated to adhere to that standard.

It was the age of foolishness, it was the epoch of incredulity.  15 characters to turn a document into a string?  That is far too few.  What will we tell our managers when they ask how many lines of code we have written?  We have a better way and it is called Xerces:

import java.io.StringWriter;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Node;

public final class XmlUtil {

  private static final TransformerFactory factory = TransformerFactory.newInstance();

  public static String toString(Node node) {
    if (node == null) {
      return null;
    }
    try {
      Source source = new DOMSource(node);
      StringWriter stringWriter = new StringWriter();
      Result result = new StreamResult(stringWriter);
      Transformer transformer = factory.newTransformer();
      transformer.transform(source, result);
      return stringWriter.getBuffer().toString();
    } catch (TransformerConfigurationException e) {
      e.printStackTrace();
    } catch (TransformerException e) {
      e.printStackTrace();
    }
    return null;
  }

}

Sample log4j.properties file

07/18/2009

I always find the hardest part of getting started with log4j is creating a log4j.properties file. For that reason, I’ve posted an example below. This file configures log4j to log any messages of level info or higher to the console except for classes under the com.dappit.Dapper.parser or org.w3c.tidy packages.

#------------------------------------------------------------------------------
#
#  The following properties set the logging levels and log appender.  The
#  log4j.rootCategory variable defines the default log level and one or more
#  appenders.  For the console, use 'S'.  For the daily rolling file, use 'R'.
#  For an HTML formatted log, use 'H'.
#
#  To override the default (rootCategory) log level, define a property of the
#  form (see below for available values):
#
#        log4j.logger. =
#
#    Available logger names:
#      TODO
#
#    Possible Log Levels:
#      FATAL, ERROR, WARN, INFO, DEBUG
#
#------------------------------------------------------------------------------
log4j.rootCategory=INFO, S

log4j.logger.com.dappit.Dapper.parser=ERROR
log4j.logger.org.w3c.tidy=FATAL

#------------------------------------------------------------------------------
#
#  The following properties configure the console (stdout) appender.
#  See http://logging.apache.org/log4j/docs/api/index.html for details.
#
#------------------------------------------------------------------------------
log4j.appender.S = org.apache.log4j.ConsoleAppender
log4j.appender.S.layout = org.apache.log4j.PatternLayout
log4j.appender.S.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} %c{1} [%p] %m%n

#------------------------------------------------------------------------------
#
#  The following properties configure the Daily Rolling File appender.
#  See http://logging.apache.org/log4j/docs/api/index.html for details.
#
#------------------------------------------------------------------------------
log4j.appender.R = org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File = logs/bensApps.log
log4j.appender.R.Append = true
log4j.appender.R.DatePattern = '.'yyy-MM-dd
log4j.appender.R.layout = org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} %c{1} [%p] %m%n

#------------------------------------------------------------------------------
#
#  The following properties configure the Rolling File appender in HTML.
#  See http://logging.apache.org/log4j/docs/api/index.html for details.
#
#------------------------------------------------------------------------------
log4j.appender.H = org.apache.log4j.RollingFileAppender
log4j.appender.H.File = logs/bensApps.html
log4j.appender.H.MaxFileSize = 100KB
log4j.appender.H.Append = false
log4j.appender.H.layout = org.apache.log4j.HTMLLayout

Printing a Stack Trace anywhere in Java

07/03/2009

You don’t need to catch an Exception in order to print a stack trace in Java.  Sometimes they can be helpful for debugging and logging purposes.  Here’s an example of how to print a stack trace at any moment:

new Exception().printStackTrace();

If you want more control over the output, you can build some code off the following:

  System.out.println("Printing stack trace:");
  StackTraceElement[] elements = Thread.currentThread().getStackTrace();
  for (int i = 1; i < elements.length; i++) {
    StackTraceElement s = elements[i];
    System.out.println("\tat " + s.getClassName() + "." + s.getMethodName()
        + "(" + s.getFileName() + ":" + s.getLineNumber() + ")");
  }

Getting Started with Tonido on OpenSUSE 11.1

06/25/2009

I’d heard of Tonido awhile back, but was having trouble getting it to run on OpenSUSE since it’s packaged only for Ubuntu.  Tonight I sat down and figured out how to get it to run:

  • Install alien via the YaST package manager
  • Convert the Tonido package to an RPM by using alien (alien -r filename.deb)
  • Install newly created Tonido RPM
  • Install libnotify1-32bit via YaST package manager
  • Open port 10001 in Firewall (Security and Users > Firewall > Allowed Services > Advanced)
  • Port forward port 10001 to the machine where Tonido is installed

Yay, now you can run Tonido.  When you start it, it will open Konqueror, for which it is very buggy.  So close that window and open http://127.0.0.1:10001/ in FireFox.  Now you’re off and running.

My initial thoughts:

  • This needs SSL support to really be useful since it gives access to my whole computer.
  • Too bad the setup is a bit hard.  I’m sure more people would adopt it if it used UPnP.
  • The WebShare app could be pretty cool in the future, but at the moment it’s mostly worthless.  You can only download one file at a time and there’s no upload.  I’d like to be able to mount my shares on my Windows machine.  I really wish it exported them via WebDav or SFTP.
  • The music player needs flac support.  I can’t play any of my music collection!

Determining Port Usage

05/18/2009

Want to know how to figure out what’s running on a given port on your machine?  The following example will show you what’s running on port 80 on your Linux machine:

lsof -i -n -P | grep :80

Maven on Eclipse Tutorial

04/12/2009

Install Java and Maven

First off, make sure you have a Java JDK installed and that your JAVA_HOME environment variable points to it. You can check by typing “echo %JAVA_HOME%” in Windows or “echo $JAVA_HOME” in Linux. You’ll next want to download and install Maven by following the directions on their website.  Once Maven is installed, you’ll want to create a settings.xml file in your .m2 directory, which is located at ~/.m2 in Linux or C:\Documents and Settings\%USER%\.m2 on Windows.  You can do this by copying the settings.xml file from the directory where Maven in installed to you .m2 directory.

Install m2eclipse

You’ll want to make sure your Eclipse installation is pointing at your JDK.  You can check by going to Window > Preferences > Java > Installed JREs.  You’ll also want to set the -vm flag in your eclipse.ini file which is located at the root of your Eclipse installation.  Here’s what my file looks like:

-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
256M
-framework
plugins\org.eclipse.osgi_3.4.0.v20080605-1900.jar
-vm
C:\Program Files\Java\jdk1.6.0_11\bin\javaw.exe
-vmargs
-Dosgi.requiredJavaVersion=1.5
-Xms40m
-Xmx512m

Finally, you get to install m2eclipse by opening up Eclipse and selecting Help > Software Updates… > Available Software > Add Site…  Then enter http://m2eclipse.sonatype.org/sites/m2e, check the newly added boxes, and press Install.

Create Your First Maven Project

Now for the fun.  You can create a Maven project in Eclipse by selecting New > Project… > Maven > Maven Project.  Check “Create a simple project” on the first screen and hit Next.  Enter the Group Id, Artifact Id, and Name.  For example, “com.benmccann.robot”, “window-robot”, “Window Robot”.  Now, at long last, you can do some actual programming.

Add Dependencies

It won’t be long before you’ll want to add dependancies.  Open the Maven Indexes View by selecting Window > Show View > Other… > Maven > Maven Indexes.  You’ll want to make sure you have the Maven Central Repository, so right-click the view and choose “Add Index”.  Enter http://repo1.maven.org/maven2/ for the Repository URL and hit Retrieve to fill in the Repository Id of central.  Now you can right-click the project and choose Maven > Add Dependancy.  We’ll add jUnit since you’ll probably want it anyway.  Type junit and you should see it populated into the box below.  Use the dropdown at the bottom to set a scope of “test” and hit OK.

How to use the Linux find command

04/01/2009

I always have trouble remembering how to use the find command in Linux, so here are a few examples.

Finding all hidden files:

find . -regex '.*/\..*'

Deleting all Java files:

rm -rf `find . -name *.java`

Deleting all directories named .svn:

rm -rf `find . -type d -name .svn`

Recursively set permissions for a web server:

chmod -R a+r ~/www
find ~/www -type d -exec chmod a+x {} \;

Finding all exectuable files:

find . -executable -type f

Extracting AMR Audio from Android 3GP Files

03/18/2009

The Android MediaRecorder currently records audio in AMR format and stores that within a 3GP container which provides metadata for the recording. Thanks to Sebastian Annies at Core Media it is possible to extract the AMR audio from the 3GP file using isobox4j. If you can’t play .amr files on your Windows machine, then I suggest K-Lite Codec Pack.

package com.benmccann.audio;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;

import com.coremedia.iso.FileRandomAccessDataSource;
import com.coremedia.iso.IsoFile;
import com.coremedia.iso.IsoOutputStream;
import com.coremedia.iso.mdta.Sample;

public class ThreegpReader {

  private final static int ANDROID_AUDIO_TRACK_NUM = 3;
  
  private final File inputFile;
  
  public ThreegpReader(File file) throws FileNotFoundException {
    this.inputFile = file;
  }
 
  public void extractAmr(OutputStream outputStream) throws IOException {
    IsoFile iso = new IsoFile(new FileRandomAccessDataSource(inputFile));
    iso.parse();
    iso.parseMdats();
    
    IsoOutputStream isoOutput = new IsoOutputStream(outputStream, false);

    // write an AMR header
    isoOutput.write(new byte[] {0x23, 0x21, 0x41, 0x4d, 0x52, 0x0a});
    
    // write the audio content
    for (Sample sample : iso.getTrack(ANDROID_AUDIO_TRACK_NUM)) {
      sample.getContent(isoOutput);
    }
    isoOutput.flush();
    isoOutput.close();
  }
  
}

Android Audio Recording Tutorial

03/11/2009

After many hours of trying to record audio on my Google Android device, I’ve finally arrived at a workable solution.  There were a few bumps along the way besides the horribly out of date MediaRecorder documentation, which was sorely lacking details.  For one, I could only get audio to record to the SD card.  Additionally, the directory being recorded to must already exist before attempting to record to it. Without further ado, here is a complete example for recording audio on the Android via the MediaRecorder API:


package com.benmccann.android.hello;

import java.io.File;
import java.io.IOException;

import android.media.MediaRecorder;
import android.os.Environment;

/**
 * @author <a href="http://www.benmccann.com">Ben McCann</a>
 */
public class AudioRecorder {

  final MediaRecorder recorder = new MediaRecorder();
  final String path;

  /**
   * Creates a new audio recording at the given path (relative to root of SD card).
   */
  public AudioRecorder(String path) {
    this.path = sanitizePath(path);
  }

  private String sanitizePath(String path) {
    if (!path.startsWith("/")) {
      path = "/" + path;
    }
    if (!path.contains(".")) {
      path += ".3gp";
    }
    return Environment.getExternalStorageDirectory().getAbsolutePath() + path;
  }

  /**
   * Starts a new recording.
   */
  public void start() throws IOException {
    String state = android.os.Environment.getExternalStorageState();
    if(!state.equals(android.os.Environment.MEDIA_MOUNTED))  {
        throw new IOException("SD Card is not mounted.  It is " + state + ".");
    }

    // make sure the directory we plan to store the recording in exists
    File directory = new File(path).getParentFile();
    if (!directory.exists() && !directory.mkdirs()) {
      throw new IOException("Path to file could not be created.");
    }

    recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    recorder.setOutputFile(path);
    recorder.prepare();
    recorder.start();
  }

  /**
   * Stops a recording that has been previously started.
   */
  public void stop() throws IOException {
    recorder.stop();
    recorder.release();
  }

}
Newer Posts
Older Posts