<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>GoZuus Blog &#187; elliott</title>
	<atom:link href="http://www.gozuus.com/blog/author/elliott/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.gozuus.com/blog</link>
	<description>on software, business, and greek life...</description>
	<lastBuildDate>Mon, 07 Dec 2009 22:23:04 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>New Feature: Custom Profile Fields</title>
		<link>http://www.gozuus.com/blog/2009/10/custom-profile-fields/</link>
		<comments>http://www.gozuus.com/blog/2009/10/custom-profile-fields/#comments</comments>
		<pubDate>Tue, 13 Oct 2009 04:43:50 +0000</pubDate>
		<dc:creator>elliott</dc:creator>
				<category><![CDATA[Product News]]></category>
		<category><![CDATA[custom fields]]></category>
		<category><![CDATA[profile]]></category>

		<guid isPermaLink="false">http://www.gozuus.com/blog/?p=207</guid>
		<description><![CDATA[Two weeks ago, we replaced the profile editor with one which we hoped would be easier for your members to understand.  At the time, we mentioned that part of our motivation was to provide a few additional improvements.  Today we&#8217;re excited to present the first of those updates.
Several groups asked for the capability [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-thumbnail wp-image-208 summaryonly" title="custom-profile-edit" src="http://www.gozuus.com/blog/wp-content/uploads/2009/10/custom-profile-edit-150x150.png" alt="custom-profile-edit" width="150" height="150" />Two weeks ago, we <a href="http://www.gozuus.com/blog/2009/10/new-profile-editor/">replaced the profile editor</a> with one which we hoped would be easier for your members to understand.  At the time, we mentioned that part of our motivation was to provide a few additional improvements.  Today we&#8217;re excited to present the first of those updates.</p>
<p>Several groups asked for the capability to collect information specific to their group on users&#8217; profiles.  Some wanted to record big sisters, initiation scroll numbers, or just general hobbies and interests.  Alumni asked if we could include information about their spouses and/or children on the site.  Since this data varies from group to group, we wanted to allow organizations to pick what sorts of additional questions would be added.</p>
<p><span id="more-207"></span>Group administrators now have an additional link on the admin screen for the site.  Click on &#8220;Custom Profile Questions&#8221; to edit the questions asked of your members.  If you&#8217;ve used the Respondable feature you&#8217;ll be right at home here, as the question types and formatting options are the same.</p>
<p>Once you&#8217;ve added additional questions, direct your users to their profile page at <a href="https://profile.gozuus.com/me">https://profile.gozuus.com/me</a> and tell them to click on the menu link for your group&#8217;s site.  (Send out an e-mail to your GoZuus list!)  They&#8217;ll now see the additional questions and can respond to them there.</p>
<p><a href="http://www.gozuus.com/blog/wp-content/uploads/2009/10/custom-profile-edit.png"><img class="aligncenter size-medium wp-image-208" title="custom-profile-edit" src="http://www.gozuus.com/blog/wp-content/uploads/2009/10/custom-profile-edit-430x399.png" alt="custom-profile-edit" width="430" height="399" /></a></p>
<p>As members fill in this information, it will begin to appear on their individual profile pages.  All members of your group will be able to look up this additional information about other users.  (Don&#8217;t worry: if a member belongs to multiple groups, members of those other groups can&#8217;t see profile information that is specific to your organization.)</p>
<p><a href="http://www.gozuus.com/blog/wp-content/uploads/2009/10/custom-profile-view.png"><img class="aligncenter size-medium wp-image-209" title="custom-profile-view" src="http://www.gozuus.com/blog/wp-content/uploads/2009/10/custom-profile-view-430x302.png" alt="custom-profile-view" width="430" height="302" /></a></p>
<p>We&#8217;ll be adding options for private questions, as well as allowing administrators to export this data very soon.  If you have ideas or questions, or want to vote to bump either of these ideas up on the priority list, please let us know in the comments!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gozuus.com/blog/2009/10/custom-profile-fields/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Updated: New Profile Editor</title>
		<link>http://www.gozuus.com/blog/2009/10/new-profile-editor/</link>
		<comments>http://www.gozuus.com/blog/2009/10/new-profile-editor/#comments</comments>
		<pubDate>Fri, 02 Oct 2009 15:00:26 +0000</pubDate>
		<dc:creator>elliott</dc:creator>
				<category><![CDATA[Product News]]></category>
		<category><![CDATA[directory]]></category>
		<category><![CDATA[gozuus]]></category>
		<category><![CDATA[parent e-mails]]></category>
		<category><![CDATA[parent lists]]></category>
		<category><![CDATA[profile]]></category>

		<guid isPermaLink="false">http://www.gozuus.com/blog/?p=180</guid>
		<description><![CDATA[We just updated the profile editor this past week.  There were a growing number of problems with the old one, and we wanted to lay the groundwork for a few additional features we&#8217;re planning.
I started off by making a list of what we didn&#8217;t like:


Profile editor was under the shell of a group siteWhen [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.gozuus.com/blog/wp-content/uploads/2009/10/profile-screenshot1-150x150.png" alt="profile-screenshot" title="profile-screenshot" width="150" height="150" class="alignright size-thumbnail wp-image-194 summaryonly" />We just updated the profile editor this past week.  There were a growing number of problems with the old one, and we wanted to lay the groundwork for a few additional features we&#8217;re planning.</p>
<p>I started off by making a list of what we didn&#8217;t like:<br />
<span id="more-180"></span></p>
<ol>
<li><b>Profile editor was under the shell of a group site</b><br/>When a member belongs to more than one site, their profile is actually shared.  Having the editor under the shell of any one group site make this unclear.</li>
<li><b>Cumbersome to edit data</b><br/>Each line of information required a click to edit, a click to save, and two server requests.  This could be much simpler.</li>
<li><b>No good place for group-specific profile info</b><br/>We&#8217;d like to allow each group to add their own additional profile questions, but there was no good place to add these questions.</li>
<li><b>Parent contact information was buried</b><br/>Many users didn&#8217;t know this existed, and therefore didn&#8217;t fill it out.</li>
<li><b>Illogical parent contact separation</b><br/>Parent e-mail addresses had their own separate page, but parent mailing addresses were supposed to be entered on your profile.  Many users also only provided a home address, assuming we would know this was their parent&#8217;s address too.</li>
<li><b>Inconvenient e-mail update flow</b><br/>To prevent users from missing messages, we needed to ensure that you could never remove a verified primary e-mail address without providing a new one in its place.</li>
</ol>
<p>Many of these were minor issues, but we knew we could do better.  We started off with a brand new profile editing site at <a href="https://profile.gozuus.com">https://profile.gozuus.com</a>.   We gave it a different look, so that users would know it was external to their GoZuus group site.  We made it faster to edit, cleanly separated parent contact information onto a new page, and provided a separate profile page for each group to which you belong.  Here&#8217;s what it looks like now:</p>
<p><a href="http://www.gozuus.com/blog/wp-content/uploads/2009/10/profile-screenshot1.png"><img src="http://www.gozuus.com/blog/wp-content/uploads/2009/10/profile-screenshot1-430x293.png" alt="profile-screenshot" title="profile-screenshot" width="430" height="293" class="aligncenter size-medium wp-image-194" /></a></p>
<p>Watch for more enhancements to this feature and the user directory in coming months!  As always, if you have suggestions please let us know!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gozuus.com/blog/2009/10/new-profile-editor/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Quick Win: Anonymous Questionnaires</title>
		<link>http://www.gozuus.com/blog/2009/09/quick-win-anonymous-questionnaires/</link>
		<comments>http://www.gozuus.com/blog/2009/09/quick-win-anonymous-questionnaires/#comments</comments>
		<pubDate>Sat, 05 Sep 2009 15:23:20 +0000</pubDate>
		<dc:creator>elliott</dc:creator>
				<category><![CDATA[Product News]]></category>
		<category><![CDATA[anonymous]]></category>
		<category><![CDATA[questionnaires]]></category>
		<category><![CDATA[respondables]]></category>

		<guid isPermaLink="false">http://www.gozuus.com/blog/?p=121</guid>
		<description><![CDATA[We&#8217;ve had a few requests for anonymous respondables.  Such a feature never occurred to me, probably because our chapter always wanted to conduct official votes during meetings (which is essentially the main reason you&#8217;d want anonymous submissions).  However, now that we have a few groups approaching the 150 member mark, I can see [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve had a few requests for anonymous respondables.  Such a feature never occurred to me, probably because our chapter always wanted to conduct official votes during meetings (which is essentially the main reason you&#8217;d want anonymous submissions).  However, now that we have a few groups approaching the 150 member mark, I can see how counting votes in a meeting could be time-consuming.</p>
<p><img class="size-medium wp-image-122" title="Anonymous Respondables" src="http://www.gozuus.com/blog/wp-content/uploads/2009/09/Picture-18-430x131.png" alt="Anonymous Respondable Options" width="430" height="131" /><br />
<span id="more-121"></span><br />
This didn&#8217;t sound too difficult, so I decided to tackle the idea one afternoon last week.  You&#8217;ll now see two new options: &#8220;anonymous and hidden&#8221; and &#8220;anonymous, but publish the answers&#8221;.  Choosing either option will remove names from all responses, and the second choice will allow all members to see what others have said.  Careful though &#8211; once you mark a respondable as anonymous, you cannot change it back!</p>
<p>While I was making updates, I also added an option to reassign the owner of a respondable.  This brings the permissions system more in line with that of e-mail lists and statistics.  By reassigning a respondable, you give access to a different member for viewing responses.  You can even reassign a respondable to a member who would otherwise not have permission to create one.</p>
<p>Now that GoZuus is launched, we hope to make small improvements like this on a weekly basis.  If you&#8217;ve got an idea for a quick change that would make your life easier, please let us know!  Tweet your idea to <a href="http://twitter.com/gozuus">@gozuus</a>, or post it on our <a href="http://www.facebook.com/pages/GoZuus/115510321176">Facebook page</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gozuus.com/blog/2009/09/quick-win-anonymous-questionnaires/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Our Git Deployment Workflow</title>
		<link>http://www.gozuus.com/blog/2009/07/our-git-deployment-workflow/</link>
		<comments>http://www.gozuus.com/blog/2009/07/our-git-deployment-workflow/#comments</comments>
		<pubDate>Wed, 15 Jul 2009 15:56:39 +0000</pubDate>
		<dc:creator>elliott</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[production]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[staging]]></category>

		<guid isPermaLink="false">http://www.gozuus.com/blog/?p=103</guid>
		<description><![CDATA[Like most Rails developers, we&#8217;re using git for source control.  However, our first attempt at setting up a deployment system made a huge mess so we went looking for a better way.

I liked the ideas set forth by Bryan Helmkamp, but there was one flaw (mentioned by Jesse Andrews in the comments) I just [...]]]></description>
			<content:encoded><![CDATA[<p>Like most Rails developers, we&#8217;re using git for source control.  However, our first attempt at setting up a deployment system made a huge mess so we went looking for a better way.<br />
<span id="more-103"></span><br />
I liked the <a href="http://www.brynary.com/2008/8/3/our-git-deployment-workflow">ideas</a> set forth by Bryan Helmkamp, but there was one flaw (mentioned by Jesse Andrews in the comments) I just couldn&#8217;t get past.  It seemed entirely too easy for Kevin or I to erase working commits the other had made in production code.</p>
<p>I took Bryan&#8217;s rake task and built upon it to help prevent this sort of issue.  Here&#8217;s the goals:</p>
<ul>
<li>All code deployed to either the staging or production environments must be in <a href="http://github.com">GitHub</a>.  Using <a href="http://www.capify.org">Capistrano</a> for deployment helps enforce this, in that no code from a local repository can ever get deployed to the server.</li>
<li>All changes start by branching off the current production head.  This ensures we always have a stable place to start working, regardless of whether its for a quick bugfix or a month-long feature update.</li>
<li>Any developer can deploy their current development branch to staging at any time.  Remember, their development branch is based off of something that was a stable production release at one time.  However, updates may have been made to production since then that are not included in their development branch.  We consider this to be okay.</li>
<li>Any developer can merge their current development branch back into production.  However, their merge must be a direct fast-forward (which guarantees no conflicts).  If changes have been committed to production since their branch was created, they must first rebase their branch to start from the current production head.</li>
<li>All code merged into production is ready to be deployed at any time.  Sounds obvious, but our first strategy failed on this because commits made to staging weren&#8217;t always ready to go to production in that order.</li>
<li>Lastly, all this needs to be automatic, safe, and simple.</li>
</ul>
<p>In our solution, we treat production as a real branch and merge code into it.  This prevents commits from being lost by rewriting history.  However, we borrowed the idea of creating staging as a branch, but treating it like a tag.  I like this because it lets any developer tear down staging to use themselves at any time.  By not making commits to staging, I never have to worry about my buggy code affecting someone else&#8217;s testing.  (Or more realistically, someone else&#8217;s buggy code screwing up my testing.)</p>
<p>So, without further ado, here&#8217;s the rake tasks:</p>
<pre class="brush: ruby;">class GitCommands

  # Shows a diff of the current production and staging branches
  # (ie, what would change if staging was deployed to production)
  def self.diff_staging
    `git fetch`
    puts `git diff origin/production origin/staging`
  end

  # Pushes the specified branch to the remote origin, then
  # resets the staging branch to be a copy of that branch.
  def self.push_staging(branch_name)
    verify_working_directory_clean
    `git push origin #{branch_name}`
    `git fetch`
    `git branch -f staging origin/staging`
    `git checkout staging`
    `git reset --hard origin/#{branch_name}`
    `git push -f origin staging`
    `git checkout #{branch_name}`
    `git branch -D staging`

    `cap deploy`

    unless is_fast_forward_of_production(branch_name)
      puts(&amp;quot;nnWARNING: NON-FAST-FORWARD!n&amp;quot;+
        &amp;quot;The production branch has been updated since this branchn&amp;quot;+
        &amp;quot;was created (or you've made more than 100 commits). Stagingn&amp;quot;+
        &amp;quot;has been updated, but you'll need to run the followingn&amp;quot;+
        &amp;quot;before attempting to push to production.nn&amp;quot;+
        &amp;quot;  git rebase -i origin/productionn&amp;quot;+
        &amp;quot;  git push -f origin #{branch_name}nn&amp;quot;+
        &amp;quot;You may want to do this now before testing on staging.nn&amp;quot;
      )
    end
  end

  # Pushes the specified branch to the remote origin, then
  # merges its changes into the production branch.
  def self.push_production(branch_name)
    verify_working_directory_clean
    `git push origin #{branch_name}`
    `git fetch`

    verify_fast_forward_of_production(branch_name)

    # Update master to be the previous production
    `git checkout master`
    `git reset --hard origin/production`
    `git push origin master`

    # Merge the current branch into production
    `git branch -f production origin/production`
    `git checkout production`
    `git merge #{branch_name}`
    `git push origin production`
    `git checkout #{branch_name}`
    `git branch -D production`

    puts(&amp;quot;nnYour branch has been merged into production, but hasn&amp;quot;+
      &amp;quot;NOT YET been deployed.  Call the appropriate capistranon&amp;quot;+
      &amp;quot;tasks to deploy code, migrate the database, then restartn&amp;quot;+
      &amp;quot;passenger to make your changes live.nn&amp;quot;+
      &amp;quot;  cap production deploy:updaten&amp;quot;+
      &amp;quot;  cap production deploy:migraten&amp;quot;+
      &amp;quot;  cap production deploy:restartnn&amp;quot;
    )
  end

  # Creates a new branch using the current production branch
  # as a base.
  def self.create_branch(branch_name)
    verify_working_directory_clean

    `git fetch`
    `git branch -f production origin/production`
    `git checkout production`
    `git branch #{branch_name}`
    `git checkout #{branch_name}`
    `git push origin #{branch_name}`
  end

  # Creates a new local branch tracking a remote branch
  def self.track_branch(branch_name)
    verify_working_directory_clean

    `git fetch`
    `git branch -f #{branch_name} origin/#{branch_name}`
    `git checkout #{branch_name}`
  end

  # Creates a new branch using the current production branch
  # as a base.
  def self.destroy_branch(branch_name)
    verify_working_directory_clean

    `git fetch`
    `git checkout master`
    `git branch -D #{branch_name}`
    `git push origin :#{branch_name}`
  end

  # Determines the name of the current working branch.
  def self.get_branch_name
    branch = `git status`.scan(/A# On branch (.+)$/)
    raise &amp;quot;Could not determine which branch to use.  Perhaps use BRANCH=?&amp;quot; if branch.blank? || branch.first.blank? || branch.first.first.blank?
    return branch.first.first
  end

protected

  # Ensures that there are no pending changes in the working directory.
  # This was edited to allow untracked (and unignored) files, but that
  # may need to be removed for 100% functionality.
  def self.verify_working_directory_clean
    output = `git status`
    return if output =~ /working directory clean/ || output =~ /nothing added to commit but untracked files present/
    raise &amp;quot;Must have clean working directory&amp;quot;
  end

  # Verifies that the specified branch is a direct fast-forward of
  # the production branch.  This ensures that merges will be smooth
  # and conflict-free when running the git:push:production task.
  def self.verify_fast_forward_of_production(branch_name)
    unless is_fast_forward_of_production(branch_name)
      raise(
        &amp;quot;Branch #{branch_name} is not a fast-forward of the production branchn&amp;quot;+
        &amp;quot;(or there's more than 100 commits since the branch).n&amp;quot;+
        &amp;quot;Run:   &amp;quot;git rebase -i origin/production&amp;quot; and resolve all conflicts,n&amp;quot;+
        &amp;quot;then:  &amp;quot;git push -f origin #{branch_name}&amp;quot; to fix this.&amp;quot;
      )
    end
    return
  end

  # Determines if the specified branch is a direct fast-forward of
  # the production branch.
  def self.is_fast_forward_of_production(branch_name)
    production_last_hex = `git log -1 origin/production`.scan(/Acommit ([da-f]{40})$/).first.first
    branch_log = `git log -100 --pretty=oneline #{branch_name}`.scan(/^[da-f]{40}/)
    return branch_log.include?(production_last_hex)
  end

end

namespace :git do

  namespace :push do

    desc &amp;quot;Push the current branch to origin/staging for testing&amp;quot;
    task :staging do
      branch_name = ENV['BRANCH'] || GitCommands.get_branch_name
      GitCommands.push_staging(branch_name)
    end

    desc &amp;quot;Safely merge the current branch back into origin/production&amp;quot;
    task :production do # =&amp;gt; ['diff:staging'] do
      branch_name = ENV['BRANCH'] || GitCommands.get_branch_name
      GitCommands.push_production(branch_name)
    end

  end

  desc &amp;quot;Show the differences between the origin/staging branch and the origin/production branch&amp;quot;
  task :diff do
    GitCommands.diff_staging
  end

  namespace :branch do

    desc &amp;quot;Create a branch for a feature or bug fix. Specify BRANCH=name&amp;quot;
    task :create do
      branch_name = ENV['BRANCH']
      raise &amp;quot;You must specify a branch name using BRANCH=name&amp;quot; if branch_name.blank?
      GitCommands.create_branch(branch_name)
    end

    desc &amp;quot;Creates a local branch tracking an already-created remote branch.  Specify BRANCH=name&amp;quot;
    task :track do
      branch_name = ENV['BRANCH']
      raise &amp;quot;You must specify a branch name using BRANCH=name&amp;quot; if branch_name.blank?
      GitCommands.track_branch(branch_name)
    end

    desc &amp;quot;Removes a remote branch from the origin.  Specify BRANCH=name&amp;quot;
    task :destroy do
      branch_name = ENV['BRANCH']
      raise &amp;quot;You must specify a branch name using BRANCH=name&amp;quot; if branch_name.blank?
      GitCommands.destroy_branch(branch_name)
    end

  end

end</pre>
<p>We&#8217;ve been using this for the past several weeks and it&#8217;s been working great.  So, did we do any better?  Anyone see any flaws or have any other ideas?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gozuus.com/blog/2009/07/our-git-deployment-workflow/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Feature Update: Statistics</title>
		<link>http://www.gozuus.com/blog/2009/06/feature-update-statistics/</link>
		<comments>http://www.gozuus.com/blog/2009/06/feature-update-statistics/#comments</comments>
		<pubDate>Thu, 04 Jun 2009 01:28:09 +0000</pubDate>
		<dc:creator>elliott</dc:creator>
				<category><![CDATA[Product News]]></category>
		<category><![CDATA[attendance]]></category>
		<category><![CDATA[balances]]></category>
		<category><![CDATA[hours]]></category>
		<category><![CDATA[philanthropy points]]></category>
		<category><![CDATA[points]]></category>
		<category><![CDATA[statistics]]></category>
		<category><![CDATA[work hours]]></category>

		<guid isPermaLink="false">http://www.gozuus.com/blog/?p=83</guid>
		<description><![CDATA[The point tracking system was a great idea, but we felt it wasn&#8217;t living up to its potential.  Today, we&#8217;ve replaced the Point module with a Statistics interface that is easier to use and much more flexible.  Take a peek below (click to enlarge):

The first thing you&#8217;ll notice is that we&#8217;re now including [...]]]></description>
			<content:encoded><![CDATA[<p>The point tracking system was a great idea, but we felt it wasn&#8217;t living up to its potential.  Today, we&#8217;ve replaced the Point module with a Statistics interface that is easier to use and much more flexible.  Take a peek below (click to enlarge):<br />
<a href="http://www.gozuus.com/blog/wp-content/uploads/2009/05/statistics-home.png"><img src="http://www.gozuus.com/blog/wp-content/uploads/2009/05/statistics-home-430x240.png" alt="Statistics Home Screen" title="Statistics Home Screen" width="430" height="240" class="aligncenter size-medium wp-image-89" /></a></p>
<p>The first thing you&#8217;ll notice is that we&#8217;re now including <strong>Attendance</strong>, <strong>Balance</strong>, and <strong>Work Hour</strong> tracking by default.  Limitations in the Points system prevented it from being used for such a wide array of purposes, but now you can access everything from one standardized interface.  We made several changes to make this possible.<br />
<span id="more-83"></span><br />
<strong>Easier Updates</strong><br />
With the original system, entries could only be made by typing in values for each individual.  If you needed to assign one work hour to each member in the chapter, the &#8216;1&#8242; key on your keyboard was bound to wear out quickly.  The new assignment page provides options to streamline this data entry process.<br />
<a href="http://www.gozuus.com/blog/wp-content/uploads/2009/05/statistics-assignment.png"><img src="http://www.gozuus.com/blog/wp-content/uploads/2009/05/statistics-assignment-430x270.png" alt="Statistics Assignment Options" title="Statistics Assignment Options" width="430" height="270" class="aligncenter size-medium wp-image-93" /></a><br />
First, you can choose to either update (add/subtract) or replace (overwrite) values.  Then, select which members are visible and enter a default value for each new record.</p>
<p>If your data is already in a spreadsheet, updates are even faster.  You can now upload a CSV file, or even paste data from Microsoft&reg; Excel&reg; into the site.  GoZuus will automatically identify which columns contain a name or e-mail address, and will prompt you to confirm the data before saving.  Header and summary rows are automatically ignored, and you can even export from QuickBooks&reg; and paste directly into GoZuus!<br />
<a href="http://www.gozuus.com/blog/wp-content/uploads/2009/05/statistics-upload.png"><img src="http://www.gozuus.com/blog/wp-content/uploads/2009/05/statistics-upload-430x270.png" alt="Statistics Upload Form" title="Statistics Upload Form" width="430" height="270" class="aligncenter size-medium wp-image-94" /></a></p>
<p><strong>Currency and Decimal Support</strong><br />
One frequent request was to provide an interface for listing account balances.  We&#8217;ve added support for currency symbols and decimal points to make this possible.  All records are now stored with decimal information, so you can also assign 1.5 hours for tasks.<br />
<a href="http://www.gozuus.com/blog/wp-content/uploads/2009/05/statistics-balance-report.png"><img src="http://www.gozuus.com/blog/wp-content/uploads/2009/05/statistics-balance-report-430x270.png" alt="Sample Balance Report" title="Sample Balance Report" width="430" height="270" class="aligncenter size-medium wp-image-95" /></a></p>
<p>It is worth mentioning that each statistic now has detailed permissions as well.  You can choose which groups of members can assign updates as well as who can see reports for other members.  For example, work hour reports might be visible to everyone in the group, while each member can only see their own account balance.</p>
<p><strong>Attendance and Tags</strong><br />
Several groups expressed interest in tracking attendance on the site, and we&#8217;re pleased to now support that as well.  The default Attendance statistic has tags for &#8220;Present&#8221;, &#8220;Excused&#8221; and &#8220;Unexcused&#8221; absences, and &#8220;Tardy&#8221; records.  We&#8217;re planning to integrate excuses into the calendar shortly, but for now it should be plenty easy to call roll right from the assignment page on your GoZuus site.</p>
<p><strong>Better Reports</strong><br />
Lastly, what good is all this data if you can&#8217;t generate meaningful reports?  Administrators (or all members if permission is granted) can view reports by user, or by update or event.  You can use this to print a list of all current account balances, or see the attendance records from any given meeting.  Reports can be reset at the beginning of each semester if desired, or can track a running lifetime total.<br />
<a href="http://www.gozuus.com/blog/wp-content/uploads/2009/05/statistics-attendance-report.png"><img src="http://www.gozuus.com/blog/wp-content/uploads/2009/05/statistics-attendance-report-430x395.png" alt="Sample Attendance Report" title="Sample Attendance Report" width="430" height="395" class="aligncenter size-medium wp-image-97" /></a></p>
<p>We&#8217;re thrilled to be offering this new functionality, and would like to thank our beta groups for providing great feedback to help drive this development.  We hope you enjoy these new features, and can&#8217;t want to see what other great uses you come up with for them!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gozuus.com/blog/2009/06/feature-update-statistics/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iCal Exports for Multi-day Events</title>
		<link>http://www.gozuus.com/blog/2009/02/ical-exports-for-multi-day-events/</link>
		<comments>http://www.gozuus.com/blog/2009/02/ical-exports-for-multi-day-events/#comments</comments>
		<pubDate>Thu, 05 Feb 2009 16:08:15 +0000</pubDate>
		<dc:creator>elliott</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[iCalendar]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://blog.gozuus.com/?p=21</guid>
		<description><![CDATA[One critical feature for GoZuus is to ensure that data is available not just within the site, but also portable in usable formats.  One obvious use of this is the group calendar.  We&#8217;ve built a nice online calendar, but we&#8217;re not out to replace Google Calendar or iCal or your iPhone.  Cleanly exporting data in [...]]]></description>
			<content:encoded><![CDATA[<p>One critical feature for GoZuus is to ensure that data is available not just within the site, but also portable in usable formats.  One obvious use of this is the group calendar.  We&#8217;ve built a nice online calendar, but we&#8217;re not out to replace Google Calendar or iCal or your iPhone.  Cleanly exporting data in iCalendar format lets us feed data into whatever scheduling application our users choose to embrace, so that their GoZuus calendar works where they want it.</p>
<p>There&#8217;s <a href="http://firstruby.wordpress.com/2007/12/10/ical-icalendar-publishing-through-rubyonrails/">plenty</a> of <a href="http://blog.milesbarr.com/2006/06/icalendar-and-rails/">resources</a> online discussing how easy it is to use the <a href="http://icalendar.rubyforge.org">Ruby Icalendar</a> library.  However, just following those directions didn&#8217;t produce quite the results I was looking for when exporting multi-day events.  Using the directions from the previous links, Apple&#8217;s iCal app displayed every event as ending one day early.  And Google Calendar put &#8220;(12:00am?)&#8221; in front of the titles.  Not exactly seamless integration.  A quick Google search didn&#8217;t turn up anything useful, so hopefully this solution will save someone else some time.<br />
<span id="more-21"></span><br />
The first one is easy.  If you dive into <a href="http://www.ietf.org/rfc/rfc2445.txt">RFC2445</a>, section 4.8.2.2 states that the <code>DTEND</code> parameter &#8220;defines the date and time <em>by which</em> the event ends.&#8221;  That&#8217;s an up-to-but-not-including statement.  If an event starts Feb 2 and ends Feb 5, then that means the event is over <em>by</em> Feb 5, and it displays as occupying only Feb 2, 3, and 4.  This is different than our model, where we define the end date to be included.  (That made more sense to me – most users who enter &#8220;Feb 2-5&#8243; are describing a four day event.)  The solution here is just to use <code>event.end_on.advance(:days =&gt; 1)</code> to push it one day forward.</p>
<p>The second one is a little more difficult.  Google&#8217;s iCal parser interprets all <code>DTSTART</code> and <code>DTEND</code> values as times unless specifically told otherwise.  If you look at the output from the Icalendar library, it lists dates and date/times as:</p>
<pre>    DTSTART:20090205
    DTSTART:20090205T083000</pre>
<p>That&#8217;s valid, but according to the RFC you can add an additional parameter in there to specify what type of value you&#8217;re providing.  This looks like:</p>
<pre>    DTSTART;VALUE=DATE:20090205
    DTSTART;VALUE=DATE-TIME:20090205T083000</pre>
<p>I couldn&#8217;t find any documentation for how to do this with the Icalendar library, so I began digging into the source for Icalendar&#8217;s component.rb.  Turns out there&#8217;s a function called <code>print_parameters(val)</code> that is called during generation, and that it prints these pairs from hash called <code>val.ical_params</code>.  So if you assign <code>event.start.ical_params = {'VALUE' =&gt; 'DATE'}</code>, the Icalendar library will add in these additional descriptors.  Seems to be undocumented, but it works for me.</p>
<p>Note that since <code>ical_params</code> is a parameter of the object itself, you can only assign this hash after you&#8217;ve assigned the object itself.  Also, it didn&#8217;t seem to work for me when the value I had assigned was a <code>String</code>.  It did work when I assigned a <code>Date</code> or <code>DateTime</code> object directly.</p>
<p>All in all, our <code>Event#to_ical</code> looks like this:</p>
<pre class="brush: ruby;">def to_ical
  ical = Icalendar::Event.new
  if self.multi_day? || self.all_day?
    ical.start = self.start_on
    ical.start.ical_params = {'VALUE' =&gt; 'DATE'}
  else
    ical.start = self.start_at
    ical.start.ical_params = {'VALUE' =&gt; 'DATE-TIME'}
  end
  if self.multi_day?
    ical.end = self.end_on.advance(:days =&gt; 1)
    ical.end.ical_params = {'VALUE' =&gt; 'DATE'}
  end
  ical.summary = self.name
  ical.description = self.details
  ical.uid = &quot;#{self.id}@gozuus&quot;
  ical.created = self.created_at.utc
  ical.last_modified = self.updated_at.utc
  return ical
end</pre>
<p>For completeness, here&#8217;s the output portion of our controller action:</p>
<pre class="brush: ruby;">
format.ics do
  @ical = Icalendar::Calendar.new
  @events.each { |event| @ical.add event.to_ical }
  @ical.publish
  render :text =&gt; @ical.to_ical, :layout =&gt; false
end
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.gozuus.com/blog/2009/02/ical-exports-for-multi-day-events/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
