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 than freedom is different and more important than free of cost. How ironic that the principal 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?

Sunday, October 20, 2013

A regional accent emerging: friends trump family

Overheard from my eldest daughter at the end of a skype with cousins...
Grace: /Wəts 'ðæt pɪkʃʌɹ/ (What's that picture. )
Katharine: /ðæts ə pɪkʃʌɹ əv ænt 'ɛli/ (That's a picture of aunt Ellie. )
Grace: (annoyed) /'ɒnt ɛli/ (*Aunt* Ellie. ) 
 So Grace is beginning to assert accent independence from her loving parents. I'm pretty sure neither Katharine nor I routinely say ɒnt, so this must be coming from school (it is, I believe, the standard pronunciation here in New England).

Tuesday, May 21, 2013

Even in an article about ngrams, NYT fails to care enough about language to factcheck

Anyone who knows me knows how much I love google ngrams. So I was interested to see David Brooks wrote a column based on it.

The beauty of google ngrams is that it makes it easy even for journalists to check facts about language. But that doesn't mean they bother to do the work. Alas, the column, which promised to string a series of ngrams observations together, in fact had its facts wrong.

For example, Brooks claims that:
That is to say, over those 48 years [between 1960 and 2008], words and phrases like “personalized,” “self,” “standout,” “unique,” “I come first” and “I can do it myself” were used more frequently. Communal words and phrases like “community,” “collective,” “tribe,” “share,” “united,” “band together” and “common good” receded.
For the time being, let's ignore the likelihood that the use of the word "tribe" in published books represents communal feeling and check some facts. I began with, "common good" and "band together," and saw that they do not both "recede" as he says. "common good" did drop over the middle of the 20th century, but has been rising over the last twenty years; "band together" has risen steadily over the last two centuries.

Next I tried the phrase, "I come first." It seemed only fair to put it in context by searching a family of such phrases, so I included phrases such as "family comes first", "faith comes first," and so on.

It turns out that "I come first" and "God comes first" track each other nearly perfectly, both rising and falling over the last one hundred years without any clear overall trend as he describes. The only clear trend that emerges from the set is a steady rise in the phrase "family comes first."

I decided to test his general theory that we've seen a rise in individualism and a decline in collective thinking with the most basic words and searched "myself" and "together." Alas, the chart holds nothing to confirm Mr. Brooks' argument.

To be clear, even if the trends he describes were true, they wouldn't necessarily tell us much. Rare in these word lists are phrases that seem equivalent -- comparing trends around "economic justice" and "prudence" (two words that do actually move in the ways he describes) doesn't tell you much since a speaker would virtually never be in a context in which they would be likely to use either word.

But even if his analysis was valid, his data are not.

It's hard to believe the NYT would be this lazy fact-checking anything else. Can you imagine they'd allow a column on sports in which the win-loss records were all made up on the spot? Or a column on politics that got the number of republicans in the senate wrong? With language, you might argue, it is harder to check facts, but in this case the article actually describes the tool needed to do the fact checking, a tool free to the public and a mouse click away.