diff --git a/README.md b/README.md index 4298e1e6..50d1eb5c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,15 @@ # Coder -## A simple way to make web stuff on Raspberry Pi +## A simple way to make web stuff. +### This is a fork of the original Raspberry Pi version that will allow our coder dojo to distribute and run Google Coder for people to use on Macs and PCs. This also includes starter projects used for classes in our dojo. +This bundle helps to create a "portable distribution" for a targetted platform. You need to have NodeJS installed on the platform you want to build for. Go into coder-apps and run "bundle_win.cmd" (Windows), or "bundle_mac.sh" Mac/Linux. The resulting folder can be zipped up and distributed onto a machine with either a local copy of the NodeJS executable or will operate with a full NodeJS install. + +Note: There appear to be some issues with the bundle_win.cmd on Windows 7. +--- + Coder is a free piece of software that turns a Raspberry Pi into a super simple platform that educators and parents can use to teach the basics of building for the web. New coders can craft small projects in HTML, CSS, and Javascript, right from the web browser. +For the Original Raspberry Pi version, click here: http://goo.gl/coder ### What You'll Find Here diff --git a/coder-apps/bundle_mac.sh b/coder-apps/bundle_mac.sh new file mode 100644 index 00000000..bf31516d --- /dev/null +++ b/coder-apps/bundle_mac.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +## +## Creates the bundle for the Mac +## +## sh bundle-mac.sh base_path +## +## Eg. +## sh bundle-mac.sh ../coder-base/ + +if [ $# != 1 ] + then + echo -e "\nUse:\nbundle-mac.sh coderbase\n" + exit +fi + +base=$1 + +mkdir -p $base + +## Copy the startup script to the base folder +cp ../coderdojo/scripts/run-coder.sh $base + +## Expand NodeJS bundle and install it in the base folder. +mkdir -p ./tmp +cp ../coderdojo/nodejs/node-mac.tar.gz ./tmp +cd ./tmp +gunzip node-mac.tar.gz +tar -xvf node-mac.tar +cd .. +mkdir -p $base/node +cp -R ./tmp/nodejs/* $base/node +rm -fr ./tmp + +## do the rest of the installation process +./install_all.sh $base +cd $base + + diff --git a/coder-apps/bundle_win.cmd b/coder-apps/bundle_win.cmd new file mode 100644 index 00000000..f0443dc6 --- /dev/null +++ b/coder-apps/bundle_win.cmd @@ -0,0 +1,19 @@ +@echo off +if =%1-==-- echo "Usage: bundle_win.cmd [coderbase]" & exit /b + +set base=%1 + +REM Create base folder +IF NOT EXIST %base% ( + mkdir %base% +) + +mkdir %base% +copy scripts\run-coder.cmd %base% + +mkdir %base%\node +copy node\node.exe %base%\node + +call install_all.cmd %base% + +cd %base% diff --git a/coder-apps/common/auth/app/app.js b/coder-apps/common/auth/app/app.js index dacd9034..c4357c14 100644 --- a/coder-apps/common/auth/app/app.js +++ b/coder-apps/common/auth/app/app.js @@ -21,7 +21,7 @@ var mustache = require('mustache'); var util = require('util'); var fs = require('fs'); -var bcrypt = require('bcrypt'); +var bcrypt = require('bcrypt-nodejs'); //stores cache of password hash and device name var device_settings = { diff --git a/coder-apps/common/coder/views/index.html b/coder-apps/common/coder/views/index.html index d762b841..09db8d56 100644 --- a/coder-apps/common/coder/views/index.html +++ b/coder-apps/common/coder/views/index.html @@ -75,7 +75,9 @@

Settings

+
Your Coder's Name
@@ -112,9 +114,11 @@

Settings

+
Save
Cancel
diff --git a/coder-apps/common/coderlib/app/app.js b/coder-apps/common/coderlib/app/app.js index 6ec223e8..21b561e9 100644 --- a/coder-apps/common/coderlib/app/app.js +++ b/coder-apps/common/coderlib/app/app.js @@ -69,9 +69,11 @@ exports.listApps = function() { var path = process.cwd(); //root application path. different from __dirname var appdir = path + "/apps/"; var apps = {}; + console.log ("reading apps from: " + appdir); var files = fs.readdirSync(appdir); for ( var x in files ) { var filename = files[x]; + console.log ('Processing: ' + filename); var info = fs.statSync( appdir + filename ); if ( info.isDirectory() ) { var appinfo = null; diff --git a/coder-apps/common/comic_creator/app/app.js b/coder-apps/common/comic_creator/app/app.js new file mode 100644 index 00000000..5e949e05 --- /dev/null +++ b/coder-apps/common/comic_creator/app/app.js @@ -0,0 +1,30 @@ +exports.settings={}; +//These are dynamically updated by the runtime +//settings.appname - the app id (folder) where your app is installed +//settings.viewpath - prefix to where your view html files are located +//settings.staticurl - base url path to static assets /static/apps/appname +//settings.appurl - base url path to this app /app/appname +//settings.device_name - name given to this coder by the user, Ie."Billy's Coder" +//settings.coder_owner - name of the user, Ie. "Suzie Q." +//settings.coder_color - hex css color given to this coder. + +exports.get_routes = [ + { path:'/', handler:'index_handler' }, +]; + +exports.post_routes = [ +]; + + +exports.index_handler = function( req, res ) { + var tmplvars = {}; + tmplvars['static_url'] = exports.settings.staticurl; + tmplvars['app_name'] = exports.settings.appname; + tmplvars['app_url'] = exports.settings.appurl; + tmplvars['device_name'] = exports.settings.device_name; + + res.render( exports.settings.viewpath + '/index', tmplvars ); +}; + +exports.on_destroy = function() { +}; \ No newline at end of file diff --git a/coder-apps/common/comic_creator/app/meta.json b/coder-apps/common/comic_creator/app/meta.json new file mode 100644 index 00000000..d08712ce --- /dev/null +++ b/coder-apps/common/comic_creator/app/meta.json @@ -0,0 +1,8 @@ +{ + "created": "2013-12-06", + "modified": "2013-12-20", + "color": "#95a5a6", + "author": "Coder Team", + "name": "Comic Creator", + "hidden": false +} \ No newline at end of file diff --git a/coder-apps/common/comic_creator/static/css/index.css b/coder-apps/common/comic_creator/static/css/index.css new file mode 100644 index 00000000..dfc6986c --- /dev/null +++ b/coder-apps/common/comic_creator/static/css/index.css @@ -0,0 +1,158 @@ +/*This sets the background color for our comic page*/ + +html body { + background-color: #2b2b2b; +} + + +/*These IDs are for the invisible divs that will hold our comic together*/ + +#page { + height: 100%; + width: 800px; + margin-right: auto; + margin-left: auto; +} + +#titleblock { + height: 160px; + width: 800px; + padding-left: 10px; +} + +/*These are the text styles for the headline and byline*/ + +h1 { + font-family: "Comic Sans MS"; + font-style: italic; + font-weight: 900; + font-size: 45px; + color: white; +} + +h2 { + font-family: "Comic Sans MS"; + font-style: italic; + font-weight: 900; + font-size: 16px; + color: white; +} + +/*These IDs are for the panels that will make up our comic.*/ + +#panel1 { + position:relative; + height: 280px; + width: 780px; + border:10px solid #2b2b2b; + float: left; + background-color: #28d8eb; + overflow: hidden; +} + +#panel2 { + position:relative; + height: 280px; + width: 280px; + border:10px solid #2b2b2b; + float: left; + background-color: #77da62; + overflow: hidden; +} + +#panel3 { + position:relative; + height: 280px; + width: 480px; + border:10px solid #2b2b2b; + float: left; + background-color: #00d26d; + overflow: hidden; +} + +#panel4 { + position:relative; + height: 280px; + width: 480px; + border:10px solid #2b2b2b; + float: left; + background-color: #ffc100; + overflow: hidden; +} + +#panel5 { + position:relative; + height: 280px; + width: 280px; + border:10px solid #2b2b2b; + float: left; + background-color: #ff9100; + overflow: hidden; +} + +/*These classes are for the different text styles we will be using in the comic*/ + +.narration { + font-family: "Comic Sans MS"; + font-style: italic; + font-weight: 900; + font-size: 15px; + padding: 15px; + color: white; + margin: 10px; + background-color: #2b2b2b; +} + +.bigtext { + font-family: "Comic Sans MS"; + color: white; + font-style: italic; + font-weight: 900; + font-size: 30px; + line-height: 100%; + margin: 20px; + text-shadow:2px 2px #2b2b2b; +} + +/* These classes can position text and images within the panel.*/ + +.left { + position:absolute; + left: 0; +} + +.right { + position:absolute; + right: 0; +} + +.top { + position:absolute; + top: 0; +} + +.bottom { + position:absolute; + bottom: 0; +} + +/*These ids can be used fit specific images into our panels based on the dimensions of the image*/ + +#image1 { + position: absolute; +} + +/*These classes are for stacking or ordering elements on top of eachother.*/ + +.inback { + z-index: 1; +} + +.inmiddle { + z-index: 2; +} + +.infront{ + z-index: 3; +} + diff --git a/coder-apps/common/comic_creator/static/js/index.js b/coder-apps/common/comic_creator/static/js/index.js new file mode 100644 index 00000000..89508e79 --- /dev/null +++ b/coder-apps/common/comic_creator/static/js/index.js @@ -0,0 +1,6 @@ + +$(document).ready( function() { + + //This code will run after your page loads + +}); \ No newline at end of file diff --git a/coder-apps/common/comic_creator/static/media/panel_1.jpg b/coder-apps/common/comic_creator/static/media/panel_1.jpg new file mode 100644 index 00000000..36923439 Binary files /dev/null and b/coder-apps/common/comic_creator/static/media/panel_1.jpg differ diff --git a/coder-apps/common/comic_creator/static/media/panel_2.jpg b/coder-apps/common/comic_creator/static/media/panel_2.jpg new file mode 100644 index 00000000..0649c429 Binary files /dev/null and b/coder-apps/common/comic_creator/static/media/panel_2.jpg differ diff --git a/coder-apps/common/comic_creator/static/media/panel_3.jpg b/coder-apps/common/comic_creator/static/media/panel_3.jpg new file mode 100644 index 00000000..32886197 Binary files /dev/null and b/coder-apps/common/comic_creator/static/media/panel_3.jpg differ diff --git a/coder-apps/common/comic_creator/static/media/panel_4.jpg b/coder-apps/common/comic_creator/static/media/panel_4.jpg new file mode 100644 index 00000000..7a603491 Binary files /dev/null and b/coder-apps/common/comic_creator/static/media/panel_4.jpg differ diff --git a/coder-apps/common/comic_creator/static/media/panel_5.jpg b/coder-apps/common/comic_creator/static/media/panel_5.jpg new file mode 100644 index 00000000..4821f06c Binary files /dev/null and b/coder-apps/common/comic_creator/static/media/panel_5.jpg differ diff --git a/coder-apps/common/comic_creator/views/index.html b/coder-apps/common/comic_creator/views/index.html new file mode 100644 index 00000000..eefd0e88 --- /dev/null +++ b/coder-apps/common/comic_creator/views/index.html @@ -0,0 +1,59 @@ + + + + Coder + + + + + + + + + + + + + + + + +
+
+

Your Title Here

+

Your Name And Credits Here

+
+
+
This is for narration
and scene-setting.
+
This is talking or a sound effect.
+ +
+
+
More narration.
+
More talking.
+ +
+
+
More narration.
+
More talking.
+ +
+
+
More narration.
+
More talking.
+ +
+
+
More narration.
+
More talking.
+ +
+
+ + \ No newline at end of file diff --git a/coder-apps/common/localauth/app/app.js b/coder-apps/common/localauth/app/app.js new file mode 100644 index 00000000..55e8ca6c --- /dev/null +++ b/coder-apps/common/localauth/app/app.js @@ -0,0 +1,651 @@ +/** + * Coder for Raspberry Pi + * A simple platform for experimenting with web stuff. + * http://goo.gl/coder + * + * Copyright 2013 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var mustache = require('mustache'); +var util = require('util'); +var fs = require('fs'); +// var bcrypt = require('bcrypt-nodejs'); + +//stores cache of password hash and device name +var device_settings = { + password_hash: '', + device_name: '', + hostname: '', + coder_owner: '', + coder_color: '#3e3e3e' +}; + + +exports.settings={}; +//These are dynamically updated by the runtime +//settings.appname - the app id (folder) where your app is installed +//settings.viewpath - prefix to where your view html files are located +//settings.staticurl - base url path to static assets /static/apps/appname +//settings.appurl - base url path to this app /app/appname +//settings.device_name - name the user gave to their coder "Susie's Coder" + + +exports.get_routes = [ + { path:'/', handler:'index_handler'}, +/* + { path:'/login', handler:'login_handler'}, + { path:'/logout', handler:'logout_handler'}, +*/ + { path:'/configure', handler:'configure_handler'}, +/* + { path:'/addpassword', handler:'addpassword_handler'}, + { path:'/changepassword', handler:'changepassword_handler'}, +*/ + { path: '/api/devicename/get', handler: 'api_devicename_get_handler' }, + { path: '/api/codercolor/get', handler: 'api_codercolor_get_handler' }, + { path: '/api/coderowner/get', handler: 'api_coderowner_get_handler' } +]; + + +exports.post_routes = [ +/* + { path: '/api/login', handler: 'api_login_handler' }, + { path: '/api/logout', handler: 'api_logout_handler' }, +*/ + { path: '/api/devicename/set', handler: 'api_devicename_set_handler' }, + { path: '/api/codercolor/set', handler: 'api_codercolor_set_handler' }, + { path: '/api/coderowner/set', handler: 'api_coderowner_set_handler' } // , +/* + { path: '/api/addpassword', handler: 'api_addpassword_handler' }, + { path: '/api/changepassword', handler: 'api_changepassword_handler' } +*/ +]; + +exports.on_destroy = function() { +}; + +/* +exports.isAuthenticated = function( req ) { + if ( typeof req.session !== 'undefined' && typeof req.session.authenticated !== 'undefined' ) { + return req.session.authenticated === true; + } + return false; +}; +*/ + +exports.isConfigured = function() { + if ( typeof device_settings.device_name !== 'undefined' && device_settings.device_name !== '' && + typeof device_settings.hostname !== 'undefined' && device_settings.hostname !== '' ) { + return true; + } else { + return false; + } +}; + +/* +exports.hasPassword = function() { + if ( typeof device_settings.password_hash !== 'undefined' && device_settings.password_hash !== '' ) { + return true; + } else { + return false; + } +}; +*/ + +exports.getDeviceName = function() { + return device_settings.device_name; +}; +exports.getCoderOwner = function() { + return device_settings.coder_owner; +}; +exports.getCoderColor = function() { + return device_settings.coder_color; +}; + +/* +exports.authenticate = function( req, password ) { + + var authenticated = bcrypt.compareSync( password, device_settings.password_hash ); + if ( authenticated ) { + req.session.authenticated = true; + } + + return authenticated; +}; + +exports.logout = function( req ) { + + req.session.authenticated = false; +}; +*/ + +exports.index_handler = function( req, res ) { + + var firstuse = "?firstuse"; + if ( typeof( req.param('firstuse') ) === 'undefined' ) { + firstuse = ""; + } + + if ( !exports.isConfigured() ) { + res.redirect('/app/auth/configure?firstuse'); +/* + } else if ( !exports.hasPassword() ) { + res.redirect('/app/auth/addpassword?firstuse'); + } else if ( !exports.isAuthenticated(req) ) { + res.redirect('/app/auth/login' + firstuse); +*/ + } else { + res.redirect('/app/coder' + firstuse); + } +}; + +/* +exports.addpassword_handler = function( req, res ) { + var tmplvars = {}; + tmplvars['static_url'] = exports.settings.staticurl; + tmplvars['app_name'] = exports.settings.appname; + tmplvars['app_url'] = exports.settings.appurl; + tmplvars['device_name'] = exports.settings.device_name; + tmplvars['page_mode'] = "addpassword"; + + //only allow this step if they have not yet set a password + if ( !exports.hasPassword() ) { + res.render( exports.settings.viewpath + '/index', tmplvars ); + } else { + res.redirect('/app/auth/login'); + } +}; + +exports.changepassword_handler = function( req, res ) { + var tmplvars = {}; + tmplvars['static_url'] = exports.settings.staticurl; + tmplvars['app_name'] = exports.settings.appname; + tmplvars['app_url'] = exports.settings.appurl; + tmplvars['device_name'] = exports.settings.device_name; + tmplvars['page_mode'] = "changepassword"; + + //only allow this step if they are authenticated + if ( exports.isAuthenticated(req) ) { + res.render( exports.settings.viewpath + '/index', tmplvars ); + } else { + res.redirect('/app/auth/login'); + } +}; +*/ + +exports.configure_handler = function( req, res ) { + var tmplvars = {}; + tmplvars['static_url'] = exports.settings.staticurl; + tmplvars['app_name'] = exports.settings.appname; + tmplvars['app_url'] = exports.settings.appurl; + tmplvars['device_name'] = exports.settings.device_name; + tmplvars['page_mode'] = "configure"; + +/* + //only allow this step if they are authenticated or have not yet set a password + if ( exports.isAuthenticated(req) || !exports.hasPassword() ) { + res.render( exports.settings.viewpath + '/index', tmplvars ); + } else { + res.redirect('/app/auth/login'); + } +*/ + res.render( exports.settings.viewpath + '/index', tmplvars ); +}; + +exports.api_devicename_get_handler = function( req, res ) { + res.json({ + device_name: exports.getDeviceName() + }); +}; +exports.api_codercolor_get_handler = function( req, res ) { + res.json({ + coder_color: exports.getCoderColor() + }); +}; +exports.api_coderowner_get_handler = function( req, res ) { + //only allow this step if they are authenticated or have not yet set a password + if ( !exports.isAuthenticated(req) && exports.hasPassword() ) { + res.json({ + status: "error", + error: "not authenticated" + }); + return; + } + res.json({ + coder_owner: exports.getCoderOwner() + }); +}; + +exports.api_devicename_set_handler = function( req, res ) { + + //only allow this step if they are authenticated or have not yet set a password + if ( !exports.isAuthenticated(req) && exports.hasPassword() ) { + res.json({ + status: "error", + error: "not authenticated" + }); + return; + } + + var devicename = req.param('device_name'); + if ( !devicename || devicename === "" || !isValidDeviceName( devicename ) ) { + res.json({ + status: 'error', + error: "invalid device name" + }); + return; + } + + device_settings.device_name = devicename; + device_settings.hostname = hostnameFromDeviceName( devicename ); + + err = saveDeviceSettings(); + + if ( !err ) { + res.json({ + status: "success", + device_name: device_settings.device_name, + hostname: device_settings.hostname + }); + } else { + res.json({ + status: "error", + error: "could not save device settings" + }); + } + +}; + + +exports.api_coderowner_set_handler = function( req, res ) { + + //only allow this step if they are authenticated or have not yet set a password + if ( !exports.isAuthenticated(req) && exports.hasPassword() ) { + res.json({ + status: "error", + error: "not authenticated" + }); + return; + } + + var owner = req.param('coder_owner'); + if ( typeof owner === 'undefined' ) { + res.json({ + status: 'error', + error: "invalid owner name" + }); + return; + } + + device_settings.coder_owner = owner; + + err = saveDeviceSettings(); + + if ( !err ) { + res.json({ + status: "success", + coder_owner: device_settings.coder_owner + }); + } else { + res.json({ + status: "error", + error: "could not save device settings" + }); + } + +}; + +exports.api_codercolor_set_handler = function( req, res ) { + + //only allow this step if they are authenticated or have not yet set a password + if ( !exports.isAuthenticated(req) && exports.hasPassword() ) { + res.json({ + status: "error", + error: "not authenticated" + }); + return; + } + + var color = req.param('coder_color'); + if ( typeof color === 'undefined' || !isValidColor( color ) ) { + res.json({ + status: 'error', + error: "invalid color" + }); + return; + } + + device_settings.coder_color = color; + + err = saveDeviceSettings(); + + if ( !err ) { + res.json({ + status: "success", + coder_color: device_settings.coder_color + }); + } else { + res.json({ + status: "error", + error: "could not save device settings" + }); + } + +}; + +/* +exports.api_addpassword_handler = function( req, res ) { + + //only allow this step if they have not yet set a password + if ( exports.hasPassword() ) { + res.json({ + status: "error", + error: "not authenticated" + }); + return; + } + + var pass = req.param('password'); + if ( !pass || pass === "" || !isValidPassword( pass ) ) { + res.json({ + status: 'error', + error: getPasswordProblem( pass ) + }); + return; + } + + var spawn = require('child_process').spawn; + var err=0; + //device_settings.device_name = devicename; + var erroutput = ""; + var output = ""; + //var setpipass = process.cwd() + '/sudo_scripts/setpipass'; + //var setpass = spawn( '/usr/bin/sudo', [setpipass] ); + //setpass.stdout.on( 'data', function( d ) { + // output += d; + //}); + //setpass.stderr.on( 'data', function( d ) { + // erroutput += d; + //}); + + //setpass.addListener( 'exit', function( code, signal ) { + var completed = function( code, signal ) { + err = code; + + + if ( err ) { + res.json({ + status: "error", + error: erroutput + }); + return; + } + + //TODO - Load hashed password + var s = bcrypt.genSaltSync(10); + var h = bcrypt.hashSync( pass, s ); + util.log("PASSWORD INITIALIZED"); + device_settings.password_hash = h; + err = saveDeviceSettings(); + + if ( !err ) { + res.json({ + status: "success" + }); + } else { + res.json({ + status: "error", + error: "Could not save device settings." + }); + } + + }; + + completed(); + + //setpass.stdin.write(pass + '\n'); + //setpass.stdin.write(pass + '\n'); + //setpass.stdin.end(); + +}; + + + +exports.api_changepassword_handler = function( req, res ) { + + //only allow this step if they are authenticated + if ( !exports.isAuthenticated(req) ) { + res.json({ + status: "error", + error: "not authenticated" + }); + return; + } + + var oldpass = req.param('oldpassword'); + var pass = req.param('password'); + + //Make sure old pass is set and matches + if ( typeof oldpass === 'undefined' || oldpass === "" + || !bcrypt.compareSync( oldpass, device_settings.password_hash ) ) { + res.json({ + status: 'error', + error: "old password was incorrect" + }); + return; + } + + if ( !pass || pass === "" || !isValidPassword( pass ) ) { + res.json({ + status: 'error', + error: getPasswordProblem( pass ) + }); + return; + } + + var spawn = require('child_process').spawn; + var err=0; + //device_settings.device_name = devicename; + var erroutput = ""; + var output = ""; + var setpipass = process.cwd() + '/sudo_scripts/setpipass'; + var setpass = spawn( '/usr/bin/sudo', [setpipass] ); + setpass.stdout.on( 'data', function( d ) { + output += d; + }); + setpass.stderr.on( 'data', function( d ) { + erroutput += d; + }); + + setpass.addListener( 'exit', function( code, signal ) { + err = code; + + + if ( err ) { + res.json({ + status: "error", + error: erroutput + }); + return; + } + + //TODO - Load hashed password + var s = bcrypt.genSaltSync(10); + var h = bcrypt.hashSync( pass, s ); + util.log("PASSWORD INITIALIZED"); + device_settings.password_hash = h; + err = saveDeviceSettings(); + + if ( !err ) { + res.json({ + status: "success" + }); + } else { + res.json({ + status: "error", + error: "Could not save device settings." + }); + } + + }); + setpass.stdin.write(pass + '\n'); + setpass.stdin.write(pass + '\n'); + setpass.stdin.end(); + +}; + + +exports.login_handler = function( req, res ) { + var tmplvars = {}; + tmplvars['static_url'] = exports.settings.staticurl; + tmplvars['app_name'] = exports.settings.appname; + tmplvars['app_url'] = exports.settings.appurl; + tmplvars['device_name'] = exports.settings.device_name; + tmplvars['page_mode'] = "login"; + + + //TODO - should this log you out automatically? + req.session.authenticated = false; + res.render( exports.settings.viewpath + '/index', tmplvars ); +}; + +exports.logout_handler = function( req, res ) { + var tmplvars = {}; + tmplvars['static_url'] = exports.settings.staticurl; + tmplvars['app_name'] = exports.settings.appname; + tmplvars['app_url'] = exports.settings.appurl; + tmplvars['device_name'] = exports.settings.device_name; + tmplvars['page_mode'] = "logout"; + + req.session.authenticated = false; + res.render( exports.settings.viewpath + '/index', tmplvars ); +}; + +exports.api_login_handler = function( req, res ) { + if ( typeof req.body.password !== 'undefined' && req.body.password !== "" ) { + var authenticated = exports.authenticate( req, req.body.password ); + if ( authenticated === true ) { + res.json( { status: 'success'} ); + return; + } + } + res.json( { + status: 'error', + error: 'invalid password' + } ); +}; +exports.api_logout_handler = function( req, res ) { + req.session.authenticated = false; + + res.json( { status: 'success'} ); +}; +*/ + +var saveDeviceSettings = function() { + err = fs.writeFileSync( process.cwd() + "/device.json", JSON.stringify(device_settings, null, 4), 'utf8' ); + return err; +}; + +var reloadDeviceSettings = function() { + var settings = { + password_hash: '', + device_name: '', + hostname: '', + coder_owner: '', + coder_color: '' + }; + + var loadedsettings = JSON.parse(fs.readFileSync( process.cwd() + "/device.json", 'utf-8' )); + settings.password_hash = ( typeof loadedsettings.password_hash !== 'undefined' && loadedsettings.password_hash !== '' ) ? loadedsettings.password_hash : settings.password_hash; + settings.device_name = ( typeof loadedsettings.device_name !== 'undefined' && loadedsettings.device_name !== '' ) ? loadedsettings.device_name : settings.device_name; + settings.hostname = ( typeof loadedsettings.hostname !== 'undefined' && loadedsettings.hostname !== '' ) ? loadedsettings.hostname : settings.hostname; + settings.coder_owner = ( typeof loadedsettings.coder_owner !== 'undefined' && loadedsettings.coder_owner !== '' ) ? loadedsettings.coder_owner : settings.coder_owner; + settings.coder_color = ( typeof loadedsettings.coder_color !== 'undefined' && loadedsettings.coder_color !== '' ) ? loadedsettings.coder_color : settings.coder_color; + + device_settings = settings; +} +reloadDeviceSettings(); + + +var isValidDeviceName = function( name ) { + if ( !name || name === '' ) { + return false; + } + //starts with an ascii word char. can contain word char's spaces and ' + if ( !name.match(/^[a-zA-Z0-9][\w ']*$/) ) { + return false; + } + //ends in an ascii word char + if ( !name.match(/[a-zA-Z0-9]$/) ) { + return false; + } + return true; +}; +var hostnameFromDeviceName = function( name ) { + var hostname = name; + hostname = hostname.toLowerCase(); + hostname = hostname.replace(/[^a-z0-9\- ]/g, ''); + hostname = hostname.replace(/[\- ]+/g,'-'); + return hostname; +}; + +/* +var getPasswordProblem = function( pass ) { + if ( !pass || pass === '' ) { + return "the password is empty"; + } + if ( pass.length < 6 ) { + return "the password should contain at least 6 characters"; + } + if ( !pass.match(/[a-z]/) || + !pass.match(/[A-Z0-9\-\_\.\,\;\:\'\"\[\]\{\}\!\@\#\$\%\^\&\*\(\)\\].*[A-Z0-9\-\_\.\,\;\:\'\"\[\]\{\}\!\@\#\$\%\^\&\*\(\)\\]/) ) { + return "your password must contain a lower case letter and at least two upper case letters or numbers"; + } +}; + +var isValidPassword = function( pass ) { + if ( !pass || pass === '' ) { + return false; + } + //at least 6 characters + if ( pass.length < 6 ) { + return false; + } + //contains lower case + if ( !pass.match(/[a-z]/) ) { + return false; + } + //contains two upper case or numbers + if ( !pass.match(/[A-Z0-9\-\_\.\,\;\:\'\"\[\]\{\}\!\@\#\$\%\^\&\*\(\)\\].*[A-Z0-9\-\_\.\,\;\:\'\"\[\]\{\}\!\@\#\$\%\^\&\*\(\)\\]/) ) { + return false; + } + return true; +}; +*/ + +var isValidColor = function( color ) { + if ( !color || color === '' ) { + return false; + } + color = color.toLowerCase(); + if ( !color.match(/^\#[a-f0-9]{6}$/) ) { + return false; + } + return true; +} + + + + diff --git a/coder-apps/common/localauth/app/meta.json b/coder-apps/common/localauth/app/meta.json new file mode 100644 index 00000000..f0786758 --- /dev/null +++ b/coder-apps/common/localauth/app/meta.json @@ -0,0 +1,8 @@ +{ + "created": "2014-04-28", + "modified": "2014-04-28", + "color": "#1abc9c", + "author": "Macon Pegram", + "name": "Auth", + "hidden": true +} \ No newline at end of file diff --git a/coder-apps/common/localauth/static/css/index.css b/coder-apps/common/localauth/static/css/index.css new file mode 100644 index 00000000..2a1c6d98 --- /dev/null +++ b/coder-apps/common/localauth/static/css/index.css @@ -0,0 +1,133 @@ + +body { + background-color: #f1c40f; + color: #fff; +} + +.form { + text-align: center; + width: 400px; + left: 50%; + margin-top: 60px; + margin-left: -200px; + position: relative; +} + +#animation { + position: absolute; + height: 100%; + width: 100%; +} + +.centercontainer { + display: table; + height: 100%; + width: 100%; + position: absolute; + top:0px; + left:0px; +} +.center { + display: table-cell; + vertical-align: middle; +} + +h1 { + font-size: 28px; + line-height: 28px; + font-weight: bold; + margin:0; + padding: 0 0 20px 0; +} + +.instructions { + font-size: 21px; + line-height: 1.2em; + padding: 0 0 20px 0; +} + +.formfield { + position: relative; + width: 400px; +} +.formfield.textinput .label { + position: absolute; + color: #999; + top:13px; + left:10px; + font-size: 16px; + line-height: 20px; + -webkit-font-smoothing: antialiased; +} + +.formfield input[type=text], .formfield input[type=password] { + border: 2px solid transparent; + width: 376px; + padding: 10px 10px; + background-color: #fff; + color: #666; + height: 20px; + line-height: 16px; + font-size: 16px; + font-family: Arial, sans-serif; + border-radius: 3px; + -webkit-font-smoothing: antialiased; + margin-bottom: 24px; +} + +.formfield input.error { + border-color: rgba(255,0,0,0.5); +} + +.errormessage { + border: 2px solid transparent; + width: 376px; + padding: 10px 10px; + background-color: #e74c3c; + color: #ffffff; + min-height: 20px; + line-height: 20px; + font-size: 12px; + font-family: Arial, sans-serif; + border-radius: 3px; + -webkit-font-smoothing: antialiased; + margin-bottom: 24px; + text-transform: uppercase; +} + +.submit { + font-size: 21px; + font-weight: bold; + line-height: 60px; + border-radius: 4px; + width:400px; + margin-bottom: 24px; + background-color: rgba(0,0,0,0.6); +} +.submit.disabled, .submit.disabled:hover { + background-color: rgba(0,0,0,0.2); +} +.submit:hover { + background-color: rgba(0,0,0,1); + cursor: pointer; +} + +.cancel { + font-size: 21px; + font-weight: bold; + line-height: 60px; + border-radius: 4px; + width:400px; + margin-bottom: 24px; + background-color: rgba(0,0,0,0.6); +} +.cancel:hover { + background-color: rgba(0,0,0,1); + cursor: pointer; +} + + + + + + diff --git a/coder-apps/common/localauth/static/js/index.js b/coder-apps/common/localauth/static/js/index.js new file mode 100644 index 00000000..bbf0e62a --- /dev/null +++ b/coder-apps/common/localauth/static/js/index.js @@ -0,0 +1,487 @@ +/** + * Coder for Raspberry Pi + * A simple platform for experimenting with web stuff. + * http://goo.gl/coder + * + * Copyright 2013 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +$(document).ready( function() { + +/* + if ( pagemode === "logout" ) { + setupLogoutFields(); + $('#logout_form').show(); + } else if ( pagemode === "login" ) { + setupLoginFields(); + $('#login_form').show(); + } else +*/ + if ( pagemode === "configure" ) { + setupConfigureFields(); + $('#configure_form').show(); + } +/* + else if ( pagemode === "addpassword" ) { + setupAddPasswordFields(); + $('#addpassword_form').show(); + } else if ( pagemode === "changepassword" ) { + setupChangePasswordFields(); + $('#changepassword_form').show(); + } else { + setupLoginFields(); + $('#login_form').show(); + } +*/ + buildAnimation(); + updateAnimation(); + $(window).on('resize', function() { + setTimeout( buildAnimation, 1 ); + }); +}); + +var hideTextLabel = function() { + $(this).parent().find('.label').hide(); +}; +var focusTextInput = function() { + $(this).parent().find('input').focus(); +}; +var onBlurTextInput = function() { + if ( $(this).val() == "" ) { + $(this).parent().find('.label').show(); + } +}; + +/* +var testLoginSubmitEnable = function() { + var $form = $('#login_form'); + if ( pagemode === "logout" ) { + $form = $('#logout_form'); + } + + + if ( $form.find('.pass').val() && $form.find('.pass').val() != "" ) { + $form.find('.submit').removeClass('disabled'); + } else { + $form.find('.submit').addClass('disabled'); + } +}; +*/ + +var testConfigureSubmitEnable = function() { + var $form = $('#configure_form'); + var devicename = $form.find('.device_name').val(); + if ( devicename && devicename != "" && + isValidDeviceName(devicename) ) { + $form.find('.submit').removeClass('disabled'); + } else { + $form.find('.submit').addClass('disabled'); + } +}; + +/* +var testAddPasswordSubmitEnable = function() { + var $form = $('#addpassword_form'); + var pass = $form.find('.pass').val(); + var pass_repeat = $form.find('.pass_repeat').val(); + $form.find('.pass, .pass_repeat').removeClass('error'); + $form.find('.errormessage').css('visibility','hidden'); + + if ( isValidPassword(pass) && pass === pass_repeat ) { + $form.find('.submit').removeClass('disabled'); + } else { + $form.find('.submit').addClass('disabled'); + } +}; + +var testChangePasswordSubmitEnable = function() { + var $form = $('#changepassword_form'); + var oldpass = $form.find('.oldpass').val(); + var pass = $form.find('.pass').val(); + var pass_repeat = $form.find('.pass_repeat').val(); + $form.find('.errormessage').css('visibility','hidden'); + $form.find('.oldpass, .pass, .pass_repeat').removeClass('error'); + if ( oldpass !== "" && isValidPassword(pass) && pass === pass_repeat ) { + $form.find('.submit').removeClass('disabled'); + } else { + $form.find('.submit').addClass('disabled'); + } +}; + + +var setupLoginFields = function() { + $('#login_form .formfield.textinput .label').click( focusTextInput ); + $('#login_form .formfield.textinput input').click( focusTextInput ); + $('#login_form .formfield.textinput input').focus( hideTextLabel ); + $('#login_form .formfield.textinput input').blur( onBlurTextInput ); + $('#login_form .formfield.textinput input').change( testLoginSubmitEnable ); + $('#login_form .formfield.textinput input').keydown( function(e) { + if (e.which != 13) { + setTimeout( testLoginSubmitEnable, 0 ); + } + }); + + //submit on enter or button click + $('#login_form .formfield.textinput .pass').keypress(function (e) { + if (e.which == 13) { + e.preventDefault(); + loginClick( $('#login_form .formfield.textinput .pass') ); + } + }); + $('#login_form .submit').click( function() { + loginClick( $('#login_form .formfield.textinput .pass') ); + }); +}; +var setupLogoutFields = function() { + $('#logout_form .formfield.textinput .label').click( focusTextInput ); + $('#logout_form .formfield.textinput input').click( focusTextInput ); + $('#logout_form .formfield.textinput input').focus( hideTextLabel ); + $('#logout_form .formfield.textinput input').blur( onBlurTextInput ); + $('#logout_form .formfield.textinput input').change( testLoginSubmitEnable ); + $('#logout_form .formfield.textinput input').keydown( function(e) { + if (e.which != 13) { + setTimeout( testLoginSubmitEnable, 0 ); + } + }); + + //submit on enter or button click + $('#logout_form .formfield.textinput .pass').keypress(function (e) { + if (e.which == 13) { + e.preventDefault(); + loginClick( $('#logout_form .formfield.textinput .pass') ); + } + }); + $('#logout_form .submit').click( function() { + loginClick( $('#logout_form .formfield.textinput .pass') ); + }); +}; +*/ +var setupConfigureFields = function() { + $('#configure_form .formfield.textinput .label').click( focusTextInput ); + $('#configure_form .formfield.textinput input').click( focusTextInput ); + $('#configure_form .formfield.textinput input').focus( hideTextLabel ); + $('#configure_form .formfield.textinput input').blur( onBlurTextInput ); + $('#configure_form .formfield.textinput input').change( testConfigureSubmitEnable ); + $('#configure_form .formfield.textinput input').keydown( function(e) { + if (e.which != 13) { + setTimeout( testConfigureSubmitEnable, 0 ); + } + }); + $('#configure_form .submit').click( configureClick ); + $('#configure_form .device_name').val( 'My Coder' ).parent().find('.label').hide(); + testConfigureSubmitEnable(); +}; +/* +var setupAddPasswordFields = function() { + $('#addpassword_form .formfield.textinput .label').click( focusTextInput ); + $('#addpassword_form .formfield.textinput input').click( focusTextInput ); + $('#addpassword_form .formfield.textinput input').focus( hideTextLabel ); + $('#addpassword_form .formfield.textinput input').blur( onBlurTextInput ); + $('#addpassword_form .formfield.textinput input').change( testAddPasswordSubmitEnable ); + $('#addpassword_form .formfield.textinput input').keydown( function(e) { + if (e.which != 13) { + setTimeout( testAddPasswordSubmitEnable, 0 ); + } + }); + + $('#addpassword_form .formfield.textinput .pass_repeat').keypress(function (e) { + if (e.which == 13) { + e.preventDefault(); + addPasswordClick(); + } + }); + + $('#addpassword_form .submit').click( addPasswordClick ); +}; + +var setupChangePasswordFields = function() { + $('#changepassword_form .formfield.textinput .label').click( focusTextInput ); + $('#changepassword_form .formfield.textinput input').click( focusTextInput ); + $('#changepassword_form .formfield.textinput input').focus( hideTextLabel ); + $('#changepassword_form .formfield.textinput input').blur( onBlurTextInput ); + $('#changepassword_form .formfield.textinput input').change( testChangePasswordSubmitEnable ); + $('#changepassword_form .formfield.textinput input').keydown( function(e) { + if (e.which != 13) { + setTimeout( testChangePasswordSubmitEnable, 0 ); + } + }); + + $('#changepassword_form .formfield.textinput .pass_repeat').keypress(function (e) { + if (e.which == 13) { + e.preventDefault(); + changePasswordClick(); + } + }); + + $('#changepassword_form .submit').click( changePasswordClick ); + $('#changepassword_form .cancel').click( function() { + window.location.href="http://github.com/"; + }); +}; + +var loginClick = function( what ) { + $this = $(what); + var $form = $('#login_form'); + if ( pagemode === "logout" ) { + $form = $('#logout_form'); + } + + $form.find('.errormessage').css('visibility','hidden'); + $form.find('.pass').removeClass('error'); + $.post( + appurl + '/api/login', + { + password: $this.parent().find('.pass').val() + }, + function( data ) { + console.log( data ); + if( data.status === "success" ) { + var firstuse = ""; + if ( typeof getParams['firstuse'] !== 'undefined' ) { + firstuse = '?firstuse'; + } + window.location.href="http://github.com/app/coder" + firstuse; + } else { + $form.find('.errormessage').text( data.error ).css('visibility','visible'); + $form.find('.pass').addClass('error'); + } + } + ); +}; +*/ +var configureClick = function() { + $this = $(this); + var $form = $('#configure_form'); + + $form.find('.device_name').removeClass('error'); + var devicename = $this.parent().find('.device_name').val(); + + if ( !isValidDeviceName(devicename) ) { + $form.find('.device_name').addClass('error'); + return; + } + + $.post( + appurl + '/api/devicename/set', + { + device_name: devicename + }, + function( data ) { + console.log( data ); + if( data.status === "success" ) { + window.location.href="http://github.com/app/auth"; + } else { + $form.find('.device_name').addClass('error'); + } + } + ); +}; + +/* +var addPasswordClick = function() { + var $form = $('#addpassword_form'); + + $form.find('.pass, .pass_repeat').removeClass('error'); + $form.find('.errormessage').css('visibility','hidden'); + var pass = $form.find('.pass').val(); + var pass_repeat = $form.find('.pass_repeat').val(); + + if ( !isValidPassword(pass) ) { + $form.find('.pass').addClass('error'); + $form.find('.errormessage').text( getPasswordProblem(pass) ).css('visibility','visible'); + return; + } + if ( pass !== pass_repeat ) { + $form.find('.pass_repeat').addClass('error'); + $form.find('.errormessage').text( "new password does not match" ).css('visibility','visible'); + return; + } + + $.post( + appurl + '/api/addpassword', + { + password: pass + }, + function( data ) { + console.log( data ); + if( data.status === "success" ) { + var firstuse = ''; + if ( typeof getParams['firstuse'] !== 'undefined' ) { + firstuse = '?firstuse'; + } + window.location.href="http://github.com/app/auth" + firstuse; + } else { + $form.find('.pass').addClass('error'); + $form.find('.errormessage').text( data.error ).css('visibility','visible'); + } + } + ); +}; + + +var changePasswordClick = function() { + + var $form = $('#changepassword_form'); + + $form.find('.oldpass, .pass, .pass_repeat').removeClass('error'); + $form.find('.errormessage').css('visibility','hidden'); + var oldpass = $form.find('.oldpass').val(); + var pass = $form.find('.pass').val(); + var pass_repeat = $form.find('.pass_repeat').val(); + + if ( oldpass === "" ) { + $form.find('.oldpass').addClass('error'); + $form.find('.errormessage').text( "your current password is required" ).css('visibility','visible'); + return; + } + if ( !isValidPassword(pass) ) { + $form.find('.pass').addClass('error'); + $form.find('.errormessage').text( getPasswordProblem(pass) ).css('visibility','visible'); + return; + } + if ( pass !== pass_repeat ) { + $form.find('.pass_repeat').addClass('error'); + $form.find('.errormessage').text( "new password does not match" ).css('visibility','visible'); + return; + } + + $.post( + appurl + '/api/changepassword', + { + oldpassword: oldpass, + password: pass + }, + function( data ) { + console.log( data ); + if( data.status === "success" ) { + window.location.href="http://github.com/app/auth"; + } else { + $form.find('.oldpass').addClass('error'); + $form.find('.errormessage').text( data.error ).css('visibility','visible'); + } + } + ); +}; +*/ +var isValidDeviceName = function( name ) { + if ( !name || name === '' ) { + return false; + } + //starts with an ascii word char. can contain word char's spaces and ' + if ( !name.match(/^[a-zA-Z0-9][\w ']*$/) ) { + return false; + } + //ends in an ascii word char + if ( !name.match(/[a-zA-Z0-9]$/) ) { + return false; + } + return true; +}; + +/* +var getPasswordProblem = function( pass ) { + if ( !pass || pass === '' ) { + return "the password is empty"; + } + if ( pass.length < 6 ) { + return "the password should contain at least 6 characters"; + } + if ( !pass.match(/[a-z]/) || + !pass.match(/[A-Z0-9\-\_\.\,\;\:\'\"\[\]\{\}\!\@\#\$\%\^\&\*\(\)\\].*[A-Z0-9\-\_\.\,\;\:\'\"\[\]\{\}\!\@\#\$\%\^\&\*\(\)\\]/) ) { + return "your password must contain a lower case letter and at least two upper case letters or numbers"; + } +}; +var isValidPassword = function( pass ) { + if ( !pass || pass === '' ) { + return false; + } + //at least 6 characters + if ( pass.length < 6 ) { + return false; + } + //contains lower case + if ( !pass.match(/[a-z]/) ) { + return false; + } + //contains two upper case or numbers + if ( !pass.match(/[A-Z0-9\-\_\.\,\;\:\'\"\[\]\{\}\!\@\#\$\%\^\&\*\(\)\\].*[A-Z0-9\-\_\.\,\;\:\'\"\[\]\{\}\!\@\#\$\%\^\&\*\(\)\\]/) ) { + return false; + } + return true; +}; +*/ +var circles = []; +var $canvas; +var ctx; +var buildAnimation = function() { + circles = []; + $canvas = $("#animation"); + ctx = $canvas.get(0).getContext("2d"); + var w = $canvas.parent().width(); + var h = $canvas.parent().height(); + $canvas.attr('width', w); + $canvas.attr('height', h); + + for ( var x=0; x<20; x++ ) { + var sx = (Math.random() * (w+100)) - 50; + var sy = (Math.random() * 800) - 400; + var circle = { + sx: sx, + sy: sy, + x: sx, + y: sy, + r: (Math.random() * 150) + 30, + opacity: .2, + direction: Math.random() > .5? 1:-1 + }; + circles.push( circle ); + } +}; + +var updateAnimation = function() { + ctx.clearRect(0, 0, $canvas.width(), $canvas.height()); + for ( var x=0; x .9 ) { + circle.opacity = .9; + } + + circle.x += (Math.random() * .2) * circle.direction; + if ( circle.x < circle.sx - 250 ) { + circle.x = circle.sx - 250; + circle.direction=1; + } else if ( circle.x > circle.sx + 250 ) { + circle.x = circle.sx + 250; + circle.direction = -1; + } + + + } + setTimeout( updateAnimation, 1000/60 ); +}; + + + diff --git a/coder-apps/common/localauth/static/media/.gitignore b/coder-apps/common/localauth/static/media/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/coder-apps/common/localauth/views/index.html b/coder-apps/common/localauth/views/index.html new file mode 100644 index 00000000..bca909c6 --- /dev/null +++ b/coder-apps/common/localauth/views/index.html @@ -0,0 +1,109 @@ + + + + Coder + + + + + + + + + + + + + + + + + +
+ +
+
+
+ + + + +
+
+ + + + + + diff --git a/coder-apps/common/pop_up_penguins/app/app.js b/coder-apps/common/pop_up_penguins/app/app.js new file mode 100644 index 00000000..5e949e05 --- /dev/null +++ b/coder-apps/common/pop_up_penguins/app/app.js @@ -0,0 +1,30 @@ +exports.settings={}; +//These are dynamically updated by the runtime +//settings.appname - the app id (folder) where your app is installed +//settings.viewpath - prefix to where your view html files are located +//settings.staticurl - base url path to static assets /static/apps/appname +//settings.appurl - base url path to this app /app/appname +//settings.device_name - name given to this coder by the user, Ie."Billy's Coder" +//settings.coder_owner - name of the user, Ie. "Suzie Q." +//settings.coder_color - hex css color given to this coder. + +exports.get_routes = [ + { path:'/', handler:'index_handler' }, +]; + +exports.post_routes = [ +]; + + +exports.index_handler = function( req, res ) { + var tmplvars = {}; + tmplvars['static_url'] = exports.settings.staticurl; + tmplvars['app_name'] = exports.settings.appname; + tmplvars['app_url'] = exports.settings.appurl; + tmplvars['device_name'] = exports.settings.device_name; + + res.render( exports.settings.viewpath + '/index', tmplvars ); +}; + +exports.on_destroy = function() { +}; \ No newline at end of file diff --git a/coder-apps/common/pop_up_penguins/app/meta.json b/coder-apps/common/pop_up_penguins/app/meta.json new file mode 100644 index 00000000..9b118b5b --- /dev/null +++ b/coder-apps/common/pop_up_penguins/app/meta.json @@ -0,0 +1,8 @@ +{ + "created": "2013-12-17", + "modified": "2013-12-20", + "color": "#80d4ea", + "author": "Coder Team", + "name": "Pop-Up Penguins", + "hidden": false +} \ No newline at end of file diff --git a/coder-apps/common/pop_up_penguins/static/css/index.css b/coder-apps/common/pop_up_penguins/static/css/index.css new file mode 100644 index 00000000..7ed9d160 --- /dev/null +++ b/coder-apps/common/pop_up_penguins/static/css/index.css @@ -0,0 +1,186 @@ + +/*This style gives the body element in our HTML a cool blue background color*/ +body { + background-color: #ccf5f5; +} + +/*This styles the div in the HTML that contains and centers our penguin game*/ +#gameholder { + width: 600px; + margin-left: auto; + margin-right: auto; +} + +/*This styles the title div in or HTML*/ +#title { + width: 600px; + height: 150px; + /*This property embeds an image into the background of our div*/ + background-image:url('http://github.com/static/apps/pop_up_penguins/media/penguin_title.png'); +} + +/*This pseudo class is applied when the mouse hovers over the 1st penguin div*/ +.penguin1:hover { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_1_hover.png'); + /*This property changes our cursor to a pointer indicating an interactive element*/ + cursor: pointer; +} + +/*This pseudo class is applied when our 1st penguin div is clicked by the mouse button*/ +.penguin1:active { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/penguin_1.png'); +} + +/*This is the style for our 1st penguin div*/ +.penguin1 { + width: 200px; + height: 200px; + float: left; + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_1.png'); +} + +/*These are the styles for our 2nd penguin div.*/ + +.penguin2:hover { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_2_hover.png'); + cursor: pointer; +} + +.penguin2:active { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/penguin_2.png'); +} + +.penguin2 { + width: 200px; + height: 200px; + float: left; + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_2.png'); +} + +/*These are the styles for our 3rd penguin div.*/ + +.penguin3:hover { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_3_hover.png'); + cursor: pointer; +} + +.penguin3:active { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/penguin_3.png'); +} + +.penguin3 { + width: 200px; + height: 200px; + float: left; + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_3.png'); +} + +/*These are the styles for our 4th penguin div.*/ + +.penguin4:hover { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_4_hover.png'); + cursor: pointer; +} + +.penguin4:active { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/penguin_4.png'); +} + +.penguin4 { + width: 200px; + height: 200px; + float: left; + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_4.png'); +} + +/*These are the styles for our 5th penguin div.*/ + +.penguin5:hover { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_5_hover.png'); + cursor: pointer; +} + +.penguin5:active { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/penguin_5.png'); +} + +.penguin5 { + width: 200px; + height: 200px; + float: left; + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_5.png'); +} + +/*These are the styles for our 6th penguin div.*/ + +.penguin6:hover { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_6_hover.png'); + cursor: pointer; +} + +.penguin6:active { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/penguin_6.png'); +} + +.penguin6 { + width: 200px; + height: 200px; + float: left; + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_6.png'); +} + +/*These are the styles for our 7th penguin div.*/ + +.penguin7:hover { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_7_hover.png'); + cursor: pointer; +} + +.penguin7:active { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/penguin_7.png'); +} + +.penguin7 { + width: 200px; + height: 200px; + float: left; + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_7.png'); +} + +/*These are the styles for our 8th penguin div.*/ + +.penguin8:hover { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_8_hover.png'); + cursor: pointer; +} + +.penguin8:active { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/penguin_8.png'); +} + +.penguin8 { + width: 200px; + height: 200px; + float: left; + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_8.png'); +} + +/*These are the styles for our yeti div.*/ + +.yeti:hover { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_9_hover.png'); + cursor: pointer; +} + +.yeti:active { + background-image:url('http://github.com/static/apps/pop_up_penguins/media/yeti.png'); +} + +.yeti { + width: 200px; + height: 200px; + float: left; + background-image:url('http://github.com/static/apps/pop_up_penguins/media/mound_9.png'); +} + + diff --git a/coder-apps/common/pop_up_penguins/static/js/index.js b/coder-apps/common/pop_up_penguins/static/js/index.js new file mode 100644 index 00000000..45738ccd --- /dev/null +++ b/coder-apps/common/pop_up_penguins/static/js/index.js @@ -0,0 +1,10 @@ + +$(document).ready( function() { + + //This code will run after your page loads + + $(".yeti").mousedown(function() { + alert("Yaaaarrrr!"); + }); + +}); \ No newline at end of file diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_1.png b/coder-apps/common/pop_up_penguins/static/media/mound_1.png new file mode 100644 index 00000000..5db6d3fc Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_1.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_1_hover.png b/coder-apps/common/pop_up_penguins/static/media/mound_1_hover.png new file mode 100644 index 00000000..d87463e3 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_1_hover.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_2.png b/coder-apps/common/pop_up_penguins/static/media/mound_2.png new file mode 100644 index 00000000..79b4eddb Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_2.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_2_hover.png b/coder-apps/common/pop_up_penguins/static/media/mound_2_hover.png new file mode 100644 index 00000000..4235d7c1 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_2_hover.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_3.png b/coder-apps/common/pop_up_penguins/static/media/mound_3.png new file mode 100644 index 00000000..f92d0ab3 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_3.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_3_hover.png b/coder-apps/common/pop_up_penguins/static/media/mound_3_hover.png new file mode 100644 index 00000000..970ca6e9 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_3_hover.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_4.png b/coder-apps/common/pop_up_penguins/static/media/mound_4.png new file mode 100644 index 00000000..25a1c2fe Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_4.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_4_hover.png b/coder-apps/common/pop_up_penguins/static/media/mound_4_hover.png new file mode 100644 index 00000000..5c7a8274 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_4_hover.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_5.png b/coder-apps/common/pop_up_penguins/static/media/mound_5.png new file mode 100644 index 00000000..4e3c7a78 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_5.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_5_hover.png b/coder-apps/common/pop_up_penguins/static/media/mound_5_hover.png new file mode 100644 index 00000000..95cc58fb Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_5_hover.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_6.png b/coder-apps/common/pop_up_penguins/static/media/mound_6.png new file mode 100644 index 00000000..baf6a405 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_6.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_6_hover.png b/coder-apps/common/pop_up_penguins/static/media/mound_6_hover.png new file mode 100644 index 00000000..339f97b7 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_6_hover.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_7.png b/coder-apps/common/pop_up_penguins/static/media/mound_7.png new file mode 100644 index 00000000..590ce635 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_7.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_7_hover.png b/coder-apps/common/pop_up_penguins/static/media/mound_7_hover.png new file mode 100644 index 00000000..437654a0 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_7_hover.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_8.png b/coder-apps/common/pop_up_penguins/static/media/mound_8.png new file mode 100644 index 00000000..c16664fd Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_8.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_8_hover.png b/coder-apps/common/pop_up_penguins/static/media/mound_8_hover.png new file mode 100644 index 00000000..9cdd0bb3 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_8_hover.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_9.png b/coder-apps/common/pop_up_penguins/static/media/mound_9.png new file mode 100644 index 00000000..274a9eb6 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_9.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/mound_9_hover.png b/coder-apps/common/pop_up_penguins/static/media/mound_9_hover.png new file mode 100644 index 00000000..81fad57d Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/mound_9_hover.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/penguin_1.png b/coder-apps/common/pop_up_penguins/static/media/penguin_1.png new file mode 100644 index 00000000..433e6ae6 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/penguin_1.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/penguin_2.png b/coder-apps/common/pop_up_penguins/static/media/penguin_2.png new file mode 100644 index 00000000..34ad06af Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/penguin_2.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/penguin_3.png b/coder-apps/common/pop_up_penguins/static/media/penguin_3.png new file mode 100644 index 00000000..ce969cb5 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/penguin_3.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/penguin_4.png b/coder-apps/common/pop_up_penguins/static/media/penguin_4.png new file mode 100644 index 00000000..0f47d461 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/penguin_4.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/penguin_5.png b/coder-apps/common/pop_up_penguins/static/media/penguin_5.png new file mode 100644 index 00000000..3353affd Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/penguin_5.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/penguin_6.png b/coder-apps/common/pop_up_penguins/static/media/penguin_6.png new file mode 100644 index 00000000..93854d77 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/penguin_6.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/penguin_7.png b/coder-apps/common/pop_up_penguins/static/media/penguin_7.png new file mode 100644 index 00000000..c60eae51 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/penguin_7.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/penguin_8.png b/coder-apps/common/pop_up_penguins/static/media/penguin_8.png new file mode 100644 index 00000000..fc36c335 Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/penguin_8.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/penguin_title.png b/coder-apps/common/pop_up_penguins/static/media/penguin_title.png new file mode 100644 index 00000000..7b29cfae Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/penguin_title.png differ diff --git a/coder-apps/common/pop_up_penguins/static/media/yeti.png b/coder-apps/common/pop_up_penguins/static/media/yeti.png new file mode 100644 index 00000000..4110d78d Binary files /dev/null and b/coder-apps/common/pop_up_penguins/static/media/yeti.png differ diff --git a/coder-apps/common/pop_up_penguins/views/index.html b/coder-apps/common/pop_up_penguins/views/index.html new file mode 100644 index 00000000..fad1107b --- /dev/null +++ b/coder-apps/common/pop_up_penguins/views/index.html @@ -0,0 +1,43 @@ + + + + Coder + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/coder-apps/common/rva_coderdojo_matrix/app/app.js b/coder-apps/common/rva_coderdojo_matrix/app/app.js new file mode 100644 index 00000000..eb6c824e --- /dev/null +++ b/coder-apps/common/rva_coderdojo_matrix/app/app.js @@ -0,0 +1,65 @@ +/* + +Hello Coder! + +This is the Node.JS piece of your program. Unlike HTML, CSS, and JS, +this part of your program doesn't run in your web browser. Instead +it runs on your Raspberry Pi, and can do more advanced things like +save and retrieve data. Coders call this "back end" or "server side" +software, and HTML, JS, and CSS code is "front end" or "client side" +software. + +There are a ton of different languages for writing server side software, +but Coder's built to use one system, called Node.JS. Node.JS uses +the Javascript language for making server-side code. Because it's +Javascript, when you get to writing back end code, you'll find that +it's very similar to what you've learned in front end JS. + + +WHAT'S GOING ON HERE +This program contains just the default back end code. The index_handler +function in this program is used to send your HTML code from the +server to your web browser. That's it! + +Many demos in Coder look just like this in the Node.js file. To do +front end coding, you won't need to do a thing in Node. It's always +here, though, for when you get to making more advanced things. + +If you're new to Coder, don't bother changing anything in here. Yet... + +*/ + + +exports.settings={}; +//These are dynamically updated by the runtime +//settings.appname - the app id (folder) where your app is installed +//settings.viewpath - prefix to where your view html files are located +//settings.staticurl - base url path to static assets /static/apps/appname +//settings.appurl - base url path to this app /app/appname +//settings.device_name - name given to this coder by the user, Ie."Billy's Coder" +//settings.coder_owner - name of the user, Ie. "Suzie Q." +//settings.coder_color - hex css color given to this coder. + +exports.get_routes = [ + { path:'/', handler:'index_handler' }, +]; + +exports.post_routes = [ +]; + + +exports.index_handler = function( req, res ) { + var tmplvars = {}; + tmplvars['static_url'] = exports.settings.staticurl; + tmplvars['app_name'] = exports.settings.appname; + tmplvars['app_url'] = exports.settings.appurl; + tmplvars['device_name'] = exports.settings.device_name; + + res.render( exports.settings.viewpath + '/index', tmplvars ); +}; + +exports.on_destroy = function() { +}; + + + diff --git a/coder-apps/common/rva_coderdojo_matrix/app/meta.json b/coder-apps/common/rva_coderdojo_matrix/app/meta.json new file mode 100644 index 00000000..9613c6c9 --- /dev/null +++ b/coder-apps/common/rva_coderdojo_matrix/app/meta.json @@ -0,0 +1,8 @@ +{ + "created": "2013-05-08", + "modified": "2014-01-14", + "color": "#00cc00", + "author": "Macon Pegram", + "name": "RVA Coder Dojo", + "hidden": false +} \ No newline at end of file diff --git a/coder-apps/common/rva_coderdojo_matrix/static/css/index.css b/coder-apps/common/rva_coderdojo_matrix/static/css/index.css new file mode 100644 index 00000000..03177c00 --- /dev/null +++ b/coder-apps/common/rva_coderdojo_matrix/static/css/index.css @@ -0,0 +1,37 @@ +body { + margin: 0px; + background-color: #808080; +} + +/* This helps to center the matrix canvas in the middle of the screen. */ +#matrix-canvas-stack canvas { + margin: auto; /* Tells the browser to automatically size the margins */ + top: 0; + left: 0; + bottom: 0; + right: 0; + width: 90%; /* Scale the canvas larger or smaller as the browser window scales */ + max-width: 800px; /* Doesn't allows the canvas become greater than 800 pixels wide */ +} + +/* This style is used when the browser cannot do HTML 5 canvas */ +/* It styles how the non-animated image should be positioned */ +#matrix-fallback { + margin: auto; + top: 0; + left: 0; + bottom: 0; + right: 0; + width: 90%; + max-width: 800px; +} + +/* This is a color hack to make the Google Coder controls more prominent */ +#coder_basicnav { + color: rgba(238,238,0,.8); + background-color: rgba(0, 255, 0, .4); +} +#coder_basicnav .coder_home a { + color: rgba(238,238,0,.8); +} +/* End of color hack */ \ No newline at end of file diff --git a/coder-apps/common/rva_coderdojo_matrix/static/js/index.js b/coder-apps/common/rva_coderdojo_matrix/static/js/index.js new file mode 100644 index 00000000..3c4e85f8 --- /dev/null +++ b/coder-apps/common/rva_coderdojo_matrix/static/js/index.js @@ -0,0 +1,253 @@ +// The page must be loaded first before the script can run. +// This makes sure that the page is loaded first. +$(document).ready(function () { + // Check to see if the browser is capable of showing an HTML 5 canvas. + // If so we can do matrix rain! + if (!!window.HTMLCanvasElement) { + var matrixRain = new MatrixRain(); // Create a Javascript Object of MatrixRain + matrixRain.setImageURL(staticurl + '/media/rva-coderdojo-lg.png'); + + // Try changing this to see what happens! + matrixRain.setText("WELCOME TO THE RVA CODER DOJO"); + + // I wonder what happens if you change this number? + matrixRain.setFontSize(10); + + // Too fast or too slow? You are in control. + // Try changing this value. + matrixRain.setDelay(80); + + // Try different colors.. remember: + // - rgb(redColor, greenColor, blueColor) + // - Colors can go from 0 [dark] to 255 [bright] + // - So rgb(255, 0, 255) will be bright purple (red + blue). + // rgb(0, 255, 0) = Bright green + matrixRain.setFontColor('rgb(0, 255, 0)'); + + // Start running the matrix rain animation! + matrixRain.start(); + } + else + { + // If we can't add an HTML 5 canvas, just show the coder dojo non-animated image. + // Add a fallback image if canvas is not supported. + var fallback = document.createElement('img'); // Creates a regular tag. + fallback.id='matrix-fallback'; + fallback.src = staticurl + '/media/rva-coderdojo-nocanvas-lg.png'; + // Attaches the RVA coder dojo image to the page as a regular html + document.body.appendChild(fallback); + } +}); + +// Original matrix-rain code from: http://thecodeplayer.com/walkthrough/matrix-rain-animation-html5-canvas-javascript +// (refactored and enhanced by RVA Coder Dojo) + +// We are using a Javascript style of coding to create a call called "MatrixRain" here. +function MatrixRain (containerId) { + + // This will insert a
into the page and give it the id 'matrix-canvas-stack' + this.canvasStackDiv = document.createElement('div'); + this.canvasStackDiv.id='matrix-canvas-stack'; + + // If the user of this class passes in a containerId value, then we will place the + // 'matrix-canvas-stack' inside the provided container element in the page. + // this lets the user position the matrix rain logo wherever they want on the page. + if (containerId != null && document.getElementById(containerId) != null) { + this.container = document.getElementById(containerId); + this.container.appendChild(this.canvasStackDiv); + } + else // If not, we just drop the 'matrix-canvas-stack' as the last element in the page. + document.body.appendChild(this.canvasStackDiv); + + // These next values are defaults which can be changed using + // the set method defined later on. + + // this is the default speed for the rain. + this.renderDelay = 50; + + // This will be the URL for the overlay image (if you have one) default is no image. + this.imageURL = null; + + // This can be a link to jump to if the user clicks on the logo. default is none + this.gotoURL = null; + + // These are just random looking matrix characters by default. They can be changed. + this.matrixText = '田由甲申甴电甶男甸甹町画甼甽甾甿畀畁畂畃畄畅畆畇畈畉畊畋界畍畎畏畐畑'; + + // This is the default font size for the matrix rain letters. + this.fontSize=8; + + // This is the default color (bright green) + this.fontColor='rgb(0,255,0)'; +}; + +// Call setGotoURL to create a landing web page to go to when the user clicks on the rain. +MatrixRain.prototype.setGotoURL = function(gotoURL) { + if (gotoURL != null) { + this.gotoURL = gotoURL; + } +}; + +// Call setText to put your own secret message in the rain. +MatrixRain.prototype.setText = function (textIn) { + if (textIn != null) + this.matrixText = textIn; +}; + +// Call setDelay with a number. Bigger numbers make the rain animate slower. +// Smaller numbers make it go faster. +MatrixRain.prototype.setDelay = function (delayIn) { + if (delayIn != null && delayIn >= 0) + this.renderDelay = delayIn; +}; + +// Call setImageURL to create an overlay image for the rain. Only the transparent portions of +// the image will show the rain. +MatrixRain.prototype.setImageURL = function (imageURL) { + if (imageURL != undefined) + this.imageURL = imageURL; +}; + +// Call setFontSize to change how big or small the letters are that make up your secret message. +MatrixRain.prototype.setFontSize = function (fontSize) { + if (fontSize != undefined && fontSize > 0) + this.fontSize = fontSize; +}; + +// Call setFontColor to change what color the text is in your secret message. +MatrixRain.prototype.setFontColor = function (fontColor) { + if (fontColor != undefined) + this.fontColor = fontColor; +}; + +// This helps to resize the canvas. +MatrixRain.prototype.resize = function (width, height) { + this.matrixCanvas.width=width; + this.matrixCanvas.height= height; + if (this.matrixOverlay != undefined) { + this.matrixOverlay.width=width; + this.matrixOverlay.height=height; + } +}; + +// This creates an HTML 5 canvas element with the provided name (id), height and width. +MatrixRain.prototype.createCanvas = function (id, width, height) { + var newCanvas = document.createElement('canvas'); + newCanvas.id = id; + if (width != null) + newCanvas.width = width; + if (height != null) + newCanvas.height = height; + + // sets the alignment so the layers will overlap. + newCanvas.style.position="absolute"; + newCanvas.style.backgroundColor="transparent"; + + return newCanvas; +}; + +// This is the function to start the matrix rain animation. Call it +// after you have created a MatrixRain javascript object, and called +// all the setters you want to configure your rain. For example: +// var matrixRain = new MatrixRain(); +// matrixRain.setText('Hello World'); +// matrixRain.setFontSize(12); +// matrixRain.start(); +MatrixRain.prototype.start = function() { + this.matrixCanvas = this.createCanvas('matrix-canvas'); + this.matrixCanvas.style.zIndex=0; + this.matrixCanvas.style.background="black"; + this.canvasStackDiv.appendChild(this.matrixCanvas); + if (this.imageURL != null) { + img = new Image(); + img.matrix = this; + img.onerror = function() { + this.matrix.startRain(); + window.console && console.log('Could not load image: ' + this.imageURL); + }; + img.onload = function() { + this.matrix.addOverlay(img); + this.matrix.startRain(); + }; + img.src = this.imageURL; + } + else { + this.startRain(); + } +}; + +// This function adds the overlay image as an HTML 5 canvas on top of the rain animation +// It is sized to be the same height and width as the rain animation. +MatrixRain.prototype.addOverlay = function(image) { + this.matrixOverlay = this.createCanvas('matrix-overlay', image.width, image.height); + this.matrixOverlay.style.zIndex=10; + this.canvasStackDiv.appendChild(this.matrixOverlay); + this.resize(image.width, image.height); + var context = this.matrixOverlay.getContext('2d'); + context.drawImage(image, 0,0); +}; + +// This will do the initial setup for the matrix rain data. +MatrixRain.prototype.startRain = function() { + this.mtxCtx = this.matrixCanvas.getContext('2d'); + + this.matrixText = this.matrixText.split(""); + + // How many characters across the canvas + this.columns = this.matrixCanvas.width / this.fontSize; + this.drops = []; + + // Where to start in the matrix code + // This allows for readable text messages to rain down. + this.textIndex = []; + + for (var x = 0; x < this.columns; x++) { + this.drops[x] = this.matrixCanvas.height + 1; + this.textIndex[x] = Math.floor(Math.random() * this.matrixText.length); + } + + // this is a poor hack to attach to the global namespace for the callback + window.MatrixRainInstance = this; + + // This sets a timer to wait until "renderDelay" expires + // then call the "render()" function (defined below) + // this process repeats forever until the user leaves the page. + setInterval(this.render, this.renderDelay); +}; + +// This function is the animation for the matrix rain. +MatrixRain.prototype.render = function() { + + // This gets access to the matrix rain class + var _this = window.MatrixRainInstance; + + // Fill the canvas with a very transparent black. + // This is what causes the letters to slowly fade out. + _this.mtxCtx.fillStyle="rgba(0,0,0,0.05)"; + _this.mtxCtx.fillRect(0, 0, _this.matrixCanvas.width, _this.matrixCanvas.height); + + // Now set the color and font size for the matrix text + _this.mtxCtx.fillStyle = _this.fontColor; + _this.mtxCtx.font = _this.fontSize + "px arial"; + + // Loop over each of the drops + for (var i=0; i < _this.drops.length; i++) { + + // Start adding text to the canvas + _this.textIndex[i] = (_this.textIndex[i] + 1) % _this.matrixText.length; + var text = _this.matrixText[_this.textIndex[i]]; + + // x = i * fontSize, y = value of drops[i]*fontSize + _this.mtxCtx.fillText(text, i*_this.fontSize, _this.drops[i]*_this.fontSize); + + // reset a drop after it hits the bottom and have it start to drop from the top. + if (_this.drops[i] * _this.fontSize > _this.matrixCanvas.height && Math.random() > 0.875) { + _this.drops[i] = 0; + } + + // bump Y coordinate + _this.drops[i]++; + } +}; + + diff --git a/coder-apps/common/rva_coderdojo_matrix/static/media/rva-coderdojo-lg.png b/coder-apps/common/rva_coderdojo_matrix/static/media/rva-coderdojo-lg.png new file mode 100644 index 00000000..5e281824 Binary files /dev/null and b/coder-apps/common/rva_coderdojo_matrix/static/media/rva-coderdojo-lg.png differ diff --git a/coder-apps/common/rva_coderdojo_matrix/static/media/rva-coderdojo-nocanvas-lg.png b/coder-apps/common/rva_coderdojo_matrix/static/media/rva-coderdojo-nocanvas-lg.png new file mode 100644 index 00000000..cd1160d7 Binary files /dev/null and b/coder-apps/common/rva_coderdojo_matrix/static/media/rva-coderdojo-nocanvas-lg.png differ diff --git a/coder-apps/common/rva_coderdojo_matrix/views/index.html b/coder-apps/common/rva_coderdojo_matrix/views/index.html new file mode 100644 index 00000000..cbba670e --- /dev/null +++ b/coder-apps/common/rva_coderdojo_matrix/views/index.html @@ -0,0 +1,31 @@ + + + + + RVA Coders + + + + + + + + + + + + + + + + + + + + diff --git a/coder-apps/install_all.cmd b/coder-apps/install_all.cmd new file mode 100644 index 00000000..9ede89ea --- /dev/null +++ b/coder-apps/install_all.cmd @@ -0,0 +1,21 @@ +@echo off +if =%1-==-- echo "Usage: install_all.cmd [coderbase]" & exit /b + +set base=%1 + +REM Create base folder +IF NOT EXIST %base% ( + mkdir %base% +) + +echo "Copying base files...." +xcopy ..\coder-base\*.* %base% /E + +echo "Installing common files" +call install_common.cmd %base% + +echo "Preparing dependent libraries" +cd %base% + +REM Note this isn't going to work because npm isn't installed +REM node\npm install \ No newline at end of file diff --git a/coder-apps/install_all.sh b/coder-apps/install_all.sh new file mode 100755 index 00000000..24049aa1 --- /dev/null +++ b/coder-apps/install_all.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +## +## Copies the common platform apps to +## the coder-base working directory. +## +## sh install_all base_path +## +## Eg. +## sh install_all ../coder-base/ + +if [ $# != 1 ] + then + echo -e "\nUse:\ninstall_all coderbase\n" + exit +fi + +base=$1 + +## Setup the base installation folder. +mkdir -p $base + +## Create basic install +cp -r ../coder-base/* $base/ +./install_common.sh $base + +## Using the base folder's copy of npm perform the necessary library pulls. +echo "Preparing dependent libraries" +cd $base +./node/bin/npm install + + diff --git a/coder-apps/install_app.cmd b/coder-apps/install_app.cmd new file mode 100644 index 00000000..fbf30b20 --- /dev/null +++ b/coder-apps/install_app.cmd @@ -0,0 +1,20 @@ +@echo off +if =%3-==-- echo "Usage: install_app.cmd [appname] [coderbase] [apppath]" & exit /b + +set app=%1 +set base=%2 +set from=%3 + + +mkdir %base%\apps\%app% +mkdir %base%\static\apps\%app% +mkdir %base%\static\apps\%app%\js +mkdir %base%\static\apps\%app%\css +mkdir %base%\static\apps\%app%\media +mkdir %base%\views\apps\%app% + +copy %from%\%app%\app\*.* %base%\apps\%app% +copy %from%\%app%\views\*.* %base%\views\apps\%app% +copy %from%\%app%\static\js\*.* %base%\static\apps\%app%\js +copy %from%\%app%\static\css\*.* %base%\static\apps\%app%\css +copy %from%\%app%\static\media\*.* %base%\static\apps\%app%\media \ No newline at end of file diff --git a/coder-apps/install_app.sh b/coder-apps/install_app.sh index 774a328a..23b92983 100755 --- a/coder-apps/install_app.sh +++ b/coder-apps/install_app.sh @@ -19,12 +19,12 @@ app=$1 base=$2 from=$3 -mkdir "$base/apps/$app" -mkdir "$base/static/apps/$app" -mkdir "$base/static/apps/$app/js" -mkdir "$base/static/apps/$app/css" -mkdir "$base/static/apps/$app/media" -mkdir "$base/views/apps/$app" +mkdir -p "$base/apps/$app" +mkdir -p "$base/static/apps/$app" +mkdir -p "$base/static/apps/$app/js" +mkdir -p "$base/static/apps/$app/css" +mkdir -p "$base/static/apps/$app/media" +mkdir -p "$base/views/apps/$app" cp $from/$app/app/* $base/apps/$app/ cp $from/$app/views/* $base/views/apps/$app/ diff --git a/coder-apps/install_common.cmd b/coder-apps/install_common.cmd new file mode 100644 index 00000000..bc8fc989 --- /dev/null +++ b/coder-apps/install_common.cmd @@ -0,0 +1,57 @@ +@echo off +if =%1-==-- echo "Usage: install_common.cmd [coderbase]" & exit /b + +echo "Creating folders...." + +set base=%1 + +REM Create base folders +IF NOT EXIST %base% ( + mkdir %base% +) + +if NOT EXIST %base%\apps ( + mkdir %base%\apps +) + +if NOT EXIST %base%\static ( + mkdir %base%\static +) + +if NOT EXIST %base%\static\apps ( + mkdir %base%\static\apps +) + +if NOT EXIST %base%\views ( + mkdir %base%\views +) + +if NOT EXIST %base%\views\apps ( + mkdir %base%\views\apps +) + +echo "Copying apps" + +call install_app.cmd auth %base% .\common\ +call install_app.cmd boilerplate %base% .\common\ +call install_app.cmd coder %base% .\common\ +call install_app.cmd coderlib %base% .\common\ +call install_app.cmd editor %base% .\common\ +call install_app.cmd eyeball %base% .\common\ +call install_app.cmd game2d %base% .\common\ +call install_app.cmd hello_coder %base% .\common\ +call install_app.cmd space_rocks_ %base% .\common\ +call install_app.cmd localauth %base% .\common\ + +REM RVA Coder Dojo extra bundles +call install_app.cmd pop_up_penguins %base% .\common\ +call install_app.cmd comic_creator %base% .\common\ +call install_app.cmd rva_coderdojo_matrix %base% .\common\ + +REM Assets for other projects used in RVA Coder Dojo +if NOT EXIST %base%\project-assets ( + mkdir %base%\project-assets +) +xcopy ..\project-assets\*.* %base%\project-assets /E + +echo "Copy completed" diff --git a/coder-apps/install_common.sh b/coder-apps/install_common.sh index a2ba85e8..3d860524 100755 --- a/coder-apps/install_common.sh +++ b/coder-apps/install_common.sh @@ -26,4 +26,14 @@ base=$1 ./install_app.sh game2d $base ./common/ ./install_app.sh hello_coder $base ./common/ ./install_app.sh space_rocks_ $base ./common/ +./install_app.sh localauth $base ./common/ + +## RVA Coder Dojo extra bundles +./install_app.sh pop_up_penguins $base ./common/ +./install_app.sh comic_creator $base ./common/ +./install_app.sh rva_coderdojo_matrix $base ./common/ + +## Assets for other projects used in RVA Coder Dojo +mkdir -p $base/project-assets +cp -r ../project-assets/* $base/project-assets diff --git a/coder-base/config.js b/coder-base/config.js index 19052a53..f4c5f53b 100644 --- a/coder-base/config.js +++ b/coder-base/config.js @@ -1,7 +1,7 @@ exports.listenIP = null; //Defaults to * -exports.listenPort = '8081'; //the SSL port things run on -exports.httpListenPort = '8080'; //this will all be redirected to SSL +exports.listenPort = '9081'; //the SSL port things run on +exports.httpListenPort = '9080'; //this will all be redirected to SSL exports.cacheApps = true; exports.httpVisiblePort = '80'; //forwarded http port the user sees exports.httpsVisiblePort = '443'; //forwarded https port the user sees diff --git a/coder-base/localserver.js b/coder-base/localserver.js index 1ef8034f..f06c1122 100644 --- a/coder-base/localserver.js +++ b/coder-base/localserver.js @@ -20,7 +20,6 @@ var express = require('express'); -var io = require('socket.io'); var net = require('http'); var http = require('http'); var https = require('https'); @@ -64,15 +63,18 @@ var apphandler = function( req, res, appdir ) { util.log( "GET: " + apppath + " " + appname ); + auth = require(appdir + "localauth" + "/app"); + + /* Disabling authentication requirement. */ //Redirect to sign-in for unauthenticated users - publicAllowed = ["auth"]; //apps that are exempt from any login (should only be auth) - auth = require(appdir + "auth" + "/app"); - user = auth.isAuthenticated(req, res); - if ( !user && publicAllowed.indexOf( appname ) < 0) { - util.log("redirect: " + "http://" + getHost(req) + ":" + config.httpVisiblePort + '/app/auth'); - res.redirect("http://" + getHost(req) + ":" + config.httpVisiblePort + '/app/auth' ); - return; - } +// publicAllowed = ["auth"]; //apps that are exempt from any login (should only be auth) +// auth = require(appdir + "auth" + "/app"); +// user = auth.isAuthenticated(req, res); +// if ( !user && publicAllowed.indexOf( appname ) < 0) { +// util.log("redirect: " + "http://" + getHost(req) + ":" + config.httpVisiblePort + '/app/auth'); +// res.redirect("http://" + getHost(req) + ":" + config.httpVisiblePort + '/app/auth' ); +// return; +// } if ( !apppath ) { @@ -133,7 +135,8 @@ var apphandler = function( req, res, appdir ) { var startLocal = function() { - http.createServer(localapp).listen( config.httpListenPort, '127.0.0.1' ); + http.createServer(localapp).listen( config.httpListenPort, 'localhost' ); + console.log('Listening on: http://127.0.0.1:' + config.httpListenPort); }; var getHost = function( req ) { @@ -162,7 +165,7 @@ localapp.use( express.session({ localapp.use( '/static', express.static( __dirname + '/static' ) ); localapp.get( '/', function( req, res ) { util.log( 'GET: /' ); - res.redirect( '/app/auth' ); + res.redirect( '/app/localauth' ); }); localapp.all( /^\/app\/(\w+)\/(.*)$/, function( req, res ) { apphandler( req, res, __dirname + '/apps/'); } ); localapp.all( /^\/app\/(\w+)\/$/, function( req, res ) { apphandler( req, res, __dirname + '/apps/'); } ); diff --git a/coder-base/package.json b/coder-base/package.json index e42be37a..fbc4b1d9 100644 --- a/coder-base/package.json +++ b/coder-base/package.json @@ -8,9 +8,8 @@ "redis": "0.8.2", "mustache": "0.7.2", "consolidate": "0.8.0", - "socket.io": "0.9.13", "express-params": "0.0.3", - "bcrypt": "0.7.4", + "bcrypt-nodejs": "*", "connect": "*", "cookie": "*" } diff --git a/coderdojo/nodejs/node-mac.tar.gz b/coderdojo/nodejs/node-mac.tar.gz new file mode 100644 index 00000000..0cff16dc Binary files /dev/null and b/coderdojo/nodejs/node-mac.tar.gz differ diff --git a/coderdojo/nodejs/node.exe b/coderdojo/nodejs/node.exe new file mode 100644 index 00000000..324fb8ce Binary files /dev/null and b/coderdojo/nodejs/node.exe differ diff --git a/coderdojo/scripts/run-coder.cmd b/coderdojo/scripts/run-coder.cmd new file mode 100644 index 00000000..a2af2d9a --- /dev/null +++ b/coderdojo/scripts/run-coder.cmd @@ -0,0 +1,3 @@ +@echo off +echo "Open your browser to the address shown below." +node\node localserver.js \ No newline at end of file diff --git a/coderdojo/scripts/run-coder.sh b/coderdojo/scripts/run-coder.sh new file mode 100644 index 00000000..c0c0bb3b --- /dev/null +++ b/coderdojo/scripts/run-coder.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +echo "Open your browser to the address shown below." +node/bin/node localserver.js diff --git a/project-assets/comic_creator/baby.jpg b/project-assets/comic_creator/baby.jpg new file mode 100644 index 00000000..ba0b9648 Binary files /dev/null and b/project-assets/comic_creator/baby.jpg differ diff --git a/project-assets/comic_creator/landscape.jpg b/project-assets/comic_creator/landscape.jpg new file mode 100644 index 00000000..10aa0b92 Binary files /dev/null and b/project-assets/comic_creator/landscape.jpg differ diff --git a/project-assets/comic_creator/penguin.jpg b/project-assets/comic_creator/penguin.jpg new file mode 100644 index 00000000..e31998eb Binary files /dev/null and b/project-assets/comic_creator/penguin.jpg differ diff --git a/project-assets/comic_creator/running.jpg b/project-assets/comic_creator/running.jpg new file mode 100644 index 00000000..f333ff44 Binary files /dev/null and b/project-assets/comic_creator/running.jpg differ diff --git a/project-assets/comic_creator/sleds.jpg b/project-assets/comic_creator/sleds.jpg new file mode 100644 index 00000000..11d490ab Binary files /dev/null and b/project-assets/comic_creator/sleds.jpg differ diff --git a/project-assets/the_perfect_sandwich/the_perfect_pbj.jpg b/project-assets/the_perfect_sandwich/the_perfect_pbj.jpg new file mode 100644 index 00000000..3404d49b Binary files /dev/null and b/project-assets/the_perfect_sandwich/the_perfect_pbj.jpg differ