diff --git a/LICENSE.txt b/LICENSE.txt index e8e6d61f..21ecb266 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,5 +1,4 @@ -Nodester (http://nodester.com) is a Node.JS Hosting Platform-as-a-Service (PaaS) -Copyright (C) 2011 Chris Matthieu (contact info: chris@nodester.com) +Copyright (C) 2011 Chris Matthieu (Contact: chris@nodester.com) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -13,4 +12,4 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see http://www.gnu.org/licenses/agpl-3.0.html. -http://www.gnu.org/licenses/why-affero-gpl.html \ No newline at end of file +http://www.gnu.org/licenses/why-affero-gpl.html diff --git a/README.rd b/README.rd deleted file mode 100644 index 81dca640..00000000 --- a/README.rd +++ /dev/null @@ -1,133 +0,0 @@ -= Nodester is an Open Source Node.JS Hosting Platform with a RESTful API and CLI - -Nodester is a free and open source Node.JS hosting platform and service for managing multi-tenant hosted NodeJS apps. It consists of an RESTful API that allows developers to create and manage NodeJS apps online as well as a command line interface to simply steps instead of using cURL. NodeJS apps names are assigned as subdomains that proxy to ports with an assigned addresses. Git is used to push updates to Nodester and instances (dynos) are launched using post-receive hooks so that they run until you stop them. - -Give our platform a spin at http://nodester.com - -== Installing Nodester on Amazon EC2, Rackspace, GoGrid, or your own datacenter services - -Please see install.txt for setup instructions (https://github.com/nodester/nodester/blob/master/install.txt) - -== RESTful API Documentation - - COUPON - /coupon - creates coupon request for early access (pass in email) - Note: This resource does not use base api url - curl -X POST -d "email=chris@nodester.com" http://localhost:8080/coupon - - STATUS - /status - returns status of the platform and number of nodejs apps running - // curl http://api.localhost:8080/status - - USER - /user - creates user account (pass in user and password and email) - Note: This resource does not use the api subdomain - curl -X POST -d "user=testuser&password=123&email=chris@nodester.com" http://localhost:8080/user - - /user - delete user account (requires basic auth) - curl -X DELETE -u "testuser:123" http://api.localhost:8080/user - - APP - /app - create nodejs app for hosting (requires basic auth and returns the port address required for use along with a git repo to push to) - curl -X POST -u "testuser:123" -d "appname=a&start=hello.js" http://api.localhost:8080/app - - Get information about an app - curl -u "testuser:123" http://api.localhost:8080/app/a - - Start or stop an app using running=true|false - curl -X POST -u "testuser:123" -d "appname=a&running=true" http://api.localhost:8080/app - curl -X POST -u "testuser:123" -d "appname=a&running=false" http://api.localhost:8080/app - - /app - update nodejs app for hosting (requires basic auth, appname, and starting page and returns the port address required for use along with a git repo to push to) - curl -X PUT -u "testuser:123" -d "appname=a&start=hello1.js" http://api.localhost:8080/app - - /app - delete nodejs app (requires basic auth and appname) - curl -X DELETE -u "testuser:123" -d "appname=test" http://api.localhost:8080/app - - /app - get nodejs app info (requires basic auth and appname) - curl -u "testuser:123" http://api.localhost:8080/app/appname - - /apps - get all your apps info (requires basic auth) - curl -u "testuser:123" http://api.localhost:8080/apps - - ENV - /env - create/update environment key/value pair (requires basic auth, appname, and environment key and value) - curl -X PUT -u "testuser:123" -d "appname=a&key=color&value=blue" http://api.nodester.com/env - - /env - delete environment key/value pair (requires basic auth, appname, and environment key) - curl -X DELETE -u "testuser:123" -d "appname=test&key=color" http://api.nodester.com/env - - /env - get environment info (requires basic auth, appname) - curl -u "testuser:123" http://api.nodester.com/env/appname - - NPM - /npm - install, update and uninstall npm packages to your application - curl -X POST -u "testuser:123" -d "appname=a&action=install&package=express" http://api.localhost:8080/npm - curl -X POST -u "testuser:123" -d "appname=a&action=update&package=express" http://api.nodester.com/npm - curl -X POST -u "testuser:123" -d "appname=a&action=uninstall&package=express" http://api.nodester.com/npm - -== CLI Documentation - -Installation of our Command Line Interface is simple using NPM. - - npm install nodester-cli -g - -Operations are as simple as nodester . Here is a list of the commands available today: - - nodester coupon - nodester user create - nodester user setup - - The commands below require you to have run 'user setup' before/ - nodester user setpass - - You should run user setup after running setpass: - nodester user setkey - nodester apps list - nodester app create - nodester app info - nodester app logs - nodester app start - nodester app restart - nodester app stop - nodester npm install - nodester npm upgrade - nodester npm uninstall - nodester appdomain add - nodester appdomain delete - -== Testing Locally - -Subdomains can be tested locally by editing /etc/hosts like this: -127.0.0.1 localhost a.localhost b.localhost c.localhost -save etc/hosts and flush DNS like this: sudo dscacheutil -flushcache - - http://localhost:80 = Homepage - http://a.localhost:80 = Runs app associated with subdomain a on couch-configured port - http://b.localhost:80 = Runs app associated with subdomain b on couch-configured port - http://chris:123@api.localhost:80/status = API to list status of all node apps - -== Todos - -We are always looking for areas to improve Nodester! Here are a few of the big ideas on our list - -* Setup public AMI running Nodester -* Ability to start app with additional instances (dynos) -* Horizontal scaling - -Feel free to suggest improvements at https://github.com/nodester/nodester/issues - -== Core Team Members - -@ChrisMatthieu (http://twitter.com/chrismatthieu) -@DanBUK (http://twitter.com/danbuk) -@Marcosvm (http://twitter.com/marcosvm) -@WeAreFractal (http://twitter.com/wearefractal) - -If this project inspires you, please feel free to help out by forking this project and sending us pull requests! \m/ -http://github.com/nodester - -== Need Help? - -Hit us up in IRC at irc.freenode.net #nodester or http://irc.nodester.com -You can also ask questions and provide feedback in our google group at http://groups.google.com/group/nodester - - diff --git a/app.js b/app.js deleted file mode 100755 index 350fe890..00000000 --- a/app.js +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env node - -/* - -Nodester opensource Node.js hosting service - -Written by: @ChrisMatthieu & @DanBUK -http://nodester.com - -*/ -require('coffee-script'); - -var express = require('express'), - url = require('url'), - sys = require('sys'), - config = require('./config'), - middle = require('./lib/middle') - nodeinfo = require('nodeinfo'); - -process.on('uncaughtException', function(err) { - console.log(err.stack); -}); - -var daemon = require('daemon'); -// daemon.setreuid(config.opt.userid); -var myapp = express.createServer(); - -myapp.configure(function() { - myapp.use(express.bodyParser()); - myapp.use(express.static(config.opt.public_html_dir)); - myapp.use(middle.error()); -}); - -// Routes -// Homepage -myapp.get('/', function(req, res, next) { - res.render('index.html'); -}); - -myapp.get('/api', function(req, res, next) { - res.redirect('/api.html'); -}); - -myapp.get('/admin', function(req, res, next) { - res.redirect('http://admin.nodester.com'); -}); - -myapp.get('/irc', function(req, res, next) { - res.redirect('http://irc.nodester.com'); -}); - -myapp.get('/monitor', function(req, res, next) { - res.redirect('http://site.nodester.com'); -}); - -// Status API -// http://localhost:4001/status -// curl http://localhost:4001/status -var status = require('./lib/status'); -myapp.get('/status', status.get); - -// New coupon request -// curl -X POST -d "email=dan@nodester.com" http://localhost:4001/coupon -var coupon = require('./lib/coupon'); -myapp.post('/coupon', coupon.post); - -// curl http://localhost:4001/unsent -myapp.get('/unsent', coupon.unsent); - - -// New user account registration -// curl -X POST -d "user=testuser&password=123&email=chris@nodefu.com&coupon=hiyah" http://localhost:4001/user -// curl -X POST -d "user=me&password=123&coupon=hiyah" http://localhost:4001/user -var user = require('./lib/user'); -myapp.post('/user', user.post); - -// localhost requires basic auth to access this section -// Edit your user account -// curl -X PUT -u "testuser:123" -d "password=test&rsakey=1234567" http://localhost:4001/user -myapp.put('/user', middle.authenticate, user.put); - -// Delete your user account -// curl -X DELETE -u "testuser:123" http://localhost:4001/user -myapp.delete('/user', middle.authenticate, user.delete); - -// All Applications info -// http://chris:123@localhost:4001/apps -// curl -u "testuser:123" http://localhost:4001/apps -var apps = require('./lib/apps'); -myapp.get('/apps', middle.authenticate, apps.get); - - -var app = require('./lib/app'); -// Application info -// http://chris:123@localhost:4001/app/ -// curl -u "testuser:123" http://localhost:4001/app/ -myapp.get('/app/:appname', middle.authenticate, middle.authenticate_app, app.get); - -// Create node app -// curl -X POST -u "testuser:123" -d "appname=test&start=hello.js" http://localhost:4001/apps -myapp.post('/app', middle.authenticate, app.post); - - -// App backend restart handler -myapp.get('/app_restart', app.app_restart); -myapp.get('/app_start', app.app_start); -myapp.get('/app_stop', app.app_stop); - -// Update node app -// start=hello.js - To update the initial run script -// running=true - To Start the app -// running=false - To Stop the app -// curl -X PUT -u "testuser:123" -d "appname=test&start=hello.js" http://localhost:4001/app -// curl -X PUT -u "testuser:123" -d "appname=test&running=true" http://localhost:4001/app -// curl -X PUT -u "testuser:123" -d "appname=test&running=false" http://localhost:4001/app -// curl -X PUT -u "testuser:123" -d "appname=test&running=restart" http://localhost:4001/app -// TODO - Fix this function, it's not doing callbacking properly so will return JSON in the wrong state! -myapp.put('/app', middle.authenticate, middle.authenticate_app, app.put); - -// Delete your nodejs app -// curl -X DELETE -u "testuser:123" -d "appname=test" http://localhost:4001/apps -myapp.delete('/app', middle.authenticate, middle.authenticate_app, app.delete); - - -myapp.delete('/gitreset', middle.authenticate, middle.authenticate_app, app.gitreset); - -// curl -u "testuser:123" -d "appname=test" http://localhost:4001/applogs -myapp.get('/applogs/:appname', middle.authenticate, middle.authenticate_app, app.logs); - -// Retrieve information about or update a node app's ENV variables -// This fulfills all four RESTful verbs. -// GET will retrieve the list of all keys. -// PUT will either create or update. -// DELETE will delete the key if it exists. -// curl -u GET -u "testuser:123" -d "appname=test" http://localhost:4001/env -// curl -u PUT -u "testuser:123" -d "appname=test&key=NODE_ENV&value=production" http://localhost:4001/env -// curl -u DELETE -u "testuser:123" -d "appname=test&key=NODE_ENV" http://localhost:4001/env -myapp.get('/env/:appname', middle.authenticate, middle.authenticate_app, app.env_get); -myapp.put('/env', middle.authenticate, middle.authenticate_app, app.env_put); -myapp.delete('/env', middle.authenticate, middle.authenticate_app, app.env_delete); - -// APP NPM Handlers -var npm = require('./lib/npm'); -// curl -X POST -u "testuser:123" -d "appname=test&package=express" http://localhost:4001/appnpm -// curl -X POST -u "testuser:123" -d "appname=test&package=express" http://localhost:4001/npm -// curl -X POST -u "testuser:123" -d "appname=test&package=express,express-extras,foo" http://localhost:4001/npm -myapp.post('/appnpm', middle.authenticate, middle.authenticate_app, npm.post); -myapp.post('/npm', middle.authenticate, middle.authenticate_app, npm.post); - -// curl -X POST -u "testuser:123" -d "appname=test&domain=" http://localhost:4001/appdomains -// curl -X DELETE -u "testuser:123" -d "appname=test&domain=" http://localhost:4001/appdomains -var domains = require('./lib/domains'); -myapp.post('/appdomains', middle.authenticate, middle.authenticate_app, domains.post); -myapp.delete('/appdomains', middle.authenticate, middle.authenticate_app, domains.delete); -myapp.get('/appdomains', middle.authenticate, domains.get); - -// curl -X POST -d "user=username" http://localhost:4001/reset_password -// curl -X PUT -d "password=newpassword" http://localhost:4001/reset_password/ -var reset_password = require('./lib/reset_password'); -myapp.post('/reset_password', reset_password.post); -myapp.put('/reset_password/:token', reset_password.put); - -myapp.use(express.errorHandler({ - showStack: true -})); -myapp.listen(4001); -console.log('Nodester app started on port 4001'); - -nodeinfo.broadcast(13377); -console.log('NodeInfo monitor started on port 13377'); \ No newline at end of file diff --git a/bin/app_start.sh b/bin/app_start.sh deleted file mode 100755 index c13aac34..00000000 --- a/bin/app_start.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -cd `dirname $0` - -./node-config.js -wait -source ./.nodester.config -rm ./.nodester.config - -export HOME=$HOME_DIR; -export PATH="/usr/local/bin:${HOME}/bin:${PATH}"; - -APPDIR=$APP_DIR -FHOME=$HOME/forever-app - -if [ ! -d $FHOME ]; then - mkdir -p $FHOME/logs - mkdir -p $FHOME/pids -fi - -if [ -f $FHOME/logs/forever.log ]; then - rm -rRf $FHOME/logs/forever.log -fi - - -wait -forever start -l logs/forever.log -o $FHOME/logs/app-out.log -e $FHOME/logs/app-err.log -d $APPDIR -p $FHOME $APPDIR/app.js -wait -forever list -p $FHOME $APPDIR/app.js diff --git a/bin/app_stop.sh b/bin/app_stop.sh deleted file mode 100755 index 8384fc93..00000000 --- a/bin/app_stop.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -cd `dirname $0` - -./node-config.js -wait -source ./.nodester.config -rm ./.nodester.config - -export HOME=$HOME_DIR; -export PATH="/usr/local/bin:${HOME}/bin:${PATH}"; - -APPDIR=$APP_DIR - - -FHOME=$HOME/forever-app - -forever stopall -p $FHOME - -sleep 1 diff --git a/bin/create_user_dir.js b/bin/create_user_dir.js deleted file mode 100755 index dc031faa..00000000 --- a/bin/create_user_dir.js +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env node - -var exec = require('child_process').exec; -var config = require('../config.js').opt; - -var dirs_string = config.git_home_dir + '/' + process.argv[2] + ' ' + config.apps_home_dir + '/' + process.argv[2]; - -var cmds = ['mkdir ' + dirs_string, 'chown ' + config.git_user + ':' + config.app_uid + ' ' + dirs_string, 'chmod 0775 ' + dirs_string - -]; - -var do_cmd = function () { - if (cmds.length > 0) { - var cmd = cmds.shift(); - console.log('Running: ' + cmd); - exec(cmd, function () { - do_cmd(); - }); - } - }; -do_cmd(); \ No newline at end of file diff --git a/bin/forever-app b/bin/forever-app deleted file mode 100755 index 534a360f..00000000 --- a/bin/forever-app +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -cd `dirname $0` - -./node-config.js -wait -source ./.nodester.config - -export HOME=$HOME_DIR; -export PATH="/usr/local/bin:${PATH}"; - -FHOME=$HOME/forever-app/ - -forever "$@" -p $FHOME - diff --git a/bin/forever-proxy b/bin/forever-proxy deleted file mode 100755 index 84bae00d..00000000 --- a/bin/forever-proxy +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -cd `dirname $0` - -./node-config.js -wait -source ./.nodester.config - -export HOME=$HOME_DIR; -export PATH="/usr/local/bin:${PATH}"; - -FHOME=$HOME/forever-proxy - - -forever "$@" -p $FHOME diff --git a/bin/install-deps.sh b/bin/install-deps.sh deleted file mode 100755 index 7a0503e5..00000000 --- a/bin/install-deps.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -sudo yum install upstart monit cairo-devel libpng git-core curl diff --git a/bin/install.js b/bin/install.js deleted file mode 100755 index 095fdd62..00000000 --- a/bin/install.js +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env node - -var nodeControl = require('../deps/node-control/index.js'); - -var util = require('util'); -var ins = util.inspect; - -var args = process.argv; -args.shift(); -args.shift(); -if (args.length < 13) { - console.error('Invalid usage!'); - console.log('install.js '); - console.log('nb. You should be able to ssh to the host using a key, and use sudo with no passphrase.'); - process.exit(1); -} -var username = args.shift(); -var hostname = args.shift(); -var tl_domain = args.shift(); -var couch_db_user = args.shift(); -var couch_db_pass = args.shift(); -var couch_db_host = args.shift(); -var couch_db_port = args.shift(); -var couch_db_prefix = args.shift(); -var apps_homedir = args.shift(); -var app_username = args.shift(); -var app_homedir = args.shift(); -var git_username = args.shift(); -var git_homedir = args.shift(); - -var deps = new Array('pool', 'express', 'npm-wrapper', 'request', 'daemon', 'forever', 'cradle', 'colored'); - -var ssh_config_base = { - user: username -}; -var ssh_hosts_base = nodeControl.hosts(ssh_config_base, [hostname]); -var host_base = ssh_hosts_base[0]; // TODO - This is for a single host install, need to create multi host install. -var ssh_config_app = { - user: app_username -}; -var ssh_hosts_app = nodeControl.hosts(ssh_config_app, [hostname]); -var host_app = ssh_hosts_app[0]; - -var random_string = function (L) { - var s = ''; - var randomchar = function () { - var n = Math.floor(Math.random() * 62); - if (n < 10) return n; // 1-10 - if (n < 36) return String.fromCharCode(n + 55); // A-Z - return String.fromCharCode(n + 61); // a-z - }; - while (s.length < L) s += randomchar(); - return s; - }; - - -var print_lines_prefix = function (prefix, lines) { - var i = 0, - l = lines.length; - for (i = 0; i < l; i++) { - if (i < (l - 1) || lines[i].length > 0) console.log('%s: %s', prefix, lines[i]); - } - }; - -var commands = []; -var add_c = function (host, cmd, exp, need) { - commands.push([host, cmd, exp, need]); - }; - - -add_c(host_base, 'sudo groupadd -g 2001 ' + app_username, '', true); -add_c(host_base, 'sudo groupadd -g 2002 ' + git_username, '', true); -add_c(host_base, 'sudo useradd -d ' + app_homedir + ' -c "nodester app" -g ' + app_username + ' -m -r -s /bin/bash ' + app_username, '', true); -add_c(host_base, 'sudo useradd -d ' + git_homedir + ' -c "nodester git user" -g ' + git_username + ' -m -r -s /bin/bash ' + git_username, '', true); -add_c(host_base, 'sudo mkdir ' + app_homedir + '/.ssh', '', true); -add_c(host_base, 'sudo mkdir ' + apps_homedir, '', true); -add_c(host_base, 'sudo chown -R ' + app_username + ':' + git_username + '' + apps_homedir, '', true); -add_c(host_base, 'sudo chmod -R 0774 ' + apps_homedir, '', true); -add_c(host_base, 'sudo cp ${HOME}/.ssh/authorized_keys ' + app_homedir + '/.ssh/authorized_keys', '', true); -add_c(host_base, 'sudo chown -R ' + app_username + ':' + app_username + ' ' + app_homedir + '/.ssh', '', false); -add_c(host_base, 'sudo chmod -R 0700 ' + app_homedir + '/.ssh', '', false); - -add_c(host_app, 'git clone http://github.com/nodester/nodester.git ./nodester', '', true); -add_c(host_app, 'cp ./nodester/example_config.js ./nodester/config.js', '', true); -add_c(host_app, 'sed -i -e "s/\\\/var\\\/nodester/' + app_homedir.replace('/', '\\\/') + '/g" ./nodester/config.js', '', false); -add_c(host_app, 'sed -i -e "s/couch_user: \'nodester/couch_user: \'' + couch_db_user + '/" ./nodester/config.js', '', false); -add_c(host_app, 'sed -i -e "s/couch_pass: \'password/couch_pass: \'' + couch_db_pass + '/" ./nodester/config.js', '', false); -add_c(host_app, 'sed -i -e "s/couch_host: \'127.0.0.1/couch_host: \'' + couch_db_host + '/" ./nodester/config.js', '', false); -add_c(host_app, 'sed -i -e "s/couch_port: 5984/couch_port: ' + couch_db_port + '/" ./nodester/config.js', '', false); -add_c(host_app, 'sed -i -e "s/couch_prefix: \'nodester/couch_prefix: \'' + couch_db_prefix + '/" ./nodester/config.js', '', false); -add_c(host_app, 'sed -i -e "s/git_user: \'nodester/git_user: \'' + git_username + '/" ./nodester/config.js', '', false); -add_c(host_app, 'sed -i -e "s/userid: \'nodester/userid: \'' + app_username + '/" ./nodester/config.js', '', false); -add_c(host_app, 'sed -i -e "s/testnodester.com/' + tl_domain + '/g" ./nodester/config.js', '', false); - -add_c(host_base, 'sudo chown -R root:' + app_username + ' ' + app_homedir + '/nodester/proxy', '', false); -add_c(host_base, 'sudo mkdir -p /usr/local/bin ' + app_homedir + '/nodester/var', '', true); -add_c(host_base, 'sudo cp -f ' + app_homedir + '/nodester/scripts/git-shell-enforce-directory /usr/local/bin/', '', false); -add_c(host_base, 'sudo chmod +x /usr/local/bin/git-shell-enforce-directory', '', true); - -var restart_key = random_string(13); -var coupon_code = random_string(8); -console.log('coupon_code set to: %s', coupon_code); -console.log('restart key set to: %s', restart_key); - -add_c(host_app, 'cp ./nodester/scripts/example_gitrepoclone.sh ./nodester/scripts/gitrepoclone.sh', '', true); -add_c(host_app, 'sed -i -e "s/KeepThisSecret/' + restart_key + '/" ./nodester/config.js', '', false); -add_c(host_app, 'sed -i -e "s/KeepThisSecret/' + restart_key + '/" ./nodester/scripts/gitrepoclone.sh', '', false); -add_c(host_app, 'sed -i -e "s/CouponCode/' + coupon_code + '/" ./nodester/config.js', '', false); -for (var i in deps) { - add_c(host_app, 'npm install ' + deps[i], '', true); -} - -add_c(host_app, './nodester/scripts/couchdb/create_all_couchdb_tables.js', '', true); -add_c(host_app, './nodester/scripts/couchdb/setup_default_views.js', '', true); - -add_c(host_base, 'sudo cp /etc/sudoers /tmp/my_file_1', '', false); -add_c(host_base, 'sudo chown ' + username + ' /tmp/my_file_1', '', false); -add_c(host_base, 'echo "' + app_username + ' ALL = NOPASSWD: ' + app_homedir + '/nodester/bin/proxy_stop.sh" >> /tmp/my_file_1', '', false); -add_c(host_base, 'echo "' + app_username + ' ALL = NOPASSWD: ' + app_homedir + '/nodester/bin/proxy_start.sh" >> /tmp/my_file_1', '', false); -add_c(host_base, 'echo "' + app_username + ' ALL = NOPASSWD: ' + app_homedir + '/nodester/scripts/launch_chrooted_app.js *" >> /tmp/my_file_1', '', false); -add_c(host_base, 'echo "' + app_username + ' ALL = NOPASSWD: ' + app_homedir + '/nodester/scripts/update_authkeys.js *" >> /tmp/my_file_1', '', false); -add_c(host_base, 'echo "' + app_username + ' ALL = NOPASSWD: ' + app_homedir + '/nodester/scripts/create_user_dir.js *" >> /tmp/my_file_1', '', false); -add_c(host_base, 'echo "' + app_username + ' ALL = NOPASSWD: ' + app_homedir + '/nodester/scripts/gitreposetup.sh *" >> /tmp/my_file_1', '', false); -add_c(host_base, 'sudo cp /tmp/my_file_1 /etc/sudoers', '', false); -add_c(host_base, 'rm -f /tmp/my_file_1', '', false); -add_c(host_base, 'sudo chown root:root /etc/sudoers', '', false); -add_c(host_base, 'sudo chmod 0440 /etc/sudoers', '', false); - -var run_command = function (cmds) { - var cmd = cmds.shift(); - cmd[0].ssh(cmd[1], cmd[2], function (err, stdout, stderr) { - if (cmd[3] === false && err > 0) { - console.error('failed command: %s', cmd[1]); - console.error('response expected: "%s"', cmd[2]); - console.error('response recieved:\nSTDOUT: "%s"\nSTDERR: "%s"', stdout, stderr); - process.exit(3); - } else { - console.log('completed: %s', cmd[1]); - if (cmds.length > 0) { - run_command(cmds); - } - } - }); - }; - -if (commands.length > 0) { - run_command(commands); -} \ No newline at end of file diff --git a/bin/node-config.js b/bin/node-config.js deleted file mode 100755 index e724ddd6..00000000 --- a/bin/node-config.js +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env node - -process.chdir(__dirname); - -var config = require('../config').opt; -var fs = require('fs'); - -var data = []; - -for (var i in config) { - if (typeof config[i] == 'string') { - data.push('export ' + i.toUpperCase() + '=' + config[i]); - } -} - -fs.writeFileSync('./.nodester.config', data.join('\n'), encoding = 'utf8'); -fs.chmodSync('./.nodester.config', '0777'); \ No newline at end of file diff --git a/bin/proxy_start.sh b/bin/proxy_start.sh deleted file mode 100755 index 71c399cb..00000000 --- a/bin/proxy_start.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -cd `dirname $0` - -./node-config.js -wait -source ./.nodester.config -wait -rm ./.nodester.config - -export HOME=$HOME_DIR; -export PATH="/usr/local/bin:${HOME}/bin:${PATH}"; - -APPDIR=$APP_DIR/proxy - -FHOME=$HOME/forever-proxy - - -if [ ! -d $HOME/var ]; then - mkdir $HOME/var -fi - -if [ ! -d $FHOME ]; then - mkdir -p $FHOME/logs - mkdir -p $FHOME/pids -fi - -if [ -f $FHOME/logs/forever.log ]; then - rm -rRf $FHOME/logs/forever.log -fi - -ulimit -n 99999; -forever start -l logs/forever.log -o $FHOME/logs/proxy-out.log -e $FHOME/logs/proxy-err.log -d $APPDIR -p $FHOME $APPDIR/proxy.js -wait -forever list -p $FHOME $APPDIR/proxy.js diff --git a/bin/proxy_stop.sh b/bin/proxy_stop.sh deleted file mode 100755 index 4ffbf1c0..00000000 --- a/bin/proxy_stop.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -cd `dirname $0` - -./node-config.js -wait -source ./.nodester.config -wait -rm ./.nodester.config - -export HOME=$HOME_DIR; -export PATH="/usr/local/bin:${HOME}/bin:${PATH}"; - -APPDIR=$APP_DIR - -FHOME=$HOME/forever-proxy - -forever stopall -p $FHOME - -sleep 1 diff --git a/bin/restart_hosted_apps.sh b/bin/restart_hosted_apps.sh deleted file mode 100755 index 332e8c36..00000000 --- a/bin/restart_hosted_apps.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -cd `dirname $0` - -./node-config.js -wait -source ./.nodester.config - -node $APP_DIR/scripts/start_hosted_apps.js restart "$@" diff --git a/bin/start_hosted_apps.sh b/bin/start_hosted_apps.sh deleted file mode 100755 index 75f0eb03..00000000 --- a/bin/start_hosted_apps.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -cd `dirname $0` - -./node-config.js -wait -source ./.nodester.config - -node $APP_DIR/scripts/start_hosted_apps.js start "$@" diff --git a/bin/stop_hosted_apps.sh b/bin/stop_hosted_apps.sh deleted file mode 100755 index eab672fe..00000000 --- a/bin/stop_hosted_apps.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -cd `dirname $0` - -./node-config.js -wait -source ./.nodester.config - -node $APP_DIR/scripts/start_hosted_apps.js stop "$@" diff --git a/bin/sync_githook.sh b/bin/sync_githook.sh deleted file mode 100755 index 28019ef1..00000000 --- a/bin/sync_githook.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -cd `dirname $0` - -./node-config.js -wait -source ./.nodester.config - -export HOME=$HOME_DIR; -export PATH="/usr/local/bin:${PATH}"; - -$APP_DIR/scripts/sync_githook.js - diff --git a/bin/top b/bin/top deleted file mode 100755 index a216ca83..00000000 --- a/bin/top +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env node - -var exec = require('child_process').exec; -//$13 should be name? -var cmd = "ps aux | awk '/chroot_runner/ && !/awk/ {print $3,$4,$2,$5,$6,$10,$9}' | sort -r | head -n 50"; - -require('colors'); - -var top = function() { - console.log('cpu\tmem\tvsz\trss\tpid\ttime\tdate'.magenta.bold); - - exec(cmd, function(err, stdout) { - var data = stdout.split('\n'); - //console.log(stdout); - data.forEach(function(l) { - var line = l.split(' '); - if (line[1]) { - for (var i = 2; i < 7; i++) { - line[i] = line[i].white; - } - - if (parseFloat(line[0]) > 0.75) { - line[0] = line[0].red.bold; - } else { - line[0] = line[0].white; - } - if (parseFloat(line[1]) > 0.75) { - line[1] = line[1].red.bold; - } else { - line[1] = line[1].white; - } - - console.log(line.join('\t')); - } - }); - }); -}; - - -top(); -setInterval(top, 2000); diff --git a/example_config.js b/example_config.js deleted file mode 100644 index 76e65253..00000000 --- a/example_config.js +++ /dev/null @@ -1,35 +0,0 @@ -exports.opt = { - couch_user: 'nodester', - couch_pass: 'password', - couch_host: '127.0.0.1', - couch_port: 5984, - couch_prefix: 'nodester', - couch_tables: ['coupons', 'nodefu', 'nextport', 'apps', 'repos', 'aliasdomains', 'password_resets'], - home_dir: '/var/nodester', - app_dir: '/var/nodester/nodester', - git_home_dir: '/git', - apps_home_dir: '/app', - public_html_dir: '/var/nodester/nodester/public', - proxy_table_file: '/var/nodester/var/proxy_table.json', - tl_dom: 'testnodester.com', - api_dom: 'api.testnodester.com', - git_user: 'nodester', - git_dom: 'testnodester.com', - coupon_code: 'CouponCode', - blocked_apps: ['www', 'api', 'admin', 'support', 'blog', 'site'], - restart_key: 'KeepThisSecret', - userid: 'nodester', - app_uid: 100, - enable_ssl: false, // Currently SSL forward to the app/api, when I have a wildcard cert to test, then all apps can have SSL. - ssl_ca_file: '', - ssl_cert_file: '', - ssl_key_file: '', - node_base_folder: '/opt/node-v0.4.9_npm_v1.0.3', - - //Amazon SES mail info - SES: { - AWSAccessKeyID: 'ACCESSKEY', - AWSSecretKey: 'SECRETKEY', - ServiceUrl: 'https://email.us-east-1.amazonaws.com', - } -}; diff --git a/install.txt b/install.txt deleted file mode 100644 index 756b4971..00000000 --- a/install.txt +++ /dev/null @@ -1,114 +0,0 @@ -PLEASE NOTE - THIS IS HORRIBLY OUT OF DATE, UPDATED INSTALL INSTRUCTIONS AND A STREAMLINED INSTALL PROCESS WILL BE DONE SOON - -Nodester - A node.js hosting platform - -Dependencies: - node.js (Latest stable version 0.4.11) - npm - curl - node.js Modules: - # http-proxy -- Included in libs/3rdparty due to changes at are not in upstream yet - pool - express - request - npm-wrapper - daemon - forever - cradle - coloured - coffee-script - -Installation: - Install node.js (0.4.x recommended) - Package from distro - OR wget, ./configure, make, make install - Create a user and group to run nodester as (do this as root) - sudo su - - groupadd nodester - useradd -d /var/nodester -c "nodester" -g nodester -m -r -s /bin/bash nodester - passwd nodester - Login to that account and ensure that .ssh/authorized_keys exists - ssh nodester@yourhost - cd ~ - mkdir .ssh - touch .ssh/authorized_keys - chmod go-rwx .ssh/authorized_keys - Update sudoers to allow running of the proxy on port 80 (do this as root) - sudo visudo - And add the following lines - nodester ALL = NOPASSWD: /var/nodester/nodester/bin/proxy_start.sh * - nodester ALL = NOPASSWD: /var/nodester/nodester/bin/proxy_stop.sh - nodester ALL = NOPASSWD: /var/nodester/nodester/bin/app_start.sh * - nodester ALL = NOPASSWD: /var/nodester/nodester/bin/app_stop.sh * - Install npm (do this as nodester) - cd ~ - echo -e "root = ~/.node_libraries\nmanroot = ~/local/share/man\nbinroot = ~/bin" > ~/.npmrc - echo -e "export PATH=\"\${PATH}:~/bin\";" >> ~/.bashrc - source ~/.bashrc - - ##This part is a hack to use the old npm with the new node until - ## certain packages can catch up and be installed with npm@0.3.x - - mkdir ~/src - cd src - git clone git://github.com/isaacs/npm.git ./npm - cd npm - git checkout origin/0.2 - make dev - - ##Fetch 0.2.6 version of node for npm - cd ~/src - sudo mkdir -p /usr/local/n/versions/ - wget http://nodejs.org/dist/node-v0.2.6.tar.gz - tar -vzxr node-v0.2.6.tar.gz - cd node-v0.2.6 - ./configure --prefix=/usr/local/n/versions/0.2.6 - make - sudo make install - - cd ~/bin - cp npm\@0.2.18 nodester-npm - vim nodester-npm - "Replace '#!/usr/bin/env node' with '#!/usr/local/n/versions/0.2.6/bin/node' - - Either install CouchDB or get a CouchOne account - - Install node-module dependencies (do this as nodester) - for X in pool express npm-wrapper request daemon forever cradle coloured; do npm install ${X}; done - - Get nodester (do this as nodester) - cd ~ - git clone git://github.com/nodester/nodester.git - cd nodester - - Ensure that the ownership of nodester/proxy is all root for security (do this as root) - cd /var/nodester - sudo chown -R root:root nodester/proxy - Install the git folder shell to restrict git to per user folders (do this as root) - cd /var/nodester/nodester - sudo cp scripts/git-shell-enforce-directory /usr/local/bin - sudo chmod +x /usr/local/bin/git-shell-enforce-directory - - Configure the app (do this as nodester) - Copy nodester/example_config.js to nodester/config.js - Edit the settings in nodester/config.js - Copy scripts/example_gitrepoclone.sh to scripts/gitrepoclone.sh - Update scripts/gitrepoclone.sh with the key you specified in config.js - Setup the CouchDB tables (do this as nodester) - cd ./nodester/scripts/couchdb/create_all_couchdb_tables.js - ./create_all_couchdb_tables.js - ./nodester/scripts/couchdb/setup_default_views.js - Start up the proxy and main/api app (do this as nodester) - cd nodester - ./bin/app_start.sh - sudo ./bin/proxy_start.sh - Test the web frontend at 127.0.0.1:80 - Create a user - .. - Create an app - .. - Start the app - .. - Test the app - .. - Rejoice! diff --git a/lib/api/status.coffee b/lib/api/status.coffee new file mode 100644 index 00000000..b52588d7 --- /dev/null +++ b/lib/api/status.coffee @@ -0,0 +1,11 @@ +db = require '../lib/database' + +module.exports = + get: (req, res, next) -> + apps = db.getDatabase 'apps' + apps.view 'nodeapps/all', (err, resp) -> + return res.end JSON.stringify {status: 'Database offline'} if err + total = resp.length + running = x for x in resp when x.running = 'true' + res.end JSON.stringify { status: 'Online', online: running, offline: total - running, total: total } + diff --git a/lib/app.js b/lib/app.js deleted file mode 100644 index cb80196f..00000000 --- a/lib/app.js +++ /dev/null @@ -1,864 +0,0 @@ -var config = require('../config'), - fs = require('fs'), - path = require('path'), - cradle = require('cradle'), - lib = require('./lib'), - unionfs = require('./unionfs').unionfs, - chroot = require('./chroot').chroot, - spawn = require('child_process').spawn, - exec = require('child_process').exec; - - -module.exports = { - logs: function (req, res, next) { - var appname = req.appname; - var user = req.user; - var app = req.app; - var app_error_log_sock = path.join(config.opt.apps_home_dir, app.username, app.repo_id + '_chroot', '.nodester', 'logs.sock'); - console.log('Attempting to connect to: ' + app_error_log_sock); - if (path.existsSync(app_error_log_sock)) { - var net = require('net'); - var timer = setTimeout(function () { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: 'Timeout getting logs.', - }) + '\n'); - app_handler.end(); - }, 10000); - var app_handler = net.createConnection(app_error_log_sock); - app_handler.once('connect', function () { - var buff = ''; - app_handler.on('data', function (data) { - buff += data.toString(); - }); - app_handler.once('end', function () { - clearTimeout(timer); - try { - var logs_strs = JSON.parse(buff); - var lines = logs_strs['logs'].split('\n'); - } catch (e) { - var lines = 'Error parsing lines.'; - } - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "success", - lines: lines - }) + '\n'); - }); - }); - } else { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: 'failure', - message: 'No logs available.' - }) + '\n'); - } - }, - gitreset: function (req, res, next) { - var appname = req.param("appname").toLowerCase(); - var user = req.user; - var app = req.app; - var apps = lib.get_couchdb_database('apps'); - apps.get(appname, function (err, doc) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - console.log('Resetting repo from git: ', app.repo_id); - var app_user_home = path.join(config.opt.git_home_dir, app.username, app.repo_id); - exec(config.opt.app_dir + '/scripts/gitreset.js ' + app_user_home, function () { - app_restart(app.repo_id, function () { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "success" - })); - }); - }); - } - }); - }, - delete: function (req, res, next) { - var appname = req.param("appname").toLowerCase(); - var user = req.user; - var app = req.app; - var apps = lib.get_couchdb_database('apps'); - apps.get(appname, function (err, doc) { - var app_user_home = path.join(config.opt.apps_home_dir, app.username, app.repo_id); - var app_git_home = path.join(config.opt.git_home_dir, app.username, app.repo_id); - if (err) { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - apps.remove(appname, doc._rev, function (err, resp) { - if (err) { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - var app_rw = app_user_home + '_rw'; - var app_chroot = app_user_home + '_chroot'; - lib.tear_down_unionfs_chroot(config.opt.node_base_folder, app_user_home, app_rw, app_chroot, function () { - lib.update_proxytable_map(function (err) { - if (err) { - console.log('Error updating Proxy! - ' + err); - } - app_stop(app.repo_id, function () { - exec('sudo ' + config.opt.app_dir + '/scripts/removeapp.js ' + app_user_home + ' ' + app_git_home, function () {}); - }); - }); - }); - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - "status": "success" - })); - } - }); - } - }); - }, - put: function (req, res, next) { - var appname = req.body.appname.toLowerCase(); - var user = req.user; - var app = req.app; - var db = lib.get_couchdb_database('apps'); - db.get(appname, function (err, appdoc) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - var start = req.body.start; - var app_user_home = path.join(config.opt.apps_home_dir, appdoc.username); - var app_home = path.join(app_user_home, appdoc.repo_id); - var app_repo = config.opt.git_user + '@' + config.opt.git_dom + ':' + path.join(config.opt.git_home_dir, appdoc.username, appdoc.repo_id + '.git'); - if (typeof start != 'undefined' && start.length > 0) { - db.merge(appname, { - start: start - }, function (err, resp) { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: success, - port: appdoc.port, - gitrepo: app_repo, - start: start, - running: appdoc.running, - pid: appdoc.pid - })); - }); - } else { - var running = req.body.running; - switch (running) { - case "true": - if (appdoc.running == "true") { - res.writeHead(408, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure - application already running." - })); - } else { - app_start(appdoc.repo_id, function (rv, pid) { - var success = "false", - running = "failed-to-start"; - if (rv === true) { - success = "success"; - running = "true"; - lib.update_proxytable_map(function (err) { - if (err) { - console.log('Error updating Proxy! - ' + err); - } - }); - } - db.merge(appname, { - running: running, - pid: pid - }, function (err, resp) { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: success, - port: appdoc.port, - gitrepo: app_repo, - start: appdoc.start, - running: running, - pid: pid - })); - }); - }); - } - break; - case "restart": - app_restart(app.repo_id, function (rv, pid) { - var success = "false", - running = "failed-to-restart"; - if (rv === true) { - success = "success"; - running = "true"; - } - db.merge(appname, { - running: running, - pid: pid - }, function (err, resp) { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: success, - port: appdoc.port, - gitrepo: app_repo, - start: appdoc.start, - running: running, - pid: pid - })); - }); - }); - break; - case "false": - if (app.running != 'true') { - res.writeHead(408, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure - application already stopped." - })); - } else { - app_stop(app.repo_id, function (rv) { - var success = "false", - running = "failed-to-stop"; - if (rv === true) { - success = "success"; - running = "false"; - lib.update_proxytable_map(function (err) { - if (err) { - console.log('Error updating Proxy! - ' + err); - } - }); - } - db.merge(appname, { - running: running, - pid: 'unknown' - }, function (err, resp) { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: success, - port: appdoc.port, - gitrepo: app_repo, - start: appdoc.start, - running: running, - pid: 'unknown' - })); - }); - }); - } - break; - default: - res.writeHead(400, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: "Invalid action." - }) + "\n"); - break; - } - } - } - }); - }, - app_start: function (req, res, next) { - var repo_id = req.query.repo_id; - var restart_key = req.query.restart_key; - if (restart_key != config.opt.restart_key) { - res.writeHead(403, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failed to start - invalid restart key" - })); - return; - } else { - app_start(repo_id, function (rv, err) { - if (rv === false) { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failed to start - " + err - })); - } else { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "started" - })); - } - }, true); - } - }, - app_stop: function (req, res, next) { - var repo_id = req.query.repo_id; - var restart_key = req.query.restart_key; - if (restart_key != config.opt.restart_key) { - res.writeHead(403, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failed to start - invalid restart key" - })); - return; - } else { - app_stop(repo_id, function (rv) { - if (rv === false) { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failed to stop" - })); - } else { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "stop" - })); - } - }); - } - }, - app_restart: function (req, res, next) { - var repo_id = req.query.repo_id; - var restart_key = req.query.restart_key; - if (restart_key != config.opt.restart_key) { - res.writeHead(403, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failed to start - invalid restart key" - })); - return; - } else { - app_restart(repo_id, function (rv) { - if (rv === false) { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failed to restart" - })); - } else { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "restarted" - })); - } - }, true); - } - }, - get: function (req, res, next) { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "success", - port: req.app.port, - gitrepo: config.opt.git_user + '@' + config.opt.git_dom + ':' + path.join(config.opt.git_home_dir, req.app.username, req.app.repo_id + '.git'), - start: req.app.start, - running: req.app.running, - pid: req.app.pid - })); - }, - post: function (req, res, next) { - var appname = req.body.appname; - var start = req.body.start; - if (!appname) { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: "Appname Required" - })); - return; - } - if (!start) { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: "Start File Required" - })); - return; - } - var user = req.user; - var apps = lib.get_couchdb_database('apps'); - apps.get(appname, function (err, doc) { - if (err) { - if (err.error == 'not_found') { - var nextport = lib.get_couchdb_database('nextport'); - nextport.get('port', function (err, next_port) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - var appport = next_port.address; - var repo_id = next_port._rev; - nextport.merge('port', { - address: appport + 1 - }, function (err, resp) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - apps.save(appname, { - start: start, - port: appport, - username: user._id, - repo_id: repo_id, - running: false, - pid: 'unknown', - env: {} - }, function (err, resp) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - var repos = lib.get_couchdb_database('repos'); - repos.save(repo_id, { - appname: appname, - username: user._id - }, function (err, resp) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - var cmd = 'sudo ' + config.opt.app_dir + '/scripts/gitreposetup.sh ' + [config.opt.app_dir, config.opt.git_home_dir, user._id, repo_id, start, config.opt.userid, config.opt.git_user, config.opt.apps_home_dir].join(' '); - console.log('gitsetup cmd: %s', cmd); - exec(cmd, function (err, stdout, stderr) { - if (err) console.error('gitsetup error: %s', err); - if (stdout.length > 0) console.log('gitsetup stdout: %s', stdout); - if (stderr.length > 0) console.error('gitsetup stderr: %s', stderr); - }); - // var gitsetup = spawn('/usr/bin/env sudo ' + config.opt.app_dir + '/scripts/gitreposetup.sh', [config.opt.app_dir, config.opt.git_home_dir, user._id, repo_id, start, config.opt.userid, config.opt.git_user]); - //Added logging to the reposetup script - // gitsetup.stdout.on('data', function (data) { - // console.log('git setup stdout: ' + data); - //}); - // gitsetup.stderr.on('data', function (data) { - // console.error('git setup stderr: ' + data); - //}); - // Respond to API request - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "success", - port: appport, - gitrepo: config.opt.git_user + '@' + config.opt.git_dom + ':' + path.join(config.opt.git_home_dir, user._id, repo_id + '.git'), - start: start, - running: false, - pid: "unknown" - })); - lib.update_proxytable_map(function (err) { - if (err) { - console.log('Error updating Proxy! - ' + err); - } - // Not sure if the user needs to be made aware in case of these errors. Admins should be though. - }); - } - }); - } - }); - } - }); - } - }); - } else { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } - } else { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: "app exists" - })); - } - }); - }, - env_get: function (req, res, next) { - var appname = req.appname.toLowerCase(); - var db = lib.get_couchdb_database('apps'); - db.get(appname, function (err, appdoc) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - var start = req.body.start; - db.get(appname, function (err, doc) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "success", - message: doc.env || {} - })); - } - }); - } - }); - }, - env_put: function (req, res, next) { - var appname = req.body.appname.toLowerCase(); - var db = lib.get_couchdb_database('apps'); - var key = req.body.key, - value = req.body.value; - if (!key || !value) { - res.writeHead(400, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: "Must specify both key and value." - }) + "\n"); - return; - } - db.get(appname, function (err, appdoc) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - env_update(res, db, appname, appdoc, key, value); - } - }); - }, - env_delete: function (req, res, next) { - var appname = req.body.appname.toLowerCase(); - var db = lib.get_couchdb_database('apps'); - var key = req.body.key; - if (!key) { - res.writeHead(400, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: "Must specify key." - }) + "\n"); - return; - } - db.get(appname, function (err, appdoc) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - env_update(res, db, appname, appdoc, key, undefined); - } - }); - } -}; - -var env_update = function (res, db, appname, appdoc, key, value) { - var env = {}; - if (appdoc.env) { - Object.keys(appdoc.env).forEach(function (k) { - env[k] = appdoc.env[k]; - }); - } - if (value !== undefined) { - env[key] = value; - } else { - delete env[key]; - } - db.merge(appname, { - env: env - }, function (err, resp) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "success", - message: value === undefined ? ("DELETE " + key) : (key + "=" + value) - })); - } - }); - }; - -var force_stop = function (repo_id, callback) { - console.log('Forcing stop for: ', repo_id); - console.log("ps aux | awk '/" + repo_id + "/ && !/awk |curl / {print $2}'"); - exec("ps aux | awk '/" + repo_id + "/ && !/awk |curl / {print $2}'", function (err, pid) { - if (err) { - callback(false); - return; - } - try { - console.log('PID: "' + pid + '"'); - if (pid.length > 0) { - var pids = pid.split('\n'), - k = false; - - var p = typeof pids[0] != 'undefined' ? parseInt(pids[0], 10) : 0; - console.log('p: "' + p + '"'); - if (p > 0) { - console.log('Sending SIGKILL to ', p); - process.kill(p, 'SIGKILL'); - k = true; - } - callback(k); - } else { - callback(true); - } - - } catch (e) { - callback(false); - } - }); - }; - - -var app_stop = function (repo_id, callback, skip_unmount) { - var db = lib.get_couchdb_database('repos'); - db.get(repo_id, function (err, doc) { - if (err) { - callback(false); - } else { - var app_home = path.join(config.opt.apps_home_dir, doc.username, doc._id); - fs.readFile(path.join(app_home + '_rw', '.nodester', 'pids', 'runner.pid'), function (err, data) { - if (err) { - callback(false); - } else { - var pid = parseInt(data.toString(), 10); - if (pid > 0) { - try { - process.kill(pid, 'SIGINT'); - var app_home = path.join(config.opt.apps_home_dir, doc.username, repo_id); - var app_rw = app_home + '_rw'; - var app_chroot = app_home + '_chroot'; - if (typeof skip_unmount == 'undefined' || skip_unmount !== true) lib.tear_down_unionfs_chroot(config.opt.node_base_folder, app_home, app_rw, app_chroot, function () {}); - } catch (e) { - // Blah - } - callback(true); - } else { - callback(false); - } - } - }); - } - }); - }; - -var app_start = function (repo_id, callback) { - var db = lib.get_couchdb_database('repos'); - db.get(repo_id, function (err, doc) { - if (err) { - callback(false, err); - } else { - var user_home = path.join(config.opt.apps_home_dir, doc.username); - var app_home = user_home + '/' + repo_id; - var apps = lib.get_couchdb_database('apps'); - apps.get(doc.appname, function (err, app) { - if (err) { - callback(false, err); - } else { - var configData = { - appdir: config.opt.app_dir, - userid: config.opt.app_uid, - chroot_base: config.opt.node_base_folder, - apphome: app_home, - apprwfolder: path.join(app_home, '..', repo_id + '_rw'), - appchroot: path.join(app_home, '..', repo_id + '_chroot'), - start: app.start, - port: app.port, - ip: '127.0.0.1', - name: doc.appname, - env: app.env || {} - }; - console.log('Checking: ', configData.apphome); - if (!path.existsSync(configData.apphome)) { - //Bad install?? - console.log('App directory does not exist: ', configData.apphome); - callback(false, err); - return; - } - console.log('Checking: ', path.join(configData.apphome, app.start)); - if (!path.existsSync(path.join(configData.apphome, app.start))) { - //Bad install?? - console.log('App start file does not exist: ', path.join(configData.apphome, app.start)); - callback(false, err); - return; - } - - console.log('Checking: ', path.join(configData.apprwfolder, '.nodester')); - if (!path.existsSync(path.join(configData.apprwfolder, '.nodester'))) { - console.log('Making Directories..'); - if (!path.existsSync(configData.apprwfolder)) fs.mkdirSync(configData.apprwfolder, '0777'); - fs.mkdirSync(path.join(configData.apprwfolder, 'app'), '0777'); - fs.mkdirSync(path.join(configData.apprwfolder, '.nodester'), '0777'); - fs.mkdirSync(path.join(configData.apprwfolder, '.nodester', 'logs'), '0777'); - fs.mkdirSync(path.join(configData.apprwfolder, '.nodester', 'pids'), '0777'); - } - try { - fs.chmodSync(path.join(configData.apprwfolder, 'app'), '0777'); - } catch (e) { - console.log('Failed to chmod %s/%s 0777', configData.apprwfolder, 'app'); - } - console.log('Writing config data: ', path.join(configData.apprwfolder, '.nodester', 'config.json')); - fs.writeFileSync(path.join(configData.apprwfolder, '.nodester', 'config.json'), JSON.stringify(configData), encoding = 'utf8'); // TODO Change to ASYNC - lib.tear_down_unionfs_chroot(configData.chroot_base, configData.apphome, configData.apprwfolder, configData.appchroot, function (resp) { - lib.setup_unionfs_chroot(configData.chroot_base, configData.apphome, configData.apprwfolder, configData.appchroot, function (resp) { - if (resp === true) { - var cmd = 'cd ' + configData.appchroot + ' && ulimit -c unlimited -n 65000 -u 100000 -i 1000000 -l 10240 -s 102400 && sudo ' + path.join(config.opt.app_dir, 'scripts', 'chroot_runner.js'); - //console.log(cmd); - exec(cmd, function (error, stdout, stderr) { - if (stdout) { - console.log(stdout); - } - if (stderr) { - console.log(stderr); - } - setTimeout(function () { - var tapp = { - pid: 'unknown', - running: 'failed-to-start' - }; - fs.readFile(path.join(configData.apprwfolder, '.nodester', 'pids', 'runner.pid'), function (err, pids) { - var pid = parseInt(pids, 10); - if (pid > 0) { - tapp.pid = pid; - tapp.running = 'true'; - } - apps.merge(doc.appname, tapp, function () { - callback(true, pid); - }); - }); - }, 1500); - }); - } else { - var tapp = { - pid: 'unknown', - running: 'failed-to-setup_unionfs_chroot' - }; - apps.merge(doc.appname, tapp, function () { - callback(false, tapp.running); - }); - } - }); - }); - } - }); - } - }); - }; - -var app_restart = function (repo_id, callback) { - app_stop(repo_id, function (rv) { - setTimeout(function () { - app_start(repo_id, function (rv, pid) { - if (rv === false) { - callback(false, pid); - } else { - callback(true, pid); - } - }); - }, 1500); - }, true); - }; diff --git a/lib/apps.js b/lib/apps.js deleted file mode 100644 index 3d9a81bb..00000000 --- a/lib/apps.js +++ /dev/null @@ -1,26 +0,0 @@ -var request = require('request'), - lib = require('./lib'), - config = require('../config'); - -module.exports = { - get: function(req, res, next) { - var user = req.user; - - var db = lib.get_couchdb_database('apps'); - db.view('nodeapps/all', {}, function(err, resp) { - var apps = []; - resp.forEach(function(row) { - if (row.username == user._id) { - apps.push({ - name: row._id, - port: row.port, - gitrepo: config.opt.git_user + '@' + config.opt.git_dom + ':' + config.opt.git_home_dir + '/' + row.username + '/' + row.repo_id + '.git', - running: row.running, - pid: row.pid - }); - } - }); - res.send(apps); - }); - } -}; \ No newline at end of file diff --git a/lib/chroot.js b/lib/chroot.js deleted file mode 100644 index 56894322..00000000 --- a/lib/chroot.js +++ /dev/null @@ -1,63 +0,0 @@ -(function() { - var lib = require('./lib.js'); - var path = require('path'); - var fs = require('fs'); - - var chroot = function(target) { - this._setup(target); - }; - - chroot.prototype._setup = function(target_path) { - this.errors = []; - this.target_path = target_path; - this.mounted = false; - this.proc_path = path.join(this.target_path, 'proc'); - this.dev_path = path.join(this.target_path, 'dev'); - }; - chroot.prototype.start = function(cb) { - if (!path.existsSync(this.proc_path)) fs.mkdirSync(this.proc_path, '0777'); - if (!path.existsSync(this.dev_path)) fs.mkdirSync(this.dev_path, '0777'); - lib.ensure_mounted('/dev', this.dev_path, '--bind', function(respA) { - if (respA === true) { - lib.ensure_mounted('proc', this.proc_path, '-t proc', function(respB) { - if (respB === true) { - this.mounted = true; - cb(undefined, true); - } else { - this.errors.push(this.proc_path + ' is not mounted'); - cb(this.errors, undefined); - } - }.bind(this)); - } else { - this.errors.push(this.dev_path + ' is not mounted'); - cb(this.errors, undefined); - } - }.bind(this)); - }; - chroot.prototype.stop = function(cb) { - if (this.mounted === true) { - var arr = ['sudo umount ' + this.dev_path, 'sudo umount ' + this.proc_path]; - lib.exec_array(arr, function() { - lib.is_mounted(this.dev_path, function(respA) { - if (respA !== false) { - this.errors.push(this.dev_path + ' is still mounted'); - cb(this.errors, undefined); - } else { - lib.is_mounted(this.proc_path, function(respB) { - if (respB !== false) { - this.errors.push(this.proc_path + ' is still mounted'); - cb(this.errors, undefined); - } else { - this.mounted = false; - cb(undefined, true); - } - }.bind(this)); - } - }.bind(this)); - }.bind(this)); - } else { - cb('not_mounted', undefined); - } - }; - exports.chroot = chroot; -})(); \ No newline at end of file diff --git a/lib/coupon.js b/lib/coupon.js deleted file mode 100644 index 8f91f0f0..00000000 --- a/lib/coupon.js +++ /dev/null @@ -1,58 +0,0 @@ -var lib = require('./lib'), - config = require('../config'); - - -module.exports = { - post: function(req, res, next) { - var email = req.body.email; - if (typeof email != 'undefined') { - var coupons = lib.get_couchdb_database('coupons'); - coupons.save(email, { - sent: false - }, function(err, resp) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - res.send({ - status: "success - you are now in queue to receive an invite on our next batch!" - }); - } - }); - } else { - res.send({ - status: "failure - please try again shortly!" - }); - } - }, - //I don't have this view, so I can't test it.. - // Convert to use Cradle - unsent: function(req, res, next) { - var coupons = lib.get_couchdb_database('coupons'); - coupons.view('coupons/unsent', function(err, resp) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - var buff = ""; - resp.forEach(function(row) { - buff += row._id + '\n'; - }); - res.writeHead(200, { - 'Content-Type': 'text/plain' - }); - res.end(buff); - } - }); - } -}; \ No newline at end of file diff --git a/lib/database.coffee b/lib/database.coffee new file mode 100644 index 00000000..adb1091f --- /dev/null +++ b/lib/database.coffee @@ -0,0 +1,8 @@ +cradle = require 'cradle' +config = require '../config' + +unless connection + connection = new cradle.Connection + config.opt.couch_host, config.opt.couch_port, {auth: {username: config.opt.couch_user, password: config.opt.couch_pass}} + +module.exports = connection diff --git a/lib/domains.js b/lib/domains.js deleted file mode 100644 index c37edd20..00000000 --- a/lib/domains.js +++ /dev/null @@ -1,113 +0,0 @@ -var request = require('request'), - config = require('../config'), - cradle = require('cradle'), - lib = require('./lib'); - -module.exports = { - post: function(req, res, next) { - var appname = req.appname, - domain = req.param("domain"), - user = req.user, - app = req.app; - - var gooddomain = lib.checkDomain(domain); - if (gooddomain === true) { - var aliasdomains = lib.get_couchdb_database('aliasdomains'); - aliasdomains.get(domain, function(err, doc) { - if (err) { - if (err.error == 'not_found') { - aliasdomains.save(domain, { - appname: app._id, - host: '127.0.0.1', - port: app.port, - username: user._id - }, function(err, resp) { - if (err) { - res.error(400, JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - res.send({ - "status": "success", - "message": "Domain added." - }); - } - }); - } else { - res.error(400, JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } - } else { - res.error(400, '{"status": "failure - domain already exists"}\n'); - } - }); - } else { - res.error(400, '{"status": "failure - ' + gooddomain + '"}\n'); - } - }, - delete: function(req, res, next) { - var appname = req.appname, - domain = req.param("domain"), - user = req.user, - app = req.app; - - var gooddomain = lib.checkDomain(domain); - if (gooddomain === true) { - var aliasdomains = lib.get_couchdb_database('aliasdomains'); - aliasdomains.get(domain, function(err, doc) { - if (err) { - if (err.error == 'not_found') { - res.error(400, '{"status": "failure - domain not found."}\n'); - } else { - res.error(400, JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } - } else { - if (doc.appname == appname) { - aliasdomains.remove(domain, function(err, resp) { - if (err) { - res.error(400, JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - res.send({ - "status": "success", - "message": "Domain deleted." - }); - } - }); - } else { - res.error(400, '{"status": "failure - domain is not for this app."}\n'); - } - } - }); - } else { - res.error(400, '{"status": "failure - ' + gooddomain + '"}\n'); - } - }, - get: function(req, res, next) { - var user = req.user; - var db = lib.get_couchdb_database('aliasdomains'); - // db.view('aliasdomains/all', {key: req.user._id}, function (err, resp) { - db.view('aliasdomains/all', {}, function(err, resp) { - var domains = []; - resp.forEach(function(row) { - if (row.username == user._id) { - domains.push({ - domain: row._id, - appname: row.appname, - host: row.host, - port: row.port - }); - } - }); - res.send(domains); - }); - } -}; \ No newline at end of file diff --git a/lib/lib.js b/lib/lib.js deleted file mode 100644 index 2d8f3d20..00000000 --- a/lib/lib.js +++ /dev/null @@ -1,311 +0,0 @@ -var cradle = require('cradle'); -var crypto = require('crypto'); -var exec = require('child_process').exec; -var config = require('../config.js'); -var chroot = require('./chroot.js').chroot; -var unionfs = require('./unionfs.js').unionfs; -var sys = require('sys'); - - -var couch_loc = "http://" + config.opt.couch_user + ":" + config.opt.couch_pass + "@" + config.opt.couch_host + ":" + config.opt.couch_port + "/"; -if (config.opt.couch_prefix.length > 0) { - couch_loc += config.opt.couch_prefix + "_"; - exports.couch_prefix = config.opt.couch_prefix + "_"; -} else { - exports.couch_prefix = ""; -} -exports.couch_loc = couch_loc; -exports.h = { - accept: 'application/json', - 'content-type': 'application/json' -}; - -var couchdb_parse = function (err, body, cb) { - if (err !== null) { - cb(err, null); - } else { - var doc = {}; - try { - doc = JSON.parse(body); - } catch (e) {} - - if (doc.hasOwnProperty('error')) { - cb(doc.error, doc); - } else { - cb(null, doc); - } - } - }; -exports.couchdb_parse = couchdb_parse; - -var get_couchdb_connection = function () { - var c_opts = { - auth: { - username: config.opt.couch_user, - password: config.opt.couch_pass - }, - cache: true, - raw: false - }; - var proto = 'http'; - if (config.opt.couch_port == 443) { - c_opts['secure'] = true; - proto = 'https'; - } - - return new(cradle.Connection)(proto + '://' + config.opt.couch_host, 5984, c_opts); - }; -exports.get_couchdb_connection = get_couchdb_connection; - -var get_couchdb_database = function (database) { - var conn = get_couchdb_connection(); - return conn.database(exports.couch_prefix + database); - }; -exports.get_couchdb_database = get_couchdb_database; - -var www_dom = 'www.' + config.opt.tl_dom; -var tl_dom = config.opt.tl_dom; -var api_dom = config.opt.api_dom; -var default_routes = { - router: {} -}; -//default_routes.router[''] = 80; -//default_routes.router['127.0.0.1'] = 4001; -default_routes.router[www_dom] = 4001; -default_routes.router[tl_dom] = 4001; -default_routes.router['site.' + config.opt.tl_dom] = 13377; -default_routes.router[api_dom] = 4001; -exports.default_routes = default_routes; - -var build_proxytable_map = function (cb) { - var conn = get_couchdb_connection(); - var apps = get_couchdb_database("apps"); - var aliasdomains = get_couchdb_database("aliasdomains"); - var proxy_map = default_routes; - apps.view('nodeapps/all', {}, function (err, resp) { - if (err) { - console.log('Error building ptable from db - ' + sys.inspect(err)); - } else { - resp.forEach(function (row) { - if (row.port && row._id) { // Block null routes - proxy_map.router[row._id + "." + config.opt.tl_dom] = parseInt(row.port); - } - }); - aliasdomains.view('aliasdomains/all', {}, function (err, resp) { - if (resp && resp.length) { - resp.forEach(function (row) { - if (row.port && row._id && row.host) { // Block null routes - proxy_map.router[row._id] = parseInt(row.port); - proxy_map.router[row.host] = parseInt(row.port); - } - }); - } - cb(proxy_map); - }); - } - }); - }; - -exports.build_proxytable_map = build_proxytable_map; - -var update_proxytable_map = function (cb) { - console.log('Update called on ptable ' + config.opt.proxy_table_file); - var fs = require('fs'); - build_proxytable_map(function (proxy_map) { - fs.writeFile(config.opt.proxy_table_file, JSON.stringify(proxy_map.router), function (err) { - if (err) { - console.log('PTABLE WRITE ERROR: ' + err); - cb(err); - } else { - fs.chmod(config.opt.proxy_table_file, '0666', function (err) { - if (err) { - console.log('PTABLE CHMOD ERROR: ' + err); - cb(err); - } else { - cb(); - } - }); - } - }); - }); - }; - -exports.update_proxytable_map = update_proxytable_map; - -var checkDomain = function (nname) { - var arr = new Array('.com', '.net', '.org', '.biz', '.coop', '.info', '.museum', '.name', '.pro', '.edu', '.gov', '.int', '.mil', '.ac', '.ad', '.ae', '.af', '.ag', '.ai', '.al', '.am', '.an', '.ao', '.aq', '.ar', '.as', '.at', '.au', '.aw', '.az', '.ba', '.bb', '.bd', '.be', '.bf', '.bg', '.bh', '.bi', '.bj', '.bm', '.bn', '.bo', '.br', '.bs', '.bt', '.bv', '.bw', '.by', '.bz', '.ca', '.cc', '.cd', '.cf', '.cg', '.ch', '.ci', '.ck', '.cl', '.cm', '.cn', '.co', '.cr', '.cu', '.cv', '.cx', '.cy', '.cz', '.de', '.dj', '.dk', '.dm', '.do', '.dz', '.ec', '.ee', '.eg', '.eh', '.er', '.es', '.et', '.fi', '.fj', '.fk', '.fm', '.fo', '.fr', '.ga', '.gd', '.ge', '.gf', '.gg', '.gh', '.gi', '.gl', '.gm', '.gn', '.gp', '.gq', '.gr', '.gs', '.gt', '.gu', '.gv', '.gy', '.hk', '.hm', '.hn', '.hr', '.ht', '.hu', '.id', '.ie', '.il', '.im', '.in', '.io', '.iq', '.ir', '.is', '.it', '.je', '.jm', '.jo', '.jp', '.ke', '.kg', '.kh', '.ki', '.km', '.kn', '.kp', '.kr', '.kw', '.ky', '.kz', '.la', '.lb', '.lc', '.li', '.lk', '.lr', '.ls', '.lt', '.lu', '.lv', '.ly', '.ma', '.mc', '.md', '.mg', '.mh', '.mk', '.ml', '.mm', '.mn', '.mo', '.mp', '.mq', '.mr', '.ms', '.mt', '.mu', '.mv', '.mw', '.mx', '.my', '.mz', '.na', '.nc', '.ne', '.nf', '.ng', '.ni', '.nl', '.no', '.np', '.nr', '.nu', '.nz', '.om', '.pa', '.pe', '.pf', '.pg', '.ph', '.pk', '.pl', '.pm', '.pn', '.pr', '.ps', '.pt', '.pw', '.py', '.qa', '.re', '.ro', '.rw', '.ru', '.sa', '.sb', '.sc', '.sd', '.se', '.sg', '.sh', '.si', '.sj', '.sk', '.sl', '.sm', '.sn', '.so', '.sr', '.st', '.sv', '.sy', '.sz', '.tc', '.td', '.tf', '.tg', '.th', '.tj', '.tk', '.tm', '.tn', '.to', '.tp', '.tr', '.tt', '.tv', '.tw', '.tz', '.ua', '.ug', '.uk', '.um', '.us', '.uy', '.uz', '.va', '.vc', '.ve', '.vg', '.vi', '.vn', '.vu', '.ws', '.wf', '.ye', '.yt', '.yu', '.za', '.zm', '.zw', '.me'); - - var mai = nname; - var val = true; - - var dot = mai.lastIndexOf("."); - var dname = mai.substring(0, dot); - var ext = mai.substring(dot, mai.length); - - if (dot > 2 && dot < 57) { - for (var i = 0; i < arr.length; i++) { - if (ext == arr[i]) { - val = true; - break; - } else { - val = false; - } - } - if (val === false) { - return "Invalid domain extension " + ext + ", please tell support to add it to allowed extensions."; - } else { - for (var j = 0; j < dname.length; j++) { - var dh = dname.charAt(j); - var hh = dh.charCodeAt(0); - if ((hh > 47 && hh < 59) || (hh > 64 && hh < 91) || (hh > 96 && hh < 123) || hh == 45 || hh == 46) { - if ((j === 0 || j == dname.length - 1) && hh == 45) { - return "Domain names should not start or end with a '-'."; - } - } else { - return "Your domain name should not have special characters"; - } - } - } - } else { - return "Your domain name is too short/long."; - } - return true; - }; - -exports.checkDomain = checkDomain; - -var escape_packages = function (str) { - return str.replace(/[^a-zA-Z0-9 \.\-_=<>@]+/g, ''); - }; -exports.escape_packages = escape_packages; - -var md5 = function (str) { - return crypto.createHash('md5').update(str).digest('hex'); - }; - -exports.md5 = md5; - -var rand_string = function (n) { - var cs = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'; - var cslen = cs.length; - var rtv = ''; - var rand_char = function () { - return cs.substr(Math.floor(Math.random() * cslen), 1); - }; - for (var i = 0; i < n; i++) { - rtv += rand_char(); - } - return rtv; - }; - -exports.rand_string = rand_string; - -var exec_array = function (arr, my_cb) { - var running = false; - var timer = null; - var do_job = function () { - running = true; - var v = arr.shift(); - exec(v, function (err, stdout, stderr) { - if (err) { - console.error('lib.exec_array exit: %d - %s', err.code, err.toString()); - } - if (stdout) { - console.log('%s stdout: %s', v, stdout); // Ugly output atm. - } - if (stderr) { - console.log('%s stderr: %s', v, stderr); // Ditto - } - running = false; - }); - }; - timer = setInterval(function () { - if (arr.length > 0) { - if (running === false) { - do_job(); - } - } else { - clearInterval(timer); - my_cb(); - } - }, 250); - }; - -exports.exec_array = exec_array; - -var is_mounted = function (pat, cb) { - exec('mount | grep \'' + pat + '\'', function (err, stdout, stderr) { - var pos = stdout.indexOf(pat); - if (pos > -1) { - cb(true); - } else { - cb(false); - } - }); - }; - -exports.is_mounted = is_mounted; - -var ensure_mounted = function (src, tgt, opts, cb) { - is_mounted(tgt, function (resp) { - if (resp === true) { - cb(true); - } else { - var cmd = 'sudo mount ' + opts + ' ' + src + ' ' + tgt; - exec(cmd, function (err, stdout, stderr) { - is_mounted(tgt, function (resp) { - if (resp === true) { - cb(true); - } else { - cb(false); - } - }); - }); - } - }); - }; - -exports.ensure_mounted = ensure_mounted; - -var tear_down_unionfs_chroot = function (chroot_base, git_home, rw_folder, final_chroot, callback) { - var chr = new chroot(final_chroot); - chr.mounted = true; - chr.stop(function (err, resp) { - // Ignore output... - // BAD need to fix this... - if (err) { - console.log('tear_down_unionfs_chroot error: ' + err); - } - var ufs = new unionfs(chroot_base, git_home, rw_folder, final_chroot); - ufs.mounted = true; - ufs.stop(function (err, resp) { - callback(); - }); - }); - }; - -exports.tear_down_unionfs_chroot = tear_down_unionfs_chroot; - -var setup_unionfs_chroot = function (chroot_base, git_home, rw_folder, final_chroot, callback) { - var ufs = new unionfs(chroot_base, git_home, rw_folder, final_chroot); - ufs.start(function (err, resp) { - if (err) { - console.error('Error setting up unionfs mounts'); - console.error(err); - callback(false); - } else { - var chr = new chroot(final_chroot); - chr.start(function (err, resp) { - if (err) { - console.error('Error setting up chroot mounts'); - console.error(err); - callback(false); - } else { - callback(true); - } - }); - } - }); - }; - -exports.setup_unionfs_chroot = setup_unionfs_chroot; diff --git a/lib/logger.js b/lib/logger.js deleted file mode 100644 index fccb9c59..00000000 --- a/lib/logger.js +++ /dev/null @@ -1,66 +0,0 @@ -var cradle = require('cradle'); -var lib = require('./lib'); -var sys = require('sys'); -var config = require('../config'); - -var logger = function(app_name) {}; -logger.prototype.setup = function(app_name, cb) { - var self = this; - self.app_name = app_name; - self.curr_id = null; - self.conn = new cradle.Connection({ - host: config.opt.couch_host, - port: config.opt.couch_port, - auth: { - user: config.opt.couch_user, - pass: config.opt.couch_pass - }, - options: { - cache: false, - raw: false - } - }); - self.db = self.conn.database(lib.couch_prefix + 'logs'); - self.db.get(self.app_name + '_position', function(err, doc) { - if (err) { - if (err.error == 'not_found') { - self.curr_id = 1; - cb(null); - } else { - cb(err); - } - } else { - self.curr_id = parseInt(doc.current_id, 10); - cb(null); - } - }); -}; -logger.prototype.log = function(message, cb) { - var self = this; - if (self.curr_id !== null) { - self.db.save(self.app_name + '_' + self.curr_id, { - message: message - }, function(err, res) { - if (err !== null) { - cb(err); - } else { - self.curr_id++; - self.db.save(self.app_name + '_position', { - current_id: self.curr_id - }, function(err, res) { - if (err !== null) { - cb(err); - } else { - cb(null); - } - }); - } - // console.log(err); - // console.log(res); - }); - } else { - cb("Error: curr_id == null"); - } -}; - -exports.logger = logger; \ No newline at end of file diff --git a/lib/middle.js b/lib/middle.js deleted file mode 100644 index 197c6f32..00000000 --- a/lib/middle.js +++ /dev/null @@ -1,121 +0,0 @@ -var lib = require('./lib'), - cradle = require('cradle'), - config = require('../config'); - -/** - * Dynamic express route to authenticate a user from CouchDB - */ -var authenticate = function(req, res, next) { - var basicauth = req.headers.authorization; - - if (typeof basicauth != 'undefined' && basicauth.length > 0) { - var buff = new Buffer(basicauth.substring(basicauth.indexOf(" ") + 1), encoding = 'base64'); - var creds = buff.toString('ascii'); - - var username = creds.substring(0, creds.indexOf(":")); - var password = creds.substring(creds.indexOf(":") + 1); - - var db = lib.get_couchdb_database('nodefu'); - db.get(username, function(err, doc) { - if (err) { - console.log(err); - res.writeHead(401, { - 'Content-Type': 'application/json' - }); - // res.end('{"status" : "failure", "message": "couchdb error."}\n'); - // Notifiy Admins that couchdb is failing maybe? if not not_found error - res.end('{"status" : "failure", "message": "Invalid username or password. CouchDB lookup failed."}\n'); - } else { - if (doc._id == username && doc.password == lib.md5(password)) { - req.user = doc; - next(); - } else { - res.writeHead(401, { - 'Content-Type': 'application/json' - }); - res.end('{"status" : "failure", "message": "Invalid username or password."}\n'); - } - } - }); - } else { - res.writeHead(401, { - 'Content-Type': 'application/json' - }); - res.write('{"status" : "No authentication data sent."}\n'); - res.end(); - } -}; - -/** - * Use CouchDB to get repo information, this route must come AFTER middle.authenticate - */ -var authenticate_app = function(req, res, next) { - //GET Request - var appname = req.params.appname; - //POST|DELETE|PUT requests - if (!appname && req.query && req.query.appname) { - appname = req.query.appname; - } - if (!appname && req.body && req.body.appname) { - appname = req.body.appname; - } - if (appname) { - appname = appname.toLowerCase(); - } - - if (!appname || appname === '') { - res.writeHead(400, { - 'Content-Type': 'application/json' - }); - res.end('{"status" : "Must pass an application name (appname)."}\n'); - return; - } - - if (req.user) { - var db = lib.get_couchdb_database('apps'); - db.get(appname, function(err, doc) { - if (err) { - res.writeHead(400, { - 'Content-Type': 'application/json' - }); - res.end('{"status" : "failure - app not found (' + appname + ')"}\n'); - } else { - if (doc.username == req.user._id || req.user._id == 'dan') { - req.appname = appname; - req.repo = req.app = doc; - next(); - } else { - res.writeHead(400, { - 'Content-Type': 'application/json' - }); - res.end('{"status" : "failure - authentication for ' + appname + ' failed."}\n'); - } - } - }); - } else { - res.writeHead(400, { - 'Content-Type': 'application/json' - }); - res.end('{"status" : "failure - authentication."}\n'); - } -}; - - -module.exports.authenticate = authenticate; -module.exports.authenticate_app = authenticate_app; -/* - * Generic request error handler. - */ -module.exports.error = function() { - return function(req, res, next) { - res.error = function(code, message) { - res.writeHead(code, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: message - })); - }; - next(); - }; -}; \ No newline at end of file diff --git a/lib/npm.js b/lib/npm.js deleted file mode 100644 index ea8c6ef5..00000000 --- a/lib/npm.js +++ /dev/null @@ -1,60 +0,0 @@ -var request = require('request'), - path = require('path'), - lib = require('./lib'), - config = require('../config'), - exec = require('child_process').exec; - -module.exports = { - post: function(req, res, next) { - var appname = req.param("appname").toLowerCase(); - var action = req.param("action"); - var package = req.param("package"); - var user = req.user; - var app = req.app; - var good_action = false; - switch (action) { - case "install": - case "update": - case "uninstall": - case "list": - good_action = true; - break; - } - - if (good_action === true) { - var app_user_home = path.join(config.opt.apps_home_dir, app.username, app.repo_id + '_rw'); - console.log(action + " " + package + " into " + app_user_home); - var sep = ' '; - if (package.indexOf(',') > -1) { - sep = ','; - package = package.replace(/ /g, ''); - } - var p = package.split(sep); - - p.forEach(function(v, k) { - p[k] = lib.escape_packages(v); - }); - package = p.join(' '); - var cmd = 'cd ' + app_user_home + '; if [ ! -d node_modules ]; then mkdir node_modules; fi; npm ' + action + ' ' + package; - var pr = exec(cmd, function(err, stdout, stderr) { - res.send({ - status: 'success', - output: "stdout: " + stdout + "\nstderr: " + stderr - }); - }); -/* - Why oh why doesn't this work.. Still the code above is, so that's good for me! - var app_user_home = path.join(config.opt.home_dir, config.opt.hosted_apps_subdir, user._id, app.repo_id); - var n = new npmwrapper(); - n.setup(path.join(app_user_home, '.node_libraries'), path.join(app_user_home, '.npm_bin'), path.join(app_user_home, '.npm_man'), action, package); - n.run(function (output) { - res.writeHead(200, {'Content-Type': 'application/json'}); - res.write(JSON.stringify({"status": 'success', output: output}) + '\n'); - res.end(); - }); -*/ - } else { - res.error(400, "failure - invalid action parameter"); - } - } -}; \ No newline at end of file diff --git a/lib/reset_password.js b/lib/reset_password.js deleted file mode 100644 index 2d45f3c9..00000000 --- a/lib/reset_password.js +++ /dev/null @@ -1,69 +0,0 @@ -var config = require('../config'), - lib = require('./lib'); - -function loadAccount(user, cb) { - var nodefu = lib.get_couchdb_database('nodefu'); - - nodefu.get(user, function(err, res) { - if (err) { - cb(null); - } else { - cb(res); - } - }); -}; - -function writeResponse(response, status, message) { - response.writeHead(status, {'Content-Type':'application/json'}) - response.end(JSON.stringify(message)) -} - -function send500(res, err) { - writeResponse(res, 500, {status: "failure", message: err.error + ' - ' + err.reason + '\n'}) -} - -module.exports = { - post: function(req, res, next) { - var user = req.body.user; - - loadAccount(user, function(account) { - if (account != null) { - - lib.get_couchdb_connection().uuids(1, function(err, doc) { - - var resets = lib.get_couchdb_database('password_resets') - resets.save(account.email, {email_sent:false, token:doc[0], user:account._id}, function(err, resp) { - if (err) { - send500(res, err); - } else { - writeResponse(res, 201,{status: "Reset password token sent to " + account.email}); - } - }) - }) - } else { - writeResponse(res, 400,{status: "Failure", message:"Invalid user provided"}); - } - }) - } , - put: function(req, res, next) { - var token = req.params.token, - password = req.body.password; - resets = lib.get_couchdb_database('password_resets'); - resets.view('tokens/list',{keys:[token]}, function(err, doc) { - if (doc && doc.length==1 && doc[0].value.token === token) { - var account = doc[0].value, - nodefu = lib.get_couchdb_database('nodefu'); - nodefu.merge(account.user, {password: lib.md5(password)}, function(err, resp) { - if (resp) { - resets.remove(account._id,account._rev ); - writeResponse(res, 200, {status:"success", message:"Your password has been updated."}); - } else { - send500(res, err); - } - }) - } else { - writeResponse(res, 404, {status:"failure", messages:"No such token"}); - } - }); - } -}; diff --git a/lib/status.js b/lib/status.js deleted file mode 100644 index e4700b2a..00000000 --- a/lib/status.js +++ /dev/null @@ -1,35 +0,0 @@ -var request = require('request'), - cradle = require('cradle'), - lib = require('./lib'), - config = require('../config'); - -module.exports = { - get: function (req, res, next) { - var apps = lib.get_couchdb_database('apps'); - var hostedapps = 0; - var countrunning = 0; - apps.view('nodeapps/all', {}, function (err, resp) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - resp.forEach(function (row) { - if (row.running == "true") { - countrunning++; - } - hostedapps++; - }); - res.send({ - status: "up", - appshosted: hostedapps, - appsrunning: countrunning - }); - } - }); - } -}; \ No newline at end of file diff --git a/lib/unionfs.js b/lib/unionfs.js deleted file mode 100644 index cedc81ec..00000000 --- a/lib/unionfs.js +++ /dev/null @@ -1,107 +0,0 @@ -(function() { - var lib = require('./lib.js'); - var path = require('path'); - var fs = require('fs'); - var exec = require('child_process').exec; - - var unionfs = function(path_base, path_app, path_rw, target_path) { - this._setup(path_base, path_app, path_rw, target_path); - }; - unionfs.prototype._setup = function(path_base, path_app, path_rw, target_path) { - this.mounted = false; - this.errors = []; - // this.tmp_base = path.join('/', 'tmp', 'union_base_' + lib.rand_string(6)); - this.tmp_base = path.join(path.dirname(path_app), path.basename(path_app) + '_pre_chroot'); - this.tmp_base_os = path.join(this.tmp_base, 'os'); - this.tmp_base_app = path.join(this.tmp_base, 'app'); - this.tmp_base_app_app = path.join(this.tmp_base, 'app', 'app'); - this.tmp_base_rw = path.join(this.tmp_base, 'rw'); - this.path_base = path_base; - this.path_app = path_app; - this.path_rw = path_rw; - this.target_path = target_path; - }; - unionfs.prototype.start = function(cb) { - if (!path.existsSync(this.tmp_base)) fs.mkdirSync(this.tmp_base, '0777'); - if (!path.existsSync(this.tmp_base_os)) fs.mkdirSync(this.tmp_base_os, '0777'); - if (!path.existsSync(this.tmp_base_app)) fs.mkdirSync(this.tmp_base_app, '0777'); - if (!path.existsSync(this.tmp_base_app_app)) fs.mkdirSync(this.tmp_base_app_app, '0777'); - if (!path.existsSync(this.tmp_base_rw)) fs.mkdirSync(this.tmp_base_rw, '0777'); - if (!path.existsSync(this.target_path)) fs.mkdirSync(this.target_path, '0777'); - var unionfs_opts = 'cow,default_permissions,allow_other,use_ino,suid,chroot=' + this.tmp_base; - lib.ensure_mounted(this.path_base, this.tmp_base_os, '-o ro --bind', function(respA) { - if (respA === true) { - lib.ensure_mounted(this.path_app, this.tmp_base_app_app, '-o ro --bind', function(respB) { - if (respB === true) { - lib.ensure_mounted(this.path_rw, this.tmp_base_rw, '-o rw --bind', function(respC) { - if (respC === true) { - exec('sudo unionfs -o ' + unionfs_opts + ' /rw=RW:/app=RO:/os=RO ' + this.target_path, function(err, stdout, stderr) { - lib.is_mounted(this.target_path, function(respd) { - if (respd !== true) { - //this.errors.push(this.target_path + ' is not mounted'); - cb(this.errors, undefined); - } else { - this.mounted = true; - cb(undefined, true); - } - }.bind(this)); - }.bind(this)); - } else { - //this.errors.push(this.tmp_base_rw + ' is not mounted'); - cb(this.errors, undefined); - } - }.bind(this)); - } else { - //this.errors.push(this.tmp_base_app_app + ' is not mounted'); - cb(this.errors, undefined); - } - }.bind(this)); - } else { - //this.errors.push(this.tmp_base_os + ' is not mounted'); - cb(this.errors, undefined); - } - }.bind(this)); - }; - unionfs.prototype.stop = function(cb) { - if (this.mounted === true) { - var arr = ['sudo umount ' + this.target_path, 'sudo umount ' + this.tmp_base_rw, 'sudo umount ' + this.tmp_base_app_app, 'sudo umount ' + this.tmp_base_os - // 'rm -Rf ' + this.tmp_base - ]; - lib.exec_array(arr, function() { - lib.is_mounted(this.target_path, function(respA) { - if (respA !== false) { - this.errors.push(this.target_path + ' is still mounted'); - cb(this.errors, undefined); - } else { - lib.is_mounted(this.tmp_base_rw, function(respB) { - if (respB !== false) { - this.errors.push(this.tmp_base_rw + ' is still mounted'); - cb(this.errors, undefined); - } else { - lib.is_mounted(this.tmp_base_app_app, function(respB) { - if (respB !== false) { - this.errors.push(this.tmp_base_app_app + ' is still mounted'); - cb(this.errors, undefined); - } else { - lib.is_mounted(this.tmp_base_os, function(respB) { - if (respB !== false) { - this.errors.push(this.tmp_base_os + ' is still mounted'); - cb(this.errors, undefined); - } else { - this.mounted = false; - cb(undefined, true); - } - }.bind(this)); - } - }.bind(this)); - } - }.bind(this)); - } - }.bind(this)); - }.bind(this)); - } else { - cb('not_mounted', undefined); - } - }; - exports.unionfs = unionfs; -})(); diff --git a/lib/user.js b/lib/user.js deleted file mode 100644 index 42cf1f64..00000000 --- a/lib/user.js +++ /dev/null @@ -1,167 +0,0 @@ -var config = require('../config'), - cradle = require('cradle'), - lib = require('./lib'), - path = require('path'), - fs = require('fs'), - exec = require('child_process').exec; - - -module.exports = { - delete: function(req, res, next) { - var user = req.user; - // need to delete all users apps - // and stop all the users apps - var db = lib.get_couchdb_database('nodefu'); - db.get(user._id, function(err, doc) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - db.remove(user._id, doc._rev, function(err, resp) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - res.send({ - "status": "success" - }); - } - }); - } - }); - }, - put: function(req, res, next) { - - var user = req.user; - var newpass = req.body.password; - var rsakey = req.body.rsakey; - - if (newpass) { - var db = lib.get_couchdb_database('nodefu'); - db.get(user._id, function(err, doc) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - db.merge(user._id, { - password: lib.md5(newpass) - }, function(err, resp) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - res.send({ - status: "success", - message: "password updated" - }); - } - }); - } - }); - } else if (rsakey) { - exec('sudo ' + config.opt.app_dir + '/scripts/update_authkeys.js ' + config.opt.git_home_dir + '/' + user._id + ' "' + rsakey + '"'); - // This will improve when merging code to handle couchdb of all keys and generation of whole auth keys file in one go. - res.send({ - status: "success", - message: "rsa key added" - }); - } - }, - post: function(req, res, next) { - - var newuser = req.body.user; - var newpass = req.body.password; - var email = req.body.email; - var coupon = req.body.coupon; - var rsakey = req.body.rsakey; - - if (req.body.coupon == config.opt.coupon_code) { - - // check for symbols in password - if (newpass.match(/[~!@#$%^&*()_+=-]/) !== null) { - res.writeHead(400, { - 'Content-Type': 'application/json' - }); - res.write('{"status": "failure - symbols in password"}\n'); - res.end(); - } else { - - var db = lib.get_couchdb_database('nodefu'); - db.get(newuser, function(err, doc) { - if (err) { - if (err.error == 'not_found') { - if (typeof rsakey == 'undefined') { - res.writeHead(400, { - 'Content-Type': 'application/json' - }); - res.write('{"status": "failure - rsakey is invalid"}\n'); - res.end(); - } else { - exec('sudo ' + config.opt.app_dir + '/scripts/update_authkeys.js ' + config.opt.git_home_dir + '/' + newuser + ' "' + rsakey + '"'); - exec('sudo ' + config.opt.app_dir + '/bin/create_user_dir.js ' + newuser); - db.save(newuser, { - password: lib.md5(newpass), - email: email - }, function(err, resp) { - if (err) { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } else { - res.send({ - status: "success" - }); - } - }); - } - } else { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - status: "failure", - message: err.error + ' - ' + err.reason - }) + '\n'); - } - } else { - res.writeHead(400, { - 'Content-Type': 'application/json' - }); - res.write('{"status": "failure - account exists"}\n'); - res.end(); - } - }); - } - } else { - res.writeHead(500, { - 'Content-Type': 'application/json' - }); - res.write('{"status": "failure", "message": "invalid coupon"}\n'); - res.end(); - } - } -}; \ No newline at end of file diff --git a/package.json b/package.json index df21b193..bedb7268 100644 --- a/package.json +++ b/package.json @@ -8,24 +8,17 @@ "dependencies":{ "coffee-script":"*", - "colors":"*", - "nodemailer":"*", - "pool":"*", - "express":"*", - "request":"*", - "npm-wrapper":"*", "bouncy":"*", "cradle":"*", "nodeinfo":"*", - "socket.io":"*", - "daemon":"*" + "socket.io":"*" }, "engines":{ - "node":">= 0.4.7" + "node":">= 0.4.0" }, "licenses":[ { - "type":"MIT", + "type":"GNU Affero", "url":"http://github.com/nodester/nodester/blob/master/LICENSE.txt" } ] diff --git a/proxy/proxy.js b/proxy/proxy.js index 8fc34b88..a12027e2 100755 --- a/proxy/proxy.js +++ b/proxy/proxy.js @@ -9,12 +9,6 @@ console.log('Starting proxy initialization'); var proxymap = {}; -// Ghetto hack for error page -var errorPage = '{title}




logo

{code}

{error}

'; -var getErrorPage = function (title, code, error) { - return errorPage.replace('{title}', title).replace('{code}', code).replace('{error}', error); - }; - //Update proxymap any time the routing file is updated fs.watchFile(config.opt.proxy_table_file, function (oldts, newts) { fs.readFile(config.opt.proxy_table_file, function (err, data) { @@ -51,10 +45,9 @@ bouncy(function (req, bounce) { if (route) { bounce(route, { headers: { Connection: 'close' } }); } else { - //bounce(proxymap['404.nodester.com']); var res = bounce.respond(); res.statusCode = 404; - res.end(getErrorPage('404 - Application not found!', '404', 'Application does not exist')); + res.end(); } }).listen(80); console.log('Proxy initialization completed'); diff --git a/public/LICENSE.txt b/public/LICENSE.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/public/api.html b/public/api.html deleted file mode 100644 index 6ccebfea..00000000 --- a/public/api.html +++ /dev/null @@ -1,408 +0,0 @@ - - - - -Nodester | Open Source Node.JS Platform as a Service - - - - - - - - - - - - - - - -
-
-

-
- - - -
- -
-

Nodester CLI

-

You can install our Command Line Interface by running "npm install -g nodester-cli"

-

You can request a Nodester hosting coupon by running
nodester coupon <email address>

-

Once you have your coupon you can setup your account by running
- nodester user create <username> <password> <email address> <file containing ssh public key> <coupon code>

-

If you already registered through the site you can setup your CLI by running
- nodester user setup <username> <password>
- nodester user setkey <file containing ssh public key>
-

- -

CLI Commands

- - Format:
- nodester <command> <param1> <param2>

- - nodester coupon <email address>
- nodester user create <username> <password> <email address> <file containing ssh public key> <coupon code>
- nodester user setup <username> <password>

- nodester user setkey <file containing ssh public key>
- nodester user setpass sendtoken
- nodester user setpass <token> <new_password>


- nodester apps list
- nodester app create <appname> <initial js file>
- nodester app info <appname>
- nodester app logs <appname>
- nodester app start <appname>
- nodester app restart <appname>
- nodester app stop <appname>
- nodester app gitreset <appname>

- nodester npm install <appname> <package name>
- nodester npm upgrade <appname> <package name>
- nodester npm uninstall <appname> <package name>

- nodester appdomain add <appname> <domain-name>
- nodester appdomain delete <appname> <domain-name>
- nodester appdomains
-
- -

REST API

- - -

COUPON REQUEST

-

Request Coupon :: POST -
Base URL: http://nodester.com

- /coupon - creates coupon request for early access (pass in email)

- curl -X POST -d "email=your_address@gmail.com" http://nodester.com/coupon
- - -

STATUS

-

Get Status :: GET -
Base URL: http://nodester.com

- /status - Returns platform status and number of apps running

- curl http://nodester.com/status
- - -

USER

-

Register User :: POST (Coupon is required.) -
Base URL: http://nodester.com

- /user - creates user account (pass in user and password and email and id_rsa.pub string) Ensure that all + in the ssh key are substituted for their %2B counter parts, else your key will break. Run this on your command line to copy your RSA string and swap out the plus signs: "cat ~/.ssh/id_rsa.pub | sed s/'+'/'%2B'/g | pbcopy"

- curl -X POST -d "coupon=mycoupon&user=testuser&password=123&email=chris@nodester.com&rsakey=ssh-rsa AAAAB3NzaC1yc..." http://nodester.com/user
- -

Update User :: PUT -
Base URL: http://api.nodester.com

- /user - update user account (pass in password and/or RSA key - "cat ~/.ssh/id_rsa.pub | sed s/'+'/'%2B'/g | pbcopy")

- curl -X PUT -u "testuser:123" -d "password=test" http://api.nodester.com/user
- curl -X PUT -u "testuser:123" -d "rsakey=1234567" http://api.nodester.com/user
- -

Delete User :: DELETE -
Base URL: http://api.nodester.com

- /user - delete user account (requires basic auth)

- curl -X DELETE -u "testuser:123" http://api.nodester.com/user
- - -

APP

-

Create Application :: POST -
Base URL: http://api.nodester.com

- - /app - create nodejs app for hosting (requires basic auth and returns the port address required for use along with a git repo to push to)

- curl -X POST -u "testuser:123" -d "appname=a&start=hello.js" http://api.nodester.com/app
- -

Change Application :: PUT -
Base URL: http://api.nodester.com

- - /app - update starting app name (requires basic auth, appname, and starting page and returns the port address required for use along with a git repo to push to and running status of the app)

- curl -X PUT -u "testuser:123" -d "appname=a&start=hello1.js" http://api.nodester.com/app
-

- or -

- /app - start and stop your hosted nodejs app (requires basic auth, appname, and running=true|false and returns the port address required for use along with a git repo to push to)

- curl -X PUT -u "testuser:123" -d "appname=a&running=true" http://api.nodester.com/app
- -

Delete Application :: DELETE -
Base URL: http://api.nodester.com

- - /app - delete nodejs app (requires basic auth and appname)

- curl -X DELETE -u "testuser:123" -d "appname=test" http://api.nodester.com/app
- -

Application Information :: GET -
Base URL: http://api.nodester.com

- - /app/<appname> - get nodejs app info (requires basic auth and appname)

- curl -u "testuser:123" http://api.nodester.com/app/appname
- - /applogs/<appname> - get nodejs app logs (requires basic auth and appname)

- curl -u "testuser:123" http://api.nodester.com/applogs/appname
- - -

ENV

-

Create/Update Environment :: PUT -
Base URL: http://api.nodester.com

- - /env - create/update environment key/value pair (requires basic auth, appname, and environment key and value)

- curl -X PUT -u "testuser:123" -d "appname=a&key=color&value=blue" http://api.nodester.com/env
- -

Delete Environment :: DELETE -
Base URL: http://api.nodester.com

- - /env - delete environment key/value pair (requires basic auth, appname, and environment key)

- curl -X DELETE -u "testuser:123" -d "appname=test&key=color" http://api.nodester.com/env
- -

Environment Information :: GET -
Base URL: http://api.nodester.com

- - /env - get environment info (requires basic auth, appname, and environment key)

- curl -u "testuser:123" -d "appname=test&key=color" http://api.nodester.com/env
- -

APPS

-

All Applications Information :: GET -
Base URL: http://api.nodester.com

- /apps - get all nodejs app info(requires basic auth)

- curl -u "testuser:123" http://api.nodester.com/apps
- - -

NPM

-

Install/Upgrade/Uninstall NPM Packages :: POST -
Base URL: http://api.nodester.com

- /npm - Allows you to manage the NPM packages for an application.

- curl -X POST -u "testuser:123" -d "appname=a&action=install&package=express" http://api.nodester.com/npm

- curl -X POST -u "testuser:123" -d "appname=a&action=update&package=express" http://api.nodester.com/npm

- curl -X POST -u "testuser:123" -d "appname=a&action=uninstall&package=express" http://api.nodester.com/npm

- - -

APPDOMAINS - Add DNS A Record for 50.16.203.53

-

Create Application Domain :: POST -
Base URL: http://api.nodester.com

- - /appdomains - create app domain for hosting example.com (requires basic auth)

- curl -X POST -u "testuser:123" -d "appname=test&domain=example.com" http://api.nodester.com/appdomains
- -

Delete Application Domain :: DELETE -
Base URL: http://api.nodester.com

- - /appdomains - delete app domain for hosting example.com (requires basic auth)

- curl -X DELETE -u "testuser:123" -d "appname=test&domain=example.com" http://api.nodester.com/appdomains
- -

Application Domain Information :: GET -
Base URL: http://api.nodester.com

- - /appdomains - get list of your domains (requires basic auth)

- curl -u "testuser:123" http://api.nodester.com/appdomains
- - -

RESET_PASSWORD

-

Reset Password :: POST -
Base URL: http://api.nodester.com

- /reset_password - Sends a e-mail with a token to reset your user password

- curl -X POST -d "user=your_username" http://nodester.com/reset_password
- -

Reset Password :: PUT -
Base URL: http://api.nodester.com

- /reset_password/<token> - Updates your password using the provided token

- curl -X PUT -d "password=your_new_password" http://nodester.com/reset_password/<token>
- - -

GIT

-

Deploying and updating your Node.js application is simple.

-

curl -X POST -u "testuser:123" -d "appname=myapp&start=hello.js" http://api.nodester.com/app

-

Upon creating or changing your application via our API, you will receive a Git reop URL from our API response. Add a Nodester remote to your project as follows:

-

git remote add nodester the_url_returned_by_our_api

-

Finally push your updates to your new Nodester environment as follows:

-

git push nodester master

-

Also make sure that you update your project's port address with the new one assigned by Nodester.

-

Start your application.

-

curl -X PUT -u "testuser:123" -d "appname=myapp&running=true" http://api.nodester.com/app

-

Don't worry :) You only need to start the application once. Subsequent git pushes will automatically pick up your changes and restart.

-

Visit your application via http://myapp.nodester.com

-
- -

 

- - -
-
-
- - - - - - diff --git a/public/background.png b/public/background.png deleted file mode 100644 index 6a8dba82..00000000 Binary files a/public/background.png and /dev/null differ diff --git a/public/blog.html b/public/blog.html deleted file mode 100644 index 4e069462..00000000 --- a/public/blog.html +++ /dev/null @@ -1,181 +0,0 @@ - - - - -Nodester | Open Source Node.JS Hosting Platform - - - - - - - - - - - - - -
- - - - -
- -
-

 

-

NodeFu is now Nodester.

- -
-
-
- - - - - - diff --git a/public/examples.html b/public/examples.html deleted file mode 100644 index 7ce691cc..00000000 --- a/public/examples.html +++ /dev/null @@ -1,198 +0,0 @@ - - - - -ablaze - a free css template - - - - - -
-
-

sitename

-
- - - -
- -
-

Examples

- -

Heading H1

-

Heading H2

-

Heading H3

-

Heading H4

-
Heading H5
-

 

- - -

Lists

-
    -
  • List item
  • -
  • List item
  • -
  • List item
  • -
- -
    - -
  1. List item
  2. -
  3. List item
  4. -
  5. List item
  6. -
-

 

- - -

Code and blockquote

- <? echo('Hello world'); ?> - -

Mauris sit amet tortor in urna tincidunt aliquam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas

-

 

- - - -

Table

- - - - - - - - - - - - - - - - - - - - - - - -
IDNameAge
1John Smith28
2Fred James49
3Rachel Johnson19
-

 

- -

Form

-
- - Form legend -
-

-

-

-

-

-

-

-
- -
-
-
-
- - - diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index f662b73e..00000000 Binary files a/public/favicon.ico and /dev/null differ diff --git a/public/images/body-arrow.png b/public/images/body-arrow.png deleted file mode 100644 index 32227955..00000000 Binary files a/public/images/body-arrow.png and /dev/null differ diff --git a/public/images/body-bg-black.png b/public/images/body-bg-black.png deleted file mode 100644 index af787390..00000000 Binary files a/public/images/body-bg-black.png and /dev/null differ diff --git a/public/images/body-bg-slider.png b/public/images/body-bg-slider.png deleted file mode 100644 index 43c2e1d7..00000000 Binary files a/public/images/body-bg-slider.png and /dev/null differ diff --git a/public/images/body-bg-small-black.png b/public/images/body-bg-small-black.png deleted file mode 100644 index d374ce0a..00000000 Binary files a/public/images/body-bg-small-black.png and /dev/null differ diff --git a/public/images/body-bg-small.png b/public/images/body-bg-small.png deleted file mode 100644 index 5e531404..00000000 Binary files a/public/images/body-bg-small.png and /dev/null differ diff --git a/public/images/body-bg.png b/public/images/body-bg.png deleted file mode 100644 index c5dd090c..00000000 Binary files a/public/images/body-bg.png and /dev/null differ diff --git a/public/images/devfu.jpg b/public/images/devfu.jpg deleted file mode 100644 index f213cdce..00000000 Binary files a/public/images/devfu.jpg and /dev/null differ diff --git a/public/images/footer.jpg b/public/images/footer.jpg deleted file mode 100644 index fd3ebdb9..00000000 Binary files a/public/images/footer.jpg and /dev/null differ diff --git a/public/images/forkme_right_white_ffffff.png b/public/images/forkme_right_white_ffffff.png deleted file mode 100644 index 8fe3a7e1..00000000 Binary files a/public/images/forkme_right_white_ffffff.png and /dev/null differ diff --git a/public/images/granite.jpg b/public/images/granite.jpg deleted file mode 100644 index 6d5f2aa6..00000000 Binary files a/public/images/granite.jpg and /dev/null differ diff --git a/public/images/item-selected.gif b/public/images/item-selected.gif deleted file mode 100644 index f9dde31a..00000000 Binary files a/public/images/item-selected.gif and /dev/null differ diff --git a/public/images/nav-sprite.gif b/public/images/nav-sprite.gif deleted file mode 100644 index f0c8d32a..00000000 Binary files a/public/images/nav-sprite.gif and /dev/null differ diff --git a/public/images/ninjasmall.png b/public/images/ninjasmall.png deleted file mode 100644 index 0982f839..00000000 Binary files a/public/images/ninjasmall.png and /dev/null differ diff --git a/public/images/nodefu.png b/public/images/nodefu.png deleted file mode 100644 index 74c2dcba..00000000 Binary files a/public/images/nodefu.png and /dev/null differ diff --git a/public/images/nodestercast.jpg b/public/images/nodestercast.jpg deleted file mode 100644 index 9edaa84d..00000000 Binary files a/public/images/nodestercast.jpg and /dev/null differ diff --git a/public/images/nodesterrocket.ico b/public/images/nodesterrocket.ico deleted file mode 100644 index f662b73e..00000000 Binary files a/public/images/nodesterrocket.ico and /dev/null differ diff --git a/public/images/nodesterrocket.jpg b/public/images/nodesterrocket.jpg deleted file mode 100644 index b69f80d3..00000000 Binary files a/public/images/nodesterrocket.jpg and /dev/null differ diff --git a/public/images/nodesterrocketlogo.jpg b/public/images/nodesterrocketlogo.jpg deleted file mode 100644 index 25f6dc92..00000000 Binary files a/public/images/nodesterrocketlogo.jpg and /dev/null differ diff --git a/public/images/nodesterrocketlogo.png b/public/images/nodesterrocketlogo.png deleted file mode 100644 index 1d59bf43..00000000 Binary files a/public/images/nodesterrocketlogo.png and /dev/null differ diff --git a/public/images/nodesterrocketlogo2.jpg b/public/images/nodesterrocketlogo2.jpg deleted file mode 100644 index da13a5e0..00000000 Binary files a/public/images/nodesterrocketlogo2.jpg and /dev/null differ diff --git a/public/images/nodestervideo.jpg b/public/images/nodestervideo.jpg deleted file mode 100644 index 6f371447..00000000 Binary files a/public/images/nodestervideo.jpg and /dev/null differ diff --git a/public/images/rocket-md-right.png b/public/images/rocket-md-right.png deleted file mode 100644 index f59b0fd9..00000000 Binary files a/public/images/rocket-md-right.png and /dev/null differ diff --git a/public/images/rocket-md.png b/public/images/rocket-md.png deleted file mode 100644 index 1dc8eef0..00000000 Binary files a/public/images/rocket-md.png and /dev/null differ diff --git a/public/images/slide-1.png b/public/images/slide-1.png deleted file mode 100644 index 8755b26b..00000000 Binary files a/public/images/slide-1.png and /dev/null differ diff --git a/public/images/slide-2.png b/public/images/slide-2.png deleted file mode 100644 index 1e7c896e..00000000 Binary files a/public/images/slide-2.png and /dev/null differ diff --git a/public/images/slide-3.png b/public/images/slide-3.png deleted file mode 100644 index 77559c17..00000000 Binary files a/public/images/slide-3.png and /dev/null differ diff --git a/public/images/slide-next.gif b/public/images/slide-next.gif deleted file mode 100644 index 49607621..00000000 Binary files a/public/images/slide-next.gif and /dev/null differ diff --git a/public/images/slide-prev.gif b/public/images/slide-prev.gif deleted file mode 100644 index b15fc82d..00000000 Binary files a/public/images/slide-prev.gif and /dev/null differ diff --git a/public/images/smallblackninja.gif b/public/images/smallblackninja.gif deleted file mode 100644 index b041e775..00000000 Binary files a/public/images/smallblackninja.gif and /dev/null differ diff --git a/public/images/smallwhiteninja.gif b/public/images/smallwhiteninja.gif deleted file mode 100644 index fbca7049..00000000 Binary files a/public/images/smallwhiteninja.gif and /dev/null differ diff --git a/public/images/stopwatch.jpg b/public/images/stopwatch.jpg deleted file mode 100644 index 701c9206..00000000 Binary files a/public/images/stopwatch.jpg and /dev/null differ diff --git a/public/images/top-nav-hover-left.gif b/public/images/top-nav-hover-left.gif deleted file mode 100644 index cffd1a4d..00000000 Binary files a/public/images/top-nav-hover-left.gif and /dev/null differ diff --git a/public/images/top-nav-selected-left.gif b/public/images/top-nav-selected-left.gif deleted file mode 100644 index 1a242cc0..00000000 Binary files a/public/images/top-nav-selected-left.gif and /dev/null differ diff --git a/public/images/tropowhite.png b/public/images/tropowhite.png deleted file mode 100644 index 764aa98e..00000000 Binary files a/public/images/tropowhite.png and /dev/null differ diff --git a/public/images/video.jpg b/public/images/video.jpg deleted file mode 100644 index b9fbb0e4..00000000 Binary files a/public/images/video.jpg and /dev/null differ diff --git a/public/images/warriors.gif b/public/images/warriors.gif deleted file mode 100644 index eabb382e..00000000 Binary files a/public/images/warriors.gif and /dev/null differ diff --git a/public/index.html b/public/index.html deleted file mode 100644 index 23a98402..00000000 --- a/public/index.html +++ /dev/null @@ -1,260 +0,0 @@ - - - - -Nodester | Open Source Node.JS Platform as a Service - - - - - - - - - - - - - - - - - -
-
-

-
- - - - -
-

- - - - - - - -
-

Preparing for Launch.

-

Request your free Nodester Node.JS hosting coupon.

- curl -X POST -d "email=your_address@gmail.com" http://nodester.com/coupon -
-

All Systems Go!

-

You have received your coupon and you're ready to install our Command Line Interface (CLI).

-
    -
  1. npm install nodester-cli -g
  2. -
  3. nodester user setup <username> <password>
  4. -
  5. nodester user setkey <file containing ssh public key>
  6. -
-
-

3-2-1 Launch App!

-

You are ready to deploy your test Hello World app with 2 commands.

-
    -
  1. nodester app create <app-name> <initial js file>
  2. -
  3. nodester app init <app-name>
  4. -
-

Visit http://myapp.nodester.com!

-
- - - - -

Experienced Nodester with Existing App?

-

Simply skip the init command and add a nodester git remote! Init basically creates a hello world app for you locally, adds git and the nodester remote, pushes your app to nodester, and launches it.

- - nodester app create myapp

- nodester app info myapp

- git remote add nodester the_url_returned_by_our_api and git push nodester master

-
- Do you have NPM modules? - - nodester npm install myapp express socket.io etc

- nodester app start myapp -
-

- OR use our REST API-

- - curl -X POST -u "testuser:123" -d "appname=myapp&start=hello.js" http://api.nodester.com/app

- git remote add nodester the_url_returned_by_our_api and git push nodester master

- NPM modules? curl -X POST -u "testuser:123" -d "appname=myapp&action=install&package=express" http://api.nodester.com/npm

- curl -X PUT -u "testuser:123" -d "appname=myapp&running=true" http://api.nodester.com/app -
- Visit your app at http://myapp.nodester.com -

Don't worry :) You only need to start the application once. Subsequent git pushes will automatically pick up your changes and restart.

-
-
-
- - - - - - diff --git a/public/jquery-1.4.4.min.js b/public/jquery-1.4.4.min.js deleted file mode 100644 index 8f3ca2e2..00000000 --- a/public/jquery-1.4.4.min.js +++ /dev/null @@ -1,167 +0,0 @@ -/*! - * jQuery JavaScript Library v1.4.4 - * http://jquery.com/ - * - * Copyright 2010, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2010, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Thu Nov 11 19:04:53 2010 -0500 - */ -(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute("data-"+b);if(typeof d==="string"){try{d=d==="true"?true:d==="false"?false:d==="null"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?"events":"__events__");if(typeof h==="function")h= -h.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type==="click")){if(a.namespace)A=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var J=h.live.slice(0);for(k=0;kd)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La, -"`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this, -e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a, -"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+ -a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/, -C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j, -s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this, -j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length}, -toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j=== --1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false; -if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload", -b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&& -!F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&& -l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H
a";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"), -k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false, -scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent= -false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom= -1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="
";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="
t
";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display= -"none"});a=function(r){var A=t.createElement("div");r="on"+r;var C=r in A;if(!C){A.setAttribute(r,"return;");C=typeof A[r]==="function"}return C};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h= -c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando); -else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one"; -if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true}, -attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&& -b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0}; -c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem, -arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid= -d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=f.split(".");f=o.shift();x=RegExp("(^|\\.)"+ -c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType=== -8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k=== -"click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+ -d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired= -B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type=== -"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]=== -0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}}); -(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3]; -break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr, -q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h= -l;g.sort(w);if(h)for(var i=1;i0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n, -m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled=== -true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"=== -g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return in[3]-0},nth:function(g,i,n){return n[3]- -0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()=== -i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]]; -if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m, -g);else if(typeof g.length==="number")for(var p=g.length;n";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g); -n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&& -function(){var g=k,i=t.createElement("div");i.innerHTML="

";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F|| -p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g= -t.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition? -function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n0)for(var h=d;h0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h= -h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context): -c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a, -2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a, -b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&& -e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/\s]+\/)>/g,P={option:[1, -""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= -c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, -wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, -prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, -this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); -return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null; -else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Aa,"<$1>");try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append", -prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument|| -b[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]===""&&!x?r.childNodes:[];for(o=k.length- -1;o>=0;--o)c.nodeName(k[o],"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script")))); -d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i, -jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true, -zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b), -h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b); -if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f= -d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left; -e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/)<[^<]*)*<\/script>/gi, -ob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\[\]$/,T=/\=\?(&|$)/,ja=/\?/,rb=/([?&])_=[^&]*/,sb=/^(\w+:)?\/\/([^\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b=== -"object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(l,k){if(k==="success"||k==="notmodified")h.html(f?c("
").append(l.responseText.replace(nb,"")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&& -!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})}, -getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html", -script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ja.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data|| -!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+mb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType==="script"&&b.cache===null)b.cache= -false;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,"$1_="+o);b.url=x+(x===b.url?(ja.test(b.url)?"&":"?")+"_="+o:"")}if(b.data&&l)b.url+=(ja.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType==="script"&&h==="GET"&&o){var r=t.getElementsByTagName("head")[0]||t.documentElement,A=t.createElement("script");if(b.scriptCharset)A.charset=b.scriptCharset; -A.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader("Content-Type", -b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}o||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&& -c.triggerGlobal(b,"ajaxSend",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m==="timeout")){J=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d|| -c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L("abort")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L("timeout")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]= -encodeURIComponent(h)+"="+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join("&").replace(tb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess", -[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"), -e=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}}); -if(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\-]=)?([\d+.\-]+)(.*)$/,ba,pa=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show", -3),a,b,d);else{d=0;for(var e=this.length;d=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b, -d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a* -Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)} -var f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true; -this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(k,o){f.style["overflow"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide|| -this.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a= -c.timers,b=0;b-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;"using"in b?b.using.call(a, -e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&& -c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase(); -c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b];else if(f.nodeType===9)return Math.max(f.documentElement["client"+ -b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e==="string"?e:e+"px")}})})(window); diff --git a/public/ninjawhite300.gif b/public/ninjawhite300.gif deleted file mode 100644 index 28c1ff6f..00000000 Binary files a/public/ninjawhite300.gif and /dev/null differ diff --git a/public/ninjawhite300trans.gif b/public/ninjawhite300trans.gif deleted file mode 100644 index c663fcfb..00000000 Binary files a/public/ninjawhite300trans.gif and /dev/null differ diff --git a/public/nodefu.gif b/public/nodefu.gif deleted file mode 100644 index ad0ee6ed..00000000 Binary files a/public/nodefu.gif and /dev/null differ diff --git a/public/page.html b/public/page.html deleted file mode 100644 index 931a58cf..00000000 --- a/public/page.html +++ /dev/null @@ -1,134 +0,0 @@ - - - - -ablaze - a free css template - - - - - -
-
-

sitename

-
- - - -
- -
-

Malesuada nec iaculis

-

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus arcu arcu, ornare nec interdum id, commodo vitae turpis. Nunc porttitor tincidunt erat, vitae tincidunt leo dignissim at. Nunc ut erat nisl, vitae egestas lorem. In facilisis tortor quam. Morbi lacinia nunc pulvinar ipsum aliquet nec ornare enim tincidunt. Fusce nulla sapien, vestibulum sit amet sodales tristique, venenatis in lorem. Nunc at erat felis. Suspendisse potenti.

-

Nunc condimentum mollis dolor, id auctor quam vehicula id. Phasellus nibh est, malesuada nec iaculis sit amet, mattis sed velit. Maecenas vestibulum volutpat lacinia. Sed vestibulum tortor at erat volutpat ultricies. Etiam non lectus metus, ut porttitor ipsum. Vivamus ultrices aliquet ultricies. Integer magna magna, mollis non fermentum a, hendrerit ac velit. Nunc at urna sit amet risus semper pellentesque sit amet vel dui. Maecenas commodo porta eros, pulvinar pharetra neque porttitor nec.

- -

Lectus urna

-

Fusce lobortis turpis ligula, sit amet pharetra augue. Suspendisse potenti. Curabitur nulla massa, elementum vel luctus id, bibendum a tortor. Nullam ut ligula nec sem vehicula adipiscing ut sit amet velit. Nunc id erat vitae quam ornare rhoncus. Cras commodo, nulla nec sollicitudin iaculis, nisl massa convallis ante, ut consectetur tortor ipsum sit amet turpis.

-

Retium turpis

-

Nam ligula dui, viverra quis auctor non, blandit pretium turpis. Aenean eu neque arcu. Fusce cursus, elit sit amet dignissim pretium, lacus eros mattis massa, ut iaculis velit purus id dui. Ut feugiat tincidunt dui. Nulla ut massa risus. Praesent dictum convallis ultricies. Integer accumsan, nulla sit amet posuere mollis, lectus urna suscipit dui, quis iaculis odio turpis a risus. Fusce suscipit molestie dui, varius lobortis purus dapibus et. Suspendisse eleifend augue at nibh molestie condimentum. Nunc nunc elit, dapibus nec sodales nec, sollicitudin ac lacus.

-

Nulla sed semper

-

Nullam orci leo, placerat sed aliquam quis, tempus at lorem. In hendrerit turpis id odio accumsan sit amet sollicitudin nibh tristique. In fermentum vehicula libero eget lacinia. Donec eu ligula metus, sit amet eleifend mi.

-

Vivamus gravida adipiscing sem nec mollis. Fusce id lectus vitae leo fringilla elementum. Etiam porttitor dui in erat accumsan ac vehicula magna mollis. Fusce eu felis ac erat hendrerit blandit.

-
-
-
- - - diff --git a/public/readme and license.txt b/public/readme and license.txt deleted file mode 100644 index 73b589bb..00000000 --- a/public/readme and license.txt +++ /dev/null @@ -1,43 +0,0 @@ -******************************************************************** - SPYKA WEBMASTER - HTTP://WWW.SPYKA.NET - FREE WEB TEMPLATES AND RESOURCES FOR WEBMASTERS -******************************************************************** - -This is a free web template by spyka webmaster (http://www.spyka.net) - - - -1. Customizing this template ------------------------------------------ -To change the text, content, links etc. open the index.html in your preferred HTML editor, -whether it be notepad, dreamweaver or frontpage. - -To change the CSS open styles.css in a HTML/CSS editor and change the appropriate -values to suit your needs. - -Need more help? Try our webmaster forums - http://spyka.net/forums - - -2. Terms of use/License ------------------------------------------ -This template has been released under a Creative Commons Attribution license, this means you can use the template as -long as a visible link to spyka Webmaster (http://www.spyka.net) remains in the footer. - -This condition can be waived by purchasing a template license for £8.00 (See 4. Template License in this document) - -For more information of the license: http://creativecommons.org/licenses/by/3.0/ - - -3. Template License ------------------------------------------ -The link back to spyka.net and any other copyright/information relating to spyka.net can -be removed with the purchase of a template license. A license costs £8.00 (Approx $12USD) -per template per site and gives the site owner/webmaster the right to remove this information. - -To purchase a license or for more information see: http://www.spyka.net/licensing - - -4. Other information ------------------------------------------ -Please contact us if you need more information about template licences, use of our templates -or other queries - spyka.net/contact diff --git a/public/styles.css b/public/styles.css deleted file mode 100644 index 06e8be8c..00000000 --- a/public/styles.css +++ /dev/null @@ -1,542 +0,0 @@ -/** global **/ -body { - margin:0px auto; - padding:0; - font-family:Verdana, Geneva, sans-serif; - font-size:18px; - color:#555; - background:#eee url('images/body-bg-black.png') repeat-x; -} - -body.small-header { - background:#fff url('images/body-bg-small-black.png') repeat-x; -} - -body.slider-header { - background:#fff url('images/body-bg-slider.png') repeat-x; -} - -* { - margin:0; - padding:0; -} - -#ribbon { - position: fixed; - top: 0; - right: 0; - z-index: 2; } - -/** element defaults **/ -table { - width:100%; - font-family:Arial, Helvetica, sans-serif; - text-align:left; -} -th, td { - padding:5px 10px; -} -th { - color:#fff; - border-top:3px solid #870101; - background-color:#A50000; -} -td { - border-bottom:1px solid #f4f4f4; -} -code, blockquote { - display:block; - border-left:5px solid #ddd; - padding:10px; - margin-bottom:20px; -} -blockquote p { - font-style:italic; - font-family:Georgia, "Times New Roman", Times, serif; - margin:0; - height: 1%; -} -p { - line-height:1.9em; - margin-bottom:20px; -} -a { - color:#0D3C84; -} -a:hover { - color:#870101; -} -a:focus { - outline:none; -} -fieldset { - display:block; - border:none; - border-top:1px solid #e0e0e0; -} -fieldset legend { - font-weight:bold; - font-size:13px; - padding-right:10px; - color:#222; -} -fieldset form { - padding-top:15px; -} -fieldset p label { - float:left; - width:150px; - font-family:Arial, Helvetica, sans-serif; -} -form input, form select, form textarea { - padding:5px; - color:#333333; - font-size:13px; - font-family:Arial, Helvetica, sans-serif; - border:1px solid #ddd; -} -form input.formbutton { - margin-left:150px; - background:#A50000; - border:none; - border-bottom:3px solid #870101; - color:#ffffff; - font-weight:bold; - padding:5px 10px; - font-size:13px; -} -h1 { - font-size:45px; - font-family:Arial, Helvetica, sans-serif; -} -h2 { - color:#000; - font-family:Arial,Helvetica,sans-serif; - font-size:30px; - font-weight:bold; - letter-spacing:-2px; - padding:0 0 5px; - margin:0; -} -h3 { - font-family:Arial,Helvetica,sans-serif; - color:#0D357B; - font-size:20px; - padding-bottom:10px; -} -h4 { - font-family:Arial,Helvetica,sans-serif; - padding-bottom:10px; - font-size:15px; - color:#870101; -} -h5 { - padding-bottom:10px; - font-size:13px; - color:#666666; -} -ul, ol { - margin:0 0 35px 35px; -} -li { - padding-bottom:5px; -} - - -/** wrapper **/ -div#wrapper { -/* width:960px;*/ - width:100%; - margin:0px auto; - padding:0; -} - - -/** sitename **/ -div#sitename { - float:left; - width:30%; -} -div#sitename h1 { - font-size:48px; - letter-spacing:-5px; - margin:0; - height:72px; - padding:18px 0 0; - text-transform:uppercase; - text-shadow: 2px 2px #000; -} -div#sitename h1 a, -div#sitename h1 a:hover { - color:#fff; - font-weight:normal; - text-decoration:none; -} -div#sitename h1 strong { - color: #A81212; -} -div#nav { - width:65%; - float:right; - padding:30px 0 0 0; - margin:0; -} -div#nav ul { - list-style:none; - float:right; - padding:0 0 0 50px; - margin:-10px 0 0 50px; -} -div#nav ul li { - display:inline; - float:left; - margin:0 5px; - padding-bottom:0; -} -div#nav ul li a, div#nav ul li a:visited, div#nav ul li a:hover { - float:left; - text-decoration:none; - color:#ffffff; - font-weight:normal; - font-size: 13px; - font-family:Arial Rounded MT Bold, Helvetica, sans-serif; - display: block; -} -div#nav ul li a span { - display:block; - padding:10px; -} -div#nav ul li a:hover { - background: #ff9900 url('images/nav-sprite.gif') no-repeat scroll right -35px; -} -div#nav ul li a:hover span { - background: transparent url('images/top-nav-hover-left.gif') no-repeat; -} -div#nav ul li.selected a, div#nav ul li.selected a:hover { - background: #222 url('images/nav-sprite.gif') no-repeat scroll top right; -} -div#nav ul li.selected a span, div#nav ul li.selected a:hover span { - background: transparent url('images/top-nav-selected-left.gif') no-repeat; -} - -/** header **/ -div#header { - padding:40px 0 0; - margin:0 auto; -/* height:135px;*/ - background: #A50000; - height:425px; -} -div#headleft{ - float:left; - width:45%; - padding:30px; - font-family:Arial,Helvetica,sans-serif; - font-size:30px; -} -div#headleft p{ - font-family:Arial,Helvetica,sans-serif; - font-size:19px; -} - -div#headright{ - float:right; - width:45%; - padding:20px; - background: #111; - height:250px; - -} -.nodestercommand{ - color:#fff; -} -.nodesteroutput{ - color:#0f0; -} - -.small-header div#header { - padding-top: 25px; - height: 64px; -} - -.slider-header div#header { - height: 245px; -} - -div#header h2 { - color:yellow; - padding-bottom:0; - font-weight:normal; - font-family:Arial Rounded MT Bold, Arial,Helvetica,sans-serif; - font-size:32px; - letter-spacing:0; - text-shadow: 2px 2px #4C0101; -} -div#header div.tagline, div#header div.slide-text { - color:#eee; - font-size:14px; - padding-bottom:10px; - font-family:'Lucida Grande','Lucida Sans Unicode',Geneva,Verdana,Sans-Serif; -} -div#header div.tagline a { - color:#ffffff; -} - -/* front page slider styles */ -div#jFlowSlide { - margin:0 auto; -} -div#slides-container { - height:220px; -} -div#slides-container div#jFlowSlide { - height:200px; -} -div#slides-container div.jFlowSlideContainer img { - margin:auto; - display:block; - border:4px solid #313D45; -} -div#slides-container div.jFlowSlideContainer div { -} -div#slides-container div.jFlowSlideContainer div.slide-image { - float:left; - width:322px; - padding-top:10px; -} -span.jFlowPrev, span.jFlowNext { - background-image:url('images/slide-prev.gif'); - background-repeat:no-repeat; - display:block; - height:25px; - width:25px; - float:left; - margin:0; - cursor:pointer; -} -span.jFlowPrev span, span.jFlowNext span { display:none; } -span.jFlowNext { - background-image:url('images/slide-next.gif'); - float:right; -} -div#slides-container div.controls { - position:relative; - top:-125px; - width:960px; - margin:0 auto; -} -div.slide-text { - padding-top: 10px; -} - -/** body **/ -div#body { - padding:10px 0; -/* background: transparent url('images/body-arrow.png') no-repeat scroll 5px 0;*/ -} - - -/** content+sidebar styles **/ -div#contenthome { - width:95%; - margin:0 auto; -} -div#content { - width:75%; - margin:0 auto; -} -div.column-left { - float:left; - margin-right:20px; -} -div.column-right { - float:right; -} -div#sidebar { - width:200px; - padding-top: 15px; -} -div#sidebar ul { - margin:0; - padding:0; - list-style:none; -} -div#sidebar li ul { - margin-bottom:20px; - width:200px; -} -div#sidebar li ul li { - display:block; - padding:5px 0px; - color:#777; -} -div#sidebar li ul li a { - color:#999; - text-decoration:none; - font-weight:bold; -} -div#sidebar li ul li a:hover { - color:#09285E; - text-decoration:underline; -} - - -div#sidebar li ul.blocklist li { - padding:0; -} -div#sidebar li ul.blocklist li.selected-item a { - color:#870101; - font-weight:bold; - background:transparent url('images/item-selected.gif') no-repeat scroll right center; -} -div#sidebar li ul.blocklist li.selected-item a:hover { - text-decoration:none; -} -div#sidebar li ul.blocklist li a { - width:200px; - display:block; - padding:5px 0px; -} - -div#sidebar h4 { - color:#0C367E; - font-family:arial; - font-size:16px; - text-transform:uppercase; - font-weight:bold; - margin:0; - padding:7px 0px; -} - - -/** footer **/ -#footer { - margin:0 auto; - background: #000 url('images/footer.jpg') repeat-x scroll bottom left; - padding: 30px 5px 0; -} - -.footer-content { - width: 960px; - margin: 0 auto; - display: block; - padding-bottom: 30px; -} - -#footer a { - color: #999; - text-decoration: underline; -} - -#footer h4 { - color: #ccc; - font-size: 18px; - font-weight: normal; - font-family: 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, Sans-Serif; -} - -#footer p { - text-align: left; - color: #999; - font-size: 12px; - font-family: Arial, Helvetica, sans-serif; - margin: 0; - padding: 0; -} - -#footer form { - margin: 0; - padding: 0; -} - -#footer form input#searchbutton { - margin: 0; - border-bottom: none; - overflow:visible; - width:auto; -} - -#footer form input#searchquery { - background-color: #333; - color: #fff; - font-family: Arial, Helvetica, sans-serif; - border: none; - padding: 6px 3px; -} - -#footer ul { - margin: 0; - padding: 0; - list-style: none; - border-top: 1px solid #222; -} - -#footer ul li { - padding: 0; -} - -#footer ul li a { - display: inline-block; /* for IE 6, 7 */ -} - -#footer ul li a { - text-decoration: none; - display: block; - font-size: 11px; - padding: 7px 10px; - border-bottom: 1px solid #222; -} - -#footer ul li a:hover { - background-color: #111; -} - -.footer-box { - width: 220px; - margin-right: 26px; - float: left; -} - -.end-footer-box { - margin-right: 0; -} - -#footer-links { - background-color: #000; - color: #ccc; - padding: 5px; -} -div#footer-links p { - text-align: right; - padding: 0; - margin: 0 auto; - font-size: 10px; - width: 960px; - display: block; -} -#footer-links a { - color: #eee; - font-weight: bold; - text-decoration: underline; -} - - - - -/** clear fix **/ -.clear:after { - content: "."; - display: block; - clear: both; - visibility: hidden; - line-height: 0; - height: 0; -} - -.clear { - display: inline-block; -} -.clear { - clear:both; - display: block; -} diff --git a/public/thickbox.css b/public/thickbox.css deleted file mode 100644 index d24b9bed..00000000 --- a/public/thickbox.css +++ /dev/null @@ -1,163 +0,0 @@ -/* ----------------------------------------------------------------------------------------------------------------*/ -/* ---------->>> global settings needed for thickbox <<<-----------------------------------------------------------*/ -/* ----------------------------------------------------------------------------------------------------------------*/ -*{padding: 0; margin: 0;} - -/* ----------------------------------------------------------------------------------------------------------------*/ -/* ---------->>> thickbox specific link and font settings <<<------------------------------------------------------*/ -/* ----------------------------------------------------------------------------------------------------------------*/ -#TB_window { - font: 12px Arial, Helvetica, sans-serif; - color: #333333; -} - -#TB_secondLine { - font: 10px Arial, Helvetica, sans-serif; - color:#666666; -} - -#TB_window a:link {color: #666666;} -#TB_window a:visited {color: #666666;} -#TB_window a:hover {color: #000;} -#TB_window a:active {color: #666666;} -#TB_window a:focus{color: #666666;} - -/* ----------------------------------------------------------------------------------------------------------------*/ -/* ---------->>> thickbox settings <<<-----------------------------------------------------------------------------*/ -/* ----------------------------------------------------------------------------------------------------------------*/ -#TB_overlay { - position: fixed; - z-index:100; - top: 0px; - left: 0px; - height:100%; - width:100%; -} - -.TB_overlayMacFFBGHack {background: url(macFFBgHack.png) repeat;} -.TB_overlayBG { - background-color:#000; - filter:alpha(opacity=75); - -moz-opacity: 0.75; - opacity: 0.75; -} - -* html #TB_overlay { /* ie6 hack */ - position: absolute; - height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'); -} - -#TB_window { - position: fixed; - background: #ffffff; - z-index: 102; - color:#000000; - display:none; - border: 4px solid #525252; - text-align:left; - top:50%; - left:50%; -} - -* html #TB_window { /* ie6 hack */ -position: absolute; -margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px'); -} - -#TB_window img#TB_Image { - display:block; - margin: 15px 0 0 15px; - border-right: 1px solid #ccc; - border-bottom: 1px solid #ccc; - border-top: 1px solid #666; - border-left: 1px solid #666; -} - -#TB_caption{ - height:25px; - padding:7px 30px 10px 25px; - float:left; -} - -#TB_closeWindow{ - height:25px; - padding:11px 25px 10px 0; - float:right; -} - -#TB_closeAjaxWindow{ - padding:7px 10px 5px 0; - margin-bottom:1px; - text-align:right; - float:right; -} - -#TB_ajaxWindowTitle{ - float:left; - padding:7px 0 5px 10px; - margin-bottom:1px; -} - -#TB_title{ - background-color:#e8e8e8; - height:27px; -} - -#TB_ajaxContent{ - clear:both; - padding:2px 15px 15px 15px; - overflow:auto; - text-align:left; - line-height:1.4em; -} - -#TB_ajaxContent.TB_modal{ - padding:15px; -} - -#TB_ajaxContent p{ - padding:5px 0px 5px 0px; -} - -#TB_load{ - position: fixed; - display:none; - height:13px; - width:208px; - z-index:103; - top: 50%; - left: 50%; - margin: -6px 0 0 -104px; /* -height/2 0 0 -width/2 */ -} - -* html #TB_load { /* ie6 hack */ -position: absolute; -margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px'); -} - -#TB_HideSelect{ - z-index:99; - position:fixed; - top: 0; - left: 0; - background-color:#fff; - border:none; - filter:alpha(opacity=0); - -moz-opacity: 0; - opacity: 0; - height:100%; - width:100%; -} - -* html #TB_HideSelect { /* ie6 hack */ - position: absolute; - height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'); -} - -#TB_iframeContent{ - clear:both; - border:none; - margin-bottom:-1px; - margin-top:1px; - _margin-bottom:1px; -} diff --git a/public/thickbox.js b/public/thickbox.js deleted file mode 100644 index 86bcf738..00000000 --- a/public/thickbox.js +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Thickbox 3.1 - One Box To Rule Them All. - * By Cody Lindley (http://www.codylindley.com) - * Copyright (c) 2007 cody lindley - * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php -*/ - -var tb_pathToImage = "images/loadingAnimation.gif"; - -/*!!!!!!!!!!!!!!!!! edit below this line at your own risk !!!!!!!!!!!!!!!!!!!!!!!*/ - -//on page load call tb_init -$(document).ready(function(){ - tb_init('a.thickbox, area.thickbox, input.thickbox');//pass where to apply thickbox - imgLoader = new Image();// preload image - imgLoader.src = tb_pathToImage; -}); - -//add thickbox to href & area elements that have a class of .thickbox -function tb_init(domChunk){ - $(domChunk).click(function(){ - var t = this.title || this.name || null; - var a = this.href || this.alt; - var g = this.rel || false; - tb_show(t,a,g); - this.blur(); - return false; - }); -} - -function tb_show(caption, url, imageGroup) {//function called when the user clicks on a thickbox link - - try { - if (typeof document.body.style.maxHeight === "undefined") {//if IE 6 - $("body","html").css({height: "100%", width: "100%"}); - $("html").css("overflow","hidden"); - if (document.getElementById("TB_HideSelect") === null) {//iframe to hide select elements in ie6 - $("body").append("
"); - $("#TB_overlay").click(tb_remove); - } - }else{//all others - if(document.getElementById("TB_overlay") === null){ - $("body").append("
"); - $("#TB_overlay").click(tb_remove); - } - } - - if(tb_detectMacXFF()){ - $("#TB_overlay").addClass("TB_overlayMacFFBGHack");//use png overlay so hide flash - }else{ - $("#TB_overlay").addClass("TB_overlayBG");//use background and opacity - } - - if(caption===null){caption="";} - $("body").append("
");//add loader to the page - $('#TB_load').show();//show loader - - var baseURL; - if(url.indexOf("?")!==-1){ //ff there is a query string involved - baseURL = url.substr(0, url.indexOf("?")); - }else{ - baseURL = url; - } - - var urlString = /\.jpg$|\.jpeg$|\.png$|\.gif$|\.bmp$/; - var urlType = baseURL.toLowerCase().match(urlString); - - if(urlType == '.jpg' || urlType == '.jpeg' || urlType == '.png' || urlType == '.gif' || urlType == '.bmp'){//code to show images - - TB_PrevCaption = ""; - TB_PrevURL = ""; - TB_PrevHTML = ""; - TB_NextCaption = ""; - TB_NextURL = ""; - TB_NextHTML = ""; - TB_imageCount = ""; - TB_FoundURL = false; - if(imageGroup){ - TB_TempArray = $("a[@rel="+imageGroup+"]").get(); - for (TB_Counter = 0; ((TB_Counter < TB_TempArray.length) && (TB_NextHTML === "")); TB_Counter++) { - var urlTypeTemp = TB_TempArray[TB_Counter].href.toLowerCase().match(urlString); - if (!(TB_TempArray[TB_Counter].href == url)) { - if (TB_FoundURL) { - TB_NextCaption = TB_TempArray[TB_Counter].title; - TB_NextURL = TB_TempArray[TB_Counter].href; - TB_NextHTML = "  Next >"; - } else { - TB_PrevCaption = TB_TempArray[TB_Counter].title; - TB_PrevURL = TB_TempArray[TB_Counter].href; - TB_PrevHTML = "  < Prev"; - } - } else { - TB_FoundURL = true; - TB_imageCount = "Image " + (TB_Counter + 1) +" of "+ (TB_TempArray.length); - } - } - } - - imgPreloader = new Image(); - imgPreloader.onload = function(){ - imgPreloader.onload = null; - - // Resizing large images - orginal by Christian Montoya edited by me. - var pagesize = tb_getPageSize(); - var x = pagesize[0] - 150; - var y = pagesize[1] - 150; - var imageWidth = imgPreloader.width; - var imageHeight = imgPreloader.height; - if (imageWidth > x) { - imageHeight = imageHeight * (x / imageWidth); - imageWidth = x; - if (imageHeight > y) { - imageWidth = imageWidth * (y / imageHeight); - imageHeight = y; - } - } else if (imageHeight > y) { - imageWidth = imageWidth * (y / imageHeight); - imageHeight = y; - if (imageWidth > x) { - imageHeight = imageHeight * (x / imageWidth); - imageWidth = x; - } - } - // End Resizing - - TB_WIDTH = imageWidth + 30; - TB_HEIGHT = imageHeight + 60; - $("#TB_window").append(""+caption+"" + "
"+caption+"
" + TB_imageCount + TB_PrevHTML + TB_NextHTML + "
close or Esc Key
"); - - $("#TB_closeWindowButton").click(tb_remove); - - if (!(TB_PrevHTML === "")) { - function goPrev(){ - if($(document).unbind("click",goPrev)){$(document).unbind("click",goPrev);} - $("#TB_window").remove(); - $("body").append("
"); - tb_show(TB_PrevCaption, TB_PrevURL, imageGroup); - return false; - } - $("#TB_prev").click(goPrev); - } - - if (!(TB_NextHTML === "")) { - function goNext(){ - $("#TB_window").remove(); - $("body").append("
"); - tb_show(TB_NextCaption, TB_NextURL, imageGroup); - return false; - } - $("#TB_next").click(goNext); - - } - - document.onkeydown = function(e){ - if (e == null) { // ie - keycode = event.keyCode; - } else { // mozilla - keycode = e.which; - } - if(keycode == 27){ // close - tb_remove(); - } else if(keycode == 190){ // display previous image - if(!(TB_NextHTML == "")){ - document.onkeydown = ""; - goNext(); - } - } else if(keycode == 188){ // display next image - if(!(TB_PrevHTML == "")){ - document.onkeydown = ""; - goPrev(); - } - } - }; - - tb_position(); - $("#TB_load").remove(); - $("#TB_ImageOff").click(tb_remove); - $("#TB_window").css({display:"block"}); //for safari using css instead of show - }; - - imgPreloader.src = url; - }else{//code to show html - - var queryString = url.replace(/^[^\?]+\??/,''); - var params = tb_parseQuery( queryString ); - - TB_WIDTH = (params['width']*1) + 30 || 630; //defaults to 630 if no paramaters were added to URL - TB_HEIGHT = (params['height']*1) + 40 || 440; //defaults to 440 if no paramaters were added to URL - ajaxContentW = TB_WIDTH - 30; - ajaxContentH = TB_HEIGHT - 45; - - if(url.indexOf('TB_iframe') != -1){// either iframe or ajax window - urlNoQuery = url.split('TB_'); - $("#TB_iframeContent").remove(); - if(params['modal'] != "true"){//iframe no modal - $("#TB_window").append("
"+caption+"
close or Esc Key
"); - }else{//iframe modal - $("#TB_overlay").unbind(); - $("#TB_window").append(""); - } - }else{// not an iframe, ajax - if($("#TB_window").css("display") != "block"){ - if(params['modal'] != "true"){//ajax no modal - $("#TB_window").append("
"+caption+"
close or Esc Key
"); - }else{//ajax modal - $("#TB_overlay").unbind(); - $("#TB_window").append("
"); - } - }else{//this means the window is already up, we are just loading new content via ajax - $("#TB_ajaxContent")[0].style.width = ajaxContentW +"px"; - $("#TB_ajaxContent")[0].style.height = ajaxContentH +"px"; - $("#TB_ajaxContent")[0].scrollTop = 0; - $("#TB_ajaxWindowTitle").html(caption); - } - } - - $("#TB_closeWindowButton").click(tb_remove); - - if(url.indexOf('TB_inline') != -1){ - $("#TB_ajaxContent").append($('#' + params['inlineId']).children()); - $("#TB_window").unload(function () { - $('#' + params['inlineId']).append( $("#TB_ajaxContent").children() ); // move elements back when you're finished - }); - tb_position(); - $("#TB_load").remove(); - $("#TB_window").css({display:"block"}); - }else if(url.indexOf('TB_iframe') != -1){ - tb_position(); - if($.browser.safari){//safari needs help because it will not fire iframe onload - $("#TB_load").remove(); - $("#TB_window").css({display:"block"}); - } - }else{ - $("#TB_ajaxContent").load(url += "&random=" + (new Date().getTime()),function(){//to do a post change this load method - tb_position(); - $("#TB_load").remove(); - tb_init("#TB_ajaxContent a.thickbox"); - $("#TB_window").css({display:"block"}); - }); - } - - } - - if(!params['modal']){ - document.onkeyup = function(e){ - if (e == null) { // ie - keycode = event.keyCode; - } else { // mozilla - keycode = e.which; - } - if(keycode == 27){ // close - tb_remove(); - } - }; - } - - } catch(e) { - //nothing here - } -} - -//helper functions below -function tb_showIframe(){ - $("#TB_load").remove(); - $("#TB_window").css({display:"block"}); -} - -function tb_remove() { - $("#TB_imageOff").unbind("click"); - $("#TB_closeWindowButton").unbind("click"); - $("#TB_window").fadeOut("fast",function(){$('#TB_window,#TB_overlay,#TB_HideSelect').trigger("unload").unbind().remove();}); - $("#TB_load").remove(); - if (typeof document.body.style.maxHeight == "undefined") {//if IE 6 - $("body","html").css({height: "auto", width: "auto"}); - $("html").css("overflow",""); - } - document.onkeydown = ""; - document.onkeyup = ""; - return false; -} - -function tb_position() { -$("#TB_window").css({marginLeft: '-' + parseInt((TB_WIDTH / 2),10) + 'px', width: TB_WIDTH + 'px'}); - if ( !(jQuery.browser.msie && jQuery.browser.version < 7)) { // take away IE6 - $("#TB_window").css({marginTop: '-' + parseInt((TB_HEIGHT / 2),10) + 'px'}); - } -} - -function tb_parseQuery ( query ) { - var Params = {}; - if ( ! query ) {return Params;}// return empty object - var Pairs = query.split(/[;&]/); - for ( var i = 0; i < Pairs.length; i++ ) { - var KeyVal = Pairs[i].split('='); - if ( ! KeyVal || KeyVal.length != 2 ) {continue;} - var key = unescape( KeyVal[0] ); - var val = unescape( KeyVal[1] ); - val = val.replace(/\+/g, ' '); - Params[key] = val; - } - return Params; -} - -function tb_getPageSize(){ - var de = document.documentElement; - var w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth; - var h = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight; - arrayPageSize = [w,h]; - return arrayPageSize; -} - -function tb_detectMacXFF() { - var userAgent = navigator.userAgent.toLowerCase(); - if (userAgent.indexOf('mac') != -1 && userAgent.indexOf('firefox')!=-1) { - return true; - } -} - - diff --git a/public/tropo-logo.png b/public/tropo-logo.png deleted file mode 100644 index f8588200..00000000 Binary files a/public/tropo-logo.png and /dev/null differ diff --git a/scripts/chroot_runner.js b/scripts/chroot_runner.js deleted file mode 100755 index 0118412e..00000000 --- a/scripts/chroot_runner.js +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env node - -require.paths.unshift('/usr/lib/node_modules'); - -var spawn = require('child_process').spawn; -var daemon = require('daemon'); -var fs = require('fs'); -var path = require('path'); -var net = require('net'); - -var config = JSON.parse(fs.readFileSync(path.join('.nodester', 'config.json'), encoding = 'utf8')); - -var oldmask, newmask = 0000; - -oldmask = process.umask(newmask); -console.log('Changed umask from: ' + oldmask.toString(8) + ' to ' + newmask.toString(8)); - -var run_max = 5; -var run_count = 0; - -var LOG_STDOUT = 1; -var LOG_STDERR = 2; - - -var env = { - PATH: '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin', - NODE_ENV: 'production' -}; -if (config.env) { - Object.keys(config.env).forEach(function (key) { - env[key] = String(config.env[key]); - }); -} -env.app_port = parseInt(config.port, 10); -env.app_host = config.ip; -var args = ['/app/' + config.start]; -var chroot_res = daemon.chroot(config.appchroot); -if (chroot_res !== true) { - log_line('chroot_runner', 'Failed to chroot to ' + config.apphome, LOG_STDERR); - pre_shutdown(); - process.exit(1); -} -var ch_uid = daemon.setreuid(config.userid); -if (ch_uid !== true) { - log_line.call('chroot_runner', 'Failed to change user to ' + config.userid, LOG_STDERR); - pre_shutdown(); - process.exit(2); -} - -var child = null; -var child_watcher_time = null; -var log_lines = []; -var myPid = daemon.start(); -(function () { - - var log_listen = function (p, cb) { - var srv = net.createServer(function (conn) { - var logs = JSON.stringify({ - logs: log_lines.join('\n') - }); - conn.write(logs); - conn.end(); - }); - srv.listen(p, cb); - }; - - var log_line = function (line, stdout) { - if (typeof this == 'string') { - line = this + line; - } - log_lines.push(line); - if (log_lines.length > 150) log_lines.shift(); - }; - - log_line.call('chroot_runner', 'New PID: ' + myPid.toString()); - if (path.existsSync('/.nodester/pids/runner.pid')) fs.unlinkSync('/.nodester/pids/runner.pid'); - fs.writeFileSync('/.nodester/pids/runner.pid', myPid.toString()); - - var log_sock_path = path.join('/', '.nodester', 'logs.sock'); - log_listen(log_sock_path, function () { - log_line('chroot_runner', 'log_listen\'ing', LOG_STDERR); - try { - fs.chmodSync(log_sock_path, '0777'); - } catch (e) { - log_line('chroot_runner', 'Failed to chmod logs.sock', LOG_STDERR); - } - process.on('SIGINT', function () { - log_line.call('chroot_runner', 'SIGINT recieved, sending SIGTERM to children.'); - if (child !== null) { - log_line.call('chroot_runner', 'Child PID: ' + child.pid.toString()); - process.kill(child.pid, 'SIGTERM'); - process.exit(); - } else { - process.exit(); - } - }); - - process.on('SIGTERM', function () { - log_line.call('chroot_runner', 'SIGTERM recieved, sending SIGTERM to children.'); - if (child !== null) { - log_line.call('chroot_runner', 'Child PID: ' + child.pid.toString()); - process.kill(child.pid, 'SIGTERM'); - process.exit(); - } else { - process.exit(); - } - }); - - var start_child = function () { - child = spawn((path.extname(args[0]) == '.coffee' ? '/usr/bin/coffee' : '/usr/bin/node'), args, { - env: env - }); - child.stdout.on('data', log_line.bind('stdout')); - child.stderr.on('data', log_line.bind('stderr')); - child.on('exit', function (code) { - if (code > 0 && run_count > run_max) { - log_line.call('Watcher', 'Error: Restarted too many times, bailing.', LOG_STDERR); - clearInterval(child_watcher_timer); - } else if (code > 0) { - log_line.call('Watcher', 'Process died with exit code ' + code + '. Restarting...', LOG_STDERR); - child = null; - } else { - log_line.call('Watcher', 'Process exited cleanly. Dieing.', LOG_STDERR); - clearInterval(child_watcher_timer); - } - }); - }; - var child_watcher = function () { - if (child === null) { - start_child(); - run_count++; - } - }; - child_watcher_timer = setInterval(child_watcher, 750); - }); -})(); diff --git a/scripts/couchdb/create_all_couchdb_tables.js b/scripts/couchdb/create_all_couchdb_tables.js deleted file mode 100755 index e7e3b83e..00000000 --- a/scripts/couchdb/create_all_couchdb_tables.js +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env node - -var cradle = require('cradle'), - config = require('../../config'); - -require('colors'); - -var c_opts = { - cache: false, - raw: false -}; -if (config.opt.couch_user.length > 0 && config.opt.couch_pass.length > 0) { - c_opts['auth'] = { - username: config.opt.couch_user, - password: config.opt.couch_pass - }; -} -var proto = 'http'; -if (config.opt.couch_port == 443) { - c_opts['secure'] = true; - proto = 'https'; -} - -var conn = new(cradle.Connection)(proto + '://' + config.opt.couch_host, 5984, c_opts); - -for (var i in config.opt.couch_tables) { - var tabname = config.opt.couch_tables[i]; - if (config.opt.couch_prefix.length > 0) { - var tabname = config.opt.couch_prefix + "_" + tabname; - }(function (table_name) { - var db = conn.database(table_name); - db.create(function (err, res) { - if (err) { - console.error(('Failed to create ' + table_name + '.').red.bold); - console.error(' ' + err.reason.red); - } else { - console.log(('Created ' + table_name + '.').yellow); - } - }); - })(tabname); -} \ No newline at end of file diff --git a/scripts/couchdb/delete_all_couchdb_tables.js b/scripts/couchdb/delete_all_couchdb_tables.js deleted file mode 100755 index 32fdd4b4..00000000 --- a/scripts/couchdb/delete_all_couchdb_tables.js +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env node - -var http = require('http'), - config = require('../../config'); - -require('colors'); - -var delete_couchdb_table = function (port, hostname, tablename, callback) { - var co = http.createClient(port, hostname); - var req = co.request('DELETE', '/' + tablename, { - host: hostname, - 'Authorization': "Basic " + (new Buffer(config.opt.couch_user + ":" + (config.opt.couch_pass || ""))).toString('base64') - }); - var rtv = false; - req.end(); - req.on('response', function (resp) { - switch (resp.statusCode) { - case 200: - rtv = true; - break; - } - callback(rtv); - }); -}; - -for(var i in config.opt.couch_tables) { - var tabname = config.opt.couch_tables[i]; - if (config.opt.couch_prefix) { - tabname = config.opt.couch_prefix + "_" + tabname; - } - (function (table_name) { - delete_couchdb_table(config.opt.couch_port, config.opt.couch_host, table_name, function (success) { - if (success) { - console.log((table_name + " was deleted.").yellow)); - } else { - console.log((table_name + " failed to be deleted.").red.bold); - } - }); - })(tabname); -} diff --git a/scripts/couchdb/setup_default_views.js b/scripts/couchdb/setup_default_views.js deleted file mode 100755 index a0315ef4..00000000 --- a/scripts/couchdb/setup_default_views.js +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/env node - -var cradle = require('cradle'), - config = require('../../config'); - -require('colors'); - -var c_opts = { - cache: false, - raw: false -}; -if (config.opt.couch_user.length > 0 && config.opt.couch_pass.length > 0) { - c_opts['auth'] = { - username: config.opt.couch_user, - password: config.opt.couch_pass - }; -} -var proto = 'http'; -if (config.opt.couch_port == 443) { - c_opts['secure'] = true; - proto = 'https'; -} - -var conn = new(cradle.Connection)(proto + '://' + config.opt.couch_host, 5984, c_opts); - -var prefix = ''; -if (config.opt.couch_prefix.length > 0) { - prefix = config.opt.couch_prefix + '_'; -} - -var all_views = [{ - table: 'apps', - design: 'nodeapps', - views: { - all: { - map: function (doc) { - emit(doc.username, doc); - } - } - } -}, { - table: 'aliasdomains', - design: 'aliasdomains', - views: { - all: { - map: function (doc) { - emit(doc.username, doc); - } - } - } -}, { - table: 'password_resets', - design: 'tokens', - views: { - all: { - map: function (doc) { - emit(doc.token, doc); - } - }, - unsent: { - map: function (doc) { - if (doc.email_sent == false) { - emit(doc.token, doc) - } - } - } - } -}]; - -for (var i in all_views) { - (function (view) { - var db = conn.database(prefix + view.table); - db.view(view.design + '/all', function (err, res) { - if (err) { - if (err.error == 'not_found') { - db.save('_design/' + view.design, view.views, function (err, res) { - if (err) { - console.error('Failed to create view ' + view.table + '/' + view.design + '.'.red.bold); - console.error(err); - } else { - console.log('Created view ' + view.table + '/' + view.design + '.'.yellow); - } - }); - } else { - console.error('Failed to query view ' + view.table + '/' + view.design + '.'.red.bold); - console.error(err); - } - } else { - console.log('Skipping creating view ' + view.table + '/' + view.design + '.'.yellow); - } - }); - })(all_views[i]); -} - - -//Default Port Number: -var db = conn.database(prefix + 'nextport'); -var default_port = 10000; -db.get('port', function (err, resp) { - if (err) { - if (err.error == 'not_found') { - db.save('port', { - address: default_port - }, function (err, resp) { - if (err) { - console.error('Error saving next port:'.red); - console.error(err); - } else console.log('Next port initialised.'.yellow); - }); - } else { - console.error('Unknown error working on next port:'.red); - console.error(err); - } - } else { - console.log('Skipping next port initialisation.'.yellow); - } -}); -// {address: 10000} \ No newline at end of file diff --git a/scripts/example_gitrepoclone.sh b/scripts/example_gitrepoclone.sh deleted file mode 100755 index 4b73387d..00000000 --- a/scripts/example_gitrepoclone.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash -# post-commit hook to create git file directory for node subdomain -SECRETKEY=PleaseRestartMyAppMKay -GITBASE=/git -APPSBASE=/app - -OLD_PWD=$PWD -gitdirsuffix=${PWD##*/} -gitdir=${gitdirsuffix%.git} -GITBASELEN=${#GITBASE}; -OLD_PWDLEN=${#OLD_PWD}; -MY_LEN=$(( ${OLD_PWDLEN} - ${GITBASELEN} - 4 )); -appdir="${APPSBASE}${OLD_PWD:${GITBASELEN}:${MY_LEN}}"; - -if [ -d "${appdir}" ]; then - echo "Syncing repo with chroot" - cd ${appdir}; - unset GIT_DIR; - git pull; -else - echo "Fresh git clone into chroot" - mkdir -p ${appdir}; - git clone . ${appdir}; - cd ${appdir}; -fi - -hook=./.git/hooks/post-receive -if [ -f "$hook" ]; then - rm $hook -fi - -if [ -f ./.gitmodules ]; then - echo "Found git submodules, updating them now..." - git submodule init; - git submodule update; -fi - -cd $OLD_PWD - -echo "Attempting to restart your app: ${gitdir}" -curl "http://127.0.0.1:4001/app_restart?repo_id=${gitdir}&restart_key=${SECRETKEY}" 2>/dev/null -echo "" -echo "App restarted.." -echo "" -echo " \m/ Nodester out \m/" -echo "" -exit 0; diff --git a/scripts/git-shell-enforce-directory b/scripts/git-shell-enforce-directory deleted file mode 100755 index 3536cbf7..00000000 --- a/scripts/git-shell-enforce-directory +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2007 Tommi Virtanen -# -# Permission is hereby granted, free of charge, to any person -# obtaining a copy of this software and associated documentation files -# (the "Software"), to deal in the Software without restriction, -# including without limitation the rights to use, copy, modify, merge, -# publish, distribute, sublicense, and/or sell copies of the Software, -# and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -# Enforce git-shell to only serve repositories -# in the given directory. The client should refer -# to them without any directory prefix. -# Repository names are forced to match ALLOW. - -import sys, os, optparse, re - -def die(msg): - print >>sys.stderr, '%s: %s' % (sys.argv[0], msg) - sys.exit(1) - -def getParser(): - parser = optparse.OptionParser( - usage='%prog [OPTIONS] DIR', - description='Allow restricted git operations under DIR', - ) - parser.add_option('--read-only', - help='disable write operations', - action='store_true', - default=False, - ) - return parser - -ALLOW_RE = re.compile("^(?Pgit-(?:receive|upload)-pack) '[a-zA-Z0-9@._-]*(/[a-zA-Z0-9@._-]*)*'$") - -COMMANDS_READONLY = [ - 'git-upload-pack', - ] - -COMMANDS_WRITE = [ - 'git-receive-pack', - ] - -def main(args): - os.umask(0022) - - parser = getParser() - (options, args) = parser.parse_args() - try: - (path,) = args - except ValueError: - parser.error('Missing argument DIR.') - os.chdir(path) - - cmd = os.environ.get('SSH_ORIGINAL_COMMAND', None) - if cmd is None: - die("Need SSH_ORIGINAL_COMMAND in environment.") - - if '\n' in cmd: - die("Command may not contain newlines.") - - match = ALLOW_RE.match(cmd) - if match is None: - die("Command to run looks dangerous") - - allowed = list(COMMANDS_READONLY) - if not options.read_only: - allowed.extend(COMMANDS_WRITE) - - if match.group('command') not in allowed: - die("Command not allowed") - - os.execve('/usr/bin/git-shell', ['git-shell', '-c', cmd], {}) - die("Cannot execute git-shell.") - -if __name__ == '__main__': - main(args=sys.argv[1:]) diff --git a/scripts/gitreposetup.sh b/scripts/gitreposetup.sh deleted file mode 100755 index 3e36a343..00000000 --- a/scripts/gitreposetup.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# script to create git repo for node subdomain -# _rev is passed into the script as a parameter - -BASEDIR=${1}; -APPDIR=${2}; -APPUSERNAME=${3}; -REV=${4}; -START=${5}; -NODESTER_UID=${6}; -GIT_UID=${7}; -APPS_DIR=${8}; - -GIT_DIR=${APPDIR}/${APPUSERNAME}/${REV}.git -APP_DIR=${APPS_DIR}/${APPUSERNAME}/${REV} - -if [ ! -d "${APPDIR}" ]; then - mkdir -p ${APPDIR}; -fi; - -mkdir -p ${GIT_DIR} ${APP_DIR}; -git init --bare ${GIT_DIR}; -#ln -s ${BASEDIR}/scripts/gitrepoclone.sh ${GIT_DIR}/hooks/post-receive; -cp ${BASEDIR}/scripts/gitrepoclone.sh ${GIT_DIR}/hooks/post-receive; - -git clone ${GIT_DIR} ${APP_DIR}/; -wait - -echo "Changing Perms" -echo "chown -R $GIT_UID:$NODESTER_UID ${GIT_DIR} ${APP_DIR}"; -chown -R $GIT_UID:$NODESTER_UID ${GIT_DIR} ${APP_DIR}; -echo "find ${GIT_DIR} ${APP_DIR} -type d -exec chmod 775 {} \;"; -find ${GIT_DIR} ${APP_DIR} -type d -exec chmod 775 {} \; -echo "find ${GIT_DIR} ${APP_DIR} -type f -exec chmod 664 {} \;"; -find ${GIT_DIR} ${APP_DIR} -type f -exec chmod 664 {} \; -echo "chmod +x ${GIT_DIR}/hooks/post-receive;"; -chmod +x ${GIT_DIR}/hooks/post-receive; \ No newline at end of file diff --git a/scripts/gitreset.js b/scripts/gitreset.js deleted file mode 100755 index af598278..00000000 --- a/scripts/gitreset.js +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env node - -var exec = require('child_process').exec; - -var app_dir = process.argv[2]; -var git_dir = app_dir + '.git'; - -var cmds = ['rm -Rf ' + app_dir, 'git clone ' + git_dir + ' ' + app_dir]; - -var do_cmd = function () { - if (cmds.length > 0) { - var cmd = cmds.shift(); - exec(cmd, function () { - do_cmd(); - }); - } - }; \ No newline at end of file diff --git a/scripts/launch_chrooted_app.js b/scripts/launch_chrooted_app.js deleted file mode 100755 index 6b81bfb1..00000000 --- a/scripts/launch_chrooted_app.js +++ /dev/null @@ -1,227 +0,0 @@ -#!/usr/bin/env node - -var fs = require('fs'), - path = require('path'), - util = require('util'), - Script = process.binding('evals').Script, - Module = require('module'); - -//This "preps" the chroot with SSL support -var c = process.binding('crypto').Connection; -var crypto = require('crypto'); -var creds = crypto.createCredentials(); - - -var config = JSON.parse(fs.readFileSync(path.join('.nodester', 'config.json'), encoding = 'utf8')); -config.userid = parseInt(config.userid); - -console.log(config); - -//These 3 lines ensure that we get the daemon setup by the nodester user and not the -// one available to root, since we are sudoed at this point -require.paths.unshift(path.join(config.appdir, '../', 'node_modules')); -require.paths.unshift(path.join(config.appdir, '../', '.node_libraries')); -require.paths.unshift('/node_modules'); -require.paths.unshift('/.node_libraries'); - -var daemon = require('daemon'); - - -var app_port = parseInt(config.port); -var app_host = config.ip; - -console.log('chroot: ', config.apphome); -daemon.chroot(config.apphome); -require.paths.unshift('/node_modules'); -console.log('Starting Daemon'); -daemon.daemonize(path.join('.nodester', 'logs', 'daemon.log'), path.join('.nodester', 'pids', 'app.pid'), function (err, pid) { - var error_log_fd = fs.openSync('/error.log', 'w'); - var log = function (obj) { - console.log(arguments); - fs.write(error_log_fd, arguments[0] + '\n'); - }; - if (err) { - log(err.stack); - } - log('Inside Daemon: ' + pid); - log('Changing to user: ' + config.userid); - try { - daemon.setreuid(config.userid); - log('User Changed: ' + process.getuid()); - } catch (e) { - log('User Change FAILED'); - } - - process.on('uncaughtException', function (err) { - fs.write(error_log_fd, err.stack); - }); - - var etc = path.join('/', 'etc'); - //create /etc inside the chroot - log('Checking for /etc'); - if (!path.existsSync(etc)) { - log('/etc does not exist. Creating..'); - fs.mkdirSync(etc, 0777); - } - log('Update /etc/resolve.conf with Googles DNS servers..'); - fs.writeFileSync(path.join(etc, 'resolv.conf'), 'nameserver 8.8.8.8\nnameserver 8.8.4.4\n', encoding = 'utf8'); - - log('Setting up sandbox..'); - //Setup the main sandbox.. - var sandbox = { - global: {}, - process: process, - require: require, - console: console, - module: {}, - __filename: config.start, - __dirname: "/", - clearInterval: clearInterval, - clearTimeout: clearTimeout, - setInterval: setInterval, - setTimeout: setTimeout - }; - - sandbox.module = new Module(); - sandbox.module.id = '.'; - sandbox.module.filename = '/' + config.start; - sandbox.module.paths = ['/']; - - sandbox.process.pid = pid; - sandbox.process.installPrefix = '/'; - sandbox.process.ARGV = ['node', config.start]; - sandbox.process.argv = sandbox.process.ARGV; - var env = sandbox.process.env = sandbox.process.ENV = { - // defaults which can be overriden - NODE_ENV: "production" - }; - - if (config.env) { - Object.keys(config.env).forEach(function (key) { - env[key] = String(config.env[key]); - }); - } - - // environment variables which cannot be overriden by config. - env.app_port = app_port; - env.app_host = app_host; - sandbox.process.mainModule = sandbox.module; - sandbox.process.kill = function () { - return 'process.kill is disabled' - }; - sandbox.process.stdout.write = sandbox.console.warn = sandbox.console.error = function (args) { - fs.write(error_log_fd, args.toString()); - }; - - console.log('Munging require paths..'); - - var _require = require; - var _resolve = require.resolve; - //this should make require('./lib/foo'); work properly - sandbox.require = function (f) { - sandbox.require.paths.forEach(function (v, k) { - if (v.indexOf('./') === 0) { - sandbox.require.paths[k] = v.substring(1); - } - }); - if (f.indexOf('./') === 0) { - try { - _require.call(_require, f); - } catch (e) { - f = f.substring(1); - } - } - //This is to support require.paths.push('./lib'); require('foo.js'); - try { - _require.call(_require, f); - } catch (e) { - var m; - sandbox.require.paths.forEach(function (v, k) { - if (m) { - return; - } - try { - m = _require.call(_require, path.join(v, f)); - f = path.join(v, f); - } catch (e) {} - }); - } - - /** - * Simple HTTP sandbox to make sure that http listens on the assigned port. - * May also need to handle the net module too.. - * THIS IS A HACK, this "sandboxing" will fail if a user "require"'s a module in a submodule. - */ - var createServer = function () { - var h = _create.apply(this, arguments); - var _listen = h.listen; - h.listen = function (port) { - port = parseInt(port, 10); - if (port !== app_port) { - console.log('[ERROR] You asked to listen on port', port, 'but nodester will use port', app_port, 'instead..'); - } else { - console.log('[INFO] Nodester listening on port:', app_port); - } - _listen.call(h, app_port); - }; - return h; - }; - var m = _require.call(_require, f); - if (m.createServer) { //Too aggressive?? - var _create = m.createServer; - m.createServer = createServer; - } - return m; - }; - for (var i in _require) { - sandbox.require[i] = _require[i]; - } - sandbox.require.resolve = function (f) { - if (f.indexOf('./') === 0) { - //console.log('Nodester fixing require path', f); - f = f.substring(1); - //console.log('Nodester fixed require path', f); - } - return _resolve.call(this, f); - }; - - - sandbox.require.main = sandbox.module; - sandbox.require.cache = {}; - sandbox.require.cache['/' + config.start] = sandbox.module; - sandbox.require.paths = ['/node_modules', '/.node_libraries']; - - sandbox.process.on('uncaughtException', function (err) { - fs.write(error_log_fd, util.inspect(err)); - }); - - console.log('Globalizing Buffer'); - sandbox.Buffer = Buffer; - - console.log('Reading file...'); - console.log(config.start + ' owned by ' + config.userid); - var isCoffee = (path.extname(config.start) === '.coffee'); - if (isCoffee) { - console.log('App is coffee-script!'); - } - fs.readFile(config.start, function (err, script_src) { - try { - var resp = daemon.setreuid(config.userid); - console.log('Final user check: ', process.getuid()); - } catch (e2) { - console.log('Final User Change Failed.'); - console.log(resp); - } - if (err) { - console.log(util.inspect(err)); - process.exit(1); - } else { - console.log('Nodester wrapped script starting (PID: ' + process.pid + ') at ', new Date()); - if (isCoffee){ - // script_src = coffee.compile(script_src); - } - Script.runInNewContext(script_src, sandbox, config.start); - } - }); - //End Daemon -}); \ No newline at end of file diff --git a/scripts/mailer.js b/scripts/mailer.js deleted file mode 100755 index 85bdd714..00000000 --- a/scripts/mailer.js +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env node - -var mailer = require('nodemailer'), - lib = require('../lib/lib'), - config = require('../config'); - -var resets = lib.get_couchdb_database('password_resets'); - -mailer.SES = config.opt.SES; - -function send_email(doc) { - mailer.send_mail({ - sender: '', - to: doc.id, - subject: 'Password reset request', - body: 'Here is your password request token: ' + doc.value.token + '\n\nYou can reset your password via Nodester API or CLI' - }, function (error, success) { - console.log('Reset password e-mail sent to: ' + doc.id) - console.log('Message ' + success ? 'sent' : 'failed'); - reset_token(doc) - }); -} - -function reset_token(doc) { - resets.merge(doc.id, { - email_sent: true - }, function (err, res) { - if (err) console.log(err) - }); -} - -resets.view('tokens/unsent', function (err, doc) { - if (!err) { - for (i = 0; i < doc.length; i++) - send_email(doc[i]) - } else { - console.log(err) - } -}); diff --git a/scripts/removeapp.js b/scripts/removeapp.js deleted file mode 100755 index 0296f8e9..00000000 --- a/scripts/removeapp.js +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env node - -var exec = require('child_process').exec; - -var app_dir = process.argv[2]; -var app_dir_rw = app_dir + '_rw'; -var git_dir = process.argv[3]; - -var cmds = ['rm -Rf ' + app_dir, 'rm -Rf ' + app_dir_rw, 'rm -Rf ' + git_dir]; - -var do_cmd = function () { - if (cmds.length > 0) { - var cmd = cmds.shift(); - console.log(cmd); - exec(cmd, function () { - do_cmd(); - }); - } - }; - -do_cmd(); \ No newline at end of file diff --git a/scripts/start_hosted_apps.js b/scripts/start_hosted_apps.js deleted file mode 100644 index 939bd38f..00000000 --- a/scripts/start_hosted_apps.js +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env node - -require.paths.unshift('/usr/lib/node_modules/'); -var http = require('http'), - config = require("../config"), - util = require('util'), - exec = require('child_process').exec, - app = require('../lib/app'); - -require('colors'); - -var action = process.argv[2], - all = false, - this_repo = false, - past = ''; - - -if (process.argv[3] && process.argv[3].toLowerCase() === 'all') { - all = true; -} else if (process.argv[3]) { - all = false; - this_repo = process.argv[3]; -} - -switch (action) { -case 'start': - verb = 'Starting'.green; - past = 'started'; - break; -case 'stop': - verb = 'Stopping'.red.bold; - past = 'stopped'; - break; -default: - action = 'restart'; - verb = 'Restarting'.yellow; - past = 'restarted'; - break; -} - -var couch_http = http.createClient(config.opt.couch_port, config.opt.couch_host); -if (config.opt.couch_prefix.length > 0) { - var cprefix = config.opt.couch_prefix + '_'; -} else { - var cprefix = ''; -} - -// var request = couch_http.request( -// 'GET', -// '/' + cprefix + 'apps' + '/_design/nodeapps/_view/all', -// { -// 'host': config.opt.couch_host, -// 'Authorization': "Basic " + base64_encode(new Buffer(config.opt.couch_user + ":" + (config.opt.couch_pass || ""))) -// } -// ); -// NATIVE BASE64 HANDLING -var buff = new Buffer(config.opt.couch_user + ':' + config.opt.couch_pass, encoding = 'ascii'); -var dbcreds = buff.toString('base64'); -var request = couch_http.request('GET', '/' + cprefix + 'apps' + '/_design/nodeapps/_view/all', { - 'host': config.opt.couch_host, - 'Authorization': "Basic " + dbcreds || "" -}); - - -request.end(); -request.on('response', function (response) { - var buff = ''; - if (response.statusCode != 200) { - util.log(response.statusCode); - util.log('Error: Cannot query CouchDB'); - process.exit(1); - } - response.setEncoding('utf8'); - response.on('data', function (chunk) { - buff += chunk; - }); - response.on('end', function () { - var resp = JSON.parse(buff); - start_running_apps(resp.rows); - }); -}); - -var apps = [], - count = 0, - g = 0, - f = 0, - good = "SUCCESS ✔", - bad = "FAILURE ✖"; - -// Another bad idea but we don't want this thing crashing -process.on('uncaughtException', function (err) { - util.print('UNCAUGHT ERROR! '.red + err); -}); -var handleResponse = function (data) { - if (data instanceof Object) { - if (data.status.indexOf('failed') > -1) { - f++; - } else { - g++; - } - util.print(' [' + ((data.status.indexOf('failed') > -1) ? bad.bold.red : good.bold.green) + ']\n'); - } else { - g++; - util.print(' [' + good.bold.green + ']\n'); - } - //Let the process fire up and daemonize before starting the next one - setTimeout(next, 500); - //next(); - }; - -var next = function () { - if (apps.length) { - var len = apps.length; - var doc = apps.pop(); - if (doc && doc.username && doc.repo_id && doc.start && doc.port) { - util.print(verb + ' (' + len + '): [' + (doc.username + '/' + doc.repo_id + '/' + doc.start + ':' + doc.port).blue + ']'); - var method = 'app_' + action; - try { - app[method]({ - query: { - repo_id: doc.repo_id, - restart_key: config.opt.restart_key - } - }, { - writeHead: function (data) {}, - send: handleResponse, - end: handleResponse, - }); - } catch (err) { - f++; - util.print(err + '\n'); - util.print('[' + bad.red.bold + ']\n'); - } - - } else { - util.log(('All ' + count + ' apps ' + past).bold); - util.log(g + ' apps ' + past + ' successfully'); - if (f) { - util.log((f + ' apps failed to ' + action).red.bold); - } - } - } else { - f++; - util.print('Missing records.\n') - util.print('[' + bad.red.bold + ']\n') - } - }; - -var start_running_apps = function (apps_arr) { - for (var i in apps_arr) { - var doc = apps_arr[i].value; - if (this_repo) { - if (doc.repo_id == this_repo) { - count++; - apps.push(doc); - } - } else { - if (doc.running == 'true' || all) { - count++; - apps.push(doc); - } - } - } - if (all) { - util.log(verb + ' ALL (' + count + ') apps..'); - } else { - util.log(verb + ' ' + count + ' apps..'); - } - next(); - }; \ No newline at end of file diff --git a/scripts/sync_githook.js b/scripts/sync_githook.js deleted file mode 100755 index 0e1ef511..00000000 --- a/scripts/sync_githook.js +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env node - -require('colors'); -var path = require('path'); -var fs = require('fs'); -var config = require('../config').opt; -var hosted = path.join(config.home_dir, config.hosted_apps_subdir); -var exists = path.existsSync; -var util = require('util'); -process.chdir(hosted); - -util.print('Reading git repos:'.magenta); -var src = path.join(config.app_dir, 'scripts', 'gitrepoclone.sh'); -var copy = function () { - if (repos.length) { - var dest = repos.pop(); - var is = fs.createReadStream(src); - var os = fs.createWriteStream(dest); - util.pump(is, os, copy); - } else { - util.print(' [done]\n'.white); - } - }; - -var repos = []; -var dirs = fs.readdirSync('.'); -dirs.forEach(function (v) { - if (exists(v)) { - var stat = fs.statSync(v); - if (stat.isDirectory()) { - var dirs = fs.readdirSync(v); - dirs.forEach(function (i) { - if (path.extname(i) === '.git') { - repos.push(path.join(hosted, v, i, 'hooks', 'post-receive')); - } - }); - } - } -}); -util.print((' (' + repos.length + ')').yellow + ' [done]\n'.white); -util.print('Processing git commit hooks'.magenta); -copy(); \ No newline at end of file diff --git a/scripts/update_authkeys.js b/scripts/update_authkeys.js deleted file mode 100755 index b6cd8bb5..00000000 --- a/scripts/update_authkeys.js +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env node - -var fs = require('fs'), - config = require('../config.js').opt; - -var stream = fs.createWriteStream(config.git_home_dir + '/.ssh/authorized_keys', { - 'flags': 'a+', - 'encoding': 'utf8', - 'mode': '0644' -}); -stream.write('command="/usr/local/bin/git-shell-enforce-directory ' + process.argv[2] + '",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ' + process.argv[3] + '\n', 'utf8'); -stream.end(); \ No newline at end of file diff --git a/ssl/.empty_dir b/ssl/.empty_dir deleted file mode 100644 index e69de29b..00000000 diff --git a/upstart/app.conf b/upstart/app.conf deleted file mode 100644 index 849f61bb..00000000 --- a/upstart/app.conf +++ /dev/null @@ -1,12 +0,0 @@ -#!upstart -description "nodester app server" -author "contra" - -start on startup -stop on shutdown - -script - export HOME="/node" - exec sudo -u nodester node /node/nodester/nodester/app.js >> /node/logs/app.log -end script - diff --git a/upstart/proxy.conf b/upstart/proxy.conf deleted file mode 100644 index 890abf3d..00000000 --- a/upstart/proxy.conf +++ /dev/null @@ -1,11 +0,0 @@ -#!upstart -description "nodester proxy server" -author "contra" - -start on startup -stop on shutdown - -script - export HOME="/node" - exec sudo node /node/nodester/nodester/proxy/proxy.js >> /node/logs/proxy.log -end script