Unverified Commit 7ec0798b authored by David Morley's avatar David Morley Committed by GitHub

2.3.0 Release (#192)

* detect language from body text of main page

* old axis not used

* changelog

* restore user ratings, tiny clean up on looks

* use API for pulls of master version - enforce some security (#159)

* use API for pulls of master version - enforce some security

* add migration

* fix podcrawler

* fix podcrawler

* add diasp.org json active pods
update composer to 7.2 php

* add diasp.org json active pods
update composer to 7.2 php

* remove wizard junk from this branch

* remove wizard junk from this branch

* Revamp masterversionpull fixes (#163)

* Use PHP_SAPI constant to save function call.

* Fix podcrawler to properly filter out only pods that support the diaspora protocol.

* Fix DB write logic and clean up pull.php code a bit.

* Use the best nodeinfo available

* Use the best nodeinfo available, need to default to 1.0

* same order each time vs random

* fix link

* little more universality

* freindica version edit, support as best as can

* using jasonrobinson.me as an example last updated at 2018-04-12 17:23:41.55 is now hidden, giving more time padding for dev branches.

* bower to yarn (#162)

* bower to yarn

* yarn -> Javascript dependencies
composer -> PHP dependencies

* changelog

* Add filter, paging, update menus to make them mobile (#161)

* Add filter, paging, update menus to make them mobile

* remove legacy items unused

* switch from images to css and bigger for fingers

* allow search/filter podmin data

* cleanup

* css important there

* footer mobile fix

* changelog

* use carbon for nice human dates. add country name in full (#164)

* use carbon for nice human dates. add country name in full

* use carbon for nice human dates. add country name in full

* old axis not used

* Improve usage of Carbon. (#166)

* changelog

* use API for pulls of master version - enforce some security (#159)

* use API for pulls of master version - enforce some security

* add migration

* fix podcrawler

* fix podcrawler

* add diasp.org json active pods
update composer to 7.2 php

* add diasp.org json active pods
update composer to 7.2 php

* remove wizard junk from this branch

* remove wizard junk from this branch

* Revamp masterversionpull fixes (#163)

* Use PHP_SAPI constant to save function call.

* Fix podcrawler to properly filter out only pods that support the diaspora protocol.

* Fix DB write logic and clean up pull.php code a bit.

* Use the best nodeinfo available

* Use the best nodeinfo available, need to default to 1.0

* same order each time vs random

* fix link

* little more universality

* freindica version edit, support as best as can

* using jasonrobinson.me as an example last updated at 2018-04-12 17:23:41.55 is now hidden, giving more time padding for dev branches.

* bower to yarn (#162)

* bower to yarn

* yarn -> Javascript dependencies
composer -> PHP dependencies

* changelog

* Add filter, paging, update menus to make them mobile (#161)

* Add filter, paging, update menus to make them mobile

* remove legacy items unused

* switch from images to css and bigger for fingers

* allow search/filter podmin data

* cleanup

* css important there

* footer mobile fix

* changelog

* use carbon for nice human dates. add country name in full

* Improve usage of Carbon. (#166)

* Carbon (#168)

* fix merge error

* rebase

* Improve usage of Carbon. (#166)

* use carbon for nice human dates. add country name in full

* Improve usage of Carbon. (#166)

* PHP 7.2 and PSR-2 compliance (#170)

* Add PHP Code Sniffer, clean up composer.json, ignore node_modules

* Initial PSR2 flash.

* Declare strict types, add file comments, remove copyright notices.

* Fix SQL code indentation.

* Smaller visual code changes.

* Modify / remove invalid or unnecessary code.

* Add some variable data fail safes.

* Move logging into lib and introduce Poduptime namespace.

* Simple cookie hint

* move to supported db for IP geo data

* travis

* cleaner lookups, utf8 does not seem needed to fix now, something to watch still in dev

* set a non-static date

* little more user friendly

* shell better formatting

* consistency

* curl it

* even smarter

* develop branch cleanup (#173)

* develop branch cleanup

* develop branch cleanup

* develop branch cleanup

* move to new lightbox that is responsive

* move to new lightbox that is responsive

* Adminunused (#175)

* remove adminrating

* remove adminrating

* remove echo

* Dbtableclean - remove hidden and secure (#176)

* remove hidden and secure from db

* remove hidden and secure from db

* remove hidden and secure from db

* This syntax (ES6) can make defining complex object literals much cleaner.

* fix weird blank pages on reloads

* remove unused line

* lat and long

* Just some alignment stuff, only visual code, no functionality.

* Refactor away unnecessary 'else' statements.

* Prevent duplicate PHP code execution for pie chart generation using passed data.

* Various little fixes, like spacing, better date output, removing unused code.

* Recursive call to stringify subarray items for API.

* Small fixes thanks to Codacy, some simple code cleanup.

* More spacing and alignment fixes, purely visual.

* Fix domain cookie check.

* There is no more slider...

* few last cleanups

* just to get things running again.

* Pullissues (#184)

* Pull some things after curl is a success rather than for all

* fix ip pull if ip

* fix loading spinner css

* allow php-cgi

* allow php-cgi

* == not ===

* more cli

* tricky pods have node info but no home page so users can not even access the pod

* implode and make them a version that conforms

* less nice to dash

* dont barf on bad pods

* space

* fix ratings

* less jumping on table

* view items

* shortversion is not really ok for dev, hack to make it decent for now

* store version in checks

* fix div

* make charts responsive for mobile

* Catch invalid GeoIP database.

* Small code simplification and remove unnecessary else statement.

* Minor code changes, purely visual.

* !blue

* Load tooltips after everything else to make sure all is loaded correctly. (#188)

* fix pull again (#191)

* few easy UI fixes (#189)

* few easy UI fixes

* Make table headers DIV instead of A tags. (#190)

Add tooltips to services images.

* leave page menu on screen
parent 97358212
bower_components
config.php
node_modules
vendor
......@@ -12,4 +12,7 @@
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/>.
\ No newline at end of file
along with this program. If not, see <http://www.gnu.org/licenses/>.
This product includes GeoLite2 data created by MaxMind, available from
<a href="http://www.maxmind.com">http://www.maxmind.com</a>.
# 2.3.0
## Podmins
* Can no longer access db/pull.php to test their pod, they can however get to a debug screen from the edit pod area
* Language is detected based on your homepage, edit your homepage to non-en if that is what you use
* Edit will send to email on file and be less delay, runner of site does not really have anyway to verify email address
## DB
* Add development and release dates to masterversions table https://github.com/diasporg/Poduptime/issues/143
* Store full country name, store days monitored each pod https://github.com/diasporg/Poduptime/issues/150
* Store detectedlanguage https://github.com/diasporg/Poduptime/issues/144
* DB migrations see db/version.md
* rename table rating_comments to ratingcomments for redbean support https://github.com/diasporg/Poduptime/issues/146
* Default new pods to UP to be checked
* Remove unused hidden and secure columns https://github.com/diasporg/Poduptime/issues/141 https://github.com/diasporg/Poduptime/issues/140
## Cleanup
* Use the git API for release versions, check development releases on pods https://github.com/diasporg/Poduptime/issues/143
* Forbid access to files that should be cli only https://github.com/diasporg/Poduptime/issues/152
* Move from bower to yarn for packages https://bower.io/blog/2017/how-to-migrate-away-from-bower/
* Move to PHP 7.2 with declare(strict_types=1);
* Move to Eslint compliance https://eslint.org/docs/rules/
* Move to PSR-2 compliance https://www.php-fig.org/psr/psr-2/
* NOTE config.php.example change to full paths for 2 items!
## End Users
* Show version and update in full view cleaner https://github.com/diasporg/Poduptime/issues/143
* Filter and search on the columns of data https://github.com/diasporg/Poduptime/issues/147
* Paginate the results so they fit per page https://github.com/diasporg/Poduptime/issues/147
* Show time as human readable everywhere https://github.com/diasporg/Poduptime/issues/150
# 2.2.0
## Podmins
......
# Poduptime
Poduptime is software to get live stats and data on listed Diaspora Pods.
Poduptime is software to get live stats and data on listed Diaspora and other Pods that support nodeinfo output.
Dependencies:
# To Install:
Environmental items you need (debian based system assumed):
OS Dependencies:
```
php7.2 php7.2-curl php7.2-pgsql php-geoip php7.2-cli php7.2-common php7.2-json php7.2-readline php-cgi git curl postgresql postgresql-contrib wget dnsutils bind9 npm nodejs nodejs-legacy composer
php7.2 php7.2-curl php7.2-pgsql php-geoip php7.2-cli php7.2-common php7.2-bcmath php7.2-json php7.2-readline php7.2-mbstring php7.2-xml php-cgi git curl postgresql postgresql-contrib dnsutils bind9 npm nodejs composer
```
GeoIP needs setup normally with a dat file
Yarn is a separate install: https://yarnpkg.com
To Install:
Clone and setup:
```
git clone https://github.com/diasporg/Poduptime.git
cd Poduptime
sudo npm install -g bower
bower install
yarn install
composer install
cp config.php.example config.php
cp config.php.example config.php (all fields required)
```
If you need to setup your Postgresql/DB:
......@@ -28,28 +35,41 @@ sudo -u postgres bash -c "psql -c \"GRANT ALL PRIVILEGES ON DATABASE podupdb TO
sudo nano /etc/postgresql/vx.x/main/pg_hba.conf
# restart postgresql
```
# import database structure
Import database schema
```
psql -U podupuser podupdb < db/tables.sql
```
Edit `config.php` to add your DB and file settings.
touch add.log in location you configured in config.php
1. Edit `config.php` to add your DB and file settings
2. Touch add.log in location you configured in config.php
3. Create your backup folder
4. Add a pod and run `db/pull.sh init`
run `db/pull.sh` manually or with cron to update your data
run `db/pull.sh debug` to debug output
run `db/pull.sh develop` to run without email alerts to end users
run `db/pull.sh Check_System_Deleted` to re-check system deleted pods as needed
# To Use:
To Upgrade:
run `db/pull.sh` manually or with cron to update your data
run `db/pull.sh debug` to debug output
run `db/pull.sh sqldebug` to debug sql
run `db/pull.sh develop` to run without email alerts to end users
run `db/pull.sh Check_System_Deleted` to re-check system deleted pods as needed
# To Upgrade:
```
cd Poduptime
git pull
bower install
yarn install
composer install
psql -U podupuser podupdb < db/migrationXXX.sql (see db/version.md for proper migration versions)
```
# To Contribute
Something here or a link to the wiki on how to....
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/0515afa78df64b6385088246ee84acde)](https://www.codacy.com/app/diasporg/Poduptime?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=diasporg/Poduptime&amp;utm_campaign=Badge_Grade)
============================
Source for Diaspora Pod Uptime
......
<?php
//Copyright (c) 2011, David Morley. This file is licensed under the Affero General Public License version 3 or later. See the COPYRIGHT file.
/**
* API access for pod data.
*/
declare(strict_types=1);
use RedBeanPHP\R;
......@@ -21,7 +26,7 @@ R::testConnection() || die('Error in DB connection');
R::usePartialBeans(true);
if ($_format === 'georss') {
echo <<<EOF
echo <<<EOF
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:georss="http://www.georss.org/georss">
<title>Diaspora Pods</title>
......@@ -30,26 +35,26 @@ if ($_format === 'georss') {
EOF;
try {
$pods = R::getAll('
SELECT name, monthsmonitored, responsetimelast7, uptimelast7, dateupdated, score, domain, country, lat, long
FROM pods_apiv1
');
} catch (\RedBeanPHP\RedException $e) {
die('Error in SQL query: ' . $e->getMessage());
}
foreach ($pods as $pod) {
$summary = sprintf(
'This pod %1$s has been watched for %2$s months and its average ping time is %3$s with uptime of %4$s%% this month and was last checked on %5$s. On a score of 100 this pod is a %6$s right now',
htmlentities($pod['name'], ENT_QUOTES),
$pod['monthsmonitored'],
$pod['responsetimelast7'],
$pod['uptimelast7'],
$pod['dateupdated'],
$pod['score']
);
echo <<<EOF
try {
$pods = R::getAll('
SELECT name, monthsmonitored, responsetimelast7, uptimelast7, dateupdated, score, domain, country, lat, long
FROM pods_apiv1
');
} catch (\RedBeanPHP\RedException $e) {
die('Error in SQL query: ' . $e->getMessage());
}
foreach ($pods as $pod) {
$summary = sprintf(
'This pod %1$s has been watched for %2$s months and its average ping time is %3$s with uptime of %4$s%% this month and was last checked on %5$s. On a score of 100 this pod is a %6$s right now',
htmlentities($pod['name'] ?? '', ENT_QUOTES),
$pod['monthsmonitored'],
$pod['responsetimelast7'],
$pod['uptimelast7'],
$pod['dateupdated'],
$pod['score']
);
echo <<<EOF
<entry>
<title>https://{$pod['domain']}</title>
<link href="https://{$pod['domain']}"/>
......@@ -62,51 +67,50 @@ EOF;
</entry>
EOF;
}
echo '</feed>';
}
echo '</feed>';
} elseif ($_format === 'json') {
try {
$pods = R::getAll('
SELECT id, domain, status, secure, score, userrating, adminrating, city, state, country, lat, long, ip, ipv6, pingdomurl, monthsmonitored, uptimelast7, responsetimelast7, local_posts, comment_counts, dateCreated, dateUpdated, dateLaststats, hidden
FROM pods_apiv1
');
} catch (\RedBeanPHP\RedException $e) {
die('Error in SQL query: ' . $e->getMessage());
}
//json output, thx Vipul A M for fixing this
header('Content-type: application/json');
try {
$pods = R::getAll('
SELECT id, domain, status, secure, score, userrating, adminrating, city, state, country, lat, long, ip, ipv6, pingdomurl, monthsmonitored, uptimelast7, responsetimelast7, local_posts, comment_counts, dateCreated, dateUpdated, dateLaststats, hidden
FROM pods_apiv1
');
} catch (\RedBeanPHP\RedException $e) {
die('Error in SQL query: ' . $e->getMessage());
}
//json output, thx Vipul A M for fixing this
header('Content-type: application/json');
$obj = [
'podcount' => count($pods),
'pods' => allToString($pods),
];
if ($_method === 'jsonp') {
print $_callback . '(' . json_encode($obj) . ')';
} else {
print json_encode($obj);
}
$obj = [
'podcount' => count($pods),
'pods' => allToString($pods),
];
if ($_method === 'jsonp') {
print $_callback . '(' . json_encode($obj) . ')';
} else {
print json_encode($obj);
}
} else {
try {
$pods = R::getAll('
SELECT domain, uptimelast7, country
FROM pods_apiv1
');
} catch (\RedBeanPHP\RedException $e) {
die('Error in SQL query: ' . $e->getMessage());
}
$i = 0;
foreach ($pods as $pod) {
$i++ > 0 && print ',';
printf(
'%1$s Up %2$s%% This Month - Located in: %3$s',
$pod['domain'],
$pod['uptimelast7'],
$pod['country']
);
}
try {
$pods = R::getAll('
SELECT domain, uptimelast7, country
FROM pods_apiv1
');
} catch (\RedBeanPHP\RedException $e) {
die('Error in SQL query: ' . $e->getMessage());
}
$i = 0;
foreach ($pods as $pod) {
$i++ > 0 && print ',';
printf(
'%1$s Up %2$s%% This Month - Located in: %3$s',
$pod['domain'],
$pod['uptimelast7'],
$pod['country']
);
}
}
/**
......@@ -121,18 +125,16 @@ EOF;
*/
function allToString(array $arr)
{
$ret = $arr;
foreach ($ret as &$item) {
if (is_array($item)) {
/** @var array $item */
foreach ($item as &$field) {
$field !== null && $field = (string) $field;
}
} else {
$item !== null && $item = (string) $item;
$ret = $arr;
foreach ($ret as &$item) {
if (is_array($item)) {
$item = allToString($item);
continue;
}
$item !== null && $item = (string) $item;
unset($item);
}
unset($field, $item);
}
return $ret;
return $ret;
}
{
"name": "poduptime",
"homepage": "https://github.com/diasporg/Poduptime",
"authors": [
"David Morley <support@diasp.org>"
],
"description": "Diaspora pod checking site",
"main": "",
"keywords": [
"diaspora"
],
"license": "AGPL",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"bootstrap": "v4.0.0-alpha.6",
"jquery-ui": "^1.12.1",
"tablesorter": "jquery.tablesorter#^2.28.3",
"leaflet": "^1.0.2",
"leaflet.markercluster": "^1.0.0",
"facebox": "*",
"chart.js": "^2.4.0"
}
}
{
"config": {
"platform": {
"php": "7.2"
}
},
"require": {
"noplanman/xec": "0.1.0",
"php": "^7.2",
"gabordemooij/redbean": "^5.0",
"jaybizzle/crawler-detect" :"1.*",
"commerceguys/enum": "^1.0"
"nesbot/carbon": "^1.31",
"commerceguys/enum": "^1.0",
"noplanman/xec": "0.1.0",
"jaybizzle/crawler-detect": "1.*",
"patrickschur/language-detection": "^3.3",
"geoip2/geoip2": "^2.9",
"maxmind-db/reader": "~1.0"
},
"require-dev": {
"squizlabs/php_codesniffer": "^3.3"
},
"autoload": {
"classmap": ["lib"]
},
"scripts": {
"check-code": [
"vendor/bin/phpcs --standard=PSR2 -snp --encoding=utf-8 --report-width=150 lib *.php"
]
}
}
This diff is collapsed.
<?php
/* Copyright (c) 2011, David Morley. This file is licensed under the Affero General Public License version 3 or later. See the COPYRIGHT file. */
//backup directory
$backup_dir = '/backup';
//log directory
$log_dir = '/log';
//location of pg dump
/**
* Config for Poduptime.
*/
//backup directory - full dir path
$backup_dir = __DIR__ . '/backup';
//log directory - full dir path
$log_dir = __DIR__ . '/log';
//location of pg dump - full dir path
$pg_dump_dir = '/usr/bin';
//db host
$pghost = 'localhost';
//db username
$pguser = '';
//db password
$pgpass = '';
//db name
$pgdb = '';
//admin email for forms
$adminemail = '';
//DNS server for dnssec testing. 1.1.1.1 tests the best
$dnsserver = '';
//CA for curl to use - suggest wget http://curl.haxx.se/ca/cacert.pem as they pull from mozilla if you use a system CA then certs like wosign and startssl will be valid but users will be unable to connect to them
//CA for curl to use - full file path (pull.sh will update this monthly)
$cafullpath = '';
//Mapbox.com API key. https://www.mapbox.com/help/how-access-tokens-work/
$mapboxkey = '';
//Geolite2-city database file in mmdb format - full file path (pull.sh will update this monthly)
$geoip2db = '';
body {
padding-top: 54px;
}
.sub-header {
border-bottom: 1px solid #eee;
padding-bottom: 10px;
}
.sidebar {
background-color: #f5f5f5;
border-right: 1px solid #eee;
bottom: 0;
display: block;
overflow-x: hidden;
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
padding: 10px;
position: fixed;
top: 54px;
z-index: 1000;
}
.sidebar .nav {
margin-bottom: 20px;
}
.sidebar .nav .nav-link {
padding: .3em .7em;
}
.main {
padding: 20px;
padding: 20px;
}
.placeholders {
margin-bottom: 30px;
text-align: center;
margin-bottom: 30px;
text-align: center;
}
.placeholders h4 {
margin-bottom: 0;
margin-bottom: 0;
}
.placeholder {
margin-bottom: 20px;
margin-bottom: 20px;
}
.placeholder img {
border-radius: 50%;
display: inline-block;
}
.rating {
font-size:9px;
border-radius: 50%;
display: inline-block;
}
.tfont {
font-size:12px;
font-size: 12px;
}
.smlogo {
width: 16px;
height: 16px;
background: url('/images/smlogo.png') 0 0;
display: inline-block;
margin: 0 2px;
width: 16px;
height: 16px;
background: url('/images/smlogo.png') 0 0;
display: inline-block;
margin: 0;
}
.smlogo-twitter {
background-position: 0 -776px;
background-position: 0 -776px;
}
.smlogo-facebook {
background-position: 0 -824px;
background-position: 0 -824px;
}
.smlogo-tumblr {
background-position: 0 -792px;
background-position: 0 -792px;
}
.smlogo-wordpress {
background-position: 0 -656px;
background-position: 0 -656px;
}
.smlogo-xmpp {
background: none;
background: none;
}
.smlogo-xmpp img {
vertical-align: unset;
vertical-align: unset;
}
#map {
height: 580px;
}
#map { height: 580px; }
.mycluster {
width: 35px;
height: 35px;
background-color: blue;
text-align: left;
font-size: 17px;
background: url('/bower_components/leaflet/dist/images/marker-icon-2x.png') repeat-y right bottom;
background-size: 25px 37px;
width: 35px;
height: 35px;
text-align: left;
font-size: 17px;
background: url('/node_modules/leaflet/dist/images/marker-icon-2x.png') repeat-y right bottom;
background-size: 25px 37px;
}
.icon {
color: red;
color: red;
}
.tablesorter-pager .btn-group-sm .btn {
font-size: 1.2em; /* make pager arrows more visible */
}
.tablesorter-filter-row td {
background: #eee;
line-height: normal;
text-align: center; /* center the input */
-webkit-transition: line-height 0.1s ease;
-moz-transition: line-height 0.1s ease;
-o-transition: line-height 0.1s ease;
transition: line-height 0.1s ease;
}
.tablesorter-filter-row .disabled {
opacity: 0.5;
filter: alpha(opacity=50);
cursor: not-allowed;
}
.tablesorter-filter-row.hideme td {
/*** *********************************************** ***/
/*** change this padding to modify the thickness ***/
/*** of the closed filter row (height = padding x 2) ***/
padding: 1px;
/*** *********************************************** ***/
margin: 0;
line-height: 0;
cursor: pointer;
}
.tablesorter-filter-row.hideme * {
height: 1px;
min-height: 0;
border: 0;
padding: 0;
margin: 0;
/* don't use visibility: hidden because it disables tabbing */
opacity: 0;
filter: alpha(opacity=0);
}
table {
empty-cells: show;
/* filters */
.tablesorter-filter {
width: 98%;
height: inherit;
margin: 1px;
padding: 1px;
background-color: #fff;
border: 1px solid #bbb;
color: #333;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-transition: height 0.1s ease;
-moz-transition: height 0.1s ease;
-o-transition: height 0.1s ease;
transition: height 0.1s ease;
}
.pagination {
display: inline-block;
color: black;
float: left;
padding: 2px 8px;
margin: 0 4px;
text-decoration: none;
transition: background-color .3s;
border: 1px solid #ddd;
cursor: pointer;
}
#facebox {
z-index: 1000 !important;
.pagination.disabled {
color: #f0f0f0;
}
#facebox .content {
width: 800px !important;
.pagedisplay {
display: inline-block;
color: black;
float: left;
padding: 2px 8px !important;
margin: 0 4px;
text-decoration: none;
transition: background-color .3s;
border: 1px solid #ddd;
cursor: pointer;
}
.tablesorter-header {
background-size: 10px 15px !important;
background-size: 10px 15px !important;
}
.loadingtable {
visibility: hidden;
width: 100%;
height: 100%;
}
@-webkit-keyframes featherlightLoader {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes featherlightLoader {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.featherlight-close-icon {
font-size: 30px;
}
.featherlight-loading .featherlight-content {
-webkit-animation: featherlightLoader 1s infinite linear;
animation: featherlightLoader 1s infinite linear;
background: transparent;
border: 8px solid #8f8f8f;
border-left-color: #fff;
border-radius: 80px;
width: 80px;
height: 80px;
min-width: 0;
}
.featherlight-loading .featherlight-content > * {
display: none !important;
}
.featherlight-loading .featherlight-close,
.featherlight-loading .featherlight-inner {
display: none;
}
<!-- /* Copyright (c) 2011, David Morley. This file is licensed under the Affero General Public License version 3 or later. See the COPYRIGHT file. */ -->
<?php
/**
* Add a new pod.
*/