Chasing the BestBecause what pushes us forward is what we see ahead.Color Profiles in Photoshop vs Flex
For the past few weeks, we've been working on getting a beta version of a Flex app out the door. Our designers, meanwhile, have been coming up with great mockups in Photoshop for what we want the app to look like. The trouble we ran into was that the colors in Photoshop did not match the colors in Flex. i.e., in pulling the colors from Photoshop (in hex) and putting them into Flex, we'd end up with entirely different colors, usually much duller.
I haven't worried about this too much in the last couple of weeks because there was plenty of actual coding to be done, but I've recently started trying to incorporate some style things into Flex, and it started bugging me more and more. I finally got around to doing a Google search for an answer today, and here it is:
http://gen-6.com/blog/?p=17Christopher Hayen informs us that the trouble is Photoshop applying color profiles to the images. Once the color profile management is off, we get the right colors. Or so the theory is... I've passed this on to our designer so we can see if we can't equalize our colors a little. If this does fix it, I will be a very happy man, as it will mean a much easier time for me to get the styles implemented, and a much prettier application at the end of the line.
Obama Takes Office
I intend to generally avoid politics on this blog, but I'll just go off on a limb and mention that the inauguration speech a couple of days ago was wonderful, and I'm hoping for a good forthcoming four years.
Facebook Connect and... Best Practices?This script should be referenced in the BODY of your file, not in the HEAD. So says the Facebook Connect documentation of its FeatureLoader file. In the... Body? Why?Turns out, I'm a fan of keeping assets in the head and the.. Er... Body of the page in the body. Go figure. For now, I stuck the file in the head, and it worked. It probably breaks in IE or something, at which point it will be time for plan B. But there was more in store: <script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php" type="text/javascript"></script> <fb:login-button></fb:login-button> <script type="text/javascript"> FB.init("YOUR_API_KEY_HERE", "xd_receiver.htm"); </script>Oh yeah. Drop that JS directly into that HTML, baby. That's the way it's done. Er... Only not.No matter, I wrapped that call in a jQuery event for running when the DOM is loaded. Slightly late, admittedly, and it does cause some slight flashes, but dammit if it isn't in a better place. What's that I hear? The user experience is degraded? Unfortunately, that qualifies as `true'. I'll blog again when I've figured out a solution (probably forcing the size of the fbc button's container using CSS so that there'll be no jumping when that sucker's loaded). In the meantime, I'll go off on a limb and mention that one of the YSlow recommendations is to shove script loading at the bottom of the body tag (http://developer.yahoo.com/performance/rules.html#js_bottom). The point they make is fair, but the trouble is that, once again, performance best practices are overriding coding best practices. Still, this is slightly more acceptable -- if they're all at the bottom, they're still all in the same place. But not with all the other assets. I'm thinking there are a couple of paths to take:
Another Concurrent Programming Metaphor
Here's another concurrent programming metaphor. Assume the inputs are completely random.
Concurrent Programming Metaphors
Last night I was explaining the troubles with concurrent programming (or, more specifically, I was explaining why immutable data structures were nice, and particularly the implications on concurrent programming) and I came up with a couple of fairly entertaining analogies:
Recursion Is A Sexy BeastI was chatting with my older brother last night about how to implement something in Clojure and he was talking about keeping track of state. We're making a tile game, and we need a way to change the list of unused tiles while the game is running. The standard approach in the non-functional world is to have a variable in a class or (god forbid) a global variable that takes care of tracking the relevant pieces of state (in this case, the list of current tiles). This variable can then be referred to from whatever procedure needs to get a hold of it. However, functional programming is all about avoiding such state-based concepts, and to get there requires a new way of approaching problems. A brief, four-month-long-or-so stint in the Erlang world brought me a more solid understanding of how to approach these problems. Not being too much of a functional programming buff, I suspect that this particular level of understanding is just skimming the top of the reorientation that functional style brings. Already I catch glimpses of higher-level thinking in Reginald Brathwaite's posts on homoiconic, and I'm hoping I'll slowly get to that level (I've still got about 15 years to catch up to that level ). Anyway, for the purposes of posterity and my own understanding, a Better (tm) way to approach the problem of passing tile information around and keeping the data follows.The tile data is basically a list of maps. Each map contains information about a given tile (such as its number and color). Thus, we can define the list of tiles as following (in Clojure):(def tile-list '({ :number 5 :color "red" } { :number 4 :color "blue" }))This defines a list of two tiles, one a red 5, and the other a blue 4, and puts them in the tile-list var. An important thing to note is that Clojure and other functional languages typically provide an easy way to access the contents of a list in terms of the first element in the list and the `rest' of the list (a new list with everything but the first element). This allows us to look at the list elements one at a time while delegating the rest of the list to a recursive call to the same function. Now, in an OO-style language, we would have some sort of Game object that keeps track of the current tile list for the current game. But we need to try to avoid this type of state-based programming. Instead, what we will do is create a play-game function that takes in a list of players and the initial tile list. This function will call itself recursively until someone wins, letting each player play at each point by calling a play-turn function that takes care of the semantics of taking tiles and such. (defn play-game [tile-list player-list] (let [player (first player-list) [update-player updated-tiles] (play-turn player tile-list)] (play-game updated-tiles (concat (rest player-list) (updated-player)))))Here play-game takes a tile list and a player list. The current player is defined as the first player in the list. The function then calls play-turn with the current player and the current tile list and expects it to return an updated player and an updated list of tiles. Then, play-game calls itself, passing itself the updated tile list and a new player list that has the updated current player at the end instead of the beginning. This means that the recursive call will run play-game with the next player, and ensures that players will continue to get called in the right order. One last thing remains: as with any recursion (or, for that matter, any loop) we need a terminating condition that allows us to end the game. For now, let's define that terminating condition as a situation where the updated-player ends up with no tiles in their hand. One thing to note is that players are also tracked as maps. Their most important property is their list of tiles: (def player-list '({ :tiles '() } { :tiles '() }))So, we define our terminating condition as `whenever the updated player has a blank list of tiles for them'. If we were to go ahead and update our code for that: (defn play-game [tile-list player-list] (let [player (first player-list) [update-tiles updated-player] (play-turn player tile-list)] (if (empty? (updated-player :tiles)) (concat (updated-player) (rest player-list)) (play-game updated-tiles (concat (rest player-list) (updated-player))))))So here we introduce a new bit of semantics to play-game: when the game is over, it will return the final player list. The final tile list is assumed to be unimportant, though we could easily return that, too. So here we have something that would probably be implemented by tracking state within a loop implemented instead with recursion. The recursion lets us keep things strictly stateless, with a function whose side-effects are reflected solely by its return values. To my eyes, this is wonderfully elegant. Imagine also that you can technically then assemble tests that verify simply that a single turn play works (by calling play-turn) and then verify that play-game works once you're sure that play-turn will return the right values for a given state. One thing that isn't immediately apparent above is what we can achieve with higher order functions. If play-game were to take as a third parameter a function that is used to play the turn, we gain two things:
In this case, if we wanted to test a turn whose play returned a winning player, we would have to be fairly knowledgeable about the internals of play-turn so as to devise a player and tile list that would definitely win (alternatively, we could override play-turn manually, but that's just dirty). If, instead, we took in play-turn as an externally provided function, we could actually pass in a play-turn function that just returned a player with an empty tile list to induce the winning condition. As the final code example, here's a play-game that takes in a play-turn function: (defn play-game [tile-list player-list play-turn] (let [player (first player-list) [update-tiles updated-player] (play-turn player tile-list)] (if (empty? (updated-player :tiles)) (concat '(updated-player) (rest player-list)) (play-game updated-tiles (concat (rest player-list) (updated-player)) play-turn))))A tremendously simple change, all we did was take in a play-turn parameter and then make sure we pass it to the recursive call to play-game. One thing to note in the above examples is that, though the syntax is basically Clojure, I didn't really bother writing it using the recurse form that actually optimizes the tail recursion. This is because I find this gets in the way of the point, which is how recursion is being used. Clojure, unlike other functional languages, doesn't automatically optimize tail recursion. This is due to limitations on the JVM where it runs. So, it introduces the `recur' form to allow you to optimize tail recursion. Anyway, I went ahead and ignored that here so I could expose the concepts rather than the implementation details. The point of the post: recursion is a sexy beast. Playing with Clojure
It's been a while since I've really played with any Lisp derivative, but I've been spending my last couple of days toying around with Clojure, which is a Lisp that runs on the JVM. I've been testing out some crazy cross-languagisms by using Clojure to code Qt through QtJambi. So far it's been pretty sexy. The REPL is nice, vim's syntax highlighting package and indentation are nice.
All in all, other than some speed bumps regarding macros (still haven't quite wrapped my head all the way around those, unfortunately), this has been my best experience with a Lisp yet. I must admit, though, I think that's more because I've adapted my way of thinking to be more amenable to parentheses. Even a year ago, I was still a bit iffy on the overabundance of parens in Lisp, but now I find I'm perfectly comfortable with using s-exps for code. I think part of it has come from using Ruby. I can't quite put my finger on it, but coding in s-exprs seems similar to some things I do in Ruby -- my head can wrap itself around the parens because there are analogues being drawn to things I do with Ruby, even if I can't quite place them.
Anyway, should be fun. Rumikub implementation in Clojure+QtJambi, coming right up! :)
I Caved...
Yeah, I caved. This just in from a MacBook Pro.
Doing Gymnastics
As part of the OpenStudy project, we need to come up with a way to deploy a Flex app and a Rails app together. The Rails side forms mostly the backend, with some frontend stuff such as the landing page also handled there. The Flex app presents the main UI for the application.
The trouble with this is that the Flex app is done in FlexBuilder, but the deployment side should be fully automatable, and therefore should only have to rely on mxmlc (the Flex command-line compiler) or perhaps fcsh (the compiler shell that allows incremental compiles and such). This is a problem because these tools rely either on XML configuration files or on command-line parameters to tell them how and what to compile. FlexBuilder, meantime, tracks this information in its own, different XML configuration files, namely .actionScriptProperties and (sometimes) .flexProperties.
Now, the most annoying part about this is that you can't really get these two playing together nicely, unless you write your own glue code. Cue gymnast (http://github.com/Shadowfiend/gymnast). The purpose of gymnast is set to be hitting up the *Properties files, reading out the information about them, and building a nice Ruby object structure that describes the projects and their inter-relations.
Right now I'm not sure exactly what I'll be doing with this. It's possible that we would initially set up some basic rake or capistrano tasks for compiling the app in order to deploy more easily. Eventually it would probably be a better idea to actually hook into the Sprouts project (http://www.projectsprouts.org/) and provide information at least in one direction, potentially in both.
For now, gymnast is just focused on extracting the metadata. What we end up doing with that metadata... Well, I'll worry about that once I actually have it.
Scribd_fu Paperclip goodnessSo over the past month or so I refactored Matt Darby's awesome scribd_fu plugin (http://github.com/mdarby/scribd_fu) to work with Paperclip in addition to attachment_fu. I'm more a fan of Paperclip, as it turns out, and had been meaning to switch OpenStudy to Paperclip. Well, I finally got around to doing both, but then I sat on my code for a little while before working on merging it back into mdarby's main repository. First lesson learned: before you start a crazy refactoring job, make sure to pull from the repository you forked. At least if you intend on merging back. Turns out, when I started hacking, the main scribd_fu repository was about 8 commits ahead of mine. I realized this about 10 commits into mine, at which point I was past the point of no return. I finished up my refactoring, and, over the last week or so, I merged the changes from the main repository back into the newly refactored code, making it work for both attachment_fu and Paperclip. All in all, it was a fun exercise in `think before you start hacking'. Still, the end result is sexy: installing the mdarby-scribd_fu gem from github will work happily, and you can use config.gem from Rails 2.1+ to delightfully have that taken care of for you. Meantime, it ensures that the rscribd gem is present, as well. Plus, it automatically figures out whether you are using Paperclip or attachment_fu and behaves accordingly. One thing to note is that, since you are installing from gems.github.com, the rscribd dependency will only be resolved automatically if you have gems.github.com in your Rubygems sources and do a$ gem install mdarby-scribd_fuIf you include a --source directive, things won't go so well, and you will instead get this nasty bugger: $ sudo gem install mdarby-scribd_fu --source http://gems.github.com ERROR: Error installing mdarby-scribd_fu: mdarby-scribd_fu requires rscribd (>= 0, runtime)
* Optionally, you can switch to the has_scribdable_attachment method with no parameters for attachment_fu. * When using Paperclip, you have to use has_scribdable_attachment and pass it the attachment that should be sent to scribd for conversion as a symbol. * Validations now work. Before, uploads happened after_save, and validations relied on results that came only after the upload took place (e.g., the presence of scribd_id). Now the upload is run before_validation, so that the validations have the data available. The price for this is that an extra temporary file may have to be created to execute the upload. All Paperclip-related methods take the scribdable attachment as a symbol. In the case of the view helper, the attribute is the second parameter. This gives the scribd_document method two forms:* scribd_document(model, alternate_text) for attachment_fu and * scribd_document(model, attachment, alternate_text) for Paperclip.The alternate_text can be left off for both.I haven't had a chance to really hammer this thing with tests, though my limited testing does show that it works just spiffily. Any bugs can be reported by listing them on the scribd_fu wiki (http://github.com/mdarby/scribd_fu/wikis). Enjoy, and let us know about problems! |
|