tag:blogger.com,1999:blog-3810991801809509272024-03-14T06:04:04.851-04:00Kuhl.ITI'm a guy who follows technology, programming, and related topics closely. This is a place for me to offer insights and tips to the world beyond my shouting distance.Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.comBlogger28125tag:blogger.com,1999:blog-381099180180950927.post-28242225421184725432011-04-04T12:44:00.008-04:002011-06-02T09:25:26.690-04:00Ajax file uploads and CSRF (in Django 1.3, or possibly other frameworks)<p>To begin, this is an update of my old post <a href="http://kuhlit.blogspot.com/2010/12/ajax-uploads-in-django-with-little-help.html">AJAX Uploads in Django (with a little help from jQuery)</a>. This guide is specific to Django, but my version of the file uploader can (theoretically, it is untested) be used with other web frameworks that use CSRF, like Ruby on Rails. You should be able to follow along with the guide and make adjustments as appropriate for your framework.</p>
<h2>Required Software</h2>
<ul>
<li><a href="https://github.com/alexkuhl/file-uploader">My version</a> of Valum's file upload</li>
<li>Python 2.6+</li>
<li>Django 1.3+</li>
</ul>
<p>If you are on an older version of Python and/or Django, reading the <a href="http://kuhlit.blogspot.com/2010/12/ajax-uploads-in-django-with-little-help.html">prior version of this post</a> and especially <a href="http://stackoverflow.com/questions/4195985/django-ajax-upload-outside-of-a-form">this Stack Overflow question of mine</a> may provide some help in adjusting the code. The only part that requires updated Python and Django is the save_upload function. The code uses buffered readers/writers and the 'with' keyword from Python 2.6+ (these parts can easily be changed I suspect) and reads from the raw HttpRequest, which comes with Django 1.3+. The Stack Overflow question has code I tried before moving up to requiring these newer software versions. It worked for small uploads below CD ISO size (700MB) and can probably be fixed to work with all uploads, I just found the Django 1.3+ solution easier and quicker at the time.</p>
<h2>Overview</h2>
<p>Ajax Upload handles the client-side very seamlessly and only gives one challenge to the programmer: it passes the file either as the raw request, for the "advanced" mode, or as the traditional form file for the "basic" mode. Thus, on the Django side, the receiving function must be written to process both cases. As the old post discusses, reading this raw request was a bit of trouble, and that is why I went with Django 1.3 as a requirement for my code.</p>
<h2>Setup and Settings</h2>
<p>First is to get AJAX Upload installed by <a href="https://github.com/alexkuhl/file-uploader">downloading the latest version from my Github repo</a>. This fork of Valum's original includes my changes as well as improvements from other forks that I need. As of this writing, I have added correct awareness in FileUploader of FileUploaderBasic's 'multiple' parameter and included David Palm's onAllComplete trigger. Once downloaded, grab <code>fileuploader.js</code> and <code>fileuploader.css</code> out of the client folder and place them wherever is appropriate for your setup. Finally, link them in your HTML via your Django templates.</p>
<h2>The Web (Client) Side</h2>
<h3>HTML</h3>
<p>This is the HTML code that will house the upload button/drag area so place it appropriately.</p>
<pre class="brush: xml"><div id="file-uploader">
<noscript>
<p>Please enable JavaScript to use file uploader.</p>
</noscript>
</div></pre>
<h3>Javascript</h3>
<p>You probably want to dump this in the same HTML/template file as the above, but it is up to you of course.</p>
<pre class="brush: js">var uploader = new qq.FileUploader( {
action: "{% url ajax_upload %}",
element: $('#file-uploader')[0],
multiple: true,
onComplete: function( id, fileName, responseJSON ) {
if( responseJSON.success )
alert( "success!" ) ;
else
alert( "upload failed!" ) ;
},
onAllComplete: function( uploads ) {
// uploads is an array of maps
// the maps look like this: { file: FileObject, response: JSONServerResponse }
alert( "All complete!" ) ;
},
params: {
'csrf_token': '{{ csrf_token }}',
'csrf_name': 'csrfmiddlewaretoken',
'csrf_xname': 'X-CSRFToken',
},
} ) ;
}</pre>
<p>Now, let's make some sense of that.</p>
<ul>
<li>It is probably simplest to use the url template tag to fill in the action as I did above, but it could also be a hard-coded URL as a string. It is set here to match the URL config covered later in this guide.</li>
<li>The multiple option is not something that is not discussed in Valum's documentation that I found. Its purpose is to limit the uploader to allow you to determine whether it supports selecting/dragging multiple files for upload at a time. A value of true allows multiples, false will let it only do one at a time. In Valum's, this option is available to FileUploaderBasic, but not FileUploader, which is the class most people use. For my repo I chose to update FileUploader to be aware of the multiple option.</li>
<li>The onAllComplete callback is something added to my repo over Valum's that I got from David Palm's fork. It is called whenever the queue of uploads becomes empty. For example, if you drag/select 4 uploads, this will fire once all 4 have finished. If you then drag/select 2 more files for upload, this will fire again when those 2 are completed.
<li>The params are set up so the uploader can interact with Django's CSRF framework properly. <code>csrf_token</code> is obviously the token itself, while <code>csrf_name</code> is the name of the input expected by Django for form submissions and <code>csrf_xname</code> is the HTTP header parameter it reads for AJAX requests. Why did I bother with making these last two parameters? Well, theoretically my version of the file uploader should work with other frameworks, which may expect different names for these. For example, Ruby on Rails will expect 'X-CSRF-Token' for AJAX requests and 'authenticity_token' for forms (I think).</li>
<li>jQuery is used to grab the appropriate part of the div. If you are not using jQuery use whatever method is appropriate for your system to get the <code>file-uploader</code> DOM element. Using regular Javascript you could do <code>document.getElementById('file-uploader')</code>, as Valum uses in the examples on his site.</li>
</ul></p>
<h2>The Server (Django) Side</h2>
<h3>Django URLs</h3>
<p>It is best to have two views for this setup to work: one to display the upload page and one to process the upload file. The URLs need to be set in <code>urls.py</code> of course.</p>
<pre class="brush: python">url( r'/project/ajax_upload/$', ajax_upload, name="ajax_upload" ),
url( r'/project/$', upload_page, name="upload_page" ),</pre>
<p>Note that these may require some adjustments depending on how your <code>urls.py</code> is coded.</p>
<h3>Views</h3>
<p>First is the upload_page view, which is going to display the page with which the user interacts. This is a simple skeleton, add whatever your template needs.</p>
<pre class="brush: python">from django.middleware.csrf import get_token
def upload_page( request ):
ctx = RequestContext( request, {
'csrf_token': get_token( request ),
} )
return render_to_response( 'upload_page.html', ctx )</pre>
<p>Including the <code>csrf_token</code> in the context is very important, as earlier code depends on having this variable available. For some reason Django does not give you access to the token automatically in templates.</p>
<p>Next is the view to handle the upload. Remember that this code must handle two situations: the case of an AJAX-style upload for the "advanced" mode and a form upload for the "basic" mode. I split this code up into two functions: one to actually save the upload and the other the view.</p>
<pre class="brush: python">def save_upload( uploaded, filename, raw_data ):
'''
raw_data: if True, uploaded is an HttpRequest object with the file being
the raw post data
if False, uploaded has been submitted via the basic form
submission and is a regular Django UploadedFile in request.FILES
'''
try:
from io import FileIO, BufferedWriter
with BufferedWriter( FileIO( filename, "wb" ) ) as dest:
# if the "advanced" upload, read directly from the HTTP request
# with the Django 1.3 functionality
if raw_data:
foo = uploaded.read( 1024 )
while foo:
dest.write( foo )
foo = uploaded.read( 1024 )
# if not raw, it was a form upload so read in the normal Django chunks fashion
else:
for c in uploaded.chunks( ):
dest.write( c )
# got through saving the upload, report success
return True
except IOError:
# could not open the file most likely
pass
return False
def ajax_upload( request ):
if request.method == "POST":
if request.is_ajax( ):
# the file is stored raw in the request
upload = request
is_raw = True
# AJAX Upload will pass the filename in the querystring if it is the "advanced" ajax upload
try:
filename = request.GET[ 'qqfile' ]
except KeyError:
return HttpResponseBadRequest( "AJAX request not valid" )
# not an ajax upload, so it was the "basic" iframe version with submission via form
else:
is_raw = False
if len( request.FILES ) == 1:
# FILES is a dictionary in Django but Ajax Upload gives the uploaded file an
# ID based on a random number, so it cannot be guessed here in the code.
# Rather than editing Ajax Upload to pass the ID in the querystring,
# observer that each upload is a separate request,
# so FILES should only have one entry.
# Thus, we can just grab the first (and only) value in the dict.
upload = request.FILES.values( )[ 0 ]
else:
raise Http404( "Bad Upload" )
filename = upload.name
# save the file
success = save_upload( upload, filename, is_raw )
# let Ajax Upload know whether we saved it or not
import json
ret_json = { 'success': success, }
return HttpResponse( json.dumps( ret_json ) )</pre>
<p>The first thing you probably want to edit here is the use of filename in either <code>ajax_upload</code> or <code>save_upload</code>. The saving function as it stands assumes filename is a path. In my actual usage, I combine filename with a constant from <code>settings.py</code> that represents the path to where uploads should be saved. So, at the beginning of <code>save_upload</code> you could have something like <code>filename = settings.UPLOAD_STORAGE_DIR + filename</code> where <code>UPLOAD_STORAGE_DIR</code> it set to something like <code>"/data/uploads/"</code>. Or, of course, you could skip the constant and hard code your path string, but that's bad right?
<br><br>And that's it, go have some fun!
<br><br>
I have had many people ask me via comments or email about providing a demo of this system. From a user standpoint it looks/works no different from the demo on <a href="http://valums.com/ajax-upload/">Valum's site</a>. As of right now I cannot provide my own demo because my web host does not provide a Django environment. I'm trying to work with them on getting it available though. I will also work on getting my code in as the Django example with the uploader code in my <a href="https://github.com/alexkuhl/file-uploader">github repo</a>. When either of those happen I will update this post.
<br><br>
Thanks to everyone who commented on the last post, they helped immensely in creating my github repo and in fixing bugs on the post itself. If you find any mistakes here please comment or contact me directly (contact info can be found on <a href="http://www.alexkuhl.org">my site</a>).</p><div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com31tag:blogger.com,1999:blog-381099180180950927.post-45639496921771202082010-12-19T12:54:00.002-05:002010-12-19T12:56:10.944-05:00The Rights and Wrongs of Dynamic Pages<p>I was recently reading <a href="http://www.economist.com/node/17723223?story_id=17723223">this article</a> over at The Economist. The content of the article aside, it made one other thing come to mind: with great power comes great responsibility.</p>
<p>As I began reading the article, and thus scrolling, all of a sudden my screen began to look a cluttered mess. A full-screen-width bar dropped down from the top with please-for-the-love-of-God-share-this-article-on-all-your-social-networking-sites buttons and a search box. Besides being redundant since those features are all already embedded on the page, it was distracting. About the same time a square box slides up from the bottom telling me I need to subscribe to the magazine, again covering up the content of the article. Again, there is already an advertisement-like area near the top of the page offering four free issues and telling you to subscribe.</p>
<p>The passive versions of these features I am fine with, but the two slide-in boxes are too much because they happen as one has already begun to read, thus distracting your attention and covering up the content you're there to see in the first place. It is a very in-your-face type of pressure that most people do not approve, just like extremely loud commercials.</p>
<p>Okay, so if The Economist is the Comcast of internet news, what's an example of dynamic pages done right in that area? I think the New York Times does it right. Go <a href="http://www.nytimes.com/2010/12/19/business/19ping.html">read an article</a> (this one I chose at random) or simply scroll through it. Nothing pops up to annoy you, everything happens on page load. The one exception is when you reach the bottom of the article a box slides in--and not over the content you're reading!--letting you know of <span style="font-style: italic;">related articles</span> you may be interested in. This is actually helpful rather than self-serving like The Economists's dynamic content.</p>
<p>So, while we are all enamored with the eye candy of modern Ajax development remember to take a critical eye to it and note those who are using it well. I think I'll go read some more NYT.</p><div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-2179541416283822142010-12-01T14:27:00.011-05:002011-04-04T13:18:31.591-04:00AJAX Uploads in Django (with a little help from jQuery)<h2>*** April 4, 2010: This post is a bit outdated and does not work with Django 1.3 final's stricter CSRF enforcement. I have a <a href="http://kuhlit.blogspot.com/2011/04/ajax-file-uploads-and-csrf-in-django-13.html">new post</a> that is much more up-to-date, cleaner, and easier to follow, especially because it uses the <a href="https://github.com/alexkuhl/file-uploader">github repo</a> I created that holds the changes that need to be made to the file uploader's javascript.***</h2>
<p>Part of my current project is creating an area where files need to be uploaded in a snazzier way that the normal "browse for a single file" sort of forms. The idea is to have a download button with the same OS chrome file dialog, but one that allows <em>multiple</em> files to be selected. Additionally, the even snappier part, is that HTML5's drag-and-drop functionality should also be available where supported.</p>
<p>After some searching I found a couple of sites that pointed me in the right direction.</p>
<ul>
<li><a href="http://valums.com/ajax-upload/">AJAX Upload</a> handles the client-side end of the upload process, including the required multiple-select and drag-and-drop (for browsers that support it). It even handles graceful fallback to iframe uploads for browsers that do not support those advanced features (Opera, IE, etc.).</li>
<li>On the Django side, I found <a href="http://www.johnberns.com/2010/07/08/using-valums-jquery-ajax-upload-with-django-1-2/">this site</a>, which gives some pointers to get it working with Django 1.2's CSRF token. The problem I encountered is simply passing the CSRF token to Ajax Upload via its params will not work, because Ajax Upload sends it in the querystring and Django expects it as POST data.</li>
</ul>
<p>Because neither of those gave me the whole picture, I had to piece things together on my own. Here is the straight-skinny on my findings for getting Ajax Upload to work with Django.</p>
<h2>Overview</h2>
<p>Ajax Upload handles the client-side very seamlessly and only gives one challenge to the programmer: it passes the file either as the raw request, for the "advanced" mode, or as the traditional form file for the "basic" mode. Thus, on the Django side, the receiving function must be written to process both cases. In the raw request version, reading the request without Django blowing memory was a bit of a challenge. I at first tried reading the data into Django's SimpleFileUpload. It is an in-memory class though, so it runs into issues with large files. Next I tried reading/writing the data through Python functions, which had similar problems. The "works all the time" solution requires Django 1.3, which is to use its new "http request file-like interface" to read from the request. If you're using Django 1.2 and figure out another way to read the request data for all file sizes please comment! I discuss these solutions a little more in depth at <a href="http://stackoverflow.com/questions/4195985/django-ajax-upload-outside-of-a-form">this Stack Overflow question</a> of mine.</p>
<h2>Setup</h2>
<p>First is to get AJAX Upload installed by getting the JS and CSS files wherever is appropriate and linking to them in your Django templates. Also make sure you have set up Django's <a href="http://docs.djangoproject.com/en/dev/topics/http/file-uploads">file upload handlers</a>. Next is setting it up on the site.</p>
<h2>The Web (Client) Side</h2>
<h3>HTML</h3>
<p>This is the HTML code that will house the upload button/drag area so place it appropriately.</p>
<pre class="brush: xml"><div id="file-uploader">
<noscript>
<p>Please enable JavaScript to use file uploader.</p>
<!-- or put a simple form for upload here -->
</noscript>
</div></pre>
<h3>Javascript</h3>
<p>You probably want to dump this in the same HTML/template file, but it is up to you.</p>
<pre class="brush: js">function generate_ajax_uploader( $url, $csrf_token, $success_func )
{
var uploader = new qq.FileUploader( {
action: $url,
element: $('#file-uploader')[0],
onComplete: function( id, fileName, responseJSON ) {
/* you probably want to handle the case when responseJSON.success is false,
which happens when the Django view could not save the file */
if( responseJSON.success )
$success_func( responseJSON ) ;
},
params: {
'csrfmiddlewaretoken': $csrf_token, /* MUST call it csrfmiddlewaretoken to work with my later changes to Ajax Upload */
},
} ) ;
}</pre>
<p>A little explanation is probably needed here.</p>
<ul>
<li>I have wrapped the code inside of a function that generates the uploader because I use it on a couple different pages that require different URLs. You can easily strip off the function part and simply place it in a regular <script> block for use on a single page.</li>
<li>It is probably simplest to use the url template tag to fill in the action, which is the URL that gets the ajax data and does the server-side processing. I use the url template tag to construct the $url parameter to this function, but if you are removing the function part put the tag directly with action: or you can hard-code the URL you want as a string.</li>
<li>I use the onComplete callback to pass returned json to another "success function" that parses the json and add information to a table on the page. Again, this is not necessary, but I thought it would be useful to show how this could work. The upload plugin itself will say whether the file upload was a success based on the returned json.</li>
<li>jQuery is used to grab the appropriate part of the div. If you are not using jQuery use whatever method is appropriate for your system to get the <code>file-uploader</code> DOM element. Using regular Javascript you could do <code>document.getElementById('file-uploader')</code>, as Valum uses in the examples on his site.</li>
</ul>
<h3>Ajax Upload Modifications</h3>
<p>I found the easiest way to get the CSRF token piece going was to modify Ajax Upload itself, unfortunately (I hate editing libraries since they need to be re-updated at each new release). Around line 1100 of fileuploader.js you will find the line "var form = ..." within UploadHandlerForm's _createForm method. Replace this line with the following:</p>
<pre class="brush: js">var form = null ;
if( params.csrfmiddlewaretoken )
{
var csrf = '<div style="display:none"><input type="hidden" name="csrfmiddlewaretoken" value="' + params.csrfmiddlewaretoken + '" /></div>' ;
form = qq.toElement('<form method="post" enctype="multipart/form-data">' + csrf + '</form>');
delete params.csrfmiddlewaretoken
}
else
form = qq.toElement('<form method="post" enctype="multipart/form-data"></form>');</pre>
<p>All this code does is search for the CSRF token, and if it is present insert it into the form in the way Django expects to receive it.</p>
<h2>The Server (Django) Side</h2>
<h3>Django URLs</h3>
<p>It is best to have two views for this setup to work: one to display the upload page and one to process the upload file. First, the URLs</p>
<pre class="brush: python">url( r'/project/ajax_upload/$', ajax_upload, name="ajax_upload" ),
url( r'/project/$', upload_page, name="upload_page" ),</pre>
<h3>Views</h3>
<p>First is the upload_page view, which is going to display the page with which the user interacts. This is a simple skeleton, add whatever your template needs.</p>
<pre class="brush: python">from django.middleware.csrf import get_token
def upload_page( request ):
ctx = RequestContext( request, {
'csrf_token': get_token( request ),
} )
return render_to_response( 'upload_page.html', ctx )</pre>
<p>Next is the view to handle the upload. Remember that this code must handle two situations: the case of an AJAX-style upload for the "advanced" mode and a form upload for the "basic" mode.</p>
<pre class="brush: python">def save_upload( uploaded, filename, raw_data ):
''' raw_data: if True, upfile is a HttpRequest object with raw post data
as the file, rather than a Django UploadedFile from request.FILES '''
try:
from io import FileIO, BufferedWriter
with BufferedWriter( FileIO( filename, "wb" ) ) as dest:
# if the "advanced" upload, read directly from the HTTP request
# with the Django 1.3 functionality
if raw_data:
foo = uploaded.read( 1024 )
while foo:
dest.write( foo )
foo = uploaded.read( 1024 )
# if not raw, it was a form upload so read in the normal Django chunks fashion
else:
for c in uploaded.chunks( ):
dest.write( c )
except IOError:
# could not open the file most likely
return False
def ajax_upload( request ):
if request.method == "POST":
# AJAX Upload will pass the filename in the querystring if it is the "advanced" ajax upload
if request.is_ajax( ):
# the file is stored raw in the request
upload = request
is_raw = True
try:
filename = request.GET[ 'qqfile' ]
except KeyError:
return HttpResponseBadRequest( "AJAX request not valid" )
# not an ajax upload, so it was the "basic" iframe version with submission via form
else:
is_raw = False
if len( request.FILES ) == 1:
# FILES is a dictionary in Django but Ajax Upload gives the uploaded file an
# ID based on a random number, so it cannot be guessed here in the code.
# Rather than editing Ajax Upload to pass the ID in the querystring, note that
# each upload is a separate request so FILES should only have one entry.
# Thus, we can just grab the first (and only) value in the dict.
upload = request.FILES.values( )[ 0 ]
else:
raise Http404( "Bad Upload" )
filename = upload.name
# save the file
success = save_upload( upload, filename, is_raw )
# let Ajax Upload know whether we saved it or not
import json
ret_json = { 'success': success, }
return HttpResponse( json.dumps( ret_json ) )</pre>
<p>And that's it, go have some fun!
<br><br>
<span style="font-weight:bold;">***Edit:</span> A few errors in the source have been fixed, thank you for your comments!</p><div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com12tag:blogger.com,1999:blog-381099180180950927.post-7198774933128231622010-11-29T15:18:00.005-05:002011-01-18T09:09:49.400-05:00Accessing guest's Apache server from the host in Virtualbox<p>To clarify the title of this post, I am running the latest Virtualbox (3.2.6) on a Windows 7 host with a linux (Kubuntu) guest. I am using the guest as a development box for a website I am working on and would like to access it from Win7 to test with Internet Explorer (yuck). This is something I've been wanting to get to work for a while but never really looked into it. Today I decided to break down and investigate. Turns out it is a fairly simple process.</p>
<h2>Option 1 - Port Forwarding</h2>
<p>
I first found this <a href="http://blog.eliotsykes.com/2009/10/29/virtualbox-how-to-accessing-guest-apache-from-host/">blog post</a> that discusses setting up the proper port settings for Virtualbox. I tried this and ran into some errors, including the one from the first comment. Just copying and pasting from the site I started up VB and immediately got the errors. I realized this is because I am using one of the Intel network adapters, not PCNet as in the example. The secret here is figuring out the appropriate device name to use in the paths given by the post. The way I found these was to look at the VBox.log file for the appropriate machine. In it you will find many lines, but you're looking for level 2 devices that look something like this:</p>
<pre class="brush: plain">[/Devices/i8254/] (level 2)</pre>
<p>In this case it is the device for the Intel network adapters. So, adjusting the code from the blog, you would run each of these at the command prompt...</p>
<pre class="brush: plain">VBoxManage setextradata YourGuestName "VBoxInternal/Devices/i8254/0/LUN#0/Config/apache/HostPort" 8888
VBoxManage setextradata YourGuestName "VBoxInternal/Devices/i8254/0/LUN#0/Config/apache/GuestPort" 80
VBoxManage setextradata YourGuestName "VBoxInternal/Devices/i8254/0/LUN#0/Config/apache/Protocol" TCPShutdown
</pre>
<p>
One thing to be careful of here is the already mentioned errors. These will prevent you from starting up the VM at all. The most common error is verr_pdm_device_not_found, which stems from having the incorrect device for the current settings, so using pcnet in the above code but having and Intel adapter chosen in the settings, or having an incorrect name in the path, say you missed the 'i' in i8254. The way to fix this is close out of VirtualBox--VMs and the program itself--and edit the xml configuration file for the machine. It will have <ExtraDataItem> entries near the top to correspond to the settings you changed above. Delete these three lines, startup VB, and your VM should now be able to start itself.</p>
<p>
The blog goes on to say you should then use localhost:8888 to access the web server but I never got this to work. I admit I did not try very hard, so the solution here could be a simple fix. I'm guessing it is some issue with Windows 7 networking handling the localhost, which is not something I felt like messing with, so I found a different solution.
</p>
<h2>Option 2 - Bridged Adapter</h2>
<p>
The network settings on my guest were to set it to connect via NAT. Changing to bridged, I was then able to browse to the guest's IP in my host (192.168.1.5 in this case) and everything worked fine. Much simpler and no messing with VBoxManage.
</p>
<h2>Option 3 - Host-only Adapter</h2>
<p>
The Host-only Adpater will also work but it will not give outside internet access to your guest. The plus side is that no physical network device is required, but for me it is hard to imagine a computer without a network device in this day and age.
</p>
<p><br><br>
Overall Option 2 is the best as I see it: simple and effective.
</p><div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-29903391766059705722010-11-08T16:57:00.004-05:002010-11-08T17:03:56.833-05:00Github: too many forks?I recently created a <a href="http://www.github.com/">Github</a> account (<a href="http://github.com/alexkuhl">check me out!</a>) and have become familiar with the site because it hosts a lot of <a href="http://www.djangoproject.com/">Django</a>-based modules. At first blush it seems like a programmer utopia: the code is open source and easily viewable, forking is encouraged and there is a somewhat intuitive interface for following them, wikis and issues are automatically created for each project, and, thanks to git, forks are (usually) easy to merge. There's a lot of users, a lot of activity, and a lot of prolific and talented programmers on github. <br />
<br />
So what's not to love?<br />
<br />
Really, Github does seem to be the cat's meow of the open source world at the moment, with a nod to <a href="http://www.bitbucket.org/">BitBucket</a>, where Mercurial-based projects are hosted. As I've said I've only recently begun to use Github, so I've discovered it has some significant oddities for someone just joining the ecosystem. I'm surprised there hasn't been more discussion of this, a quick search of the interwebs only really turned up <a href="http://andrewwilkinson.wordpress.com/2010/01/27/where-github-possibly-went-wrong/">this post by Andrew Wilkinson</a>.<br />
<br />
I'll summarize his points and then add some spice.<br />
<ul><li>Coders are "rock stars" that are emphasized over their projects and the interface is designed from a contributor point of view. He goes on to later point out that projects of any decent size typically have more users than contributors, so the interface is a bit quirky for someone just wanting to use the project.</li>
<li>Each fork gets its own issues and wiki, making it confusing where to discuss the project.</li>
<li><b>Determining which fork to use is not trivial</b></li>
</ul>The interface issues of the first I don't have much of an issue with because it sounds like Github is working on it; they've even made some <a href="http://github.com/blog/729-all-of-your-downloads-one-big-button">recent improvements</a> on this front.<br />
<br />
The second is definitely a problem, but I think is a necessary one. A fork potentially has its own features and bugs, so these need to be put somewhere. However, anything not specific to the fork should be put in the wiki/issue tracker/whatever of the main project. I think this would be less of an issue if the next point were fixed.<br />
<br />
Finally, I come to the heart of my Github confusion: which fork does one use? By 'use' I mean either fork and contribute to or, as a user, download and install. The developers have said they are working on a way to better identify the "main" project, but the solution is yet to be seen.<br />
<br />
I'll show how I find the "main" project, and then examine the issue itself. There are two "find main" methods that probably need to be used together. The Network graph (read up on it <a href="http://github.com/blog/39-say-hello-to-the-network-graph-visualizer">here</a>, you really need to understand these graphs to understand the my later figures) is not the place I start because it is relative to the current project, it will be used in a bit. What I mean by "relative to the current project" is, if you're looking at a project that is say the fork of the original project, all the commits for the original up to the point that the fork occurred are put into the forked project's timeline. Thus, I first try to find the "grandfather" or original project that started the chain. I do this by following the "forked from" links until I get up to the one that is not a fork of another.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img border="0" height="142" src="http://2.bp.blogspot.com/_AWxLWaBi_wE/TLTLMNdH34I/AAAAAAAADm4/5afD5RJGYik/s200/github4.png" style="margin-left: auto; margin-right: auto;" width="200" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Currently looking at dcramer's version of the project, a fork of robhudson's, which happens to be the grandfather.</td><td class="tr-caption" style="text-align: center;"><br />
</td><td class="tr-caption" style="text-align: center;"><br />
</td><td class="tr-caption" style="text-align: center;"><br />
</td><td class="tr-caption" style="text-align: center;"><br />
</td><td class="tr-caption" style="text-align: center;"><br />
</td></tr>
</tbody></table><div class="separator" style="clear: both; text-align: center;"><a href="http://2.bp.blogspot.com/_AWxLWaBi_wE/TLTLMNdH34I/AAAAAAAADm4/5afD5RJGYik/s1600/github4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"></a></div>After getting to the grandfather, I then look at the Network graph, which I consider clearer now because all forks show only their own commits. Typically the grandfather is the "main" version of the project, but occasionally a grandfather will become dormant and a fork will become the main line of development. Look to see whether the grandfather is still being updated, forked, and other forks are merging back. If not, see if another fork has taken over this position. If not, find the fork with the bug fixes and improvements that seem best, as it will probably become the "main" version as other people make the same conclusion as you (hopefully). Another thing that may be helpful is checking the number of watchers of a project/fork, this can give you an idea of its popularity.<br />
<br />
Okay, so hopefully you can see this is about as clear as mud and a rather inexact science. Wilkinson's "rock star" description is apt: projects are first identified first by the coder--<b>robhudson's</b> django-debug-toolbar--rather than the project itself. Admittedly this makes sense based on how git and forks work, but it leaves the interface muddied. Whom do I trust? robhudson or dcramer? Side note: I'm glad people generally use their names or sensible nicknames as identifiers, if "l33tskillz393" had a fork I don't think I'd even give it the time of day.<br />
<br />
To further clarify lets look at some pictures of the Network graphs for a couple of projects I've looked at recently. <br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img border="0" height="172" src="http://1.bp.blogspot.com/_AWxLWaBi_wE/TLTN5HRC23I/AAAAAAAADm8/tKovyWylV0E/s400/github.png" style="margin-left: auto; margin-right: auto;" width="400" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">(<a href="http://github.com/ericflo/django-pagination">django-pagination</a>)</td></tr>
</tbody></table><div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/_AWxLWaBi_wE/TLTN5HRC23I/AAAAAAAADm8/tKovyWylV0E/s1600/github.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"></a></div><br />
What I have identified as the grandfather and main branch is the line on the top. There are more forks not shown here, but none below hgrimelid's have any "recent" commits. It is pretty clear here that the grandfather branch is the "main" version of the project: past forks have either died or merged their changes back in (merges can be seen on the blue and neon green lines in the upper left). There are some recent forks off the latest grandfather commit, possibly with important bug changes or features, so it makes the decision a bit less clear. Go with the main branch and assume important changes will be merged in a future version, or go with a fork and hope it doesn't turn into a dead end?<br />
<br />
Lets look at another with a slightly different situation.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img border="0" height="161" src="http://1.bp.blogspot.com/_AWxLWaBi_wE/TLTP_Pj2s0I/AAAAAAAADnA/NlKC8qUL4tM/s400/github2.png" style="margin-left: auto; margin-right: auto;" width="400" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">(<a href="http://github.com/directeur/django-sorting">django-sorting</a>)</td></tr>
</tbody></table><div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/_AWxLWaBi_wE/TLTP_Pj2s0I/AAAAAAAADnA/NlKC8qUL4tM/s1600/github2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"></a></div>The grandfather is again on top. But this time the grandfather looks a bit outdated, no updates in months! Looks like a very active project though, plenty of forks--and forks of forks!--being made and updated. I do not think there is a clear choice.<br />
<br />
Github has highlighted an unforeseen problem with distributed version control when the participants aren't under some guiding light, such as working for the same company. The traditional model of a project is that there is some entity--a person, a committee, a company--that determines a project's versions, features, etc. Distributed source control may be used to develop the project, but at some point someone says "this is the next version" and everyone trusts that authority. This can be seen commercially in, say, how Microsoft releases new versions of Windows every so often. In the more complicated world of distributed version control, look at what git was created for developing in the first place: the kernel. It gets all kinds of forks and such but in the end the idea is that they get merged back in to the mainline kernel, Torvalds baptizes it, and distributions push this authoritative version out to users. In this traditional model, users and programmers really only care about the project as a whole, not the forks that went into it.<br />
<br />
Github flips this on its head, I assume because of the "rock star" approach. Each programmer is given equal stage and there is no definitive project. Without an authority people go on their merry way and we get these spider webs of Network graphs.<br />
<br />
I'm going to eagerly await Github's "find the main branch" solution. My admittedly rather warm-and-fuzzy suggestion is to strongly encourage merging forks. Traditionally forks have been a big deal because they split a project's development due to legal reasons or vision disagreements or whatever. But the assumption is there is no other recourse and no reconciliation. Perhaps this trained behavior is one reason for the lack of merges? Anyway, forks usually make significant changes to a project that are not necessarily meant to play nice with the original project. In the Github world forks are THE way to update projects. Thus forks are not splits, they are the way you do even small-scale things like fix bugs and add minor features. These are things that should bubble up to the main project, not languish in a soon-to-be-forgotten fork. It seems from my own experience that people fork, fix the bugs they need for their personal use, and then forget about the project altogether. If you look at the figures I've provided you see an abundance of forks, but merges are rare.<br />
<br />
If Github could convince all the forkers to be mergers it would be a much happier place.<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-6140052551486139852010-06-10T18:48:00.001-04:002010-11-08T17:03:07.263-05:00Traders don't know jack (about technology)As I was driving home today I caught a <a href="http://www.npr.org/templates/story/story.php?storyId=127747626">story on NPR</a> about the practice of high frequency trading, or HFT. For those of you who don't know, HFT in a nutshell is some (supposedly, we'll get to this in a second) clever guys writing custom software that makes stock trades in microseconds based on trading volumes and such. The idea is to make fractions of a penny billions of times. It is an interesting topic and for more you should listen to the story.<br />
<br />
What caught my ear though is they begin talking about the new server farm the NYSE is building in New Jersey that will handle all its transactions. The story then goes on to talk about how the HFT people are falling over themselves trying to get office space as close to the NYSE building as possible or, even better, inside the building itself. It is explained that the closer to the NYSE servers these guys get the faster their programs can communicate with the NYSE and thus lead to better informed trades. <br />
<br />
If you're a computer scientist something should sound amiss there. Closer to the NYSE servers makes your trades go faster? Buzzzz wrong! This is most definitely true if you have a direct connection to the NYSE but I am assuming these guys don't, they're using the internet like the rest of us. This means their information packets have to go from their computers, out to their service provider to get routed, to bouncing around the interwebs, and finally come shooting back to the NYSE which is only a few feet away from the original computer. Cell phones work in a similar manner, so if you're not a tech person and want a more concrete example get someone in the same room as you and call their cell phone from yours. Note the delay between when the person says something and when you hear it coming through the phone. It takes time for the voice to travel from the phone, to a tower, go through some routing and other towers, and then to the other phone, which is analogous to how internet traffic bounces around. <br />
<br />
So, Wall Street proves its stupidity yet again. I think I'll invest with the guys that are building their office next to their ISP.<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-35341616999865913302010-05-10T11:22:00.003-04:002010-12-19T12:57:26.360-05:00Simple Page Navigation -- why is it so hard?I am a big fan of Men's Health but have come to really loathe their online articles. I began looking at <a href="http://eatthis.menshealth.com/slideshow/30-saltiest-foods-america">this article</a> and the first page required me to scroll a bit to read the text. One would think the "next page" sort of links would be at the bottom thanks to the unofficial convention amongst major web sites. This is not the case however, the next/previous buttons are at the TOP of the article, requiring you to first scroll to read the page (this is okay in my book despite the no-scrolling zealotry) then scroll back to where you were to move to the next page. Terrible HCI design. There needs to be plenty of room for creativity on the web, but I'm afraid the art departments are still winning the battle over the (probably non-existent) user experience folks.<br />
<br />
I've been noticing poor navigation on plenty of other sites too so I'm not trying to pick on MH. The worst offenders seem to be "top 10" sort of lists. If I get the time, I'd like to dive into this a little more.<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-36047961878391628602010-03-28T15:56:00.000-04:002010-03-28T15:56:00.758-04:00Have Games Gone Anywhere in the Last Decade?I was just browsing through the newest issue of PC Gamer and came across this month's "10 Years Ago" feature. It is a small column that gives a little overview of what was going on in the PC Gamer issue from a decade ago. The thing that struck me is this particular issue had the "PC Gamer Readers' All-Time Top 50" list. And guess what were the top five?<br />
<br />
Half-life, StarCraft, Diablo, Warcraft II, and Civ II. <br />
<br />
Other than the fact that 3 of the top 5 are Blizzard games (time to buy some Activision stock) something struck me: these are pretty much the games everyone is playing TEN YEARS LATER. These games are still played heavily and their sequels (including World of Warcraft from the Warcraft series) are some of the most played and highest selling games in recent gaming history. And what are some of the most hotly anticipated games in the pipeline? Starcraft II, Diablo III, the next WoW update, Civ IV, and I'm sure there will be more Half-life 2 updates and sequels at some point. <br />
<br />
So what does this say about the games industry and we as gamers? It seems the games industry has become pretty much the same landscape as Hollywood: unimaginative blockbusters are rolled out based on existing franchises to bring in the dough while smaller indie titles that show that spark, magic, and imagination that makes a good game great rarely get the attention they deserve.<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-46426370114618442502010-01-08T11:34:00.003-05:002010-01-08T11:55:36.888-05:00Security Done WrongIf you know much at all about computer security, and more specifically authentication and passwords, you know that the problem is immensely difficult. You have to deal with the play between impossible-to-remember strong passwords and easily-remembered-but-easily-cracked user created ones. It is not an easy problem to solve and it seems no traction has been made on this in recent years. <br /><br />I did come across a case where someone has taken security to a ridiculous extreme. I was trying to order some transcripts from the University of Louisville and I haven't been a student there since 2002. At first it didn't seem so bad: I was able to drudge up my student ID number to get my username and then got my password reset. Great, that was easy, now just login and request a transcript... Nope. I have to have a PIN to login to the registration system, not my regular password that is used <span style="font-weight:bold;">for everything else</span>. No recovery option available either. Ugh. Grabbed the phone and called the registrar to get it straightened out. The man was very friendly, took my student ID and some authentication information. Good, sounds like he can help. <br /><br />"Now the PIN is a 6-digit number that you made up when you became a student. If you were going to make a 6-digit number what would it be?" <br /><br />My mind went blank. Ummmm?! "Maybe it was my birthday?" <br /><br />"No sir, that is a date." This is when I knew I was in trouble. I tried the 6-digit form of my birthday and no dice.<br /><br />"I really have no idea what it would be."<br /><br />"Well then you will have to mail in the transcript request form."<br /><br />"There's no way of retrieving or resetting it?!"<br /><br />"No sir it was set by you and we cannot do anything to it."<br /><br />What a terrible system. If you are a student using the system every semester to register and such (assuming registration uses the PIN) this would be fine. But is it a realistic expectation that I will remember a number I made up 8(!) years ago from a totally different place in my life? <br /><br />"Sorry Mr. President we can't launch the Earth saving device until we get your identity authentication passphrase! You set it 45 years ago when you turned 18 and it's impossible to recover. Now what is it before humanity is destroyed?"<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-62986218114760931582009-10-19T11:07:00.002-04:002009-10-19T11:36:24.195-04:00Is this really telling me something?I was recently going through the October issue of Discover and tucked away in the back between pages of lame ads is the "September's What is This?" on page 75. It is a <a href="http://www.chrisharrison.net/projects/bibleviz/index.html">visualization of the Bible</a> Chris Harrison at Carnegie Mellon that uses colored arcs to show references between the books of the Bible. It also throws in length in verses for the chapters of the books along the bottom, a secondary viz of sorts.<br /><br />This is all fine and dandy but I have to ask: What is This? *How appropriate eh? nudge nudge* To be fair, Chris makes it clear that he put together this viz to be "something more beautiful than functional." I'll give him this because a nice rainbow pattern emerges due to the arcs being colored based on distance of the reference. But he then goes on to say "At the same time, we wanted something that honored and revealed the complexity of the data at every level –- as one leans in, smaller details should become visible."<br /><br />This leads into something I've noticed with visualization in general: in the end all these fancy new ways of representing data aren't really helping me draw any conclusions. The golden oldies are much more effective at the actual goal of visualization: "Visualization is any technique for creating images, diagrams, or animations to communicate a message" (from <a href="http://en.wikipedia.org/wiki/Visualization_(computer_graphics)">Wikipedia</a>).<br /><br />It may be my untrained eye, but this graph is not revealing anything about the complexity of the data. Is it simply that there is a fairly even distribution of long and short arcs? Anyone familiar with the Bible could probably tell you that. What else is going on here to make it worthy of being in Discover? I'm not trying to pick on Chris here, he's just a high profile example of how I mostly feel about the "making graphs" part of the field. Especially while in grad school, I came across many projects that I simply looked at and said "So?"<br /><br />Just to end on a positive note I think Chris's website design rocks.<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-74371943193283731972009-09-27T18:27:00.006-04:002009-09-27T19:34:56.223-04:00Conundrum of ChoiceIf you follow the Linux world at all you have seen the same questions asked and topics debated over and over again. Is this the year of the Linux desktop? What is holding Linux back? What's the best way to bring new people into the fold? Can grandma be happy with Linux? All free software or take a more accepting view of proprietary software?<br /><br />While these are all important discussions I think the most important question discussed is whether there should be a "standard Linux." I've seen people get extremely flamed to Sunday and back for even having the guts to bring this up. But why is there such vitriol against the idea? <br /><br />I've had family and friends ask me "how do you know all this stuff?" in amazement as I can tell them some way to fix their Windows problem from memory over the phone. How did I learn this stuff? Well, besides having to do it a million times, there is only one way to do it: "Open Explorer, go to Tools, ..." <br /><br />In Linux this is not the case. At all. Sure, I can tell them to open up a terminal/console and type in some commands but uninformed user shudders at this; clicking buttons is their comfort zone. This leaves Konqueror as the way to do things. Oh wait, it's not just Konqueror. There's Dolphin, Nautilus, Midnight Commander, Thunar, and on and on. What prompted this whole thought process is <a href="http://resources.zdnet.co.uk/articles/comment/0,1000002985,39763719,00.htm">this editorial</a> at ZDNet that is a rundown of the 10 best Linux file managers.<br /><br />Even an experienced computer scientist like myself cannot keep track of all the different ways to do something in Linux. This allows for a wealth of customization and allowing you to do things your way, but this is really only a benefit to tech people who, let's be honest, can switch distributions and such as they please. An instance of the flip side for normal users occurred this summer. My students were working in a Linux environment and, though I told them to set KDE as their default, some people who had seen Linux before wanted to use Gnome. I let them, but later when they had problems translating KDE-centric instructions to Gnome I had to shrug and say "I don't know." This is where the "one to rule them all distro" makes sense: avoiding the huge hurdle that new users experience of getting help. Everyone joining the party would be in the same boat, everyday users could give each other tips, online guides would be simplified and they'd never find one for the wrong environment, and techie people would only need to learn the generic way and then whatever way they prefer doing things. <br /><br />Ah but that would make too much sense. People will continue to bicker for all eternity because they don't want Ubuntu to become the standard over their beloved Fedora (replace those two with any other distros to your pleasing). They'll say it isn't in the spirit of Linux or that it's against free software because this Joe Everyman distro would have to include graphics drivers and media codecs. <br /><br />Look at the rising popularity of Linux Mint and PCLinuxOS, the two that seem to have gotten the closest to this ideal. New users don't care about our tired and pointless debates, they are worried about practicality and usability. An article about the 10 best file managers isn't going to get their juices flowing like the rest of us.<br /><br />To satisfy the grognards, isn't the spirit having a distro to suit everyone's needs? This distro-for-everyone would serve the users who don't care about customization and choice, the people coming over from Windows or Mac that are used to being told how they should accomplish something. If we are honest with ourselves these people are not using Linux now, so this new distro probably would not hurt the existing distros that much.<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com2tag:blogger.com,1999:blog-381099180180950927.post-23187438482632697692009-08-12T14:01:00.004-04:002010-03-18T17:53:04.031-04:00Graphing in PythonTo begin, let me explain the project briefly: I set out with this project to learn a little more about grabbing data from the web, processing csv/xls, and most importantly graphing in Python. I decided to investigate the question of whether gas and oil prices are tied very closely because we all notice how much gas jumps up and for apparently no reason. For more information about the results see <a href="http://www.sugarydonut.com/2009/08/oil-vs-gas-prices.html">my Sugary Donut blog entry</a>. <br /><br />What I want to discuss here is Python's graphing capabilities. There are no language features for it, but plenty of people have developed libraries for it. I initially considered cairoplot and matplotlib but dismissed them as being "too big and complicated." I wanted something simple, quick, and without dependent packages. gnuplot got rejected for similar reasons as well as just not looking cool enough (imagine that, an ugly gnu tool *rolls eyes*). I initially started with PyGoogleChart and I immediately hit the problem that the graphs were of limited (re: poor) quality. This made me move onto PyChart, which looked like a well maintained project. I again ran into graphs of small size but also had trouble displaying the data in the way needed. The largest stumbling block was getting the dates to display along the bottom. I found examples of this convoluted solution of associating values with each date (so the values are plotted and the dates become the labels along the axis) on the PyChart website. However, I never really got this to work the way I wanted and it felt like a hack.... the back kind. Thus I gave in and decided to give matplotlib a try and I wish I had chosen it to begin with. It easily handled date data for one of the axes and required no coaxing or hacks to get the graph I needed.<br /><br />My complaint with matplotlib (as well as the others) is poor documentation. There's no "here's the easy explanation of how to do this stuff." To get the matplotlib stuff finalized I had to dig through FAQs, various examples, and the API documentation just to get a simple graph to look the way I wanted it to. Yuck.<br /> <br /><a href="http://www.alexkuhl.org/code/#oilgas">Check out the code</a><div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-64596670640291765062009-07-24T22:29:00.004-04:002010-12-19T12:58:11.712-05:00Apple Snags Coveted Market Segment<a href="http://www.dailytech.com/article.aspx?newsid=15778">Daily Tech</a> mentions a Business Insider article that talks about Apple dominating the >$1000 computer market with a whopping 91% market share. I have to say that that percentage is impressive no matter what, but upon further thought it may not be as big a deal as some are making it out to be. <br /><br />The first thing to note is that it says other makers are "stuck" in the sub-$500 range. In June the average computer price was $701 with PCs averaging $515 and Macs $1400. Because the average of these numbers is nowhere near the given average I'm not sure what they are including in those categories.<br /><br />Anyway, I would say there are only a few types of PC buyers. Tech people (who could go either way), Mac lovers, and everyone else. "Everyone else" largely buys those cheap PCs for various reasons and Mac people try to steer them into Macland. Thanks largely to the success of the ipod-itunes combo along with the iphone Apple has been gaining a lot of users. But do these people have a choice? Apple doesn't exactly offer a cheap computer, so this for one skews their numbers. Side note to Apple: if OS X is so efficient and stable why not release a cheaper computer with toned down specs and try to gain even more market share? Might as well ride the "Apple is hip" wave while you can. I have a feeling they don't do it because it would cannibalize their high-price (and high-margin) hardware.<br /><br />The second skewing point is the (probably larger) portion of the "tech people" crowd that opt for a regular PC, which include the gaming crowd. These people generally know their way around inside the computer and, as a result, are more likely to build a computer from scratch and then might upgrade rather than purchase a new one. They can even do this for the "everyone else" category. These numbers don't show up as a PC sale and I believe could make a significant impact on market share percentages, especially because few Apple users upgrade and Apple itself doesn't exactly make it easy.<br /><br />A little food for thought when considering the market share. But, as I said, impressive for Apple nonetheless, who is on quite a run even in these dark economic times.<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-30869833265956280302009-07-02T09:14:00.005-04:002009-07-02T13:11:44.361-04:00The Minimalist's AssertionsThe other day, Linux Today had a news item linking to <a href="http://fullmetalgerbil.com/2009/06/26/five-reasons-i-prefer-slackware-over-ubuntu/">this site</a>. Yet another blog link of someone shouting at the ether that somehow made the news. Maybe I'm just jealous I don't make the news; that's good though, that means I'm still undiscovered and real. I'm not sure this particular piece should have because the points given are so hackneyed it's not even annoying anymore. It did make me think about the overall philosophy though. Why do the supporters of the minimal distros keep beating the same drum over and over?<br /><br />The points this guys presents:<br /><br />1. A slower release cycle. <br />2. Speed. <br />3. Stability. <br />4. Minimalist install. <br />I'll skip his last point about the brown color scheme because that's too much of a personal opinion thing.<br /><br />I think his points are valid from a narrow point of view of a technology enthusiast, but my argument is that for the everyday user or even the lazy technologist like myself, these aren't all that important. We want an easy-to-use box that gets out of the way to let us do more important things, like waste time on Gmail. <br /><br />These are obviously important to the community because, as I said, these points get reiterated every so often, but why? I have to wonder if it is because the new users coming into Linux are not interested in the "hardcore" distros and the people who love them are feeling threatened. Ubuntu, SUSE, PCLinuxOS, and others are all expanding the Linux audience and I am extremely excited about this. I think that the nerd market already knows about Linux and has been using it, so these new users will more and more become, by a large percentage, casual or non-tech people. And this means that Slackware and the like will continue to be pushed to the fringes, which always brings up the problem of irrelevancy over the horizon and exodus of developers/users. Yes, these casual people could eventually desire to learn more and try something like Slack, but let's be honest in the fact that this probably will not happen. Ease of use is number one for a lot of people and I think that's truly the divide between Slack and Ubuntu (and others that fall in each category). <br /><br />To give a personal anecdote, I've been using Linux for many years now, have a graduate degree in computer science, and generally am patient enough with misbehaving technology to root out the problem and fix it. Twice now I've gotten the gumption to install Arch because I'll be in control. I'll make the decisions. It'll be MY computer. I'll "learn Linux" instead of "learn Ubuntu." But what happens is I get tired of messing with the OS instead of messing with whatever I'm trying to accomplish. I will admit my second go at Arch was much quicker and seemed to have a little more automagical configuration than I remembered from the first install. There is a fine line that Arch (Slack, etc.) take a small step over in pushing things onto the user that should happen automagically because it just doesn't matter. Setting up hardware is the best example I can give here: I don't care how my sound card is configured, just do it so I don't have to figure out that I have to unmute some channel in the command-line alsamixer. <br /><br />But that's the beauty of Linux distros, there's something for everyone.<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-35394887256092293582009-06-15T23:03:00.004-04:002009-06-15T23:09:52.574-04:00You eyeballin' me, snake?A large part of <a href="http://www.alexkuhl.org/teaching/tip/summer/">my summer class</a> at Duke TIP this year involves making games with PyGame. Not having used it before I've been teaching it to myself in preparation for class, so I have been on the site for tutorials and documentation quite a bit. I'll probably post a lot of my thoughts on both teaching with Python and Pygame and Pygame in general as I dig further into my course. For now, I just wanted to say the main snake logo on the top of the PyGame site surprised me yesterday. I noticed that the image is actually animated and the snake's left (the viewer's left, that is) moves every second or so. This "feature" may have been there for quite some time, but this is the first time I noticed it so it caught me off guard and made me smile!<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-59444159025639691122009-06-10T23:27:00.002-04:002009-06-10T23:38:46.901-04:00Windows7: the right direction?<a href="http://lifehacker.com/5285358/upcoming-tech-that-will-rock-your-world">Lifehacker</a> has an article about some techs that will "Rock Your World" out and one of the items is Windows 7. Note that OS X Snow Leopard is also on the list and the following commentary applies in a general sense.<br /><br />So I can see how Windows 7 would be a significant improvement over Vista, but is it really world rocking caliber? Is it world rocking because it really is in general or just because Vista was such a flop? Lifehacker's commentary mostly focuses on graphical and UI improvements like the new task bar and multi-touch support. Hmmm, my world is pretty stable at the moment. I can see how these may be "wow the future is here" for someone not in the tech world, but for someone who is in a technological field what is there really here to sink your teeth into? They do mention that it is "faster and smaller" but do not go into much detail. These are the things I want to see improved in a an operating system, not slicker transparency effects (because, really, that's not the operating system!).<br /><br />Microsoft had some cool stuff lined up for Longhorn/Vista long before release, such as WinFS and Monad (the new command line) but they dropped those in interest of the dreaded user access controls and gimmicky slickness. Also, MS people have shown that Windows can be a small and efficient OS (WinMini was it?), but they're hardly proving themselves with their actual releases. So what has MS really contributed to the world of the operating systems other than frustrating people so much some have moved to other platforms (win for Apple and Linux)?<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-13594616923984759412009-05-28T19:49:00.002-04:002009-05-28T19:57:49.748-04:00KDE teams needs to rethink versioningThey did it with KDE (the desktop) and now they've done it with KOffice: released a product not ready for the public as a new version number. In their defense they have made it clear that the initial "dot oh" release is not meant to be a fully featured or functional product and so is not for end users for both of these packages. But... <br /><br />This is utter stupidity. I'm not sure how else to describe it. Every other product on the planet uses a new version number to signify a significant update to a product that is stable and an improvement over the old product. The KDE people do not seem to get this system and all it is going to do is confuse users in the end. Yes, power/advanced/guru users can understand this but the intermediate to beginner will not get this at all. If Firefox 4 came out without the ability to manage bookmarks or, in a more direct analogy, if the next MS Office shipped without PowerPoint (to be added later in a patch) NO ONE WOULD USE THESE PRODUCTS. <br /><br />Come on KDE, just follow the conventions, use betas and release candidates, etc.. You're hurting yourselves and the Linux/open source community at large; confusing your users is not the way to build a community.<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com2tag:blogger.com,1999:blog-381099180180950927.post-70724585020140545292009-05-27T16:39:00.004-04:002009-05-27T16:55:11.056-04:00Great video game wallpapersFound these somewhere, thought I forget where now. I want to say <a href="http://www.dfckr.com/">DFCKR</a>. Anyway, unlike most fan art, these are beautiful paintings of some classic video game scenes. Way to go <a href="http://orioto.deviantart.com/gallery/#Videogame-Remakes">Orioto</a>!<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-44500207910243395402009-04-23T16:04:00.006-04:002009-04-25T10:09:48.175-04:00PC vs Mac by CNBC OTMThere's a lot flying around the internets about a segment from CNBC's On The Money featuring Jim Goldman, their Silicon Bureau Chief, talking about the true cost of a $699 PC <a href="http://www.cnbc.com/id/15840232?video=1096873496&play=1">[video link]</a>.<br /><br />I've seen several sites basically saying this guy is an idiot, and I totally agree, but they have not presented the full options and true facts available. The claims of the "true cost of owning a PC versus a Mac" by Jim:<br /><ul><li>Mac has a lot more included that a "stripped down PC" doesn't have</li><li>He gives a list of things you need to buy to get it to "perform like a Mac"....</li><li>Norton Anti-virus at $50/yr</li><li>Multimedia Software at $80-104</li><li>Photoshop at $140</li><li>Video Editing at $100</li><li>Music Software at $100</li><li>Geek Squad Visit at $140, which is just for diagnosis, not fixing the problem</li><li>"Intangibles"....</li><li>Mac laptop 1.2lbs lighter (than what?"</li><li>Battery life 4x better (than what? HP 2.5hrs Apple 8)<br /></li><li>"Faster Chip"</li><li>Higher-res screen<br /></li></ul>To begin, he apparently <a href="http://www.businessweek.com/technology/ByteOfTheApple/blog/archives/2009/04/cnbc_on_the_mac.html">stole his talking points</a> from Business Week writer Arik Hesseldahl, whose original article about this is <a href="http://www.businessweek.com/technology/content/apr2009/tc20090415_602968_page_1.htm">here</a>.<br /><br />Let's examine these one by one here. I think calling a PC "stripped down" is unfair and he should have defined what exactly he meant. There's also the problem that when the general population thinks of Windows or Mac that they are mostly thinking of things that aren't the actual operating system, but we'll ignore that for now.<br /><br />Jim puts Norton as $50/yr and asserts that viruses are such a huge problem on PCs and Arik, who gives a 3 year lifespan for the to-be-purchased laptop, tallies this to $150. Why Norton in particular? McAfee and others produce fine AV software. Jim did not do his research in that Norton AV is only $35/yr, it's $50/yr for Norton Internet Security. The need for the IS over AV products is shaky at best because, of course, there are free and/or open-source products out there to cover the offered functionality. For instance<a href="http://phoenixlabs.org/pg2/"> PeerGuardian</a> and <a href="http://www.javacoolsoftware.com/spywareblaster.html"> Spyware Blaster</a> to keep malicious sites and IPs from getting at your computer while there's a whole host of anti-spyware/adware program available such as <a href="http://www.safer-networking.org/index2.html">Spybot</a> or Lavasoft's Ad-Aware. Also there's a nice browser plugin from McAfee called <a href="http://www.siteadvisor.com/">SiteAdvisor</a> that tells you when a site is known to be a malicious as you browse and is available for at least Firefox and IE. And finally, in terms of anti-virus, there's no need to pay for software if you're a home user as there are plenty of free ones out there like <a href="http://www.free-av.com/">Avira Antivir</a> (the one I recommend and use) and <a href="http://free.avg.com/">AVG</a>. Additionally, though not quite as polished, there is the open source <a href="http://www.clamav.net/">ClamAV</a>. So, total extra cost so far: $0.<br /><br />Just a side note, since viruses and stability seem to be such strong bullet points for Mac supporters: don't believe all the hype. Macs are not immune to viruses, trojans, etc. as can be seen by the recent botnet that targeted Macs. Security researchers have been proving for some time now that Apple's platform is vulnerable just like Windows, it is just Apple has thus far lacked the market share to warrant much attention from the bad guys. Also, a little user education can go a long way. Since Windows XP came out I have had absolutely 0 problems that weren't solved by a simple reboot and have had no viruses or spyware. Why? Because I'm an educated user, I don't go looking around on fishy (or phishy! har har!) websites, and I'm careful about what I open or install on my Windows computer. To help save yourself from e-mail scams and viruses use webmail like <a href="http://www.gmail.com/">Gmail</a> that has good spam filtering and attachment scanning. Another plus you aren't open to the attacks that only require you to open an e-mail, which have been known to occur with the Microsoft Outlook e-mail client.<br /><br />Multimedia Software for $80-104. Jim never really gets into what he means here and Arik doesn't really have this as a category. Arik mentions Muvee Reveal for $80 and CyberlinkDVD for $104, so I guess this is where Jim gets his range. However, Muvee Reveal is video editing so should be in that category. That leaves us with "multimedia" meaning DVD software. Many DVDs come with some form of (usually not great) software for free and Windows Media Player will play some DVDs without having to buy a codec. The real winner here is <a href="http://www.videolan.org/">VLC</a> though. It'll play just about any format you throw at it and will play DVDs flawlessly without having to buy or download any codecs like with WMP. Arik also mentions Roxio Creator which has a ton of functionality, as seen by a quick skimming of its features list. I do not see anything here that can't be accomplished with free and/or open source software though. If you can't find the appropriate program that'll do what you need it to instead of buying Roxio send me an e-mail and I can help you <a href="http://www.alexkuhl.org/">[see my page for contact info]</a>. Adding with the last category: $0.<br /><br />Ahhh Photoshop. The apparent pinnacle of Appledom and bastion of fanbois everywhere. The problem here is that, again, Jim got it wrong. Photoshop does not cost anywhere near $140 (it's $699); that'll get you Elements, which, as Arik points out, is a perfectly reasonable substitution for a home user. Jim plows through this making it sound like a Mac comes with Photoshop, which is dead wrong, and the small bit of functionality he talks about is not photo editing, it's photo management. Arik is much clearer here, saying Photoshop Elements for $140 will give you the photo editing capabilities that iPhoto gives you, but doesn't discuss the photo management portion. So, looking at iPhoto, it is a good product and has some wonderful features. However, I would say most users would be happy with the functionality and super easy usage that <a href="http://picasa.google.com/">Picasa</a> provides for free, in both photo editing and management. If one needs to do some hardcore editing there is always <a href="http://www.gimp.org/">GIMP</a> or <a href="http://www.gimpshop/">GIMPShop</a> (GIMP hacked up to provide a more Photoshop-like interface). Summing again: $0.<br /><br />Video editing is admittedly my weak point as I've never really gotten into it. Jim claims you need $100 for this but, again, doesn't go into detail. Arik doesn't really discuss this other than the already mentioned Roxio Creator and Muvee Reveal. In about 3 seconds of Googling I found <a href="http://jahshaka.org/">Jashaka</a> which appears to be a pretty slick video editing tool. I'm sure there are others out there too. Seeing a trend? 0$.<br /><br />Finally $100 for music software. This is the one that really made me laugh. Who has honestly shelled out money for music software any time this millennium? Windows Media Player is free, Winamp is free, and iTunes is free (for both Mac and Windows, though you have to download it for Windows). Where's the $100 coming from? Another fail on Jim's part, $0. Side note: if you want iTunes on Windows but don't want all the extra crap (MobileMe, Bonjour, Apple Updater always wanting you to install Safari, etc.) you can Google "iTunes lite," Lifehacker has mentioned it in the past.<br /><br />Both guys claim that you're probably going to need a Geek Squad visit and Jim even goes so far as to say Macs "tend not to [break down]." Arik, yet again, is much more accurate in saying that Apple's Genius Bar for diagnosis is free. For both a PC and a Mac you'll have a warranty for actual hardware failures, it's a bit murkier for software stuff you've broken. I'm not going to bother looking up the cost of fixing something at Apple versus Geek Squad but there's going to be cost either way. I will say that a Mac is probably less likely to get messed up by a user, but it is not outside of the realm of possibility. In the end, it's probably all moot because I would bet there's that family member or neighbor or friend that you know that can fix the problem in 10 seconds.<br /><br />Next Jim mentions iLife being free with a Mac, which is true, but only partially. iLife will come with your Mac, but if you want to upgrade to the latest versions it'll run you $79/yr. Arik even fails to mention this little catch. Whoops. You don't *have* to upgrade, but considering the upgrades for the products I've mentioned are free we'll assume you need two uprades over your 3 year lifespan, so that's $158 ON THE APPLE SIDE. Note that *some* of the free and/or open source projects I mentioned might be able to run on a Mac. One of the things that I'm going to ignore that Arik talks about is GarageBand, a music creation and lessons suite. I can't imagine this being of much use to the average user because most people simply aren't musicians and so won't take putting music together seriously. As far as lessons go, try a book or video from the library or search internet video and sites, there's plenty of resources out there. If you really do need the audio creation stuff try Googling "garageband alternative," seems like there's plenty of options out there.<br /><br />Though neither mention it, I know MobileMe is popular amongst Apple users for its ability to "Access and manage your email, contacts, calendar, photos, and files at me.com" (from MobileMe's site at Apple). This functionality is currently provided for free from Google (plus extras such as Google Docs) and Microsoft provides similar service for free through its Live service. The Individual package for MobileMe will set you back $99 per year if you want that functionality. There is a free trial, which we'll assume is a year Ibecause I don't want to look it up, so that's another $198 ON THE APPLE SIDE. You could, of course, use the mentioned free services with a Mac. (Gizmodo also noted this lack of MobileMe mention)<br /><br />Both come down and say that, to get a Mac-equivalent PC you're going to spend $1500 total. From my tallies above I come up with $0 extra so far, leaving the cost at $699. The only things left are the "intangibles." First I'll address Jim's "Faster chip" because I have no idea what he's talking about here. I'll assume he means CPU, in which case there can be no claim here because he never gives a particular PC model; there are any number of models with varying specs available at that price. This really goes for all of his intangibles. Arik was looking at a particular HP model so his comparisons are somewhat fair, but what about other models and brands? Not to mention there is NO WAY I can believe getting a slightly lighter laptop with a slightly higher resolution screen to match the particular Mac that Arik is comparing to is going to cost an extra $800. The only thing left is battery, which it's been shown the Mac doesn't always get exactly the claimed 8 hours. First of all it there are a lot of assumptions there and in real-world usage it's only been observed to be about 4 hours <a href="http://gizmodo.com/5160578/the-17+inch-macbook-pro-review">[an example]</a>. My laptop gets 4 hours too. I'm not sure this whole battery thing is fair either, the particular HP model is extremely limiting. Just because Apple buyers have little to no choice on what they get from Apple doesn't mean PC users don't have plenty of options.<br /><br />In the end everything but the "intangibles" cost a whopping total of $0 extra for the PC. Although Arik (I'm not giving Jim credit here) does have some points about the hardware specs, I have already mentioned that he's only comparing one particular HP model to the Mac and there are plenty of other options out there. Also, $800 for a small bump in resolution and a pound less on weight seems steep to me, I can easily price those upgrades out on other computers for much cheaper than that. Let's even take these two at their word of $1500 total cost. That's still a LOT cheaper than the $2800 MacBook that Arik is comparing too! I'm going to go ahead and chalk Jim into the "moronic talking heads from news television" AND the "blinded Mac fanboi" categories.<br /><br />I guess my final bit of advice would be to buy a PC instead of a Mac and ditch Windows altogether for a flavor of Linux, such as Ubuntu (or, due to my preference of KDE, Kubuntu) or Mint. The benefits here are too many to mention.<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com1tag:blogger.com,1999:blog-381099180180950927.post-48056487647723172492009-04-15T22:07:00.005-04:002009-04-15T22:13:34.723-04:00Fox News makes bold, BOLD predictions!<a href="http://www.foxnews.com/story/0,2933,515647,00.html">10 Technologies About To Go Extinct</a><br /><br />Make sure to note that there is an *about* in the middle of there and then read the list. Way to go Fox! Floppies are almost dead?! No ways! Typewriters?! Discmen (or is that Discmans?)!? Ack! This really only confirms their average viewer age is well over the hill. Yet another reason to not pay attention to Fox's news offerings...<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-91151803266801188312009-04-06T23:23:00.003-04:002009-04-06T23:30:39.829-04:00Eternal BetaGmail's fifth birthday has come and gone. In those five years Gmail has steadily gained against the established competition and has demonstrated far more creativity. However there is one little nagging fact that everyone keeps talking about: why is gmail still in beta?<br /><br />A five year beta is just silly. PhD's have been written in shorter periods of time. Betas typically mean a product that is having little or no features added and is mostly working on stability and bug squashing. Gmail does not fit this paradigm. It has been mostly stable (ignoring the service outages, which are not a problem with the Gmail code itself) and a solid performer for years now with more focus on feature additions it seems.<br /><br />The real killer is the fact that there is Gmail Labs. Google's product labs have been about experimental functionality and "not ready for prime time" sort of projects. Hmmm. Does this sound like alpha and beta software? So Gmail is even mature enough to have its own alpha/beta system. How can you really have a beta within a beta? Honestly, come on. It's time you let your baby free Googles!<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com1tag:blogger.com,1999:blog-381099180180950927.post-5942961245143461522009-04-01T21:12:00.002-04:002009-04-01T21:16:03.200-04:00The April First UpdateWell I pondered doing an April Fool's joke but, considering my readership is probably one (myself) I didn't want to spend the time crafting the perfect joke. I will however pass on a nice, legitimate bit of math and nerd humor. Check out <a href="http://www.pcbsd.org/">PC-BSD</a> and notice--besides being an alternative OS you should try out instead of Windows or Mac--what the new v7 is being called. That's right, the Fibonacci Edition. The only problem is 7 isn't a Fibonacci number. Math fail!<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-66508808404938576532009-03-29T21:01:00.003-04:002009-03-29T21:16:33.788-04:00Converting color spaces in C++I recently posted my first bit of open source code on my website. It came about because I've had to do some converting of RGB colorspace into HSV for purposes of histogram matching for my research. There is code out there that can be found through The Googles but I've never been satisfied with any of them for various reasons. I've tried to make my code much more readible, straightforward, and clean than whizbang-look-at-all-the-c++-tricks-I-used code obscurity. I've also added the ability to convert RGB to HSL and back. I didn't see much use in having HSL<->HSV but this would not be hard to get by using RGB as a middle man. Have a look at it, use it, improve it, but make sure you follow the license! <a href="http://www.alexkuhl.org/code">RGB-HSL-HSV converter project</a> or the direct <a href="http://www.alexkuhl.org/code/cpp/rgb_hsv_hsl.hpp">c++ code</a>.<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-26121942479374282302009-03-28T14:12:00.003-04:002009-03-28T14:28:06.515-04:00Web needs a paradigm shiftI was browsing the <a href="http://www.hardforum.com">[H]ardForum</a> earlier today and something dawned on me. There's all kinds of buzz amongst web-heads about the new CSS/HTML/whatever standards and Apple is doing custom CSS additions to allow for animation in WebKit (bad Apple! follow the standards!). My realization is that CSS cannot be the future of the web.<br /><br />CSS is an extremely powerful way of expressing design and layout for a site. However, from personal experience and seeing a bazillion posts asking for CSS help, it is just too complicated or confusing to consistently get correct. Long ago we learned tables were bad for layout, we should use div instead. However, there seems to be no agreement as to the best way to use them and sites are often accused of overusing them. That's just one example, forums are littered with people asking why they can't get item x to overlap, float, stay put, or any other number of things on their pages and it seems the solution usually ends up being something obscure or unintuitive. <br /><br />Some stalwarts would write this off as people not knowing what they are doing. But isn't computer science about making things easier on ourselves? Programming languages have moved from the miserable days of low-level languages to the immense spectrum of high-level ones we have today. Why can't the web do the same thing and unburden some of the mundane work? Anyone who has looked at a CSS file from a large website cannot claim that it's easy to get the gist of immediately with a straight face. One example of a CSS failing may be that there's too many ways to do things. It should be moving more towards Pythonic thinking than C++. Yes allowing for 1, 2, or 4 arguments for, say, padding space is a good shorthand but it's not obvious as to which order they are in or how the 2 maps to handling the other two dimensions.<br /><br />Right now I cannot propose a new solution or ways to fix this. But I do know that we can do better, much better.<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0tag:blogger.com,1999:blog-381099180180950927.post-8270467960957221702009-03-17T22:31:00.004-04:002009-03-29T21:17:53.669-04:00Python tip: splitting strings with whitespaceThis has gotten me so many times now I figure I need to write it down. Plus, it'll be here for everyone else's benefit.<br /><br />Examine the following Python code:<br />>>> s = "foo bar spam eggs" # two spaces between bar-spam, three between spam-eggs<br />>>> s.split( " " )<br />['foo', 'bar', '', 'spam', '', '', 'eggs']<br />>>> s.split( )<br />['foo', 'bar', 'spam', 'eggs']<br /><br />Note that if you split on " " as in the first command, Python will split only on the first space in a span of whitespace. After the first, subsequent spaces are placed as empty strings into the returned list. However, if you use the split with no arguments, each split eats all connected whitespace.<div class="blogger-post-footer"><hr /> <a href="http://www.alexkuhl.org/blog">KuhlTech</a></div>Anonymoushttp://www.blogger.com/profile/13076198147587091595noreply@blogger.com0