Posts Tagged ‘App Engine’

Yahoo! UI on App Engine

May 22, 2008

The Yahoo! User Interface Library or YUI is a handy collection of JavaScript for DOM scripting, DHTML and AJAX applications. And since JavaScript along with Python is one of the languages for Google’s App Engine, it’s useful to look at how hard it is to use the Yahoo! UI library on App Engine.

At least to throw together a simple donut slider.

To get started look at the starter page on the YUI slider page. Download the minimum slider components which is some JavaScript, some images files and some CSS. In your /static/js directory you’ll want to add dragdrop-min.js, slider-min.js and yahoo-dom-event.js. Then you’ll have to code up a simple the-slider.js file which looks like the example but contains arrays for the link titles and the link urls. This JavaScript should also include a function to update the div with the dynamic content, in this case referred to as endvalue, when the slideEnd is triggered.

slider.subscribe("slideEnd", function() {
  YAHOO.log("slideEnd fired", "warn");
  var endvalue = Dom.get(contentarea);
  var i = slider.getRealValue();
  if (i < minPosts) i = minPosts;
  if (i > maxPosts) i = maxPosts;
  endvalue.innerHTML = '';
  for (j = 0; j < 10; j++)
    {
      if ((i+j) < maxPosts) {
        endvalue.innerHTML += '<a class="rt" href="' + theURLs[i+j] + '" target="_blank">' + theTitles[i+j] + '</a><br>';
     }
  }
});

Next up you can optionally update the graphics for your slider. The default .gif files are in an /assets folder. In this I added a donut image for the knob. You can use anything you want just remember to update your app.yaml file or it won’t work.

- url: /assets/
  static_dir: static/assets

Next use the .css file (path also added to the app.yaml) and finally add another class to the python code to create the page. In this case add a class sliderPage that maps to /slider and import the javascript, css and some default urls and titles. That’s it. Pretty straightforward.

class sliderPage(webapp.RequestHandler):
  def get(self):
    self.response.headers['Content-Type'] = 'text/html'
    self.response.out.write('<script src="/js/yahoo-dom-event.js"></script>')
    self.response.out.write('<script src="/js/dragdrop-min.js"></script>')
    self.response.out.write('<script src="/js/slider-min.js"></script>')
    self.response.out.write('<link rel="stylesheet" type="text/css" href="/css/s.css" />')
    self.response.out.write('<script src="/js/the-slider.js"></script>')
    self.response.out.write('')
    self.response.out.write('<p><table> <tr> <td>Older</td> <td>')
    self.response.out.write('<div id="slider-bg" tabindex="-1" title="Slider">')
    self.response.out.write('<div id="slider-thumb"><img src="/assets/thumb-n.gif"></div>')
    self.response.out.write('</div> </td> <td>Newer</td> </tr> </table>')
    self.response.out.write('')
    self.response.out.write('<p><div id="the-content">')
    self.response.out.write('<a class="rt" href="https://boldlentil.wordpress.com/2007/05/05/hello-world/" target="_blank">Remembering Gerald</a><br>')
   (... other starting titles and urls here... )
    self.response.out.write('</div>')
    self.response.out.write('<p>-<p>')
    self.response.out.write('<a class="rt" href="https://boldlentil.wordpress.com/" target="_blank">Bold Lentil</a><br>')
    self.response.out.write('')
    self.response.out.write('</html>')

Now what would be handy would be a /sstatic or shared static directory for assets, like the donut slider, to be shared across all my future applications…

Google App Engine: Adding JavaScript and Images

May 15, 2008

Bold lentil now has a dynamic graphical jump page.

It’s here.

Yes it’s hosted on app engine and yes it uses JavaScript. I was at a talk the other day by Dick Wall and there was speculation about what language might be supported after python. I think the question is what languages will be supported after python and JavaScript.

So assuming you have a useful JavaScript function in a thumbs.js file and it starts with an array of urls:

  function stepThumbnails(theSign) {
    var theURLs = new Array();
    theURLs[0] = "";
    theURLs[1] = "https://boldlentil.wordpress.com/2007/05/05/hello-world/";
    theURLs[2] = "https://boldlentil.wordpress.com/2007/05/05/cetacean-mutation/";
    theURLs[3] = "https://boldlentil.wordpress.com/2007/05/06/four-things-about-the-new-r2d2-mailboxes/";
    theURLs[4] = "https://boldlentil.wordpress.com/2007/05/09/domestic-politics/";
    theURLs[5] = "https://boldlentil.wordpress.com/2007/05/10/two-hundred-and-thirty-one-things-i-learned-using-the-internets/";
    theURLs[6] = "https://boldlentil.wordpress.com/2007/05/10/still-havent-finished-my-post-on-prcrastination/";
...
    theURLs[92] = "https://boldlentil.wordpress.com/2008/04/21/karl-attacks/";
    theURLs[93] = "https://boldlentil.wordpress.com/2008/04/23/toxoplasmosis-choose-your-own-post-ending/";
    theURLs[94] = "https://boldlentil.wordpress.com/2008/04/24/lenigme-by-gustave-dore/";
    theURLs[95] = "https://boldlentil.wordpress.com/2008/05/01/gm-to-cut-1000s-announces-failed-business-plan/";
    theURLs[96] = "https://boldlentil.wordpress.com/2008/05/01/dont-something-the-elephant-seals/";

Then add some code to define the width, height and size of the jump pages (in terms of number of thumbnail images). And then add some calculations for a starting and ending value for the specific array of thumbnails.

    var max = 96;
    var wide = 4;
    var high = 4;
    var theStep = (wide * high);
    var myStep = (theStep * theSign);
    if (theSign == 0) {
      var one = 1;
      var two = 1;
      var tre = theStep;
    }
    else {
      var one = parseInt(document.f1.theStartValue.value);
      var two = one + myStep;
      if (two < 1) two = 1;
      if (two > max) {
        two = one;
      }
      document.f1.theStartValue.value = two;
      var tre = two + myStep - 1;
      if (myStep < 0) tre = two - myStep - 1;
    }

Finally some more JavaScript to loop over the range to create a table of image thumbnails. Nothing fancy here.

    theText = '<p>';
    var theTable = '<table>';
    var twoPlus = two;
    for (i = 0; i < high; i++) {
      theTable += '<tr>';
      for (j = 0; j < wide; j++) {
        twoPlus = two + (i * wide) + j;
        if (twoPlus <= max) {
          theTable += '<td><a href=';
          theTable += theURLs[twoPlus];
          theTable += '><img src="/images/thumbnails/thumbnail-'+twoPlus+'.gif" border=0></a></td>\n';
        }
        else {
          thetable += '<td></td>\n';
        }
      }
      theTable += '</tr>';
    }
    theTable += '</table>';
    document.getElementById('theCurrentThumbnails').innerHTML = theText + theTable;
    document.f1.theStartValue.value = two;

Then save this file in a directory /static/js in the same directory as the root python code. Now I’m sure all this can be done more succinctly in python but if you already have some JavaScript handy why not use it?

The next step is to set up the images file. In this case I used /static/images/thumbnails. The thumbnails were created using a script file to be square and 128 by 128. Some experimentation seemed to lead me to believe that the /static for both the js and images was required. Anyways with the JavaScript code above in the /static/js directory and the GIF thumbnails in the /static/images/thumbnails directory it’s time to edit the app.yaml file to look something like:

application: 1boldlentil
version: 6
runtime: python
api_version: 1

handlers:
- url: /
  script: boldlentil.py

- url: /js
  static_dir: static/js

- url: /images/thumbnails
  static_dir: static/images/thumbnails

- url: /.*
  script: boldlentil.py

The two new handlers are for the JavaScript and for the images. Pretty easy once you know to add both of these to a /static directory and also know not to reference this /static in the code. Finally, the boldlentil.py file has to be edited to add a /jump page. This is pretty straightforward:

class jumpPage(webapp.RequestHandler):
  def get(self):
    self.response.headers['Content-Type'] = 'text/html'
    self.response.out.write('')
    self.response.out.write('')
    self.response.out.write('<head>');
    self.response.out.write('<script language="JavaScript" src="/js/thumbs.js">');
    self.response.out.write('</script>');
    self.response.out.write('</head>');
    self.response.out.write('<body onLoad="stepThumbnails(0)">');
    self.response.out.write('<form name="f1">');
    self.response.out.write('  <input type="hidden" name="theStartValue" value="1"><p>');
    self.response.out.write('  <input type="button" value="-15" onClick="stepThumbnails(-1)">');
    self.response.out.write('  <input type="button" value="+15" onClick="stepThumbnails(1)" ><p>');
    self.response.out.write('</form>');
    self.response.out.write('</body>');
    self.response.out.write('<div id="theCurrentThumbnails">');
    self.response.out.write('</div>');
    self.response.out.write('<a href=https://boldlentil.wordpress.com/><b>Bold Lentil</b> <a><p>');
    self.response.out.write('');
    self.response.out.write('</html>');

The final result is simple and appealing in a minimalist, wisenheimer way. And unlike computing randomish numbers the jump page even registers on the dashboard.

Google App Engine: Fun with the Datastore

May 12, 2008

The Datastore is the App Engine online database for use by your online application. So not only does Google host your python code but as you accumulate application data and format it as a database they will also manage that data. The last post had adding a form to collect user seed values for the online randomish number generator. Now it’s time to store those seed values in the 1boldlentil application Datastore. Start with adding this line to import the app engine database functionality:

from google.appengine.ext import db

After this a database of seed values should be declared before the main page. This database is pretty simple and at this point consists of the seed value as an integer and the date for that entry. Google has their worked example in their documentation but you have to dig to get a list of types and properties which is here.

class SeedValues(db.Model):
  theSeed = db.IntegerProperty()
  date = db.DateTimeProperty(auto_now_add=True)

Finally we’ll use the two page structure of a simple form to collect a seed value followed by a page to print the values generated with that seed value. So for version five of the application we’ll have a /5s to hold the form and /5 to show the results. The /5s is identical to the /4s from the previous post so it won’t be shown here. The results created with /5 are different though. The top part of this class declaration has theSeed declared and assigns it to the seed value from the form. This value is then put into the database with thisSeed.put().

class version5Page(webapp.RequestHandler):
  def post(self):
    userSeed = int(cgi.escape(self.request.get('theSeed')))
    thisSeed = SeedValues()
    thisSeed.theSeed = userSeed
    thisSeed.put()
    self.response.headers['Content-Type'] = 'text/html'
    self.response.out.write('')
    self.response.out.write('')
    self.response.out.write('theSeed=');
    self.response.out.write(userSeed)
    self.response.out.write('<p>');
    self.response.out.write('<a href=https://boldlentil.wordpress.com ')
    self.response.out.write('target="_blank">')
    self.response.out.write('<b>Randomish Numbers</b></a><p>')
    random.seed(userSeed)
    stop = 25
    i = 1
    while i <= stop:
      self.response.out.write(random.random())
      self.response.out.write('<br>')
      i = i + 1
    self.response.out.write('<p><b>Last 10 seed values:</b> ')
    LastTenSeeds = db.GqlQuery("SELECT * FROM SeedValues ORDER BY date DESC LIMIT 10")
    for aSeed in LastTenSeeds:
      self.response.out.write(cgi.escape(str(aSeed.theSeed)))
      self.response.out.write(' ')

After the now too familiar for loop to print out the resulting randomish numbers is a Google Query Language or GQL query for the last ten seed values which are then printed to the screen. Once again pretty simple. Define the specific database class to be used by the application, create an instance and fill it and then access with queries.

The result is: here.

Note that the types and properties also has built in support for GPS coordinates, IM and ratings. No the next post will not be about letting you readers rate each other randomish number generator seed values. But it’s tempting.

Google App Engine: Basic Form Handling

May 9, 2008

Behind every good psuedo-random generator there is a good seed value for that psuedo-random generator.

The previous three versions of the online randomish generator simply used pythons default seed of the system time. This would be a good place to add a simple HTML form to allow users to enter their own seed value. First off you’ll need to remember to:

import cgi

Then define a class for the seed form input page. Note the standard workhorse HTML form in the code. The action is set equal to “/4″ and the method is a post. This class is defined in webapp.WSGIApplication as (‘/4s’, version4Seed) and is the url linked to from the / or entry url for 1boldlentil.

class version4Seed(webapp.RequestHandler):
  def get(self):
    self.response.headers['Content-Type'] = 'text/html'
    self.response.out.write('')
    self.response.out.write('')
    self.response.out.write('<html><body>');
    self.response.out.write('<form action="/4" method="post">')
    self.response.out.write('<div>Seed value:')
    self.response.out.write('<input type="text" name="theSeed" size="11"></div>')
    self.response.out.write('<div><input type="submit"')
    self.response.out.write('value="Compute Randomish Numbers"></div>')
    self.response.out.write('</form></body></html>')

Then define the page that takes this form post and generates the corresponding random numbers using the seed values. The user seed is passed to the page using cgi.escape(self.request.get(‘theSeed’)) and this value is used to seed the random number generator. Now every time you use the page with the same random number generator the program will return the same 25 numbers.

class version4Page(webapp.RequestHandler):
  def post(self):
    userSeed = int(cgi.escape(self.request.get('theSeed')))
    self.response.headers['Content-Type'] = 'text/html'
    self.response.out.write('')
    self.response.out.write('')
    self.response.out.write('theSeed=');
    self.response.out.write(userSeed)
    self.response.out.write('<p>');
    self.response.out.write('<a href=https://boldlentil.wordpress.com ')
    self.response.out.write('target="_blank">')
    self.response.out.write('<b>Randomish Numbers</b></a><p>')
    random.seed(userSeed)
    stop = 25
    i = 1
    while i <= stop:
      self.response.out.write(random.random())
      self.response.out.write('<br>')
      i = i + 1

In the main() the webapp.WSGIApplication declares that (‘/4′, version4Page).

Which is pretty easy. Import cgi, define class/url tuple for the form and another class/url tuple to handle the data. Pretty straightforward. And testing on the local machine calling the url /4 directly without filling out the form just returns a blank page. Once its uploaded to appspot though it will give a 405 to try to access the page/url directly without filing in the form.

Version 4 of randomish numbers is here.

Google App Engine: the Users API

May 8, 2008

The previous versions of the online randomish numbers generator have been open to the entire web. The App Engine users API can be used to require a user login with a Google user account. Once again start by importing the corresponding code:

from google.appengine.api import users

In this case the password protected version of the online randomish number generator will be added to version 3 of the app. This app will be located at /3 and will call version3Page and starts by setting the value of user to the current user using the third line below.

class version3Page(webapp.RequestHandler):
  def get(self):
    user = users.get_current_user()
    if user:
      self.response.headers['Content-Type'] = 'text/html'
      self.response.out.write('')
      self.response.out.write('')
      self.response.out.write('<a href=https://boldlentil.wordpress.com target="_blank">')
      self.response.out.write('<b>Randomish Numbers</b></a> for ')
      self.response.out.write(user.nickname() + '.<p>')
      stop = 25
      i = 1
      while i <= stop:
        self.response.out.write(random.random())
        self.response.out.write('<br>')
        i = i + 1
      self.response.out.write('<a href=' + users.create_logout_url("/") +'>sign out</a><p>');
    else:
      self.redirect(users.create_login_url(self.request.uri))

If the user is logged in then the randomish numbers are generated. The user is greeted by writing the value of user.nickname() to the page. Finally a link is added at the bottom so that the user can log out. This log out link is created with users.create_logout_url( “/” ) and the “/” will return the user to the top of the boldlentil app. If the user is not logged in then self.redirect(users.create_login_url(self.request.uri)) sends the user to a login screen to log in. Pretty straight forward.

The result is here.

The users API also has separate functions handle admin login so that, for example, certain pages can be accessed only by admins. The User Objects page notes that “at this time, the users API does not provide permanent unique identifiers for Google Accounts.” Although the same page also says that “unique user IDs and email address change propagation may be implemented in a future release.”

Google App Engine: Twice as Many Randomish Numbers with webapp Framework

May 8, 2008

Previous app engine fun resulted in a simple online randomish number generator. This is all well and good but this example didn’t make any use of the webapp framework and, really, don’t the users really deserve twice as many random numbers?

So starting with the previous python to generate random numbers the first step is to import the corresponding code:

import wsgiref.handlers
from google.appengine.ext import webapp

Next define a class for the main page. This is / or entry web page for the application. In this case it’s simply some URLs that point to versions one and two of the randomish number generators. This is called with a request handler. Note that the two versions are linked to a specific URLs, in this case /1 and /2.

class MainPage(webapp.RequestHandler):
  def get(self):
    self.response.headers['Content-Type'] = 'text/html'
    self.response.out.write('')
    self.response.out.write('')
    self.response.out.write('Randomish Numbers: ')
    self.response.out.write('<a href=/1 target="_blank">')
    self.response.out.write('<b>version 1</b></a>, ')
    self.response.out.write('<a href=/2 target="_blank">')
    self.response.out.write('<b>version 2</b></a><p>')
    self.response.out.write('<a href=https://boldlentil.wordpress.com target="_blank">')
    self.response.out.write('<b>Bold Lentil</b></a><p>')

Once the MainPage is defined the next class to define is the version 1 page. This page generates 25 randomish numbers. w00t!

 class version1Page(webapp.RequestHandler):
  def get(self):
    self.response.headers['Content-Type'] = 'text/html'
    self.response.out.write('')
    self.response.out.write('')
    self.response.out.write('<a href=https://boldlentil.wordpress.com target="_blank">')
    self.response.out.write('<b>Randomish Numbers</b></a><p>')
    stop = 25
    i = 1
    while i <= stop:
      self.response.out.write(random.random())
      self.response.out.write('<br>')
      i = i + 1

After the version 1 page, the next step is to the version 2 page. This page generates 50 randomish numbers. Woot! Woot!

class version2Page(webapp.RequestHandler):
  def get(self):
    self.response.headers['Content-Type'] = 'text/html'
    self.response.out.write('')
    self.response.out.write('')
    self.response.out.write('<a href=https://boldlentil.wordpress.com target="_blank">')
    self.response.out.write('<b>Randomish Numbers</b></a><p>')
    stop = 50
    i = 1
    while i <= stop:
      self.response.out.write(random.random())
      self.response.out.write('<br>')
      i = i + 1

Finally what event loop would be complete without a main()? Note the tuples inside of WSGIApplication that link /1 and /2 to version1Page and version2Page respectively.

def main():
  application = webapp.WSGIApplication(
                                       [('/', MainPage),
                                        ('/1', version1Page),
                                        ('/2', version2Page)],
                                       debug=True)
  wsgiref.handlers.CGIHandler().run(application)

if __name__ == "__main__":
  main()

Revise the app.yaml with the new version number and then upload. Note that after uploading the code it will be necessary to use the versions menu item to switch the default to the new version.

The final result is here.

Google App Engine: Randomish Numbers Generator

May 6, 2008

Got my invite to try out Google App Engine.

Logged in and downloaded version 1.0.1.

But then noted I also had to update python. Downloaded and installed 2.5.2.

Then installed the App Engine.

Read through the helloworld example and noted the page about GQL or Google’s “SQL-like language for retrieving data entities from the App Engine scalable datastore” (but without the joins)

Elsewhere there is the App Engine blog, a comparison to EC2 and a port of the engine to EC2.

Now to do some quick coding, an online randomish numbers generator.

import random
print 'Content-Type: text/html'
print ''
print ''
print '<a href=https://boldlentil.wordpress.com target="_blank">'
print '<b>Randomish Numbers</b>'
print '</a><p>'
stop = 25
i = 1
while i <= stop:
  print random.random()
  print '<br>'
  i = i + 1

Wrote this to tools/app-engine/boldlentil/1/boldlentil.py. Also wrote a simple app.yaml using the helloworld example. From /usr/local/google_appengine can then run this simple test app using:

./dev_appserver.py /Users/boldlentil/tools/app-engine/boldlentil/1

Checking http://localhost:8080/ the app returns a screen of randomish numbers. So far so good. The simple user guide goes on to describe the web application framework but I can’t wait, let’s see if I can get this uploaded as is. Jump to http://appengine.google.com/ and now it’s time to select an Application Identifier and an Application Title. But it’s probably a good time to read the Google App Engine Terms of Use. Can’t be under 13 years old. OK. Also “the Service is provided to you without charge for up to 500MB of disk storage, 10GB incoming bandwidth per day, 10GB outgoing bandwidth per day, 200 million megacycles of CPU per day and 2,000 emails per day.” Sounds good. Finally, “by submitting, posting or displaying the Content on or through the Service you give Google a worldwide, royalty-free, and non-exclusive license to reproduce, adapt, modify, translate, publish, publicly perform, publicly display and distribute such Content for the sole purpose of enabling Google to provide you with the Service in accordance with its privacy policy.” Sounds good.

You upload python and they get Content. I guess randomish numbers are content.

So next up creating an application Bold Lentil and using appcfg.py to upload the application.

./appcfg.py update /Users/boldlentil/tools/app-engine/boldlentil/1

Finally use gmail email and login to complete the upload.

Now to test it here.

It worked – and testing it only used 14.95 of my 199608.00 Gigacycles. Slick!

Follow

Get every new post delivered to your Inbox.