Monday, October 26, 2015

Making booklets

Our newspaper kids wanted to make a mini-booklet-style 5.5x4.25" newspaper made of simple 8.5x11" sheets of paper folded.

To do the layout properly with nice 2-page spreads etc., we set the papersize in our software to 5.5"x4.25", but that then raises the problem of how to properly print it out on copy paper so it folds neatly.

After much searching, I found a useful post which has just the instructions I needed -- here is a shellscript to implement the solution with my own variants:

echo Converting to postscript
pdf2ps $1 working_file.ps
echo Rotating pages
pstops -w 4.25in -h 5.5in 8:7\(0.0in,0.01in\),0\(0.0in,0.01in\),4U\(4.25in,5.50in\),3U\(4.25in,5.50in\),1\(0.0in,0.01in\),6\(0.0in,0.01in\),2U\(4.25in,5.50in\),5U\(4.25in,5.50in\) working_file.ps working_ordered.ps
echo Putting 4 to a page
psnup -4 -s1 working_ordered.ps output.ps
echo Outputting to PDF
filename=$1
filename="${filename%.*}"
ps2pdf output.ps $filename.bookematized.pdf
echo "Done. Output in: $filename.bookematized.pdf"

The magic is in that pstops line with the page order and the flipping of the appropriate pages. The psnup line just slaps four pages onto a page, which is simple enough.

Since my pages were appropriately formatted, I used the -s1 command to prevent psnup from scaling. If you wanted to take e.g. 4 8.5x11 pages and shrink them to fit on 4.25x5.5, you could do it by adjusting the paper sizes in the pstops line and then removing the -s1 line (that's what the original code I copied does, more or less -- so just start there).




Monday, December 8, 2014

Google Classroom: Top 5 Fixes I'd like to see before I sign up for a second semester

This semester, I took on a new role as director of instructional technology just as google released a new tool: google classroom. Given how thoroughly google-dependent our school already is, I thought it was a natural fit and signed myself and my students up for a semester of piloting google classroom. Here's what I've found.

Google Classroom is close to being great. When I compare the user interface of google classroom to the user interface of our school's online gradebook, it's an object lesson in UI design. Where our gradebook is byzantine, slow, and opaque, Google classroom is simple, smooth, and clear.

That said, google classroom gets details wrong, and it gets them wrong in ways that matter. More importantly, for reasons I can't quite comprehend, google seemed to stop short of making classroom a full-blown powertool on the level of its other google apps.

As it is, I'm unlikely to use classroom for another semester; I do better with my own cobbled together system using a range of scripts + docs +mail + calendar to get things done.

Here's the top 5 fixes I'd like to see before I commit to classroom for another semester:

#5. Allow collaboration everywhere. The killer feature of google docs is collaboration. Remember the days of editing a shared word doc on a server and being locked out while a colleague edits? Yeah, that was awful; google's real-time collaboration + revision history is awesome. How ironic then that google classroom makes no convenient way to assign small group projects or work with coteachers.

#4. Allow multi-step assignments. Good teachers use google classroom to help students draft, revise, collaborate, re-draft, copy-edit and, finally, publish work. When I was in grad school, I couldn't have dreamed of tools as good as google docs for teaching the writing process.

Alas, google classroom makes it easy to create an assignment with a single due date, but leaves me hanging if I want to have a multi-step assignment (brainstorm due to share with a team on one day, a draft due for feedback a week later, and a final draft due a week after that). Classroom only allows associating a single due date with an assignment and has no way to carry docs from one assignment automatically over into a new one.

It is possible to have an assignment go back and forth between teacher and student multiple times using "resubmit" and "hand back," which is what I've done, but my students complain that it's hard to keep track of due dates for revision this way, and they're right.

#3 Fix the assignment view in google drive for teachers: When you're grading a virtual stack of papers, little details matter, and google gets most of them wrong.

First, there's no easy way to sort documents by student first or last name, which is usually how they're listed in a gradebook. Second, if students attach files of their own, they don't get renamed with their name in the title. Third, if students hand in multiple files, they don't get grouped together in any way.

In my pre-google-classroom life, I had a folder for each class and each student had a single folder named last-name, first-name. This made it trivial to go down a class list and check work. Google classroom gives me nothing as easy.

If you have multi-document projects, like the one I'm grading right now, it can be a nightmare simply sorting out which document came from who (this is made worse by the ownership problem -- I can't sort the files by owner because the owner is me in all cases once the student's have handed the work in).
  
#2. Fix the broken ownership model. Google classroom has students own documents until they get turned in; then teachers own them until they hand them back. And so on. Teachers should be co-owners of the documents from the beginning.

Lacking ownership means no ability to access revision history until an assignment is turned in, which robs me of one of google docs greatest powers in the classroom.  (Think of this simple scenario: I'm about to conference with a student who has been "writing" in my class for the last 40 minutes. Before I move over to their desk to talk, I'd like to take a look at what they've produced -- under a traditional doctopus or shared-folder model with shared ownership, I can peek at revision history and see exactly what they've done with their 40 minutes of classroom; with the google classroom ownership model, I've got nothing).  

#1. Create a scripting API: the beauty of classroom is its simplicity, so I don't really expect google to get everything right. There's no way they can handle all the different ways teachers assess (rubrics, standards-based, point-based, etc. etc.), or the different features we might want to implement (group work, multi-stage work, models, and on). It's easy to see that if they do implement all these features, they'll quickly lose the elegance that is one of the main features of classroom to begin with.

The solution? Add-ons. Writing custom scripts for docs and sheets is a breeze and a boon for schools. Releasing classroom without an API for scripting stands in the way of educators who want to really get a hold of it and make it work for real schools. Google can't hope to get this right for all of us, but they can give us the power to do it ourselves. Once they do so, an ecosystem of hacker educators will spring up to make creative uses of classroom google never imagined. Until they do so, we're all left sitting on our hands, meekly hoping that google will deign to implement our next feature request.

Monday, October 6, 2014

Four Freedoms

Updating our wordpress based newspaper site, I saw that wordpress prominently includes the 4 key freedoms in their "about" page. They are:
  1. You have the freedom to run the program, for any purpose.
  2. You have access to the source code, the freedom to study how the program works, and the freedom to change it to make it do what you wish.
  3. You have the freedom to redistribute copies of the original program so you can help your neighbor.
  4. You have the freedom to distribute copies of your modified versions to others. By doing this you can give the whole community a chance to benefit from your changes.
This strikes me as a reasonable starting point for any public institution, including ours, which seeks to inculcate students with feelings of curiosity, ownership, and empowerment around computers.

It's a useful reminder that free as in freedom is different and more important than free as in free of cost. How ironic that the principle reason we don't use free software at our school is that google has made is so extraordinarily convenient to use their own free-as-in-beer closed-source solutions in schools. While key tools like chrome are open source and while Google does make API's available for many aspects of their apps suite that make tinkering with docs/sites/etc. not just do-able but often fun, I find the exercise of just re-reading the basic software freedoms to be a sobering one.

I wonder, in the face of good free-as-in-beer enterprise software from google, are there any schools out there working to give students their software freedoms? Making the switch from a Microsoft infrastructure to a Google one seems like a no-brainer (lower cost, greater functionality), but it strikes me that the ease of that switch may have made a switch to a truly open infrastructure a non-starter.

Creating digital portfolios with google sites

Our school has used google sites for some time for students to use portfolios. We have a template portfolio that we use, and then we have traditionally had students create their own portfolios based on that template. The problem is that the "creating the site" step can take a while, and, in spite of clear directions, students get mixed up and don't follow our naming system, and then for years down the road whenever a teacher wants to see a portfolio, it's hard to find.

So, this year, I automated the process of creating student portfolios. This blog post serves as notes for me and anyone else who wants to automate the process of:

(A) Creating new google sites based on a template
(B) Re-assigning ownership to someone else
(C) Setting the permissions so everyone in the domain can view the site.

Though google documents this stuff, it's not as simple or transparent as it should be, and it's a bit error prone. There's also precious little help to be googled -- hopefully this post will help improve that situation.

Google, if you're listening, I would love to see an updated google sites API soon. Among other things, you really need to start supporting your page templates better through your API -- right now there's no working way to programmatically touch content on pages that use page templates (which, in the case of our school, is *all* pages)

Let me walk you through the different scripting steps...
  1. Log into google...

    import atom.data
    import gdata.sites.client
    import gdata.sites.data
    import urlparse
    
    client = gdata.sites.client.SitesClient(source='yourCo-yourAppName-v1', domain='domain.org')
    pw = 'SECRET'
    master_user = 'USERNAME@DOMAIN.org'
    client.ClientLogin(master_user,pw,client.source)

    This gets you the client object, which is what you'll use to do nearly everything.
  2. Create a new site based on a template.

    client.CreateSite is the command to create a site. The tricky part here is finding a template to use. Google's tutorial tells you to use the parameter source_site, but only template source_sites are usable. To find the right value, it's simplest to (1) create a site using the template you want (2) find the site object for that site (3) grab the source_site attribute off of that one. In my case, the basic code to create a site looks like this:
    entry = client.CreateSite(name+' '+str(yog), source_site='https://sites.google.com/feeds/site/innovationcharter.org/sampleportfolio')
  3. Fix permissions: My last step is changing the permissions so the site is owned by the student and not me. This code has to run after the site has successfully been created; when running code creating hundreds of sites, there can be an issue with this not working properly. I ended up writing the code so that first I created all the sites, then I fixed all the permissions, which worked more reliably than creating a site then fixing permissions. I believe there may be a switch I could hand to CreateSite to fix the issue I was having with editing permissions immediately after creating the site, but I've lost track of that documentation at this point.

    At any rate, here's the way to fix the permissions up.
    First, add the user to the entry:

    def add_user_to_entry (user, entry):
       print 'Adding user to entry...',user,entry
       role = gdata.acl.data.AclRole(value='owner')
       scope = gdata.acl.data.AclScope(value=user,type='user')
       user_acl = gdata.sites.data.AclEntry(scope=scope,role=role)
       client.Post(user_acl,entry.FindAclLink())


    Second, delete ourselves from the entry (this assumes our master user is stored in the variable master_user, as above)

    def delete_master_entry (entry):
        acl = client.GetAclFeed(entry.FindAclLink())
        for e in acl.entry:
            if master_user in e.to_string():
                client.Delete(e)

    Finally, in our school, we have portfolios readable by anyone within our domain. To enforce this, we run this code:

    def make_domain_readable (entry):
        print 'Make domain-readable'
        role = gdata.acl.data.AclRole(value='reader')
        scope = gdata.acl.data.AclScope(value='innovationcharter.org',type='domain')
        domain_acl = gdata.sites.data.AclEntry(scope=scope,role=role)
        client.Post(domain_acl,entry.FindAclLink())
    
To put it all together, here is the complete script I used to read in a list of usernames from a file and create digital portfolios accordingly. The file format is simply a CSV file with Email addresses on it. I inferred the first/last name based on the address -- it would be trivial to alter the code to put whatever data you wanted in a spreadsheet in.


import re
import csv
import atom.data
import gdata.sites.client
import gdata.sites.data
import urlparse
import traceback
import csv
import time

client = gdata.sites.client.SitesClient(source='yourCo-yourAppName-v1', domain='mydomain.org')
pw = 'topsecretpassword'
master_user = 'admin@mydomain.org'
client.ClientLogin(master_user,pw,client.source)
# Convenience Functions

def delete_master_entry (entry):
    '''Remove master user from site - get rid of our ownership'''
    acl = client.GetAclFeed(entry.FindAclLink())
    for e in acl.entry:
        if master_user in e.to_string():
            client.Delete(e)
    
def add_user_to_entry (user, entry):
    '''Add user as owner of site entry'''
    role = gdata.acl.data.AclRole(value='owner')
    scope = gdata.acl.data.AclScope(value=user,type='user')
    user_acl = gdata.sites.data.AclEntry(scope=scope,role=role)
    client.Post(user_acl,entry.FindAclLink())

def make_domain_readable (entry):
    '''Make site readable by everyone in domain'''
    role = gdata.acl.data.AclRole(value='reader')
    scope = gdata.acl.data.AclScope(value='mydomain.org',type='domain')
    domain_acl = gdata.sites.data.AclEntry(scope=scope,role=role)
    client.Post(domain_acl,entry.FindAclLink())

def create_dp (email, name, yog):
    '''Create a digital portfolio based with a title based on name
     and year of graduation. 
    '''
    print 'Create DP',email,name,yog
    try:
        entry = client.CreateSite(name+' '+str(yog),
            source_site='https://sites.google.com/feeds/site/mydomain.org/sampleportfolio')
    except:
        # Print exceptions but don't raise them - this allows us to run
        # the script through even if there's a few bad data entries that
        # need correcting later.
        traceback.print_exc()
        entry = None
    if entry:
        # We postpone fixing permissions since there seems to be a bug in the API
        # that means updating permissions right away will often silently fail.
        def pull_trigger_later ():
            print 'Fixing user info for ',email,name,yog
            add_user_to_entry(email,entry)
            delete_master_entry(entry)        
            make_domain_readable(entry)
    else:
        def pull_trigger_later():
            print 'No entry was created for ',email,name,yog,'so no further action'
    # We return a function to fix permissions and the entry -- that way whoever
    # calls us can decide when to fix the permissions.
    return entry,pull_trigger_later

def print_permissions (entry):
    afeed = client.GetAclFeed(entry.FindAclLink())
    for e in afeed.entry:
        print e.to_string()
# LOOP TO READ IN DATA FROM CSV FILE, CREATE SITES, AND THEN, LATER, 
# FIX PERMISSIONS.

entries = [] # To store sites we've created
triggers = [] # Functions to fix permissions (we'll do this later)

reader = csv.reader(file('digital_portfolio_data.csv','r'))
reader.next() # Remove first line - header
for line in reader:
    # You'd update this for whatever data source you can conveniently create
    # for your own domain. This is based on our own usernames which are
    # first.last@innovationcharter.org, and it's based on the fact that I'm
    # creating a group of sites for the class of 2018 only (if I weren't, I'd
    # have added a field to the csv with the YOG).
    email = line[0]
    first = email.split('.')[0].capitalize()
    last = email.split('.')[1].split('@')[0].capitalize()
    name = ' '.join([first,last])
    e,f = create_dp(email,name,'2018')
    entries.append(e)
    triggers.append(f) # Save the permissions-fixing for later

# We're done creating sites, now let's fix permissions...
print len(triggers),'triggers to run.'
print 'Sleeping while google finishes its business' 
time.sleep(30) # Ugly ugly ugly
print "I'm alive again!"
for n,t in enumerate(triggers):
    try:
        print 'Running trigger #',n
        t()
    except:
        # Again, report errors but don't stop loop for them.
        traceback.print_exc()

Saturday, March 22, 2014

Two views of addition, two weeks apart

Now that I'm watching my kids learn skills like addition and reading which go above and beyond the obvious natural language acquisition, it's still amazing to watch the process of acquisition, and to see how suddenly things click so that what seemed impossible becomes totally natural in a matter of just weeks.

Since a colleague of mine who used to be an elementary school teacher mentioned to me that "counting on" was something that took kids a while to get, I've been paying attention. Sure enough, though Grace can happily count numbers and add them, she's spent quite a long time doing addition by putting two groups together and then counting all the items, rather than simply starting counting from one set and then up to the other. It's kind of fascinating how stubborn she is in this, and how much math she can seem to know when she still can't get the basic idea that if you have five things and you add four you only have to count up four from five.

Anyway, here's two facebook posts (the new journal? ack?) of mine documenting the shift -- because they have dates, I can actually see how little time it took to make the transition from absolutely not counting on to doing it like it's nothing.

From March 7th:

Watched Grace add 8 and 5 today to get 13. I noticed she did it all on the fingers of one hand and seemed to be counting up to thirteen. I asked her how she did it, and she explained she did 4 + 4 +5, because she somehow already knew 8 was 4 + 4.

Doesn’t it seem kind of weird that she can break that problem down that way in her head all to avoid using two hands to count (I think maybe she was holding something with the other hand?), but still can’t simply count on (i.e. start at 8 and then count 5 more up to 13)?

From March 22nd:

Grace magically started counting on today!

(in the context of a card game where this matters...) Me: Grace, what's 4 + 7
Grace: Do you mean 7 + 4?
Me: Sure -- that's the same thing.
Grace: Okay... [counting to four on one hand], 8,9,10,11... 11!
Me: Grace, who taught you to do that?
Grace: No one, I just do it.
Me: Huh.


So I can tell you with reasonable certainty that 2 weeks ago Grace couldn't count on when I tried to coach her to do it and looked at me in total confusion when I suggested it as an approach to handling numbers that didn't fit on her fingers. Now she's doing it like it's the most obvious thing in the world, with no awareness of having learned it.

The question, as ever: did she "learn" this from the inadvertent teaching I've been doing as I've been trying to understand how she does math in her head, or did something in her development just click today so she was ready to do it now?

I realize the answer is almost certainly a little of both, but I certainly lean toward the development side of this question. It amazes me how many skills seem absolutely unlearnable until some magical threshold is passed and they're learned seemingly effortlessly...

Sunday, December 8, 2013

"Us-guys:" how Lila recreated the birth of "nosotros," only in 2-year-old English

Yesterday at whole foods, all three girls were on the verge of melting down and we had a long drive ahead of us. I grabbed a box of truffles for the road. As I did so, I noticed that Katharine had already gotten one, leading to this exchange:
Me: Oh, you already grabbed chocolates?
K: Yeah, I got some for work.
Lila (excitedly): Some chocolates for work and some for us-guys!  [əm wawI fə wək æn əm wawI fə əsgaiz]
Grace (archly): Lila, it's "us," not "us-guys." Dad, she said Us-guys.
This led, of course, to me giving an impromptu lecture on the evolution of "nosotros" in Spanish, which, though unappreciated by Grace, I will nonetheless repeat here.

 At about the time Spain was busy conquering the world, it was in more or less the same place we are now with its evolution of second person pronouns. Spanish, like English, started out with singular and plural second-person pronouns:


EnglishSpanish
Sing.PluralSing.Plural
1st person:IWeYoNos
2nd person:ThouYouVos

In both languages, the plural form was used as a term of respect for people of rank, both in the second person and the first (the royal "we"), etc. In what seems like an odd move, both languages at one point or another generalized the plural/respectful form to a universal "you" form:


EnglishSpanish
Sing.PluralSing.Plural
1st person:IWeYoNos
2nd person:YouYouVosVos
Obviously, that leads to confusion in the 2nd person, and a great deal of innovation has occurred in both languages to fill in the gap.

Various innovative forms
EnglishSpanish
Sing.PluralSing.Plural
2nd person:You, ThouhYou, Y'all, You guys, Yous, Yous guysVos, Tú, Vuestra merced, UstedVos, Vos-todos, vosotros, vuestras mercedes, ustedes

Eventually, Spain evolved four different 2nd person forms to address formal and informal, singular and plural, and "vosotros" became the standard 2nd person informal plural form. It was only after the evolution of "vosotros" that "nosotros" came into being instead of "nos" as the full (non-clitic) form of the first-person-plural pronoun, presumably as an attempt to regularize the forms by rhyming them (of course "nos" and "vos" had originally rhymed, but by this time "vos" was no longer a plural pronoun).

So, what does all of this have to do with "us-guys"? Of course, "us-guys" was formed by precisely the same pattern that formed "nosotros" in Spanish. Just as "otros" was taken to be a plural marker, "guys" is understood by Lila as the plural-marker in my Northeastern dialect. It strikes me that it is quite possible that Lila learned the grammatical meaning of "guys" (turn a pronoun plural) before she learned its literal meaning.

To understand what happened in the Spanish in terms of modern-day English, you would have to imagine the following events taking place in order for English to arrive where Spanish presently is:

1. All speakers adopt Lila's habit of adding "-guys" to "us" and "we" in addition to adding it to "you" (you-guys, us-guys, we-guys). This new us-guys form becomes so common it is used universally by speakers everywhere, no matter what their feeling are on 2nd person pronouns.
2. "Thou" becomes trendy again and becomes the normal informal 2nd person pronoun, leaving "you" on its own to sound old-fashioned and oddly formal, except in a few countries colonized by England, where "you" continues to be the normal pronoun or where it exists in alternation with "thou."
3. "Your honor" and "your honors" becomes a standard form of formal address in all kinds of situations, except in particularly left-leaning English-speaking enclaves, and becomes contracted first to "yonor" and then finally to "onna" The abbreviation is written either "On./Ons." or "Yn./Yns." depending on where you see it.
4. Many people stop saying "you-guys" all the time, so that "you-guys" sounds like a particularly New-England thing. Most of the world uses "onnas" for the 2nd person plural, regardless of formality.

Saturday, November 23, 2013

Texting Speak + Cross-Language Pollination + Morphology = New Words

So the other day in a dopey article I grabbed from a Spanish teen magazine for students to look at, I discovered the Spanish word "BeFa" (also spelled "befa"). From context, I had a gut feeling it meant "best friend," which a Puertorican student confirmed for me.

This word is awesome: it derives from "BF" (English internet/texting speak for best friend). I assume (dangerous, I know) that this happened in the following way:

BF - borrowed form from English
be efe
- borrowing as pronounced in Spanish
befe - new word form from fusing the two letters. Spanish phonetic rules don't distinguish between double vowels between words and single ones (this is how "ten te en pie" becomes tentempié, for example)
befes - new plural word form based on Spanish morphological rules for creating a plural
befa - new playful Spanish feminine form, based on Spanish morphological rules for creating a feminine form. This is highly unusual, however, because usually words ending in "e" do not change form for gender.
befas - new plural feminine form.

Quick google searches seem to confirm that ="befe" (m), "befes" (m), "befa" (f) and "befas" (f) all exist as forms in Spanish. Google also confirms that my proposed intermediate forms "BF"and "be efe" also exist, as well as "mi be efe efe" and "mi be efe efe efe" which suggests that some speakers think the extra "f" in "bff" serves as an intensifier rather than standing for "forever." Some other hybrids that exist but are rarer are "BFa" and "BFas." I was able to find only a handful of hits for "mis be efes" and none for "mis bes efes," suggesting that the whole "BF" is taken as a word and not as two words.

Google ngrams, alas, has yet to capture the phenomenon in print -- I'd love to have an up-to-date Google ngrams like tool for internet text as well as print.
Question: what other texting words are likely to have crossed over into Spanish?