Binary Tree Sort in Python
I’m writing a little module in python that contains lots of sorting algorithms (which can be found on my GitHub: here), and one i found particularly fun was the Binary Tree Sort.
This implements a “Node” Class to form the tree. Each Node has data and a left and right value. Left and Right should be other nodes or None. It has a “flatten” method that recursively flattens the tree into a sorted list. It makes use of a method, “_concatList”, that I had originally written for implementing the Quick Sort, but it ended up working quite well here too.
The sort itself is very simple. It loops through the list and inserts each element to a tree, and finally flattens it.
# Binary Tree Node class Node: left, right, data = None, None, 0 def __init__(self, data): self.left = None self.right = None self.data = data # add data to the tree def insert(self, data): # return false if the data is a duplicate if data == self.data: return false # if data is less than the current node go left elif data < self.data: # if no data here, make a new node if self.left == None: self.left = Node(data) # else try the same on its left child else: self.left.insert(data) # if its greater, go right else: # if no data here, make a new node if self.right == None: self.right = Node(data) # else try the same on its right child else: self.right.insert(data) # flatten a node into a list def flatten(self): # if no children, return this nodes data as a list if self.left == None and self.right == None: return [self.data] # create empty list li = [] # append the first list if self.left is not None: li.extend(self.left.flatten()) # append data li.append(self.data) # append the second list if self.right is not None: li.extend(self.right.flatten()) return li # Binary Tree Sort def BinaryTreeSort(li): # create the root node with the first element root = Node(li[0]) # add each element to the tree for i in xrange(1, len(li)): root.insert(li[i]) #flatten the tree return root.flatten() # Concatenate two sorted lists # used for Binary Search Tree and Quick Sort def _concatList(l1, a, l2): # create a new list li = [] if l1 is not None: # append each of the elements from l1 for l in l1: li.append(l) else: pass if a is not None: # append the middle if there is one li.append(a) else: pass if l2 is not None: # append each of the elements from l2 for l in l2: li.append(l) else: pass return li
Here’s my test:
>>> Disorder.BinaryTreeSort([5,2,3,8,1,9,15,4,18])
[1, 2, 3, 4, 5, 8, 9, 15, 18]
Open For Business
Me and my great friend CBallenar have decided to open ourselves up as a freelance web development team, and we are looking for small to medium sized web development projects!
I have been developing PHP & MySQL websites and applications with HTML, CSS for 5 years now (since the age of 14) and added jQuery for AJAX and animation into the mix two years ago. Most of them were personal projects that got trashed for one reason or another, but I have plenty of experience with PHP. My big published project is Aud, an HTML audio player and playlist manager. My professional work is a few internal websites in different companies. I have also worked with Python, specifically Django.
If you have a project for us, please contact me at the.anti.9atgmaildotcom
Using C# Reflection for a simple Plugin System
.NET Reflection is a very, very powerful tool. One thing I used it for is making a basic plugin system for my web server.
I needed some sort of way to know what assemblies to load, so I used a configuration file with a simple format to parse. For each module I wanted to load, I put a line that was the path to the DLL, preceded by the word “mod”
mod C:\modules\module.dll
I figured that me or someone else might write a plugin that used another external library, so I used “dep” to mark DLL’s that were needed for the modules.
dep C:\dependencies\dependency.dll
When the server starts up, it reads through this configuration file, takes all the lines that start with mod or dep and assigns puts their path in module and dependency ArrayList’s respectively. Once the config file is read, it goes through and loads the dependencies first.
Assembly.LoadFile(DependencyPath);
Loading the modules is a little more complicated. For this I created a simple Module class to hold some information I would need about it, and be able to give me access to the Assembly object that loading the dll returns. In this case, when I load the module, I want to go into a class called ModuleMap that contains the url mapping info that I require for the plugin, and call its GetUrlMap method.
public class Module
{
public string ModulePath;
public string ModuleNamespace;
public Assembly ModuleAssembly;
public List<UrlMapItem> UrlMap;
public Module(string modulepath)
{
ModulePath = modulepath;
}
public void Load()
{
if (!File.Exists(ModulePath))
{
throw new NoSuchModuleException("Error: No such module at '" + ModulePath + "'.");
}
ModuleAssembly = Assembly.LoadFile(ModulePath);
int lastslash = ModulePath.LastIndexOf(@"\");
string assemblynamespace = ModulePath.Substring(lastslash+1, ModulePath.LastIndexOf('.') - lastslash-1);
ModuleNamespace = assemblynamespace;
Type t = ModuleAssembly.GetType(assemblynamespace+".ModuleMap");
if (t != null)
{
MethodInfo m = t.GetMethod("GetUrlMap");
if (m != null)
{
UrlMap = (List<UrlMapItem>)m.Invoke(null, (new object[]{}));
}
else
{
throw new InvalidModuleMapException("Error: The ModuleMap class is incorrect!");
}
}
else
{
throw new InvalidModuleMapException("Error: The ModuleMap class is missing!");
}
}
}
When I use the Invoke() method, I passed it two arguments. In this case, since it is a static method, the first argument is null. The second argument is an object array that contains the arguments for the invoked method. The Invoke() method returns an instance of an object class, so I casted it into the object type I needed, which in this case was a List.
Now, that UrlMapClass, that I now have a list of, contains two pieces of information:
- A url
- A method with the full namespace/class path (ex. “testnamespace.testclass.methodname”)
Then I took a Hashtable and used the namespace.class.method path as the key, and the Module.ModuleAssembly as the value object. This way when I go to call it, I can enter the path that I know is being called, take the Assembly object, and do what I did before and call MethodInfo.Invoke().
Assembly assembly = (Assembly)ModuleList[methodnamespace];
Type t = assembly.GetType(method.Substring(0, method.LastIndexOf('.')));
MethodInfo m = t.GetMethod(method.Substring(method.LastIndexOf('.') + 1));
Page p = (Page)m.Invoke(null, (new object[] { rq }));
The method variable contained the whole method.class.methodname path and the methodnamespace variable contained just the namespace. To get the class for GetType() I used a substring of the whole namespace.class.methodname string that was from 0 to the last . which would give you just namespace.class.
This is a pretty simple example. I structured my plugin DLL’s in such a way that it gave me all the info I needed to call the corresponding methods in a very simple manner. There are obviously much more complex ways to do this.
Handling Multiple Connections: Asynchronous Network I/O with C#
Here is a little tutorial for handling multiple simultaneous connections in C#.
The trick to doing asynchronous I/O with C# sockets is the AsyncCallback. You call the socket.Begin* methods, passing them an AsyncCallback object (which is a method) and a state object. The state object you pass is the socket itself. When the callback is called, it is passed an IAsyncResult. This contains the AsyncState, which is the state object you passed. You can cast it into a Socket and continue processing. Now we can get to the code:
The first thing we need is to include the proper references:
using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading;
You may be wondering why we need System.Threading. This is because we need a ManualResetEvent. This is used to signal events between the methods.
We’ll now write a class called ServerRunner, which starts the serving by its method Run(). It has 3 other methods, AcceptCon(), SendData(), and ReceiveData(). All 3 methods take an IAsyncResult “iar”.
First we need a couple of class variables
private Byte[] data = new Byte[2048];
private int size = 2048;
private Socket server;
static ManualResetEvent allDone = new ManualResetEvent(false);
This gives us some stuff for the actual transmission of the data, and of course the ManualResetEvent that I explained earlier. Heres our Run method that starts everything:
public void Run()
{
try
{
server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint iep = new IPEndPoint(IPAddress.Any, 33333);
server.Bind(iep);
Console.WriteLine("Server initialized..");
server.Listen(100);
Console.WriteLine("Listening...");
while (true)
{
allDone.Reset();
server.BeginAccept(new AsyncCallback(AcceptCon), server);
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
This starts like any listening socket. Create an IPEndPoint and bind your server socket to it. Then call the listen method. Then you want to start an infinite loop calling the BeginAccept() method with the AsyncCallback and state object. Around it, you want your ManualResetEvent’s Reset() and WaitOne() methods. This makes it so it waits until the connection has actually been accepted and started to be dealt with before it can start to accept a new one. In the next method You’ll see the ManualResetEvent’s Set() method, which tells it that it is ok to continue to the next connection. Heres the AcceptCon() method we put as the AsyncCallback to the BeginAccpet()
void AcceptCon(IAsyncResult iar)
{
allDone.Set();
try
{
Socket oldserver = (Socket)iar.AsyncState;
Socket client = oldserver.EndAccept(iar);
Console.WriteLine(client.RemoteEndPoint.ToString() + " connected");
byte[] message = Encoding.ASCII.GetBytes("Welcome");
client.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(SendData), client);
}
catch (Exception)
{
Console.WriteLine("Connection closed..");
return;
}
}
In this method, first we call the ManualResetEvent’s Set() method, which tells it that we have gotten what we need. Then we cast the iar.AsyncState (the state object we passed into the method, which was a Socket) back to what it originally was so we can use it. This code sends a simple “Welcome” message to the client that connects. However you can choose to do whatever you want. We then call the BeginSend method, again with an AsyncCallback (this time to the SendData() method) and a state object (this time client socket).
void SendData(IAsyncResult iar)
{
try
{
Socket client = (Socket)iar.AsyncState;
int sent = client.EndSend(iar);
client.BeginReceive(data, 0, size, SocketFlags.None, new AsyncCallback(ReceiveData), client);
}
catch (Exception)
{
Console.WriteLine("Connection closed..");
return;
}
}
This method finishes off the send, and then starts to listen for more data by calling the ReceiveData() method as an AsyncCallback, again passing the client socket as a state object.
void ReceiveData(IAsyncResult iar)
{
try
{
Socket client = (Socket)iar.AsyncState;
int recv = client.EndReceive(iar);
if (recv == 0)
{
client.Close();
server.BeginAccept(new AsyncCallback(AcceptCon), server);
return;
}
string receivedData = Encoding.ASCII.GetString(data, 0, recv);
// process received data here
// decide what to send back
byte[] message2 = Encoding.ASCII.GetBytes("reply");
client.BeginSend(message2, 0, message2.Length, SocketFlags.None, new AsyncCallback(SendData), client);
}
catch (Exception)
{
Console.WriteLine("Connection closed..");
return;
}
}
This is where we do all the data handling. It takes in data, does what you need to do with the data, and sends back a response. In this method we check to see if the socket is done, in which case we close it, call BeginAccept again to continue listening, and return to end the method execution. This method doesn’t actually have any data handling in it, it simply sends the string “reply” as a response to every piece of data that comes in. But I left comments showing you where to put your methods to actually deal with the data and come up with a response. When we are done handling the data, we call the BeginSend, which sends off the data, and then goes back to receiving again. It continues until the connection is closed.
A small warning about this code: The only exception handling in here is to keep the server from crashing if the client disconnects unexpectedly. If you are planning to use this as any sort of production code, I suggest you put in much more detailed exception handling.
Well. There it is. It’s much simpler than I thought it was going to be, and it only requires those 3 methods really. Hope you can all put this to good use.
UPnP Tomfoolery – Using UPnP for peer-to-peer connections
I’m writing this post for two reasons:
- It is a pretty cool thing to do and very useful
- The amount of useful documentation and links you can find is very small
It took me about 12 hours of futsing with this and Googling things to get this correct. Most of my information actually came from bug reports of various open source projects that use UPnP for peer-to-peer connections.
I haven’t put much error checking in here, I want to keep the code short and as easy to understand as possible. I’ll leave that one up to the users to figure out.
To use this code, you must first call NAT.Discover(). This makes sure you have a UPnP device available. After that you can go ahead and Add and Delete ports as you wish. Heres the code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Xml;
using System.IO;
namespace enChatClient
{
public class NAT
{
static TimeSpan _timeout = new TimeSpan(0, 0, 0, 3);
public static TimeSpan TimeOut
{
get { return _timeout; }
set { _timeout = value; }
}
static string _descUrl, _serviceUrl, _eventUrl;
public static bool Discover()
{
System.Net.NetworkInformation.NetworkInterface nic = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()[0];
System.Net.NetworkInformation.GatewayIPAddressInformation gwInfo = nic.GetIPProperties().GatewayAddresses[0];
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
string req = "M-SEARCH * HTTP/1.1\r\n" +
"HOST: " + gwInfo.Address.ToString() + ":1900\r\n" +
"ST:upnp:rootdevice\r\n" +
"MAN:\"ssdp:discover\"\r\n" +
"MX:3\r\n\r\n";
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);
IPEndPoint endPoint = new
IPEndPoint(IPAddress.Parse(gwInfo.Address.ToString()), 1900);
client.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout, 5000);
byte[] q = Encoding.ASCII.GetBytes(req);
client.SendTo(q, q.Length, SocketFlags.None, endPoint);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint senderEP = (EndPoint)sender;
byte[] data = new byte[1024];
int recv = client.ReceiveFrom(data, ref senderEP);
string queryResponse = "";
queryResponse = Encoding.ASCII.GetString(data);
DateTime start = DateTime.Now;
string resp = queryResponse;
if (resp.Contains("upnp:rootdevice"))
{
resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9);
resp = resp.Substring(0, resp.IndexOf("\r")).Trim();
if (!string.IsNullOrEmpty(_serviceUrl = GetServiceUrl(resp)))
{
_descUrl = resp;
return true;
}
}
return false;
}
private static string GetServiceUrl(string resp)
{
XmlDocument desc = new XmlDocument();
try
{
desc.Load(WebRequest.Create(resp).GetResponse().GetResponseStream());
}
catch (Exception)
{
return null;
}
XmlNamespaceManager nsMgr = new XmlNamespaceManager(desc.NameTable);
nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0");
XmlNode typen = desc.SelectSingleNode("//tns:device/tns:deviceType/text()", nsMgr);
if (!typen.Value.Contains("InternetGatewayDevice"))
return null;
XmlNode node = desc.SelectSingleNode("//tns:service[tns:serviceType=\"urn:schemas-upnp-org:service:WANIPConnection:1\"]/tns:controlURL/text()", nsMgr);
if (node == null)
return null;
XmlNode eventnode = desc.SelectSingleNode("//tns:service[tns:serviceType=\"urn:schemas-upnp-org:service:WANIPConnection:1\"]/tns:eventSubURL/text()", nsMgr);
_eventUrl = CombineUrls(resp, eventnode.Value);
return CombineUrls(resp, node.Value);
}
private static string CombineUrls(string resp, string p)
{
int n = resp.IndexOf("://");
n = resp.IndexOf('/', n + 3);
return resp.Substring(0, n) + p;
}
public static void ForwardPort(int port, ProtocolType protocol, string description)
{
if (string.IsNullOrEmpty(_serviceUrl))
throw new Exception("No UPnP service available or Discover() has not been called");
IPHostEntry ipEntry = Dns.GetHostByName(Dns.GetHostName());
IPAddress addr = ipEntry.AddressList[0];
XmlDocument xdoc = SOAPRequest(_serviceUrl,
"<m:AddPortMapping xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\"><NewRemoteHost xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"string\"></NewRemoteHost><NewExternalPort xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"ui2\">" +
port.ToString() + "</NewExternalPort><NewProtocol xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"string\">" +
protocol.ToString().ToUpper() + "</NewProtocol><NewInternalPort xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"ui2\">" +
port.ToString() + "</NewInternalPort><NewInternalClient xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"string\">" +
addr + "</NewInternalClient><NewEnabled xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"boolean\">1</NewEnabled><NewPortMappingDescription xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"string\">" +
description + "</NewPortMappingDescription><NewLeaseDuration xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"ui4\">0</NewLeaseDuration></m:AddPortMapping>",
"AddPortMapping");
}
public static void DeleteForwardingRule(int port, ProtocolType protocol)
{
if (string.IsNullOrEmpty(_serviceUrl))
throw new Exception("No UPnP service available or Discover() has not been called");
XmlDocument xdoc = SOAPRequest(_serviceUrl,
"<u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
"<NewRemoteHost></NewRemoteHost>" +
"<NewExternalPort>" + port.ToString() + "</NewExternalPort>" +
"<NewProtocol>" + protocol.ToString().ToUpper() + "</NewProtocol>" +
"</u:DeletePortMapping>", "DeletePortMapping");
}
public static IPAddress GetExternalIP()
{
if (string.IsNullOrEmpty(_serviceUrl))
throw new Exception("No UPnP service available or Discover() has not been called");
XmlDocument xdoc = SOAPRequest(_serviceUrl, "<u:GetExternalIPAddress xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
"</u:GetExternalIPAddress>", "GetExternalIPAddress");
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xdoc.NameTable);
nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0");
string IP = xdoc.SelectSingleNode("//NewExternalIPAddress/text()", nsMgr).Value;
return IPAddress.Parse(IP);
}
private static XmlDocument SOAPRequest(string url, string soap, string function)
{
string req = "<?xml version=\"1.0\"?>" +
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +
"<s:Body>" +
soap +
"</s:Body>" +
"</s:Envelope>";
WebRequest r = HttpWebRequest.Create(url);
r.Timeout = 10000;
r.Method = "POST";
byte[] b = Encoding.UTF8.GetBytes(req);
r.Headers.Add("SOAPACTION", "\"urn:schemas-upnp-org:service:WANIPConnection:1#" + function + "\"");
r.ContentType = "text/xml; charset=\"utf-8\"";
r.ContentLength = b.Length;
r.GetRequestStream().Write(b, 0, b.Length);
XmlDocument resp = new XmlDocument();
WebResponse wres = r.GetResponse();
Stream ress = wres.GetResponseStream();
resp.Load(ress);
return resp;
}
}
}
These SOAP requests use two UPnP “commands”:
- AddPortMapping
- DeletePortMapping
AddPortMapping needs the following parameters:
- NewRemoteHost – Used to make it so that only one remote host can connect. Generally not used and OK to leave blank.
- NewExternalPort – The port that the incoming outside connection should be connecting on.
- NewProtocol – This is the protocol that will be running on the port. should be either “TCP” or “UDP”.
- NewInternalPort – The port on the inside of the network that the connection will be forwarded to.
- NewInternalClient – The internal IP address the connection should be forwarded to.
- NewEnabled – Whether the connection should be enabled or not. You want to set this to 1 so it actually works.
- NewPortMappingDescription – Just a short description of what the port is actually being used for. Generally the program name.
- NewLeaseDuration – Just set this to 0.
If the AddPortMapping doesn’t work for some reason you will get a server 500 error. Otherwise you will get an xml response
DeletePortMapping needs the following parameters:
- NewRemoteHost – Same thing as AddPortMapping. Not really used.
- NewExternalPort – The external port that the forwarding you’re deleting is running on.
- NewProtocol – The protocol it is running. “TCP” or “UDP”
If there is no such port mapping in the table, you will get a server 500 error, so be careful.
You can also check to see if a mapping exists by using GetSpecificPortMapping entry which takes NewRemoteHost, NewExternalPort, and NewPortMappingProtocol, and it returns a bunch of data on the connection. However the downside is that if it doesn’t exist, you get a server 500 error, and these can be trick to handle if you’re using a WebRequest, as it just throws it as a WebException.
The other way to do it is to GetGenericPortMappingEntry which returns the table of them and you can search it for the one you want.
NOTE: AddPortMapping will overwrite the previous mapping on the same port and protocol.
PyCrawler – Open Source simple web crawler
A while ago I made a post about a Web Crawler in less that 50 lines of python. Well, I took that and made it a little (and really, I mean just a little..) more sophisticated, and stuck it on GitHub. Anyone who wants to can contribute, or use the code however they want.
Javascript Optimization Tip: Faux-StringBuilder
In my new site, Aud (which you can see my original post on here), I use a lot of javascript, and I wanted it to be very fast. One part that was amazingly slow was the generation of the playlist. The script does an ajax call to the server to get the playlist as JSON, and then turns each song into a table row and appends it to the table in the playlist div. Simple, yes, but if you do it wrong and have a lot of data, it’s very slow. Heres a tip I figured out to help speed up the process:
Instead of using your typical concatenation techniques like this:
var table = "";
for (var i = 0; i < playlist.length; i++) {
table += "<tr><td><strong>Artist: " + artist + " Album: " + album + " Song: " + song + "</td></tr>";
}
$('#table').append(table);
You would do something like this:
var table = [];
for (var i = 0; i < playlist.length; i++) {
table.push(["<tr><td><strong>Artist: ", artist, " Album: ", album, " Song: ", song, "</td></tr>"].join(''));
}
$('#table').append(table.join(''));
Now some people might think, “Well, why not put the .append() inside the loop?”. You really don’t want to do that. It’s very costly in terms of speed, and ends up even slower.
So if you have a lot of appending to strings, try making it an array, and pusing and joining!
Introducing Aud: A Simple HTML 5 Media Player
On my main desktop, for whatever reason, I couldn’t get the sound to work in any program except my browser. So for a while I was stuck listening to Pandora and YouTube videos (don’t get me wrong, I like Pandora, but after a while I just wanted to listen to the music in my own library). And then, one day, I was reading an article about HTML 5, and I realized that maybe I could put some of the new elements to good use and make myself a way to listen to my music. And that’s exactly what I did.
With HTML 5′s new audio tag, some JQuery, and about 150 lines of PHP, I produced this (Warning: IE and FireFox not supported. Chrome and Safari only). The whole thing is about 300 lines of JS, but that is far more than is needed to make yourself a simple little audio player. In this post I’ll be covering the basics of how it works, and I will be making other posts that go into details about other parts of the app.
<!DOCTYPE html>
<html>
<head>
<title>Aud</title>
<script src="js/jquery-1.4.2.min.js" type="text/javascript"></script> <script src="func.js" type="text/javascript"></script>
<script type="text/javascript">
playlist = [
{
artist: "10 Years",
album: "The Autumn Effect",
file: "Waking Up",
url: "Waking_Up.mp3"
},
{
artist: "10 Years",
album: "The Autumn Effect",
file: "Fault Line",
url: "Fault_Line.mp3"
},
{
artist: "10 Years",
album: "The Autumn Effect",
file: "The Recipe",
url: "The_Recipe.mp3"
}
]; // 3 song playlist
$(document).ready(function() {
aud = $('#player .aud').get(0);
aud.pos = 0;
$('#player .play').bind('click', function(evt) {
evt.preventDefault();
if (aud.networkState == 0) {
aud.pos = -1;
$('#player .next').trigger('click');
} else {
aud.play();
}
});
$('#player .pause').bind('click', function(evt) {
evt.preventDefault();
aud.pause();
});
$('#player .next').bind('click', function(evt) {
evt.preventDefault();
aud.pause();
aud.pos++;
if (aud.pos == playlist.length) aud.pos = 0;
aud.setAttribute('src', playlist[aud.pos].url);
$('#songname').html("
<strong>Artist:</strong> " + playlist[aud.pos].artist + "
<strong>Album:</strong> " + playlist[aud.pos].album + "
<strong>File:</strong> " + playlist[aud.pos].file + "
");
aud.load();
aud.play();
});
$('#player .prev').bind('click', function(evt) {
evt.preventDefault();
aud.pause();
aud.pos--;
if (aud.pos < 0) aud.pos = playlist.length - 1;
aud.setAttribute('src', playlist[aud.pos].url);
$('#songname').html("
<strong>Artist:</strong> " + playlist[aud.pos].artist + "
<strong>Album:</strong> " + playlist[aud.pos].album + "
<strong>File:</strong> " + playlist[aud.pos].file + "
");
aud.load();
});
aud.addEventListener('canplay', function(evt) {
$('#player .play').trigger('click');
});
aud.addEventListener('ended', function(evt) {
$('#player .next').trigger('click');
});
});
</script>
</head>
<body>
<div id='main'>
<div id='player'>
<div id='controls'>
<div id='back' class='prev'></div><div id='play' class='play'></div><div class='next' id='forward'></div>
<a href='#' class='pause'>Pause</a>
<div id='songname'>
<p>Song</p>
</div>
</div>
<audio class='aud'>
<p>Oops, looks like your browser doesnt support HTML 5!</p>
</audio>
</div>
</div>
</body>
</html>
This is all you need to make yourself a functioning little player. It’s pretty simple. I’ve quite enjoyed working its really easy API.
FYI, the reason my app is not supported in Firefox is because its audio tag doesn’t support the mp3 format like Chrome and Safari do. Right now firefox only supports the .ogg format.
There is a lot more that went into this app that I will be posting on later, so be sure to check back!
Hello, Ubuntu
I’ve always been a devout Windows user. In my 10 or so years using computers, I’ve used pretty much explicitly Windows until recently.
The first system I used was my parents Windows 95 machine. I liked it because it had Solitaire. Then we moved up to Windows ME. Even at my young age I was smart enough to know Windows ME was horrible. But then XP came out. I liked it because it looked cooler, and was slightly faster than ME (give me a break i was still pretty young). I had some good times with Windows XP. When I finally got to the age where I realized I liked computers, We were still in the XP era. So I got pretty familiar with it. First I used it for games. But as things moved on, I spent my days fiddling around trying to set up a Ragnarok server on the machine. This got me more familiar.
Then Vista came out. Everyone was ripping it to shreds and I was hearing all sorts of terrible things about it. Unfortunately, while changing the PSU in my computer, I dropped the old PSU on top of the motherboard. It was dead. So my parents got me a new Dell, which of course, came with vista. At first I didn’t like Vista because they had changed the layout of everything, and I couldn’t find the things I wanted. Luckily that’s a simple problem and I got over that in a couple of days. After that, I learned to like vista, a lot. All the while I was growing used to the Windows environment and learning and learning more and more about computers and programming. And now of course, with about 5 years of programming under my belt, Windows 7 comes along!
Windows 7 is great. Its zippy. And I like some of the other features like the new task bar. I’ve been using Windows 7 since the beta, and I’ve been really happy with it.
So now I’ve spent 10 years in the windows environment and I’m quite comfortable with it. I’ve found a few things I like in each new version of Windows that comes out, and it keeps me happy for a little while longer each time. Unfortunately, after 10 years, I’ve grown bored of windows. I’m too comfy with it, and I feel like it’s time to try something new. Enter Ubuntu.
Now I’ve had little bits and pieces of Ubuntu (and a couple of other flavors of linux) experience thrown in with my 10 years of computing. I’ve had a couple VM’s with it, just to play around. I also worked with a Red Hat server at one of my jobs. But I’ve never really used linux more than part-time. Until now.
The other day, I took apart my main machine and made two out of it. I kept my windows machine in a usable condition (just in case) and I spawned a new computer, a linux box. I immediately installed Ubuntu. The installation went smoothly and was easier than I expected (I had had some trouble with it in the past). And just like that, I was up and running.
Things have run pretty smoothly since then, with only a couple glitches. The first thing I had to deal with was the nVidia drivers, which as I have learned are terrible for dual monitor support. When I had originally booted into Ubuntu, it had been using some standard graphics driver that seemed to do a pretty darn good job. It immediately recognized both of my monitors, and it was easy to set them up in the right position. However I then got a notice saying I should install my nVidia drivers. So I did, and thats where things went down hill.
After I got the driver installed, I restarted the computer and it booted into the OS, but this time, only one of my monitors worked. So I did some fiddling, but I could not, for the life of me, get it to recognize the second monitor. I got frustrated and realized, “Why am I bothering with this, I had a perfectly good, working solution before!”. I uninstalled the nVidia driver. And everything worked again.
So then I spent a day playing around, installing the programs I wanted, etc. And then I realized that the disc I had used to install ubuntu was the 9.04 disc. I went to the upgrade manager, and of course there was a button say “There is a new version of Ubuntu available, would you like to upgrade now?” (or something to that effect). I hit yes, and it did its thing for a while. Then it rebooted into the new version, and it worked just fine except for one thing. It had switched which monitor was the main monitor (the one with the application bars). This makes it slightly awkward to use, as my main monitor is now on the right instead of in the center. I still haven’t figured out how to change this (if you know, please leave a suggestion in a comment), but I’ve gotten used to it and it’s not so bad.
The last problem I discovered was that I had no sound. This was a problem. I did some internet searching and found that ALSA didn’t support my sound card, and I didn’t want to go buy one, so I took the advice of a friend and installed OSS4. Poof! sound works.
So I’m still getting adjusted, but I’m really liking the environment so far. The one thing I don’t like is all the dependencies you have to figure out. When I try to build an application, inevitably, I don’t have all the packages. And of course, I don’t have all the dependencies for those packages either. So I have to go lib-hunting. This was very frustrating. But I’ve been getting through it, and so far I’m quite happy with the switch.
I’m very excited to learn a new environment, and I’m having fun. If nothing else, it adds something to my resume.
Also, I have to give Ubuntu credit: Out of all the distro’s I’ve fiddled with, Ubuntu is one of the easiest and best supported ones. Hooray!
Python Web Crawler in Less Than 50 Lines
I got kind of bored today, and wrote a pretty simple web crawler with python and it turned out to be less than 50 lines. It doesn’t store output, I’ll leave that up to anyone who wants to use the code, because, well, theres just too many ways to choose from. Right now you pass it a starting link as a parameter and it will crawl forever untill it runs out of links. But that is not a likely condition. So here ya go. Have fun. Feel free to ask questions
import sys
import re
import urllib2
import urlparse
tocrawl = set([sys.argv[1]])
crawled = set([])
keywordregex = re.compile('<meta\sname=["\']keywords["\']\scontent=["\'](.*?)["\']\s/>')
linkregex = re.compile('<a\s*href=[\'|"](.*?)[\'"].*?>')
while 1:
try:
crawling = tocrawl.pop()
print crawling
except KeyError:
raise StopIteration
url = urlparse.urlparse(crawling)
try:
response = urllib2.urlopen(crawling)
except:
continue
msg = response.read()
startPos = msg.find('<title>')
if startPos != -1:
endPos = msg.find('</title>', startPos+7)
if endPos != -1:
title = msg[startPos+7:endPos]
print title
keywordlist = keywordregex.findall(msg)
if len(keywordlist) > 0:
keywordlist = keywordlist[0]
keywordlist = keywordlist.split(", ")
print keywordlist
links = linkregex.findall(msg)
crawled.add(crawling)
for link in (links.pop(0) for _ in xrange(len(links))):
if link.startswith('/'):
link = 'http://' + url[1] + link
elif link.startswith('#'):
link = 'http://' + url[1] + url[2] + link
elif not link.startswith('http'):
link = 'http://' + url[1] + '/' + link
if link not in crawled:
tocrawl.add(link)
** EDIT **
This was a very early draft of this program. As it turns out, I revisited this project a few months later and it evolved much more.
If you would like to check out the more evolved form, feel free to have a look here at my github!