Friday, October 18, 2013

School Announcements: Auto-Generating Announcement Documents (printable and viewable online)

Rather than having to manually create a document every day with the daily announcements, I've created a script that will do it for you. There are, of course, other features that could be added, but this is good enough for today.

To start, announcements are submitted via a Google Form, so they end in a spreadsheet. There are three pieces of data: the text of the announcement, the category, and the expiry date.


The script creates a new Google Document (in a public folder), then takes data from the spreadsheet and pastes it into that newly created document. The code for the script follows. (Creative Commons Attribution-ShareAlike).


function createAnnoucementDocument() {
  // Set up a trigger to run this every weekday, perhaps at 8:00 am
 // Define a custom paragraph style.
var styleHeading = {};
 styleHeading[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.CENTER;
 styleHeading[DocumentApp.Attribute.FONT_SIZE] = 18;
 styleHeading[DocumentApp.Attribute.BOLD] = true;

var styleCategory = {};
 styleCategory[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.LEFT;
 styleCategory[DocumentApp.Attribute.FONT_SIZE] = 12;
 styleCategory[DocumentApp.Attribute.BOLD] = true;

var styleText = {};
 styleText[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.LEFT;
 styleText[DocumentApp.Attribute.FONT_SIZE] = 12;
 styleText[DocumentApp.Attribute.BOLD] = false;

  // Get the current date
  var app = UiApp.createApplication();
  var dateToday = new Date();
  // date formatting here: http://docs.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html
  var formattedDateToday = Utilities.formatDate(new Date(), "MST", "yyyy-MM-dd");
  
  // Create the document
  var documentName = formattedDateToday + " School Announcements";
  var doc = DocumentApp.create(documentName);
  // Move the document to the shared folder entitled "Announcements"
  var documentFile = DocsList.getFileById(doc.getId());
  var folderName = DocsList.getFolder("Announcements");
  documentFile.addToFolder(folderName);
  
  // the spreadsheet that contains the results of the announcement submission form
  var sheet = SpreadsheetApp.openById("***INSERT_SPREADSHEET_KEY_HERE***").getSheets()[0];

  // Start creating the body of the document
  var body = doc.getBody();
  
  body.appendParagraph("Name of School Goes Here\r"+formattedDateToday).setAttributes(styleHeading);

  // Read the whole spreadsheet into a list
  //  if Expiry Date (column D) is > or equal to today's date then process it, else ignore
  //  switch if category match then append to document

  var data = sheet.getRange(2, 2, sheet.getLastRow(), sheet.getLastColumn()).getValues();
  for (var row=0, total=data.length; row < total; row++) {
    var rowData = data[row];
    var announcementText = rowData[0];
    var announcementCategory = rowData[1];
    var announcementExpiry = rowData[2];
    if (announcementExpiry >= dateToday) {
      switch (announcementCategory) {
        case "General":
          body.appendParagraph(announcementText).setAttributes(styleText);
        break;
      }
    }
  }
  body.appendParagraph("Events and Meetings").setAttributes(styleCategory);
    for (var row=0, total=data.length; row < total; row++) {
    var rowData = data[row];
    var announcementText = rowData[0];
    var announcementCategory = rowData[1];
    var announcementExpiry = rowData[2];
    if (announcementExpiry >= dateToday) {
      switch (announcementCategory) {
        case "Events and Meetings":
          body.appendParagraph(announcementText).setAttributes(styleText);
        break;
      }
    }
  }
  body.appendParagraph("Athletics").setAttributes(styleCategory);
    for (var row=0, total=data.length; row < total; row++) {
    var rowData = data[row];
    var announcementText = rowData[0];
    var announcementCategory = rowData[1];
    var announcementExpiry = rowData[2];
    if (announcementExpiry >= dateToday) {
      switch (announcementCategory) {
        case "Athletics":
          body.appendParagraph(announcementText).setAttributes(styleText);
        break;
      }
    }
  }
  body.appendParagraph("Cafeteria").setAttributes(styleCategory);
    for (var row=0, total=data.length; row < total; row++) {
    var rowData = data[row];
    var announcementText = rowData[0];
    var announcementCategory = rowData[1];
    var announcementExpiry = rowData[2];
    if (announcementExpiry >= dateToday) {
      switch (announcementCategory) {
          case "Cafeteria":
        body.appendParagraph(announcementText).setAttributes(styleText);
        break;
      }
    }
  }
  return app;
}

Monday, October 14, 2013

Gamification of Health

Feel free to correct me in the comments, but I'm seeing two main trends in the gamification of health. The first is using game mechanics for fitness, motivating us to get us off the couch. The second is gamified, or at least game-based, treatments.

Since I'm and educator and not a health professional, I'm not particularly qualified to comment on the latter. However I have been reading many interesting articles about video games for pain reduction or for treating ADHD, and I'm very interested in devices that help us measure ourselves. For example, check out this story about using an inexpensive EEG device together with video games as therapy for ADHD.

Of broader application, though, is the use of game mechanics to help reverse our sedentary patterns. Devices such as the FitBit products, and games such as Nike+ Kinect Training help us to measure ourselves and set goals. As I write this during a weekend of overeating, I realize that these things need to be as "frictionless" as possible. It's much easier to have another slice of pie than to go to the gym, or to turn on the Xbox and spend half an hour working out. There continues to be a lot of thought put into seamlessly incorporating fitness (and motivation) into our daily lives.

Often the best motivation, for fitness or anything else, involves collaboration or competition with other people. Upcoming competitions such as triathlons or games encourage us to train, and collaborations such the November Project motivate us because our friends are doing it. Of course this means that we need to convince our friends to participate.

In education, however, we have a unique environment with a captive audience. Students participate in events such as the Terry Fox Run, as well as school sports and intramurals. Some organizations try to replicate this with Corporate Challenges, or with online gamification systems such as OfficeVibe, but for some reason those don't seem as successful. Maybe because we don't usually have PhysEd teachers working in our offices.

So there are two things that I'm thinking about related to this. First, of course, is how to continue use our time with students to encourage lifelong fitness. The second, though, is how to replicate for adults the fitness motivation that we see in schools. I see the principles of gamification as one of the best ways to continue doing that.

But first I think I'll go have another slice of pie.

Gamification of Health

Feel free to correct me in the comments, but I'm seeing two main trends in the gamification of health. The first is using game mechanics for fitness, motivating us to get us off the couch. The second is gamified, or at least game-based, treatments.

Since I'm and educator and not a health professional, I'm not particularly qualified to comment on the latter. However I have been reading many interesting articles about video games for pain reduction or for treating ADHD, and I'm very interested in devices that help us measure ourselves. For example, check out this story about using an inexpensive EEG device together with video games as therapy for ADHD.

Of broader application, though, is the use of game mechanics to help reverse our sedentary patterns. Devices such as the FitBit products, and games such as Nike+ Kinect Training help us to measure ourselves and set goals. As I write this during a weekend of overeating, I realize that these things need to be as "frictionless" as possible. It's much easier to have another slice of pie than to go to the gym, or to turn on the Xbox and spend half an hour working out. There continues to be a lot of thought put into seamlessly incorporating fitness (and motivation) into our daily lives.

Often the best motivation, for fitness or anything else, involves collaboration or competition with other people. Upcoming competitions such as triathlons or games encourage us to train, and collaborations such the November Project motivate us because our friends are doing it. Of course this means that we need to convince our friends to participate.

In education, however, we have a unique environment with a captive audience. Students participate in events such as the Terry Fox Run, as well as school sports and intramurals. Some organizations try to replicate this with Corporate Challenges, or with online gamification systems such as OfficeVibe, but for some reason those don't seem as successful. Maybe because we don't usually have PhysEd teachers working in our offices.

So there are two things that I'm thinking about related to this. First, of course, is how to continue use our time with students to encourage lifelong fitness. The second, though, is how to replicate for adults the fitness motivation that we see in schools. I see the principles of gamification as one of the best ways to continue doing that.

But first I think I'll go have another slice of pie.

Thursday, September 19, 2013

Empowered by Technology

The reason that I like technology so much is that it's empowering. The Internet, programming, and even video games allow us to do things that would be otherwise impossible. These technologies also give us a very real sense of power and control over our lives.

The Internet is the greatest repository of information, and misinformation, ever created. You can learn how to do things, share your own expertise, and even look up obscure facts. Scientia potentia est.

Programming is another way that technology empowers us. Basic services such as "If This Then That" (ifttt.com) and more advanced programming languages such as Python allow us to make these machines do our bidding. We can turn our ideas into reality.

Video games are, for many, much more than entertainment. They are empowering in that they allow us control over our own stories and our virtual worlds. They make possible things that are otherwise impossible or impractical, such as driving really fast, flying, or building worlds for others to experience. Minecraft is a great example.

Of course we also need to consider the negative impacts that technology is having on our society and on ourselves. TLDR.

Saturday, June 1, 2013

Google Apps Bulk Delete Users Script

Google Apps has a bulk account creation tool, but nothing for bulk deleting accounts. I had previously written something in Python to bulk delete accounts from a text file, but it was time to create something web-based. This will only work if you have the Domain API enabled, which means that you'll have to enable it in your Google Apps for Education Admin console.

Just a note, though, before deleting users you may want to direct them to the Data Liberation tools for downloading their data.

The actual script is in Google Apps Script. You can see it by visiting Google Apps Delete Users, or create your own copy at script.google.com using the source code below.

Let me know if this works for you, or if you have suggestions for improvements.


 function doGet() {  
 // get the user's credentials for their Google Apps account  
  var user = Session.getEffectiveUser().getUserLoginId()  
  var domain = UserManager.getDomain();  
  var welcome = "You are running this script as " + user + " on the domain " + domain;  
 // set up the user interface  
  var app = UiApp.createApplication().setTitle('Delete Google Apps Users by MisterHay');  
  app.add(app.createLabel(welcome));  
  app.add(app.createHTML("<br>Make sure you have enabled the Provisioning API (support.google.com/a/bin/answer.py?hl=en&answer=60757).<br>This script will delete Google Apps user accounts that you paste or type below. Each account name must be on its own line.<br>e.g.<br>misterhay<br>mpython<br>unladen.swallow<p>"));  
  var textArea = app.createTextArea().setName("textArea").setSize("20%", "60%").setStyleAttribute("background", "white").setStyleAttribute("color", "black").setFocus(true);  
  var serverHandler = app.createServerHandler("deleteAccounts").addCallbackElement(textArea);  
  var clientHandler = app.createClientHandler().forEventSource().setEnabled(false).setText("deleting accounts...");  
  app.add(textArea);  
  var button = app.createButton("Delete Accounts");  
  button.addClickHandler(serverHandler);  
  button.addClickHandler(clientHandler);  
  app.add(button);  
  app.add(app.createLabel("no accounts deleted").setId("finishedLabel").setVisible(false));  
  return app;  
 }  
   
 function deleteAccounts(eventInfo) {  
  var app = UiApp.createApplication();  
  var deleteThese = eventInfo.parameter.textArea;  
  var stringArray = deleteThese.split(/\n/);  
  for (var loopNumber = 0; loopNumber < stringArray.length; loopNumber++) {  
   var deleteThisUser = stringArray[loopNumber];  
 // rename the accounts before we delete them to avoid the five day wait before account names can be reused  
   var renamedUser = deleteThisUser + '_old';  
   Logger.log(renamedUser);  
 // delete the account  
   UserManager.getUser(deleteThisUser).setUsername(renamedUser);  
   UserManager.getUser(renamedUser).deleteUser();  
   }  
 // tell the user how many accounts we deleted.  
  app.getElementById("finishedLabel").setText(loopNumber + " accounts deleted").setVisible(true);  
  return app;  
 }  

Monday, May 27, 2013

Playing a YouTube Playlist in your DigitalSignage

If you're using DigitalSignage.com you'd probably like to play some videos on the screens. You can, of course, upload them to the Resources section, but if you'd just like to loop a YouTube playlist that's fairly easy.

First you'll need to find the URL for a YouTube playlist. Click the title of the playlist, then click the Share button. The URL will be something like http://www.youtube.com/playlist?list=PL627F181E0CB37E19 and the important part is the characters after the = sign.

I'm assuming that you know how to set up screen divisions and campaigns, so grab an HTML5 component from the toolbox and drop it in place. The URL you will put in that component will look like this http://www.youtube.com/embed?listType=playlist&autoplay=1&loop=1&list=PL627F181E0CB37E19 where autoplay=1 means that it will automatically play the through the playlist, and loop=1 means that it will go back to the beginning once it finishes. Of course you will replace the characters after list= with the playlist that you want to use.

Saturday, May 18, 2013

Playing Songza on an EeePC 701

This old seven-inch laptop is still useful for a few things, I've recently connected it to my stereo system as a Songza player.

There were two things I needed to do to get this working:

Install Lubuntu
Install Adobe Flash Player from the tar.gz (which involved copying the .so file to /usr/lib/Chromium and copying the folder somewhere else)

I can write up more details if you ask in the comments.

I tried Google Chrome, but it was too resource-intensive so the audio stuttered. I wasn't able to install the Flash plugin in Midori for some reason, so I went back to Chromium and got it working there. The next step will be to connect a USB IR remote receiver with some scripts for selecting different Songza playlists, pausing, and adjusting the volume.