<?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-3366502883257825993</id><updated>2011-09-27T19:59:05.556-07:00</updated><category term='bittorrent'/><category term='regex'/><category term='control'/><category term='antenna'/><category term='sms'/><category term='python'/><category term='wifi'/><category term='twitter'/><category term='rss'/><category term='fortran'/><category term='programming'/><category term='parallel'/><category term='telescope'/><category term='mod'/><category term='art'/><category term='openmp'/><category term='eeepc'/><category term='general'/><category term='tvd'/><category term='f2py'/><category term='isohunt'/><category term='threading'/><category term='science'/><title type='text'>FluxTrap</title><subtitle type='html'>Trapping any inflow of productivity since 2008</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://fluxtrap.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://fluxtrap.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>mg</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img457.imageshack.us/img457/628/catseyenebula2smallnl4.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>12</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3366502883257825993.post-135074117659048300</id><published>2011-09-27T19:57:00.000-07:00</published><updated>2011-09-27T19:59:05.568-07:00</updated><title type='text'>Dead Simple Real Time Plotting with C/C++ and Python</title><content type='html'>&lt;h4&gt;Concepts:&lt;/h4&gt; &lt;br /&gt;&lt;ul&gt; &lt;br /&gt;  &lt;li&gt;Standard &lt;a href="http://en.wikipedia.org/wiki/Standard_streams#Standard_input_.28stdin.29"&gt;input&lt;/a&gt;/&lt;a href="http://en.wikipedia.org/wiki/Standard_streams#Standard_output_.28stdout.29"&gt;output&lt;/a&gt; (Think: the input and output of your program)&lt;/li&gt; &lt;br /&gt;  &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Pipeline_(Unix)"&gt;Unix Pipes&lt;/a&gt;&lt;/li&gt; &lt;br /&gt;  &lt;li&gt;&lt;a href="http://lmgtfy.com/?q=pylab+tutorial"&gt;Plotting with matplotlib&lt;/a&gt;&lt;/li&gt; &lt;br /&gt;&lt;/ul&gt; &lt;br /&gt; &lt;br /&gt;&lt;hr align=center width=75%&gt; &lt;br /&gt; &lt;br /&gt;  &lt;p&gt;So, you have your code working, but you are tired of having to run a separate program to see plots?  There are many simple solutions, but I am going to present what I think is the absolute simplest.  What we are going to do is have your C/C++ program output the data and have python capture it and save plots in real-time!  What does this entail?  Well...&lt;/p&gt; &lt;br /&gt; &lt;br /&gt;  &lt;ul&gt; &lt;br /&gt;   &lt;li&gt;Your C/C++ program no longer writes to a file (using fprintf), but rather writes to the standard output (STDIN, using simply printf)&lt;/li&gt; &lt;br /&gt;   &lt;li&gt;Your python script will now read data straight from STDIN using raw_input()&lt;/li&gt; &lt;br /&gt;   &lt;li&gt;You will have to use a unix shell to sew all of this together&lt;/li&gt; &lt;br /&gt;  &lt;/ul&gt; &lt;br /&gt; &lt;br /&gt;&lt;p&gt;Let's look at a very simple example.  Suppose we have a very important C program that outputs some very important numbers.  In order for it to work with this new standard, we have it output the data to screen.  Namely, it does:&lt;/p&gt; &lt;br /&gt; &lt;br /&gt;&lt;pre&gt; &lt;br /&gt;&lt;b&gt;makedata.c&lt;/b&gt; &lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;math.h&amp;gt;&lt;br /&gt; &lt;br /&gt;#define PI 3.14159&lt;br /&gt; &lt;br /&gt;int main()&lt;br /&gt;{ &lt;br /&gt;  int i,j;&lt;br /&gt;  for(j=0; j&amp;lt;10; j++) {&lt;br /&gt;    for(i=0; i&amp;lt;20; i++) {&lt;br /&gt;      printf("%f\t",sinf(i * PI / 10.0 + j*PI/10));&lt;br /&gt;    }&lt;br /&gt;    printf("\n");&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;p&gt;Now, when we run this, we get a bunch of numbers thrown to screen!&lt;/p&gt; &lt;br /&gt; &lt;br /&gt;&lt;pre&gt; &lt;br /&gt;$ gcc -lm -o makedata makedata.c&lt;br /&gt;$ ./makedata&lt;br /&gt;0.000000 0.309017 0.587785 0.809017 0.951056 1.000000 0.951057 0.809018 0.587787 0.309019 0.000003 -0.309014 -0.587783 -0.809015 -0.951055 -1.000000 -0.951058 -0.809020 -0.587789 -0.309022 &lt;br /&gt;0.309017 0.587785 0.809017 0.951056 1.000000 0.951057 0.809018 0.587787 0.309019 0.000003 -0.309014 -0.587783 -0.809015 -0.951055 -1.000000 -0.951058 -0.809020 -0.587789 -0.309022 -0.000005 &lt;br /&gt;0.587785 0.809017 0.951056 1.000000 0.951057 0.809018 0.587787 0.309019 0.000003 -0.309014 -0.587783 -0.809015 -0.951055 -1.000000 -0.951058 -0.809020 -0.587789 -0.309022 -0.000005 0.309012 &lt;br /&gt;0.809017 0.951056 1.000000 0.951057 0.809018 0.587787 0.309019 0.000003 -0.309014 -0.587783 -0.809015 -0.951055 -1.000000 -0.951058 -0.809020 -0.587789 -0.309022 -0.000005 0.309012 0.587781 &lt;br /&gt;0.951056 1.000000 0.951057 0.809018 0.587787 0.309019 0.000003 -0.309014 -0.587783 -0.809015 -0.951055 -1.000000 -0.951058 -0.809020 -0.587789 -0.309022 -0.000005 0.309012 0.587781 0.809013 &lt;br /&gt;1.000000 0.951057 0.809018 0.587787 0.309019 0.000003 -0.309014 -0.587783 -0.809015 -0.951055 -1.000000 -0.951058 -0.809020 -0.587789 -0.309022 -0.000005 0.309012 0.587781 0.809013 0.951055 &lt;br /&gt;0.951057 0.809018 0.587787 0.309019 0.000003 -0.309014 -0.587783 -0.809015 -0.951055 -1.000000 -0.951058 -0.809020 -0.587789 -0.309022 -0.000005 0.309012 0.587781 0.809013 0.951055 1.000000 &lt;br /&gt;0.809018 0.587787 0.309019 0.000003 -0.309014 -0.587783 -0.809015 -0.951055 -1.000000 -0.951058 -0.809020 -0.587789 -0.309022 -0.000005 0.309012 0.587781 0.809013 0.951055 1.000000 0.951059 &lt;br /&gt;0.587787 0.309019 0.000003 -0.309014 -0.587783 -0.809015 -0.951055 -1.000000 -0.951058 -0.809020 -0.587789 -0.309022 -0.000005 0.309012 0.587781 0.809013 0.951055 1.000000 0.951059 0.809021 &lt;br /&gt;0.309019 0.000003 -0.309014 -0.587783 -0.809015 -0.951055 -1.000000 -0.951058 -0.809020 -0.587789 -0.309022 -0.000005 0.309012 0.587781 0.809013 0.951055 1.000000 0.951059 0.809021 0.587792 &lt;br /&gt;&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;p&gt;In order to capture the data in python, we must use the raw_input() function.  This function simply gets input from the user and puts it into a variable.  It puts everything the user types up to when they press enter.  This is why the C code is that it only prints a newline (ie: '\n') once one full line of data has been outputted to screen. If we had put a newline in the first printf statement, the python plotting program would only plot one number at a time!  So, you can think of the tab (\t) as deliniating between values and the newline (\n) deliniating between different sets of data.  The python code that reads this data looks like:&lt;/p&gt; &lt;br /&gt; &lt;br /&gt;&lt;pre&gt; &lt;br /&gt;&lt;b&gt;plot.py&lt;/b&gt; &lt;br /&gt;import numpy as np&lt;br /&gt;import pylab as py&lt;br /&gt; &lt;br /&gt;def plot_data(data):&lt;br /&gt;  py.clf()&lt;br /&gt;  py.plot(data)&lt;br /&gt;  py.show()&lt;br /&gt;  py.savefig("data-%.8d.png"%counter)&lt;br /&gt; &lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;  counter = 0&lt;br /&gt;  while True:&lt;br /&gt;    try:&lt;br /&gt;      tmp = raw_input().strip().split()&lt;br /&gt;      data = np.array(tmp, dtype=np.double)&lt;br /&gt;    except EOFError:&lt;br /&gt;      print "Input has terminated! Exiting"&lt;br /&gt;      exit()&lt;br /&gt;    except ValueError:&lt;br /&gt;      print "Invalid input, skipping.  Input was: %s"%tmp&lt;br /&gt;      continue&lt;br /&gt; &lt;br /&gt;    print "Plotting plot number %d"%counter&lt;br /&gt;    plot_data(data)&lt;br /&gt;    counter += 1&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;p&gt;You can test this program by running it, typing a bunch of numbers separated by a space, then pressing enter.  It will plot it, display it and save it!  Then, the program will ask you again for more numbers.  To exit, you type Control-D which makes the EOFError happen.&lt;/p&gt; &lt;br /&gt; &lt;br /&gt;&lt;p&gt;What is going on in this program is quite simple.  First, "tmp" gets the long string of characters that you typed in.  However, python doesn't know it contains numbers, it just looks like a bunch of random characters!  Now, we use numpy and tell it to create an array out of the data.  The "dtype=np.double" is us telling numpy that we are realing with valid numbers.  A ValueError happens if we weren't good on our promise and the input isn't in fact all numbers.&lt;/p&gt; &lt;br /&gt; &lt;br /&gt;&lt;p&gt;Now for the most important part... how do we put these two things together?  Unix has a very cool thing called input/output redirection.  This allows us to redirect the output of one program to the input of another.  So, instead of us having to type in the numbers for the python script, we can have the C/C++ program type it for us!  The syntax is quite simple, all you have to do is:&lt;/p&gt; &lt;br /&gt; &lt;br /&gt;&lt;pre&gt; &lt;br /&gt;$ ./makedata | python plot.py&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;p&gt;And now you are done!  You should have a bunch of plots coming up of sin waves with various phases. Congrats!&lt;/p&gt; &lt;br /&gt; &lt;br /&gt;&lt;p&gt;There is one more thing you can do to make your plots even more fancy.  Sometimes, you don't want to save each figure or have to click through to see every plot, one at a time.  Instead, you just want to see an animation of what is happening as it is happening!  Or, you are already making an animation with many py.plot() statements, and you want it to be smoother and faster!  To do this, you can to look into pylab animations.  The people at scipy have a great &lt;a href="http://www.scipy.org/Cookbook/Matplotlib/Animations"&gt;tutorial&lt;/a&gt; on this issue.  You can also look at a &lt;a href="https://github.com/mynameisfiber/waveequation/blob/master/fortran/test-waveequation.py"&gt;small plotting script&lt;/a&gt; I made which does something very similar.&lt;/p&gt; &lt;br /&gt; &lt;br /&gt;&lt;p&gt;The basics of this method involve: creating your plots at the beginning of your script, and saving them into variables.  Then, when you get new data that you want to plot, you simply change the data in the plot with .set_data().  One thing to note is the line "py.ion()" right after I imported pylab and how I use py.draw() instead of py.show().  If you want to get started playing around with this, simply take the same code from earlier in this document, add "py.ion()" after we import pylab, delete the py.savefig() line and replace py.show() with py.draw()!  This will give you a (quite slow) animation.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3366502883257825993-135074117659048300?l=fluxtrap.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fluxtrap.blogspot.com/feeds/135074117659048300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fluxtrap.blogspot.com/2011/09/dead-simple-real-time-plotting-with-cc.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/135074117659048300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/135074117659048300'/><link rel='alternate' type='text/html' href='http://fluxtrap.blogspot.com/2011/09/dead-simple-real-time-plotting-with-cc.html' title='Dead Simple Real Time Plotting with C/C++ and Python'/><author><name>mg</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img457.imageshack.us/img457/628/catseyenebula2smallnl4.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3366502883257825993.post-3040328901315897452</id><published>2010-01-06T23:00:00.000-08:00</published><updated>2010-01-07T14:59:18.991-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='openmp'/><category scheme='http://www.blogger.com/atom/ns#' term='tvd'/><category scheme='http://www.blogger.com/atom/ns#' term='fortran'/><category scheme='http://www.blogger.com/atom/ns#' term='f2py'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='parallel'/><title type='text'>fortran + python = good</title><content type='html'>So, after a long time working solely in &lt;a href="http://en.wikipedia.org/wiki/Fortran"&gt;FORTRAN&lt;/a&gt;, I decided to try to find a way to use python to get the same things done.  I wanted to incorporate what I had done in FORTRAN as a library that way I wouldn't have to recode much and could instead continue developing (except now in the wonderful warmth of python)&lt;br /&gt;&lt;br /&gt;The most successful method I tried was using f2py.  What f2py does is take in a FORTRAN module (see the tvd module below, for example) and makes a python interface for it.  What this means is that you can import fortran code and run it at the the speeds you would expect from compiled code!&lt;br /&gt;&lt;br /&gt;Let me first take you through &lt;a href="http://www.blogger.com/post-edit.g?blogID=3366502883257825993&amp;amp;postID=3040328901315897452#code"&gt;the module&lt;/a&gt;.  You can see from the 'include "omp_lib.h"' that I'm using &lt;a href="http://openmp.org/wp/openmp-specifications/"&gt;openMP&lt;/a&gt;.  For those that don't know, openMP is a great way of making any code parallel on shared memory machines (ie: if you have a computer with multiple cores or hyper-threading).  The lines with "!$OMP", called &lt;a href="http://en.wikipedia.org/wiki/Directive_(programming)"&gt;pragmas&lt;/a&gt;, are in fact  calls to openMP and effect to proceeding code.  In addition, I created a function called "set_num_threads" to manually change the ammount of parallelization that is used by the program (by default, the number of threads is equal to the number of CPU's on the machine).  A great thing about this "!$OMP" convention is that, since ! designates a comment, you can still compile and run this code without having openMP enabled!&lt;br /&gt;&lt;br /&gt;Now, let's move on to &lt;a href="http://www.scipy.org/F2py"&gt;f2py&lt;/a&gt;!  You can see every subroutine (and function) has lines starting with "!f2py".  Similar to openMP, this is used to designate various options.  For example, the "!f2py threadsafe" tells python that the function will be using various threads and that the gil shouldn't be used.  As a result, we cannot take in or return in python objects (there are methods to take in &lt;a href="http://cens.ioc.ee/projects/f2py2e/usersguide/index.html#call-back-arguments"&gt;python callbacks&lt;/a&gt; when not using threadsafe).  The intent option sets if a parameter is going to be inputed or outputted.  With intent, python knows how to interpret python input and what should be given back as return values.&lt;br /&gt;&lt;br /&gt;So, let's look at the function set.  It takes in, in python, u and CFL.  The other parameters are optional.  In addition, you can see that "dt" and "maxv" are inputs but are calculated in the function.  I did this little hack so that I can return multiple values to python.  So in the end, this function is defined, in the python space, as "u, dt, maxv = step(u, cfl)".  The most beautiful part is that when passing u to this module from python, u is a numpy array!  Note that the other functions that are called (namely, do[XYZ] are also defined in the module, however for the sake of brevity they are not listed below).&lt;br /&gt;&lt;br /&gt;In order to use this fortran module, we need to compile it with f2py.  The end result is a .so that can be imported into fortran.  I compiled this particular module with `f2py -c -m tvd --f90flags="-fopenmp -lm " --opt="-O3 --ffast-math" -lgomp --fcompiler=gnu95 tvd.f90`  So, let's go through this.  "-c" tells f2py to look at the pragmas in the code in order to learn how each function should be handled.  "-m tvd" defined the name of the resulting module.  the --f90flags, as expected, dictate the flags send to the FORTRAN compiler.  I have chosen to use openmp (not needed, by the way, with newer versions of GCC where openMP is built-in) and libmath.  opt sets the optimization flags.  -lgomp tells f2py to use openMP (this redundancy seems necessary although I have a feeling that one of my statements telling f2py to use openMP is redundant).  Finally, "fcompiler" tells f2py to use gfortran.&lt;br /&gt;&lt;br /&gt;Let's look at a little session with this module, as to understand what f2py created.  (I use &lt;a href="http://ipython.scipy.org/"&gt;ipython&lt;/a&gt; for its tab-completion)&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;In [1]: import numpy&lt;br /&gt;&lt;br /&gt;In [2]: from tvd import tvd&lt;br /&gt;&lt;br /&gt;In [3]: u = numpy.random.random((4,100,100,100)) #create a random velocity field&lt;br /&gt;&lt;br /&gt;In [4]: u[0,:,:,:] = 1 #set density to 1 to avoid instabilities&lt;br /&gt;&lt;br /&gt;In [5]: %timeit output = tvd.step(u, 0.65)&lt;br /&gt;10 loops, best of 3: 704 ms per loop&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Amazing!  It takes &lt;b&gt;704ms&lt;/b&gt; to evolve a 100x100x100 isothermal grid!  Normal usage of this would be: `u, dt, maxv = tvd.step(u, 0.65)`.  One note, I write "from tvd import tvd" because the first "tvd" represents the file and the second "tvd" represents the FORTRAN module.  If instead I had just written tvd.f90 as a series of subroutines and not as a FORTRAN module, I could have simply written "import tvd".  Now, I can get to doing real science instead of being swamped by the inhuman syntax of FORTRAN (a language best spelled in all caps to truly illustrate its crimes).&lt;br /&gt;&lt;br /&gt;And now, for the code... I'm leaving out the actual computational part however I may release that in the near future (comment if you'd like to see it!).&lt;br /&gt;&lt;br /&gt;&lt;a name="code"&gt;&lt;/a&gt;&lt;br /&gt;&lt;pre class="prettyprint" style="border-style: solid; border-width: thin; overflow-y: scroll; overflow-x: auto; width: 525px; height: 600px;"&gt;tvd.f90:&lt;br /&gt;MODULE tvd&lt;br /&gt;&lt;br /&gt;  implicit none&lt;br /&gt;  include "omp_lib.h"&lt;br /&gt;&lt;br /&gt;  DOUBLE PRECISION :: csound=1&lt;br /&gt;&lt;br /&gt;  CONTAINS&lt;br /&gt;&lt;br /&gt;  SUBROUTINE set_num_threads(n)&lt;br /&gt;    !f2py threadsafe&lt;br /&gt;    !f2py intent(in) n&lt;br /&gt;    INTEGER :: n&lt;br /&gt;    CALL OMP_SET_NUM_THREADS(n)&lt;br /&gt;  END SUBROUTINE set_num_threads&lt;br /&gt;&lt;br /&gt;  SUBROUTINE step(u, n, CFL, dt, maxv)&lt;br /&gt;    !f2py threadsafe&lt;br /&gt;    !f2py intent(in) u&lt;br /&gt;    !f2py intent(in) n&lt;br /&gt;    !f2py intent(in) CFL&lt;br /&gt;    !f2py intent(in), optional dt&lt;br /&gt;    !f2py intent(in), optional maxv&lt;br /&gt;    !f2py intent(out) :: u, dt, maxv&lt;br /&gt;    !f2py depend(u) n&lt;br /&gt;    INTEGER :: n, k&lt;br /&gt;    DOUBLE PRECISION, DIMENSION(4,n,n,n) :: u&lt;br /&gt;    DOUBLE PRECISION :: CFL, dt, maxv&lt;br /&gt;  &lt;br /&gt;    !$OMP PARALLEL DO shared(u) private(n,k) &amp;amp;&lt;br /&gt;    !$OMP SCHEDULE(dynamic) REDUCTION(MAX:maxv)&lt;br /&gt;    DO k=1,n&lt;br /&gt;      maxv = max( maxval( abs(u(2,:,:,k)) / u(1,:,:,k) ), &amp;&lt;br /&gt;                  maxval( abs(u(3,:,:,k)) / u(1,:,:,k) ), &amp;&lt;br /&gt;                  maxval( abs(u(4,:,:,k)) / u(1,:,:,k) )  &amp;&lt;br /&gt;                )&lt;br /&gt;    END DO&lt;br /&gt;    !$OMP END PARALLEL DO&lt;br /&gt;  &lt;br /&gt;    !Calculate the timestep based on the courant condition&lt;br /&gt;    if (dt .eq. 0.0) dt = CFL / (csound+maxv)&lt;br /&gt;   &lt;br /&gt;    !perform strang splitting using the hydro only 2nd order&lt;br /&gt;    !TVD algorithm given by http://arxiv.org/abs/astro-ph/0305088&lt;br /&gt;    CALL doX(u,n,dt, maxv)&lt;br /&gt;     CALL doY(u,n,dt, maxv)&lt;br /&gt;      CALL doZ(u,n,dt, maxv)&lt;br /&gt;      CALL doZ(u,n,dt, maxv)&lt;br /&gt;     CALL doY(u,n,dt, maxv)&lt;br /&gt;    CALL doX(u,n,dt, maxv)&lt;br /&gt;  END subroutine step&lt;br /&gt;END MODULE&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/3366502883257825993-3040328901315897452?l=fluxtrap.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fluxtrap.blogspot.com/feeds/3040328901315897452/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fluxtrap.blogspot.com/2009/12/fortran-python-good.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/3040328901315897452'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/3040328901315897452'/><link rel='alternate' type='text/html' href='http://fluxtrap.blogspot.com/2009/12/fortran-python-good.html' title='fortran + python = good'/><author><name>mg</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img457.imageshack.us/img457/628/catseyenebula2smallnl4.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3366502883257825993.post-4328549223528683136</id><published>2009-05-07T15:17:00.000-07:00</published><updated>2009-05-07T15:52:03.494-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='control'/><category scheme='http://www.blogger.com/atom/ns#' term='bittorrent'/><category scheme='http://www.blogger.com/atom/ns#' term='regex'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='twitter'/><category scheme='http://www.blogger.com/atom/ns#' term='isohunt'/><category scheme='http://www.blogger.com/atom/ns#' term='sms'/><category scheme='http://www.blogger.com/atom/ns#' term='rss'/><category scheme='http://www.blogger.com/atom/ns#' term='threading'/><title type='text'>SMS/Twitter Control of your server</title><content type='html'>Well, I thought it was about time to post something, so let me show you this little project I've been tinkering with.  It basically allows me to control my server with a cellphone.  This can be applied to any computer with python installed and can do really anything (right now I have it search/download bittorrent files).&lt;br /&gt;&lt;br /&gt;It basically works by creating a master thread on the server that constantly checks some secured twitter account for directed messages.  This basically means that you can send a directed message to some secured user through twitter from your cell phone and when the computer reads this message it will act on it.&lt;br /&gt;&lt;br /&gt;The following is the main code: it creates a main thread on the computer listening for new messages.  When a new message is found, a new thread is created and the correct command is executed (the commands are defined in the configuration file which will come soon).  The benefit to creating new threads is that the task can be halted later by initiating a stop command (the stop commands are hard programmed and are automatically generated for each configuration defined command).&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint" style="border-style: solid; border-width: thin; overflow-y: scroll; overflow-x: auto; width: 525px; height: 600px;"&gt;#!/usr/bin/python&lt;br /&gt;#&lt;br /&gt;# Copyright 2008 Michael Gorelick &lt;mynameisfiber[ait]gmail[dodt]com&gt;&lt;br /&gt;#&lt;br /&gt;# This program is free software: you can redistribute it and/or modify&lt;br /&gt;# it under the terms of the GNU General Public License as published by&lt;br /&gt;# the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;# (at your option) any later version.&lt;br /&gt;#&lt;br /&gt;# This program is distributed in the hope that it will be useful,&lt;br /&gt;# but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;# GNU General Public License for more details.&lt;br /&gt;#&lt;br /&gt;# You should have received a copy of the GNU General Public License&lt;br /&gt;# along with this program.  If not, see:&lt;br /&gt;# http://www.gnu.org/licenses/gpl.html.&lt;br /&gt;from __future__ import division&lt;br /&gt;&lt;br /&gt;'''A tool to allow for remote control of a machine with twitter'''&lt;br /&gt;&lt;br /&gt;__author__ = 'Michael G &lt;mynameisfiber@gmail.com&gt;'&lt;br /&gt;__version__ = '0.1'&lt;br /&gt;&lt;br /&gt;from sys import stdout&lt;br /&gt;import threading, time, twitter, re, ConfigParser, subprocess&lt;br /&gt;&lt;br /&gt;######### CONFIG FILE ##############&lt;br /&gt;configfile = 'twitcontrol.conf'&lt;br /&gt;&lt;br /&gt;class TwitThread(threading.Thread):&lt;br /&gt;  def __init__(self,actions,twitter,command):&lt;br /&gt;    threading.Thread.__init__(self)&lt;br /&gt;    self._stop = threading.Event()  #Set the hook for self.stop()&lt;br /&gt;    self.actions = actions&lt;br /&gt;    self.twitter = twitter&lt;br /&gt;    self.commandstruct = command&lt;br /&gt;    self.process = None&lt;br /&gt;&lt;br /&gt;  def run(self):&lt;br /&gt;    '''Finds what action is linked to the inputed command'''&lt;br /&gt;    command = self.commandstruct['text']&lt;br /&gt;    for name,contents in self.actions.iteritems():&lt;br /&gt;      found = contents['match'].match(command)&lt;br /&gt;      if found:&lt;br /&gt;        self.name = name&lt;br /&gt;        print "%s: %s: Starting"%(time.ctime(),name)&lt;br /&gt;        self.doCommand(found,command,contents)&lt;br /&gt;        return None&lt;br /&gt;      elif command.lower() == "stop %s"%name.lower():&lt;br /&gt;        self.name = "killthread-%s"%name&lt;br /&gt;        for thread in threading.enumerate():&lt;br /&gt;          if thread.name.lower() == name.lower():&lt;br /&gt;            print "%s: Killing %s"%(time.ctime(),name)&lt;br /&gt;            thread.stop()&lt;br /&gt;        return None&lt;br /&gt;&lt;br /&gt;  def doCommand(self,match,command,action):&lt;br /&gt;    '''Runs the command given by the config file for the given input'''&lt;br /&gt;    if action["output"] == "start":&lt;br /&gt;      self.message("%s: Started"%self.name)&lt;br /&gt;    print "Running command: %s"%(action["command"]%match.groupdict())&lt;br /&gt;    self.process = subprocess.Popen(action["command"]%match.groupdict(),\&lt;br /&gt;      stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)&lt;br /&gt;    #We use the following hack because Popen.wait() or Popen.interact() lock&lt;br /&gt;    #the process so we cannot kill it if another thread sends a self.stop()&lt;br /&gt;    while self.process.poll() == None:&lt;br /&gt;      time.sleep(1)&lt;br /&gt;    if action["output"] == "end":&lt;br /&gt;      self.message("%s: Done"%self.name)&lt;br /&gt;    if self.process.returncode != 0:&lt;br /&gt;      err = self.formatstd(self.process.stderr)&lt;br /&gt;      print "%s: %s: Error: %s"%(time.ctime(),self.name,err)&lt;br /&gt;      if action["output"] == "output":&lt;br /&gt;        self.message("%s: Error: %s"%(self.name,err))&lt;br /&gt;    else:&lt;br /&gt;      suc = self.formatstd(self.process.stdout)&lt;br /&gt;      print "%s: %s: Success: %s"%(time.ctime(),self.name,suc)&lt;br /&gt;      if action["output"] == "output":&lt;br /&gt;        self.message("%s: Success: %s"%(self.name,suc))&lt;br /&gt;&lt;br /&gt;  def formatstd(self,fd,maxsize=120):&lt;br /&gt;    '''Extracts and formats data from a datastream'''&lt;br /&gt;    return ", ".join([x.strip() for x in fd.readlines()])[:maxsize]&lt;br /&gt;&lt;br /&gt;  def message(self,msg):&lt;br /&gt;    '''Sends a tweet to the command sender truncated to 140 characters'''&lt;br /&gt;    self.twitter.PostDirectMessage(self.commandstruct['sender_id'],msg[:140])&lt;br /&gt;&lt;br /&gt;  def stop(self):&lt;br /&gt;    '''Stops the current thread and terminates any open processes'''&lt;br /&gt;    print "%s: %s: Thread Killed"%(time.ctime(),self.name)&lt;br /&gt;    self.process.terminate()&lt;br /&gt;    self._stop.set()&lt;br /&gt;&lt;br /&gt;  def stopped(self):&lt;br /&gt;    return self._stop.isSet()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class TwitControl:&lt;br /&gt;  def __init__(self,actions,user,passwd,recieveID,timeout=5):&lt;br /&gt;    self.actions = actions&lt;br /&gt;    self.twitter = twitter.Api(username=user,password=passwd)&lt;br /&gt;    self.recieveID = recieveID&lt;br /&gt;    self.timeout = timeout&lt;br /&gt;&lt;br /&gt;  def getMessages(self):&lt;br /&gt;    '''Gets all directed messages from twitter from a given user'''&lt;br /&gt;    return [x.AsDict() for x in self.twitter.GetDirectMessages() \&lt;br /&gt;    if x.GetSenderId() == self.recieveID]&lt;br /&gt;&lt;br /&gt;  def start(self):&lt;br /&gt;    '''Checks for new messages and commands the threads'''&lt;br /&gt;    commands = self.getMessages()&lt;br /&gt;    numcommands = len(commands)&lt;br /&gt;    while True:&lt;br /&gt;      commands = self.getMessages()&lt;br /&gt;      print ".",; stdout.flush()&lt;br /&gt;      if len(commands) &gt; numcommands:&lt;br /&gt;        for command in commands[0:len(commands)-numcommands]:&lt;br /&gt;          print "%s: MASTER: Found Command: %s"%(time.ctime(),command['text'])&lt;br /&gt;          TwitThread(self.actions,self.twitter,command).start()&lt;br /&gt;        numcommands = len(commands)&lt;br /&gt;      elif len(commands) &lt; numcommands:&lt;br /&gt;        numcommands = len(commands)&lt;br /&gt;      time.sleep(self.timeout)&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;  configfd = ConfigParser.RawConfigParser()&lt;br /&gt;  configfd.read(configfile)&lt;br /&gt;  print "Reading config: %s" % configfile&lt;br /&gt;&lt;br /&gt;  username  = configfd.get('Connection', 'username')&lt;br /&gt;  password  = configfd.get('Connection', 'password')&lt;br /&gt;  recieveID = configfd.getint('Connection', 'recieveID')&lt;br /&gt;  if configfd.has_option('Connection', 'timeout'):&lt;br /&gt;    timeout = configfd.getint('Connection', 'timeout')&lt;br /&gt;  else:&lt;br /&gt;    timeout = 5&lt;br /&gt;&lt;br /&gt;  actions = {}&lt;br /&gt;  for section in configfd.sections():&lt;br /&gt;    if section == 'Connection':&lt;br /&gt;      continue&lt;br /&gt;    action = {}&lt;br /&gt;    action['match']   = re.compile(configfd.get(section,'match'))&lt;br /&gt;    action['command'] = configfd.get(section,'command')&lt;br /&gt;    action['output']  = configfd.get(section,'output')&lt;br /&gt;    actions.update({section:action})&lt;br /&gt;  print "Loaded modules: %s"%", ".join(actions.keys())&lt;br /&gt;&lt;br /&gt;  print "Listening to user: %s"%username&lt;br /&gt;  control = TwitControl(actions,username,password,recieveID,timeout)&lt;br /&gt;  control.start()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And the following is a sample from the configuration file:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint" style="border-style: solid; border-width: thin; overflow-y: scroll; overflow-x: auto; width: 525px; height: 400px;"&gt;# Copyright 2008 Michael Gorelick &lt;mynameisfiber[ait]gmail[dodt]com&gt;&lt;br /&gt;#&lt;br /&gt;# This program is free software: you can redistribute it and/or modify&lt;br /&gt;# it under the terms of the GNU General Public License as published by&lt;br /&gt;# the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;# (at your option) any later version.&lt;br /&gt;#&lt;br /&gt;# This program is distributed in the hope that it will be useful,&lt;br /&gt;# but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;# GNU General Public License for more details.&lt;br /&gt;#&lt;br /&gt;# You should have received a copy of the GNU General Public License&lt;br /&gt;# along with this program.  If not, see:&lt;br /&gt;# http://www.gnu.org/licenses/gpl.html.&lt;br /&gt;&lt;br /&gt;[Connection]&lt;br /&gt;username = Secured Username&lt;br /&gt;password = Password of secured username&lt;br /&gt;recieveID = User ID of the command issuer&lt;br /&gt;&lt;br /&gt;[reverseSSH]&lt;br /&gt;match = reverse (?P&lt;IP&gt;(?:\d{1,3}\.?){4}) (?P&lt;PORT&gt;\d+)&lt;br /&gt;command = ssh -R %(PORT)s:localhost:22 %(IP)s&lt;br /&gt;output = start&lt;br /&gt;&lt;br /&gt;[Talk]&lt;br /&gt;match = say (?P&lt;text&gt;.+)&lt;br /&gt;command = flite -t "%(text)s"&lt;br /&gt;output = None&lt;br /&gt;&lt;br /&gt;[Bittorrent]&lt;br /&gt;match = bt (?P&lt;search&gt;.+)&lt;br /&gt;command = transmission-remote -a "`/home/fiber/projects/pyisohunt/pyisohunt.py -n 1 -s seeds -p '%%(url)s' %(search)s`"&lt;br /&gt;output = output&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The commands use regex in order to extract keywords.  So basically, I can SMS 'd user say hello there' and my computer will initiate the command `flite -t "hello there"` once it receives it!  I also have the output of each command regulated by the 'output' parameter on each command.  It can either notify me when the command starts, when it ends, or it can send me the output of the command (or, of course, none of the above).&lt;br /&gt;&lt;br /&gt;Now, the interesting part is the bittorrent section.  Here I send the keywords to another little program I made (really just a bunch of regex and rss tricks... I'll include it at the end).  This program returns the URL of the highest seeded match to the keywords from IsoHunt.com.  This is sent to transmission and my server starts downloading the torrent!  (I use &lt;a href="http://www.transmissionbt.com/"&gt;Transmission&lt;/a&gt; for bittorrent on my server with the Clutch web UI) So essentially, if a friend recommends a movie (that is in the public domain, of course ;) when I am out, I can tell my server to start downloading it so it will be ready when I am home.&lt;br /&gt;&lt;br /&gt;Also, I can set my server to start a reverse-ssh connection to any IP.  This is great because I can keep my router locked down but still connect to my server from the outside.  Note: normally this sets my server to set up a reverse connection to an intermediary server so that everyone can be behind a firewall, but I'd like to keep the location of this server unknown for now.&lt;br /&gt;&lt;br /&gt;Finally, the following is the source for pyisohunt.py.  It was a true hack so don't expect clean code!&lt;br /&gt;&lt;pre class="prettyprint" style="border-style: solid; border-width: thin; overflow-y: scroll; overflow-x: auto; width: 525px; height: 600px;"&gt;#!/bin/env python&lt;br /&gt;#&lt;br /&gt;# Copyright 2008 Michael Gorelick &lt;mynameisfiber[ait]gmail[dodt]com&gt;&lt;br /&gt;#&lt;br /&gt;# This program is free software: you can redistribute it and/or modify&lt;br /&gt;# it under the terms of the GNU General Public License as published by&lt;br /&gt;# the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;# (at your option) any later version.&lt;br /&gt;#&lt;br /&gt;# This program is distributed in the hope that it will be useful,&lt;br /&gt;# but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;# GNU General Public License for more details.&lt;br /&gt;#&lt;br /&gt;# You should have received a copy of the GNU General Public License&lt;br /&gt;# along with this program.  If not, see:&lt;br /&gt;# http://www.gnu.org/licenses/gpl.html.&lt;br /&gt;&lt;br /&gt;import feedparser, re, getopt&lt;br /&gt;from sys import argv&lt;br /&gt;&lt;br /&gt;class pyisohunt:&lt;br /&gt;  def __init__(self, search,cat):&lt;br /&gt;    self.search = search&lt;br /&gt;    self.category = cat&lt;br /&gt;    self.isohunt = feedparser.parse( \&lt;br /&gt;      "http://isohunt.com/js/rss/%s?iht=%d"%(search.replace(" ","+"),cat))&lt;br /&gt;    self.results = self.parse(self.isohunt.entries)&lt;br /&gt;&lt;br /&gt;  def parse(self,entries):&lt;br /&gt;    results = []&lt;br /&gt;    findstats = re.compile(u"Size: (?P&lt;size&gt;[0-9.]+) MB, in (?P&lt;files&gt;[0-9]+) files")&lt;br /&gt;    findhealth = re.compile(u"Seeds: (?P&lt;seeds&gt;[0-9]+) \&amp;nbsp\; \| \&amp;nbsp\; Leechers: (?P&lt;leechers&gt;[0-9]+) \&amp;nbsp\; \| \&amp;nbsp\; Downloads: (?P&lt;downloads&gt;[0-9]+)\&lt;")&lt;br /&gt;    fieldtype = {"size":float, "files":int, "seeds":int, "leechers":int, "downloads":int, "title":unicode,"url":str} &lt;br /&gt;    for item in entries:&lt;br /&gt;      tmp = {}&lt;br /&gt;      tmp['title'] = item.title[:item.title.rfind('[')]&lt;br /&gt;      tmp['url'] = item.enclosures[0].href&lt;br /&gt;      tmp.update(findstats.search(item.summary_detail.value).groupdict())&lt;br /&gt;      tmp.update(findhealth.search(item.summary_detail.value).groupdict())&lt;br /&gt;      results.append(dict([(title,fieldtype[title](value)) for title,value in tmp.iteritems()]))&lt;br /&gt;    return results&lt;br /&gt;&lt;br /&gt;  def sort(self,key="seeds"):&lt;br /&gt;    return sorted(self.results,lambda x, y: y[key] - x[key])&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;  categories = {"all":-1,"video":1,"tv":3,"audio":2,"musicvideo":10,\&lt;br /&gt;                "game":4,"app":5,"pic":6,"anime":7,"comic":8,"book":9,\&lt;br /&gt;                "misc":0,"unclassified":11}&lt;br /&gt;  sortfields = ["size","files","seeds","leechers","downlads"]&lt;br /&gt;  help = """%s [-c category] [-s sort] [-n maxresults] search&lt;br /&gt;  Search through IsoHunt torrents on the commandline.  By Michael G.&lt;br /&gt;  -c  Category name. Can be: """ + ", ".join(categories.keys()) + """&lt;br /&gt;  -s  Sort field.  Can be: """ + ", ".join(sortfields) + """&lt;br /&gt;  -p  Print string (standard python printf notation... try with '-p ""' to see fields)&lt;br /&gt;  -n  Max number of results (Note: sort is applied before results are truncated\n"""&lt;br /&gt;&lt;br /&gt;  #Default valus&lt;br /&gt;  category = categories["all"]&lt;br /&gt;  sortfield = "seeds"&lt;br /&gt;  maxresults = None&lt;br /&gt;  printf = """Title: %(title)s&lt;br /&gt;  URL: %(url)s&lt;br /&gt;  Size: %(size)0.2f MB&lt;br /&gt;  Files: %(files)d&lt;br /&gt;  Seeds: %(seeds)d&lt;br /&gt;  Leechers: %(leechers)d&lt;br /&gt;  Downloads: %(downloads)d&lt;br /&gt;  """&lt;br /&gt;&lt;br /&gt;  try:&lt;br /&gt;    opts, args = getopt.getopt(argv[1:], "hc:s:n:p:")&lt;br /&gt;  except Exception:&lt;br /&gt;    print "Usage: " + help%argv[0]&lt;br /&gt;    exit(1)&lt;br /&gt;  errors = []&lt;br /&gt;  if args == []:&lt;br /&gt;    errors.append("Must have search terms!")&lt;br /&gt;  else:&lt;br /&gt;    search = " ".join(['"%s"'%x for x in args])&lt;br /&gt;  for o, a in opts:&lt;br /&gt;    if o == "-c":&lt;br /&gt;      try:&lt;br /&gt;        category = categories[a]&lt;br /&gt;      except KeyError:&lt;br /&gt;        errors.append("Invalid category")&lt;br /&gt;    elif o == "-p":&lt;br /&gt;      try:&lt;br /&gt;        printf = str(a)&lt;br /&gt;        test = a%{'files': 1, 'title': "1", 'url':"1",u'downloads': 1, u'leechers': 1, u'seeds': 1, u'size':1}&lt;br /&gt;        del test&lt;br /&gt;      except KeyError, e:&lt;br /&gt;        errors.append("Invalid printf string: Invalid Key: %s"%",".join(e))&lt;br /&gt;      except ValueError:&lt;br /&gt;        errors.append("Invalid print string")&lt;br /&gt;    elif o == "-s":&lt;br /&gt;      if not a in sortfields:&lt;br /&gt;        errors.append("Invalid sort field")&lt;br /&gt;      else:&lt;br /&gt;        sortfield = a&lt;br /&gt;    elif o == "-n":&lt;br /&gt;      try:&lt;br /&gt;        maxresults = int(a)&lt;br /&gt;      except ValueError:&lt;br /&gt;        errors.append("Invalid max number of results (must be integer)")&lt;br /&gt;    elif o == "-h":&lt;br /&gt;      print help%argv[0]&lt;br /&gt;      exit(0)&lt;br /&gt;  if errors != []:&lt;br /&gt;    print "Usage: " + help%argv[0] + "\n".join(errors)&lt;br /&gt;    exit(1)&lt;br /&gt;&lt;br /&gt;  results = pyisohunt(search,category)&lt;br /&gt;  for result in results.sort(sortfield)[:maxresults]:&lt;br /&gt;    if printf:&lt;br /&gt;      print printf%result&lt;br /&gt;    else:&lt;br /&gt;      print result&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Well, I don't really know what else to say about this... ask questions and I'll be sure to give you more details than you ever wanted!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3366502883257825993-4328549223528683136?l=fluxtrap.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fluxtrap.blogspot.com/feeds/4328549223528683136/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fluxtrap.blogspot.com/2009/05/smstwitter-control-of-your-server.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/4328549223528683136'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/4328549223528683136'/><link rel='alternate' type='text/html' href='http://fluxtrap.blogspot.com/2009/05/smstwitter-control-of-your-server.html' title='SMS/Twitter Control of your server'/><author><name>mg</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img457.imageshack.us/img457/628/catseyenebula2smallnl4.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3366502883257825993.post-2148617215670925238</id><published>2008-12-22T14:41:00.000-08:00</published><updated>2008-12-27T16:44:30.398-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wifi'/><category scheme='http://www.blogger.com/atom/ns#' term='antenna'/><category scheme='http://www.blogger.com/atom/ns#' term='mod'/><category scheme='http://www.blogger.com/atom/ns#' term='eeepc'/><title type='text'>eeePC 901 Antenna Mod</title><content type='html'>Well, after the treachery of exams and then the confusing transition into vacation I finally think it's time to update!  Well, I've done quite a lot: everything seems ready for the final version of the 3D whiteboard along with the construction of the 3D display.  Furthermore everything is in motion to begin the fusion device first semester of the next academic year (damn you Darryl for leaving to Singapore!).  But, in the realm of the actual rather than the theoretical, I have modded my eeePC 901 to support external antennas (for only $20).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_tf6A1GluJrw/SVQBnrHqhwI/AAAAAAAAAHI/3AE81kT2S5A/s1600-h/IMG_2654.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_tf6A1GluJrw/SVQBnrHqhwI/AAAAAAAAAHI/3AE81kT2S5A/s320/IMG_2654.JPG" alt="" id="BLOGGER_PHOTO_ID_5283850043913832194" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I love my eeePC, it has changed the way I work.  I carry it around with me everywhere scarcely ever noticing its weight allowing me to do work almost anywhere!  It's powerful enough for testing, enough hard drive space for my tools, runs of my simulation and even some music.  The only downside when I first got it: the antennas weren't powerful enough to pick up those elusive wifi signals.  Although, after cracking the magic device open I found that the internal antennas were hooked up using U.FL connection.  And so the hacking began!&lt;br /&gt;&lt;br /&gt;[picture of wireless module to come in very near future]&lt;br /&gt;&lt;br /&gt;Above you can see the actual wifi module from the expansion bay (this is the removable region in the center of the bottom of the laptop).  This led me to buy a U.FL to RP-SMA cabel from hyperlinktech (&lt;a href="http://www.hyperlinktech.com/item.aspx?id=1123"&gt;http://www.hyperlinktech.com/item.aspx?id=1123&lt;/a&gt;) as seen below:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_tf6A1GluJrw/SVAhQU-zfwI/AAAAAAAAAGY/uglhs5fLMNA/s1600-h/IMG_2621.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_tf6A1GluJrw/SVAhQU-zfwI/AAAAAAAAAGY/uglhs5fLMNA/s320/IMG_2621.JPG" alt="" id="BLOGGER_PHOTO_ID_5282758927299346178" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_tf6A1GluJrw/SVAhQLMA5mI/AAAAAAAAAGQ/LC8DrnMcu38/s1600-h/IMG_2620.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 240px; height: 320px;" src="http://3.bp.blogspot.com/_tf6A1GluJrw/SVAhQLMA5mI/AAAAAAAAAGQ/LC8DrnMcu38/s320/IMG_2620.JPG" alt="" id="BLOGGER_PHOTO_ID_5282758924670396002" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_tf6A1GluJrw/SVP83shTICI/AAAAAAAAAGg/aZhhsPmLPwo/s1600-h/IMG_2624.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 240px; height: 320px;" src="http://3.bp.blogspot.com/_tf6A1GluJrw/SVP83shTICI/AAAAAAAAAGg/aZhhsPmLPwo/s320/IMG_2624.JPG" alt="" id="BLOGGER_PHOTO_ID_5283844821609553954" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I chose RP-SMA for the outside connection because I already had an RP SMA antenna from an old router and it seems to be the most popular kind (so getting new antennas shouldn't be too much of a problem).  I also bought a 9dB 2.4GHz antenna from the same store.  2.4GHz is the frequency of wireless internet (802.11a/b/n).  In order to make everything fit into the eee, I had to sand the stopper almost all the way down until it looks like:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_tf6A1GluJrw/SVP83-KrgfI/AAAAAAAAAGo/22w7kT4vY2c/s1600-h/IMG_2630.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 240px; height: 320px;" src="http://4.bp.blogspot.com/_tf6A1GluJrw/SVP83-KrgfI/AAAAAAAAAGo/22w7kT4vY2c/s320/IMG_2630.JPG" alt="" id="BLOGGER_PHOTO_ID_5283844826346521074" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In order to make this hack a nice clean one, I decided to completely gut out the computer so I could put everything back where I wanted to.  There are MANY screws so make sure to keep everything organized.  I normally take a sheet of paper and put the screws on different parts of it while marking in marker where those screws should be (and how many of them I took out!).  I also took out the screen because I was going to machine the hole, but I later realized it was easy enough to do at home.  Here's a beauty shot of everything dismantled:&lt;br /&gt;&lt;br /&gt;&lt;pictures of="" taking="" the="" thing="" appart=""&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_tf6A1GluJrw/SVP_en1s88I/AAAAAAAAAHA/cYIzZ44CVyo/s1600-h/IMG_2634.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_tf6A1GluJrw/SVP_en1s88I/AAAAAAAAAHA/cYIzZ44CVyo/s320/IMG_2634.JPG" alt="" id="BLOGGER_PHOTO_ID_5283847689391109058" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I decided to have the RP SMA connection come out of the "lock" region of the case (right behind the eth0 port).  So, I had to make sure that the wire didn't block or bend the motherboard (scary thought! one crack and you have transformed your eeepc into a nice paper weight!).  So, I drilled the hole for the connection making sure that it's center was .5mm below the stand of the motherboard (circled in red).  To make the hole i used a standard dremel tool outfitted with a 1/8" drill bit.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_tf6A1GluJrw/SVP-eiceePI/AAAAAAAAAGw/1NfSUHmyc64/s1600-h/IMG_2626.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_tf6A1GluJrw/SVP-eiceePI/AAAAAAAAAGw/1NfSUHmyc64/s320/IMG_2626.JPG" alt="" id="BLOGGER_PHOTO_ID_5283846588431497458" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_tf6A1GluJrw/SVP-e4b5XtI/AAAAAAAAAG4/-7KmStpgXk0/s1600-h/IMG_2631.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_tf6A1GluJrw/SVP-e4b5XtI/AAAAAAAAAG4/-7KmStpgXk0/s320/IMG_2631.JPG" alt="" id="BLOGGER_PHOTO_ID_5283846594334645970" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/pictures&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_tf6A1GluJrw/SVbLZrKia8I/AAAAAAAAAHg/fv63rN3-KDM/s1600-h/IMG_2655.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_tf6A1GluJrw/SVbLZrKia8I/AAAAAAAAAHg/fv63rN3-KDM/s320/IMG_2655.JPG" alt="" id="BLOGGER_PHOTO_ID_5284634854709947330" border="0" /&gt;&lt;/a&gt;&lt;pictures of="" taking="" the="" thing="" appart=""&gt;&lt;br /&gt;With that completed I snaked the wire underneath where the motherboard sits.  I now plugged the cable to the wifi module, unplugging one of the internal antennas (I recommend doing this before remounting everything as it takes a good amount of force.  I even detached the wifi module to make sure there'd be no damage to the motherboard).  Once everything is hooked up, it should look like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_tf6A1GluJrw/SVQBoVD4FaI/AAAAAAAAAHY/PRK_8ScGGmw/s1600-h/IMG_2650.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 240px; height: 320px;" src="http://4.bp.blogspot.com/_tf6A1GluJrw/SVQBoVD4FaI/AAAAAAAAAHY/PRK_8ScGGmw/s320/IMG_2650.JPG" alt="" id="BLOGGER_PHOTO_ID_5283850055172232610" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_tf6A1GluJrw/SVQBnyZYuII/AAAAAAAAAHQ/QsizXrsezc4/s1600-h/IMG_2646.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_tf6A1GluJrw/SVQBnyZYuII/AAAAAAAAAHQ/QsizXrsezc4/s320/IMG_2646.JPG" alt="" id="BLOGGER_PHOTO_ID_5283850045867210882" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_tf6A1GluJrw/SVQBnrHqhwI/AAAAAAAAAHI/3AE81kT2S5A/s1600-h/IMG_2654.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_tf6A1GluJrw/SVQBnrHqhwI/AAAAAAAAAHI/3AE81kT2S5A/s320/IMG_2654.JPG" alt="" id="BLOGGER_PHOTO_ID_5283850043913832194" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This has been a tremendous gain!  The 3dB antenna fits nicely in the carrying case (and so does the eee even with the added width) and the 9dB fits nicely in my backpack.  Below is a comparison between only internal antennas, external mod without any antenna and finally external mod with 3dB antenna using `iwlist wifi0 scanning`&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint" style="border-style: solid; border-width: thin; overflow-y: scroll; overflow-x: auto; width: 525px;"&gt;&lt;br /&gt;#before&lt;br /&gt;fiber@mercury:~$ cat wireless.before&lt;br /&gt; Cell 01 - Address: 00:1E:58:40:6D:8F&lt;br /&gt;           ESSID:"telepathy"&lt;br /&gt;           Mode:Managed&lt;br /&gt;           Channel:11&lt;br /&gt;           Quality:100/100  Signal level:-31 dBm  Noise level:-81 dBm&lt;br /&gt;#after without antenna&lt;br /&gt;fiber@mercury:~$ cat wireless.afternoext&lt;br /&gt; Cell 01 - Address: 00:1E:58:40:6D:8F&lt;br /&gt;           ESSID:"telepathy"&lt;br /&gt;           Mode:Managed&lt;br /&gt;           Channel:11&lt;br /&gt;           Quality:65/100  Signal level:-64 dBm  Noise level:-81 dBm&lt;br /&gt;#after with 3dB antenna&lt;br /&gt;fiber@mercury:~$ cat wireless.after3db&lt;br /&gt; Cell 01 - Address: 00:1E:58:40:6D:8F&lt;br /&gt;           ESSID:"telepathy"&lt;br /&gt;           Mode:Managed&lt;br /&gt;           Channel:11&lt;br /&gt;           Quality:100/100  Signal level:-29 dBm  Noise level:-81 dBm&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;30% gain with a cheap antenna I just had lying around.  I'll post some stats on the 9dB antenna once I am in a controllable enough area (ie: home).  Remember, &lt;a href="http://en.wikipedia.org/wiki/Decibel"&gt;dBm&lt;/a&gt; work on the log base 10 scale, so every unit change in dB is a factor of 10 change in strength.&lt;br /&gt;&lt;br /&gt;So tell me how this mod works for you or if there are any points that I didn't clearly explain!  Happy Hacking!&lt;/pictures&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3366502883257825993-2148617215670925238?l=fluxtrap.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fluxtrap.blogspot.com/feeds/2148617215670925238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fluxtrap.blogspot.com/2008/12/eeepc-901-antenna-mod.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/2148617215670925238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/2148617215670925238'/><link rel='alternate' type='text/html' href='http://fluxtrap.blogspot.com/2008/12/eeepc-901-antenna-mod.html' title='eeePC 901 Antenna Mod'/><author><name>mg</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img457.imageshack.us/img457/628/catseyenebula2smallnl4.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_tf6A1GluJrw/SVQBnrHqhwI/AAAAAAAAAHI/3AE81kT2S5A/s72-c/IMG_2654.JPG' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3366502883257825993.post-3046561242040788057</id><published>2008-11-18T09:58:00.000-08:00</published><updated>2008-11-18T10:11:05.944-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='science'/><title type='text'>new project</title><content type='html'>Well, it's taking longer than I expected for the parts for my most recent project to come in.  I'm waiting for some wireless pigtails (U.FL to RP-SMA) so that my EEE PC has an external antenna (an easy hack, but one I haven't seen any documentation online for).&lt;br /&gt;&lt;br /&gt;In the meantime, here's an old video I made a while ago playing with non-Newtonian fluids.  This is really easy to make (just saturate water with corn starch) and very fun!  Non-Newtonian fluids are fluids whose viscosity is dependant on the applied strain.  So, the strain from the speaker constantly hitting the fluid causes it to become much more viscous to the point of appearing solid.  This causes all sorts of fun!  In this video I played a 100hz sin wave through the speaker.  I did this later as a demonstration at the Dragon Academy and I have to say it was a great success, I recommend it for any teachers or demonstrators.  Hope everyone enjoys!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;embed id="VideoPlayback" src="http://video.google.com/googleplayer.swf?docid=7055299918183154020&amp;amp;hl=en&amp;amp;fs=true" style="width: 400px; height: 326px;" allowfullscreen="true" allowscriptaccess="always" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3366502883257825993-3046561242040788057?l=fluxtrap.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fluxtrap.blogspot.com/feeds/3046561242040788057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fluxtrap.blogspot.com/2008/11/new-project.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/3046561242040788057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/3046561242040788057'/><link rel='alternate' type='text/html' href='http://fluxtrap.blogspot.com/2008/11/new-project.html' title='new project'/><author><name>mg</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img457.imageshack.us/img457/628/catseyenebula2smallnl4.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3366502883257825993.post-8625159029320228337</id><published>2008-11-04T21:32:00.000-08:00</published><updated>2009-02-20T17:39:11.639-08:00</updated><title type='text'>obama fever</title><content type='html'>OBAMA WON! Truly a day to remember. So, in the spirit of science funding not being slashed to death I am going to release one of my first python scripts that downloads all images off of the NASA Astronomy Picture of the Day (apod).&lt;br /&gt;&lt;br /&gt;I tried keeping the code commented so that it could also serve as a good learning tool. One thing I'd like to include is some way of saving the description of the image. This could be done by saving it into a text file with the same filename as the image, but I suspect there is a better way (using ImageMagick to embed the information?). If you have an idea or preference, post a comment! So, here it goes:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint" style="border-style: solid; border-width: thin; overflow-y: scroll; overflow-x: auto; width: 525px; height: 600px;"&gt;&lt;br /&gt;#!/bin/env python&lt;br /&gt;#&lt;br /&gt;# Copyright 2008 Michael Gorelick &lt;mynameisfiber[ait]gmail[dodt]com&gt;&lt;br /&gt;#&lt;br /&gt;# This program is free software: you can redistribute it and/or modify&lt;br /&gt;# it under the terms of the GNU General Public License as published by&lt;br /&gt;# the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;# (at your option) any later version.&lt;br /&gt;#&lt;br /&gt;# This program is distributed in the hope that it will be useful,&lt;br /&gt;# but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;# GNU General Public License for more details.&lt;br /&gt;#&lt;br /&gt;# You should have received a copy of the GNU General Public License&lt;br /&gt;# along with this program.  If not, see:&lt;br /&gt;# http://www.gnu.org/licenses/gpl.html.&lt;br /&gt;&lt;br /&gt;import re, urllib, sys, os&lt;br /&gt;&lt;br /&gt;### Check/Do Help&lt;br /&gt;help = """NASA Image Getter - Michael G. (GPL 2008)&lt;br /&gt;./%s [-h] [imagepath]&lt;br /&gt;imagepath  - path to save images&lt;br /&gt;-h, --help - this help"""%sys.argv[0]&lt;br /&gt;&lt;br /&gt;if "-h" in sys.argv or "--help" in sys.argv:&lt;br /&gt;exit(help)&lt;br /&gt;elif len(sys.argv) == 1:&lt;br /&gt;print "Not enough program arguments"&lt;br /&gt;exit(help)&lt;br /&gt;&lt;br /&gt;### CONFIG&lt;br /&gt;allowedChars = '[-a-zA-Z0-9*:\'.,&amp;amp;!?\(\)//\n"+;_ ]'&lt;br /&gt;allowedFiles = '[jpg|jpeg|png|gif|mov|avi|mpeg|mpg]'&lt;br /&gt;url = "http://antwrp.gsfc.nasa.gov/apod/archivepix.html"&lt;br /&gt;pbarwidth = 80&lt;br /&gt;try:&lt;br /&gt;imagePath = sys.argv[1]&lt;br /&gt;os.makedirs(imagePath)&lt;br /&gt;except Exception, e:&lt;br /&gt;#errno == 17 means the directory already exists.&lt;br /&gt;if e.errno != 17:&lt;br /&gt; exit(e)&lt;br /&gt;print "Saving images to %s"%imagePath&lt;br /&gt;&lt;br /&gt;##############################################&lt;br /&gt;## This section looks for links to image pages&lt;br /&gt;print "Searching for image pages in", url&lt;br /&gt;html = urllib.urlopen(url).read()&lt;br /&gt;pagePattern = re.compile('([0-9]{6}).html"&gt;(' + allowedChars + '*)')&lt;br /&gt;pages = pagePattern.findall(html)&lt;br /&gt;totalpages = len(pages)&lt;br /&gt;print "Found", totalpages, "image pages."&lt;br /&gt;&lt;br /&gt;#############################################&lt;br /&gt;## Now we go to the pages and extract a list&lt;br /&gt;##  of images and download&lt;br /&gt;try:&lt;br /&gt;alreadyHave = open(imagePath + "/tracker.log").readlines()&lt;br /&gt;except IOError, e:&lt;br /&gt;alreadyHave = ""&lt;br /&gt;totalhave = len(alreadyHave)&lt;br /&gt;try:&lt;br /&gt;tracker = open(imagePath + "/tracker.log", 'a+')&lt;br /&gt;except IOError, e:&lt;br /&gt;exit(e)&lt;br /&gt;&lt;br /&gt;base = url[0:url.rfind('/')]&lt;br /&gt;imagePattern = re.compile('&amp;lt;a href="image/(' + allowedChars + '*.' + \&lt;br /&gt;allowedFiles + ')"', re.IGNORECASE)&lt;br /&gt;sanitizePattern = re.compile('[//\n\r\t]')&lt;br /&gt;imageGet = urllib.URLopener()&lt;br /&gt;&lt;br /&gt;for i, page in enumerate(pages):&lt;br /&gt;try:&lt;br /&gt; if page[0]+"\n" not in alreadyHave:&lt;br /&gt;   #Extract information from image page&lt;br /&gt;   title = sanitizePattern.sub("", page[1])&lt;br /&gt;   currentpage = base + "/ap" + page[0] + ".html"&lt;br /&gt;   print "Getting " + title&lt;br /&gt;   content = urllib.urlopen(currentpage).read()&lt;br /&gt;   image = imagePattern.findall(content)&lt;br /&gt;&lt;br /&gt;   #Parse data&lt;br /&gt;   filename = imagePath + "/" + (title + \&lt;br /&gt;     image[0][image[0].rfind('.'):]).replace(" ","_")&lt;br /&gt;   print "\tFilename: " + filename&lt;br /&gt;   url = base + "/image/" + image[0]&lt;br /&gt;   print "\tURL: " + url&lt;br /&gt;&lt;br /&gt;   print "\n[" + "="*(pbarwidth*(i-totalhave)/(totalpages-totalhave)) \&lt;br /&gt;     +"@"+"="*(pbarwidth*(i-totalpages)/(totalhave-totalpages)-1)+"]",&lt;br /&gt;   sys.stdout.flush()&lt;br /&gt;&lt;br /&gt;   #Download&lt;br /&gt;   imageGet.retrieve(url, filename)&lt;br /&gt;   tracker.write(page[0] + "\n")&lt;br /&gt;&lt;br /&gt;   print "\r" + " "*(pbarwidth+2),"\r",&lt;br /&gt;   sys.stdout.flush()&lt;br /&gt;except IndexError, e:&lt;br /&gt; print "\tImage not found\n"&lt;br /&gt;except IOError, e:&lt;br /&gt; print "\t404 Error\n"&lt;br /&gt;&lt;br /&gt;tracker.close()&lt;br /&gt;print "Done"&lt;br /&gt;&lt;/http:&gt;&lt;/mynameisfiber[ait]gmail[dodt]com&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3366502883257825993-8625159029320228337?l=fluxtrap.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fluxtrap.blogspot.com/feeds/8625159029320228337/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fluxtrap.blogspot.com/2008/11/obama-feaver.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/8625159029320228337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/8625159029320228337'/><link rel='alternate' type='text/html' href='http://fluxtrap.blogspot.com/2008/11/obama-feaver.html' title='obama fever'/><author><name>mg</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img457.imageshack.us/img457/628/catseyenebula2smallnl4.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3366502883257825993.post-7645444920294228741</id><published>2008-11-03T09:06:00.000-08:00</published><updated>2008-11-03T09:09:56.082-08:00</updated><title type='text'>Distractions</title><content type='html'>Well, exams are finally done but I am still contending with all the work I had to put off.  In the works is a post on the topic of conscience and the release of my mac remote code.  For now, I will distract everyone with an old youtube video of mine: exploding flint (well, actually ferrocium)&lt;br /&gt;&lt;br /&gt;&lt;object height="344" width="425"&gt;&lt;param name="movie" value="http://www.youtube.com/v/wLp-3YBZQkE&amp;amp;hl=en&amp;amp;fs=1&amp;amp;rel=0"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/wLp-3YBZQkE&amp;amp;hl=en&amp;amp;fs=1&amp;amp;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="344" width="425"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;The video pretty much explains itself.  It is a nice little demo on the properties of ferrocium.  In the end, this stability (or lack thereof) is why it proves to be so useful in lighters. Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3366502883257825993-7645444920294228741?l=fluxtrap.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fluxtrap.blogspot.com/feeds/7645444920294228741/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fluxtrap.blogspot.com/2008/11/distractions.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/7645444920294228741'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/7645444920294228741'/><link rel='alternate' type='text/html' href='http://fluxtrap.blogspot.com/2008/11/distractions.html' title='Distractions'/><author><name>mg</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img457.imageshack.us/img457/628/catseyenebula2smallnl4.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3366502883257825993.post-1133029168241551493</id><published>2008-10-26T00:49:00.000-07:00</published><updated>2008-10-26T07:56:33.701-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='telescope'/><category scheme='http://www.blogger.com/atom/ns#' term='science'/><title type='text'>failed telescope night</title><content type='html'>So, after a while spent getting my telescope aligned (and, of course, staring at M41 and M42 for a while), the clouds came in before I could get the camera ready. When I was done cursing the clouds and the cold I had been sitting in, I decided to take pictures of Toronto to gauge the camera.&lt;br /&gt;&lt;br /&gt;I was using my 8" Celestron (f#=10, focal length=2032 mm).  It's a great telescope although it takes a magical touch to get aligned.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_tf6A1GluJrw/SQQhgFYXeoI/AAAAAAAAAFw/eNVwrzedkT0/s1600-h/IMG_2534.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_tf6A1GluJrw/SQQhgFYXeoI/AAAAAAAAAFw/eNVwrzedkT0/s320/IMG_2534.JPG" alt="" id="BLOGGER_PHOTO_ID_5261367099759491714" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;This is the main picture of interest: the symbol of BMO on top of First Canadian Place (which is 2580m away from my balcony).  From my calculations, the symbol is 6m tall which means I'm capturing about .1332° or 2.32e-3rad of the sky! (I got this number by doing &lt;img style="width: 60px; height: 15px; border: 0px;" alt="[; 2\cdot tan^{-1}(\frac{6/2}{2580}) ;]" title=" 2\cdot tan^{-1}(\frac{6/2}{2580}) " src="http://thewe.net/tex/%202%5Ccdot%20tan%5E%7B-1%7D%28%5Cfrac%7B6/2%7D%7B2580%7D%29" border="0px" /&gt;)&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_tf6A1GluJrw/SQQhgBqiJMI/AAAAAAAAAF4/Ft9YNYRDyTc/s1600-h/0007.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_tf6A1GluJrw/SQQhgBqiJMI/AAAAAAAAAF4/Ft9YNYRDyTc/s320/0007.jpg" alt="" id="BLOGGER_PHOTO_ID_5261367098761946306" border="0px" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;By the way, &lt;a href="http://fluxtrap.blogspot.com/2008/10/telescope-camera-howto-v1.html"&gt;the picture of the moon&lt;/a&gt; I took before was with my astroscan (f#=4.1, focal length=445cm).  It's a great telescope to bring around and it's really quick to get set up and start observing, although the optics aren't that great which leads to a lot of artifacts.  Also, I like the tactility that comes with manually aiming the beast.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_tf6A1GluJrw/SQQhgRvAawI/AAAAAAAAAGA/2LPizpp1VnM/s1600-h/IMG_2543.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 240px; height: 320px;" src="http://4.bp.blogspot.com/_tf6A1GluJrw/SQQhgRvAawI/AAAAAAAAAGA/2LPizpp1VnM/s320/IMG_2543.JPG" alt="" id="BLOGGER_PHOTO_ID_5261367103075674882" border="0" /&gt;&lt;/a&gt;While I was first testing the camera I took the following picture from 37m away:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_tf6A1GluJrw/SQQnbDfnrUI/AAAAAAAAAGI/3Q8ws4qw4yA/s1600-h/0004.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_tf6A1GluJrw/SQQnbDfnrUI/AAAAAAAAAGI/3Q8ws4qw4yA/s320/0004.jpg" alt="" id="BLOGGER_PHOTO_ID_5261373610423463234" border="0" /&gt;&lt;/a&gt;Since my camera is 9.5cm tall and it takes up 46.1% of the height and 34.6% of the width of the image we can get... (5.563e-3, 7.413e-3)radians = (.318,.424)degrees=(height,width) degrees!&lt;br /&gt;&lt;br /&gt;So, if we take the differences in f# into account, both measurements agree! *phew*, well at least now I can say tonight wasn't a waste.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3366502883257825993-1133029168241551493?l=fluxtrap.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fluxtrap.blogspot.com/feeds/1133029168241551493/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fluxtrap.blogspot.com/2008/10/failed-telescope-night.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/1133029168241551493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/1133029168241551493'/><link rel='alternate' type='text/html' href='http://fluxtrap.blogspot.com/2008/10/failed-telescope-night.html' title='failed telescope night'/><author><name>mg</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img457.imageshack.us/img457/628/catseyenebula2smallnl4.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_tf6A1GluJrw/SQQhgFYXeoI/AAAAAAAAAFw/eNVwrzedkT0/s72-c/IMG_2534.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3366502883257825993.post-2426928736049837622</id><published>2008-10-25T16:46:00.000-07:00</published><updated>2008-11-14T01:27:30.344-08:00</updated><title type='text'>oscilloscope!</title><content type='html'>&lt;div style="text-align: center;"&gt;&lt;div style="text-align: left;"&gt;So, I was at active surplus (with trusted, albeit slightly slow, sidekick Darryl) looking for parts for the fusor or the 3D display when I ran into this amazing old school oscilloscope.  After quickly brainstorming some reason I could justify buying this beautiful piece of science equipment (or history depending on your view) I got it!  The justification is actually quite good: instead of buying a Geiger counter, we can use activated aluminum and a charged plate (neutron hits the aluminum, shoots of an electron which gets captured by the plate which turns into a signal that the oscilloscope can see) to verify fusion is happening.&lt;br /&gt;&lt;br /&gt;Anyways, here's a little video of the piece in action: hooked up to my speakers playing Roads by Portishead.  Sorry about the video quality... also the cameras refresh rate doesn't do justice to the display.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;object width="320" height="266" class="BLOG_video_class" id="BLOG_video-220713425c6c5b34" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"&gt;&lt;param name="movie" value="http://www.youtube.com/get_player"&gt;&lt;param name="bgcolor" value="#FFFFFF"&gt;&lt;param name="allowfullscreen" value="true"&gt;&lt;param name="flashvars" value="flvurl=http://v16.nonxt5.googlevideo.com/videoplayback?id%3D220713425c6c5b34%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1331196120%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D24B3590D0410DA6AB5DCB2F1D73D6AEB617C488.5DB1B6575DFA34F329FF1423115DC562C64F16EA%26key%3Dck1&amp;amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D220713425c6c5b34%26offsetms%3D5000%26itag%3Dw160%26sigh%3Dfplv_ASJDvz8tiprwh_G-lIlIrs&amp;amp;autoplay=0&amp;amp;ps=blogger"&gt;&lt;embed src="http://www.youtube.com/get_player" type="application/x-shockwave-flash"width="320" height="266" bgcolor="#FFFFFF"flashvars="flvurl=http://v16.nonxt5.googlevideo.com/videoplayback?id%3D220713425c6c5b34%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1331196120%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D24B3590D0410DA6AB5DCB2F1D73D6AEB617C488.5DB1B6575DFA34F329FF1423115DC562C64F16EA%26key%3Dck1&amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D220713425c6c5b34%26offsetms%3D5000%26itag%3Dw160%26sigh%3Dfplv_ASJDvz8tiprwh_G-lIlIrs&amp;autoplay=0&amp;ps=blogger"allowFullScreen="true" /&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;As for the fusor route, we are going to get florescent transformers (~20,000V at a couple miliamps) for power, and hopefully e-bay will have the correct vacuum pump (it's hard to find ones that go down to 5microns).  As for the vacuum container... we might just have to get one custom made.  This is one piece that I don't really want to try building myself since it's the only part of the project that could seriously maim us.&lt;br /&gt;&lt;br /&gt;Oh, and stay tuned... tomorrow I'm going to post a video I did a while ago about getting a cool explosion using ferrocium which you can get out of a common lighter!&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3366502883257825993-2426928736049837622?l=fluxtrap.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='enclosure' type='video/mp4' href='http://www.blogger.com/video-play.mp4?contentId=220713425c6c5b34&amp;type=video%2Fmp4' length='0'/><link rel='replies' type='application/atom+xml' href='http://fluxtrap.blogspot.com/feeds/2426928736049837622/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fluxtrap.blogspot.com/2008/10/oscilloscope.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/2426928736049837622'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/2426928736049837622'/><link rel='alternate' type='text/html' href='http://fluxtrap.blogspot.com/2008/10/oscilloscope.html' title='oscilloscope!'/><author><name>mg</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img457.imageshack.us/img457/628/catseyenebula2smallnl4.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3366502883257825993.post-409591086192559042</id><published>2008-10-24T07:56:00.001-07:00</published><updated>2008-10-24T13:40:29.980-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='art'/><title type='text'>panoramas</title><content type='html'>So, a little bit ago I got a new camera (well, I guess it's no longer new) so I thought, since I couldn't afford any great lenses, I'd get acquainted with good post-processing.  First thing to attend to was mending a mosaic of pictures together into one seamless picture.  So, bellow is my evolution in trying to get a good panorama:&lt;br /&gt;&lt;br /&gt;Balcony View:&lt;br /&gt;This one didn't look too bad.  I was lucky that lighting conditions didn't change too much as I took all the photos.&lt;br /&gt;&lt;a href="http://www.cdf.toronto.edu/%7Ec7goreli/panorama/Balcony_View.jpg"&gt;&lt;img src="http://www.cdf.toronto.edu/%7Ec7goreli/panorama/thumbBalcony_View.jpg" border=0 /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Night Panorama:&lt;br /&gt;I was rushed.  As a result I didn't get enough pictures to get good perspective.  Also, you can see the lighting conditions changed drastically as I took the pictures.&lt;br /&gt;&lt;a href="http://www.cdf.toronto.edu/%7Ec7goreli/panorama/Night_Panorama.jpg"&gt;&lt;img src="http://www.cdf.toronto.edu/%7Ec7goreli/panorama/thumbNight_Panorama.jpg" border=0 /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Dawn Panorama:&lt;br /&gt;That's not change, that's more of the same!  I took these pictures fast enough to have some resemblance to homogeneous lighting, even though it's homogeneously dark.&lt;br /&gt;&lt;a href="http://www.cdf.toronto.edu/%7Ec7goreli/panorama/Dawn_Panorama.jpg"&gt;&lt;img src="http://www.cdf.toronto.edu/%7Ec7goreli/panorama/thumbDawn_Panorama.jpg" border=0 /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Toronto Through a fishbowl:&lt;br /&gt;This one turned out great!  I took more than enough pictures and did it quickly.  You can see a few artifacts from mending (check the train tracks), but all in all it turned out great.  In fact, there are parts of the image that were cut out of all the photos that I had to reconstruct completely using photoshop (special prize to whoever can guess where).  If you want to see a full resolution (17mb, 5989x4058) version, go &lt;a href="http://www.archive.org/download/TorontoThroughAFishbowl/TorontoThroughAFishbowl.png"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;a href="http://www.cdf.toronto.edu/%7Ec7goreli/panorama/Sunset_Panorama.jpg"&gt;&lt;img src="http://www.cdf.toronto.edu/%7Ec7goreli/panorama/thumbSunset_Panorama.jpg" border=0 /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Sunset:&lt;br /&gt;So, I was doing work and I look out the window and I see a rainbow AND the moon.  So, I quickly try to get as many pictures as I can for a panorama.  Didn't turn out exactly how I wanted, but it is still quite cool!&lt;br /&gt;&lt;a href="http://www.cdf.toronto.edu/%7Ec7goreli/panorama/sunset2.png"&gt;&lt;img src="http://www.cdf.toronto.edu/%7Ec7goreli/panorama/thumbsunset2.png" border=0 /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For all these images, I loaded them into photoshop and used the automated function "photomerge".  Once the images were merged I blended the edges and applied any sort of photoshop magic I could to make the image seem smooth.  This was hard in some cases (ie: in the last image, sunrise, you can see a drastic color change in the sky).&lt;br /&gt;&lt;br /&gt;These skills are actually quite useful for many things, especially the telescope camera.  I used basically the same technique to make the moon picture from the &lt;a href="http://fluxtrap.blogspot.com/2008/10/telescope-camera-howto-v1.html"&gt;telescope camera&lt;/a&gt; (although I probably should have used a more stack oriented program... that's what the future is for!).&lt;br /&gt;&lt;br /&gt;So, feel free to download all these images, just remember they are all licenced under the &lt;span style="font-weight: bold;" class="key"&gt;Creative Commons (&lt;/span&gt;&lt;span style="font-weight: bold;" class="value"&gt;&lt;a rel="license" title="Attribution-Noncommercial-Share Alike 2.5 Canada" href="http://creativecommons.org/licenses/by-nc-sa/2.5/ca/" target="_blank"&gt;Attribution-Noncommercial-Share Alike 2.5 Canada&lt;/a&gt;)&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3366502883257825993-409591086192559042?l=fluxtrap.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fluxtrap.blogspot.com/feeds/409591086192559042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fluxtrap.blogspot.com/2008/10/panoramas.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/409591086192559042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/409591086192559042'/><link rel='alternate' type='text/html' href='http://fluxtrap.blogspot.com/2008/10/panoramas.html' title='panoramas'/><author><name>mg</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img457.imageshack.us/img457/628/catseyenebula2smallnl4.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3366502883257825993.post-6976378530536998787</id><published>2008-10-23T07:47:00.001-07:00</published><updated>2008-11-14T01:23:42.933-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='general'/><category scheme='http://www.blogger.com/atom/ns#' term='science'/><title type='text'>Projects to come</title><content type='html'>I also want to use this blog as a place to write down the projects I want to try doing on top of talking about the ones I've already completed.  So, here's a list of what's coming up and what I would like to come up:&lt;br /&gt;&lt;br /&gt;In the works:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;3D Whiteboard (almost done!)&lt;/li&gt;&lt;li&gt;3D Volumetric Display (anyone want to donate an optical bench or some mirrors? :) (with help from Darryl)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Fusor"&gt;Fusor&lt;/a&gt; (anyone know how to make a cheap vacuum chamber?) (together with Darryl)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;python Hobbyist Observer Tool (phot?, almost done... but not ready for the public yet)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;pyremote (python tool set for the mac remote... basically done, I'm just making some modules ftw)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;To come:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Ferrofluid"&gt;Ferrofluid&lt;/a&gt; (I'm doing this one for the kids at a local highschool)&lt;/li&gt;&lt;li&gt;Hologram of Saturn (well, I have the camera, now I just need some clear nights!) (Helping Darryl)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Micron sized tractor beam! (too cool to say no)&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.nature.com/nature/videoarchive/x-rays/"&gt;Tape as an x-ray source&lt;/a&gt; (again, vacuum chamber?)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Materials Wishlist:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.unitednuclear.com/vacpump.htm"&gt;Vacuum Pump&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Vacuum Chamber! (or at least the materials to make one)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;NeHe Laser&lt;/li&gt;&lt;li&gt;Heavy Water (harder to get in Canada than I thought... united nuclear has some if someone wouldn't mind bringing me some back from the US)&lt;/li&gt;&lt;li&gt;Microscope&lt;/li&gt;&lt;li&gt;Oscilloscope&lt;/li&gt;&lt;li&gt;Wave Generator&lt;/li&gt;&lt;li&gt;LCD Projector (3d (whiteboard|display))&lt;br /&gt;&lt;/li&gt;&lt;li&gt;That paper thing... what's it called?... money?&lt;/li&gt;&lt;/ul&gt;On top of those personal projects, I'm also working with &lt;a href="http://astro.utoronto.ca/%7Ematzner/"&gt;Chris Matzner&lt;/a&gt; on protostellar outflow-driven turbulence.  To put shortly, we are basically seeing if jet's shot out by young stars, protostars, can cause a feedback effect and, by the creation of super-sonic turbulence, slow down star formation rates.  I'll put a post about that sooner rather than later... I think I will start a one post per day rule to get this thing going.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3366502883257825993-6976378530536998787?l=fluxtrap.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fluxtrap.blogspot.com/feeds/6976378530536998787/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fluxtrap.blogspot.com/2008/10/projects-to-come.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/6976378530536998787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/6976378530536998787'/><link rel='alternate' type='text/html' href='http://fluxtrap.blogspot.com/2008/10/projects-to-come.html' title='Projects to come'/><author><name>mg</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img457.imageshack.us/img457/628/catseyenebula2smallnl4.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3366502883257825993.post-2330317336553383556</id><published>2008-10-22T17:55:00.000-07:00</published><updated>2008-10-26T01:57:06.532-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='telescope'/><category scheme='http://www.blogger.com/atom/ns#' term='science'/><title type='text'>Telescope Camera HOWTO v1</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_tf6A1GluJrw/SP_2uPylOxI/AAAAAAAAAE4/QxsDBS4mjcM/s1600-h/IMG_2522.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_tf6A1GluJrw/SP_2uPylOxI/AAAAAAAAAE4/QxsDBS4mjcM/s320/IMG_2522.JPG" alt="" id="BLOGGER_PHOTO_ID_5260194164165131026" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Alright, well... after many failed attempts to start a blog I will, instead of starting and ending with an introductory post, get right into it.  This will be kind of odd as I've already completed this project in full, but soon i'm going to be doing it again, so stay tuned for version two of this howto!&lt;br /&gt;&lt;br /&gt;Anyways, I've always wanted a camera for my telescope but they were always too damn expensive!  So, I did what any hacker would do: made my own.  The good thing about something like this is that it can be used for any kind of optical system... in fact I will be making one for a microscope soon (and be using properly milled pieces).&lt;br /&gt;&lt;br /&gt;So, for this project you'll need:&lt;ol&gt;&lt;li&gt;A webcam (any kind will do, I got a cheap $8 logitec express from canada computers)&lt;/li&gt;&lt;li&gt;Some sort of metal case.  It should have at least an internal volume of 2.5x5x3.5cm (might be different depending on what webcam you get)&lt;/li&gt;&lt;li&gt;Computer fan with heat sink (see image)&lt;/li&gt;&lt;li&gt;Camera film tube.&lt;/li&gt;&lt;/ol&gt;(Total cost: ~$20)&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_tf6A1GluJrw/SP_2ov8xQkI/AAAAAAAAAEg/zto8lEdCNrc/s1600-h/IMG_2519.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_tf6A1GluJrw/SP_2ov8xQkI/AAAAAAAAAEg/zto8lEdCNrc/s320/IMG_2519.JPG" alt="" id="BLOGGER_PHOTO_ID_5260194069718581826" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;And now to begin the fun!  Find out how to open the webcam and do so.  For my webcam there was a screw covered by a small plastic cap that held the whole unit together.  You can always just smash it apart, but you don't want to destroy the delicate CCD or the circuitry!&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_tf6A1GluJrw/SP_2tlnNDRI/AAAAAAAAAEw/Fl9wFSYU6zE/s1600-h/IMG_2521.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_tf6A1GluJrw/SP_2tlnNDRI/AAAAAAAAAEw/Fl9wFSYU6zE/s320/IMG_2521.jpg" alt="" id="BLOGGER_PHOTO_ID_5260194152843119890" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Once open,  disconnect the mic (you might want to keep it for later, it became really useful in my assembly) and take the circuitry out of the casing.  Make sure the pins on the board for the mic are stowed away, some cameras are already quite compact (in the image below I had to fold the pins down, making sure not to touch anything else).  Now take the lens off of the CCD (it unscrews).  Be careful because you don't want the CCD to get dirty!  You'll see that there is still a plastic piece where the lens used to be that is screwed onto the board (I'll call this the lens holder).  Screw this off and break the glass off of it!  This glass is an infrared filter and we don't want it.  Make sure that everything is clean and screw this piece back on.  Now you have a visible+infrared camera, but we want more!&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_tf6A1GluJrw/SQD8denGdBI/AAAAAAAAAFg/UdORBs6i7TA/s1600-h/IMG_2520.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_tf6A1GluJrw/SQD8denGdBI/AAAAAAAAAFg/UdORBs6i7TA/s320/IMG_2520.jpg" alt="" id="BLOGGER_PHOTO_ID_5260481948132209682" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Also, a good tip is to take the lens and glue something long to it... then you can use this as a lens cap so the CCD doesn't get dirty when you store it.  Save this step for last so you can see what would best serve your needs.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_tf6A1GluJrw/SP_4aRsJOgI/AAAAAAAAAFI/AcW-f-oARHA/s1600-h/IMG_2525.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_tf6A1GluJrw/SP_4aRsJOgI/AAAAAAAAAFI/AcW-f-oARHA/s320/IMG_2525.JPG" alt="" id="BLOGGER_PHOTO_ID_5260196020100872706" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Now, look at the main cable that connects the USB to the circuit board... you need to identify the ground and power.  Voltmeters are useful for this (just plug in the USB cable and check where the voltage flows).  Remember where this is for future reference.&lt;br /&gt;&lt;br /&gt;Let's take care of the casing for now.  First, decide what you are going to use as the front and back of the case.  Screw the fan/heat sink securely to the back of the case.  You want to make sure that it is secure so that you don't have any excess vibrations.  Next, drill a hole in the front the size of the circle of the lens holder from before.  This is where the CCD is going!  Also, figure out how you want the wires to come out of the case... I drilled a hole in the side and had all the wires (USB+power to the fan) coming out of it.  And finally, take that film canister and cut the base off so it becomes just a tube.  Glue the lip side down onto the case so that it is centered on the hole for the CCD.  I recommend using epoxy or something that gives a bit... more rigid glues (super glue and the like) seem to chip off after extensive use with things like this.  And now the case is ready... almost done!&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_tf6A1GluJrw/SP_4ay1af-I/AAAAAAAAAFQ/8xKfX51_0gY/s1600-h/IMG_2526.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 240px; height: 320px;" src="http://3.bp.blogspot.com/_tf6A1GluJrw/SP_4ay1af-I/AAAAAAAAAFQ/8xKfX51_0gY/s320/IMG_2526.JPG" alt="" id="BLOGGER_PHOTO_ID_5260196028998123490" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Now you want to get all the wires through the hole in the case you prepared.  Solder the wires for the fan onto the correct parts of the USB wire (I found it useful to branch off the wires coming off the CCD board using the wires from the microphone so I had more room to do my work).  Before reattaching the USB wires to the CCD board, apply some glue to the outside of the lens holder (being extra careful not to get any on the ccd... this is how i ruined my first CCD) and get it securely fitted into the hole in the case.  Now, the final step: attach the usb cable and close the case up!&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_tf6A1GluJrw/SP_4Z8eM_0I/AAAAAAAAAFA/zCfG96DRepY/s1600-h/IMG_2523.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_tf6A1GluJrw/SP_4Z8eM_0I/AAAAAAAAAFA/zCfG96DRepY/s320/IMG_2523.JPG" alt="" id="BLOGGER_PHOTO_ID_5260196014405254978" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;You are finally ready to take pictures!  Use whatever webcam program you prefer.  I personally use a script I made in python that uses openCV to control the webcam and find the FWHM (full width half maximum) of a selected region so you know everything is in focus.  In a later post I will release this code!  For now I'll leave you with a picture of the moon I took while testing this unit.  I used gqcam to take the pictures and photoshop to put them together.  They were taken off my 4.5" Astroscan telescope (not the best... in fact most distortion comes from the antique optics in the giant red beast, but when it clears up I'll take/post some pictures with my 8" Celestron!).&lt;br /&gt;&lt;br /&gt;Hope everyone enjoyed this and please post pictures you take with the camera here!  Oh, and if you have any question, just post a comment.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_tf6A1GluJrw/SP_2kTjo2TI/AAAAAAAAAEY/o71OwvIkuKI/s1600-h/moon1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 318px;" src="http://3.bp.blogspot.com/_tf6A1GluJrw/SP_2kTjo2TI/AAAAAAAAAEY/o71OwvIkuKI/s320/moon1.png" alt="" id="BLOGGER_PHOTO_ID_5260193993377503538" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3366502883257825993-2330317336553383556?l=fluxtrap.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fluxtrap.blogspot.com/feeds/2330317336553383556/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fluxtrap.blogspot.com/2008/10/telescope-camera-howto-v1.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/2330317336553383556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3366502883257825993/posts/default/2330317336553383556'/><link rel='alternate' type='text/html' href='http://fluxtrap.blogspot.com/2008/10/telescope-camera-howto-v1.html' title='Telescope Camera HOWTO v1'/><author><name>mg</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img457.imageshack.us/img457/628/catseyenebula2smallnl4.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_tf6A1GluJrw/SP_2uPylOxI/AAAAAAAAAE4/QxsDBS4mjcM/s72-c/IMG_2522.JPG' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
