initial commit

This commit is contained in:
Seán C McCord 2017-09-30 22:12:29 -04:00
commit 14b485e2d7
38 changed files with 1664 additions and 0 deletions

26
.drone.yml Normal file
View file

@ -0,0 +1,26 @@
pipeline:
build:
image: ulexus/drone-revel
pull: true
commands:
- mkdir -p ${GOPATH}/github.com/CyCoreSystems/test-revel
- cp -a * ${GOPATH}/github.com/CyCoreSystems/test-revel/
- revel build github.com/CyCoreSystems/test-revel tmp
publish:
image: plugins/docker
repo: quay.io/cycore/web
tags:
- "${DRONE_COMMIT}"
registry: quay.io
email: ulexus@gmail.com
secrets: [ docker_username, docker_password ]
deploy:
image: quay.io/honestbee/drone-kubernetes
namespace: web
deployment: cycore
container: web
secrets: [ kubernetes_username, kubernetes_token, kubernetes_server ]
repo: quay.io/cycore/web
tag:
- "${DRONE_COMMIT}"

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
test-results/
tmp/
routes/

3
Dockerfile Normal file
View file

@ -0,0 +1,3 @@
FROM ulexus/go-minimal
COPY tmp/cycore-web /app
COPY tmp/src /

75
README.md Normal file
View file

@ -0,0 +1,75 @@
# Welcome to Revel
## Getting Started
A high-productivity web framework for the [Go language](http://www.golang.org/).
### Start the web server:
revel run myapp
Run with <tt>--help</tt> for options.
### Go to http://localhost:9000/ and you'll see:
"It works"
### Description of Contents
The default directory structure of a generated Revel application:
myapp App root
app App sources
controllers App controllers
init.go Interceptor registration
models App domain models
routes Reverse routes (generated code)
views Templates
tests Test suites
conf Configuration files
app.conf Main configuration file
routes Routes definition
messages Message files
public Public assets
css CSS files
js Javascript files
images Image files
app
The app directory contains the source code and templates for your application.
conf
The conf directory contains the applications configuration files. There are two main configuration files:
* app.conf, the main configuration file for the application, which contains standard configuration parameters
* routes, the routes definition file.
messages
The messages directory contains all localized message files.
public
Resources stored in the public directory are static assets that are served directly by the Web server. Typically it is split into three standard sub-directories for images, CSS stylesheets and JavaScript files.
The names of these directories may be anything; the developer need only update the routes.
test
Tests are kept in the tests directory. Revel provides a testing framework that makes it easy to write and run functional tests against your application.
### Follow the guidelines to start developing your application:
* The README file created within your application.
* The [Getting Started with Revel](http://revel.github.io/tutorial/index.html).
* The [Revel guides](http://revel.github.io/manual/index.html).
* The [Revel sample apps](http://revel.github.io/samples/index.html).
* The [API documentation](https://godoc.org/github.com/revel/revel).
## Contributing
We encourage you to contribute to Revel! Please check out the [Contributing to Revel
guide](https://github.com/revel/revel/blob/master/CONTRIBUTING.md) for guidelines about how
to proceed. [Join us](https://groups.google.com/forum/#!forum/revel-framework)!

11
app/controllers/app.go Normal file
View file

@ -0,0 +1,11 @@
package controllers
import "github.com/revel/revel"
type App struct {
*revel.Controller
}
func (c App) Index() revel.Result {
return c.Render()
}

109
app/controllers/contact.go Normal file
View file

@ -0,0 +1,109 @@
package controllers
import (
"bytes"
"encoding/json"
"html/template"
"net/http"
"os"
"time"
"github.com/CyCoreSystems/test-revel/app/routes"
"github.com/pkg/errors"
"github.com/revel/revel"
)
var contactEmailT *template.Template
func init() {
contactEmailT = template.Must(template.New("contactEmail").Parse(contactEmailTemplate))
}
// Contact controller handles customer contact operations
type Contact struct {
*revel.Controller
}
// Request handles a customer contact request
func (c Contact) Request(name, email string) revel.Result {
emailBody, err := renderContactEmail(name, email)
if err != nil {
return c.Controller.RenderError(errors.Wrap(err, "failed to render email for contact request"))
}
body, err := emailRequestBody(emailBody)
if err != nil {
return c.Controller.RenderError(errors.Wrap(err, "failed to encode email request"))
}
// Don't sent when in dev mode
if revel.Config.BoolDefault("mode.dev", true) {
revel.INFO.Println("email:", name, email, bytes.NewBuffer(body).String())
c.Flash.Success("request faked")
return c.Redirect(routes.App.Index())
}
mreq, err := http.NewRequest("POST", "https://api.sendinblue.com/v2.0/email", bytes.NewReader(body))
mreq.Header.Add("api-key", os.Getenv("SENDINBLUE_APIKEY"))
mreq.Header.Add("Content-Type", "application/json")
mreq.Header.Add("X-Mailin-Tag", "contact-request")
resp, err := http.DefaultClient.Do(mreq)
if err != nil {
revel.ERROR.Println("Failed to send contact request email", name, email, err)
return c.Controller.RenderError(errors.Wrap(err, "failed to send contact request email"))
}
if resp.StatusCode > 299 {
revel.ERROR.Println("Contact request email was rejected:", name, email, resp.Status, bytes.NewBuffer(body).String())
c.Flash.Error("failed to send context request")
return c.Redirect(routes.App.Index())
}
c.Flash.Success("Request sent")
return c.Redirect(routes.App.Index())
}
func renderContactEmail(name, email string) (string, error) {
buf := new(bytes.Buffer)
err := contactEmailT.Execute(buf, struct {
Name string
Email string
Timestamp string
}{
Name: name,
Email: email,
Timestamp: time.Now().String(),
})
if err != nil {
return "", err
}
return buf.String(), nil
}
func emailRequestBody(email string) ([]byte, error) {
body := struct {
To map[string]string `json:"to"`
Subject string `json:"subject"`
From []string `json:"from"`
HTML string `json:"html"`
}{
To: map[string]string{"ulexus@gmail.com": "Sean C McCord"},
Subject: "Contact Request",
From: []string{"sys@cycoresys.com", "CyCore Systems Inc"},
HTML: email,
}
return json.Marshal(&body)
}
var contactEmailTemplate = `
<html>
<body>
<h3>Web Contact Form</h3>
<ul>
<li><b>Name:</b> {{.Name}}</li>
<li><b>Email:</b> {{.Email}}</li>
<li><b>Timestamp:</b> {{.Timestamp}}</li>
</ul>
</body>
</html>
`

38
app/init.go Normal file
View file

@ -0,0 +1,38 @@
package app
import "github.com/revel/revel"
func init() {
// Filters is the default set of global filters.
revel.Filters = []revel.Filter{
revel.PanicFilter, // Recover from panics and display an error page instead.
revel.RouterFilter, // Use the routing table to select the right Action
revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
revel.ParamsFilter, // Parse parameters into Controller.Params.
revel.SessionFilter, // Restore and write the session cookie.
revel.FlashFilter, // Restore and write the flash cookie.
revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie.
revel.I18nFilter, // Resolve the requested language
HeaderFilter, // Add some security based headers
revel.InterceptorFilter, // Run interceptors around the action.
revel.CompressFilter, // Compress the result.
revel.ActionInvoker, // Invoke the action.
}
// register startup functions with OnAppStart
// ( order dependent )
// revel.OnAppStart(InitDB)
// revel.OnAppStart(FillCache)
}
// TODO turn this into revel.HeaderFilter
// should probably also have a filter for CSRF
// not sure if it can go in the same filter or not
var HeaderFilter = func(c *revel.Controller, fc []revel.Filter) {
// Add some common security headers
c.Response.Out.Header().Add("X-Frame-Options", "SAMEORIGIN")
c.Response.Out.Header().Add("X-XSS-Protection", "1; mode=block")
c.Response.Out.Header().Add("X-Content-Type-Options", "nosniff")
fc[0](c, fc[1:]) // Execute the next filter stage.
}

31
app/views/App/Index.html Normal file
View file

@ -0,0 +1,31 @@
{{set . "title" "CyCore Systems"}}
{{template "header.html" .}}
<div id="page">
<div class="transcontentunit twelve" id="mainlogo">
&nbsp;
</div>
<div class="transcontentunit twelve" id="mainstatement">
<h2>
Whether you need a design, an MVP, or a finished product: we solve problems.
</h2>
</div>
<div class="transcontentunit twelve" id="maincontact">
{{template "flash.html" .}}
{{template "contact.html" .}}
</div>
<div class="transcontentunit twelve" id="mainservice">
<ul>
<li class="one">Architecture</li>
<li class="two">Design</li>
<li class="one">Performance</li>
<li class="three">Containerizing</li>
<li class="one">UI, UX, Usability</li>
<li class="two">App Development</li>
<li class="three">Voice &amp; IoT</li>
<li class="two">Training</li>
</ul>
</div>
</div>
{{template "footer.html" .}}

7
app/views/contact.html Normal file
View file

@ -0,0 +1,7 @@
<h4>Set up a no-obligation fifteen minute call now
<form action="/contact/request" method="POST">
<input type="text" name="name" placeholder="Your Name" REQUIRED />
<input type="email" name="email" placeholder="Your Email" REQUIRED />
<input type="submit" name="submit" value="Let's Chat" />
</form>
</h4>

64
app/views/debug.html Normal file
View file

@ -0,0 +1,64 @@
<style type="text/css">
#sidebar {
position: absolute;
right: 0px;
top:69px;
max-width: 75%;
z-index: 1000;
background-color: #fee;
border: thin solid grey;
padding: 10px;
}
#toggleSidebar {
position: absolute;
right: 0px;
top: 50px;
background-color: #fee;
}
</style>
<div id="sidebar" style="display:none;">
<h4>Available pipelines</h4>
<dl>
{{ range $index, $value := .}}
<dt>{{$index}}</dt>
<dd>{{$value}}</dd>
{{end}}
</dl>
<h4>Flash</h4>
<dl>
{{ range $index, $value := .flash}}
<dt>{{$index}}</dt>
<dd>{{$value}}</dd>
{{end}}
</dl>
<h4>Errors</h4>
<dl>
{{ range $index, $value := .errors}}
<dt>{{$index}}</dt>
<dd>{{$value}}</dd>
{{end}}
</dl>
</div>
<a id="toggleSidebar" href="#" class="toggles"><i class="glyphicon glyphicon-chevron-left"></i></a>
<script>
$sidebar = 0;
$('#toggleSidebar').click(function() {
if ($sidebar === 1) {
$('#sidebar').hide();
$('#toggleSidebar i').addClass('glyphicon-chevron-left');
$('#toggleSidebar i').removeClass('glyphicon-chevron-right');
$sidebar = 0;
}
else {
$('#sidebar').show();
$('#toggleSidebar i').addClass('glyphicon-chevron-right');
$('#toggleSidebar i').removeClass('glyphicon-chevron-left');
$sidebar = 1;
}
return false;
});
</script>

20
app/views/errors/404.html Normal file
View file

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Not found</title>
</head>
<body>
{{if eq .RunMode "dev"}}
{{template "errors/404-dev.html" .}}
{{else}}
{{with .Error}}
<h1>
{{.Title}}
</h1>
<p>
{{.Description}}
</p>
{{end}}
{{end}}
</body>
</html>

16
app/views/errors/500.html Normal file
View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>Application error</title>
</head>
<body>
{{if eq .RunMode "dev"}}
{{template "errors/500-dev.html" .}}
{{else}}
<h1>Oops, an error occured</h1>
<p>
This exception has been logged.
</p>
{{end}}
</body>
</html>

18
app/views/flash.html Normal file
View file

@ -0,0 +1,18 @@
{{if .flash.success}}
<div class="alert alert-success">
{{.flash.success}}
</div>
{{end}}
{{if or .errors .flash.error}}
<div class="alert alert-error">
{{if .flash.error}}
{{.flash.error}}
{{end}}
<ul style="margin-top:10px;">
{{range .errors}}
<li>{{.}}</li>
{{end}}
</ul>
</div>
{{end}}

25
app/views/footer.html Normal file
View file

@ -0,0 +1,25 @@
<div class="footer">
<div class="credit">
<a href="http://www.cycoresys.com">
Site by CyCore Systems
</a>
</div>
<div class="copy">
&copy; 2016 CyCore Systems
</div>
<!--
<div class="social">
<a href="">
<i class="fa fa-twitter"></i>
</a>
</div>
-->
</div>
{{if eq .RunMode "dev"}}
{{template "debug.html" .}}
{{end}}
</body>
</html>

19
app/views/header.html Normal file
View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<title>{{.title}}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="CyCore Systems, Inc.">
<link rel="shortcut icon" type="image/png" href="/public/img/favicon.png">
<link rel="stylesheet/less" type="text/css" href="/public/css/master.less"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/2.7.1/less.min.js"></script>
{{range .moreStyles}}
<link rel="stylesheet" type="text/css" href="/public/{{.}}">
{{end}}
{{range .moreScripts}}
<script src="/public/{{.}}" type="text/javascript" charset="utf-8"></script>
{{end}}
</head>
<body>

218
conf/app.conf Normal file
View file

@ -0,0 +1,218 @@
################################################################################
# Revel configuration file
# See:
# http://revel.github.io/manual/appconf.html
# for more detailed documentation.
################################################################################
# This sets the `AppName` variable which can be used in your code as
# `if revel.AppName {...}`
app.name = cycore-web
# A secret string which is passed to cryptographically sign the cookie to prevent
# (and detect) user modification.
# Keep this string secret or users will be able to inject arbitrary cookie values
# into your application
app.secret = pggqixEuKBuN8nuwrUAkTyrjCnx5YtRNh4Y7TIHvmRKh0SXrqcqPxDny6UtMyxLL
# Revel running behind proxy like nginx, haproxy, etc
app.behind.proxy = false
# The IP address on which to listen.
http.addr =
# The port on which to listen.
http.port = 9000
# Whether to use SSL or not.
http.ssl = false
# Path to an X509 certificate file, if using SSL.
#http.sslcert =
# Path to an X509 certificate key, if using SSL.
#http.sslkey =
# For any cookies set by Revel (Session,Flash,Error) these properties will set
# the fields of:
# http://golang.org/pkg/net/http/#Cookie
#
# Each cookie set by Revel is prefixed with this string.
cookie.prefix = CYCORE
# A secure cookie has the secure attribute enabled and is only used via HTTPS,
# ensuring that the cookie is always encrypted when transmitting from client to
# server. This makes the cookie less likely to be exposed to cookie theft via
# eavesdropping.
#
# In dev mode, this will default to false, otherwise it will
# default to true.
# cookie.secure = false
# Limit cookie access to a given domain
#cookie.domain =
# Define when your session cookie expires. Possible values:
# "720h"
# A time duration (http://golang.org/pkg/time/#ParseDuration) after which
# the cookie expires and the session is invalid.
# "session"
# Sets a session cookie which invalidates the session when the user close
# the browser.
session.expires = 720h
# The date format used by Revel. Possible formats defined by the Go `time`
# package (http://golang.org/pkg/time/#Parse)
format.date = 2006-01-02
format.datetime = 2006-01-02 15:04
# Timeout specifies a time limit for request (in seconds) made by a single client.
# A Timeout of zero means no timeout.
timeout.read = 90
timeout.write = 60
# Determines whether the template rendering should use chunked encoding.
# Chunked encoding can decrease the time to first byte on the client side by
# sending data before the entire template has been fully rendered.
results.chunked = false
# Prefixes for each log message line
# User can override these prefix values within any section
# For e.g: [dev], [prod], etc
log.trace.prefix = "TRACE "
log.info.prefix = "INFO "
log.warn.prefix = "WARN "
log.error.prefix = "ERROR "
# The default language of this application.
i18n.default_language = en
# The default format when message is missing.
# The original message shows in %s
#i18n.unknown_format = "??? %s ???"
# Module to serve static content such as CSS, JavaScript and Media files
# Allows Routes like this:
# `Static.ServeModule("modulename","public")`
module.static=github.com/revel/modules/static
################################################################################
# Section: dev
# This section is evaluated when running Revel in dev mode. Like so:
# `revel run path/to/myapp`
[dev]
# This sets `DevMode` variable to `true` which can be used in your code as
# `if revel.DevMode {...}`
# or in your templates with
# `<no value>`
mode.dev = true
# Pretty print JSON/XML when calling RenderJson/RenderXml
results.pretty = true
# Automatically watches your applicaton files and recompiles on-demand
watch = true
# If you set watch.mode = "eager", the server starts to recompile
# your application every time your application's files change.
watch.mode = "normal"
# Watch the entire $GOPATH for code changes. Default is false.
#watch.gopath = true
# Module to run code tests in the browser
# See:
# http://revel.github.io/manual/testing.html
module.testrunner = github.com/revel/modules/testrunner
# Where to log the various Revel logs
log.trace.output = off
log.info.output = stderr
log.warn.output = stderr
log.error.output = stderr
# Revel log flags. Possible flags defined by the Go `log` package,
# please refer https://golang.org/pkg/log/#pkg-constants
# Go log is "Bits or'ed together to control what's printed"
# Examples:
# 0 => just log the message, turn off the flags
# 3 => log.LstdFlags (log.Ldate|log.Ltime)
# 19 => log.Ldate|log.Ltime|log.Lshortfile
# 23 => log.Ldate|log.Ltime|log.Lmicroseconds|log.Lshortfile
log.trace.flags = 19
log.info.flags = 19
log.warn.flags = 19
log.error.flags = 19
# Revel request access log
# Access log line format:
# RequestStartTime ClientIP ResponseStatus RequestLatency HTTPMethod URLPath
# Sample format:
# 2016/05/25 17:46:37.112 127.0.0.1 200 270.157µs GET /
log.request.output = stderr
################################################################################
# Section: prod
# This section is evaluated when running Revel in production mode. Like so:
# `revel run path/to/myapp prod`
# See:
# [dev] section for documentation of the various settings
[prod]
mode.dev = false
results.pretty = false
watch = false
module.testrunner =
log.trace.output = off
log.info.output = off
log.warn.output = log/%(app.name)s.log
log.error.output = log/%(app.name)s.log
# Revel log flags. Possible flags defined by the Go `log` package,
# please refer https://golang.org/pkg/log/#pkg-constants
# Go log is "Bits or'ed together to control what's printed"
# Examples:
# 0 => just log the message, turn off the flags
# 3 => log.LstdFlags (log.Ldate|log.Ltime)
# 19 => log.Ldate|log.Ltime|log.Lshortfile
# 23 => log.Ldate|log.Ltime|log.Lmicroseconds|log.Lshortfile
log.trace.flags = 3
log.info.flags = 3
log.warn.flags = 3
log.error.flags = 3
# Revel request access log
# Access log line format:
# RequestStartTime ClientIP ResponseStatus RequestLatency HTTPMethod URLPath
# Sample format:
# 2016/05/25 17:46:37.112 127.0.0.1 200 270.157µs GET /
# Example:
# log.request.output = %(app.name)s-request.log
log.request.output = off
app.behind.proxy = true
app.secret = ${COOKIE_SECRET}

22
conf/routes Normal file
View file

@ -0,0 +1,22 @@
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~
module:testrunner
GET / App.Index
# Handle contact requests
POST /contact/request Contact.Request
# Ignore favicon requests
GET /favicon.ico 404
# Map static resources from the /app/public folder to the /public path
GET /public/*filepath Static.Serve("public")
# GPG Public key
GET /scm.asc Static.Serve("public", "scm.asc")
# Catch all
* /:controller/:action :controller.:action

7
messages/sample.en Normal file
View file

@ -0,0 +1,7 @@
# Sample messages file for the English language (en)
# Message file extensions should be ISO 639-1 codes (http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)
# Sections within each message file can optionally override the defaults using ISO 3166-1 alpha-2 codes (http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
# See also:
# - http://www.rfc-editor.org/rfc/bcp/bcp47.txt
# - http://www.w3.org/International/questions/qa-accept-lang-locales

12
public/css/alert.import.less vendored Normal file
View file

@ -0,0 +1,12 @@
.alert {
width: 100%;
text-align: center;
}
.alert-error {
color: @red;
}
.alert-success {
color: @green;
}

1
public/css/anim.import.less vendored Normal file
View file

@ -0,0 +1 @@
//ANIMATIONS

164
public/css/base.import.less vendored Normal file
View file

@ -0,0 +1,164 @@
//PRESETS
body, div, nav, ul, li, a, label, span, table {
margin: 0;
padding: 0;
float: left;
box-sizing: border-box;
background-clip: border-box;
}
body {
min-height: 100%;
height: 100%;
background: @background;
}
ul {
list-style: none;
}
div {
float: left;
}
a {
text-decoration: none;
font-weight: bold;
padding: 5px 10px;
.border-radius(7px);
.fasttrans;
color: @key;
}
a:hover { .fasttrans; color: @keylight;}
.hide { display: none; }
//GRID COLUMNS
.twelve { .column(12); }
.ten { .column(10); }
.nine { .column(9); }
.eight { .column(8); }
.six { .column(6); }
.five { .column(5); }
.four { .column(4); }
.three { .column(3); }
.two { .column(2); }
//STRUCTURES
#page {
width: 100%;
height: 100%;
min-height: 500px;
background: white;
}
.unit { //used for tables
overflow: hidden;
.background-linear-gradient(#fff 25%, @lightgrey);
border: 1px solid @lightgrey;
.border-radius(5px);
.box-shadow(1px 1px 1px 0 rgba(0, 0, 0, 0.6));
}
.contentunit {
.background-linear-gradient(white, fadeout(@keylight, 98%));
.border-radius(10px);
border: 2px solid fadeout(@keylight, 60%);
}
.transcontentunit {
.contentunit;
background: transparent none;
border: 2px solid transparent;
}
.colorcontentunit {
.contentunit;
background: @key;
border: 2px solid @key;
font-size: 1.3em;
color: white;
padding: 20px;
}
label {
width: 40%;
text-align: right;
margin-left: 7px;
}
i {
color: white;
display: block;
text-align: center;
margin: 0 auto;
background-color: @key;
.border-radius(150px);
.box-shadow(0px 1px 2px 0 @darkestgrey);
.fasttrans;
}
i:hover { background-color: @keylight; .fasttrans; }
.social i {
font-size: 26px;
height: 32px;
width: 42px;
padding-top: 10px;
color: white;
}
.hide { display: none; }
.tag {
display: block;
background: fadeout(@keylight, 80%);
.border-radius(2px);
padding: 2px 5px;
margin: 2px 10px 2px 0;
border: 1px solid @lightestgrey;
color: @darkgrey;
font-weight: bold;
}
.footer {
position: relative;
width: 100%;
height: 50px;
padding: 50px 30px 0 30px;
.copy, .credit {
.sans;
font-size: 16px;
font-weight: normal;
line-height: 30px;
margin: 0;
width: auto;
padding: 0 10px;
}
.credit a {
margin: 0;
padding: 0;
line-height: 30px;
color: @key;
}
.credit a:hover {
color: @keydark;
}
.copy {
color: @darkgrey;
float: right;
}
.login {
float: right;
a { .sans; }
}
.social {
float: right;
height: 100%;
padding-right: 50px;
}
}

82
public/css/button.import.less vendored Normal file
View file

@ -0,0 +1,82 @@
//BUTTONS
button { border: 0 none; }
button.demo {
background-color: @key;
border-top: 1px solid @keylight;
border-bottom: 1px solid @transblack;
.box-shadow(
inset 0 0 20px 5px @transblack,
inset 0 0 0 0 @keylight,
0 2px 4px 0 @lightblack);
text-shadow: -1px -1px 0 black, 1px 1px 0 @keylight;
color: white;
.slowtrans;
i {
color: @key;
font-size: 85px;
text-shadow: 0 0 0 transparent;
vertical-align: bottom;
position: relative;
top: -11px;
}
}
button.demo:hover {
// background-color: @keylight;
.box-shadow(
inset 0 0 20px 5px @transblack,
inset 0px 10px 50px 0 fadeout(@keylight, 70%),
0 2px 4px 0 @lightblack);
text-shadow: -1px -1px 0 black, 1px 1px 0 @key;
.slowtrans;
i {
color: white;
text-shadow: 0 0 4px @key;
.fasttrans;
}
}
button.large {
width: 800px;
margin: 0 auto;
height: 100px;
.border-radius(8px);
padding-top: 7px;
font-size: 80px;
line-height: 100px;
}
button.medium {
.column(5, 8);
.push(2);
height: 60px;
.border-radius(6px);
margin-top: 20px;
font-size: 40px;
line-height: 60px;
i { font-size: 50px; top: -6px; }
}
button.green:hover { background-color: @green; .fasttrans; }
button.small {
.column(2);
.push(2);
margin-top: 100px;
height: 50px;
.border-radius(6px);
font-size: 40px;
line-height: 50px;
}
button:focus { outline: none; }

76
public/css/fonts.import.less vendored Normal file
View file

@ -0,0 +1,76 @@
//CHANGE IMPORT AND open/sans/bold
@import url(https://fonts.googleapis.com/css?family=Montserrat|Rokkitt:700|Rubik+Mono+One);
.open { font-family: Verdana, sans-serif; }
.sans { font-family: Monserrat, sans-serif; }
.bold { font-family: Rokkitt, sans-serif; }
* {
font-size: 16px;
line-height: 24px;
}
a {
font-weight: bold;
}
.nav a { .open; }
.brand {
.open;
display: block;
color: @grey;
margin: 0 auto;
text-align: center;
line-height: 48px;
}
.light {
color: white;
text-shadow: 1px 1px 2px @darkgrey, -1px -1px 1px @darkestgrey;
}
h1, h2, h3, h4, h5, h6 { .open; }
h1 {
font-size: 5em;
position: relative;
color: @red;
word-wrap: break-word;
font-weight: normal;
line-height: 2em;
text-shadow: -1px -1px 0 black;
}
h2 {
font-size: 3em;
line-height: 1.2em;
color: @key;
}
h3 {
font-size: 1.2em;
padding-left: 10px; padding-right: 10px;
}
h4 {
font-size: 2.2em;
line-height: 1em;
color: @keylight;
text-align: center;
}
h5, h6 { color: @darkergrey; }
h5 {
font-size: 1em;
}
h6 {
font-size: 1.1em;
}
em {
color: @keydark;
font-style: italic;
font-weight: normal;
padding: 2px;
.border-radius(2px);
}
.fix { color: @red; }

34
public/css/forms.import.less vendored Normal file
View file

@ -0,0 +1,34 @@
label, .label, input, select, textarea {
font-size: 20px;
line-height: 20px;
display: inline-block;
.border-radius(3px);
vertical-align: top;
padding: 5px 10px;
border: 0 none;
float: left;
width: auto;
}
input, select, textarea {
}
input {
border: 1px solid @lightgrey;
}
input[type=submit] {
.bold;
padding: 7px 20px;
margin-left: 10px;
background: @keylight;
color: white;
.fasttrans;
}
input[type=submit]:hover, input[type=submit]:active {
background: saturate(@contrast, 20%);
.fasttrans;
}

65
public/css/grid.import.less vendored Normal file
View file

@ -0,0 +1,65 @@
/////////////////
// Semantic.gs // for LESS: http://lesscss.org/
/////////////////
// Defaults which you can freely override
@column-width: 60;
@gutter-width: 0;
@columns: 12;
// Utility variable — you should never need to modify this
@gridsystem-width: (@column-width*@columns) + (@gutter-width*@columns) * 1px;
// Set @total-width to 100% for a fluid layout
@total-width: 100%;
// Uncomment these two lines and the star-hack width/margin lines below to enable sub-pixel fix for IE6 & 7. See http://tylertate.com/blog/2012/01/05/subpixel-rounding.html
// @min-width: 960;
// @correction: 0.5 / @min-width * 100 * 1%;
// The micro clearfix http://nicolasgallagher.com/micro-clearfix-hack/
.clearfix() {
*zoom:1;
&:before,
&:after {
content:"";
display:table;
}
&:after {
clear:both;
}
}
//////////
// GRID //
//////////
body {
width: 100%;
.clearfix;
}
.row(@columns:@columns) {
display: block;
width: @total-width*((@gutter-width + @gridsystem-width)/@gridsystem-width);
margin: 0 @total-width*(((@gutter-width*.5)/@gridsystem-width)*-1);
// *width: @total-width*((@gutter-width + @gridsystem-width)/@gridsystem-width)-@correction;
// *margin: 0 @total-width*(((@gutter-width*.5)/@gridsystem-width)*-1)-@correction;
.clearfix;
}
.column(@x,@columns:@columns) {
display: inline;
float: left;
width: @total-width*((((@gutter-width+@column-width)*@x)-@gutter-width) / @gridsystem-width);
margin: 0 @total-width*((@gutter-width*.5)/@gridsystem-width);
// *width: @total-width*((((@gutter-width+@column-width)*@x)-@gutter-width) / @gridsystem-width)-@correction;
// *margin: 0 @total-width*((@gutter-width*.5)/@gridsystem-width)-@correction;
}
.push(@offset:1) {
margin-left: @total-width*(((@gutter-width+@column-width)*@offset) / @gridsystem-width) + @total-width*((@gutter-width*.5)/@gridsystem-width);
}
.pull(@offset:1) {
margin-right: @total-width*(((@gutter-width+@column-width)*@offset) / @gridsystem-width) + @total-width*((@gutter-width*.5)/@gridsystem-width);
}

87
public/css/master.less Normal file
View file

@ -0,0 +1,87 @@
@import 'grid.import.less';
@import 'var.import.less';
@import 'fonts.import.less';
@import 'rules.import.less';
@import 'anim.import.less';
@import 'base.import.less';
@import 'nav.import.less';
@import 'forms.import.less';
@import 'tables.import.less';
@import 'button.import.less';
@import 'media.import.less';
@import 'alert.import.less';
//ADD CUSTOM AND OVERRIDE CODE HERE
//HOME
#mainlogo {
background: url('/public/img/logo/Cycore_web_optimized.jpg')
center center no-repeat;
background-size: contain;
height: 500px;
}
#mainstatement {
color: @keydark;
text-align: center;
}
#maincontact {
h4 { text-align: center; }
form { padding: 20px;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
input { margin: 2px; flex: 1 0 auto; }
}
#mainservice {
padding: 0 10px;
ul { .twelve;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-around;
align-content: stretch;
li {
display: block;
height: 5em;
width: auto;
margin: 10px;
flex: 1 0 auto;
font-size: 1.5em;
font-weight: bold;
color: @darkergrey;
text-align: center;
padding: 1em;
padding-top: 2em;
.stripes;
}
.one {background-color: @contrast; }
.two {background-color: lighten(#2196f3, 10%);}
.three {background-color: fadeout(#4caf50, 10%);}
}
}

14
public/css/media.import.less vendored Normal file
View file

@ -0,0 +1,14 @@
//COLUMN RESPONSE
//add here
//ADD BREAKPOINTS IF NECESSARY
@media all and (max-width: 1180px) {
}

39
public/css/nav.import.less vendored Normal file
View file

@ -0,0 +1,39 @@
//NAV MENUS AND LINKS
.nav {
position: fixed;
height: 50px;
margin: 0 0;
padding: 0;
z-index: 1000;
background: black ;
background-size: contain;
display: flex;
justify-content: space-between;
align-items: center;
.logo { padding: 7px 0 0 0;
width: auto;
}
a {
display: block;
flex: 0 0 auto;
padding-top: 18px;
.two;
.slowtrans;
z-index: 1000;
color: @keylight;
}
a:hover {
.fasttrans;
}
}

142
public/css/rules.import.less vendored Normal file
View file

@ -0,0 +1,142 @@
.placeholder (@color) {
input::-webkit-input-placeholder { color: @color; padding: 7px 10px 3px 10px;}
input:-moz-placeholder { color: @color;padding: 7px 10px 3px 10px; }
input::-moz-placeholder { color: @color;padding: 7px 10px 3px 10px; }
input:-ms-input-placeholder { color: @color;padding: 7px 10px 3px 10px; }
}
.border-radius (@radius) {
border-radius: @radius;
-moz-border-radius: @radius;
-webkit-border-radius: @radius;
background-clip: padding-box;
-moz-background-clip: padding;
-webkit-background-clip: padding-box;
}
.background-linear-gradient (@color1, @color2) {
background: linear-gradient(top, @color1, @color2);
background: -moz-linear-gradient(@color1, @color2); //FF3.6-
background: -webkit-linear-gradient(top, @color1, @color2); //S5.1, Chrome 10-
background: -o-linear-gradient(top, @color1, @color2); //O 11.1
background: -ms-linear-gradient(@color1, @color2); //IE10
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='@color1', endColorstr='@color2'); //IE6-7
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='@color1', endColorstr='@color2')"; //IE8-9
}
.background-linear-gradient (@color1, @color2, @color3) {
background: linear-gradient(top, @color1, @color2, @color3);
background: -moz-linear-gradient(@color1, @color2, @color3); //FF3.6-
background: -webkit-linear-gradient(top, @color1, @color2, @color3); //S5.1, Chrome 10-
background: -o-linear-gradient(top, @color1, @color2, @color3); //O 11.1
background: -ms-linear-gradient(@color1, @color2, @color3); //IE10
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='@color1', endColorstr='@color3'); //IE6-7
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='@color1', endColorstr='@color3')"; //IE8-9
}
.background-gradient (@degrees, @color1, @color2, @color3, @color4, @color5, @color6, @color7) {
background-image: linear-gradient(@degrees, @color1, @color2, @color3, @color4, @color5, @color6, @color7);
background-image: -moz-linear-gradient(@degrees, @color1, @color2, @color3, @color4, @color5, @color6, @color7);
background-image: -webkit-linear-gradient(@degrees, @color1, @color2, @color3, @color4, @color5, @color6, @color7);
background-image: -o-linear-gradient(@degrees, @color1, @color2, @color3, @color4, @color5, @color6, @color7);
background-image: -ms-linear-gradient(@degrees, @color1, @color2, @color3, @color4, @color5, @color6, @color7);
}
.box-shadow (none) {
box-shadow: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
}
.box-shadow (@shadow) {
box-shadow: @shadow;
-moz-box-shadow: @shadow;
-webkit-box-shadow: @shadow;
}
.box-shadow (@shadow1, @shadow2) {
box-shadow: @shadow1, @shadow2;
-moz-box-shadow: @shadow1, @shadow2;
-webkit-box-shadow: @shadow1, @shadow2;
}
.box-shadow (@shadow1, @shadow2, @shadow3) {
box-shadow: @shadow1, @shadow2, @shadow3;
-moz-box-shadow: @shadow1, @shadow2, @shadow3;
-webkit-box-shadow: @shadow1, @shadow2, @shadow3;
}
.transition (@property, @duration, @function, @delay) {
-webkit-transition: @property @duration @function @delay;
-moz-transition: @property @duration @function @delay;
-o-transition: @property @duration @function @delay;
-ms-transition: @property @duration @function @delay;
transition: @property @duration @function @delay;
}
.transition (@property1, @duration1, @function1, @delay1, @property2, @duration2, @function2, @delay2) {
-webkit-transition: @property1 @duration1 @function1 @delay1, @property2 @duration2 @function2 @delay2;
-moz-transition: @property1 @duration1 @function1 @delay1, @property2 @duration2 @function2 @delay2;
-o-transition: @property1 @duration1 @function1 @delay1, @property2 @duration2 @function2 @delay2;
-ms-transition: @property1 @duration1 @function1 @delay1, @property2 @duration2 @function2 @delay2;
transition: @property1 @duration1 @function1 @delay1, @property2 @duration2 @function2 @delay2;
}
.transition (@property1, @duration1, @function1, @delay1, @property2, @duration2, @function2, @delay2, @property3, @duration3, @function3, @delay3) {
-webkit-transition: @property1 @duration1 @function1 @delay1, @property2 @duration2 @function2 @delay2, @property3 @duration3 @function3 @delay3;
-moz-transition: @property1 @duration1 @function1 @delay1, @property2 @duration2 @function2 @delay2, @property3 @duration3 @function3 @delay3;
-o-transition: @property1 @duration1 @function1 @delay1, @property2 @duration2 @function2 @delay2, @property3 @duration3 @function3 @delay3;
-ms-transition: @property1 @duration1 @function1 @delay1, @property2 @duration2 @function2 @delay2, @property3 @duration3 @function3 @delay3;
transition: @property1 @duration1 @function1 @delay1, @property2 @duration2 @function2 @delay2, @property3 @duration3 @function3 @delay3;
}
.transition (@property1, @duration1, @function1, @delay1, @property2, @duration2, @function2, @delay2, @property3, @duration3, @function3, @delay3, @property4, @duration4, @function4, @delay4) {
-webkit-transition: @property1 @duration1 @function1 @delay1, @property2 @duration2 @function2 @delay2, @property3 @duration3 @function3 @delay3, @property4 @duration4 @function4 @delay4;
-moz-transition: @property1 @duration1 @function1 @delay1, @property2 @duration2 @function2 @delay2, @property3 @duration3 @function3 @delay3, @property4 @duration4 @function4 @delay4;
-o-transition: @property1 @duration1 @function1 @delay1, @property2 @duration2 @function2 @delay2, @property3 @duration3 @function3 @delay3, @property4 @duration4 @function4 @delay4;
-ms-transition: @property1 @duration1 @function1 @delay1, @property2 @duration2 @function2 @delay2, @property3 @duration3 @function3 @delay3, @property4 @duration4 @function4 @delay4;
transition: @property1 @duration1 @function1 @delay1, @property2 @duration2 @function2 @delay2, @property3 @duration3 @function3 @delay3, @property4 @duration4 @function4 @delay4;
}
.transition (inherit) {
-webkit-transition: inherit;
-moz-transition: inherit;
-o-transition: inherit;
-ms-transition: inherit;
transition: inherit;
}
.fasttrans { .transition(all, 0.4s, ease, 0s); }
.slowtrans { .transition(all, 2s, ease, 0s); }
.rotate (@deg) {
-webkit-transform: rotate(@deg);
-moz-transform: rotate(@deg);
-o-transform: rotate(@deg);
-ms-transform: rotate(@deg);
transform: rotate(@deg);
}
.scale(@amount) {
-webkit-transform: scale(@amount);
-moz-transform: scale(@amount);
-ms-transform: scale(@amount);
transform: scale(@amount);
}
.flipX {
-webkit-transform: scaleX(-1);
-moz-transform: scaleX(-1);
-ms-transform: scaleX(-1);
-o-transform: scaleX(-1);
transform: scaleX(-1);
}
//TEXTURES
.polka {
background:
radial-gradient(@lighttransblack 15%, transparent 16%) 0 0,
radial-gradient(@lighttransblack 15%, transparent 16%) 8px 8px,
radial-gradient(rgba(255,255,255,.01) 15%, transparent 20%) 0 1px,
radial-gradient(rgba(255,255,255,.01) 15%, transparent 20%) 8px 9px;
background-size: 8px 8px;
}
.stripes {
background: repeating-linear-gradient(
45deg,
transparent,
transparent 10px,
@transwhite 10px,
@transwhite 20px
);
}

49
public/css/tables.import.less vendored Normal file
View file

@ -0,0 +1,49 @@
//TABLE
table {
.unit;
border-collapse: collapse;
background-clip: padding-box;
}
td, th {
margin: 0;
text-align: center;
vertical-align: middle;
padding: 7px 5px;
}
@color1: fadeout(#fff, 40%);
@color2: fadeout(lighten(desaturate(@highlightblue, 20%), 40%), 45%);
tr:nth-child(2n+1) td {
background: @color1;
}
tr:nth-child(2n) td {
background: @color2;
}
th {
background: @lightergrey;
color: @darkgrey;
}
tr:hover td:nth-child(1n) {
background-color: @highlightyellow;
}
td.header {
background: transparent !important;
color: @darkergrey;
text-shadow: 1px 1px 1px #fff;
font-weight: bold;
text-align: right;
padding-right: 15px;
}
table i {
color: @darkergrey;
}
table i:hover {
color: fadeout(@lightlightblue, 30%);
}
.large { width: 80%; margin-left: 10%; }

54
public/css/var.import.less vendored Normal file
View file

@ -0,0 +1,54 @@
//COLOR VARIABLES
@background: white;
@border: @transblack;
//BRAND COLORS
@key: #2d65af; //CHANGE ME!! NOT >>
@keylight: #38b4e7;
@keylightest: lighten(@key, 25%);
@keydark: darken(@key, 15%);
@keydarker: darken(@key, 29%);
@keydarkest: darken(@key, 36%);
@contrast: #ff9900;
@contrastdark: darken(@contrast, 28%);
@contrastlight: lighten(@contrast, 15%);
@contrastlightest: lighten(@contrast, 23%);
//FUNCTION COLORS
@lightlightblue: lighten(@highlightblue, 14%);
@highlightblue: #0069ff;
@darkhighlightblue: darken(@highlightblue, 10%);
@orange: #FF8300;
@highlightyellow: #fcf4b5;
@gold: #FFEF02;
@red: #aa0000;
@purple: #1100ff;
@green: #008d00;
@darkgreen: darken(desaturate(@green, 10%), 10%);
//MONO
@lightestgrey: #eee;
@lightergrey: #ddd;
@lightgrey: #ccc;
@grey: #aaa;
@darkgrey: #888;
@darkergrey: #555;
@darkestgrey: #222;
@lighttransblack: rgba(0,0,0,0.02);
@transblack: rgba(0, 0, 0, 0.2);
@lightblack: rgba(0, 0, 0, 0.5);
@midblack: rgba(0, 0, 0, 0.8);
@transwhite: rgba(255, 255, 255, 0.05);
@lightwhite: rgba(255, 255, 255, 0.1);
@midwhite: rgba(255, 255, 255, 0.6);

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/img/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

112
public/scm.asc Normal file
View file

@ -0,0 +1,112 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2
mQINBFdMggwBEACv2/63qtJF5hCZML+nNdTHS5Hmlu9QSEljtp7ju9oJExbXeMk7
aOQeUWUoF2IiQBLMSZPtLk4m/gN45AYCBUrh+zgVVlDFDmEIt3PiNQdWKdQlWt3z
CjwS8gXdZU+HPBdg2ytDCNpXdFR8LlUr8uIRJ1zKVtGiaudmwIRWgnjouYg/dxNQ
j2MnRpPg/r7m0uqjlgKXwWLFTm6hEGSDE+f2zFhaVnoAXQgVub5CLtgWeDBhw+Mz
VmUjDQbrh9rSpF/zI+10qL3IdPjVLUgmPV7nHelko4NNxBvSOjmkHE9QkVnVmRPj
WJ0K7t++LxZ1ptzq2Ja+sem1V6yiAJ/gznIFuO+wC/TbmJQx9x+xxYnCVY1mQsqC
zSDieUDTA2+Fqqkmec2U9rVMwHeXnLaDsDZ8QNB3OVVSsv5o1dsiHZrdX4XWaRXx
liGZa+QKcV7c/OW5Ni4eCHoMs7mGz7KuEZdASgEWxS18jKTaGWPFCMOSaJhNxyes
EWWX+qFexUYy0GAbWnQUx4dtfmvnAx/bg5r5CuCaRPjMWEboB0sWvdP902Uhcefn
swLWHBNKrQBiHvEDjjydfl3cNzMbxAXVzyZoGAAiAzGdFqk/p7Rr/fdD+wAOhfVO
JlRH2cwdshtDBoFiLjPQyzyI/6DXZs6akqv5LixAyxI9AR/2AT8mxPSMcQARAQAB
tCFTZcOhbiBDIE1jQ29yZCA8dWxleHVzQGdtYWlsLmNvbT6JAjkEEwEIACMFAldM
ggwCGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRBQ3KOO/Uf3v0EWD/0Q
We17hanENr/KU30bDLN/Cw7KOFFshOkp7j/oD5m2zl6N+iNeF4+OQVyWFQTAgUms
MZTSb44TAJj/VC9C1PpFSEkKOhVMDzYfLLpSIgvNzbBpRWuWfEpG7yU9E//CKYrF
D2BWIoumA2pjMheTahGwvvgy/YAkVbrydxcKRsKNzsjyYj5j57H4Xo1yX4nj+s0X
nPu4ia09n8ZyqZYi6rijKbusGMFdAmIfe4zbsMcwdSeXOJMctwtOVRolJFGz71D+
1y9lZUHucoC7mu4p92aZshpHjv9ek3/DRGJ0d0/5ZxVhSW1O/Fk2GbUw9cu4rtxI
XwPG1krBKG2DxRCVrtHTmxlhUaRMwGA5FyO0apa4Rb1aaMgfXl4k8pI0jpUD+bik
156mWkZZNn5bQNNKHvuvbtOGOn3rzhvEGi6FpaI+Wg6M3bdqdEqw3f2KqBw2VMOV
w+7xrDZR78FZ2kcm7CQzGLhAr1DJoe3ClobKpQb90skDV7W60lUTDwkmDq/uzFzY
YZencHy6eA2Y/Y82SrdioW+ISl6ZDWBr0ICfmZK853PXgRj5LoT71XathzS6Gdpc
jUs1RwT5ywLL4+KlqhG/F7ndFrYOBCwB3OC0KAmKmjEIfBFN2G2bjHQJJVKzg57G
kdS53bda515PuEOLiZFANKaDxMosfxa5y0PDrfVchbQ5U2XDoW4gQyBNY0NvcmQg
KGh0dHA6Ly9jeWNvcmVzeXMuY29tKSA8c2NtQGN5Y29yZXN5cy5jb20+iQI5BBMB
CAAjBQJXeW1PAhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQUNyjjv1H
9782GhAAqtw31A8vqqDJlrheTOpvB2XzJRUUvN5mljEqumt/t0rF3DBy2tJFYqfG
KhHdyS3jmjQO9y8j4TDDItV1GsYlxhpfFYL9OegIwOW4trMXKRtPTohlK2dvAJrT
VyEiFMuRPZpBa9q9MiT37j/Wf2OyxY4vMSbu/oU2cHDIXf16MOw9Uz+yVGD7VVbl
IdxhueCMY5qUf6OZMFd1+X3tyvs9/fc8RANXb4ecsSmjrNMKK6tEBiJWf5jAbO80
Hwj7beIb6uZzT6zccGDaPdpijWzCQjrjdm2trJQOPoI66rrKe66zdz23k77AFKEL
w5sFlHhwLuB8yNn6iTquI1++nKUxmxh/KCwV1t0R4m7kAauiFmm18+qGBE7lpumh
F5g5CfNAs/avb/s+kGWFNJte8W7MroNroBJ0E3AoppJWxhqag8IR9HBhq3snnu6I
00T3JMvD88tHS5mCr0ktdQgDimofHNuTZEo7H/tB3uNbLXnJnlDEdNqNchoD+CtE
ZcEoC+vwaPDWobKD5saE1lX+MnK3ffYpom6rfSU4/uF7zlEpiT17TvXpYncBWlei
xeG6ThggqF2uJJ1fS8mOY7L7U8hB7VwC3+OaeP+SMG1xDfqz5M59BiNqKSaZzMEd
/u8nfcyKpGfRg+izN3ker4jbzz7F3MBW3KUpW5hUXetwip9gjre0OVNlw6FuIEMg
TWNDb3JkIChodHRwOi8vY3ljb3Jlc3lzLmNvbSkgPHN5c0BjeWNvcmVzeXMuY29t
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
dvqfj+9x
=isk0
-----END PGP PUBLIC KEY BLOCK-----

21
tests/apptest.go Normal file
View file

@ -0,0 +1,21 @@
package tests
import "github.com/revel/revel/testing"
type AppTest struct {
testing.TestSuite
}
func (t *AppTest) Before() {
println("Set up")
}
func (t *AppTest) TestThatIndexPageWorks() {
t.Get("/")
t.AssertOk()
t.AssertContentType("text/html; charset=utf-8")
}
func (t *AppTest) After() {
println("Tear down")
}