Forgot your password?
typodupeerror
User Journal

Journal: Missing: Clipboard Swap

Journal by jomama717

We are all very familiar with the ctrl-x/ctrl-c/ctrl-v cut/copy/paste functionality (s/ctrl/open-apple/ to be (non?)PC) but we are missing one: swap. There have been hundreds of times when the ability to hit a simple combination keystroke to simultaneously copy the selected text to the clipboard and paste the previous contents of the clipboard over the selected area would have been a huge help. I'm sure this can be done in various apps using macros, but a swap functionality with the same cross-app status that cut/copy/paste enjoy would be nice.

User Journal

Journal: Battling "Terminal Obesity" 2

Journal by jomama717
Like many fellow IT professionals I struggle against the inevitable weight gain that comes with hours of sitting in front of a terminal with little time left over to hit the gym. It all comes down to calories - typing doesn't go a long way towards burning them, so I've come up with a few simple changes I can make in my routine to cut down the intake:
  1. Eat slow, eat less

    As a Subway fiend I did an experiment: rather than inhaling a footlong in 15 minutes, I tried slowly eating a six inch sub over the course of a half an hour. Eureka! At the end of the half hour I was completely stuffed (as opposed to ludicrously stuffed), and on half of the calories to boot. One tip - make it a point to actually put down whatever you are eating after every bite - you may be surprised how much that slows you down.

  2. Take the stairs

    May not sound like much, but I was shocked to discover that walking up 4 flights of stairs instead of taking the elevator actually winded me. To me this indicated two things: (1) I was grossly out of shape, and (2) that effort must have burned a few calories. Elevator be damned.

  3. Resist the dish

    As the pounds pile up, what once was an added bonus in the workplace - the abundance of candy dishes and snack machines - becomes a constant temptation. A little bit of self discipline goes a long way (6 tootsie rolls have 140 calories!!!) If the need to snack is firmly entrenched, bring your own - almonds and popcorn flavored rice cakes are my personal favorites. Moderation is still the key - an ounce of almonds (20-25) has as many calories as the six tootsie rolls (but won't leave you hungry for more in 10 minutes).

  4. Take a hike

    When I'm wrestling with a tricky problem or design detail, I have always found it beneficial to get away from my desk for a while. This used to mean hitting the snack room - using this "brain time" as an excuse to eat even more. Now I leave the building altogether and walk a few laps around it. Not only am I getting some exercise, but the fresh air seems to stoke the fire a bit. It's snowing you say? Get some snow shoes. Why not?

  5. Water is good - and free!

    Drinking water every day is such a simple thing, but goes a long way towards shedding the lbs. I used to drink Coke straight up (~5 a day to the tune of 755 calories) until I switched to diet. Sure, diet coke has no calories, but what exactly does it have? Now I drink water: no calories, free, and alll natural baby.

It's still a struggle, and I still have to work at these rules every day, but I think I've at least stopped the bleeding. I'd love to hear other ideas people have come up with in the interest of avoiding out of control weight gain in the IT workplace, and I hope at least one person out there gives some of these ideas a try.

Java

Journal: Java Trie Implementation

Journal by jomama717
/******************************************
* The three classes below implement a    *
* "Trie" structure in java.  My favorite *
* application of this structure is a     *
* streaming keyword replacer where a     *
* keywords can be compared one character *
* at a time as a stream is read.  Enjoy! *
******************************************/

/**************
* LookupTree *
**************/

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.util.Iterator;

/**
* A collection of LookupTreeNodes that represents a list of words
* layed out in such a way that incremental lookup by letter is convenient.
*/
public class LookupTree
{
  private LookupTreeNode mRootNode = new LookupTreeNode();

  public void addWord(String word)
  {
    LookupTreeNode nodeIter = mRootNode, tempIter = null;
    char currentChar = (char)0;

    for(int i = 0; i < word.length(); i++)
    {
      currentChar = word.charAt(i);

      if( (tempIter = nodeIter.getNodeForLetter(currentChar)) == null )
      {
        nodeIter = nodeIter.addLetter( currentChar, false );
      }
      else
      {
        nodeIter = tempIter;
      }
    }

    if( nodeIter.getIsWord() )
    {
      System.out.println( "Word: " + word + " already exists in table" );
    }
    else
    {
      nodeIter.setIsWord(true);
    }
  }

  /**
   * Given a file containing a list or words seperated by newlines fill up the
   * tree with those words.
   * @param fileName The name of the file to read words from.
   */
  public void loadWordsFromFile(String fileName)
  {
    String tempStr = null;
    File inFile = null;
    BufferedReader br = null;

    try
    {
      inFile = new File(fileName);

      br = new BufferedReader(
            new InputStreamReader(
             new FileInputStream(inFile)));

    }
    catch(FileNotFoundException fe)
    {
      System.out.println( fe.toString() );
      return;
    }

    try
    {
      while( (tempStr = br.readLine()) != null )
      {
        this.addWord( tempStr );
      }
    }
    catch(IOException ioe)
    {
      System.out.println( ioe.toString() );
    }
  }

  /**
   * Given String return true if the word is in the tree, false otherwise.
   * @param word The word to check the existence of.
   * @returns boolean true if the word is in the tree, false otherwise.
   */
  public boolean wordExists( String word )
  {
    LookupTreeNode nodeIter = mRootNode;
    boolean returnVal = false;
    char currentChar = (char)0;

    for( int i = 0; i < word.length(); i++)
    {
      currentChar = word.charAt(i);
      nodeIter = nodeIter.getNodeForLetter(currentChar);
      if( nodeIter == null )
      {
        break;
      }
    }

    if( nodeIter != null && nodeIter.getIsWord() )
    {
      returnVal = true;
    }

    return returnVal;
  }

  /**
   * Walk the table and perform an action on each word. Order is not guaranteed.
   * @param node The node to start from.
   * @param currWord The starting String, used for recursion
   * @param action A method in the form void action(String arg) to be performed on each string found
   */
  private void walkTable(LookupTreeNode node, String currWord, Method action)
  {
    Iterator iter = node.getLetterIterator();
    LookupTreeNode nextNode = null;
    Object [] arg = new Object[1];
    StringBuffer currentWord = new StringBuffer(currWord);
    currentWord.setLength( currWord.length() + 1 );
    char currentChar = (char)0;

    while( iter.hasNext() )
    {
      currentChar = ((Character)(iter.next())).charValue();
      currentWord.setCharAt(currWord.length(), currentChar);
      nextNode = node.getNodeForLetter( currentChar );
      if( nextNode.getIsWord() )
      {
        arg[0] = currentWord.toString();
        if( action != null && this.validateActionMethod( action ) )
        {
          try
          {
            action.invoke( this, arg );
          }
          catch( Exception e )
          {
            System.out.println( "Error while trying to execute method: " + action.toString() +
                                ": " + e.toString() );
          }
        }
        else
        {
          System.out.println( "Action method null or invalid" );
        }
      }

      this.walkTable( nextNode, currentWord.toString(), action );
    }
  }

  /**
   * Make sure that the method passed as action to the walker is of the right format.
   */
  private boolean validateActionMethod( Method action )
  {
    Class [] params = action.getParameterTypes();
    boolean returnVal = true;

    try
    {
      if( params.length != 1 || !params[0].equals(Class.forName("java.lang.String")) )
      {
        returnVal = false;
      }
    }
    catch( Exception e )
    {
      System.out.println( "Invalid class for parameter found" );
      returnVal = false;
    }

    return returnVal;
  }

  /**
   * Walk the tree and print each word
   */
  public void printTable()
  {
    try
    {
      this.walkTable( mRootNode, new String(), this.getActionMethodFromName( "printWord" ) );
    }
    catch(Exception e)
    {
      System.out.println( e.toString() );
    }
  }

  protected void printWord( String arg )
  {
    System.out.println( arg );
  }

  /**
   * utility for retrieving the Method object from the method name from *this* class
   */
  private Method getActionMethodFromName( String funcName )
  {
    Method returnMethod = null;

    try
    {
      Class [] params = { new String().getClass() };
      returnMethod = this.getClass().getDeclaredMethod( funcName, params );
    }
    catch( Exception e )
    {
      System.out.println( "Warning - returning null method: " + e.toString() );
    }

    return returnMethod;
  }

  /**
   * Return an iterator that can be used to incrementally (letter by letter)
   * check if a word exists in the list.
   */
  public LookupTreeIterator getIterator()
  {
    return new LookupTreeIterator(mRootNode);
  }

  /**
   * Return an iterator that can be used to incrementally (letter by letter)
   * check if a word exists in the list.
   */
  public boolean isRootChar( char c)
  {
    return mRootNode.containsLetter( c );
  }

  public static void main( String [] args )
  {
    try
    {
      LookupTree LT = new LookupTree();
      LT.loadWordsFromFile("dictionary.txt");
      LT.printTable();

      BufferedReader stdReader = new BufferedReader(
                                 new InputStreamReader( System.in ));

      String tempStr = null;

      while(true)
      {
        System.out.print("Enter a word to lookup, or \"quit\" to quit: ");
        tempStr = stdReader.readLine();
        if(tempStr.equals("quit") )
        {
          break;
        }
        else
        {
          System.out.println( LT.wordExists( tempStr ) );
        }
      }
    }
    catch(Exception e)
    {
      e.printStackTrace();
      System.out.println( e.toString() );
    }
  }

}

/******************
* LookupTreeNode *
******************/

import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

/**
* Represents one node of a tree class that makes
* incremental word-lookup easy.
*/
public class LookupTreeNode
{
  //true when the word ending with the letter that is this
  //TreeNode's key is a complete word.
  private boolean isWord = false;
  private HashMap letterMap = new HashMap();

  public LookupTreeNode() {}

  /**
   * Returns an iterator over the set of keys in this Node.
   * The set of keys is the set of letters represented at this
   * level of the tree.
   * @returns Iterator The keySet iterator
   */
  public Iterator getLetterIterator()
  {
    return letterMap.keySet().iterator();
  }

  /**
   * Returns the Set of keys int his Node.  The keys represent
   * the letters represented at this level of the tree.
   * returns Set The set of letters in this Node.
   */
  public Set getLetterSet()
  {
    return letterMap.keySet();
  }
  /**
   * Returns the Set of keys int his Node.  The keys represent
   * the letters represented at this level of the tree.
   * returns Set The set of letters in this Node.
   */

  public boolean containsLetter( char c )
  {
    return letterMap.containsKey(new Character(c));
  }

  /**
   * Adds a new letter at this level, and returns the corresponding
   * Node that is created.
   * @param c The letter to be added
   * @param isword If true, the isWord flag will be set for true in the returned Node,
   *        indicating that the added letter completed a word.
   * @returns LookupTreeNode The added node.
   */
  public LookupTreeNode addLetter(char c, boolean isword)
  {
    LookupTreeNode newNode = new LookupTreeNode();

    letterMap.put(new Character(c), newNode);

    return newNode;
  }

  public boolean getIsWord() { return this.isWord; }
  public void setIsWord( boolean isword ) { isWord = isword; }

  /**
   * See if this node contains some letter c.  If it does, return the letter's
   * corresponding node.
   * @param c The letter to look up
   * @returns LookupTreeNode the Node corresponding to the letter c, or null
   */
  public LookupTreeNode getNodeForLetter(char c)
  {
    return (LookupTreeNode)letterMap.get(new Character(c));
  }
}

/**********************
* LookupTreeIterator *
**********************/

import java.util.Set;

/**
  * The iterator class.  Maintains state and can be reset.
  */
public class LookupTreeIterator
{
   private final int BUFFER_SIZE     = 1024;
   private LookupTreeNode mInitialTreeNode = null;
   private LookupTreeNode mCurrentTreeNode = null;
   private Set mCurrentNodeKeys      = null;
   private char [] mCurrentWord      = null;
   private int mCurrentWordCount     = 0;
   private boolean mValidState       = true;
   private boolean mIsWord           = false;

   /**
    * Start at node rootNode, initialize word buffer, set initial node for reset later.
    */
   public LookupTreeIterator( LookupTreeNode rootNode )
   {
     mCurrentTreeNode  = mInitialTreeNode = rootNode;
     mCurrentNodeKeys  = mCurrentTreeNode.getLetterSet();
     mCurrentWord      = new char [ BUFFER_SIZE ];
     mCurrentWordCount = 0;
   }

   /**
    * See if the character c exists at the iterator's current location in the tree.
    */
   public boolean tryCharacter( char c )
   {
     boolean returnVal = false;
     mCurrentWord[ mCurrentWordCount++ ] = c;
     if( mCurrentNodeKeys.contains( new Character(c) ) )
     {
       returnVal = true;
       gotoNextNode(c);
     }
     else
     {
       mValidState = false;
       mIsWord = false;
     }
     return returnVal;
   }

   /**
    * Iterate to the next letter, only called if that letter exists.
    */
   private void gotoNextNode( char c )
   {
     mCurrentTreeNode = mCurrentTreeNode.getNodeForLetter(c);
     mCurrentNodeKeys = mCurrentTreeNode.getLetterSet();
     mIsWord = mCurrentTreeNode.getIsWord();
   }

   /**
    * Get the current buffer containing all looked up letters, including any that didn't exist.
    */
   public String getCurrentBuffer()
   {
     //MJM return mCurrentWord.toString();
     return new String( mCurrentWord, 0, mCurrentWordCount );
   }

   /**
    * Is the word currently held in the buffer a complete word in the tree?
    */
   public boolean isWord()
   {
     return mIsWord;
   }

   /**
    * Is the iterator currently in a valid state?  i.e. did the last letter checked exist,
    * meaning that what is currently in the buffer can be traced in through the tree?
    */
   public boolean isValid()
   {
     return mValidState;
   }

   /**
    * Reset the iterator
    */
   public void reset()
   {
     mCurrentTreeNode = mInitialTreeNode;
     mCurrentNodeKeys = mCurrentTreeNode.getLetterSet();
     mCurrentWordCount = 0;
     mValidState = true;
   }

}
User Journal

Journal: How a Macbook Saved My Marriage 2

Journal by jomama717
Ok, the subject is a gross exaggeration, but check this out:

My wife of close to a year has a macbook that I rarely use but am increasingly intrigued by. Out of the blue I get a business trip to London for one week (we live in Chicago), where my wife's brother lives. She would love to come with me but alas her passport is in limbo. Why? She is having her last name changed to mine...DOH! Feeling bad about all of this I devise a plan to leave cards hidden around the house that contain riddles that divulge the location of a small present, one each day while I am away. The only problem - how to indicate the location of the clue cards, which are themselves hidden? I thought about email, but decided I would probably be too busy to remember every morning, and the time difference would be tricky. A phone call is no good because she would use her jedi mind control powers to bypass the clues and get straight to the present. Maybe an automated daily event of some kind...? After some thinking I come up with a simple file/shell script combination that I leave on her laptop:

The file (clues.txt) is a text file with a line for each day/clue that starts with the date followed by a colon, e.g. "Mar_19:<the riddle>".

An example riddle/clue is:
"From where I sit from daybreak to close, right under this is under my nose" (I do development work full time from home, and the card was under my keyboard)

The script:

CLUES=/some/obscure/path/clues.txt
cluekey=`date | tr -s '[:space:]' | cut -d" " -f2,3 | tr ' ' '_'`;
clue=`cat "$CLUES" | grep "$cluekey" | cut -d":" -f2`

if [ "X$clue" = "X" ]; then
echo "No clue today!";
else
echo $clue
fi

Simple enough - now for the really cool part - the Macbook has a feature that I stumble across called "automator" which is basically a workflow engine that uses as tasks various actions from various applications on the computer. One of these actions is "Run Shell Script" - which takes text input and gives text output. Another workflow task is "Text to Speech", which takes text as input and "speaks" the text as output. I create a simple 2 step workflow of my script and the text to speech piece, and then the automator allows me to save the workflow as an application on the desktop! I save the workflow as "GetTodaysClue" and stick it right in the middle of her desktop. Before I leave to catch my flight on Friday I leave some flowers and a card that points out the curious new icon on her desktop, and the game is afoot. The clue automatically changes each day and is spoken as many time as my wife needs to hear it before the next day - brilliant!

The whole plan was a huge hit, and I gained a great deal of respect for the mac - so much so that I plan on buying one when my PC dies.

Movies

Journal: "Golden Ass" Anime

Journal by jomama717
I recently read the ancient story The Golden Ass written by Apuleius and was blown away by the imagery and wild storyline it contained. It soon after occured to me what a great movie it would make, although due to some of the racy subject matter in it it might be better served by an animated movie along the lines of Princess Mononoke or even Fire and Ice . I'm not holding my breath - but man would that be cool!
Unix

Journal: More useful shell functions

Journal by jomama717
Here are some more shell functions that I have found to be extremely useful in a development environment.  Most are made obsolete by using an IDE, but there are always cases where you get stuck in a console writing code.

#
#C/C++ source recursive find: recfind <search_string>
#
function recfind {
    find . -name "*.[ch]*" -print | xargs grep -n "$1";
} 2>/dev/null

#
#Java source recursive find: jrecfind <search_string>
#
function jrecfind {
    find . -name "*.java" -print | xargs egrep -n "$1";
} 2>/dev/null

#
#Generic recursive find: grecfind [<filespec>] <search_string>
#
function grecfind {
    if [ $# -eq 1 ]; then
        findStr=${1};
        fileSpec=*;
    else
        findStr=${2};
        fileSpec=${1};
    fi

    find . -name "${fileSpec}" -print | xargs grep -n ${findStr};
} 2>/dev/null

#
#Find a java class in a deployed application environment: findClass <classname>
#
function findClass {
  echo "Looking in jars..."
  for jarfile in `find . -name "*.jar" -print`; do
    FOUND=(`jar tf $jarfile | grep "$1"`);
    if [ ! -z ${FOUND[0]} ]; then
      echo "Found in $jarfile:";
      for found in ${FOUND[@]}; do
        echo "$found";
      done
    fi
  done
  echo "...done.  Looking on filesystem..."
  find . -name "*$1*.class" -print
  echo "...done."
} 2>/dev/null

Unix

Journal: Bash "cd" wrapper 4

Journal by jomama717
Below is some bash script I wrote years ago that allows you to "anchor" up to 5 directories for fast access later by entering the command "cd [1-5]".  You can assign a number to the current directory by typing "cd -s [1-5]", and dump the current assignments with "cd -p".  Aside from these new options cd operates as normal (unless you have directories named 1,2,3,4, or 5).  There is also a "dir_persist" function that saves off the current set of anchors under a given tag and can be loaded up after a subsequent login.  I find that this simple change allows me to navigate a large source repository much faster than before (no more cd ../../../../../../../other_component).  Note that this is the "cygwinized" version, which should run on unix but I've never tried it.  I originally only used it only on unix machines, and had to jump through some hoops to handle directories with spaces in the names on cygwin.

CD_USAGE="cd: Usage: cd [ -s [ 1-5 | [1-5]=<directory> ] | -p | <directory name> | [1-5] ]";

function dir_persist {
     DIRSTRINGS="ONE_DC TWO_DC THREE_DC FOUR_DC FIVE_DC";
    _DIRSTRINGS=($DIRSTRINGS);

    if [ $# -eq 0 ]; then
      echo -n "Enter a name to persist dirs under, or <enter> to skip: "
      read session_tag
    else
      session_tag=${1}
    fi

    if [ "${session_tag}" = "" ]; then
        CDFILE_NAME=".cdfile_${HOSTNAME}_default"
    else
        CDFILE_NAME=".cdfile_${HOSTNAME}_${session_tag}"
    fi

    let count=0;
    while [ $count -lt 5 ] ; do
      outp=`env | grep "${_DIRSTRINGS[$count]}"`;
      if [ "" != "$outp" ] ; then
        dir_to_print=`echo $outp | cut -d"=" -f2`;
        let num=count+1;
        if [ $count -eq 0 ] ; then
            echo "$num=$dir_to_print" > ~/${CDFILE_NAME};
        else
            echo "$num=$dir_to_print" >> ~/${CDFILE_NAME};
        fi
      fi
      let count=count+1;
    done
}

function dirset {
     DIRSTRINGS="ONE_DC TWO_DC THREE_DC FOUR_DC FIVE_DC";
    _DIRSTRINGS=($DIRSTRINGS);
let err=0;

if [ "$#" -ge 2 ] || [ "$#" -eq 0 ] ; then
   let err=1;
fi
if [ -z `echo "$1" | grep "="` ] ; then
    let reg=$1;
    let pwd_flag=1;
else
    let reg=`echo "$1" | cut -d"=" -f1`;
    dir=`echo "$1" | cut -d"=" -f2 | tr '~' ' '`;
    let pwd_flag=0;
fi

if [ $reg -gt 5 ] || [ $reg -eq 0 ] ; then
   echo >&2 "cd: Invalid directory choice";
   let err=1;
fi
if [ $err -eq 0 ] ; then
    let reg=reg-1;
    if [ $pwd_flag -eq 1 ] ; then
        littlePWD="${PWD}"
        export "${_DIRSTRINGS[$reg]}=${littlePWD}";
    else
        littleDir="${dir}"
        export "${_DIRSTRINGS[$reg]}=${littleDir}";
    fi
fi
}

function cd {
  DIRSTRINGS="ONE_DC TWO_DC THREE_DC FOUR_DC FIVE_DC"
  _DIRSTRINGS=($DIRSTRINGS)
  let err=0

case $# in
0)
    command cd
     return
;;
1)
    if [ "$1" = "-p" ] ; then
      let count=0
       while [ "$count" -lt 5 ] ; do
         outp=`env | grep "${_DIRSTRINGS[$count]}"`
         if [ "" != "$outp" ] ; then
           dir_to_print=`echo $outp | cut -d"=" -f2`
           let num=count+1
           echo "$num) $dir_to_print"
         fi
         let count=count+1
       done
     elif [ "$1" = 1 -o "$1" = 2 -o "$1" = 3 -o "$1" = 4 -o "$1" = 5 ] ; then
      let choice=$1
      let choice=choice-1
      _CD_STRING="\$${_DIRSTRINGS[$choice]}"
      CD_STRING=`eval echo "${_CD_STRING}"`
      command cd "${CD_STRING}"
     else
      command cd "${1}"
      return
     fi
;;
2)
    teststr=`echo $1 | grep "\-s"`
   if [ -z "$teststr" ] ; then
      echo >&2 "$CD_USAGE"
      let err=1
      return
   fi
      dirset "$2"
;;
*)
     echo >&2 "$CD_USAGE"
     let err=1
     return
;;
esac

}
Puzzle Games (Games)

Journal: "Text Twist" cheating code

Journal by jomama717

UPDATE:

If anyone cares (HA!) I noticed recently that TextTwist 2 came out, so I downloaded it and sure enough they are using the same crazy flat file representation of a trie that they used in the first version (see below), I just had to tweak the code to allow 15 letter words and expand the result table size. Change:

#define MAX_WORD_LEN 7
#define RESULT_TABLE_SIZE 64

to:

#define MAX_WORD_LEN 15
#define RESULT_TABLE_SIZE 128

and you're good to go.

The C++ code below is some old code (I just updated it to use the std::* stuff) I found laying around from a few years back that I wrote to cheat at the game "Text Twist" that I was semi-addicted to once. The game is a standard jumble/word finding game where you get 5-7 letters and have to put together all of the words that can be made from those letters. What originally got me interested was a file called "longtree.bin" in the installation area that turned out to be a flat-file representation of a trie (http://en.wikipedia.org/wiki/Trie) containing all of the words in the game. The code below compiles (on windows only as it is, the file handling stuff is windows specific) into an executable that takes the longtree file and sequences of letters and dumps out the exact list of words (in the correct order) that the game will count. The code is not professional quality, so expect some crashes if you color outside of the lines. Enjoy! ///////Begin code////////

#include <string>
#include <stdlib.h>
#include <fstream>
#include <iostream>
#include <ctype.h>
#include <windows.h>
 
#define MAX_WORD_LEN 7
#define RESULT_TABLE_SIZE 64
 
typedef HANDLE fileDesc;
typedef int (*compareFunc)(std::string, std::string);
 
bool validFile(fileDesc file);
fileDesc createFile(const char *fileName);
fileDesc openFile(const char *fileName);
int fileRead(fileDesc fd, void *buf, size_t s);
int fileGetCurrentPointer(fileDesc fd);
int fileSetCurrentPointer(fileDesc fd, unsigned int offset);
bool closeFile(fileDesc file);
bool writeFile(fileDesc file, const char *buffer, size_t len);
int alphaCompare(std::string a, std::string b);
int hashCompare(std::string a, std::string b);
int sortHash(std::string str, int idx);
void rotateStr( std::string &str, int idx);
 
enum state { S_START=0, S_ALPHA=1, S_ZERO=2, S_ONE=3, S_ERROR=5 };
 
///////////////
// nodeList //
///////////////
struct nodeList
{
  char letter;
  bool isWord;
  nodeList *nextLetter;
  nodeList *nextLocal;
};
 
/////////////////
// searchTree //
/////////////////
class searchTree
{
private:
  std::ofstream tout;
  nodeList *root;
  std::string *resultTable[RESULT_TABLE_SIZE];
  int wordCounts[MAX_WORD_LEN];
public:
  searchTree()
  {
    root = NULL;
    tout.open("debugTree.txt", std::ios::out);
    for(int i = 0; i < RESULT_TABLE_SIZE; i++) resultTable[i] = NULL;
    for(int j = 0; j < MAX_WORD_LEN; j++) wordCounts[j] = 0;
  }
  void addWordToTree(std::string newWord);
  int getAllSubWords(std::string findMe);
  nodeList *createBasicNode(char letter);
  nodeList *isLetterInList(nodeList *head, char let);
  nodeList *addLetterToList(nodeList *head, char let);
  void operateOnPerms(std::string s, int i);
  void findAllSubsOf(std::string str);
  void addToResultTable(std::string str);
  void resetResultTable();
  void printResultTable();
  void sortResultTable(compareFunc func);
  void printWordCounts();
};
 
/////////////////
// treeReader //
/////////////////
class treeReader
{
private:
  std::ofstream fout;
  searchTree *myTree;
  fileDesc descriptor;
  int markers[MAX_WORD_LEN], reader;
  state currentState;
  char currentVal;
  static const char fileName[];
public:
  treeReader()
  {
    fout.open("ttwist_debug.txt", std::ios::out);
    myTree = new searchTree;
    descriptor = openFile(fileName);
    currentState = S_START;
 
    for(int i = 0; i < MAX_WORD_LEN; i++)
    {
      markers[i] = -1;
    }
 
    reader = 0;
    fileSetCurrentPointer(descriptor, reader);
    currentVal = getCharacter(reader);
  }
 
  ~treeReader(){ fout.close(); }
  void processTree();
  char getCharacter(int pos);
  char lookAtNext(int pos);
  void advanceReader(){ reader++; }
  void getWordSkipLast();
  void getWordFull();
  void deleteAndAdvanceMarkers();
  void setNextMarker(int pos);
  void setCurrentState(state newState){ currentState = newState; }
  void foundAlpha();
  void foundZero();
  void foundOne();
};
 
////////////////////////////////////
// //
// treeReader Functions //
// //
////////////////////////////////////
 
void treeReader::processTree()
{
  char value;
  char inputStr[256];
  std::string *temp = new std::string;
  while(value = getCharacter(reader))
  {
    if(isalpha(value))
    {
      foundAlpha();
    }
    else if(value == '0')
    {
      foundZero();
    }
    else if(value == '1')
    {
      foundOne();
    }
    else
    {
      std::cout << "Error: foreign character found\n";
      exit(1);
    }
 
    advanceReader();
  }
 
  myTree->printWordCounts();
 
  while(1)
  {
    std::cout << "Enter a string: ";
    std::cin >> *temp;
    if(*temp == "kwit") break;
    myTree->findAllSubsOf(*temp);
  }
  std::cout << "Done!\n";
}
 
void treeReader::foundAlpha()
{
  switch(currentState)
  {
    case S_START:
      setNextMarker(reader);
      break;
    case S_ALPHA:
      break;
    case S_ZERO:
      setNextMarker(reader);
      break;
    case S_ONE:
      setNextMarker(reader);
      break;
  }
 
  setCurrentState(S_ALPHA);
}
 
void treeReader::foundZero()
{
  switch(currentState)
  {
    case S_START:
      break;
    case S_ALPHA:
      break;
    case S_ZERO:
      break;
    case S_ONE:
      break;
  }
 
  setCurrentState(S_ZERO);
}
 
void treeReader::foundOne()
{
  switch(currentState)
  {
    case S_START:
      break;
  case S_ALPHA:
      getWordSkipLast();
      break;
    case S_ZERO:
      getWordFull();
      deleteAndAdvanceMarkers();
      break;
    case S_ONE:
      getWordFull();
      deleteAndAdvanceMarkers();
      break;
  }
 
  setCurrentState(S_ONE);
}
 
void treeReader::getWordSkipLast()
{
  char *foundWord = (char*)malloc((MAX_WORD_LEN + 1)*sizeof(char));
  int i;
  for(i = 0; i < MAX_WORD_LEN; i++)
  {
    if(markers[i] == -1) break;
      foundWord[i] = getCharacter(markers[i]);
  }
 
  foundWord[i - 1] = '\0';
  std::string str(foundWord);
  myTree->addWordToTree(str);
  free(foundWord);
}
 
void treeReader::getWordFull()
{
  char *foundWord = (char*)malloc((MAX_WORD_LEN + 1)*sizeof(char));
  int i;
  for(i = 0; i < MAX_WORD_LEN; i++)
  {
    if(markers[i] == -1) break;
      foundWord[i] = getCharacter(markers[i]);
  }
 
  foundWord[i] = '\0';
  std::string str(foundWord);
  myTree->addWordToTree(str);
  free(foundWord);
}
 
char treeReader::getCharacter(int pos)
{
  void *buf = malloc(32);
  char *returnVal, returnChar;
  fileSetCurrentPointer(descriptor, pos);
 
  if(!fileRead(descriptor, buf, 1))
  {
    return 0; //EOF
  }
 
  fileSetCurrentPointer(descriptor, pos); //don't increment
  returnVal = (char*)buf;
  returnChar = returnVal[0];
  free((char*)buf);
  return returnChar;
}
 
char treeReader::lookAtNext(int pos)
{
  char returnChar;
  returnChar = getCharacter(pos+1); //check for EOF
  return returnChar;
}
 
void treeReader::setNextMarker(int pos)
{
  int i = 0;
  while((markers[i] != -1) && (i < MAX_WORD_LEN)) i++;
  markers[i] = pos;
}
 
void treeReader::deleteAndAdvanceMarkers()
{
  for(int i = MAX_WORD_LEN - 1; i >= 0; i--)
  {
    if(markers[i] != -1)
    {
      if(!isalpha(lookAtNext(markers[i])))
      {
        markers[i] = -1;
      }
      else
      {
        markers[i]++;
        return;
      }
    }
  }
}
 
const char treeReader::fileName[] = "longtree.bin";
 
///////////////////////////////////////////
// //
// searchTree Functions //
// //
///////////////////////////////////////////
 
void searchTree::addWordToTree(std::string newWord)
{
  nodeList *nextLetterList = root;
  nodeList *follow = root;
  nodeList *looker = root;
 
  wordCounts[newWord.length() - 1] += 1;
 
  for(int i = 0; i < newWord.length(); i++)
  {
    if(root == NULL)
    {
      root = createBasicNode(newWord[i]);
      follow = root;
      nextLetterList = looker = root->nextLetter;
      continue;
    }
 
    looker = isLetterInList(nextLetterList, newWord[i]);
 
    if(looker == NULL)
    { //not in list
      looker = addLetterToList(nextLetterList, newWord[i]);
 
      if(nextLetterList == NULL)
      {
        nextLetterList = looker; //first let in list
      }
 
      if(follow != nextLetterList)
      { //if not on first level of tree
        follow->nextLetter = nextLetterList;
      }
    }
 
    follow = looker;
    nextLetterList = looker = looker->nextLetter;
  }
 
  follow->isWord = true;
}
 
nodeList *searchTree::createBasicNode(char letter)
{
  nodeList *ptr = new nodeList;
  ptr->letter = letter;
  ptr->nextLocal = ptr->nextLetter = NULL;
  ptr->isWord = false;
  return ptr;
}
 
nodeList *searchTree::isLetterInList(nodeList *head, char let)
{
  nodeList *temp;
  for(temp = head; temp != NULL; temp = temp->nextLocal)
  {
    if(temp->letter == let)
    {
      return temp;
    }
  }
 
  return NULL;
}
 
//this assumes that let is not in list
nodeList *searchTree::addLetterToList(nodeList *head, char let)
{
  nodeList *temp, *follow = NULL;
  for(temp = head; temp != NULL; temp = temp->nextLocal)
  {
    follow = temp;
  }
 
  temp = createBasicNode(let);
 
  if(follow != NULL) follow->nextLocal = temp; //if not first letter
  return temp;
}
 
int searchTree::getAllSubWords(std::string findMe)
{
  int i = 0;
  std::string result("");
  nodeList *lastLet = root;
  nodeList *looker = root;
  for(int i = 0; i < findMe.length(); i++)
  {
    while((looker != NULL) && (looker->letter != findMe[i]))
    {
      looker = looker->nextLocal;
    }
 
    if(looker == NULL)
    {
      return 0;
    }
    else if(looker->letter = findMe[i])
    {
      result += looker->letter;
      if(looker->isWord)
      {
        addToResultTable(result);
      }
    }
    else if(looker == NULL)
    {
      return 0;
    }
 
    lastLet = looker;
    looker = looker->nextLetter;
  }
}
 
void searchTree::addToResultTable(std::string str)
{
  int i;
  for(i = 0; resultTable[i] != NULL; i++)
  {
    if(i >= RESULT_TABLE_SIZE)
    {
      std::cout << "Result table limit exceeded\n";
      return;
    }
    if(*resultTable[i] == str)
    {
      return;
    }
  }
 
  resultTable[i] = new std::string(str);
}
 
void searchTree::printResultTable()
{
  sortResultTable(&hashCompare);
  sortResultTable(&alphaCompare);
  for(int i = 0; i < RESULT_TABLE_SIZE; i++)
  {
    if(resultTable[i] == NULL) return;
    std::cout << *resultTable[i] << std::endl;
  }
}
 
void searchTree::resetResultTable()
{
  for(int i = 0; i < RESULT_TABLE_SIZE; i++)
  {
    if(resultTable[i] == NULL) return;
    delete resultTable[i];
    resultTable[i] = NULL;
  }
}
 
void searchTree::sortResultTable(compareFunc func)
{
  int i, j, m, n;
  std::string *temp;
  for(m = 0; resultTable[m] != NULL; m++);
  i = m-1;
  int lastExchangeIdx;
 
  while (i > 0)
  {
    lastExchangeIdx = 0;
    for(j = 0; j < i; j++)
    {
      if((*func)(*resultTable[j+1],*resultTable[j]) == 1)
      {
        temp = resultTable[j];
        resultTable[j] = resultTable[j+1];
        resultTable[j+1] = temp;
        lastExchangeIdx = j;
      }
    }
 
    i = lastExchangeIdx;
  }
}
 
//return a < b ? 1 : 0
int alphaCompare(std::string a, std::string b)
{
  if(a.length() != b.length()) return -1;
 
  for(int i = 0; i < a.length(); i++)
  {
    if(a[i] == b[i])
    {
      continue;
    }
    else if(a[i] < b[i])
    {
      return 1;
    }
    else
    {
      return 0;
    }
  }
}
 
//return a < b ? 1 : 0
int hashCompare(std::string a, std::string b)
{
  int aHash = sortHash(a, 0);
  int bHash = sortHash(b, 0);
  if(aHash == bHash)
  {
    return -1;
  }
  else if(aHash < bHash)
  {
    return 1;
  }
  else
  {
    return 0;
  }
}
 
int sortHash(std::string str, int idx)
{
  return ((int)str[idx] * (str.length() - 2));
}
 
void searchTree::findAllSubsOf(std::string str)
{
  operateOnPerms(str, 0);
  printResultTable();
  resetResultTable();
}
 
void searchTree::operateOnPerms(std::string s, int n)
{
  int i;
  if( n == s.length()-1 )
  {
    getAllSubWords(s);
  }
  else
  {
    int k=s.length();
 
    for( i=n ; i<k ; i++ )
    {
      int j;
 
      for( j=k+n-i ; j<k ; j++ )
        if( s[n] == s[j]) break;
 
      if( j==k ) operateOnPerms( s,n+1);
 
      rotateStr( s, n);
    }
  }
}
 
void searchTree::printWordCounts()
{
  for(int i = 0; i < MAX_WORD_LEN; i++)
  {
    if(wordCounts[i])
    {
      std::cout << "Words with " << i+1 << " letters: " << wordCounts[i] << std::endl;
    }
  }
}
 
void rotateStr( std::string &str, int idx )
{
  char temp = 0;
  int i = 0;
  int len = str.length();
 
  if(idx < len )
  {
    temp = str[idx];
 
    for(int i = idx; i<len-1; i++) str[i] = str[i+1];
    str[len-1] = temp;
  }
}
 
///////////////////////////////////////////
// //
// Main //
// //
///////////////////////////////////////////
 
int
main()
{
  treeReader TR;
  TR.processTree();
  return 0;
}
 
////////////////////////////////////////////
// //
// File Processing Functions //
// //
////////////////////////////////////////////
 
bool
validFile(fileDesc file)
{
    return file != INVALID_HANDLE_VALUE;
}
 
fileDesc
createFile(const char *fileName)
{
    return CreateFile(fileName,
                      GENERIC_READ | GENERIC_WRITE,
                      FILE_SHARE_READ,
                      NULL,
                      CREATE_ALWAYS,
                      FILE_ATTRIBUTE_NORMAL,
                      NULL);
}
 
fileDesc
openFile(const char *fileName)
{
    return CreateFile(fileName,
                      GENERIC_READ,
                      FILE_SHARE_READ,
                      NULL,
                      OPEN_EXISTING,
                      0,
                      NULL);
}
 
int
fileRead(fileDesc fd, void *buf, size_t s)
{
    BOOL successful;
    DWORD br;
 
    successful = ReadFile((HANDLE)fd, buf, s, &br, 0);
    if(!successful)
        return -1;
    else
        return br;
}
 
int
fileGetCurrentPointer(fileDesc fd)
{
    return SetFilePointer((HANDLE)fd, 0, NULL, FILE_CURRENT);
}
 
int
fileSetCurrentPointer(fileDesc fd, unsigned int offset)
{
    return SetFilePointer((HANDLE)fd, offset, NULL, FILE_BEGIN);
}
 
bool
closeFile(fileDesc file)
{
    return CloseHandle(file);
}
 
bool
writeFile(fileDesc file, const char *buffer, size_t len)
{
    DWORD bytesWritten;
 
    return WriteFile(file, buffer, len, &bytesWritten, NULL);
}

Music

Journal: Madonna vs. Doctor Who

Journal by jomama717
I heard the Madonna song "Hung Up" on TV the other day and the background beat/tune sounded to me exactly like the Doctor Who theme song as I remember it (Tom Baker years). I tried to get the original Doctor Who theme from itunes but all I came up with was some crappy rip-off remix of it, which, actually did sound a lot like the Madonna song. I suppose I'll have to buy a Doctor Who DVD and rip the theme off of there if I want to get my hands on the real deal.

The Force is what holds everything together. It has its dark side, and it has its light side. It's sort of like cosmic duct tape.

Working...