<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6946125878559207247</id><updated>2012-01-17T08:17:24.287-08:00</updated><category term='nasa'/><category term='string pluck'/><category term='coefficients'/><category term='ephemeris'/><category term='infinite recursion'/><category term='jpl'/><category term='classifier'/><category term='author detection'/><category term='waveforms'/><category term='music'/><category term='chebyshev'/><category term='learning algorithm'/><category term='query'/><category term='audio'/><category term='pyaudio'/><category term='davy&apos;s law'/><category term='numpy'/><category term='procedural'/><category term='astro-phys'/><category term='python'/><category term='scipy'/><category term='synthesizer'/><category term='authorship'/><category term='qualia'/><category term='pygame'/><category term='naive bayes'/><category term='guitar'/><category term='computers computing computers'/><category term='json'/><category term='ephemeride'/><title type='text'>Wybiral</title><subtitle type='html'>B(log n)</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://davywybiral.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://davywybiral.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Wybiral</name><uri>http://www.blogger.com/profile/04401873536119552162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_ZeDxs16m_Ns/SXKZ4kxjniI/AAAAAAAAAKE/3kIaGWSXwec/S220/avatar179439_18.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>14</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6946125878559207247.post-1437231754034155669</id><published>2011-11-05T07:08:00.000-07:00</published><updated>2011-11-08T21:19:41.502-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='query'/><category scheme='http://www.blogger.com/atom/ns#' term='jpl'/><category scheme='http://www.blogger.com/atom/ns#' term='chebyshev'/><category scheme='http://www.blogger.com/atom/ns#' term='json'/><category scheme='http://www.blogger.com/atom/ns#' term='astro-phys'/><category scheme='http://www.blogger.com/atom/ns#' term='coefficients'/><category scheme='http://www.blogger.com/atom/ns#' term='nasa'/><category scheme='http://www.blogger.com/atom/ns#' term='ephemeris'/><category scheme='http://www.blogger.com/atom/ns#' term='ephemeride'/><title type='text'>Planetary states API</title><content type='html'>I needed a way to deal with planetary positions and velocities and found NASA's &lt;a href="http://ssd.jpl.nasa.gov/horizons.cgi"&gt;HORIZONS&lt;/a&gt; and the &lt;a href="http://ssd.jpl.nasa.gov/?ephemerides"&gt;ephemerides&lt;/a&gt;. But I wanted a simpler interface than telnet or lugging around the massive ephemeris files with my applications. So instead, I wrote a simple JSON api for dealing with ephemeris files.&lt;br /&gt;&lt;br /&gt;Suppose one wanted to get the chebyshev coefficients for computing mercury's state for today's date (November 5th), the URL query would look like this:&lt;br /&gt;&lt;pre&gt;http://www.astro-phys.com/api/coeffs?date=2011-11-5&amp;bodies=mercury&lt;/pre&gt;&lt;br /&gt;Which would return a JSON object whose structure looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;{&lt;br /&gt;  "date": 2455870.5,&lt;br /&gt;  "results": {&lt;br /&gt;    {"mercury": {&lt;br /&gt;      "coeffs": ...&lt;br /&gt;      "start": 2455856.5,&lt;br /&gt;      "end": 2455872.5&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Where "coeffs" contains the chebyshev coefficients for evaluating the state of mercury between the julian dates 2455856.5 and 2455872.5&lt;br /&gt;&lt;br /&gt;To simplify it even further, you can grab the state of mercury at 9:30am on November 5th 2011 by using this url:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;http://www.astro-phys.com/api/states?date=2011-11-5+9:30am&amp;bodies=mercury&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Which would return:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;{&lt;br /&gt;  "date": 2455870.89583,&lt;br /&gt;  "results": {&lt;br /&gt;    "mercury": [&lt;br /&gt;      [30007449.557, -50119248.882, -29922524.4351],&lt;br /&gt;      [2879610.10503, 2030853.04543, 786401.74378]&lt;br /&gt;    ]&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Where the first array in "mercury" is the position vector (x, y, z) and the second array is the velocity vector (vx, vy, vz)&lt;br /&gt;&lt;br /&gt;Multiple planets can be entered, comma-separated.&lt;br /&gt;&lt;br /&gt;Applications requiring entire ephemeride records can use this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;http://www.astro-phys.com/api/records?date=2011-11-5+9:30am&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This will give you...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;{&lt;br /&gt;  "date": 2455870.89583,&lt;br /&gt;  "start": 2455824.5,&lt;br /&gt;  "end": 2455888.5,&lt;br /&gt;  "results": {&lt;br /&gt;    "mercury": [&lt;br /&gt;      [...]&lt;br /&gt;    ],&lt;br /&gt;    ...&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Where date is the date asked for, start is the beginning of the record and end is the end of the record. "results" contains every ephemeris body mapped to a list of its coefficient chunks for that record.&lt;br /&gt;&lt;br /&gt;The ephemeris being used is &lt;a href="ftp://ssd.jpl.nasa.gov/pub/eph/planets/ascii/de406/"&gt;DE406&lt;/a&gt; for the time being, though I may add others later (and a backwards compatible means of specifying).&lt;br /&gt;&lt;br /&gt;It doesn't include the full date range of DE406 yet, it only contains dates between 2000-2200 (I'll be adding more as needed, if you request a range increase it will probably be granted).&lt;br /&gt;&lt;br /&gt;To see a web application using it in action, visit &lt;a href="http://www.astro-phys.com"&gt;http://www.astro-phys.com&lt;/a&gt; and click "start" (its streaming the records to evaluate positions for the planets, the interface can be dragged and zoomed with the mouse).&lt;br /&gt;&lt;br /&gt;Lastly, the constants section of the ephemeris is also available from the url&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;http://www.astro-phys.com/api/constants&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;When querying for coefficients, you can't ask for earth or moon directly. You have to use "earthmoon" (the earthmoon barycenter) and "geomoon" (the geocentric moon) and compute their states from those. However, when querying for "states", astro-phys does this for you.&lt;br /&gt;&lt;br /&gt;PS: All api queries can also take a '&amp;callback=somefunction' to be treated as &lt;a href="http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/"&gt;jsonp&lt;/a&gt;. This works great with &lt;a href="http://api.jquery.com/jQuery.getJSON/"&gt;jquery's getJSON&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here's an example using jQuery.getJSON (note, when date is missing the current time is assumed)&lt;br /&gt;&lt;pre&gt;var url = 'http://www.astro-phys.com/api/states?callback=?';&lt;br /&gt;$.getJSON(url, {bodies: 'mercury'}, function(data) {&lt;br /&gt;  var p = data.results.mercury[0];&lt;br /&gt;  var v = data.results.mercury[1];&lt;br /&gt;  alert('Position:\nx='+p[0]+'\ny='+p[1]+'\nz='+p[2]);&lt;br /&gt;  alert('Velocity:\nx='+v[0]+'\ny='+v[1]+'\nz='+v[2]);&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6946125878559207247-1437231754034155669?l=davywybiral.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davywybiral.blogspot.com/feeds/1437231754034155669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6946125878559207247&amp;postID=1437231754034155669' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/1437231754034155669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/1437231754034155669'/><link rel='alternate' type='text/html' href='http://davywybiral.blogspot.com/2011/11/planetary-states-api.html' title='Planetary states API'/><author><name>Wybiral</name><uri>http://www.blogger.com/profile/04401873536119552162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_ZeDxs16m_Ns/SXKZ4kxjniI/AAAAAAAAAKE/3kIaGWSXwec/S220/avatar179439_18.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6946125878559207247.post-2192122766835037571</id><published>2011-05-14T05:43:00.000-07:00</published><updated>2011-06-30T01:58:47.924-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='infinite recursion'/><category scheme='http://www.blogger.com/atom/ns#' term='computers computing computers'/><category scheme='http://www.blogger.com/atom/ns#' term='davy&apos;s law'/><category scheme='http://www.blogger.com/atom/ns#' term='qualia'/><title type='text'>Davy's law</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Davy's Law:&lt;/span&gt; Computers can't compute/predict themselves.&lt;br /&gt;&lt;br /&gt;No physical computer is capable of losslessly determining it's effect on every state in it's state space by means of internal simulation. That is, the only way it can accurately achieve the result of a state is by actually being put into that state.&lt;br /&gt;&lt;br /&gt;The limiting factor here is the necessity of storing the entirety of it's state AND its rule set within it's alloted state (with room to spare for performing computation). This would be in violation of the &lt;a href="http://en.wikipedia.org/wiki/Pigeonhole_principle"&gt;pigeonhole principle&lt;/a&gt;'s effect on &lt;a href="http://en.wikipedia.org/wiki/Lossless_data_compression#Limitations"&gt;lossless compression&lt;/a&gt;. Not to mention that if it were possible, it could simulate it simulating it simulating it... And unless it can solve the &lt;a href="http://en.wikipedia.org/wiki/Halting_problem"&gt;halting problem&lt;/a&gt;, that's probably just not a good feature for a system to have.&lt;br /&gt;&lt;br /&gt;Davy's law does not prohibit computers from computing with isolated portions of it's state. It also does not state that there aren't some global state computations that are possible. That is, some states can be losslessly compressed and manipulated in this form. Rather it postulates that a computer cannot compute the results of every state for it's entire state space.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6946125878559207247-2192122766835037571?l=davywybiral.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davywybiral.blogspot.com/feeds/2192122766835037571/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6946125878559207247&amp;postID=2192122766835037571' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/2192122766835037571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/2192122766835037571'/><link rel='alternate' type='text/html' href='http://davywybiral.blogspot.com/2011/05/ive-been-up-all-night-again.html' title='Davy&apos;s law'/><author><name>Wybiral</name><uri>http://www.blogger.com/profile/04401873536119552162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_ZeDxs16m_Ns/SXKZ4kxjniI/AAAAAAAAAKE/3kIaGWSXwec/S220/avatar179439_18.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6946125878559207247.post-7776234350863784006</id><published>2011-04-28T03:02:00.000-07:00</published><updated>2011-05-03T03:35:48.725-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='classifier'/><category scheme='http://www.blogger.com/atom/ns#' term='naive bayes'/><category scheme='http://www.blogger.com/atom/ns#' term='authorship'/><category scheme='http://www.blogger.com/atom/ns#' term='author detection'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='learning algorithm'/><title type='text'>Naive Bayes (and author detection)</title><content type='html'>I've been playing around with various classification algorithms lately, so I wrote a really simplified discrete &lt;a href="http://en.wikipedia.org/wiki/Naive_Bayes_classifier"&gt;naive bayes classifier&lt;/a&gt; in Python. No emphasis on sample correction, simplicity was key here, but it still works quite well.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;from operator import itemgetter&lt;br /&gt;from collections import defaultdict&lt;br /&gt;&lt;br /&gt;class BayesClassifier:&lt;br /&gt;&lt;br /&gt;  def __init__(self):&lt;br /&gt;    self.total_count = 0                # Observations of individual attributes&lt;br /&gt;    self.class_count = defaultdict(int) # Observations of cls&lt;br /&gt;    self.attrs_count = defaultdict(int) # Observations of (cls, attrs)&lt;br /&gt;    self.correction = 0.0001            # Prevent multiplication by 0.0&lt;br /&gt;&lt;br /&gt;  def train(self, cls, attrs):&lt;br /&gt;    ''' Add observation of 'attrs' as being an instance of 'cls' '''&lt;br /&gt;    self.class_count[cls] += 1&lt;br /&gt;    for attr in attrs:&lt;br /&gt;      self.attrs_count[(cls, attr)] += 1&lt;br /&gt;      self.total_count += 1&lt;br /&gt;&lt;br /&gt;  def rate(self, cls, attrs):&lt;br /&gt;    ''' Return probability rating of 'attrs' being an instance of 'cls' '''&lt;br /&gt;    result = float(self.class_count[cls]) / self.total_count&lt;br /&gt;    for attr in attrs:&lt;br /&gt;      result *= self.attrs_count.get((cls, attr), self.correction)&lt;br /&gt;    return result / pow(self.total_count, len(attrs))&lt;br /&gt;      &lt;br /&gt;  def classify(self, attrs):&lt;br /&gt;    ''' Return most likely class that 'attrs' belongs to '''&lt;br /&gt;    rated_classes = [(self.rate(cls, attrs), cls) for cls in self.class_count]&lt;br /&gt;    rated_classes.sort(key=itemgetter(0), reverse=True)&lt;br /&gt;    return rated_classes[0][1]&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Playing around with it I used various spam/not-spam training sets and various categorical training sets. Attributes can be labeled by the user instead of just "bag of words" lists by tagging the values in the attrs list, such as &lt;code&gt;['weekday:wed', 'weather:sunny', 'humidity:high']&lt;/code&gt;. Likewise, positional attributes can easily be tagged with their index &lt;code&gt;['0:this', '1:works', '2:well']&lt;/code&gt;. Its trivial to write a function that turns lists, objects, dicts, data models into such tagged attribute lists.&lt;br /&gt;&lt;br /&gt;But playing with the algorithm in its "bag of words" form, I thought it would be neat to see how it does with authorship detection. Using an approach similar to spam/not-spam I trained it to classify quotes by author based on word and punctuation probabilities. In this example it parses &lt;a href="http://www.brainyquote.com"&gt;brainyquote.com&lt;/a&gt; to train from the first pages of quotes by a given author, then tests the classifier with known quotes that weren't included on the first page. In a real world scenario, you'd want to train it with a much larger corpus, but in this case it works fairly well.&lt;br /&gt;&lt;br /&gt;Here is it learning to classify between Richard Dawkins, George W Bush, and Charles Dickens :) (yes, I chose them for word contrast)&lt;br /&gt;&lt;pre&gt;from urllib import urlopen&lt;br /&gt;from BeautifulSoup import BeautifulSoup&lt;br /&gt;&lt;br /&gt;def getwords(text):&lt;br /&gt;  ''' Split text into words and useful punctuation tokens '''&lt;br /&gt;  import string&lt;br /&gt;  text = text.replace("'", '')&lt;br /&gt;  # Remove useless punctuation&lt;br /&gt;  for c in string.punctuation:&lt;br /&gt;    if c not in '.,;?!':&lt;br /&gt;      text = text.replace(c, ' ')&lt;br /&gt;  # Keep useful punctuation&lt;br /&gt;  for c in '.,;?!':&lt;br /&gt;    text = text.replace(c, ' puncuation:%s ' % c)&lt;br /&gt;  text = text.lower()&lt;br /&gt;  return [str(word) for word in text.split() if len(word) &gt; 3]&lt;br /&gt;&lt;br /&gt;def getquotes(author):&lt;br /&gt;  ''' Return list of quotes by author from brainyquote.com '''&lt;br /&gt;  base_url = 'http://www.brainyquote.com/quotes/authors/%s/%s.html'&lt;br /&gt;  soup = BeautifulSoup(urlopen(base_url % (author[0], author)).read())&lt;br /&gt;  td = soup.find('td', {'align': 'left', 'valign': 'top', 'width': 440})&lt;br /&gt;  quotes = []&lt;br /&gt;  for quote in td.findAll('span', {'class': 'body'}):&lt;br /&gt;    quotes.append(quote.string)&lt;br /&gt;  return quotes&lt;br /&gt;&lt;br /&gt;bayes = BayesClassifier()&lt;br /&gt;&lt;br /&gt;# Train bayes with quotes by author&lt;br /&gt;for author in ['richard_dawkins', 'george_w_bush', 'charles_dickens']:&lt;br /&gt;  for quote in getquotes(author):&lt;br /&gt;    bayes.train(author, getwords(quote))&lt;br /&gt;&lt;br /&gt;test_data = [&lt;br /&gt;  ['Bush',&lt;br /&gt;   "Government does not create wealth. The major role for the government is to create an environment where people take risks to expand the job rate in the United States."],&lt;br /&gt;  ['Dawkins',&lt;br /&gt;   "There may be fairies at the bottom of the garden. There is no evidence for it, but you can't prove that there aren't any, so shouldn't we be agnostic with respect to fairies?"],&lt;br /&gt;  ['Dickens',&lt;br /&gt;   "I have known a vast quantity of nonsense talked about bad men not looking you in the face. Don't trust that conventional idea. Dishonesty will stare honesty out of countenance any day in the week, if there is anything to be got by it."],&lt;br /&gt;]&lt;br /&gt;&lt;br /&gt;# Test bayes with untrained quotes&lt;br /&gt;for author, quote in test_data:&lt;br /&gt;  guess = bayes.classify(getwords(quote))&lt;br /&gt;  print 'Classified as %s, should be %s' % (guess, author)&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6946125878559207247-7776234350863784006?l=davywybiral.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davywybiral.blogspot.com/feeds/7776234350863784006/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6946125878559207247&amp;postID=7776234350863784006' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/7776234350863784006'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/7776234350863784006'/><link rel='alternate' type='text/html' href='http://davywybiral.blogspot.com/2011/04/naive-bayes-and-author-detection.html' title='Naive Bayes (and author detection)'/><author><name>Wybiral</name><uri>http://www.blogger.com/profile/04401873536119552162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_ZeDxs16m_Ns/SXKZ4kxjniI/AAAAAAAAAKE/3kIaGWSXwec/S220/avatar179439_18.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6946125878559207247.post-7976200376491913268</id><published>2010-10-19T10:58:00.000-07:00</published><updated>2011-05-06T15:15:21.145-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='synthesizer'/><category scheme='http://www.blogger.com/atom/ns#' term='pygame'/><category scheme='http://www.blogger.com/atom/ns#' term='procedural'/><category scheme='http://www.blogger.com/atom/ns#' term='scipy'/><category scheme='http://www.blogger.com/atom/ns#' term='waveforms'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='music'/><category scheme='http://www.blogger.com/atom/ns#' term='audio'/><category scheme='http://www.blogger.com/atom/ns#' term='string pluck'/><category scheme='http://www.blogger.com/atom/ns#' term='numpy'/><title type='text'>Python musical update</title><content type='html'>Based on my procedural music project I had been working on &lt;a href="http://davywybiral.blogspot.com/2010/09/procedural-music-with-pyaudio-and-numpy.html"&gt;here&lt;/a&gt;. I've made some improvements. Abstracted the playback some, can now play through numpy, oss, or pyaudio. The plan is to default to the best playback method, right now it just uses the first one that seems available. I did this because I got dozens of complaints about using just pyaudio. Can save audio to wave files, other formats would be nice but are not worth my time right now. It's got a few example files to give some idea of usage, but no documentation.&lt;br /&gt;&lt;br /&gt;Google code project page is up: &lt;a href="http://code.google.com/p/python-musical/"&gt;http://code.google.com/p/python-musical/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Download link: &lt;a href="http://python-musical.googlecode.com/files/python-musical.tar.gz"&gt;http://python-musical.googlecode.com/files/python-musical.tar.gz&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Examples include:&lt;br /&gt;&lt;a href="http://code.google.com/p/python-musical/source/browse/trunk/example-01.py"&gt;arpeggiated chord progression&lt;/a&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/python-musical/source/browse/trunk/example-02.py"&gt;randomly generated lead (with chorus effect)&lt;/a&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/python-musical/source/browse/trunk/example-03.py"&gt;basic example of waveform generating&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you want to take a listen without running it, I saved the audio output of examples 1 and 2...&lt;br /&gt;&lt;a href="http://python-musical.googlecode.com/files/example-01.wav"&gt;Example-01.wav&lt;/a&gt;&lt;br /&gt;&lt;a href="http://python-musical.googlecode.com/files/example-02.wav"&gt;Example-02.wav&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6946125878559207247-7976200376491913268?l=davywybiral.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davywybiral.blogspot.com/feeds/7976200376491913268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6946125878559207247&amp;postID=7976200376491913268' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/7976200376491913268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/7976200376491913268'/><link rel='alternate' type='text/html' href='http://davywybiral.blogspot.com/2010/10/python-musical-update.html' title='Python musical update'/><author><name>Wybiral</name><uri>http://www.blogger.com/profile/04401873536119552162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_ZeDxs16m_Ns/SXKZ4kxjniI/AAAAAAAAAKE/3kIaGWSXwec/S220/avatar179439_18.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6946125878559207247.post-526615814629533289</id><published>2010-09-30T14:06:00.000-07:00</published><updated>2011-05-06T15:19:34.293-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='synthesizer'/><category scheme='http://www.blogger.com/atom/ns#' term='pyaudio'/><category scheme='http://www.blogger.com/atom/ns#' term='scipy'/><category scheme='http://www.blogger.com/atom/ns#' term='guitar'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='music'/><category scheme='http://www.blogger.com/atom/ns#' term='numpy'/><title type='text'>My new musical instrument: Python</title><content type='html'>It's still very young, but &lt;a href="http://code.google.com/p/python-musical/"&gt;here&lt;/a&gt; is the library I've been working on for &lt;a href="http://davywybiral.blogspot.com/2010/09/procedural-music-with-pyaudio-and-numpy.html"&gt;generating music in (nothing but) Python&lt;/a&gt;. "test.py" is an example of what you can do. The real purpose isn't to code your music out this way, it's intended as a backend for generating / manipulating music. My end goal is a tab-based editor that plays back with this, but I'm going to keep working on this backend and hope some brave snake wrestler comes along and has the itch to write a proper interface (and if that doesn't happen, I'll start on the interface when I feel satisfied with the backend).&lt;br /&gt;&lt;br /&gt;The Timeline and Hit classes are just ideas right now. I'm not sure they'll stay in the form they are (I'm thinking a guitar-oriented timeline, holding fret/string/amplitude per hit, is more along the lines of what I need).&lt;br /&gt;&lt;br /&gt;I'm also on the hunt for efficient numpy/scipy implemented effects and sound sources. I've been playing around some with generating Karplus-Strong pluck sounds and delay/chorus/flanger effects, but I'm not exactly satisfied with the sound and runtime efficiency of what I have.&lt;br /&gt;&lt;br /&gt;Be sure to check out the "minor" scale version of this "major" progression.&lt;br /&gt;&lt;br /&gt;Also be sure to let me know if you have any advice on optimizing (without jumping into the C just yet) or creating a better code interface / representation of these concepts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6946125878559207247-526615814629533289?l=davywybiral.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davywybiral.blogspot.com/feeds/526615814629533289/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6946125878559207247&amp;postID=526615814629533289' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/526615814629533289'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/526615814629533289'/><link rel='alternate' type='text/html' href='http://davywybiral.blogspot.com/2010/09/my-new-musical-instrument-python.html' title='My new musical instrument: Python'/><author><name>Wybiral</name><uri>http://www.blogger.com/profile/04401873536119552162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_ZeDxs16m_Ns/SXKZ4kxjniI/AAAAAAAAAKE/3kIaGWSXwec/S220/avatar179439_18.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6946125878559207247.post-1657465392921959256</id><published>2010-09-21T21:48:00.000-07:00</published><updated>2011-12-17T09:17:29.878-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='synthesizer'/><category scheme='http://www.blogger.com/atom/ns#' term='procedural'/><category scheme='http://www.blogger.com/atom/ns#' term='pyaudio'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='music'/><category scheme='http://www.blogger.com/atom/ns#' term='numpy'/><title type='text'>Procedural music with PyAudio and NumPy</title><content type='html'>Combining two of my favorite pastimes, programming and music... This is the hacky "reduced to it's basic components" version of a library I've been working on for generating music and dealing with music theory.&lt;br /&gt;&lt;br /&gt;Tweaking the harmonics by changing the shape of the harmonic components and ratios can produce some interesting sounds. This one only uses sine waveforms, but a square / saw generator is trivial with numpy.&lt;br /&gt;&lt;br /&gt;It takes a second to generate, so don't turn your volume up too loud in anticipation (it may be loud).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;import math&lt;br /&gt;import numpy&lt;br /&gt;import pyaudio&lt;br /&gt;import itertools&lt;br /&gt;from scipy import interpolate&lt;br /&gt;from operator import itemgetter&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class Note:&lt;br /&gt;&lt;br /&gt;  NOTES = ['c','c#','d','d#','e','f','f#','g','g#','a','a#','b']&lt;br /&gt;&lt;br /&gt;  def __init__(self, note, octave=4):&lt;br /&gt;    self.octave = octave&lt;br /&gt;    if isinstance(note, int):&lt;br /&gt;      self.index = note&lt;br /&gt;      self.note = Note.NOTES[note]&lt;br /&gt;    elif isinstance(note, str):&lt;br /&gt;      self.note = note.strip().lower()&lt;br /&gt;      self.index = Note.NOTES.index(self.note)&lt;br /&gt;&lt;br /&gt;  def transpose(self, halfsteps):&lt;br /&gt;    octave_delta, note = divmod(self.index + halfsteps, 12)&lt;br /&gt;    return Note(note, self.octave + octave_delta)&lt;br /&gt;&lt;br /&gt;  def frequency(self):&lt;br /&gt;    base_frequency = 16.35159783128741 * 2.0 ** (float(self.index) / 12.0)&lt;br /&gt;    return base_frequency * (2.0 ** self.octave)&lt;br /&gt;&lt;br /&gt;  def __float__(self):&lt;br /&gt;    return self.frequency()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class Scale:&lt;br /&gt;&lt;br /&gt;  def __init__(self, root, intervals):&lt;br /&gt;    self.root = Note(root.index, 0)&lt;br /&gt;    self.intervals = intervals&lt;br /&gt;&lt;br /&gt;  def get(self, index):&lt;br /&gt;    intervals = self.intervals&lt;br /&gt;    if index &lt; 0:&lt;br /&gt;      index = abs(index)&lt;br /&gt;      intervals = reversed(self.intervals)&lt;br /&gt;    intervals = itertools.cycle(self.intervals)&lt;br /&gt;    note = self.root&lt;br /&gt;    for i in xrange(index):&lt;br /&gt;      note = note.transpose(intervals.next())&lt;br /&gt;    return note&lt;br /&gt;&lt;br /&gt;  def index(self, note):&lt;br /&gt;    intervals = itertools.cycle(self.intervals)&lt;br /&gt;    index = 0&lt;br /&gt;    x = self.root&lt;br /&gt;    while x.octave != note.octave or x.note != note.note:&lt;br /&gt;      x = x.transpose(intervals.next())&lt;br /&gt;      index += 1&lt;br /&gt;    return index&lt;br /&gt;&lt;br /&gt;  def transpose(self, note, interval):&lt;br /&gt;    return self.get(self.index(note) + interval)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def sine(frequency, length, rate):&lt;br /&gt;  length = int(length * rate)&lt;br /&gt;  factor = float(frequency) * (math.pi * 2) / rate&lt;br /&gt;  return numpy.sin(numpy.arange(length) * factor)&lt;br /&gt;&lt;br /&gt;def shape(data, points, kind='slinear'):&lt;br /&gt;    items = points.items()&lt;br /&gt;    items.sort(key=itemgetter(0))&lt;br /&gt;    keys = map(itemgetter(0), items)&lt;br /&gt;    vals = map(itemgetter(1), items)&lt;br /&gt;    interp = interpolate.interp1d(keys, vals, kind=kind)&lt;br /&gt;    factor = 1.0 / len(data)&lt;br /&gt;    shape = interp(numpy.arange(len(data)) * factor)&lt;br /&gt;    return data * shape&lt;br /&gt;&lt;br /&gt;def harmonics1(freq, length):&lt;br /&gt;  a = sine(freq * 1.00, length, 44100)&lt;br /&gt;  b = sine(freq * 2.00, length, 44100) * 0.5&lt;br /&gt;  c = sine(freq * 4.00, length, 44100) * 0.125&lt;br /&gt;  return (a + b + c) * 0.2&lt;br /&gt;&lt;br /&gt;def harmonics2(freq, length):&lt;br /&gt;  a = sine(freq * 1.00, length, 44100)&lt;br /&gt;  b = sine(freq * 2.00, length, 44100) * 0.5&lt;br /&gt;  return (a + b) * 0.2&lt;br /&gt;&lt;br /&gt;def pluck1(note):&lt;br /&gt;  chunk = harmonics1(note.frequency(), 2)&lt;br /&gt;  return shape(chunk, {0.0: 0.0, 0.005: 1.0, 0.25: 0.5, 0.9: 0.1, 1.0:0.0})&lt;br /&gt;&lt;br /&gt;def pluck2(note):&lt;br /&gt;  chunk = harmonics2(note.frequency(), 2)&lt;br /&gt;  return shape(chunk, {0.0: 0.0, 0.5:0.75, 0.8:0.4, 1.0:0.1})&lt;br /&gt;&lt;br /&gt;def chord(n, scale):&lt;br /&gt;  root = scale.get(n)&lt;br /&gt;  third = scale.transpose(root, 2)&lt;br /&gt;  fifth = scale.transpose(root, 4)&lt;br /&gt;  return pluck1(root) + pluck1(third) + pluck1(fifth)&lt;br /&gt;&lt;br /&gt;root = Note('A', 3)&lt;br /&gt;scale = Scale(root, [2, 1, 2, 2, 1, 3, 1])&lt;br /&gt;&lt;br /&gt;chunks = []&lt;br /&gt;chunks.append(chord(21, scale))&lt;br /&gt;chunks.append(chord(19, scale))&lt;br /&gt;chunks.append(chord(18, scale))&lt;br /&gt;chunks.append(chord(20, scale))&lt;br /&gt;chunks.append(chord(21, scale))&lt;br /&gt;chunks.append(chord(22, scale))&lt;br /&gt;chunks.append(chord(20, scale))&lt;br /&gt;chunks.append(chord(21, scale))&lt;br /&gt;&lt;br /&gt;chunks.append(chord(21, scale) + pluck2(scale.get(38)))&lt;br /&gt;chunks.append(chord(19, scale) + pluck2(scale.get(37)))&lt;br /&gt;chunks.append(chord(18, scale) + pluck2(scale.get(33)))&lt;br /&gt;chunks.append(chord(20, scale) + pluck2(scale.get(32)))&lt;br /&gt;chunks.append(chord(21, scale) + pluck2(scale.get(31)))&lt;br /&gt;chunks.append(chord(22, scale) + pluck2(scale.get(32)))&lt;br /&gt;chunks.append(chord(20, scale) + pluck2(scale.get(29)))&lt;br /&gt;chunks.append(chord(21, scale) + pluck2(scale.get(28)))&lt;br /&gt;&lt;br /&gt;chunk = numpy.concatenate(chunks) * 0.25&lt;br /&gt;&lt;br /&gt;p = pyaudio.PyAudio()&lt;br /&gt;stream = p.open(format=pyaudio.paFloat32, channels=1, rate=44100, output=1)&lt;br /&gt;stream.write(chunk.astype(numpy.float32).tostring())&lt;br /&gt;stream.close()&lt;br /&gt;p.terminate()&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The scale in use is Harmonic Minor.&lt;br /&gt;It's encoded via halfsteps as: "[2, 1, 2, 2, 1, 3, 1]"&lt;br /&gt;Try changing it to natural minor: "[2, 1, 2, 2, 1, 2, 2]"&lt;br /&gt;&lt;br /&gt;I'd be interested in teaming up with anyone willing to write some actual input methods (matrix sequencer, tab reader, however else it could be done) as well as an interface for tweaking synthesized sounds. My present code base is a bit much for a blog post, so contact me if interested.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6946125878559207247-1657465392921959256?l=davywybiral.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davywybiral.blogspot.com/feeds/1657465392921959256/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6946125878559207247&amp;postID=1657465392921959256' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/1657465392921959256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/1657465392921959256'/><link rel='alternate' type='text/html' href='http://davywybiral.blogspot.com/2010/09/procedural-music-with-pyaudio-and-numpy.html' title='Procedural music with PyAudio and NumPy'/><author><name>Wybiral</name><uri>http://www.blogger.com/profile/04401873536119552162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_ZeDxs16m_Ns/SXKZ4kxjniI/AAAAAAAAAKE/3kIaGWSXwec/S220/avatar179439_18.png'/></author><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6946125878559207247.post-3019349851117112544</id><published>2010-09-09T18:06:00.000-07:00</published><updated>2010-09-09T18:23:41.549-07:00</updated><title type='text'>Javascript insort function</title><content type='html'>I recently had the need for some sorted insertion in Javascript arrays, thought I'd share this tiny bit of code:&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Array.prototype.bisect = function(x, lo, hi) {&lt;br /&gt;  var mid;&lt;br /&gt;  if(typeof(lo) == 'undefined') lo = 0;&lt;br /&gt;  if(typeof(hi) == 'undefined') hi = this.length;&lt;br /&gt;  while(lo &lt; hi) {&lt;br /&gt;    mid = Math.floor((lo + hi) / 2);&lt;br /&gt;    if(x &lt; this[mid]) hi = mid;&lt;br /&gt;    else lo = mid + 1;&lt;br /&gt;  }&lt;br /&gt;  return lo&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Array.prototype.insort = function(x) {&lt;br /&gt;  this.splice(this.bisect(x), 0, x);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Of course, these methods only work on an already sorted (or empty) array, so if you're using them on an array that came from elsewhere, sort it first. But once sorted, these insertions will maintain the sortedness, no need to 'push' and 'sort' every time you need to insert something into a sorted array.&lt;br /&gt;&lt;br /&gt;(lo and hi parameters are optionally possible for the bisection method to allow restricted searches)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6946125878559207247-3019349851117112544?l=davywybiral.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davywybiral.blogspot.com/feeds/3019349851117112544/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6946125878559207247&amp;postID=3019349851117112544' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/3019349851117112544'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/3019349851117112544'/><link rel='alternate' type='text/html' href='http://davywybiral.blogspot.com/2010/09/javascript-insort-function.html' title='Javascript insort function'/><author><name>Wybiral</name><uri>http://www.blogger.com/profile/04401873536119552162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_ZeDxs16m_Ns/SXKZ4kxjniI/AAAAAAAAAKE/3kIaGWSXwec/S220/avatar179439_18.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6946125878559207247.post-736323374436693611</id><published>2009-02-22T14:45:00.000-08:00</published><updated>2009-02-22T20:35:32.524-08:00</updated><title type='text'>The names behind the languages</title><content type='html'>If we're going to continue to spill blood in these language wars, it's important that we all know who our generals are (and who our enemy generals are). Feel free to offer corrections or extensions to the list.&lt;br /&gt;&lt;br /&gt;C - &lt;a href="http://www.cs.bell-labs.com/who/dmr/"&gt;Dennis Ritchie&lt;/a&gt;&lt;br /&gt;&lt;img src="http://cm.bell-labs.com/cm/cs/who/dmr/dmr.gif" style="cursor:pointer; cursor:hand;width: 125px; height: 145px;" border="0" alt="" /&gt;&lt;br /&gt;&lt;div&gt;C++ - &lt;a href="http://www.research.att.com/~bs/homepage.html"&gt;Bjarne Stroustrup&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/commons/thumb/d/da/BjarneStroustrup.jpg/225px-BjarneStroustrup.jpg" style="cursor:pointer; cursor:hand;width: 225px; height: 169px;" border="0" alt="" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Forth - &lt;a href="http://www.colorforth.com/"&gt;Charles H. Moore&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/commons/thumb/f/f6/ChuckMoore.jpg/200px-ChuckMoore.jpg" style="cursor:pointer; cursor:hand;width: 200px; height: 168px;" border="0" alt="" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Lisp - &lt;a href="http://www-formal.stanford.edu/jmc/"&gt;John McCarthy&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/commons/thumb/4/49/John_McCarthy_Stanford.jpg/225px-John_McCarthy_Stanford.jpg" style="cursor:pointer; cursor:hand;width: 225px; height: 150px;" border="0" alt="" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Perl - &lt;a href="http://www.wall.org/~larry/"&gt;Larry Wall&lt;/a&gt;&lt;/div&gt;&lt;div&gt; &lt;img src="http://www.wall.org/~larry/inset2.gif" style="cursor:pointer; cursor:hand;width: 92px; height: 124px;" border="0" alt="" /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;PHP - &lt;a href="http://www.lerdorf.com/"&gt;Rasmus Lerdorf&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;img src="http://lerdorf.com/pics/thumbs/rl5.jpg" style="cursor:pointer; cursor:hand;width: 167px; height: 250px;" border="0" alt="" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Python - &lt;a href="http://www.python.org/~guido/"&gt;Guido van Rossum&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;img src="http://www.python.org/~guido/images/IMG_2192.jpg" style="cursor:pointer; cursor:hand;width: 166px; height: 250px;" border="0" alt="" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ruby - &lt;a href="http://en.wikipedia.org/wiki/Yukihiro_Matsumoto"&gt;Yukihiro Matsumoto&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/commons/thumb/7/76/Yukihiro_Matsumoto.JPG/225px-Yukihiro_Matsumoto.JPG" style="cursor:pointer; cursor:hand;width: 160px;" border="0" alt="" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Tcl - &lt;a href="http://home.pacbell.net/ouster/"&gt;John K. Ousterhout&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;img src="http://home.pacbell.net/ouster/Photo2008Small.jpg" style="cursor:pointer; cursor:hand;width: 160px;" border="0" alt="" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6946125878559207247-736323374436693611?l=davywybiral.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davywybiral.blogspot.com/feeds/736323374436693611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6946125878559207247&amp;postID=736323374436693611' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/736323374436693611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/736323374436693611'/><link rel='alternate' type='text/html' href='http://davywybiral.blogspot.com/2009/02/names-behind-languages.html' title='The names behind the languages'/><author><name>Wybiral</name><uri>http://www.blogger.com/profile/04401873536119552162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_ZeDxs16m_Ns/SXKZ4kxjniI/AAAAAAAAAKE/3kIaGWSXwec/S220/avatar179439_18.png'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6946125878559207247.post-253062612358112721</id><published>2009-01-19T20:31:00.000-08:00</published><updated>2011-05-03T03:36:47.654-07:00</updated><title type='text'>Venn Diagrams with google charts</title><content type='html'>I recently had the need to view some data sets as &lt;a href="http://en.wikipedia.org/wiki/Venn_Diagram"&gt;venn diagrams&lt;/a&gt;, so I found &lt;a href="http://code.google.com/apis/chart/"&gt;google's chart api&lt;/a&gt; and hacked out a little AJAX application to do so, you can try it out &lt;a href="http://davy.wybiral.googlepages.com/venn.html"&gt;here&lt;/a&gt;. And, for the fun of it, a VERY simple Python implementation:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import urllib&lt;br /&gt;from PIL import Image&lt;br /&gt;import StringIO&lt;br /&gt;&lt;br /&gt;def venn_diagram_url(a, b, c, width=400, height=200):&lt;br /&gt;   values = [width, height, len(a), len(b), len(c)]&lt;br /&gt;   values.append(len(a &amp;amp; b))&lt;br /&gt;   values.append(len(a &amp;amp; c))&lt;br /&gt;   values.append(len(c &amp;amp; b))&lt;br /&gt;   values.append(len(a &amp;amp; b &amp;amp; c))&lt;br /&gt;   base_str = 'http://chart.apis.google.com/chart?'&lt;br /&gt;   args_str = 'cht=v&amp;amp;chs=%sx%s&amp;amp;chd=t:%s,%s,%s,%s,%s,%s,%s'   &lt;br /&gt;   return base_str + (args_str % tuple(values))&lt;br /&gt;  &lt;br /&gt;a = set((1, 2, 3))&lt;br /&gt;b = set((2, 4))&lt;br /&gt;c = set((3, 4, 5))&lt;br /&gt;&lt;br /&gt;data = StringIO.StringIO(urllib.urlopen(venn_diagram_url(a, b, c)).read())&lt;br /&gt;Image.open(data).show()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Not much to it... But maybe someone will find it useful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6946125878559207247-253062612358112721?l=davywybiral.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davywybiral.blogspot.com/feeds/253062612358112721/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6946125878559207247&amp;postID=253062612358112721' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/253062612358112721'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/253062612358112721'/><link rel='alternate' type='text/html' href='http://davywybiral.blogspot.com/2009/01/venn-diagrams-with-google-charts.html' title='Venn Diagrams with google charts'/><author><name>Wybiral</name><uri>http://www.blogger.com/profile/04401873536119552162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_ZeDxs16m_Ns/SXKZ4kxjniI/AAAAAAAAAKE/3kIaGWSXwec/S220/avatar179439_18.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6946125878559207247.post-4107972731242148746</id><published>2008-11-25T08:27:00.001-08:00</published><updated>2010-09-10T23:39:11.765-07:00</updated><title type='text'>Trampolining for recursion...</title><content type='html'>In essence, &lt;a href="http://en.wikipedia.org/wiki/Continuation-passing_style"&gt;CPS&lt;/a&gt; (continuation passing style) is a method of calling functions where instead of returning a value, you pass the results to another function (the continuation) provided as an argument. I wont go too deep into the reasoning behind this, as it's usually not used directly but rather as a middle representation of programming languages by some compiler/interpreter (read more on the wikipedia link).&lt;br /&gt;&lt;br /&gt;The big downside is that you're bombarding the stack with function frames for every call, going deeper and deeper, but never returning (you just keep passing what would be the return value to another function).&lt;br /&gt;&lt;br /&gt;One nifty method of avoiding this is to use a &lt;a href="http://en.wikipedia.org/wiki/Trampoline_%28computers%29"&gt;trampoline&lt;/a&gt;. A trampoline resembles a &lt;a href="http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-24.html#%_sec_3.5"&gt;&lt;/a&gt;&lt;a href="http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-24.html#%_sec_3.5"&gt;stream/lazy-list&lt;/a&gt; to anyone who's read &lt;a href="http://mitpress.mit.edu/sicp/full-text/book/book.html"&gt;SICP&lt;/a&gt;. Essentially, instead of calling functions from within another function, you return a bounce "call" to the trampoline which makes the call for you, doing the same with the return value of that call until it gets a land (a non-bounce return). This avoids the use of the stack for function calls, but allows you to use function closure as a means of saving state.&lt;br /&gt;&lt;br /&gt;That being said, here is a simple trampoline implementation in Python showing a recursive fibonacci function implemented in CPS:&lt;br /&gt;&lt;pre&gt;class Call:&lt;br /&gt;  def __init__(self, fn, *args, **kwargs):&lt;br /&gt;    self.call = lambda: fn(*args, **kwargs)&lt;br /&gt;&lt;br /&gt;def trampoline(obj):&lt;br /&gt;  while isinstance(obj, Call):&lt;br /&gt;    obj = obj.call()&lt;br /&gt;  return obj&lt;br /&gt;&lt;br /&gt;def fibonacci(k, n):&lt;br /&gt;  if n &lt; 2:&lt;br /&gt;    return Call(k, n)&lt;br /&gt;  def with_a(a):&lt;br /&gt;    def with_b(b):&lt;br /&gt;      return Call(k, a + b)&lt;br /&gt;    return Call(fibonacci, with_b, n - 1)&lt;br /&gt;  return Call(fibonacci, with_a, n - 2)&lt;br /&gt;&lt;br /&gt;call = fibonacci(lambda x: x, 20)&lt;br /&gt;&lt;br /&gt;print trampoline(call)&lt;/pre&gt;Here is a normal fibonacci function, memoized, that fails due to exceeding Pythons recursion limit. The problem being, of course, that you have to recurse down deep enough to use the leaf calls to accumulate to the trunk:&lt;br /&gt;&lt;pre&gt;def memoized(func):&lt;br /&gt;  cache = {}&lt;br /&gt;  def decorator(*args):&lt;br /&gt;    if args not in cache:&lt;br /&gt;      cache[args] = func(*args)&lt;br /&gt;    return cache[args]&lt;br /&gt;  return decorator&lt;br /&gt;&lt;br /&gt;@memoized&lt;br /&gt;def fibonacci(n):&lt;br /&gt;  if n &lt; 2:&lt;br /&gt;    return n&lt;br /&gt;  return fibonacci(n - 2) + fibonacci(n - 1)&lt;br /&gt;print fibonacci(1000)&lt;/pre&gt;Here, however, is essentially the same function (memoized) implemented using a trampoline. The trampoline allows it to "recurse" all the way to the leaf calls because the calls are actually being made external to the function and state is being preserved in the with_a/with_b closures:&lt;br /&gt;&lt;pre&gt;def kmemoized(func):&lt;br /&gt;  cache = {}&lt;br /&gt;  def decorator(k, *args):&lt;br /&gt;    if args in cache:&lt;br /&gt;      return Call(k, cache[args])&lt;br /&gt;    def with_value(value):&lt;br /&gt;      cache[args] = value&lt;br /&gt;      return Call(k, value)&lt;br /&gt;    return Call(func, with_value, *args)&lt;br /&gt;  return decorator&lt;br /&gt;&lt;br /&gt;@kmemoized&lt;br /&gt;def fibonacci(k, n):&lt;br /&gt;  if n &lt; 2:&lt;br /&gt;    return Call(k, n)&lt;br /&gt;  def with_a(a):&lt;br /&gt;    def with_b(b):&lt;br /&gt;      return Call(k, a + b)&lt;br /&gt;    return Call(fibonacci, with_b, n - 1)&lt;br /&gt;  return Call(fibonacci, with_a, n - 2)&lt;/pre&gt;Practical for typical application development? Probably not...&lt;br /&gt;&lt;br /&gt;A neat concept to play around with (or an interesting strategy at generating Python code)? Definitely!&lt;br /&gt;&lt;br /&gt;(Somewhat) related wikipedia articles: &lt;a href="http://en.wikipedia.org/wiki/Continuation"&gt;continuation&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Functional_programming"&gt;functional-programming&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Tail_call_optimization"&gt;tail-call-optimization&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Thunk"&gt;thunk&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Closure_%28computer_science%29"&gt;closure&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6946125878559207247-4107972731242148746?l=davywybiral.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davywybiral.blogspot.com/feeds/4107972731242148746/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6946125878559207247&amp;postID=4107972731242148746' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/4107972731242148746'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/4107972731242148746'/><link rel='alternate' type='text/html' href='http://davywybiral.blogspot.com/2008/11/trampolining-for-recursion.html' title='Trampolining for recursion...'/><author><name>Wybiral</name><uri>http://www.blogger.com/profile/04401873536119552162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_ZeDxs16m_Ns/SXKZ4kxjniI/AAAAAAAAAKE/3kIaGWSXwec/S220/avatar179439_18.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6946125878559207247.post-6005721934580153710</id><published>2008-08-06T14:00:00.000-07:00</published><updated>2011-05-03T00:45:51.376-07:00</updated><title type='text'>Python: know when to be lazy</title><content type='html'>Lazy is good. One Python trend I've noticed quite a bit is the severe under-usage of generators. I often see list comprehension being used in situations where building a temporary list is not only wasteful, but more work.&lt;br /&gt;&lt;br /&gt;Example:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;print sum([x * 2 for x in something])&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In this case, LC is being used to build a temporary list whose only purpose is to be iterated by "sum". Instead of constructing this list, why not pass an iterable object to "sum" and have it accumulate the sum from that? Well, not only can you, but it's even less to type (a whopping two characters less):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;print sum(x * 2 for x in something)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Simply excluding the square brackets takes it from a list-comp to a generator expression, which is lazily evaluated. To demonstrate, proof that generators don't actually compute anything until they are pulled:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def f(x):&lt;br /&gt;    print x&lt;br /&gt;&lt;br /&gt;a = [f("LC") for x in xrange(10)]&lt;br /&gt;b = (f("GE") for x in xrange(10))&lt;br /&gt;&lt;br /&gt;print "outside"&lt;br /&gt;b.next()&lt;br /&gt;&lt;br /&gt;print "outside"&lt;br /&gt;b.next()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So naturally, these can be a really useful and compact way to transform a sequence. But the generator-expression syntax doesn't really allow for very complex stuff... Lucky Python also supports generator functions using the "yield" keyword that allows you to lazily preserve state between calls to "next"&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def powersof2():&lt;br /&gt;    x = 1&lt;br /&gt;    while True:&lt;br /&gt;        yield x&lt;br /&gt;        x *= 2&lt;br /&gt;&lt;br /&gt;g = powersof2()&lt;br /&gt;print g.next()&lt;br /&gt;print g.next()&lt;br /&gt;print g.next()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And then, another thing I see is similar use of the map, filter, zip functions, which here in Python2.5 land return an entire list (this won't be an issue in Python3, however). For the time being, if you need a lazy map/filter, either use generator expressions or use the itertools module&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;from itertools import imap, ifilter&lt;br /&gt;&lt;br /&gt;def even(x):&lt;br /&gt;    return not(x % 2)&lt;br /&gt;&lt;br /&gt;print sum(ifilter(even, imap(int, "1 2 3 4 5 6 7 8 9".split())))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In this case, the imap/ifilter works better than generator expressions (IMO) because of the need for the strings as integers in the "even" function. With GE I'm forced to either call the int function twice, or to break it up across lines:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;print sum(int(x) for x in "1 2 3 4 5 6 7 8 9".split() if even(int(x)))&lt;br /&gt;# OR&lt;br /&gt;ints = (int(x) for x in "1 2 3 4 5 6 7 8 9".split())&lt;br /&gt;print sum(x for x in ints if even(x))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;But, since this is lazy, the filtering is done as the mapping takes place (neither are bundled into any temporary lists or anything)&lt;br /&gt;&lt;br /&gt;Likewise, using "range" instead of "xrange" for integer iteration is also a wasteful practice (this will be fixed in Python3 as well).&lt;br /&gt;&lt;br /&gt;To wrap it up, just for fun (no practical value to a Python coder at all), how would you make a lazy sequence in Python if it didn't support generators or iterators? The way the lisp gods did before us... (lazy cons streams)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def fibonacci(a=0, b=1):&lt;br /&gt;    return (a, lambda: fibonacci(b, a + b))&lt;br /&gt;&lt;br /&gt;def take(n, seq):&lt;br /&gt;    if n:&lt;br /&gt;        return (seq[0], lambda: take(n - 1, apply(seq[1])))&lt;br /&gt;&lt;br /&gt;def lmap(f, seq):&lt;br /&gt;    while seq:&lt;br /&gt;        yield f(seq[0])&lt;br /&gt;        seq = apply(seq[1])&lt;br /&gt;&lt;br /&gt;print sum(lmap(int, take(1000, fibonacci())))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(I know, I cheated with the lmap function, but Pythons recursive limit makes it a bit impractical)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6946125878559207247-6005721934580153710?l=davywybiral.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davywybiral.blogspot.com/feeds/6005721934580153710/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6946125878559207247&amp;postID=6005721934580153710' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/6005721934580153710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/6005721934580153710'/><link rel='alternate' type='text/html' href='http://davywybiral.blogspot.com/2008/08/python-know-when-to-be-lazy.html' title='Python: know when to be lazy'/><author><name>Wybiral</name><uri>http://www.blogger.com/profile/04401873536119552162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_ZeDxs16m_Ns/SXKZ4kxjniI/AAAAAAAAAKE/3kIaGWSXwec/S220/avatar179439_18.png'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6946125878559207247.post-7767393478123329645</id><published>2008-07-23T12:56:00.000-07:00</published><updated>2008-07-23T17:02:15.782-07:00</updated><title type='text'>GAE: Batch operations</title><content type='html'>Given the limit on individual requests with GAE, doing things like batch updates to your database (live) can be an interesting challenge. I recently had to update all of the votes for &lt;a href="http://www.challenge-you.com/"&gt;Challenge-You!&lt;/a&gt; to support a new rating system. The best approach I found was an AJAX-style solution. Have one request that returns a list of references to the entities you need to change (or if you're working with more than 1000 entities, you might want to partition the list into chunks by date or some other order, and work with one chunk at a time). Keeping those references in a stack in Javascript, pop them off one-by-one and send each to the controller that applies the change, repeating until the stack is empty. If the operations aren't too expensive, you could even send a handful of them per-request to speed things up. It's also trivial to implement some kind of progress bar or other graphical update to keep you informed.&lt;br /&gt;&lt;br /&gt;And example of the Javascript code (using &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt;) that handles the client side:&lt;br /&gt;&lt;pre style="border: 1px solid #d0d0d0; background-color: #eaeaea; padding: 8px;"&gt;var data = null;&lt;br /&gt;&lt;br /&gt;function doupdate() {&lt;br /&gt;    if(data.length == 0) return;&lt;br /&gt;    $.ajax({&lt;br /&gt;        type:"POST",&lt;br /&gt;        url:"doupdate",&lt;br /&gt;        data:"id=" + data.pop(),&lt;br /&gt;        success:function(msg) {&lt;br /&gt;            setTimeout(function() {&lt;br /&gt;                doupdate();&lt;br /&gt;            }, 1000);&lt;br /&gt;        }&lt;br /&gt;    });&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;$(document).ready(function() {&lt;br /&gt;    $.ajax({&lt;br /&gt;        type:"POST",&lt;br /&gt;        url:"getlist",&lt;br /&gt;        data:"",&lt;br /&gt;        success:function(msg) {&lt;br /&gt;            data = msg.split(" ");&lt;br /&gt;            doupdate();&lt;br /&gt;        }&lt;br /&gt;    });&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In this example, my site would have two urls for handling this, "getlist" which returns a space-delimited list of references/ids (however you're handling the entities) and "doupdate" which takes in one reference and applies the needed change.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6946125878559207247-7767393478123329645?l=davywybiral.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davywybiral.blogspot.com/feeds/7767393478123329645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6946125878559207247&amp;postID=7767393478123329645' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/7767393478123329645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/7767393478123329645'/><link rel='alternate' type='text/html' href='http://davywybiral.blogspot.com/2008/07/gae-batch-operations.html' title='GAE: Batch operations'/><author><name>Wybiral</name><uri>http://www.blogger.com/profile/04401873536119552162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_ZeDxs16m_Ns/SXKZ4kxjniI/AAAAAAAAAKE/3kIaGWSXwec/S220/avatar179439_18.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6946125878559207247.post-417805859976036278</id><published>2008-07-20T11:18:00.000-07:00</published><updated>2008-07-20T11:47:32.340-07:00</updated><title type='text'>Speed kiddies</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Speed kiddie:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Someone who learns or uses a low-level (often compiled) language for the constant coefficient performance increase. These people often have no regards for computational complexity and are usually confused by asymptotic notation. They frequently suffer from severe cases of premature optimization and believe that manageability comes second to runtime speed (in &lt;span style="font-weight: bold;"&gt;all&lt;/span&gt; applications). You can often find them trolling around web-forums bragging about their pointer or bit manipulation skills (the code is generally characterized by non-reusable design and a significant lack of readability).&lt;br /&gt;&lt;br /&gt;Examples:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;"What do you mean my algorithm runs at O(n!)? It's twice as fast as yours with this small test set"&lt;/li&gt;&lt;li&gt;"How do you write efficient code in Python... It doesn't even have pointers!"&lt;/li&gt;&lt;li&gt;"I don't need to write readable code, I'm not going to forget my own code..."&lt;/li&gt;&lt;li&gt;"High level languages are for the weak, real men enjoy pain... PAIN!!!"&lt;/li&gt;&lt;li&gt;"Lisp doesn't offer anything new to me, C has macros too!"&lt;br /&gt;&lt;/li&gt;&lt;li&gt;"RAWRRR POOINTERRRZZZ!!!!!!!!!!!!!!!!!!"&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6946125878559207247-417805859976036278?l=davywybiral.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davywybiral.blogspot.com/feeds/417805859976036278/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6946125878559207247&amp;postID=417805859976036278' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/417805859976036278'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/417805859976036278'/><link rel='alternate' type='text/html' href='http://davywybiral.blogspot.com/2008/07/speed-kiddies.html' title='Speed kiddies'/><author><name>Wybiral</name><uri>http://www.blogger.com/profile/04401873536119552162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_ZeDxs16m_Ns/SXKZ4kxjniI/AAAAAAAAAKE/3kIaGWSXwec/S220/avatar179439_18.png'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6946125878559207247.post-964587830994242271</id><published>2008-01-13T19:15:00.000-08:00</published><updated>2008-05-05T16:14:20.266-07:00</updated><title type='text'>Javascript == bad</title><content type='html'>Along the way while writing Epy, I've noticed some things about Javascript (a language I once considered perfectly reasonable) that are in serious need of a revamp (at least at the time of writing this). Here are just a few of the (many) issues I have with Javascript:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Namespaces. In the world of most Javascript, everything is global or function-scope, there seems to be no use of namespace or module-style development at all. It's possible to simulate namespaces by wrapping entire modules in an object definition, but this is usually too much of a hassle for practicality.&lt;/li&gt;&lt;li&gt;Objects. Javascript's object system is, well, crap. Sure, it's ad-hoc like Python, but it has no formal way of creating simple constructors. You can use the "this" object in a function, or create a new instance of "Object" to append methods to, but there are no standards for constructing an object.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Objects do &lt;span style="font-weight: bold;"&gt;not&lt;/span&gt; support destructors. Many might argue that a memory-safe language like Js doesn't need them, but destructors have more use than freeing memory. They serve a very useful purpose in a lot of OO designs, memory-safe or not.&lt;/li&gt;&lt;li&gt;Javascript does &lt;span style="font-weight: bold;"&gt;not&lt;/span&gt; support associative arrays! You can use the "Array" object, or even the "Object" object to assign associative values to using the index operators, but this is deceiving... Any time you use "obj['index'] = something" you could replace it with "obj.index = something" which causes major problems with naming collisions. This style of object/hashtable is bad, there should be a clear distinction between the two.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Javascript is &lt;span style="font-weight: bold;"&gt;not&lt;/span&gt; cross-browser compatible... Don't get me started...&lt;/li&gt;&lt;/ol&gt;Yet Javascript remains at the heart of our internet! Projects like Epy could help to solve some of these problems by abstracting away the issues allowing you to develop your client-side scripting in a more pleasant syntax (such as Python). But maybe someday we'll just use another language all-together :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6946125878559207247-964587830994242271?l=davywybiral.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davywybiral.blogspot.com/feeds/964587830994242271/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6946125878559207247&amp;postID=964587830994242271' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/964587830994242271'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6946125878559207247/posts/default/964587830994242271'/><link rel='alternate' type='text/html' href='http://davywybiral.blogspot.com/2008/01/javascript-bad.html' title='Javascript == bad'/><author><name>Wybiral</name><uri>http://www.blogger.com/profile/04401873536119552162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_ZeDxs16m_Ns/SXKZ4kxjniI/AAAAAAAAAKE/3kIaGWSXwec/S220/avatar179439_18.png'/></author><thr:total>3</thr:total></entry></feed>
