Sunday, December 30, 2012

DOCX Text Mining in Python and Java

In recent years Microsoft has been kind in making its formats easier to parse than binary lumps like the old .doc format. Instead, they now use XML within zip files with the extension .docx. This format can be quickly and easily parsed in Python (see my earlier xlsx parser.)

The Format

Within all new .docx files there is a folder named word and within this folder is a file named document.xml. This has a bunch of <w:t> tags, which hold text. To extract the text, just find those and pull out the contents!

The Code (Python)

#!/usr/bin/env python3
'''

Copyright 2012 Joseph Lewis <joehms22@gmail.com> | <joseph@josephlewis.net>

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of the nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

This software recieves a docx file from the command line, and returns the text
from its path.

'''

import zipfile
import xml.dom.minidom
import sys


def extract_docx_text(fp):
myFile = zipfile.ZipFile(fp)

share = xml.dom.minidom.parseString(myFile.read('word/document.xml'))
text = share.getElementsByTagName('w:t')

return " ".join([node.childNodes[0].nodeValue for node in text])

if __name__ == "__main__":
if len(sys.argv) == 1:
print "usage: docx.py FILENAME [FILENAME...]"
else:
for arg in sys.argv:
try:
print(extract_docx_text(arg))
except Exception:
pass # not a valid zipfile, probably.

The Code (Java)

There is an issue with this Java implementation, but it should work for most purposes: special characters that are escaped in xml, like &amp; will not be unescaped in processing.
/**

Copyright 2012 Joseph Lewis <joehms22@gmail.com> | <joseph@josephlewis.net>

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of the nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

This software recieves a docx file from the command line, and returns the text
from its path.

**/
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class DOCXExtracter {
private static String convertStreamToString(java.io.InputStream is) {
try(Scanner s = new java.util.Scanner(is).useDelimiter("\\A")) {
return s.hasNext() ? s.next() : "";
}
}

public static String extractFromPath(String path) throws IOException
{
ZipFile zipFile = new ZipFile(path);
String ret = extractFromFile(zipFile);
zipFile.close();
return ret;
}

public static String extractFromFile(ZipFile f) throws IOException
{
ZipEntry e = f.getEntry("word/document.xml");
InputStream is = f.getInputStream(e);
String contents = convertStreamToString(is);
is.close();
return contents.replaceAll("(?s)\\<.*?\\>", " ");
}

public static void main(String[] args)
{
for(int i = 0; i < args.length; i++)
try {
System.out.println(extractFromPath(args[i]));
} catch (IOException e) {
e.printStackTrace();
}
}
}

A Python Hopfield Network

Quick Background

Hopfield networks are general purpose neural networks that take a set of input values (boolean) and produce an output of same length. They are particularly useful in signal processing and cleaning up images where noise is an issue, (think smudged characters).

I imagine they would be particularly useful in normalizing inputs from different hardware (e.g. creating color profiles, removing static or echos from some microphones, etc.)

This Implementation

This implementation is a tanslation of the algorithm found in the Clever Algorithms book from Ruby to Python.
#!/usr/bin/env python3
# A translation of http://www.cleveralgorithms.com/nature-inspired/neural/hopfield_network.html
import random

def random_vector(minmax):
return [row[0] + ((row[1] - row[0]) * random.random()) for row in minmax]

def initialize_weights(problem_size):
return random_vector([[-0.5,0.5] for i in range(problem_size)])

def create_neuron(num_inputs):
return {'weights' : initialize_weights(num_inputs)}

def propagate_was_change(neurons):
i = random.randrange(len(neurons))
activation = 0

for j, other in enumerate(neurons):
activation += other['weights'][i] * other['output'] if i != j else 0

output = 1 if activation >= 0 else -1
change = output != neurons[i]['output']
neurons[i]['output'] = output
return change

def flatten(nested):
try:
return [item for sublist in nested for item in sublist]
except TypeError:
return nested

def get_output(neurons, pattern, evals=100):
vector = flatten(pattern)

for i, neuron in enumerate(neurons):
neuron['output'] = vector[i]

for j in range(evals):
propagate_was_change(neurons)

return [neuron['output'] for neuron in neurons]

def train_network(neurons, patters):
for i, neuron in enumerate(neurons):
for j in range((i+1), len(neurons)):
if i == j:
continue

wij = 0.0

for pattern in patters:
vector = flatten(pattern)
wij += vector[i] * vector[j]

neurons[i]['weights'][j] = wij
neurons[j]['weights'][i] = wij

def to_binary(vector):
return [0 if i == -1 else 1 for i in vector]

def print_patterns(provided, expected, actual):
p, e, a = to_binary(provided), to_binary(expected), to_binary(actual)
p1, p2, p3 = ', '.join(map(str, p[0:2])), ', '.join(map(str, p[3:5])), ', '.join(map(str, p[6:8]))
e1, e2, e3 = ', '.join(map(str, e[0:2])), ', '.join(map(str, e[3:5])), ', '.join(map(str, e[6:8]))
a1, a2, a3 = ', '.join(map(str, a[0:2])), ', '.join(map(str, a[3:5])), ', '.join(map(str, a[6:8]))
print( "Provided\tExpected\tGot")
print( "%s\t\t%s\t\t%s" % (p1, e1, a1))
print( "%s\t\t%s\t\t%s" % (p2, e2, a2))
print( "%s\t\t%s\t\t%s" % (p3, e3, a3))


def calculate_error(expected, actual):
return sum([1 for i in range(len(expected)) if expected[i] != actual[i]])

def perturb_pattern(vector, num_errors=1):
perturbed = [v for v in vector]
indicies = [0 for i in range(random.randrange(len(perturbed)))]

while len(indicies) < num_errors:
index = random.randrange(len(perturbed))
if not index in indicies:
indicies.append(index)

for i in indicies:
perturbed[i] = -1 if perturbed[i] == 1 else 1

return perturbed


def test_network(neurons, patterns):
error = 0.0

for pattern in patterns:
vector = flatten(pattern)
perturbed = perturb_pattern(vector)
output = get_output(neurons, perturbed)
error += calculate_error(vector, output)
print_patterns(perturbed, vector, output)

error = error / float(len(patterns))
print("Final Result: avg pattern error=%s" % (error))

return error

def execute(patters, num_inputs):
neurons = [create_neuron(num_inputs) for i in range(num_inputs)]
train_network(neurons, patters)
test_network(neurons, patters)
return neurons

if __name__ == "__main__":
# problem configuration
num_inputs = 9
p1 = [[1,1,1],[-1,1,-1],[-1,1,-1]] # T
p2 = [[1,-1,1],[1,-1,1],[1,1,1]] # U
patters = [p1, p2]
# execute the algorithm
execute(patters, num_inputs)

Saturday, December 29, 2012

Get CRON to Send Email Reports

Here is a quick tip: if you have CRON running jobs, but want assurance they're getting done by way of email, do the following:
Open CRON:
crontab -e
You'll see something like this:
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command

28 * * * * cd /home/joseph/google_drive && grive
Now add the following line to the end of the file:
MAILTO=somebody@your.domain
Then Save and Close; as long as you have a mail server set up and running, you'll get an email with the output of each of the commands in the file every time they're run.

If You Don't Have a Mail Server

If you don't have a mail server set up, and are running Ubuntu, you may want to check out Juju Charms they are Ubuntu's newest way to set up complex server configurations with a single command. Or just follow this tutorial on how to set up Postfix.

Friday, December 28, 2012

Friday Link List - Sixth Sense, End of Social Media and 3D Printer Sale

Operating Systems

  • OUYA the $99 alternative video game console that runs Android has just gotten its first batch of prototypes in.

Curiosities

  • North Paw is an interesting project that will always have you know where North is (it uses a haptic feedback anklet that you wear for several weeks that eventually gets stuck in your mind).
  • Warren Ellis published an article about the end of the first generation of social media, definitely worth a read.

Algorithms

  • Nothing to see here!

Making

Thursday, December 27, 2012

One in One Out

I'm an avid fan of Leo Babauta author of zenhabits. I admire his work to pair down his worldly things because in the end, they are the things that own you. While I may not be ready to cut down all of my possessions to 100 items I do have a practice of one in, one out.

Any time I get something new, I get rid of something old. At first this seems rather difficult, as you may think "I need all of this stuff" but you start to realize it isn't true. One of the easiest things to cut is books, with so many being open-sourced or reaching the public domain every day it is easy to trade out the paper for the digital. (Not that I advocate becoming an archive of everything digital)

Another great place to purge is the paper you collect; a friend of my father's used to run under the rule "what is the worst that can happen if I don't have this?" and that kept her office neat and clean. Chances are that you don't really need most of the paper you keep around.

The simple guide to removing clutter is this:
  • Have I used the thing in the past year? (if no, chances are you don't need it)
  • Can I get the thing digitally for free, or transfer it to digital easily?
  • If I donate this thing, will it help someone else?
  • Will this thing become mostly obsolete before I use it again?
  • Do I already have one of these?
Being this is one hour hacks, give yourself a one hour challenge to get rid of 100 things, even if they're small (small things still take up room in your brain!)

Wednesday, December 26, 2012

On MOOCs

I recently read an opinion piece labeled "Jump Off the Coursera Bandwagon" --published in The Chronicle of Higher Education--which puts up a few interesting points against online education:
There are critical pedagogical issues at stake in the online market, and MOOC's have not done nearly enough to deal with those concerns.

Coursera and its devotees simply have it wrong. The Coursera model doesn't create a learning community; it creates a crowd. In most cases, the crowd lacks the loyalty, initiative, and interest to advance a learning relationship beyond an informal, intermittent connection.

Why should we be impressed that an online course can reach 100,000 students at once? By celebrating massification, advocates of Coursera elevate volume as the chief objective of online learning. Is that truly our goal in academe?
Because posing a rhetorical question is a very poor form of argument, it is here I'll stop quoting and answer YES.

What MOOCs Do

MOOCs are an invaluable tool, and align better with the underlying principles the pedagogy than do traditional methods.
The goal of the professor is to ignite a curiosity in the minds of the uninitiated and stoke it in to a roaring flame. However, in order to stay employed and live in the real world they have to meet certain ratings from students; students that are easily upset with lower GPAs. They have to appease everyone, including all of the students that surf Facebook all the way through lectures.
If you must subjugate your students to treating you with a formal respect, the war is already lost. Teachers gain respect by being unmatched. MOOCs promise to bring these kinds of educators out in to the open, where they'll be respected by hundreds of thousands instead of a few in a classroom.
Students should never be totally loyal to their professors, and MOOCs allow students to quickly and easily seek out alternative styles of teaching, and alternative viewpoints.
As to "the crowd lack"ing the initiative to advance the relationship, that is an unfounded statement. Students that actively watch and participate in MOOCs are clearly far beyond those that are in traditional colleges that try to escape the classes with a good grade.
Now to the questions the author posed:
"Why should we be impressed that an online course can reach 100,000 students at once?"
Because it proves there is a vast market for education that is not being met, and that there are 100,000 students interested enough in the topic that weren't getting their needs met through traditional means.
"By celebrating massification, advocates of Coursera elevate volume as the chief objective of online learning. Is that truly our goal in academe?"
MOOCs allow everyone with a decent network connection to become classically educated. There is no bias based upon race, religion, color, ethnicity, or prior level of education.

Conclusion

Locking away education has been the prerogative of tyrants. In a world that is dominated by technologies few understand because of their complexities open on-demand education has no real drawbacks, other than possibly causing a change in the way education works.
I don't feel universities will go away for a good long time, they are simply too important of an institution to fail, but they certainly will change if MOOCs catch on; and I feel that many of the mediocre professors will be looking for new things to do with their lives, as will many of the mediocre students.
As a student, my goal is to graduate, and with a high enough GPA such that I can get in to a good grad school. There are some classes in topics such as Mathematics, Chemistry, or Circiutry where I would happily take the class, if it didn't count toward my GPA. I want the knowledge, and feel it would be exciting to learn, but not at the expense of my future; so I have turned to Coursera for these topics, and will never regret the time I spend learning.

Monday, December 24, 2012

Sunday, December 23, 2012

Tiny Embeddable Java Webserver

This is a tiny embedded Java webserver that'll serve pages from a local drive or a .jar (if it is within the jar file).
While it may not be completely useful to do this a very easy extension would include a Map from Strings to Objects, and call the .toString() method on the object and use that as output.
By creating something like this, you would get a simple CGI like server that you could use to write difficult GUI code, using styling from CSS and Javascript.

Source Code

/**
* A local embedded webserver, will run from a .jar file, and serve files
* from the root.
*
* @author Joseph Lewis <joehms22@gmail.com>
*/

import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;


public class Webserver extends Thread
{
private static final FileNotFoundException FILE_NOT_FOUND = new FileNotFoundException();
private static final byte[] ERROR_404 = "HTTP/1.0 404 Not Found\r\nContent-type: text/plain\r\n\r\n404 Error, page not found.".getBytes();
private static final int PORT_NUM = 8_000;
public static Webserver SERVER = null;
private ServerSocket serverSocket;

public static Webserver getInstance()
{
// Make sure we only ever have one server running.
if(SERVER == null)
SERVER = new Webserver();

return SERVER;
}

private Webserver()
{
try
{
serverSocket = new ServerSocket(PORT_NUM);

System.err.println("Starting server on port: " + PORT_NUM);

// If you're running this embedded, you will probably want to
// make the thread a daemon so it quits when your main program
// quits rather than serves forever.
//setDaemon(true);

start();

} catch (IOException e) {
e.printStackTrace();
}
}

@Override
public void run()
{
// Starts a new thread for every request we get.
while (true)
try {
new RequestHandler(serverSocket.accept());
} catch (Exception e) {
e.printStackTrace();
}
}

public static void main(String[] args)
{
Webserver.getInstance();
}


private class RequestHandler extends Thread
{
private final Socket socket;
private final ClassLoader m_loader;
private static final String DEFAULT_INDEX_PAGE = "index.html";

// Start the thread in the constructor
public RequestHandler(Socket s) {
socket = s;
m_loader = Webserver.getInstance().getClass().getClassLoader();
start();
}

@Override
public void run()
{
try
{
DataInputStream in = new DataInputStream(socket.getInputStream());
PrintStream out = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));


// Parse the HTML request
StringTokenizer st = new StringTokenizer(in.readLine());

try
{
String requestType = st.nextToken();
String filename = normalizeFilePath(st.nextToken());

System.err.println("Request: " + requestType + " " + filename);


InputStream f = m_loader.getResourceAsStream(filename);

if(f == null)
throw FILE_NOT_FOUND;

out.print("HTTP/1.0 200 OK\r\nContent-type: " + getMimeType(filename) + "\r\n\r\n");

// Send file contents to client, then close the connection
final byte[] a = new byte[2048];
int n;
while ((n = f.read(a)) > 0)
out.write(a, 0, n);


} catch (NoSuchElementException | FileNotFoundException e) {
out.print(ERROR_404);
}

out.close();
in.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}

public String getMimeType(String filename)
{
String ext = filename.substring(filename.indexOf(".") + 1);

switch(ext)
{
case "html": case "htm":
return "text/html";
case "css":
return "text/css";
case "java":
return "text/x-java";
case "class":
return "application/x-java";
case "png":
return "image/png";
case "jpg": case "jpeg":
return "image/jpeg";
case "js":
return "application/javascript";
default:
return "application/octet-stream";
}
}

public String normalizeFilePath(String filename) throws FileNotFoundException
{
// Remove GET params.
if(filename.contains("?"))
filename = filename.split("?", 2)[0];

// Make requests to a folder show the index.html file.
if(filename.endsWith("/"))
filename += DEFAULT_INDEX_PAGE;

// Remove leading /
while (filename.indexOf("/") == 0)
filename = filename.substring(1);

// Check for illegal characters to prevent access to superdirectories
if (filename.contains("..") || filename.contains(":") || filename.contains("|"))
throw FILE_NOT_FOUND;

return filename;
}
}
}

Friday, December 21, 2012

Java 7's Best New Features

Java 6 is approaching its end of life release in February 2013, so here are some new features of Java 7 that will help you hit the ground running with the new JDK. A few of them are sure to be huge timesavers, like using Strings in switch statements.

Binary Literals

int j = 0b10101010101;

Underscores in Numbers

Let you quickly see how large a number really is.
int k = 1_000_000;

String Switch Statements

Use the new string switch statements to apply .equals() on the string:
switch(someString)
{
case "Saturday": case "Sunday":
return "weekend";

default:
return "weekday";
}

Automatic Resource Closing

When you open streams in try blocks, they are now automatically closed.
try(InputStream in = socket.getInputStream();
PrintStream out = new PrintStream(new BufferedOutputStream(socket.getOutputStream())))
{
byte[] b = new byte[1024];
int k = 0;
while((k = in.read(b)) > 0)
out.write(b,0,k);
}

// in and out will be cleaned up after this.

Multiple Catch

You can now catch more than one exception at a time:
try{

// do stuff here

}catch(IOException | NullPointerException ex)
{
// Handle either exception
}

New Diamond Operator

No longer do you have to declare the same type in the constructor and variable when you're providing types:
HashMap<String, Integer> myMap = new HashMap<>();

NIO

This is a huge topic, too long to be covered here; but there is a new library for working with various filesystems that abstracts away their differences, so you can use the same code to work remotely, locally, within zip files, etc.

Compute/Fork Join

Java now provides an interface for embarrassingly parallel fork-join tasks (such as sorting), just implement Compute.

Swing Improvements

  • Draw on top of components, then erase the drawing, using JLayer
  • Make translucent windows with .setOpacity(<float>) on a JFrame
  • New HSV tab on JColorChooser.

Open Source Laptops, Rebuilding Pong, Free Neural Networking Course: Friday Link List

Operating Systems

  • Syllalbe OS should benefit now that REBOL 3 has been released under the Apache License. What does this mean for the world? Nothing. Syllable is a mostly pedantic project and REBOL is a difficult language that suffers the same flaws as smalltalk and has a severely limited scope compared to JavaScript (that already runs everywhere and is not encumbered by strange programming paradigms.)

Curiosities

Algorithms

Making

  • Andrew “bunnie” Huang has designed an open-source laptop motherboard with some great features, including built-in FPGA, touch-screen ports, and lots of UART /GPIO ports.
  • Pong Reborn Rebuilding the original arcade version of Atari's Pong.

Thursday, December 20, 2012

A Tiny Java Mime Lookup Library

I couldn't find a nice and very tiny solution to looking up a mimetype based on file extension in Java, so I built one, it uses /etc/mime.types as the source for the information, after the first run, the library should be pretty fast due to the use of a HashMap for lookups.

Get a Mime by Extension

lookupMapping("doc");

Get a Mime by Path

getMime("/path/to/some/file.tar.gz"); // looks up extension "gz"

Full Code Listing

import java.util.HashMap;

/**
* Looks up a mimetype based upon a file extension.
*/
public class MimeType {
public static final String DEFAULT_MIME = "application/octet-stream";

/**
* A list of extensions and their appropriate mime mappings.
*/
private static final String[][] MIME_MAPPING = {{"323","text/h323"},
{"3gp","video/3gpp"},
{"7z","application/x-7z-compressed"},
{"abw","application/x-abiword"},
{"ai","application/postscript"},
{"aif","audio/x-aiff"},
{"aifc","audio/x-aiff"},
{"aiff","audio/x-aiff"},
{"alc","chemical/x-alchemy"},
{"amr","audio/amr"},
{"amr","audio/amr"},
{"anx","application/annodex"},
{"apk","application/vnd.android.package-archive"},
{"appcache","text/cache-manifest"},
{"~","application/x-trash"},
{"%","application/x-trash"},
{"art","image/x-jg"},
{"asc","text/plain"},
{"asf","video/x-ms-asf"},
{"asn","chemical/x-ncbi-asn1"},
{"asn","chemical/x-ncbi-asn1-spec"},
{"aso","chemical/x-ncbi-asn1-binary"},
{"asx","video/x-ms-asf"},
{"atom","application/atom+xml"},
{"atomcat","application/atomcat+xml"},
{"atomsrv","application/atomserv+xml"},
{"au","audio/basic"},
{"avi","video/x-msvideo"},
{"awb","audio/amr-wb"},
{"awb","audio/amr-wb"},
{"axa","audio/annodex"},
{"axv","video/annodex"},
{"bak","application/x-trash"},
{"bat","application/x-msdos-program"},
{"b","chemical/x-molconn-Z"},
{"bcpio","application/x-bcpio"},
{"bib","text/x-bibtex"},
{"bin","application/octet-stream"},
{"bmp","image/x-ms-bmp"},
{"book","application/x-maker"},
{"boo","text/x-boo"},
{"brf","text/plain"},
{"bsd","chemical/x-crossfire"},
{"c3d","chemical/x-chem3d"},
{"cab","application/x-cab"},
{"cac","chemical/x-cache"},
{"cache","chemical/x-cache"},
{"cap","application/vnd.tcpdump.pcap"},
{"cascii","chemical/x-cactvs-binary"},
{"cat","application/vnd.ms-pki.seccat"},
{"cbin","chemical/x-cactvs-binary"},
{"cbr","application/x-cbr"},
{"cbz","application/x-cbz"},
{"cc","text/x-c++src"},
{"cda","application/x-cdf"},
{"cdf","application/x-cdf"},
{"cdr","image/x-coreldraw"},
{"cdt","image/x-coreldrawtemplate"},
{"cdx","chemical/x-cdx"},
{"cdy","application/vnd.cinderella"},
{"cef","chemical/x-cxf"},
{"cer","chemical/x-cerius"},
{"chm","chemical/x-chemdraw"},
{"chrt","application/x-kchart"},
{"cif","chemical/x-cif"},
{"class","application/java-vm"},
{"cls","text/x-tex"},
{"cmdf","chemical/x-cmdf"},
{"cml","chemical/x-cml"},
{"cod","application/vnd.rim.cod"},
{"com","application/x-msdos-program"},
{"cpa","chemical/x-compass"},
{"cpio","application/x-cpio"},
{"cpp","text/x-c++src"},
{"cpt","application/mac-compactpro"},
{"cpt","image/x-corelphotopaint"},
{"cr2","image/x-canon-cr2"},
{"crl","application/x-pkcs7-crl"},
{"crt","application/x-x509-ca-cert"},
{"crw","image/x-canon-crw"},
{"csd","audio/csound"},
{"csf","chemical/x-cache-csf"},
{"csh","application/x-csh"},
{"csh","text/x-csh"},
{"csm","chemical/x-csml"},
{"csml","chemical/x-csml"},
{"css","text/css"},
{"csv","text/csv"},
{"ctab","chemical/x-cactvs-binary"},
{"c","text/x-csrc"},
{"c++","text/x-c++src"},
{"ctx","chemical/x-ctx"},
{"cu","application/cu-seeme"},
{"cub","chemical/x-gaussian-cube"},
{"cxf","chemical/x-cxf"},
{"cxx","text/x-c++src"},
{"dat","application/x-ns-proxy-autoconfig"},
{"davmount","application/davmount+xml"},
{"dcm","application/dicom"},
{"dcr","application/x-director"},
{"deb","application/x-debian-package"},
{"diff","text/x-diff"},
{"dif","video/dv"},
{"dir","application/x-director"},
{"djv","image/vnd.djvu"},
{"djvu","image/vnd.djvu"},
{"dll","application/x-msdos-program"},
{"dl","video/dl"},
{"dmg","application/x-apple-diskimage"},
{"dms","application/x-dms"},
{"doc","application/msword"},
{"docm","application/vnd.ms-word.document.macroEnabled.12"},
{"docx","application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
{"dot","application/msword"},
{"dotm","application/vnd.ms-word.template.macroEnabled.12"},
{"dotx","application/vnd.openxmlformats-officedocument.wordprocessingml.template"},
{"d","text/x-dsrc"},
{"dvi","application/x-dvi"},
{"dv","video/dv"},
{"dx","chemical/x-jcamp-dx"},
{"dxr","application/x-director"},
{"emb","chemical/x-embl-dl-nucleotide"},
{"embl","chemical/x-embl-dl-nucleotide"},
{"eml","message/rfc822"},
{"ent","chemical/x-ncbi-asn1-ascii"},
{"ent","chemical/x-pdb"},
{"eot","application/vnd.ms-fontobject"},
{"eps2","application/postscript"},
{"eps3","application/postscript"},
{"eps","application/postscript"},
{"epsf","application/postscript"},
{"epsi","application/postscript"},
{"erf","image/x-epson-erf"},
{"es","application/ecmascript"},
{"etx","text/x-setext"},
{"exe","application/x-msdos-program"},
{"ez","application/andrew-inset"},
{"fb","application/x-maker"},
{"fbdoc","application/x-maker"},
{"fch","chemical/x-gaussian-checkpoint"},
{"fchk","chemical/x-gaussian-checkpoint"},
{"fig","application/x-xfig"},
{"flac","audio/flac"},
{"fli","video/fli"},
{"flv","video/x-flv"},
{"fm","application/x-maker"},
{"frame","application/x-maker"},
{"frm","application/x-maker"},
{"gal","chemical/x-gaussian-log"},
{"gam","chemical/x-gamess-input"},
{"gamin","chemical/x-gamess-input"},
{"gan","application/x-ganttproject"},
{"gau","chemical/x-gaussian-input"},
{"gcd","text/x-pcs-gcd"},
{"gcf","application/x-graphing-calculator"},
{"gcg","chemical/x-gcg8-sequence"},
{"gen","chemical/x-genbank"},
{"gf","application/x-tex-gf"},
{"gif","image/gif"},
{"gjc","chemical/x-gaussian-input"},
{"gjf","chemical/x-gaussian-input"},
{"gl","video/gl"},
{"gnumeric","application/x-gnumeric"},
{"gpt","chemical/x-mopac-graph"},
{"gsf","application/x-font"},
{"gsm","audio/x-gsm"},
{"gtar","application/x-gtar"},
{"hdf","application/x-hdf"},
{"hh","text/x-c++hdr"},
{"hin","chemical/x-hin"},
{"hpp","text/x-c++hdr"},
{"hqx","application/mac-binhex40"},
{"hs","text/x-haskell"},
{"hta","application/hta"},
{"htc","text/x-component"},
{"h","text/x-chdr"},
{"h++","text/x-c++hdr"},
{"html","text/html"},
{"htm","text/html"},
{"hwp","application/x-hwp"},
{"hxx","text/x-c++hdr"},
{"ica","application/x-ica"},
{"ice","x-conference/x-cooltalk"},
{"ico","image/vnd.microsoft.icon"},
{"ics","text/calendar"},
{"icz","text/calendar"},
{"ief","image/ief"},
{"iges","model/iges"},
{"igs","model/iges"},
{"iii","application/x-iphone"},
{"info","application/x-info"},
{"inp","chemical/x-gamess-input"},
{"ins","application/x-internet-signup"},
{"iso","application/x-iso9660-image"},
{"isp","application/x-internet-signup"},
{"ist","chemical/x-isostar"},
{"istr","chemical/x-isostar"},
{"jad","text/vnd.sun.j2me.app-descriptor"},
{"jam","application/x-jam"},
{"jar","application/java-archive"},
{"java","text/x-java"},
{"jdx","chemical/x-jcamp-dx"},
{"jmz","application/x-jmol"},
{"jng","image/x-jng"},
{"jnlp","application/x-java-jnlp-file"},
{"jpeg","image/jpeg"},
{"jpe","image/jpeg"},
{"jpg","image/jpeg"},
{"js","application/javascript"},
{"json","application/json"},
{"kar","audio/midi"},
{"key","application/pgp-keys"},
{"kil","application/x-killustrator"},
{"kin","chemical/x-kinemage"},
{"kml","application/vnd.google-earth.kml+xml"},
{"kmz","application/vnd.google-earth.kmz"},
{"kpr","application/x-kpresenter"},
{"kpt","application/x-kpresenter"},
{"ksp","application/x-kspread"},
{"kwd","application/x-kword"},
{"kwt","application/x-kword"},
{"latex","application/x-latex"},
{"lha","application/x-lha"},
{"lhs","text/x-literate-haskell"},
{"lin","application/bbolin"},
{"lsf","video/x-la-asf"},
{"lsx","video/x-la-asf"},
{"ltx","text/x-tex"},
{"ly","text/x-lilypond"},
{"lyx","application/x-lyx"},
{"lzh","application/x-lzh"},
{"lzx","application/x-lzx"},
{"m3g","application/m3g"},
{"m3u8","application/x-mpegURL"},
{"m3u","audio/mpegurl"},
{"m3u","audio/x-mpegurl"},
{"m4a","audio/mpeg"},
{"maker","application/x-maker"},
{"man","application/x-troff-man"},
{"mbox","application/mbox"},
{"mcif","chemical/x-mmcif"},
{"mcm","chemical/x-macmolecule"},
{"md5","application/x-md5"},
{"mdb","application/msaccess"},
{"me","application/x-troff-me"},
{"mesh","model/mesh"},
{"mid","audio/midi"},
{"midi","audio/midi"},
{"mif","application/x-mif"},
{"mkv","video/x-matroska"},
{"mm","application/x-freemind"},
{"mmd","chemical/x-macromodel-input"},
{"mmf","application/vnd.smaf"},
{"mml","text/mathml"},
{"mmod","chemical/x-macromodel-input"},
{"mng","video/x-mng"},
{"moc","text/x-moc"},
{"mol2","chemical/x-mol2"},
{"mol","chemical/x-mdl-molfile"},
{"moo","chemical/x-mopac-out"},
{"mop","chemical/x-mopac-input"},
{"mopcrt","chemical/x-mopac-input"},
{"movie","video/x-sgi-movie"},
{"mov","video/quicktime"},
{"mp2","audio/mpeg"},
{"mp3","audio/mpeg"},
{"mp4","video/mp4"},
{"mpc","chemical/x-mopac-input"},
{"mpega","audio/mpeg"},
{"mpeg","video/mpeg"},
{"mpe","video/mpeg"},
{"mpga","audio/mpeg"},
{"mpg","video/mpeg"},
{"mph","application/x-comsol"},
{"mpv","video/x-matroska"},
{"ms","application/x-troff-ms"},
{"msh","model/mesh"},
{"msi","application/x-msi"},
{"mvb","chemical/x-mopac-vib"},
{"mxf","application/mxf"},
{"mxu","video/vnd.mpegurl"},
{"nb","application/mathematica"},
{"nbp","application/mathematica"},
{"nc","application/x-netcdf"},
{"nef","image/x-nikon-nef"},
{"nwc","application/x-nwc"},
{"o","application/x-object"},
{"oda","application/oda"},
{"odb","application/vnd.oasis.opendocument.database"},
{"odc","application/vnd.oasis.opendocument.chart"},
{"odf","application/vnd.oasis.opendocument.formula"},
{"odg","application/vnd.oasis.opendocument.graphics"},
{"odi","application/vnd.oasis.opendocument.image"},
{"odm","application/vnd.oasis.opendocument.text-master"},
{"odp","application/vnd.oasis.opendocument.presentation"},
{"ods","application/vnd.oasis.opendocument.spreadsheet"},
{"odt","application/vnd.oasis.opendocument.text"},
{"oga","audio/ogg"},
{"ogg","audio/ogg"},
{"ogv","video/ogg"},
{"ogx","application/ogg"},
{"old","application/x-trash"},
{"one","application/onenote"},
{"onepkg","application/onenote"},
{"onetmp","application/onenote"},
{"onetoc2","application/onenote"},
{"orc","audio/csound"},
{"orf","image/x-olympus-orf"},
{"otg","application/vnd.oasis.opendocument.graphics-template"},
{"oth","application/vnd.oasis.opendocument.text-web"},
{"otp","application/vnd.oasis.opendocument.presentation-template"},
{"ots","application/vnd.oasis.opendocument.spreadsheet-template"},
{"ott","application/vnd.oasis.opendocument.text-template"},
{"oza","application/x-oz-application"},
{"p7r","application/x-pkcs7-certreqresp"},
{"pac","application/x-ns-proxy-autoconfig"},
{"pas","text/x-pascal"},
{"patch","text/x-diff"},
{"pat","image/x-coreldrawpattern"},
{"pbm","image/x-portable-bitmap"},
{"pcap","application/vnd.tcpdump.pcap"},
{"pcf","application/x-font"},
{"pcf.Z","application/x-font"},
{"pcx","image/pcx"},
{"pdb","chemical/x-pdb"},
{"pdf","application/pdf"},
{"pfa","application/x-font"},
{"pfb","application/x-font"},
{"pgm","image/x-portable-graymap"},
{"pgn","application/x-chess-pgn"},
{"pgp","application/pgp-encrypted"},
{"pk","application/x-tex-pk"},
{"pls","audio/x-scpls"},
{"pl","text/x-perl"},
{"pm","text/x-perl"},
{"png","image/png"},
{"pnm","image/x-portable-anymap"},
{"potm","application/vnd.ms-powerpoint.template.macroEnabled.12"},
{"pot","text/plain"},
{"potx","application/vnd.openxmlformats-officedocument.presentationml.template"},
{"ppam","application/vnd.ms-powerpoint.addin.macroEnabled.12"},
{"ppm","image/x-portable-pixmap"},
{"pps","application/vnd.ms-powerpoint"},
{"ppsm","application/vnd.ms-powerpoint.slideshow.macroEnabled.12"},
{"ppsx","application/vnd.openxmlformats-officedocument.presentationml.slideshow"},
{"ppt","application/vnd.ms-powerpoint"},
{"pptm","application/vnd.ms-powerpoint.presentation.macroEnabled.12"},
{"pptx","application/vnd.openxmlformats-officedocument.presentationml.presentation"},
{"prf","application/pics-rules"},
{"prt","chemical/x-ncbi-asn1-ascii"},
{"ps","application/postscript"},
{"psd","image/x-photoshop"},
{"p","text/x-pascal"},
{"pyc","application/x-python-code"},
{"pyo","application/x-python-code"},
{"py","text/x-python"},
{"qgs","application/x-qgis"},
{"qtl","application/x-quicktimeplayer"},
{"qt","video/quicktime"},
{"ra","audio/x-pn-realaudio"},
{"ra","audio/x-realaudio"},
{"ram","audio/x-pn-realaudio"},
{"rar","application/rar"},
{"ras","image/x-cmu-raster"},
{"rb","application/x-ruby"},
{"rd","chemical/x-mdl-rdfile"},
{"rdf","application/rdf+xml"},
{"rdp","application/x-rdp"},
{"rgb","image/x-rgb"},
{"rm","audio/x-pn-realaudio"},
{"roff","application/x-troff"},
{"ros","chemical/x-rosdal"},
{"rpm","application/x-redhat-package-manager"},
{"rss","application/x-rss+xml"},
{"rtf","application/rtf"},
{"rtx","text/richtext"},
{"rxn","chemical/x-mdl-rxnfile"},
{"scala","text/x-scala"},
{"sce","application/x-scilab"},
{"sci","application/x-scilab"},
{"sco","audio/csound"},
{"scr","application/x-silverlight"},
{"sct","text/scriptlet"},
{"sd2","audio/x-sd2"},
{"sda","application/vnd.stardivision.draw"},
{"sdc","application/vnd.stardivision.calc"},
{"sd","chemical/x-mdl-sdfile"},
{"sdd","application/vnd.stardivision.impress"},
{"sdf","application/vnd.stardivision.math"},
{"sdf","chemical/x-mdl-sdfile"},
{"sds","application/vnd.stardivision.chart"},
{"sdw","application/vnd.stardivision.writer"},
{"ser","application/java-serialized-object"},
{"sfv","text/x-sfv"},
{"sgf","application/x-go-sgf"},
{"sgl","application/vnd.stardivision.writer-global"},
{"sha1","application/x-sha1"},
{"sh","application/x-sh"},
{"shar","application/x-shar"},
{"shp","application/x-qgis"},
{"sh","text/x-sh"},
{"shtml","text/html"},
{"shx","application/x-qgis"},
{"sid","audio/prs.sid"},
{"sig","application/pgp-signature"},
{"sik","application/x-trash"},
{"silo","model/mesh"},
{"sis","application/vnd.symbian.install"},
{"sisx","x-epoc/x-sisx-app"},
{"sit","application/x-stuffit"},
{"sitx","application/x-stuffit"},
{"skd","application/x-koan"},
{"skm","application/x-koan"},
{"skp","application/x-koan"},
{"skt","application/x-koan"},
{"sldm","application/vnd.ms-powerpoint.slide.macroEnabled.12"},
{"sldx","application/vnd.openxmlformats-officedocument.presentationml.slide"},
{"smi","application/smil"},
{"smil","application/smil"},
{"snd","audio/basic"},
{"spc","chemical/x-galactic-spc"},
{"spl","application/futuresplash"},
{"spl","application/x-futuresplash"},
{"spx","audio/ogg"},
{"sql","application/x-sql"},
{"src","application/x-wais-source"},
{"srt","text/plain"},
{"stc","application/vnd.sun.xml.calc.template"},
{"std","application/vnd.sun.xml.draw.template"},
{"sti","application/vnd.sun.xml.impress.template"},
{"stl","application/sla"},
{"stw","application/vnd.sun.xml.writer.template"},
{"sty","text/x-tex"},
{"sv4cpio","application/x-sv4cpio"},
{"sv4crc","application/x-sv4crc"},
{"svg","image/svg+xml"},
{"svgz","image/svg+xml"},
{"sw","chemical/x-swissprot"},
{"swf","application/x-shockwave-flash"},
{"swfl","application/x-shockwave-flash"},
{"sxc","application/vnd.sun.xml.calc"},
{"sxd","application/vnd.sun.xml.draw"},
{"sxg","application/vnd.sun.xml.writer.global"},
{"sxi","application/vnd.sun.xml.impress"},
{"sxm","application/vnd.sun.xml.math"},
{"sxw","application/vnd.sun.xml.writer"},
{"t","application/x-troff"},
{"tar","application/x-tar"},
{"taz","application/x-gtar-compressed"},
{"tcl","application/x-tcl"},
{"tcl","text/x-tcl"},
{"texi","application/x-texinfo"},
{"texinfo","application/x-texinfo"},
{"tex","text/x-tex"},
{"text","text/plain"},
{"tgf","chemical/x-mdl-tgf"},
{"tgz","application/x-gtar-compressed"},
{"thmx","application/vnd.ms-officetheme"},
{"tiff","image/tiff"},
{"tif","image/tiff"},
{"tk","text/x-tcl"},
{"tm","text/texmacs"},
{"torrent","application/x-bittorrent"},
{"tr","application/x-troff"},
{"tsp","application/dsptype"},
{"ts","video/MP2T"},
{"tsv","text/tab-separated-values"},
{"txt","text/plain"},
{"udeb","application/x-debian-package"},
{"uls","text/iuls"},
{"ustar","application/x-ustar"},
{"val","chemical/x-ncbi-asn1-binary"},
{"vcd","application/x-cdlink"},
{"vcf","text/x-vcard"},
{"vcs","text/x-vcalendar"},
{"vmd","chemical/x-vmd"},
{"vms","chemical/x-vamas-iso14976"},
{"vrml","model/vrml"},
{"vrml","x-world/x-vrml"},
{"vrm","x-world/x-vrml"},
{"vsd","application/vnd.visio"},
{"wad","application/x-doom"},
{"wav","audio/x-wav"},
{"wax","audio/x-ms-wax"},
{"wbmp","image/vnd.wap.wbmp"},
{"wbxml","application/vnd.wap.wbxml"},
{"webm","video/webm"},
{"wk","application/x-123"},
{"wma","audio/x-ms-wma"},
{"wmd","application/x-ms-wmd"},
{"wmlc","application/vnd.wap.wmlc"},
{"wmlsc","application/vnd.wap.wmlscriptc"},
{"wmls","text/vnd.wap.wmlscript"},
{"wml","text/vnd.wap.wml"},
{"wm","video/x-ms-wm"},
{"wmv","video/x-ms-wmv"},
{"wmx","video/x-ms-wmx"},
{"wmz","application/x-ms-wmz"},
{"woff","application/x-font-woff"},
{"wp5","application/vnd.wordperfect5.1"},
{"wpd","application/vnd.wordperfect"},
{"wrl","model/vrml"},
{"wrl","x-world/x-vrml"},
{"wsc","text/scriptlet"},
{"wvx","video/x-ms-wvx"},
{"wz","application/x-wingz"},
{"x3db","model/x3d+binary"},
{"x3d","model/x3d+xml"},
{"x3dv","model/x3d+vrml"},
{"xbm","image/x-xbitmap"},
{"xcf","application/x-xcf"},
{"xcos","application/x-scilab-xcos"},
{"xht","application/xhtml+xml"},
{"xhtml","application/xhtml+xml"},
{"xlam","application/vnd.ms-excel.addin.macroEnabled.12"},
{"xlb","application/vnd.ms-excel"},
{"xls","application/vnd.ms-excel"},
{"xlsb","application/vnd.ms-excel.sheet.binary.macroEnabled.12"},
{"xlsm","application/vnd.ms-excel.sheet.macroEnabled.12"},
{"xlsx","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
{"xlsx","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
{"xlt","application/vnd.ms-excel"},
{"xltm","application/vnd.ms-excel.template.macroEnabled.12"},
{"xltx","application/vnd.openxmlformats-officedocument.spreadsheetml.template"},
{"xltx","application/vnd.openxmlformats-officedocument.spreadsheetml.template"},
{"xml","application/xml"},
{"xpi","application/x-xpinstall"},
{"xpm","image/x-xpixmap"},
{"xsd","application/xml"},
{"xsl","application/xml"},
{"xspf","application/xspf+xml"},
{"xtel","chemical/x-xtel"},
{"xul","application/vnd.mozilla.xul+xml"},
{"xwd","image/x-xwindowdump"},
{"xyz","chemical/x-xyz"},
{"zip","application/zip"},
{"zmt","chemical/x-mopac-input"}};

private final HashMap<String, String> m_mapping;
private static MimeType instance;

private MimeType()
{
m_mapping = new HashMap<String, String>();

for(int i = 0; i < MIME_MAPPING.length; i++)
{
m_mapping.put(MIME_MAPPING[i][0], MIME_MAPPING[i][1]);
}
}

private static MimeType getInstance()
{
if(instance == null)
instance = new MimeType();

return instance;
}

/**
* Returns a mime given the extension, or the default if none is found.
* @param ext - the extension to lookup the mime based upon.
* @return
*/
private String lookupMapping(String ext)
{
String mime = m_mapping.get(ext);

if(mime == null)
return DEFAULT_MIME;

return mime;
}

/**
* Looks up a mimetype.
*
* @param path - the path to look at the mime for.
* @return - the mime of the path.
*/
public static String getMime(String path)
{
String ext = path.substring(path.lastIndexOf('.') + 1);
return getInstance().lookupMapping(ext);
}
}

Tuesday, December 18, 2012

Javascript mimetype detector - Tool Tuesday

Warning: Shameless self-promotion.
As I noted in my post about the proliferation of app formats, HTML5/Javascript are becoming more and more viable languages to build desktop applications in, because they natively work on phones, tablets, and desktops; as well as nearly all types of operating systems without os specific instructions.
One of the things I recently needed for a project was a way to detect the mime of user uploaded files, but I didn't want to use the builtin browser detection; as this system would have to work on file names that had also been saved as binary blobs in a database.
I came up with this solution.

Usage

Get a list of mimes by extension.
jsmime.getMimesByExt("exe") --> ["application/x-msdos-program"]
Get a list of mimes by path.
jsmime.getMimesByPath("C:\Some\Path\File.exe") --> ["application/x-msdos-program"]
Check to see if a path (or extension) is of the type given.
jsmime.pathIsMime("C:\Some\Path\File.exe", "application/x-msdos-program") --> true
The default returned for unknown extensions is:
["application/octet-stream", "text/plain"]

Monday, December 17, 2012

Inexpensive Wifi Extender

If you're looking for a high intensity directional antaenna to get WiFi from point to point, the Directional Bi Quad at Seattle Wireless seems to be a great option. Easy to build, cheap, and made from materials already found in your home!
Directional Bi Quad
Directional Bi Quad

Potential Improvements

  • Encase the thing in a tupperware to keep it rainproof.
  • Print a mounting bracket so pointing isn't so difficult.

Sunday, December 16, 2012

Minimalist Design - Sunday Reflection

The past year has brought some incredible leaps in a minimalist look in application design. It seems somewhat related to The New Aesthetic; which is the result of mixing the digital world with the physical one.
The trend can be seen throughout Google's ecosystem. Android has become sleek and dark, while it's web sites have become high contrast and simple. Even the YouTube player has become very simple, ditching it's subtle gradients for a plain matte gray.

Microsoft has also embraced the style in its newly released Windows 8. The chrome and bloat from Windows 7 is (mostly) gone, leaving you with straight lines, high contrast colors, and few distracting graphics.
As technology becomes more and more a part of our lives, this will hopefully become more common. By stripping away the graphics and the visual candy software becomes much more understandable and usable.

Advantages of Minimalist Design

  • No time spent wondering what icons do.
  • Less time worrying about visual consistancy.
  • Your software ages far better.
  • Less work maintaining software.

Saturday, December 15, 2012

Friday Link List

Operating Systems

Algorithms

  • SamSnyder.com has a great page filled with links to algorithms and data structures of all varieties.

Making

  • Thingiverse has an awesome automatic transmission model that can be 3D printed to your desktop.

Friday, December 14, 2012

Netcat - Tool Tuesday

Netcat (nc) is an invaluable tool that makes working with network connections as easy as working with text files (for those of you on UNIX, that is pretty dang easy!)

Set Up a Chat Server

This is a very quick way to set up a person to person chat over the Internet. It isn't encrypted, but it is simple and always works.
Server
# nc -l 8080
Client (replace the IP with any other host)
# nc 127.0.0.1 8080

Clone a Harddisk Over the Web

This is a great free and dirty replacement to Norton Ghost which helps you clone a harddisk from one machine to another.
Machine to Clone to
# nc -l 2222 > /dev/sdb
Machine to Clone From
# nc FROM_HOSTNAME 2222 < /dev/sda
(Note that if a quit character is encountered somewhere in the disk it will kill netcat.)

Transfer a File

Need to transfer a file between a computer but don't have SSH or FTP?
Sender
# nc  -l 8080 < /path/to/some.file
Receiver
# nc localhost 8080 > output.file 

See Web Headers

Ever want to see what your web-browser is sending out as headers?
Server
# nc -l 8080
Then point your web-browser to http://localhost:8080/ and watch the netcat window show what your browser is telling all sites you visit.
Example Output
GET / HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:17.0) Gecko/20100101 Firefox/17.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
Cookie: wp-settings-time-1=1348281280

Leave Yourself a Backdoor

Warning, this will totally leave your system open to attackers (and some netcat builds don't even allow this flag for that reason, like Ubuntu's.)
Server
# nc -l 8080 -e /bin/bash
With this example, as soon as you connect, you'll be communicating with a BASH instance running at whatever security level you opened nc with. If you want your users to at least have to authenticate, use /bin/login instead.

Run a Portscan

If you don't have nmap installed, and don't want to build something in Python, you can quickly tell which ports are being used on a host using the following:
# nc -zv localhost 1-5000 2>&1 | grep succeeded
This command checks ports 1-5000 on localhost, and looks for any ports that are open. The reason we redirect stderr to stdout is grep only works on stdout, while nc outputs the information we want on stderr.

Monday, December 10, 2012

Cookies! - Maker Monday, Holiday Edition

For years my grandmother would make all of her children large tins of cookies for Christmas; before she moved and stopped making them, I made sure to get her recipes. The secret is either love, or butter, I'm still not entirely sure. What I am sure about is how well they can smooth over rough family situations:
 

Butter Cookies:

Bake Time
10 min / batch
Bake Temp
375°
Number
4 dozen (48)
Prep Time
15 min

Ingredients:

  • 1 Cup (2 sticks) of Butter
  • ½ Cup Sugar
  • 2 Egg Yolks
  • 2 Cups of Sifted Flour
  • ½ Teaspoon Vanilla (or other flavoring of your choice)

Optional Ingredients:

  • Food Coloring
  • Cookie Sprinkles

Directions:

  1. Preheat oven to 375° F
  2. Soften butter.
  3. Cream together butter and sugar.
  4. Add egg yolks, mixing well.
  5. Gradually add flour, mixing after each addition.
  6. Add flavoring and food coloring of your choice.
  7. Follow one of the two methods below.
  • Log Method
    • Divide in half.
    • Wrap in waxed paper.
    • Refrigerate for 1 hour or until firm.
    • Shape each half into 15-inch log; wrap in wax paper
    • Cut cookies off of log.
  • Cookie Press
    • Use your cookie press normally.
  1. Put dough on cookie sheet, around two inches apart.
  2. Bake in oven for ten minutes or until lightly brown around edges.
  3. Remove from baking sheet immediately.
  4. Let cool on wire rack.

 

Grandmothers Oatmeal Cookies:

Bake Time
10 min / batch
Bake Temp
350°
Number
4 dozen (48)
Prep Time
30 min + 1 hour stand time

Ingredients:

  • 3 Eggs
  • 1 Cup Nuts
  • 1 Cup Raisins
  • 1 Tbsp. Vanilla
  • 1 Cup Butter
  • 1 Cup Brown Sugar
  • 1 Cup White Sugar
  • 2 ½ Cup Flour
  • 2 Teaspoons Baking Soda
  • 1 Teaspoon Cinnamon
  • 2 Cups Quick Oatmeal

Directions:

  1. Beat eggs.
  2. Combine Eggs, Raisins and Vanilla, Let stand 1 hour.
  3. Preheat Oven To 350°.
  4. Cream Butter and sugar.
  5. Add flour, baking soda, and cinnamon.
  6. Stir in oatmeal, nuts, and raisins.
  7. Roll into 1” balls, flatten slightly, then bake for around 10 min.

    Old Fashioned Oatmeal Cookies:

    Bake Time
    12 min / batch
    Bake Temp
    375°
    Number
    4 dozen (48)
    Prep Time
    15 min

    Ingredients:

  8. 2 Cups of Sifted Flour
  9. 1 Teaspoon Soda
  10. 1 Teaspoon Salt
  11. 1 ½ Teaspoons Cinnamon
  12. 2 Cups of Quick Cooking Oatmeal
  13. ½ Cups of Brown Sugar, Firmly Packed
  14. ½ Cup Granulated Sugar
  15. 1 Cup Shortening (Room Temp)
  16. 2 Eggs, Unbeaten
  17. 1/3 Cup Milk (Sweet or Sour)
  18. 1 Teaspoon Vanilla
  19. 1 Cup raisins or dates
  20. ¾ Cup chopped nuts

Directions:

  1. Preheat oven to 375°.
  2. Stir together, flour, soda, salt, cinnamon.
  3. Add, oatmeal, sugar, brown sugar, shortening, eggs, milk, vanilla.
  4. Beat on medium speed until blended (around 2 min).
  5. Scrape bowl while beating.
  6. Add raisins, and nuts.
  7. Beat on low speed until blended.
  8. Bake on greased sheet around two inches apart.
  9. Cook for 12 minutes, or until browned.


Original Toll House Cookies:

Bake Time
10 min / batch
Bake Temp
375°
Number
7.5 Dozen
Prep Time
15 min

Ingredients:

  • 1 Cup Shortening
  • ¾ Cup Granulated Sugar
  • ¾ Cup Firmly Packed Brown Sugar
  • 1 Teaspoon Vanilla
  • ½ Teaspoon Water
  • 2 Eggs
  • 2 ¼ Cups Flour
  • 1 Teaspoon Baking Soda
  • 1 Teaspoon Salt
  • 12 Ounce Package Of Semi Sweet Chocolate Morsels
  • 1 Cup Chopped Nuts

Directions:

  1. Preheat oven to 375°.
  2. Combine shortening, sugar, vanilla, and water.
  3. Beat until creamy.
  4. Beat in egg.
  5. Add all dry ingredients except nuts and chocolate, mix well.
  6. Mix in chocolate chips and nuts at a lower speed.
  7. Drop tablespoonfuls onto cookie sheet.
  8. Bake for 10 – 12 minutes.


Sugar Cookies:

Bake Time
8 -10 min / batch
Bake Temp
375°
Number
4 dozen (48)
Prep Time
15 min + refrigeration time

Ingredients:

  • 1 ½ Cups Powdered Sugar
  • 1 Cup Butter
  • 1 Egg
  • 1 Teaspoon Vanilla
  • ½ Teaspoon Almond
  • 2 ½ Cups Flour
  • 1 Teaspoon Cream Of Tartar
  • 1 Teaspoon Baking Soda

Directions:

  1. Cream together butter and sugar.
  2. Add egg and flavoring.
  3. Stir in dry ingredients.
  4. Chill until workable.
  5. Preheat oven to 375°.
  6. Bake 8 – 10 minutes.

Sunday, December 9, 2012

Drowning in Web App Formats

With the rise of HTML5, (and the web being, arguably, the best defined MVC system around) there has been an explosion of technologies wanting to take advantage of it for apps, notably:
Firefox RT, Chrome Apps, W3C widgets/Tizen Apps, and Opera Apps all fall in to a simple group consisting of variations on a theme. They're all HTML, CSS, and JS files packed in a zip file with a manifest. The only real difference is the manifest format (excluding some features where APIs are different).

My point is that if someone cared to create a small utility they could make development much simpler for the rest of us wanting to write true cross-platform applications. Perhaps Tizen for desktops. In the meantime, keep an eye on my github, as I may have a good reason to write something that can convert sites to standalone apps.

Happy Grace Hopper Day 2012!

Grace Hopper (December 9, 1906 – January 1, 1992) was a US Naval officer and inventor of the first compiler and machine-independent programming language.

Friday, December 7, 2012

Friday Link List

Operating Systems

Haiku, a BeOS clone is near it's first release after eleven years. The article gives a nice rundown of the project for those not in the know.

Phenomina

The Listserve is an ongoing lottery consisting of a group of people who have joined it; every day, a randomly chosen one gets to send a message to the whole group (it eventually hopes to have a million people, currently it is at around twenty-two thousand)

McSweeneys has a positively delightful short look at the future of used (e)book stores.
"Why, hello there!—I was just appraising some rare PDFs in the back room when I heard you come in. Feel free to peruse our inventory, and if you have any questions, please allow me—one of the world’s foremost authorities on and purveyors of fine electronic books—to act as your steward through the wonderfully esoteric world of antique eBook collecting."

Algorithms

Jeff Moser gives a great account of the math behind the SSL cryptography that all happens within a few milliseconds of you connecting to a secure website.

Making

Thingiverse now allows users to "collect" items together in to groups, and also allows others to view these groups. No more searching around for parts that will work together!