(this works well as a dark backdrop against your iPhone icons)
Le Mans Classic Laurent Nivalle, classic cars, incredible race, amazing photography
To re-cap quickly, the FAQtory (pronounced Factory) is a simplified stackoverflow-like question and answer app. It allows you to Ask and Answer questions on any topic you like. The app is entirely content-focused and deliberately simple. A simple user voting mechanism ensures the most popular questions and most correct answers filter to the top.
Looking at the logs, it was last August when I kicked off the very first commit. After almost a year of on-again, off-again work and long periods of inactivity, last week finally saw it launch! In its current form the FAQtory is deployed for a single account, (pmfaqtory.com) – you can take a look here. Over time PMfaqtory intend to use FAQtory to build a resource of project management questions and answers.
This is a big milestone for me and with all features locked down for launch, I can concentrate on preparing for a general release. This will involve adding an account model, pricing options and payment gateway integration. I’ll also be moving the app to a new server stack and cloud based host.
Over the coming weeks I hope to talk more about some the design and technology decisions I have made so far. For a bit of fun, here is a replay of the Git log using the latest Gource visualisation engine (now with added ‘Bloom’ effect!)
music is 'Penguin' by the Books
You may have heard the news on my recent engagement. Not to be outdone in the proceedings, I took it upon myself to buy a new watch. I haven’t been a ‘watch wearer’ for years, always resorting to pull whatever gadget or phone I had out of my pocket for the time. No longer!
I was surprised to find out just how hard this particular watch is to find. Apparently you must specifically order it from Zenith through an authorized Zenith reseller, and after trawling around every swiss watch shop in London, I had lead times from 6 to 1 month. I went with Harrods, they had the original 1965 model in stock (for trying on), excellent customer service and they could have a new one ready for collection in 2 weeks.
I’ve been happily wearing it daily for the last couple of weeks and its running well. It is an automatic, so after initial winding you must wear it daily for the first 12 days to get it trained to your wrist’s movements.
I have jumped on board the RVM bandwagon for managing my development environments. I recently sold my Mac Pro on eBay and have a fresh new 27" iMac on the way. So I thought I’d document this part of the install process and a couple of gotcha’s.
# install readline for OSX if needed - check if it already exists in /usr/local/lib wget ftp://ftp.cwru.edu/pub/bash/readline-6.1.tar.gz tar -xvzf readline-6.1.tar.gz cd readline-6.1 ./configure && make && sudo make install # install RVM from github bash < <( curl http://rvm.beginrescueend.com/releases/rvm-install-head ) # edit your .bash_login (or profile) and add this at the bottom [[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # check RVM has installed OK, look for 'is a function' . ~/.bash_login type rvm | head -n1 rvm notes # install REE, or whatever Ruby you'd like rvm install ree -C --enable-shared,--with-readline-dir=/usr/local # show what rubies are installed rvm list # set REE as the default and current ruby rvm --default ree # check your working directories which ruby && which gem # In general I use Bundler for apps, but for .irbrc and some scripts I need these too gem install wirble awesome_print hirb bundler mysql heroku # and finally for the postgres (pg) gem sudo env ARCHFLAGS='-arch i386' gem install pg
I’m surprised by how few steps it takes these days (to get Ruby & Rails up and running with a database), four years ago this was a different story altogether. With tools like RVM and Bundler, it couldn’t be simpler.
My primary backup is Time Machine set to auto-backup my entire machine to a single 1TB drive (including all my iTunes media and applications). This way I can do a full restore if I ever need to. BUT, what happens when that drive fails? I needed a remote, off-site backup for my essential files. The stuff I just couldn’t afford to loose if Time Machine died.
I wanted a solution that was simple, fast, efficient (incremental and deletes redundant files), secure and wouldn’t cost the earth. After researching different options (MobileMe, Dropbox, S3, iDrive, mozy) I found that I could simply use rSync over SSH with my Dreamhost. Here’s how …
I already use Dreamhost to host some legacy websites, and they offer unlimited storage space on even their cheapest hosting plan. Per/Gb its way more cost effective than Amazon S3. I setup the following bash script to run these rsync commands on a daily cron interval (where mydhserver.dreamhost.com is my remote dreamhost server)
#!/bin/bash # send via rsync using SSH rsync -azP --delete --delete-excluded --exclude-from=/Users/matt/.rsync_exclude.txt /Users/matt/Documents email@example.com:~/rsync_backup rsync -azP --delete --delete-excluded --exclude-from=/Users/matt/.rsync_exclude.txt /Users/matt/Sites firstname.lastname@example.org:~/rsync_backup rsync -azP --delete --delete-excluded --exclude-from=/Users/matt/.rsync_exclude.txt /Users/matt/work email@example.com:~/rsync_backup rsync -azP --delete --delete-excluded --exclude-from=/Users/matt/.rsync_exclude.txt /Users/matt/resources firstname.lastname@example.org:~/rsync_backup rsync -azP --delete --delete-excluded --exclude-from=/Users/matt/.rsync_exclude.txt /Users/matt/workbench email@example.com:~/rsync_backup
I have a separate rsync_backup user setup on my Dreamhost account using an SSH key pair without passphrase. Make sure sure that ~/rsync_backup exists on your remote server before running this. The .rsync_exclude.txt file simply contains a list of file patterns to exlude from backups, mine looks like this;
Steam Content .svn .DS_Store
rSync will use SSH by default when sending your data (so its encrypted over the wire). However, you should remember that your backed up data (on the remote machine) is NOT encrypted, it is only as secure as the server it resides on.
So rSync is cheap, simple, fast (you can tweak SSH options to make it faster/slower), incremental and secure. Here’s a few helpful links on configuring your rSync backups further.
We managed to pick up this little ring in Damiani (who were very helpful in getting it re-sized before we left —thanks to Mr. Filippo Gossi). We liked Florence so much, we might even consider having the wedding there! We visited the Tuscan countryside on a couple of Vespa scooters and saw plenty of great locations.
I don’t usually recommend iPhone games here, but I stumbled upon Hook Champ a week ago and i’ve been ‘hooked’ since. It’s a speedy platform, jumping/swinging game with a classic 8-bit retro style. Its highly addictive and great fun in vs. mode, trying to outpace your competitor to the finish. Playing takes me on a nostalgic trip back to the excellent Rick Dangerous series on the Amiga.
I’ve also been reading the dev blog for The Incident another retro styled iPhone game due for release soon. It’s interesting to see how the developer (Matt Comi) approaches different aspects of the game on the iPhone SDK.
ActsAsTextcaptcha - pretending to be human just got tougher!
You can also play around with a working demo on heroku.
The gem can be configured with your very own logic questions (to fall back on if the textcaptcha service is down) or as a replacement for the service. It also makes use of bcrypt encryption when storing the answers in your session (recommended if you’re using the default Rails CookieStore)
The gem contains two parts, a module for your ActiveRecord models, and a tiny helper method (spamify).
A call to spamify(@model) in your controller will query the Text CAPTCHA web service. A restful GET request is made with Net::HTTP and parsed using the standard XML::Parser. A spam_question is assigned to the model, and an array of possible answers are encrypted in the session.
validate_spam_answer() is called on @model.validate() and checks that the @model.spam_answer matches one of those possible answers in the session. This validation is only carried out on new records, i.e. never on edit, only on create. User’s attempted spam answers are not case-sensitive and have trailing/leading white-space removed.
BCrypt encryption is used to securely store the possible answers in your session. You must specify a valid bcrypt-salt and (computational) cost in your options. Without these options possible answers will be MD5-hashed only.
allowed?() and perform_spam_check?() are utility methods (that can be overridden in your model) They basically act as flags allowing you to control creation of new records, or whether the spam check should be carried out at all.
If an error occurs in loading or parsing the web service XML, ActsAsTextcaptcha will fall back to choose a random logic question defined in your options. Additionally, if you’d prefer not to use the service at all, you can omit the api_key from your options entirely.
If the web service fails or no-api key is specified AND no alternate questions are configured, the @model will not require spam checking and will pass as valid.
For more details on the code please check the documentation.
Text CAPTCHA’s logic questions are aimed at a child’s age of 7, so they can be easily solved by all but the most cognitively impaired users. As they involve human logic, such questions cannot be solved by a robot. There are both advantages and disadvantages for using logic questions rather than image based captchas, find out more at Text CAPTCHA.Rob Tuley of Openknot
Finally, since things have changed so much over the years, i’ll be doing a refresher post on the state of play for creating/testing and releasing a Rails gem/plugin from scratch.
If you choose to install as a plugin, or are interested in the code, the following rake tasks are available;