rascunho

commit f754bf11d6cb035652c1e068b3696720bd3f2c31

Author: Pedro Lucas Porcellis <porcellis@eletrotupi.com>

Rename from core to rascunho for better packaging

 app.py | 4 ++--
  | 0 
  | 8 ++++----
  | 4 ++--
  | 4 ++--
  | 0 
  | 4 ++--
  | 0 
  | 0 
  | 0 
  | 0 
  | 0 
  | 0 
  | 2 +-


diff --git a/app.py b/app.py
index e9b5046d9e4bc0e6ec0b2d601613823a5a76db5e..785bbe0945b4502d3613ff1d9473913f4d8dde6d 100644
--- a/app.py
+++ b/app.py
@@ -1,5 +1,5 @@
-from core.app import app
-from core.config import env
+from rascunho.app import app
+from rascunho.config import env
 
 if __name__ == '__main__':
     debug = False




diff --git a/core/__init__.py b/core/__init__.py
deleted file mode 100644
index c07c45996e3bd354c2448c09f07c6f2cfe45d922..0000000000000000000000000000000000000000
--- a/core/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from .app import app




diff --git a/core/app.py b/core/app.py
deleted file mode 100644
index 1b3d402484864cf17f7f021a3aa94768a2486270..0000000000000000000000000000000000000000
--- a/core/app.py
+++ /dev/null
@@ -1,84 +0,0 @@
-from flask import Flask, abort, render_template, request
-from jinja2 import Markup
-import locale
-from core.config import read_from_config, env
-from core.database import db, init_database
-import mistune
-import humanize
-from datetime import datetime, timedelta
-from pytz import timezone
-
-class Rascunho(Flask):
-    def __init__(self, *args, **kwargs):
-        super().__init__(__name__, *args, **kwargs)
-
-        init_database()
-
-        try:
-            # TODO: Use the locale config, from my local package it doesn't
-            # work as the package is out-of-date on Arch's Community Repository
-            humanize.i18n.activate("pt_BR")
-            locale.setlocale(locale.LC_ALL, read_from_config("locale"))
-            locale.setlocale(locale.LC_TIME, read_from_config("locale"))
-        except:
-            pass
-
-
-        from core.blueprints.basic import basic
-        from core.blueprints.api import api
-
-        self.register_blueprint(basic)
-        self.register_blueprint(api)
-
-        @self.template_filter()
-        def human_date(d):
-            if not d:
-                return 'Nunca'
-
-            local_tz = timezone(str(read_from_config("timezone")))
-            d = d.replace(tzinfo=timezone('UTC'))
-            local_date = d.astimezone(local_tz)
-
-            if isinstance(d, timedelta):
-                return Markup('<span title="{}">{}</span>'.format(
-                    f'{d.seconds} segundos', humanize.naturaldelta(d)))
-
-            return Markup('<span title="{}">{}</span>'.format(
-                d.strftime('%Y-%m-%d %H:%M:%S UTC'),
-                humanize.naturaltime(
-                    datetime.now().astimezone(local_tz) - local_date
-                )))
-
-        @self.template_filter()
-        def md(text):
-            return mistune.markdown(text)
-
-        @self.errorhandler(422)
-        def handle_unprocessable_entity(e):
-            if request.path.startswith("/api"):
-                return { "errors": [ { "reason": "422 Unprocessable Entity" } ] }, 422
-
-            return render_template("unprocessable_entity.html", 422)
-
-        @self.errorhandler(500)
-        def handle_internal_server_error(e):
-            if request.path.startswith("/api"):
-                return { "errors": [ { "reason": "500 Internal Server Error" } ] }, 500
-
-            return render_template("internal_error.html", 500)
-
-        @self.errorhandler(404)
-        def handle_not_found(e):
-            if request.path.startswith("/api"):
-                return { "errors": [ { "reason": "404 Not Found" } ] }, 404
-
-            return render_template("not_found.html"), 404
-
-        @self.context_processor
-        def inject():
-            return {
-                "env": env
-            }
-
-
-app = Rascunho()




diff --git a/core/blueprints/__init__.py b/core/blueprints/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
Binary files a/core/blueprints/__init__.py and /dev/null differ




diff --git a/core/blueprints/api.py b/core/blueprints/api.py
deleted file mode 100644
index 3d49d78c2e7615844a93c6c3c6ef46bb9b991b8b..0000000000000000000000000000000000000000
--- a/core/blueprints/api.py
+++ /dev/null
@@ -1,46 +0,0 @@
-from flask import Blueprint, abort, request
-from hashlib import sha1
-from core.types.document import Document
-from core.database import db
-import json
-
-api = Blueprint("apiv1", __name__)
-
-@api.route('/api/v1', methods = ['POST'])
-def create():
-    params = json.loads(request.data.decode('utf-8'))
-
-    doc = None
-    content = params.get('text')
-
-    if not content:
-        abort(422)
-
-    sha = sha1()
-    sha.update(content.encode())
-    sha.update(request.remote_addr.encode())
-
-    existing_doc = Document.query.filter(Document.sha == sha.hexdigest()).one_or_none()
-
-    if existing_doc:
-        doc = existing_doc
-    else:
-        doc = Document()
-
-    doc.sha = sha.hexdigest()
-    doc.content = content
-
-    db.add(doc)
-    db.commit()
-    db.flush()
-
-    return doc.to_dict(), 201
-
-@api.route('/api/v1/<sha>', methods = ['GET'])
-def show(sha):
-    doc = Document.query.filter(Document.sha == sha).one_or_none()
-
-    if not doc:
-        abort(404)
-
-    return doc.to_dict(), 200




diff --git a/core/blueprints/basic.py b/core/blueprints/basic.py
deleted file mode 100644
index 37a0fa7cbe2a94e2ec52846c1fee74ef54204688..0000000000000000000000000000000000000000
--- a/core/blueprints/basic.py
+++ /dev/null
@@ -1,59 +0,0 @@
-from flask import Blueprint, render_template, request, abort, Response, redirect, url_for
-from core.database import db
-from core.types.document import Document
-from hashlib import sha1
-
-basic = Blueprint('basic', __name__)
-
-@basic.route("/", methods = ['GET', 'POST'])
-def index():
-    if request.method == "GET":
-        doc = Document.query.order_by(Document.created_at.asc()).first()
-        return render_template('index.html', doc = doc)
-    else:
-        return create(request.form)
-
-@basic.route("/<sha>", methods = ['GET'])
-def show(sha):
-    doc = Document.query.filter(Document.sha == sha).one_or_none()
-
-    if not doc:
-        abort(404)
-
-    return render_template('preview.html', doc = doc)
-
-@basic.route("/<sha>/raw", methods = ['GET'])
-def raw(sha):
-    doc = Document.query.filter(Document.sha == sha).one_or_none()
-
-    if not doc:
-        abort(404)
-
-    return Response(doc.content, mimetype="text/plain")
-
-def create(params):
-    doc = None
-    content = params['text']
-
-    if not content:
-        abort(422)
-
-    sha = sha1()
-    sha.update(content.encode())
-    sha.update(request.remote_addr.encode())
-
-    existing_doc = Document.query.filter(Document.sha == sha.hexdigest()).one_or_none()
-
-    if existing_doc:
-        doc = existing_doc
-    else:
-        doc = Document()
-
-    doc.sha = sha.hexdigest()
-    doc.content = content
-
-    db.add(doc)
-    db.commit()
-    db.flush()
-
-    return redirect(url_for('basic.show', sha = doc.sha))




diff --git a/core/config.py b/core/config.py
deleted file mode 100644
index 30c507fa0d04934468781a4121749e2a81f8793f..0000000000000000000000000000000000000000
--- a/core/config.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from configparser import ConfigParser
-
-config = ConfigParser()
-config.read_file(open('config.ini'))
-
-env = config['meta']['env']
-
-read_from_config = lambda key: config.get(env, key)




diff --git a/core/database.py b/core/database.py
deleted file mode 100644
index 1c68f5788eadcf97c0c3f878188d8ba70aaca780..0000000000000000000000000000000000000000
--- a/core/database.py
+++ /dev/null
@@ -1,33 +0,0 @@
-from sqlalchemy import create_engine, event
-from sqlalchemy.orm import sessionmaker, scoped_session
-from sqlalchemy.ext.declarative import declarative_base
-
-from datetime import datetime
-
-from core.config import read_from_config
-
-engine = create_engine(read_from_config('connection-string'), echo=True)
-db = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
-
-Base = declarative_base()
-Base.query = db.query_property()
-
-def init_database():
-    @event.listens_for(Base, 'before_insert', propagate=True)
-    def before_insert(mapper, connection, target):
-        if hasattr(target, '_no_autoupdate'):
-            return
-        if hasattr(target, 'created_at'):
-            target.created_at = datetime.utcnow()
-        if hasattr(target, 'updated_at'):
-            target.updated_at = datetime.utcnow()
-
-    @event.listens_for(Base, 'before_update', propagate=True)
-    def before_insert(mapper, connection, target):
-        if hasattr(target, '_no_autoupdate'):
-            return
-        if hasattr(target, 'updated_at'):
-            target.updated_at = datetime.utcnow()
-
-    import core.types
-    Base.metadata.create_all(bind=engine)




diff --git a/core/static/rascunho.css b/core/static/rascunho.css
deleted file mode 100644
index 2fe65ac733b7c1f3f6d369e47398e7095cb512dc..0000000000000000000000000000000000000000
--- a/core/static/rascunho.css
+++ /dev/null
@@ -1,70 +0,0 @@
-.py {
-    margin-top: 1rem;
-    margin-bottom: 1rem;
-}
-
-.box {
-    border: 2px dashed #ccc;
-    padding: 0.5rem;
-}
-
-details > summary {
-    cursor: pointer;
-}
-
-.text-muted {
-    color: #ccc;
-}
-
-.public-box > textarea {
-    width: 100%;
-    border: 0;
-    resize: none;
-}
-
-button {
-    background-color: #444;
-    border-color: transparent;
-    border-width: 1px;
-    color: white;
-    cursor: pointer;
-    justify-content: center;
-    padding-bottom: calc(0.5em - 1px);
-    padding-left: 1em;
-    padding-right: 1em;
-    padding-top: calc(0.5em - 1px);
-    text-align: center;
-    white-space: nowrap
-}
-
-button:hover {
-    background-color: #3e3e3e;
-    border-color: transparent;
-    color: #fff;
-}
-
-/*
- * Markdown to HTML specific styles
- */
-
-blockquote {
-    background-color: #efefef;
-    margin: 0;
-    padding: 2px 1em;
-}
-
-blockquote > p {
-    margin-left: 1em;
-    color: gray;
-}
-
-pre {
-    padding: 5px;
-    background-color: #efefef;
-    white-space: pre-wrap;
-}
-
-code {
-    background-color: #efefef;
-    padding: 0px 5px;
-}




diff --git a/core/static/umbo.min.css b/core/static/umbo.min.css
deleted file mode 100644
index 383623170d0ade7431eb41575f04ea77ff66e026..0000000000000000000000000000000000000000
--- a/core/static/umbo.min.css
+++ /dev/null
@@ -1 +0,0 @@
-html {line-height: 1.15;-webkit-text-size-adjust: 100%;}body {margin: 0;}main {display: block;}h1 {font-size: 2em;margin: 0.67em 0;}hr {box-sizing: content-box;height: 0;overflow: visible;}pre {font-family: monospace, monospace;font-size: 1em;}a {background-color: transparent;}abbr[title] {border-bottom: none;text-decoration: underline;text-decoration: underline dotted;}b,strong {font-weight: bolder;}code,kbd,samp {font-family: monospace, monospace;font-size: 1em;}small {font-size: 80%;}sub,sup {font-size: 75%;line-height: 0;position: relative;vertical-align: baseline;}sub {bottom: -0.25em;}sup {top: -0.5em;}img {border-style: none;}button,input,optgroup,select,textarea {font-family: inherit;font-size: 100%;line-height: 1.15;margin: 0;}button,input {overflow: visible;}button,select {text-transform: none;}button,[type="button"],[type="reset"],[type="submit"] {-webkit-appearance: button;}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner {border-style: none;padding: 0;}button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring {outline: 1px dotted ButtonText;}fieldset {padding: 0.35em 0.75em 0.625em;}legend {box-sizing: border-box;color: inherit;display: table;max-width: 100%;padding: 0;white-space: normal;}progress {vertical-align: baseline;}textarea {overflow: auto;}[type="checkbox"],[type="radio"] {box-sizing: border-box;padding: 0;}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button {height: auto;}[type="search"] {-webkit-appearance: textfield;outline-offset: -2px;}[type="search"]::-webkit-search-decoration {-webkit-appearance: none;}::-webkit-file-upload-button {-webkit-appearance: button;font: inherit;}details {display: block;}summary {display: list-item;}template {display: none;}[hidden] {display: none;}*, ::after, ::before {box-sizing: border-box;}body {font-family: Roboto, "Helvetica Neue", "San Francisco", "Open Sans", Arial, sans-serif;font-size: 1.1875rem;text-rendering: optimizeLegibility;line-height: 1.31579;}h1, .heading-xl {font-size: 3rem;}h2, .heading-l {font-size: 2.25rem;}h3, .heading-m {font-size: 1.5rem;}h4, .heading-s {font-size: 1.1875rem;}a {color: #1d70b8;}a:hover {color: #003078;}a:active {color: #336752;outline: 3px solid transparent;background-color: #33fe96;text-decoration: none;box-shadow: 0 -2px #33fe96,0 4px #0b0c0c;}ul, ol {font-size: 1.1875rem;line-height: 1.31579;}.umbo-table {width: 100%;border-spacing: 0;border-collapse: collapse;}.umbo-caption {font-weight: 700;display: table-caption;text-align: left;}.umbo-table-header, .umbo-table-cell {padding: 10px 20px 10px 0;border-bottom: 1px solid #b1b4b6;text-align: left;vertical-align: top;}.umbo-table-header-numeric, .umbo-table-cell-numeric {text-align: right;}.umbo-table-header {font-weight: 700;}.umbo-table-cell-numeric {font-feature-settings: normal;font-variant-numeric: tabular-nums;}.container {box-sizing: border-box;margin-left: auto;margin-right: auto;padding-right: 8px;padding-left: 8px;}.container-fluid {padding-right: 16px;padding-left: 16px;}@media only screen and (min-width: 576px) {.container {width: 560px;max-width: 100%;}}@media only screen and (min-width: 768px) {.container {width: 752px;max-width: 100%;}}@media only screen and (min-width: 992px) {.container {width: 976px;max-width: 100%;}}@media only screen and (min-width: 1200px) {.container {width: 1184px;max-width: 100%;}}.row {box-sizing: border-box;display: -webkit-box;display: -ms-flexbox;display: flex;-webkit-box-flex: 0;-ms-flex: 0 1 auto;flex: 0 1 auto;-webkit-box-orient: horizontal;-webkit-box-direction: normal;-ms-flex-direction: row;flex-direction: row;-ms-flex-wrap: wrap;flex-wrap: wrap;margin-right: -8px;margin-left: -8px;}.row.reverse {-webkit-box-orient: horizontal;-webkit-box-direction: reverse;-ms-flex-direction: row-reverse;flex-direction: row-reverse;}.col.reverse {-webkit-box-orient: vertical;-webkit-box-direction: reverse;-ms-flex-direction: column-reverse;flex-direction: column-reverse;}.col-xs,.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-offset-0,.col-xs-offset-1,.col-xs-offset-2,.col-xs-offset-3,.col-xs-offset-4,.col-xs-offset-5,.col-xs-offset-6,.col-xs-offset-7,.col-xs-offset-8,.col-xs-offset-9,.col-xs-offset-10,.col-xs-offset-11,.col-xs-offset-12,.col-sm,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-offset-0,.col-sm-offset-1,.col-sm-offset-2,.col-sm-offset-3,.col-sm-offset-4,.col-sm-offset-5,.col-sm-offset-6,.col-sm-offset-7,.col-sm-offset-8,.col-sm-offset-9,.col-sm-offset-10,.col-sm-offset-11,.col-sm-offset-12,.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-md-offset-0,.col-md-offset-1,.col-md-offset-2,.col-md-offset-3,.col-md-offset-4,.col-md-offset-5,.col-md-offset-6,.col-md-offset-7,.col-md-offset-8,.col-md-offset-9,.col-md-offset-10,.col-md-offset-11,.col-md-offset-12,.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-offset-0,.col-lg-offset-1,.col-lg-offset-2,.col-lg-offset-3,.col-lg-offset-4,.col-lg-offset-5,.col-lg-offset-6,.col-lg-offset-7,.col-lg-offset-8,.col-lg-offset-9,.col-lg-offset-10,.col-lg-offset-11,.col-lg-offset-12,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-offset-0,.col-xl-offset-1,.col-xl-offset-2,.col-xl-offset-3,.col-xl-offset-4,.col-xl-offset-5,.col-xl-offset-6,.col-xl-offset-7,.col-xl-offset-8,.col-xl-offset-9,.col-xl-offset-10,.col-xl-offset-11,.col-xl-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;-ms-flex-preferred-size: 100%;flex-basis: 100%;padding-right: 8px;padding-left: 8px;max-width: 100%;}.col-xs {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-xs-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-xs-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-xs-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-xs-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-xs-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-xs-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-xs-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-xs-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-xs-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-xs-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-xs-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-xs-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-xs-offset-0 {margin-left: 0;}.col-xs-offset-1 {margin-left: 8.33333333%;}.col-xs-offset-2 {margin-left: 16.66666667%;}.col-xs-offset-3 {margin-left: 25%;}.col-xs-offset-4 {margin-left: 33.33333333%;}.col-xs-offset-5 {margin-left: 41.66666667%;}.col-xs-offset-6 {margin-left: 50%;}.col-xs-offset-7 {margin-left: 58.33333333%;}.col-xs-offset-8 {margin-left: 66.66666667%;}.col-xs-offset-9 {margin-left: 75%;}.col-xs-offset-10 {margin-left: 83.33333333%;}.col-xs-offset-11 {margin-left: 91.66666667%;}.start-xs {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-xs {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-xs {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-xs {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-xs {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-xs {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-xs {-ms-flex-pack: distribute;justify-content: space-around;}.between-xs {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-xs {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-xs {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-xs {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}@media only screen and (min-width: 576px) {.col-sm {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-sm-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-sm-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-sm-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-sm-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-sm-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-sm-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-sm-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-sm-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-sm-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-sm-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-sm-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-sm-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-sm-offset-0 {margin-left: 0;}.col-sm-offset-1 {margin-left: 8.33333333%;}.col-sm-offset-2 {margin-left: 16.66666667%;}.col-sm-offset-3 {margin-left: 25%;}.col-sm-offset-4 {margin-left: 33.33333333%;}.col-sm-offset-5 {margin-left: 41.66666667%;}.col-sm-offset-6 {margin-left: 50%;}.col-sm-offset-7 {margin-left: 58.33333333%;}.col-sm-offset-8 {margin-left: 66.66666667%;}.col-sm-offset-9 {margin-left: 75%;}.col-sm-offset-10 {margin-left: 83.33333333%;}.col-sm-offset-11 {margin-left: 91.66666667%;}.start-sm {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-sm {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-sm {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-sm {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-sm {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-sm {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-sm {-ms-flex-pack: distribute;justify-content: space-around;}.between-sm {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-sm {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-sm {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-sm {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (min-width: 768px) {.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-md-offset-0,.col-md-offset-1,.col-md-offset-2,.col-md-offset-3,.col-md-offset-4,.col-md-offset-5,.col-md-offset-6,.col-md-offset-7,.col-md-offset-8,.col-md-offset-9,.col-md-offset-10,.col-md-offset-11,.col-md-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;padding-right: 8px;padding-left: 8px;}.col-md {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-md-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-md-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-md-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-md-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-md-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-md-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-md-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-md-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-md-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-md-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-md-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-md-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-md-offset-0 {margin-left: 0;}.col-md-offset-1 {margin-left: 8.33333333%;}.col-md-offset-2 {margin-left: 16.66666667%;}.col-md-offset-3 {margin-left: 25%;}.col-md-offset-4 {margin-left: 33.33333333%;}.col-md-offset-5 {margin-left: 41.66666667%;}.col-md-offset-6 {margin-left: 50%;}.col-md-offset-7 {margin-left: 58.33333333%;}.col-md-offset-8 {margin-left: 66.66666667%;}.col-md-offset-9 {margin-left: 75%;}.col-md-offset-10 {margin-left: 83.33333333%;}.col-md-offset-11 {margin-left: 91.66666667%;}.start-md {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-md {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-md {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-md {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-md {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-md {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-md {-ms-flex-pack: distribute;justify-content: space-around;}.between-md {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-md {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-md {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-md {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (min-width: 992px) {.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-offset-0,.col-lg-offset-1,.col-lg-offset-2,.col-lg-offset-3,.col-lg-offset-4,.col-lg-offset-5,.col-lg-offset-6,.col-lg-offset-7,.col-lg-offset-8,.col-lg-offset-9,.col-lg-offset-10,.col-lg-offset-11,.col-lg-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;padding-right: 8px;padding-left: 8px;}.col-lg {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-lg-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-lg-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-lg-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-lg-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-lg-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-lg-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-lg-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-lg-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-lg-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-lg-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-lg-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-lg-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-lg-offset-0 {margin-left: 0;}.col-lg-offset-1 {margin-left: 8.33333333%;}.col-lg-offset-2 {margin-left: 16.66666667%;}.col-lg-offset-3 {margin-left: 25%;}.col-lg-offset-4 {margin-left: 33.33333333%;}.col-lg-offset-5 {margin-left: 41.66666667%;}.col-lg-offset-6 {margin-left: 50%;}.col-lg-offset-7 {margin-left: 58.33333333%;}.col-lg-offset-8 {margin-left: 66.66666667%;}.col-lg-offset-9 {margin-left: 75%;}.col-lg-offset-10 {margin-left: 83.33333333%;}.col-lg-offset-11 {margin-left: 91.66666667%;}.start-lg {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-lg {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-lg {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-lg {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-lg {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-lg {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-lg {-ms-flex-pack: distribute;justify-content: space-around;}.between-lg {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-lg {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-lg {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-lg {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (min-width: 1200px) {.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-offset-0,.col-xl-offset-1,.col-xl-offset-2,.col-xl-offset-3,.col-xl-offset-4,.col-xl-offset-5,.col-xl-offset-6,.col-xl-offset-7,.col-xl-offset-8,.col-xl-offset-9,.col-xl-offset-10,.col-xl-offset-11,.col-xl-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;padding-right: 8px;padding-left: 8px;}.col-xl {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-xl-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-xl-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-xl-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-xl-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-xl-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-xl-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-xl-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-xl-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-xl-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-xl-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-xl-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-xl-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-xl-offset-0 {margin-left: 0;}.col-xl-offset-1 {margin-left: 8.33333333%;}.col-xl-offset-2 {margin-left: 16.66666667%;}.col-xl-offset-3 {margin-left: 25%;}.col-xl-offset-4 {margin-left: 33.33333333%;}.col-xl-offset-5 {margin-left: 41.66666667%;}.col-xl-offset-6 {margin-left: 50%;}.col-xl-offset-7 {margin-left: 58.33333333%;}.col-xl-offset-8 {margin-left: 66.66666667%;}.col-xl-offset-9 {margin-left: 75%;}.col-xl-offset-10 {margin-left: 83.33333333%;}.col-xl-offset-11 {margin-left: 91.66666667%;}.start-xl {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-xl {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-xl {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-xl {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-xl {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-xl {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-xl {-ms-flex-pack: distribute;justify-content: space-around;}.between-xl {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-xl {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-xl {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-xl {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (max-width: 575px) {.hidden-xs {display: none;}}@media only screen and (min-width: 576px) and (max-width: 767px) {.hidden-sm {display: none;}}@media only screen and (min-width: 768px) and (max-width: 991px) {.hidden-md {display: none;}}@media only screen and (min-width: 992px) and (max-width: 1199px) {.hidden-lg {display: none;}}@media only screen and (min-width: 1200px) {.hidden-xl {display: none;}}.umbo-fieldset {min-width: 0;margin: 0;padding: 0;border: 0;}.umbo-fieldset-legend {margin-bottom: 5px;}.umbo-form-group {display: block;margin-bottom: 30px;}.umbo-label {display: block;font-size: 1rem;font-weight: 400;margin-bottom: 5px;}.umbo-input {font-size: 1rem;line-height: 1.5;padding: .25rem .375rem;height: 2.5rem;border-color: #888;}.umbo-input:focus {outline: 3px solid #33fe96;outline-offset: 0;border: 1px solid #0b0c0c;box-shadow: inset 0px 0px 0px 2px;}.umbo-form-actions {display: inline-block;}.umbo-input-full-width {width: 100%;}.umbo-input-large {width: 75%;}.umbo-input-medium {width: 50%;}.umbo-input-small {width: 25%;}.umbo-input-xsmall {width: 10%;}
\ No newline at end of file




diff --git a/core/templates/index.html b/core/templates/index.html
deleted file mode 100644
index 58f7a3d1d3ccc6a082e675d35ecbbdf7ca6ddf54..0000000000000000000000000000000000000000
--- a/core/templates/index.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{% extends 'layout.html' %}
-
-{% block body %}
-	<div class="row">
-		<div class="col-xs">
-			{{ doc.content | md | safe }}
-		</div>
-	</div>
-
-	<div class="row box">
-		<div class="col-xs">
-			<form method="POST" action="/" class="public-box">
-				<textarea name="text" cols="72" rows="30" placeholder="Escreva aqui"></textarea>
-				<br />
-				<button type="submit">Enviar</button>
-			</form>
-		</div>
-	</div>
-{% endblock %}




diff --git a/core/templates/internal_server.html b/core/templates/internal_server.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
Binary files a/core/templates/internal_server.html and /dev/null differ




diff --git a/core/templates/layout.html b/core/templates/layout.html
deleted file mode 100644
index 3503a71a1648076a7de6ef7334a9b59df0a30ed4..0000000000000000000000000000000000000000
--- a/core/templates/layout.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
-		<title>Rascunho - Prévia de Markdown</title>
-		<meta name="viewport" content="width=device-width, initial-scale=1" />
-		<link href="/static/umbo.min.css" rel="stylesheet" />
-		<link href="/static/rascunho.css" rel="stylesheet" />
-	</head>
-
-	<body>
-		<div class="container py">
-			{% block body %}
-			{% endblock %}
-		</div>
-	</body>
-</html>
-




diff --git a/core/templates/not_found.html b/core/templates/not_found.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
Binary files a/core/templates/not_found.html and /dev/null differ




diff --git a/core/templates/preview.html b/core/templates/preview.html
deleted file mode 100644
index 207bf8599bb51a2c03f1da875f558ad92afbefd8..0000000000000000000000000000000000000000
--- a/core/templates/preview.html
+++ /dev/null
@@ -1,31 +0,0 @@
-{% extends 'layout.html' %}
-
-{% block body %}
-	<div class="row">
-		<div class="col-xs">
-			{{ doc.content | md | safe }}
-		</div>
-	</div>
-
-	<div class="row">
-		<div class="col-xs">
-			<details>
-				<summary>Informações sobre este rascunho</summary>
-				<div class="box text-muted">
-					<ul>
-						<li>
-							Identificador: {{ doc.sha }}
-						</li>
-						<li>
-							Criado há: {{ doc.created_at | human_date | safe }}
-						</li>
-						<li>
-							<a href="/{{doc.sha}}/raw">Ver arquivo puro</a>
-						</li>
-					</ul>
-				</div>
-			</details>
-		</div>
-	</div>
-
-{% endblock %}




diff --git a/core/templates/unprocessable_entity.html b/core/templates/unprocessable_entity.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
Binary files a/core/templates/unprocessable_entity.html and /dev/null differ




diff --git a/core/types/__init__.py b/core/types/__init__.py
deleted file mode 100644
index 9c01ea2470e408389a5b947f4247f87ecd21a81d..0000000000000000000000000000000000000000
--- a/core/types/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from . import document




diff --git a/core/types/document.py b/core/types/document.py
deleted file mode 100644
index 9f6cf83adf823e11b6bb9fb671eb7a8528fd00d9..0000000000000000000000000000000000000000
--- a/core/types/document.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import sqlalchemy as sa
-from core.database import Base
-
-class Document(Base):
-    __tablename__ = 'documents'
-
-    id = sa.Column(sa.Integer, primary_key=True)
-    sha = sa.Column(sa.String(40), nullable=False, index=True)
-    content = sa.Column(sa.Unicode, nullable=False)
-
-    created_at = sa.Column(sa.DateTime, nullable=False)
-    updated_at = sa.Column(sa.DateTime, nullable=False)
-
-    def to_dict(self):
-        return {
-            "sha": self.sha,
-            "content": self.content,
-            "created_at": self.created_at,
-            "updated_at": self.updated_at
-        }




diff --git a/rascunho/__init__.py b/rascunho/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..c07c45996e3bd354c2448c09f07c6f2cfe45d922
--- /dev/null
+++ b/rascunho/__init__.py
@@ -0,0 +1 @@
+from .app import app




diff --git a/rascunho/app.py b/rascunho/app.py
new file mode 100644
index 0000000000000000000000000000000000000000..19d288e2c2c290d6a4304be25fd780d0cfcf6dd7
--- /dev/null
+++ b/rascunho/app.py
@@ -0,0 +1,84 @@
+from flask import Flask, abort, render_template, request
+from jinja2 import Markup
+import locale
+from rascunho.config import read_from_config, env
+from rascunho.database import db, init_database
+import mistune
+import humanize
+from datetime import datetime, timedelta
+from pytz import timezone
+
+class Rascunho(Flask):
+    def __init__(self, *args, **kwargs):
+        super().__init__(__name__, *args, **kwargs)
+
+        init_database()
+
+        try:
+            # TODO: Use the locale config, from my local package it doesn't
+            # work as the package is out-of-date on Arch's Community Repository
+            humanize.i18n.activate("pt_BR")
+            locale.setlocale(locale.LC_ALL, read_from_config("locale"))
+            locale.setlocale(locale.LC_TIME, read_from_config("locale"))
+        except:
+            pass
+
+
+        from rascunho.blueprints.basic import basic
+        from rascunho.blueprints.api import api
+
+        self.register_blueprint(basic)
+        self.register_blueprint(api)
+
+        @self.template_filter()
+        def human_date(d):
+            if not d:
+                return 'Nunca'
+
+            local_tz = timezone(str(read_from_config("timezone")))
+            d = d.replace(tzinfo=timezone('UTC'))
+            local_date = d.astimezone(local_tz)
+
+            if isinstance(d, timedelta):
+                return Markup('<span title="{}">{}</span>'.format(
+                    f'{d.seconds} segundos', humanize.naturaldelta(d)))
+
+            return Markup('<span title="{}">{}</span>'.format(
+                d.strftime('%Y-%m-%d %H:%M:%S UTC'),
+                humanize.naturaltime(
+                    datetime.now().astimezone(local_tz) - local_date
+                )))
+
+        @self.template_filter()
+        def md(text):
+            return mistune.markdown(text)
+
+        @self.errorhandler(422)
+        def handle_unprocessable_entity(e):
+            if request.path.startswith("/api"):
+                return { "errors": [ { "reason": "422 Unprocessable Entity" } ] }, 422
+
+            return render_template("unprocessable_entity.html", 422)
+
+        @self.errorhandler(500)
+        def handle_internal_server_error(e):
+            if request.path.startswith("/api"):
+                return { "errors": [ { "reason": "500 Internal Server Error" } ] }, 500
+
+            return render_template("internal_error.html", 500)
+
+        @self.errorhandler(404)
+        def handle_not_found(e):
+            if request.path.startswith("/api"):
+                return { "errors": [ { "reason": "404 Not Found" } ] }, 404
+
+            return render_template("not_found.html"), 404
+
+        @self.context_processor
+        def inject():
+            return {
+                "env": env
+            }
+
+
+app = Rascunho()




diff --git a/rascunho/blueprints/__init__.py b/rascunho/blueprints/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
Binary files /dev/null and b/rascunho/blueprints/__init__.py differ




diff --git a/rascunho/blueprints/api.py b/rascunho/blueprints/api.py
new file mode 100644
index 0000000000000000000000000000000000000000..1edecc9851c5358d76068bda4eec292465a6c3c6
--- /dev/null
+++ b/rascunho/blueprints/api.py
@@ -0,0 +1,46 @@
+from flask import Blueprint, abort, request
+from hashlib import sha1
+from rascunho.types.document import Document
+from rascunho.database import db
+import json
+
+api = Blueprint("apiv1", __name__)
+
+@api.route('/api/v1', methods = ['POST'])
+def create():
+    params = json.loads(request.data.decode('utf-8'))
+
+    doc = None
+    content = params.get('text')
+
+    if not content:
+        abort(422)
+
+    sha = sha1()
+    sha.update(content.encode())
+    sha.update(request.remote_addr.encode())
+
+    existing_doc = Document.query.filter(Document.sha == sha.hexdigest()).one_or_none()
+
+    if existing_doc:
+        doc = existing_doc
+    else:
+        doc = Document()
+
+    doc.sha = sha.hexdigest()
+    doc.content = content
+
+    db.add(doc)
+    db.commit()
+    db.flush()
+
+    return doc.to_dict(), 201
+
+@api.route('/api/v1/<sha>', methods = ['GET'])
+def show(sha):
+    doc = Document.query.filter(Document.sha == sha).one_or_none()
+
+    if not doc:
+        abort(404)
+
+    return doc.to_dict(), 200




diff --git a/rascunho/blueprints/basic.py b/rascunho/blueprints/basic.py
new file mode 100644
index 0000000000000000000000000000000000000000..ab074db00e5eceb37736539029ed458b80a053c8
--- /dev/null
+++ b/rascunho/blueprints/basic.py
@@ -0,0 +1,59 @@
+from flask import Blueprint, render_template, request, abort, Response, redirect, url_for
+from rascunho.database import db
+from rascunho.types.document import Document
+from hashlib import sha1
+
+basic = Blueprint('basic', __name__)
+
+@basic.route("/", methods = ['GET', 'POST'])
+def index():
+    if request.method == "GET":
+        doc = Document.query.order_by(Document.created_at.asc()).first()
+        return render_template('index.html', doc = doc)
+    else:
+        return create(request.form)
+
+@basic.route("/<sha>", methods = ['GET'])
+def show(sha):
+    doc = Document.query.filter(Document.sha == sha).one_or_none()
+
+    if not doc:
+        abort(404)
+
+    return render_template('preview.html', doc = doc)
+
+@basic.route("/<sha>/raw", methods = ['GET'])
+def raw(sha):
+    doc = Document.query.filter(Document.sha == sha).one_or_none()
+
+    if not doc:
+        abort(404)
+
+    return Response(doc.content, mimetype="text/plain")
+
+def create(params):
+    doc = None
+    content = params['text']
+
+    if not content:
+        abort(422)
+
+    sha = sha1()
+    sha.update(content.encode())
+    sha.update(request.remote_addr.encode())
+
+    existing_doc = Document.query.filter(Document.sha == sha.hexdigest()).one_or_none()
+
+    if existing_doc:
+        doc = existing_doc
+    else:
+        doc = Document()
+
+    doc.sha = sha.hexdigest()
+    doc.content = content
+
+    db.add(doc)
+    db.commit()
+    db.flush()
+
+    return redirect(url_for('basic.show', sha = doc.sha))




diff --git a/rascunho/config.py b/rascunho/config.py
new file mode 100644
index 0000000000000000000000000000000000000000..30c507fa0d04934468781a4121749e2a81f8793f
--- /dev/null
+++ b/rascunho/config.py
@@ -0,0 +1,8 @@
+from configparser import ConfigParser
+
+config = ConfigParser()
+config.read_file(open('config.ini'))
+
+env = config['meta']['env']
+
+read_from_config = lambda key: config.get(env, key)




diff --git a/rascunho/database.py b/rascunho/database.py
new file mode 100644
index 0000000000000000000000000000000000000000..9998ba7434ea4caf35c2aa547233fc154c572421
--- /dev/null
+++ b/rascunho/database.py
@@ -0,0 +1,33 @@
+from sqlalchemy import create_engine, event
+from sqlalchemy.orm import sessionmaker, scoped_session
+from sqlalchemy.ext.declarative import declarative_base
+
+from datetime import datetime
+
+from rascunho.config import read_from_config
+
+engine = create_engine(read_from_config('connection-string'), echo=True)
+db = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
+
+Base = declarative_base()
+Base.query = db.query_property()
+
+def init_database():
+    @event.listens_for(Base, 'before_insert', propagate=True)
+    def before_insert(mapper, connection, target):
+        if hasattr(target, '_no_autoupdate'):
+            return
+        if hasattr(target, 'created_at'):
+            target.created_at = datetime.utcnow()
+        if hasattr(target, 'updated_at'):
+            target.updated_at = datetime.utcnow()
+
+    @event.listens_for(Base, 'before_update', propagate=True)
+    def before_insert(mapper, connection, target):
+        if hasattr(target, '_no_autoupdate'):
+            return
+        if hasattr(target, 'updated_at'):
+            target.updated_at = datetime.utcnow()
+
+    import rascunho.types
+    Base.metadata.create_all(bind=engine)




diff --git a/rascunho/static/rascunho.css b/rascunho/static/rascunho.css
new file mode 100644
index 0000000000000000000000000000000000000000..2fe65ac733b7c1f3f6d369e47398e7095cb512dc
--- /dev/null
+++ b/rascunho/static/rascunho.css
@@ -0,0 +1,70 @@
+.py {
+    margin-top: 1rem;
+    margin-bottom: 1rem;
+}
+
+.box {
+    border: 2px dashed #ccc;
+    padding: 0.5rem;
+}
+
+details > summary {
+    cursor: pointer;
+}
+
+.text-muted {
+    color: #ccc;
+}
+
+.public-box > textarea {
+    width: 100%;
+    border: 0;
+    resize: none;
+}
+
+button {
+    background-color: #444;
+    border-color: transparent;
+    border-width: 1px;
+    color: white;
+    cursor: pointer;
+    justify-content: center;
+    padding-bottom: calc(0.5em - 1px);
+    padding-left: 1em;
+    padding-right: 1em;
+    padding-top: calc(0.5em - 1px);
+    text-align: center;
+    white-space: nowrap
+}
+
+button:hover {
+    background-color: #3e3e3e;
+    border-color: transparent;
+    color: #fff;
+}
+
+/*
+ * Markdown to HTML specific styles
+ */
+
+blockquote {
+    background-color: #efefef;
+    margin: 0;
+    padding: 2px 1em;
+}
+
+blockquote > p {
+    margin-left: 1em;
+    color: gray;
+}
+
+pre {
+    padding: 5px;
+    background-color: #efefef;
+    white-space: pre-wrap;
+}
+
+code {
+    background-color: #efefef;
+    padding: 0px 5px;
+}




diff --git a/rascunho/static/umbo.min.css b/rascunho/static/umbo.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..383623170d0ade7431eb41575f04ea77ff66e026
--- /dev/null
+++ b/rascunho/static/umbo.min.css
@@ -0,0 +1 @@
+html {line-height: 1.15;-webkit-text-size-adjust: 100%;}body {margin: 0;}main {display: block;}h1 {font-size: 2em;margin: 0.67em 0;}hr {box-sizing: content-box;height: 0;overflow: visible;}pre {font-family: monospace, monospace;font-size: 1em;}a {background-color: transparent;}abbr[title] {border-bottom: none;text-decoration: underline;text-decoration: underline dotted;}b,strong {font-weight: bolder;}code,kbd,samp {font-family: monospace, monospace;font-size: 1em;}small {font-size: 80%;}sub,sup {font-size: 75%;line-height: 0;position: relative;vertical-align: baseline;}sub {bottom: -0.25em;}sup {top: -0.5em;}img {border-style: none;}button,input,optgroup,select,textarea {font-family: inherit;font-size: 100%;line-height: 1.15;margin: 0;}button,input {overflow: visible;}button,select {text-transform: none;}button,[type="button"],[type="reset"],[type="submit"] {-webkit-appearance: button;}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner {border-style: none;padding: 0;}button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring {outline: 1px dotted ButtonText;}fieldset {padding: 0.35em 0.75em 0.625em;}legend {box-sizing: border-box;color: inherit;display: table;max-width: 100%;padding: 0;white-space: normal;}progress {vertical-align: baseline;}textarea {overflow: auto;}[type="checkbox"],[type="radio"] {box-sizing: border-box;padding: 0;}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button {height: auto;}[type="search"] {-webkit-appearance: textfield;outline-offset: -2px;}[type="search"]::-webkit-search-decoration {-webkit-appearance: none;}::-webkit-file-upload-button {-webkit-appearance: button;font: inherit;}details {display: block;}summary {display: list-item;}template {display: none;}[hidden] {display: none;}*, ::after, ::before {box-sizing: border-box;}body {font-family: Roboto, "Helvetica Neue", "San Francisco", "Open Sans", Arial, sans-serif;font-size: 1.1875rem;text-rendering: optimizeLegibility;line-height: 1.31579;}h1, .heading-xl {font-size: 3rem;}h2, .heading-l {font-size: 2.25rem;}h3, .heading-m {font-size: 1.5rem;}h4, .heading-s {font-size: 1.1875rem;}a {color: #1d70b8;}a:hover {color: #003078;}a:active {color: #336752;outline: 3px solid transparent;background-color: #33fe96;text-decoration: none;box-shadow: 0 -2px #33fe96,0 4px #0b0c0c;}ul, ol {font-size: 1.1875rem;line-height: 1.31579;}.umbo-table {width: 100%;border-spacing: 0;border-collapse: collapse;}.umbo-caption {font-weight: 700;display: table-caption;text-align: left;}.umbo-table-header, .umbo-table-cell {padding: 10px 20px 10px 0;border-bottom: 1px solid #b1b4b6;text-align: left;vertical-align: top;}.umbo-table-header-numeric, .umbo-table-cell-numeric {text-align: right;}.umbo-table-header {font-weight: 700;}.umbo-table-cell-numeric {font-feature-settings: normal;font-variant-numeric: tabular-nums;}.container {box-sizing: border-box;margin-left: auto;margin-right: auto;padding-right: 8px;padding-left: 8px;}.container-fluid {padding-right: 16px;padding-left: 16px;}@media only screen and (min-width: 576px) {.container {width: 560px;max-width: 100%;}}@media only screen and (min-width: 768px) {.container {width: 752px;max-width: 100%;}}@media only screen and (min-width: 992px) {.container {width: 976px;max-width: 100%;}}@media only screen and (min-width: 1200px) {.container {width: 1184px;max-width: 100%;}}.row {box-sizing: border-box;display: -webkit-box;display: -ms-flexbox;display: flex;-webkit-box-flex: 0;-ms-flex: 0 1 auto;flex: 0 1 auto;-webkit-box-orient: horizontal;-webkit-box-direction: normal;-ms-flex-direction: row;flex-direction: row;-ms-flex-wrap: wrap;flex-wrap: wrap;margin-right: -8px;margin-left: -8px;}.row.reverse {-webkit-box-orient: horizontal;-webkit-box-direction: reverse;-ms-flex-direction: row-reverse;flex-direction: row-reverse;}.col.reverse {-webkit-box-orient: vertical;-webkit-box-direction: reverse;-ms-flex-direction: column-reverse;flex-direction: column-reverse;}.col-xs,.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-offset-0,.col-xs-offset-1,.col-xs-offset-2,.col-xs-offset-3,.col-xs-offset-4,.col-xs-offset-5,.col-xs-offset-6,.col-xs-offset-7,.col-xs-offset-8,.col-xs-offset-9,.col-xs-offset-10,.col-xs-offset-11,.col-xs-offset-12,.col-sm,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-offset-0,.col-sm-offset-1,.col-sm-offset-2,.col-sm-offset-3,.col-sm-offset-4,.col-sm-offset-5,.col-sm-offset-6,.col-sm-offset-7,.col-sm-offset-8,.col-sm-offset-9,.col-sm-offset-10,.col-sm-offset-11,.col-sm-offset-12,.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-md-offset-0,.col-md-offset-1,.col-md-offset-2,.col-md-offset-3,.col-md-offset-4,.col-md-offset-5,.col-md-offset-6,.col-md-offset-7,.col-md-offset-8,.col-md-offset-9,.col-md-offset-10,.col-md-offset-11,.col-md-offset-12,.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-offset-0,.col-lg-offset-1,.col-lg-offset-2,.col-lg-offset-3,.col-lg-offset-4,.col-lg-offset-5,.col-lg-offset-6,.col-lg-offset-7,.col-lg-offset-8,.col-lg-offset-9,.col-lg-offset-10,.col-lg-offset-11,.col-lg-offset-12,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-offset-0,.col-xl-offset-1,.col-xl-offset-2,.col-xl-offset-3,.col-xl-offset-4,.col-xl-offset-5,.col-xl-offset-6,.col-xl-offset-7,.col-xl-offset-8,.col-xl-offset-9,.col-xl-offset-10,.col-xl-offset-11,.col-xl-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;-ms-flex-preferred-size: 100%;flex-basis: 100%;padding-right: 8px;padding-left: 8px;max-width: 100%;}.col-xs {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-xs-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-xs-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-xs-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-xs-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-xs-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-xs-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-xs-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-xs-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-xs-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-xs-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-xs-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-xs-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-xs-offset-0 {margin-left: 0;}.col-xs-offset-1 {margin-left: 8.33333333%;}.col-xs-offset-2 {margin-left: 16.66666667%;}.col-xs-offset-3 {margin-left: 25%;}.col-xs-offset-4 {margin-left: 33.33333333%;}.col-xs-offset-5 {margin-left: 41.66666667%;}.col-xs-offset-6 {margin-left: 50%;}.col-xs-offset-7 {margin-left: 58.33333333%;}.col-xs-offset-8 {margin-left: 66.66666667%;}.col-xs-offset-9 {margin-left: 75%;}.col-xs-offset-10 {margin-left: 83.33333333%;}.col-xs-offset-11 {margin-left: 91.66666667%;}.start-xs {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-xs {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-xs {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-xs {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-xs {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-xs {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-xs {-ms-flex-pack: distribute;justify-content: space-around;}.between-xs {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-xs {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-xs {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-xs {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}@media only screen and (min-width: 576px) {.col-sm {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-sm-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-sm-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-sm-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-sm-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-sm-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-sm-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-sm-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-sm-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-sm-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-sm-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-sm-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-sm-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-sm-offset-0 {margin-left: 0;}.col-sm-offset-1 {margin-left: 8.33333333%;}.col-sm-offset-2 {margin-left: 16.66666667%;}.col-sm-offset-3 {margin-left: 25%;}.col-sm-offset-4 {margin-left: 33.33333333%;}.col-sm-offset-5 {margin-left: 41.66666667%;}.col-sm-offset-6 {margin-left: 50%;}.col-sm-offset-7 {margin-left: 58.33333333%;}.col-sm-offset-8 {margin-left: 66.66666667%;}.col-sm-offset-9 {margin-left: 75%;}.col-sm-offset-10 {margin-left: 83.33333333%;}.col-sm-offset-11 {margin-left: 91.66666667%;}.start-sm {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-sm {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-sm {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-sm {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-sm {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-sm {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-sm {-ms-flex-pack: distribute;justify-content: space-around;}.between-sm {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-sm {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-sm {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-sm {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (min-width: 768px) {.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-md-offset-0,.col-md-offset-1,.col-md-offset-2,.col-md-offset-3,.col-md-offset-4,.col-md-offset-5,.col-md-offset-6,.col-md-offset-7,.col-md-offset-8,.col-md-offset-9,.col-md-offset-10,.col-md-offset-11,.col-md-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;padding-right: 8px;padding-left: 8px;}.col-md {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-md-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-md-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-md-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-md-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-md-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-md-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-md-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-md-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-md-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-md-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-md-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-md-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-md-offset-0 {margin-left: 0;}.col-md-offset-1 {margin-left: 8.33333333%;}.col-md-offset-2 {margin-left: 16.66666667%;}.col-md-offset-3 {margin-left: 25%;}.col-md-offset-4 {margin-left: 33.33333333%;}.col-md-offset-5 {margin-left: 41.66666667%;}.col-md-offset-6 {margin-left: 50%;}.col-md-offset-7 {margin-left: 58.33333333%;}.col-md-offset-8 {margin-left: 66.66666667%;}.col-md-offset-9 {margin-left: 75%;}.col-md-offset-10 {margin-left: 83.33333333%;}.col-md-offset-11 {margin-left: 91.66666667%;}.start-md {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-md {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-md {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-md {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-md {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-md {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-md {-ms-flex-pack: distribute;justify-content: space-around;}.between-md {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-md {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-md {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-md {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (min-width: 992px) {.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-offset-0,.col-lg-offset-1,.col-lg-offset-2,.col-lg-offset-3,.col-lg-offset-4,.col-lg-offset-5,.col-lg-offset-6,.col-lg-offset-7,.col-lg-offset-8,.col-lg-offset-9,.col-lg-offset-10,.col-lg-offset-11,.col-lg-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;padding-right: 8px;padding-left: 8px;}.col-lg {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-lg-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-lg-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-lg-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-lg-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-lg-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-lg-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-lg-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-lg-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-lg-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-lg-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-lg-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-lg-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-lg-offset-0 {margin-left: 0;}.col-lg-offset-1 {margin-left: 8.33333333%;}.col-lg-offset-2 {margin-left: 16.66666667%;}.col-lg-offset-3 {margin-left: 25%;}.col-lg-offset-4 {margin-left: 33.33333333%;}.col-lg-offset-5 {margin-left: 41.66666667%;}.col-lg-offset-6 {margin-left: 50%;}.col-lg-offset-7 {margin-left: 58.33333333%;}.col-lg-offset-8 {margin-left: 66.66666667%;}.col-lg-offset-9 {margin-left: 75%;}.col-lg-offset-10 {margin-left: 83.33333333%;}.col-lg-offset-11 {margin-left: 91.66666667%;}.start-lg {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-lg {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-lg {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-lg {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-lg {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-lg {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-lg {-ms-flex-pack: distribute;justify-content: space-around;}.between-lg {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-lg {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-lg {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-lg {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (min-width: 1200px) {.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-offset-0,.col-xl-offset-1,.col-xl-offset-2,.col-xl-offset-3,.col-xl-offset-4,.col-xl-offset-5,.col-xl-offset-6,.col-xl-offset-7,.col-xl-offset-8,.col-xl-offset-9,.col-xl-offset-10,.col-xl-offset-11,.col-xl-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;padding-right: 8px;padding-left: 8px;}.col-xl {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-xl-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-xl-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-xl-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-xl-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-xl-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-xl-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-xl-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-xl-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-xl-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-xl-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-xl-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-xl-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-xl-offset-0 {margin-left: 0;}.col-xl-offset-1 {margin-left: 8.33333333%;}.col-xl-offset-2 {margin-left: 16.66666667%;}.col-xl-offset-3 {margin-left: 25%;}.col-xl-offset-4 {margin-left: 33.33333333%;}.col-xl-offset-5 {margin-left: 41.66666667%;}.col-xl-offset-6 {margin-left: 50%;}.col-xl-offset-7 {margin-left: 58.33333333%;}.col-xl-offset-8 {margin-left: 66.66666667%;}.col-xl-offset-9 {margin-left: 75%;}.col-xl-offset-10 {margin-left: 83.33333333%;}.col-xl-offset-11 {margin-left: 91.66666667%;}.start-xl {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-xl {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-xl {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-xl {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-xl {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-xl {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-xl {-ms-flex-pack: distribute;justify-content: space-around;}.between-xl {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-xl {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-xl {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-xl {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (max-width: 575px) {.hidden-xs {display: none;}}@media only screen and (min-width: 576px) and (max-width: 767px) {.hidden-sm {display: none;}}@media only screen and (min-width: 768px) and (max-width: 991px) {.hidden-md {display: none;}}@media only screen and (min-width: 992px) and (max-width: 1199px) {.hidden-lg {display: none;}}@media only screen and (min-width: 1200px) {.hidden-xl {display: none;}}.umbo-fieldset {min-width: 0;margin: 0;padding: 0;border: 0;}.umbo-fieldset-legend {margin-bottom: 5px;}.umbo-form-group {display: block;margin-bottom: 30px;}.umbo-label {display: block;font-size: 1rem;font-weight: 400;margin-bottom: 5px;}.umbo-input {font-size: 1rem;line-height: 1.5;padding: .25rem .375rem;height: 2.5rem;border-color: #888;}.umbo-input:focus {outline: 3px solid #33fe96;outline-offset: 0;border: 1px solid #0b0c0c;box-shadow: inset 0px 0px 0px 2px;}.umbo-form-actions {display: inline-block;}.umbo-input-full-width {width: 100%;}.umbo-input-large {width: 75%;}.umbo-input-medium {width: 50%;}.umbo-input-small {width: 25%;}.umbo-input-xsmall {width: 10%;}
\ No newline at end of file




diff --git a/rascunho/templates/index.html b/rascunho/templates/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..58f7a3d1d3ccc6a082e675d35ecbbdf7ca6ddf54
--- /dev/null
+++ b/rascunho/templates/index.html
@@ -0,0 +1,19 @@
+{% extends 'layout.html' %}
+
+{% block body %}
+	<div class="row">
+		<div class="col-xs">
+			{{ doc.content | md | safe }}
+		</div>
+	</div>
+
+	<div class="row box">
+		<div class="col-xs">
+			<form method="POST" action="/" class="public-box">
+				<textarea name="text" cols="72" rows="30" placeholder="Escreva aqui"></textarea>
+				<br />
+				<button type="submit">Enviar</button>
+			</form>
+		</div>
+	</div>
+{% endblock %}




diff --git a/rascunho/templates/internal_server.html b/rascunho/templates/internal_server.html
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
Binary files /dev/null and b/rascunho/templates/internal_server.html differ




diff --git a/rascunho/templates/layout.html b/rascunho/templates/layout.html
new file mode 100644
index 0000000000000000000000000000000000000000..3503a71a1648076a7de6ef7334a9b59df0a30ed4
--- /dev/null
+++ b/rascunho/templates/layout.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>Rascunho - Prévia de Markdown</title>
+		<meta name="viewport" content="width=device-width, initial-scale=1" />
+		<link href="/static/umbo.min.css" rel="stylesheet" />
+		<link href="/static/rascunho.css" rel="stylesheet" />
+	</head>
+
+	<body>
+		<div class="container py">
+			{% block body %}
+			{% endblock %}
+		</div>
+	</body>
+</html>
+




diff --git a/rascunho/templates/not_found.html b/rascunho/templates/not_found.html
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
Binary files /dev/null and b/rascunho/templates/not_found.html differ




diff --git a/rascunho/templates/preview.html b/rascunho/templates/preview.html
new file mode 100644
index 0000000000000000000000000000000000000000..207bf8599bb51a2c03f1da875f558ad92afbefd8
--- /dev/null
+++ b/rascunho/templates/preview.html
@@ -0,0 +1,31 @@
+{% extends 'layout.html' %}
+
+{% block body %}
+	<div class="row">
+		<div class="col-xs">
+			{{ doc.content | md | safe }}
+		</div>
+	</div>
+
+	<div class="row">
+		<div class="col-xs">
+			<details>
+				<summary>Informações sobre este rascunho</summary>
+				<div class="box text-muted">
+					<ul>
+						<li>
+							Identificador: {{ doc.sha }}
+						</li>
+						<li>
+							Criado há: {{ doc.created_at | human_date | safe }}
+						</li>
+						<li>
+							<a href="/{{doc.sha}}/raw">Ver arquivo puro</a>
+						</li>
+					</ul>
+				</div>
+			</details>
+		</div>
+	</div>
+
+{% endblock %}




diff --git a/rascunho/templates/unprocessable_entity.html b/rascunho/templates/unprocessable_entity.html
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
Binary files /dev/null and b/rascunho/templates/unprocessable_entity.html differ




diff --git a/rascunho/types/__init__.py b/rascunho/types/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..9c01ea2470e408389a5b947f4247f87ecd21a81d
--- /dev/null
+++ b/rascunho/types/__init__.py
@@ -0,0 +1 @@
+from . import document




diff --git a/rascunho/types/document.py b/rascunho/types/document.py
new file mode 100644
index 0000000000000000000000000000000000000000..51556c2fc4a6ef93a0220f4709b79b740b09346d
--- /dev/null
+++ b/rascunho/types/document.py
@@ -0,0 +1,20 @@
+import sqlalchemy as sa
+from rascunho.database import Base
+
+class Document(Base):
+    __tablename__ = 'documents'
+
+    id = sa.Column(sa.Integer, primary_key=True)
+    sha = sa.Column(sa.String(40), nullable=False, index=True)
+    content = sa.Column(sa.Unicode, nullable=False)
+
+    created_at = sa.Column(sa.DateTime, nullable=False)
+    updated_at = sa.Column(sa.DateTime, nullable=False)
+
+    def to_dict(self):
+        return {
+            "sha": self.sha,
+            "content": self.content,
+            "created_at": self.created_at,
+            "updated_at": self.updated_at
+        }