Archive for the 'Programming' Category

Paper on DataMill

Nov 24 2015 Published by under Courses,Programming

The manuscript for the journal paper that I co-authored has been accepted for Software: Practice and Experience. The paper is titled DataMill: A Distributed Heterogeneous Infrastructure for Robust Experimentation and describes the second version of DataMill, a performance evaluation infrastructure, that I helped to build.

No responses yet

Merge Tags with django-taggit

Jan 01 2015 Published by under Fiddle Salad,Programming,Python Fiddle

Today I cleaned up the database for Fiddle Salad and Python Fiddle. Both use the same Django back-end for code storage. While browsing tags, I noticed that often both CamelCase and lowercase spellings were used for tags. Since I was working on a tag suggest feature earlier this week, I decided to convert all tags to lowercase so that tag suggestions would not be redundant. An additional benefit is further normalization of the data. Fortunately, I found a fork of django-taggit, the Django app I used for tagging, that supported enforcing lowercase tags everywhere. Two management commands were already present for normalizing data, mergetags and lowercasetags. django-taggit had two fields for each tag, a name and slug. lowercasetags converted all tag names to their lowercase form. mergetags takes at least two tag slugs and merges all tags into a single destination tag. The result is that all associations are moved to a single tag. While mergetags is suitable for manually resolving redundant data, the number of tags on Fiddle Salad is too large. I wrote an command to automate this process:

from django.core.management.base import BaseCommand, CommandError
from taggit.models import Tag, TaggedItem
from django.core.exceptions import ObjectDoesNotExist

class Command(BaseCommand):
    help = 'merges all tags automatically'

    def merge(self, extra_slugs, dest_slug):
        try:
            dest_tag = Tag.objects.get(slug=dest_slug)
        except ObjectDoesNotExist:
            raise CommandError('Destination Tag "%s" does not exist' % dest_slug)

        for slug in extra_slugs:
            try:
                tag = Tag.objects.get(slug=slug)
            except ObjectDoesNotExist:
                raise CommandError('Tag "%s" does not exist' % slug)

            items = TaggedItem.objects.filter(tag=tag)
            count = items.count()
            for i, item in enumerate(items):
                if i % 20 == 0:
                    self.stdout.write('Merging %s %d/%d\n' % (slug, i+1, count))
                obj = item.content_object
                if not obj:
                    return
                obj.tags.remove(tag)
                obj.tags.add(dest_tag)
            tag.delete()

            self.stdout.write('Successfully merged tags into "%s"\n' % dest_slug)


    def handle(self, *args, **options):
        for tag in Tag.objects.all():
            if Tag.objects.filter(name=tag.name).count() > 1:
                tags = Tag.objects.filter(name=tag.name).order_by('id')
                dest = tags[0].slug
                extras = []
                for tag in tags[1::]:
                    extras.append(tag.slug)
                self.merge(extras, dest)

Because performance is not a concern for a single-time data processing script, I did not bother to optimize the queries nor run-time. This script would be useful for anyone who wants to normalize tags in the same manner, so it is in a git repository. Finally, I tested the new command on a clone of the production database.

bash-4.1$ python manage.py lowercasetags
Lowercasing 1/1621
Lowercasing 21/1621
.
.
.
Lowercasing 1621/1621
bash-4.1$ python manage.py mergealltags
Merging jquery_1 1/46
Merging jquery_1 21/46
Merging jquery_1 41/46
Successfully merged tags into "jquery"
Successfully merged tags into "jquery"
Merging stylus_1 1/7
Successfully merged tags into "stylus"
Merging hello_1 1/10
Successfully merged tags into "hello"
Merging test_1 1/147
Merging test_1 21/147
Merging test_1 41/147
Merging test_1 61/147
Merging test_1 81/147
Merging test_1 101/147
Merging test_1 121/147
Merging test_1 141/147
Successfully merged tags into "test"
Merging me_1 1/2
Successfully merged tags into "me"
Merging no_1 1/5
Successfully merged tags into "no"
Merging one_1 1/16
Successfully merged tags into "one"
Merging things_1 1/3
Successfully merged tags into "things"
Merging learning_1 1/4
Successfully merged tags into "learning"
Successfully merged tags into "body"
Merging week-one_1 1/1
Successfully merged tags into "week-one"
Merging studio_1 1/33
Merging studio_1 21/33
Successfully merged tags into "studio"
Merging internet_1 1/36
Merging internet_1 21/36
Successfully merged tags into "internet"
Merging assignment_1 1/6
Successfully merged tags into "assignment"
Merging homework_1 1/6
Successfully merged tags into "homework"
Merging lessons_1 1/1
Successfully merged tags into "lessons"
Merging code_1 1/12
Merging tags_1 1/7
Successfully merged tags into "tags"
Merging two_1 1/6
Successfully merged tags into "two"
Merging salcedo_1 1/3
Successfully merged tags into "salcedo"
Merging page_1 1/15
Successfully merged tags into "page"
Merging music_1 1/4
Successfully merged tags into "music"
Merging table_1 1/7
Successfully merged tags into "table"
Merging band_1 1/9
Merging texas_1 1/1
Successfully merged tags into "texas"
Merging biography_1 1/2
Merging assignment-two_1 1/2
Successfully merged tags into "assignment-two"
Merging website_1 1/9
Merging a_1 1/2
Successfully merged tags into "a"
Merging words_1 1/1
Successfully merged tags into "words"
Merging section_1 1/2
Successfully merged tags into "section"
Merging header_1 1/1
Successfully merged tags into "header"
Merging ui_1 1/4
Successfully merged tags into "ui"
Merging first_1 1/8
Successfully merged tags into "first"
Merging random_1 1/1
Successfully merged tags into "random"
Merging internet-studio_1 1/5
Successfully merged tags into "internet-studio"
Merging angularjs_1 1/11
Successfully merged tags into "angularjs"
Merging i_1 1/2
Successfully merged tags into "i"
Merging lines_1 1/1
Successfully merged tags into "lines"
Merging row_1 1/1
Successfully merged tags into "row"
Merging alex-alpha_1 1/1
Successfully merged tags into "alex-alpha"
Merging assignment-one_1 1/2
Successfully merged tags into "assignment-one"
Merging google_1 1/1
Successfully merged tags into "google"
Merging man_1 1/4
Successfully merged tags into "man"
Merging nick_1 1/1
Successfully merged tags into "nick"
Merging cartoon_1 1/1
Successfully merged tags into "cartoon"
Merging batman_1 1/2
Successfully merged tags into "batman"
Merging code_1 1/7
Merging the_1 1/1
Successfully merged tags into "the"
Merging animation_1 1/2
Successfully merged tags into "animation"
Merging band_1 1/4
Merging assignment-one-of-three_1 1/2
Successfully merged tags into "assignment-one-of-three"
Merging status_1 1/1
Successfully merged tags into "status"
Merging python_1 1/2
Successfully merged tags into "python"
Merging cat_1 1/1
Successfully merged tags into "cat"
Merging none_1 1/7
Successfully merged tags into "none"
Merging adam_1 1/2
Successfully merged tags into "adam"
Merging school_1 1/3
Successfully merged tags into "school"
Merging website_1 1/9
Merging biography_1 1/2
Merging bootstrap_1 1/8
Successfully merged tags into "bootstrap"
Merging datamill_1 1/5
Successfully merged tags into "datamill"
Merging gentoo_1 1/2
Successfully merged tags into "gentoo"
Merging dobschal_1 1/1
Successfully merged tags into "dobschal"
Merging weimar_1 1/1
Successfully merged tags into "weimar"

When all went fine, I ran lowercasetags and mergealltags on both Fiddle Salad and Python Fiddle. Now I was really impressed with the results as I clicked through the tags on both sites. The tags on Fiddle Salad were much better organized as they were ordered by popularity. While looking through the tags, I noticed that “test” was among the top. I decided to add ‘test’ to the list of stopwords for django-taggit. These stopwords are removed during save so that they are not associated with new snippets.
Now that the tags are normalized, I am ready to move on and deploy tag suggestions.

One response so far

Course Planner Prerequisite Parsing Fixes

Nov 24 2013 Published by under CourseTree,Programming

One of the bugs still in the Waterloo Course Planner is the handling of prerequisite sentences that end with “* students only.”. The fix I made was rather simple. Though converting existing test cases to unit tests did not help because none of the older grammar rules were changed and therefore the tests were not broken, it did help in the development of new grammar rules. Python unit tests does a nice job of pinpointing the exact place where the expected results differ from running the code.

Failure
Traceback (most recent call last):
  File "N:\Projects\ply\prereqyacc.py", line 182, in testQuirks
    self.assertEqual(results, map(parser.parse, prereqs))
AssertionError: Lists differ: ['MATH 127/MATH 128/MATH 137/M... != ['MATH 127/MATH 128/MATH 137/M...

First differing element 1:
MATH 115/MATH 119
MATH 115, MATH 119

- ['MATH 127/MATH 128/MATH 137/MATH 147', 'MATH 115/MATH 119']
?                                                  ^

+ ['MATH 127/MATH 128/MATH 137/MATH 147', 'MATH 115, MATH 119']
?                                                  ^^

“* students only.” appearing in a string results in the tokenizer printing out a list of invalid tokens. There are two ways of ignoring strings in PLY:

  1.  t_ignore_ in the tokenizer
  2. change t_ignore_ to a token and add a new rule that returns an empty string in the parser

I used the second method this time, since the semicolon preceding “* students only.” would also need to be ignored. Semicolons are treated as a signal for an “and” clause otherwise. The new rule looks like the following:

def p_restriction(p):
    'semi_restriction : SEMI STUDENTS_ONLY'
    p[0] = ''

No responses yet

Coding in Python in the Browser

Nov 20 2013 Published by under Python Fiddle

I made this video in the summer and Python Fiddle back in 2010. It is still the best Python IDE on the web running in a browser. So here is a demo if you’re new to Python:

No responses yet

Course Planner Book Links and Share Bar

Nov 17 2013 Published by under CourseTree

First up on the list is the bad news: the old share bar is permanently gone as Google has shut it down. That’s right! Google has shut down a competitor’s service after buying it. At least the meebo team is honest and left us a message:

Meebo was acquired by Google on June 4, 2012.

Our team is now working just a few miles down the road with the Google+ team, where we continue to focus on creating delightful experiences for our users, developers, and publishers.

Meebo’s products are no longer available, but you can find all the latest and greatest things that we’re working on at https://developers.google.com/+/.

Thanks,
The Meebo Team

Elsewhere on the internet, you can find news reports about the shutdown. That gives credence to the “Google is Evil” motto.

On the course explorer side, there has recently been a change to Amazon’s Ecommerce API, breaking code for getting book titles and URLs that I wrote several years ago. Basically, most of the responses returned changed from single item ones to

<?xml version="1.0"?>
<ItemLookupResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
<OperationRequest>
    <RequestId>cd6bd87d-046c-4a07-a99e-16fc600ebe31</RequestId>
    <Arguments>
        <Argument Name="Operation" Value="ItemLookup"/>
        <Argument Name="Service" Value="AWSECommerceService"/>
        <Argument Name="AssociateTag" Value="yuguzhan-20"/>
        <Argument Name="SearchIndex" Value="Books"/>
        <Argument Name="Signature" Value="a6ZCkXLOYFw8xTYH8gaBl/K5YGeTlQdGxtDKwY2YuaU="/>
        <Argument Name="ItemId" Value="9780470392164"/>
        <Argument Name="IdType" Value="ISBN"/>
        <Argument Name="AWSAccessKeyId" Value="AKIAIZLBWTLA3LJJZ2MA"/>
        <Argument Name="Timestamp" Value="2013-11-17T19:21:08.000Z"/>
    </Arguments>
    <RequestProcessingTime>0.0220990000000000</RequestProcessingTime>
</OperationRequest>
<Items>
    <Request>
        <IsValid>True</IsValid>
        <ItemLookupRequest>
            <IdType>ISBN</IdType>
            <ItemId>9780470392164</ItemId>
            <ResponseGroup>Small</ResponseGroup>
            <SearchIndex>Books</SearchIndex>
            <VariationPage>All</VariationPage>
        </ItemLookupRequest>
    </Request>
    <Item>
        <ASIN>0470392169</ASIN>
        <DetailPageURL>http://www.amazon.ca/How-Read-Proofs-Introduction-Mathematical/dp/0470392169%3FSubscriptionId%3DAKIAIZLBWTLA3LJJZ2MA%26tag%3Dyuguzhan-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D0470392169</DetailPageURL>
        <ItemLinks>
            <ItemLink>
                <Description>Add To Wishlist</Description>
                <URL>http://www.amazon.ca/gp/registry/wishlist/add-item.html%3Fasin.0%3D0470392169%26SubscriptionId%3DAKIAIZLBWTLA3LJJZ2MA%26tag%3Dyuguzhan-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386005%26creativeASIN%3D0470392169</URL>
            </ItemLink>
            <ItemLink>
                <Description>Tell A Friend</Description>
                <URL>http://www.amazon.ca/gp/pdp/taf/0470392169%3FSubscriptionId%3DAKIAIZLBWTLA3LJJZ2MA%26tag%3Dyuguzhan-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386005%26creativeASIN%3D0470392169</URL>
            </ItemLink>
            <ItemLink>
                <Description>All Customer Reviews</Description>
                <URL>http://www.amazon.ca/review/product/0470392169%3FSubscriptionId%3DAKIAIZLBWTLA3LJJZ2MA%26tag%3Dyuguzhan-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386005%26creativeASIN%3D0470392169</URL>
            </ItemLink>
            <ItemLink>
                <Description>All Offers</Description>
                <URL>http://www.amazon.ca/gp/offer-listing/0470392169%3FSubscriptionId%3DAKIAIZLBWTLA3LJJZ2MA%26tag%3Dyuguzhan-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386005%26creativeASIN%3D0470392169</URL>
            </ItemLink>
        </ItemLinks>
        <ItemAttributes>
            <Author>Daniel Solow</Author>
            <Manufacturer>Wiley</Manufacturer>
            <ProductGroup>Book</ProductGroup>
            <Title>How to Read and Do Proofs: An Introduction to Mathematical Thought Processes</Title>
        </ItemAttributes>
    </Item>
</Items>
</ItemLookupResponse>

to multiple item ones

<?xml version="1.0"?>
<ItemLookupResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
<OperationRequest>
    <RequestId>cc114a2f-75e9-419a-81a4-fc7e98f6df13</RequestId>
    <Arguments>
        <Argument Name="Service" Value="AWSECommerceService"/>
        <Argument Name="Operation" Value="ItemLookup"/>
        <Argument Name="Signature" Value="cfstltrmlmtQHrzz5s9t130uhLWZFG3Y7It9EqBQ/pA="/>
        <Argument Name="AssociateTag" Value="yuguzhan-20"/>
        <Argument Name="ItemId" Value="9780201350883"/>
        <Argument Name="IdType" Value="ISBN"/>
        <Argument Name="AWSAccessKeyId" Value="AKIAIZLBWTLA3LJJZ2MA"/>
        <Argument Name="Timestamp" Value="2013-11-17T19:19:46.000Z"/>
        <Argument Name="SearchIndex" Value="Books"/>
    </Arguments>
    <RequestProcessingTime>0.0407320000000000</RequestProcessingTime>
</OperationRequest>
<Items>
    <Request>
        <IsValid>True</IsValid>
        <ItemLookupRequest>
            <IdType>ISBN</IdType>
            <ItemId>9780201350883</ItemId>
            <ResponseGroup>Small</ResponseGroup>
            <SearchIndex>Books</SearchIndex>
            <VariationPage>All</VariationPage>
        </ItemLookupRequest>
    </Request>
    <Item>
        <ASIN>0201350882</ASIN>
        <DetailPageURL>http://www.amazon.ca/Algorithms-Parts-1-4-Fundamentals-Structure/dp/0201350882%3FSubscriptionId%3DAKIAIZLBWTLA3LJJZ2MA%26tag%3Dyuguzhan-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D0201350882</DetailPageURL>
        <ItemLinks>
            <ItemLink>
                <Description>Add To Wishlist</Description>
                <URL>http://www.amazon.ca/gp/registry/wishlist/add-item.html%3Fasin.0%3D0201350882%26SubscriptionId%3DAKIAIZLBWTLA3LJJZ2MA%26tag%3Dyuguzhan-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386005%26creativeASIN%3D0201350882</URL>
            </ItemLink>
            <ItemLink>
                <Description>Tell A Friend</Description>
                <URL>http://www.amazon.ca/gp/pdp/taf/0201350882%3FSubscriptionId%3DAKIAIZLBWTLA3LJJZ2MA%26tag%3Dyuguzhan-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386005%26creativeASIN%3D0201350882</URL>
            </ItemLink>
            <ItemLink>
                <Description>All Customer Reviews</Description>
                <URL>http://www.amazon.ca/review/product/0201350882%3FSubscriptionId%3DAKIAIZLBWTLA3LJJZ2MA%26tag%3Dyuguzhan-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386005%26creativeASIN%3D0201350882</URL>
            </ItemLink>
            <ItemLink>
                <Description>All Offers</Description>
                <URL>http://www.amazon.ca/gp/offer-listing/0201350882%3FSubscriptionId%3DAKIAIZLBWTLA3LJJZ2MA%26tag%3Dyuguzhan-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386005%26creativeASIN%3D0201350882</URL>
            </ItemLink>
        </ItemLinks>
        <ItemAttributes>
            <Author>Robert Sedgewick</Author>
            <Manufacturer>Addison-Wesley Professional</Manufacturer>
            <ProductGroup>Book</ProductGroup>
            <Title>Algorithms in C++, Parts 1-4: Fundamentals, Data Structure, Sorting, Searching (3rd Edition)</Title>
        </ItemAttributes>
    </Item>
    <Item>
        <ASIN>B001FWIJFA</ASIN>
        <DetailPageURL>http://www.amazon.ca/Algorithms-Parts-1-4-Fundamentals-Structure-ebook/dp/B001FWIJFA%3FSubscriptionId%3DAKIAIZLBWTLA3LJJZ2MA%26tag%3Dyuguzhan-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3DB001FWIJFA</DetailPageURL>
        <ItemLinks>
            <ItemLink>
                <Description>Add To Wishlist</Description>
                <URL>http://www.amazon.ca/gp/registry/wishlist/add-item.html%3Fasin.0%3DB001FWIJFA%26SubscriptionId%3DAKIAIZLBWTLA3LJJZ2MA%26tag%3Dyuguzhan-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386005%26creativeASIN%3DB001FWIJFA</URL>
            </ItemLink>
            <ItemLink>
                <Description>Tell A Friend</Description>
                <URL>http://www.amazon.ca/gp/pdp/taf/B001FWIJFA%3FSubscriptionId%3DAKIAIZLBWTLA3LJJZ2MA%26tag%3Dyuguzhan-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386005%26creativeASIN%3DB001FWIJFA</URL>
            </ItemLink>
            <ItemLink>
                <Description>All Customer Reviews</Description>
                <URL>http://www.amazon.ca/review/product/B001FWIJFA%3FSubscriptionId%3DAKIAIZLBWTLA3LJJZ2MA%26tag%3Dyuguzhan-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386005%26creativeASIN%3DB001FWIJFA</URL>
            </ItemLink>
            <ItemLink>
                <Description>All Offers</Description>
                <URL>http://www.amazon.ca/gp/offer-listing/B001FWIJFA%3FSubscriptionId%3DAKIAIZLBWTLA3LJJZ2MA%26tag%3Dyuguzhan-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386005%26creativeASIN%3DB001FWIJFA</URL>
            </ItemLink>
        </ItemLinks>
        <ItemAttributes>
            <Author>Robert Sedgewick</Author>
            <Manufacturer>Addison-Wesley Professional</Manufacturer>
            <ProductGroup>eBooks</ProductGroup>
            <Title>Algorithms in C++, Parts 1-4: Fundamentals, Data Structure, Sorting, Searching (3rd Edition)</Title>
        </ItemAttributes>
    </Item>
</Items>
</ItemLookupResponse>

As with many of these bugs, they are easy to fix once cause of the problem is found. If you know XML, an exercise for you is to spot the difference between the top one and the bottom one.

No responses yet

Too Lazy to Click: A Decline in Traffic with a Tips Panel

Oct 17 2013 Published by under Fiddle Salad,Programming

After launching the a new tips panel on Fiddle Salad that shows on top of other dialog windows whenever a fiddle is opened, I found a decline in traffic. Specifically, page views decreased. Does that mean the tips were poorly done? To investigate, I compared the views in the past 30 days to the previous period and looked at the traffic for different pages. The top pages ranked by page view saw an increase in ratio compared to the rest. My hypothesis is that when opening a saved fiddle, users were deterred by the tip panel that opened. I found the data to back up the hypothesis.
google analytics traffic
The analysis is that there were 0 visitors to the pages in the past 30 days because they just didn’t bother to check off “Show tips on startup”. This made sense, as the tips panel often blocked pieces of code. My plan is to just show the tips panel once a day so that opening saved fiddles wouldn’t show it.

Update:
I found out that the new tab page in Chrome stable was changed, removing the apps. This would explain the decline in traffic on the CoffeeScript IDE page. This change has been there for 4 months on the Chrome beta channel that I use on Windows.

No responses yet

Building UIs with Wijmo

Oct 11 2013 Published by under Coincidences,Life,Programming,Uncategorized

Right after I finished my classes at Waterloo, I started writing my book on Wijmo. Wijmo is an advanced widget library based on jQuery UI, which is the most popular UI toolkit in the community. The preface to my book explains what the book is about:

Wijmo is a new JavaScript library focusing on user interface widgets. It builds on jQuery UI, enhancing existing widgets, and adding new ones. In this book we examine the Wijmo widgets essential for web development. The useful configuration options for 15 widgets are covered along with their usage scenarios. Most of the chapters take a code recipe approach for tasks that occur often in web development. Whenever you come across a widget or user interface component that you’ve implemented before, chances are that Wijmo widgets have you covered. The chapters in this book are designed to get you started using the widgets in no time. On the other hand, Chapter 6, Dashboard with Wijmo Grid, takes a different approach in building an application and explaining how it works.

I would recommend buying this book if you’ve already purchased a license for Wijmo or you plan to be using Wijmo for development. On my project at work and while writing this book, I have used Wijmo in combination with Knockout to put together UIs.
Wijmo book cover
Building UIs With Wijmo was just published last month. I was originally contacted by the publisher to write the book because I had used Wijmo on one of my Github projects. The best thing is one favourite pet project leads to another. I will save that for another post, but for now there is a contest running on Fiddle Salad if you want a free copy.

5 responses so far

Using Encapsulation to Make an Awesome Angular JS Editor in Fiddle Salad

Sep 26 2013 Published by under Fiddle Salad,Programming

Angular JS is a popular MVC framework by Google, and I received a bug report that Fiddle Salad wouldn’t reload the preview as it does in all other cases. This problem was noticed before, but it wasn’t a priority since pressing the refresh button as required in all other web development methods solves the problem. However, this was because I was attempting to solve it at the wrong level by modifying a method. As I’ve learned, there are dependencies between the execute, reset, and initiation of the class involved.

Fiddle Salad’s CodeRunner class has just 5 public methods. They are

  • execute()
  • add_file()
  • remove_css()
  • reset()
  • debug()

as in the class diagram on the wiki at https://github.com/yuguang/fiddlesalad/wiki/2.-Classes. Therefore, any implementation of a CodeRunner just needs to support these 5 methods. The debug method could be refactored into a super class because it would generate the template for the new execute() method.

debug: ->
  ###
  Debug opens a new window with the code loaded in the page. External CSS and JS files are loaded through head tags.
  It assumes all external resources are stored in the view model.
  ###

  template =
    css: _.template '<link rel="stylesheet" type="text/css" href="<%= source %>" />'
    js: _.template '<script type="text/javascript" src="<%= source %>"></script>'
    html: _.template """
          <!DOCTYPE html>
          <html>
            <head>
              <title>Fiddle Salad Debug View</title>
              <script src="http://leaverou.github.com/prefixfree/prefixfree.min.js"></script>
              <style>
                <%= css %>
              </style>
            </head>
            <body>
              <%= body %>
              <%= headtags %>
              <script type="text/javascript">
                <%= javascript %>
              </script>
            </body>
          </html>
          """

  # initialize array of head tags
  headTags = new Array
  # for each external resource in view model
  _.each viewModel.resources(), (resource) =>
    # get the file type of the resource, call mapped template with resource, and append generated HTML to head tags
    headTags.push template[@filetype resource.source()](source: resource.source())
  headtags = headTags.join('')
  # get JavaScript and CSS code from the engine
  javascript = engine.get_code LANGUAGE_TYPE.COMPILED_PROGRAM
  body = engine.get_code LANGUAGE_TYPE.COMPILED_DOCUMENT
  css = engine.get_code LANGUAGE_TYPE.COMPILED_STYLE
  # call the template for the window with the head tags and code
  html = template.html {javascript, css, body, headtags}
  # open window with generated HTML
  window.open = 'data:text/html;charset=utf-8,' + encodeURIComponent(html)

If I just change the last line, the debug method turns into a reset method.

@window.location = 'data:text/html;charset=utf-8,' + encodeURIComponent(html)

The rest of the class still needs to be completed, but they are as obvious as appending to an array when adding JS/CSS files.

No responses yet

Show tips on startup in 4 lines of code

Aug 17 2013 Published by under Fiddle Salad,Programming

Fiddle Salad has accumulated many features, but where are they? In keeping with one of its principles, features are hidden until the situation calls for them. One example is the JavaScript errors that are shown on hover over the results window. Recently, I’ve decided showing an unobtrusive tips window is as good as hiding features to reduce UI clutter. So, let’s start with 4 lines of Knockout code.

TipsPanel = ->
  @startup = ko.observable(not store.get('hideTipsOnStartup'))
  @startup.subscribe((checked) ->
    store.set('hideTipsOnStartup', not checked)
  )

I start by setting startup to a storage value using store.js. It uses HTML5 local storage with cookies for fallback. Since I want to show the tips panel by default and hideTipsOnStartup would not be set, startup is set to the opposite hideTipsOnStartup. JavaScript’s ! and CoffeeScript’s not casts an expression to a boolean, as required by Knockout’s checked binding.
Next, I add a manual subscription to the observable so that its value is stored each time the checkbox is checked or unchecked.
Finally, the checkbox is bound to tips.startup where tips is a TipsPanel instance.

<label><input data-bind="checked: $root.tips.startup" type="checkbox"/> Show tips on startup</label>

No responses yet

Grabbing a Share of the Pie – Marketing Fiddle Salad Correctly

Aug 01 2013 Published by under Fiddle Salad,Programming

The idea of running Fiddle Salad came in a weird way. At first, I was just making a Python to JavaScript compiler and putting it on a website. It was simple enough, as the compiler was already built for it. The back-end for saving and authentication through Google, Twitter, and Facebook used the same one as Python Fiddle. After the site was launched, I noticed that not many people were interested in writing Python. Also, I got a taste of CoffeeScript, which is now my favorite language.

I think the demise of the Python-only fiddle came as a combination of low traffic and no saves. If nobody ever sees it or uses it, then it is better gone. Fortunately, I had the chance to design and develop the next generation of Fiddle Salad to support other languages.

6067OT_3_13

The real Fiddle Salad was launched in April of 2012. I remembered calling the previous version Python Fiddle. Last January, I decided to do an experiment with the CoffeeScript page by creating a separate app in the Chrome App Store. It turned out to double my number of daily visitors. Last May, it was featured on Lifehacker as one of the best apps for development. So why not do it again?

I waited until the right time. Last month and the previous one, the project received major updates which I will be discussing on the Fiddle Salad blog. Meanwhile, I published more apps in the Chrome App Store.

The difference now is that instead of an app supporting more features that show up in searches, I’ve limited the features that are marketed. This way it targets specific audiences. JavaScript programmers don’t want to find out about the features built for CoffeeScript, and a programmer looking for a CoffeeScript IDE won’t bother with an app that doesn’t have CoffeeScript in the title.

 

No responses yet

Next »