diff --git a/loginapp/main.py b/loginapp/main.py index c6af88b2b..1f1c8a943 100644 --- a/loginapp/main.py +++ b/loginapp/main.py @@ -56,4 +56,4 @@ def uploadme(): @main.route('/profile') @login_required def profile(): - return render_template('profile.html', name=current_user.name) \ No newline at end of file + return render_template('profile.html', name=current_user.name) \ No newline at end of file diff --git a/loginapp/templates/upload.html b/loginapp/templates/upload.html index 18e8c2678..67bbbf258 100644 --- a/loginapp/templates/upload.html +++ b/loginapp/templates/upload.html @@ -17,6 +17,9 @@
+
+ +
diff --git a/microblog/.flaskenv b/microblog-project/flask1/.flaskenv
similarity index 100%
rename from microblog/.flaskenv
rename to microblog-project/flask1/.flaskenv
diff --git a/microblog/.gitattributes b/microblog-project/flask1/.gitattributes
similarity index 100%
rename from microblog/.gitattributes
rename to microblog-project/flask1/.gitattributes
diff --git a/microblog/.gitignore b/microblog-project/flask1/.gitignore
similarity index 100%
rename from microblog/.gitignore
rename to microblog-project/flask1/.gitignore
diff --git a/microblog-project/flask1/.vscode/settings.json b/microblog-project/flask1/.vscode/settings.json
new file mode 100644
index 000000000..7709bc616
--- /dev/null
+++ b/microblog-project/flask1/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "jira-plugin.workingProject": ""
+}
\ No newline at end of file
diff --git a/microblog-project/flask1/CNAME.md b/microblog-project/flask1/CNAME.md
new file mode 100644
index 000000000..f2f4222a9
--- /dev/null
+++ b/microblog-project/flask1/CNAME.md
@@ -0,0 +1 @@
+flask.skinetics.tech
diff --git a/microblog/LICENSE b/microblog-project/flask1/LICENSE
similarity index 100%
rename from microblog/LICENSE
rename to microblog-project/flask1/LICENSE
diff --git a/microblog-project/flask1/README.md b/microblog-project/flask1/README.md
new file mode 100644
index 000000000..6d4b587b1
--- /dev/null
+++ b/microblog-project/flask1/README.md
@@ -0,0 +1,20 @@
+# flask1
+Flask web app testing - with user authentication and front end posting
+
+[ParentRepo](https://github.com/acord-robotics/datascience)
+
+List of python libraries:
+* Flask
+* Flask-wtf
+* Flask-migrate
+* Flask-sqlalchemy
+* Flask-login
+
+E.g.
+```
+pip install flask
+```
+
+# Commit reference guide
+* GHC = Github Codespaces
+* Venv = `root/microblog` (in root, or main/parent directory) - virtual environment with the above libraries installed
\ No newline at end of file
diff --git a/microblog-project/flask1/app/__init__.py b/microblog-project/flask1/app/__init__.py
new file mode 100644
index 000000000..92c769114
--- /dev/null
+++ b/microblog-project/flask1/app/__init__.py
@@ -0,0 +1,44 @@
+import logging
+from logging.handlers import SMTPHandler, RotatingFileHandler
+import os
+from flask import Flask
+from flask_sqlalchemy import SQLAlchemy
+from flask_migrate import Migrate
+from flask_login import LoginManager
+from config import Config
+#from app import routes, models, errors
+
+app = Flask(__name__)
+app.config.from_object(Config)
+db = SQLAlchemy(app)
+migrate = Migrate(app, db)
+login = LoginManager(app)
+login.login_view = 'login'
+
+if not app.debug: # Only enable the email logger when the app is running without debug mode
+ if app.config['MAIL_SERVER']:
+ auth = None
+ if app.config['MAIL_USERNAME'] or app.config['MAIL_PASSWORD']:
+ auth = (app.config['MAIL_USERNAME'], app/config['MAIL_PASSWORD'])
+ secure = None
+ if app.config['MAIL_USE_TLS']:
+ secure = ()
+ mail_handler = SMTPHandler(
+ mailhost=(app.config['MAIL_SERVER'], app.config['MAIL_PORT']),
+ fromaddr='no-reply@' + app.config['MAIL_SERVER'],
+ toaddrs=app.config['ADMINS'], subject='Microblog Failure',
+ credentials=auth, secure=secure)
+ mail_handler.setLevel(logging.ERROR)
+ app.logger.addHandler(mail_handler)
+
+ if not os.path.exists('logs'):
+ os.mkdir('logs') # create logs directory if it doesn't exist using os library
+ file_handler = RotatingFileHandler('logs/microblog.log', maxBytes=10240,
+ backupCount=10)
+ file_handler.setFormatter(logging.Formatter(
+ '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))
+ file_handler.setLevel(logging.INFO)
+ app.logger.addHandler(file_handler)
+
+ app.logger.setLevel(logging.INFO)
+ app.logger.info('Microblog startup')
\ No newline at end of file
diff --git a/microblog-project/flask1/app/errors.py b/microblog-project/flask1/app/errors.py
new file mode 100644
index 000000000..1fa9df992
--- /dev/null
+++ b/microblog-project/flask1/app/errors.py
@@ -0,0 +1,11 @@
+from flask import render_template
+from app import app, db
+
+@app.errorhandler(404)
+def not_found_error(error):
+ return render_template('404.html'), 404
+
+@app.errorhandler(500)
+def internal_error(error):
+ db.session.rollback()
+ return render_template('500.html'), 500
\ No newline at end of file
diff --git a/microblog-project/flask1/app/forms.py b/microblog-project/flask1/app/forms.py
new file mode 100644
index 000000000..5ec161da9
--- /dev/null
+++ b/microblog-project/flask1/app/forms.py
@@ -0,0 +1,36 @@
+from flask_wtf import FlaskForm
+from wtforms import StringField, PasswordField, BooleanField, SubmitField
+from wtforms.validators import DataRequired, Length
+from wtforms import StringField, TextAreaField, SubmitField
+
+
+class LoginForm(FlaskForm):
+ username = StringField('Username', validators=[DataRequired()])
+ password = PasswordField('Password', validators=[DataRequired()])
+ remember_me = BooleanField('Remember Me')
+ submit = SubmitField('Sign In')
+
+class EditProfileForm(FlaskForm):
+ username = StringField('Username', validators=[DataRequired()])
+ about_me = TextAreaField('About me', validators=[Length(min=0, max=140)])
+ submit = SubmitField('Submit')
+
+ def __init__(self, original_username, *args, **kwargs):
+ super(EditProfileForm, self).__init__(*args, **kwargs)
+ self.original_username = original_username
+
+ def validate_username(self, username):
+ if username.data != self.original_username:
+ user = User.query.filter_by(username=self.username.data).first()
+ if user is not None:
+ raise ValidationError('Please use a different username')
+
+# Integrating Followers with the Application - Part 8
+class EmptyForm(FlaskForm):
+ submit = SubmitField('Submit')
+
+# allow users to make their own posts
+class PostForm(FlaskForm):
+ post = TextAreaField('Say something', validators=[
+ DataRequired(), Length(min=1, max=140]) # The form must be completed with content and the length has to be within 1-140 characters
+ submit = SubmitField('Submit') # button labelled submit that links to db.commit()
\ No newline at end of file
diff --git a/microblog-project/flask1/app/models.py b/microblog-project/flask1/app/models.py
new file mode 100644
index 000000000..a23c0ad9a
--- /dev/null
+++ b/microblog-project/flask1/app/models.py
@@ -0,0 +1,76 @@
+from datetime import datetime
+from hashlib import md5
+from app import db, login
+from flask_login import UserMixin
+from werkzeug.security import generate_password_hash, check_password_hash
+
+
+followers = db.Table(
+ 'followers',
+ db.Column('follower_id', db.Integer, db.ForeignKey('user.id')),
+ db.Column('followed_id', db.Integer, db.ForeignKey('user.id'))
+)
+
+
+class User(UserMixin, db.Model):
+ id = db.Column(db.Integer, primary_key=True)
+ username = db.Column(db.String(64), index=True, unique=True)
+ email = db.Column(db.String(120), index=True, unique=True)
+ password_hash = db.Column(db.String(128))
+ posts = db.relationship('Post', backref='author', lazy='dynamic')
+ about_me = db.Column(db.String(140))
+ last_seen = db.Column(db.DateTime, default=datetime.utcnow)
+ followed = db.relationship(
+ 'User', secondary=followers,
+ primaryjoin=(followers.c.follower_id == id),
+ secondaryjoin=(followers.c.followed_id == id),
+ backref=db.backref('followers', lazy='dynamic'), lazy='dynamic')
+
+ def __repr__(self):
+ return ' The administrator has been notified. Sorry for the inconvenience!File Not Found
+
+{% endblock %}
\ No newline at end of file
diff --git a/microblog-project/flask1/app/templates/500.html b/microblog-project/flask1/app/templates/500.html
new file mode 100644
index 000000000..d641ad244
--- /dev/null
+++ b/microblog-project/flask1/app/templates/500.html
@@ -0,0 +1,7 @@
+{% extends "base.html" %}
+
+{% block content %}
+ An unexpected error has occured
+
+
diff --git a/microblog-project/flask1/app/templates/_profile.html b/microblog-project/flask1/app/templates/_profile.html
new file mode 100644
index 000000000..3d4cea226
--- /dev/null
+++ b/microblog-project/flask1/app/templates/_profile.html
@@ -0,0 +1,23 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+
+
+
+
+ {{ post.author.username }}
+
+ says:
+
{{ post.body }}
+ Edit Profile
+
+{% endblock %}
\ No newline at end of file
diff --git a/microblog-project/flask1/app/templates/base.html b/microblog-project/flask1/app/templates/base.html
new file mode 100644
index 000000000..026c6273b
--- /dev/null
+++ b/microblog-project/flask1/app/templates/base.html
@@ -0,0 +1,33 @@
+
+
+ {% if title %}
+
+ {% with messages = get_flashed_messages() %}
+ {% if messages %}
+
+ {% for message in messages %}
+
+ {% endif %}
+ {% endwith %}
+ {% block content %}{% endblock %}
+
+
diff --git a/microblog-project/flask1/app/templates/index.html b/microblog-project/flask1/app/templates/index.html
new file mode 100644
index 000000000..cf4f8052d
--- /dev/null
+++ b/microblog-project/flask1/app/templates/index.html
@@ -0,0 +1,27 @@
+{% extends "base.html" %}
+
+{% block content %}
+ Hi, {{ current_user.username }}!
+ {% if form %}
+
+ {% endif %}
+ {% for post in posts %}
+ {% include '_post.html' %}
+ {% endfor %}
+ {% if prev_url %}
+ Newer posts
+ {% endif %}
+ {% if next_url %}
+ Older posts
+ {% endif %}
+{% endblock %}
\ No newline at end of file
diff --git a/microblog-project/flask1/app/templates/login.html b/microblog-project/flask1/app/templates/login.html
new file mode 100644
index 000000000..806e09a6a
--- /dev/null
+++ b/microblog-project/flask1/app/templates/login.html
@@ -0,0 +1,24 @@
+{% extends "base.html" %}
+
+{% block content %}
+ Sign In
+
+{% endblock %}
diff --git a/microblog-project/flask1/app/templates/user.html b/microblog-project/flask1/app/templates/user.html
new file mode 100644
index 000000000..3ab2bdbaa
--- /dev/null
+++ b/microblog-project/flask1/app/templates/user.html
@@ -0,0 +1,25 @@
+{% extends "base.html" %}
+
+{% block content %}
+ Hi, {{ current_user.username }}!
+
+ {% for post in posts %}
+ {% include '_post.html' %}
+ {% endfor %}
+ {% if prev_url %}
+ Newer posts
+ {% endif %}
+ {% if next_url %}
+ Older posts
+ {% endif %}
+{% endblock %}
\ No newline at end of file
diff --git a/microblog-project/flask1/config.py b/microblog-project/flask1/config.py
new file mode 100644
index 000000000..b3cd65175
--- /dev/null
+++ b/microblog-project/flask1/config.py
@@ -0,0 +1,16 @@
+import os
+basedir = os.path.abspath(os.path.dirname(__file__))
+
+
+class Config(object):
+ SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
+ SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
+ 'sqlite:///' + os.path.join(basedir, 'app.db')
+ SQLALCHEMY_TRACK_MODIFICATIONS = False
+ MAIL_SERVER = os.environ.get('MAIL_SERVER')
+ MAIL_PORT = int(os.environ.get('MAIL_PORT') or 25)
+ MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None
+ MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
+ MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
+ ADMINS = ['liam@skinetics.tech']
+ POSTS_PER_PAGE = 25
\ No newline at end of file
diff --git a/microblog-project/flask1/microblog.py b/microblog-project/flask1/microblog.py
new file mode 100644
index 000000000..a96ac1664
--- /dev/null
+++ b/microblog-project/flask1/microblog.py
@@ -0,0 +1,7 @@
+from app import app, db
+from app.models import User, Post
+
+
+@app.shell_context_processor
+def make_shell_context():
+ return {'db': db, 'User': User, 'Post': Post}
\ No newline at end of file
diff --git a/microblog-project/flask1/microblog/pyvenv.cfg b/microblog-project/flask1/microblog/pyvenv.cfg
new file mode 100644
index 000000000..d2988223d
--- /dev/null
+++ b/microblog-project/flask1/microblog/pyvenv.cfg
@@ -0,0 +1,3 @@
+home = /opt/python/latest/bin
+include-system-site-packages = false
+version = 3.8.6
diff --git a/microblog/migrations/README b/microblog-project/flask1/migrations/README
old mode 100755
new mode 100644
similarity index 100%
rename from microblog/migrations/README
rename to microblog-project/flask1/migrations/README
diff --git a/microblog/migrations/alembic.ini b/microblog-project/flask1/migrations/alembic.ini
similarity index 100%
rename from microblog/migrations/alembic.ini
rename to microblog-project/flask1/migrations/alembic.ini
diff --git a/microblog-project/flask1/migrations/env.py b/microblog-project/flask1/migrations/env.py
new file mode 100644
index 000000000..8b3fb3353
--- /dev/null
+++ b/microblog-project/flask1/migrations/env.py
@@ -0,0 +1,96 @@
+from __future__ import with_statement
+
+import logging
+from logging.config import fileConfig
+
+from sqlalchemy import engine_from_config
+from sqlalchemy import pool
+from flask import current_app
+
+from alembic import context
+
+# this is the Alembic Config object, which provides
+# access to the values within the .ini file in use.
+config = context.config
+
+# Interpret the config file for Python logging.
+# This line sets up loggers basically.
+fileConfig(config.config_file_name)
+logger = logging.getLogger('alembic.env')
+
+# add your model's MetaData object here
+# for 'autogenerate' support
+# from myapp import mymodel
+# target_metadata = mymodel.Base.metadata
+config.set_main_option(
+ 'sqlalchemy.url',
+ str(current_app.extensions['migrate'].db.engine.url).replace('%', '%%'))
+target_metadata = current_app.extensions['migrate'].db.metadata
+
+# other values from the config, defined by the needs of env.py,
+# can be acquired:
+# my_important_option = config.get_main_option("my_important_option")
+# ... etc.
+
+
+def run_migrations_offline():
+ """Run migrations in 'offline' mode.
+
+ This configures the context with just a URL
+ and not an Engine, though an Engine is acceptable
+ here as well. By skipping the Engine creation
+ we don't even need a DBAPI to be available.
+
+ Calls to context.execute() here emit the given string to the
+ script output.
+
+ """
+ url = config.get_main_option("sqlalchemy.url")
+ context.configure(
+ url=url, target_metadata=target_metadata, literal_binds=True
+ )
+
+ with context.begin_transaction():
+ context.run_migrations()
+
+
+def run_migrations_online():
+ """Run migrations in 'online' mode.
+
+ In this scenario we need to create an Engine
+ and associate a connection with the context.
+
+ """
+
+ # this callback is used to prevent an auto-migration from being generated
+ # when there are no changes to the schema
+ # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
+ def process_revision_directives(context, revision, directives):
+ if getattr(config.cmd_opts, 'autogenerate', False):
+ script = directives[0]
+ if script.upgrade_ops.is_empty():
+ directives[:] = []
+ logger.info('No changes in schema detected.')
+
+ connectable = engine_from_config(
+ config.get_section(config.config_ini_section),
+ prefix='sqlalchemy.',
+ poolclass=pool.NullPool,
+ )
+
+ with connectable.connect() as connection:
+ context.configure(
+ connection=connection,
+ target_metadata=target_metadata,
+ process_revision_directives=process_revision_directives,
+ **current_app.extensions['migrate'].configure_args
+ )
+
+ with context.begin_transaction():
+ context.run_migrations()
+
+
+if context.is_offline_mode():
+ run_migrations_offline()
+else:
+ run_migrations_online()
diff --git a/microblog/migrations/script.py.mako b/microblog-project/flask1/migrations/script.py.mako
old mode 100755
new mode 100644
similarity index 100%
rename from microblog/migrations/script.py.mako
rename to microblog-project/flask1/migrations/script.py.mako
diff --git a/microblog-project/flask1/migrations/versions/76c86cb9832b_followers.py b/microblog-project/flask1/migrations/versions/76c86cb9832b_followers.py
new file mode 100644
index 000000000..67a4bcb2e
--- /dev/null
+++ b/microblog-project/flask1/migrations/versions/76c86cb9832b_followers.py
@@ -0,0 +1,33 @@
+"""followers
+
+Revision ID: 76c86cb9832b
+Revises: eb54505e6fb3
+Create Date: 2021-02-16 02:07:28.243603
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = '76c86cb9832b'
+down_revision = 'eb54505e6fb3'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('followers',
+ sa.Column('follower_id', sa.Integer(), nullable=True),
+ sa.Column('followed_id', sa.Integer(), nullable=True),
+ sa.ForeignKeyConstraint(['followed_id'], ['user.id'], ),
+ sa.ForeignKeyConstraint(['follower_id'], ['user.id'], )
+ )
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_table('followers')
+ # ### end Alembic commands ###
diff --git a/microblog-project/flask1/migrations/versions/eb54505e6fb3_users_table.py b/microblog-project/flask1/migrations/versions/eb54505e6fb3_users_table.py
new file mode 100644
index 000000000..7fac0b74f
--- /dev/null
+++ b/microblog-project/flask1/migrations/versions/eb54505e6fb3_users_table.py
@@ -0,0 +1,51 @@
+"""users table
+
+Revision ID: eb54505e6fb3
+Revises:
+Create Date: 2021-02-14 04:08:38.638686
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = 'eb54505e6fb3'
+down_revision = None
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('user',
+ sa.Column('id', sa.Integer(), nullable=False),
+ sa.Column('username', sa.String(length=64), nullable=True),
+ sa.Column('email', sa.String(length=120), nullable=True),
+ sa.Column('password_hash', sa.String(length=128), nullable=True),
+ sa.Column('about_me', sa.String(length=140), nullable=True),
+ sa.Column('last_seen', sa.DateTime(), nullable=True),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_user_email'), 'user', ['email'], unique=True)
+ op.create_index(op.f('ix_user_username'), 'user', ['username'], unique=True)
+ op.create_table('post',
+ sa.Column('id', sa.Integer(), nullable=False),
+ sa.Column('body', sa.String(length=140), nullable=True),
+ sa.Column('timestamp', sa.DateTime(), nullable=True),
+ sa.Column('user_id', sa.Integer(), nullable=True),
+ sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_post_timestamp'), 'post', ['timestamp'], unique=False)
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_index(op.f('ix_post_timestamp'), table_name='post')
+ op.drop_table('post')
+ op.drop_index(op.f('ix_user_username'), table_name='user')
+ op.drop_index(op.f('ix_user_email'), table_name='user')
+ op.drop_table('user')
+ # ### end Alembic commands ###
diff --git a/microblog-project/flask1/tests.py b/microblog-project/flask1/tests.py
new file mode 100644
index 000000000..8afaf88c1
--- /dev/null
+++ b/microblog-project/flask1/tests.py
@@ -0,0 +1,89 @@
+from datetime import datetime, timedelta
+import unittest
+from app import app, db
+from app.models import User, Post
+
+class UserModelCase(unittest.TestCase):
+ def setUp(self):
+ app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
+ db.create_all()
+
+ def tearDown(self):
+ db.session.remove()
+ db.drop_all()
+
+ def test_password_hashing(self):
+ u = User(username='susan')
+ u.set_password('cat')
+ self.assertFalse(u.check_password('dog'))
+ self.assertTrue(u.check_password('cat'))
+
+ def test_avatar(self):
+ u = User(username='john', email='john@example.com')
+ self.assertEqual(u.avatar(128), ('https://www.gravatar.com/avatar/'
+ 'd4c74594d841139328695756648b6bd6'
+ '?d=identicon&s=128'))
+
+ def test_follow(self):
+ u1 = User(username='john', email='john@example.com')
+ u2 = User(username='susan', email='susan@example.com')
+ db.session.add(u1)
+ db.session.add(u2)
+ db.session.commit()
+ self.assertEqual(u1.followed.all(), [])
+ self.assertEqual(u1.followers.all(), [])
+
+ u1.follow(u2)
+ db.session.commit()
+ self.assertTrue(u1.is_following(u2))
+ self.assertEqual(u1.followed.count(), 1)
+ self.assertEqual(u1.followed.first().username, 'susan')
+ self.assertEqual(u2.followers.count(), 1)
+ self.assertEqual(u2.followers.first().username, 'john')
+
+ u1.unfollow(u2)
+ db.session.commit()
+ self.assertFalse(u1.is_following(u2))
+ self.assertEqual(u1.followed.count(), 0)
+ self.assertEqual(u2.followers.count(), 0)
+
+ def test_follow_posts(self):
+ # create four users
+ u1 = User(username='john', email='john@example.com')
+ u2 = User(username='susan', email='susan@example.com')
+ u3 = User(username='mary', email='mary@example.com')
+ u4 = User(username='david', email='david@example.com')
+ db.session.add_all([u1, u2, u3, u4])
+
+ # create four posts
+ now = datetime.utcnow()
+ p1 = Post(body="post from john", author=u1,
+ timestamp=now + timedelta(seconds=1))
+ p2 = Post(body="post from susan", author=u2,
+ timestamp=now + timedelta(seconds=4))
+ p3 = Post(body="post from mary", author=u3,
+ timestamp=now + timedelta(seconds=3))
+ p4 = Post(body="post from david", author=u4,
+ timestamp=now + timedelta(seconds=2))
+ db.session.add_all([p1, p2, p3, p4])
+ db.session.commit()
+
+ # setup the followers
+ u1.follow(u2) # john follows susan
+ u1.follow(u4) # john follows david
+ u2.follow(u3) # susan follows mary
+ u3.follow(u4) # mary follows david
+ db.session.commit()
+
+ # check the followed posts of each user
+ f1 = u1.followed_posts().all()
+ f2 = u2.followed_posts().all()
+ f3 = u3.followed_posts().all()
+ f4 = u4.followed_posts().all()
+ self.assertEqual(f1, [p2, p4, p1])
+ self.assertEqual(f2, [p2, p3])
+ self.assertEqual(f3, [p3, p4])
+ self.assertEqual(f4, [p4])
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
\ No newline at end of file
diff --git a/microblog-project/microblog-23-api/.flaskenv b/microblog-project/microblog-23-api/.flaskenv
new file mode 100644
index 000000000..6006c26dc
--- /dev/null
+++ b/microblog-project/microblog-23-api/.flaskenv
@@ -0,0 +1 @@
+FLASK_APP=microblog.py
diff --git a/microblog-project/microblog-23-api/.gitattributes b/microblog-project/microblog-23-api/.gitattributes
new file mode 100644
index 000000000..efdba8764
--- /dev/null
+++ b/microblog-project/microblog-23-api/.gitattributes
@@ -0,0 +1,2 @@
+* text=auto
+*.sh text eol=lf
diff --git a/microblog-project/microblog-23-api/.gitignore b/microblog-project/microblog-23-api/.gitignore
new file mode 100644
index 000000000..1e4f83607
--- /dev/null
+++ b/microblog-project/microblog-23-api/.gitignore
@@ -0,0 +1,40 @@
+*.py[cod]
+
+# C extensions
+*.so
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+eggs
+parts
+bin
+var
+sdist
+develop-eggs
+.installed.cfg
+lib
+lib64
+__pycache__
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+nosetests.xml
+
+# Translations
+*.mo
+
+# Mr Developer
+.mr.developer.cfg
+.project
+.pydevproject
+
+venv
+app.db
+microblog.log*
diff --git a/microblog/Dockerfile b/microblog-project/microblog-23-api/Dockerfile
similarity index 100%
rename from microblog/Dockerfile
rename to microblog-project/microblog-23-api/Dockerfile
diff --git a/microblog-project/microblog-23-api/LICENSE b/microblog-project/microblog-23-api/LICENSE
new file mode 100644
index 000000000..62e77cb45
--- /dev/null
+++ b/microblog-project/microblog-23-api/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 Miguel Grinberg
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/microblog/Procfile b/microblog-project/microblog-23-api/Procfile
similarity index 100%
rename from microblog/Procfile
rename to microblog-project/microblog-23-api/Procfile
diff --git a/microblog/README.md b/microblog-project/microblog-23-api/README.md
similarity index 100%
rename from microblog/README.md
rename to microblog-project/microblog-23-api/README.md
diff --git a/microblog/Vagrantfile b/microblog-project/microblog-23-api/Vagrantfile
similarity index 100%
rename from microblog/Vagrantfile
rename to microblog-project/microblog-23-api/Vagrantfile
diff --git a/microblog/app/__init__.py b/microblog-project/microblog-23-api/app/__init__.py
similarity index 100%
rename from microblog/app/__init__.py
rename to microblog-project/microblog-23-api/app/__init__.py
diff --git a/microblog/app/api/__init__.py b/microblog-project/microblog-23-api/app/api/__init__.py
similarity index 100%
rename from microblog/app/api/__init__.py
rename to microblog-project/microblog-23-api/app/api/__init__.py
diff --git a/microblog/app/api/auth.py b/microblog-project/microblog-23-api/app/api/auth.py
similarity index 100%
rename from microblog/app/api/auth.py
rename to microblog-project/microblog-23-api/app/api/auth.py
diff --git a/microblog/app/api/errors.py b/microblog-project/microblog-23-api/app/api/errors.py
similarity index 100%
rename from microblog/app/api/errors.py
rename to microblog-project/microblog-23-api/app/api/errors.py
diff --git a/microblog/app/api/tokens.py b/microblog-project/microblog-23-api/app/api/tokens.py
similarity index 100%
rename from microblog/app/api/tokens.py
rename to microblog-project/microblog-23-api/app/api/tokens.py
diff --git a/microblog/app/api/users.py b/microblog-project/microblog-23-api/app/api/users.py
similarity index 100%
rename from microblog/app/api/users.py
rename to microblog-project/microblog-23-api/app/api/users.py
diff --git a/microblog/app/auth/__init__.py b/microblog-project/microblog-23-api/app/auth/__init__.py
similarity index 100%
rename from microblog/app/auth/__init__.py
rename to microblog-project/microblog-23-api/app/auth/__init__.py
diff --git a/microblog/app/auth/email.py b/microblog-project/microblog-23-api/app/auth/email.py
similarity index 100%
rename from microblog/app/auth/email.py
rename to microblog-project/microblog-23-api/app/auth/email.py
diff --git a/microblog/app/auth/forms.py b/microblog-project/microblog-23-api/app/auth/forms.py
similarity index 100%
rename from microblog/app/auth/forms.py
rename to microblog-project/microblog-23-api/app/auth/forms.py
diff --git a/microblog/app/auth/routes.py b/microblog-project/microblog-23-api/app/auth/routes.py
similarity index 100%
rename from microblog/app/auth/routes.py
rename to microblog-project/microblog-23-api/app/auth/routes.py
diff --git a/microblog/app/cli.py b/microblog-project/microblog-23-api/app/cli.py
similarity index 100%
rename from microblog/app/cli.py
rename to microblog-project/microblog-23-api/app/cli.py
diff --git a/microblog/app/email.py b/microblog-project/microblog-23-api/app/email.py
similarity index 100%
rename from microblog/app/email.py
rename to microblog-project/microblog-23-api/app/email.py
diff --git a/microblog/app/errors/__init__.py b/microblog-project/microblog-23-api/app/errors/__init__.py
similarity index 100%
rename from microblog/app/errors/__init__.py
rename to microblog-project/microblog-23-api/app/errors/__init__.py
diff --git a/microblog/app/errors/handlers.py b/microblog-project/microblog-23-api/app/errors/handlers.py
similarity index 100%
rename from microblog/app/errors/handlers.py
rename to microblog-project/microblog-23-api/app/errors/handlers.py
diff --git a/microblog/app/main/__init__.py b/microblog-project/microblog-23-api/app/main/__init__.py
similarity index 100%
rename from microblog/app/main/__init__.py
rename to microblog-project/microblog-23-api/app/main/__init__.py
diff --git a/microblog/app/main/forms.py b/microblog-project/microblog-23-api/app/main/forms.py
similarity index 100%
rename from microblog/app/main/forms.py
rename to microblog-project/microblog-23-api/app/main/forms.py
diff --git a/microblog/app/main/routes.py b/microblog-project/microblog-23-api/app/main/routes.py
similarity index 100%
rename from microblog/app/main/routes.py
rename to microblog-project/microblog-23-api/app/main/routes.py
diff --git a/microblog/app/models.py b/microblog-project/microblog-23-api/app/models.py
similarity index 100%
rename from microblog/app/models.py
rename to microblog-project/microblog-23-api/app/models.py
diff --git a/microblog/app/search.py b/microblog-project/microblog-23-api/app/search.py
similarity index 100%
rename from microblog/app/search.py
rename to microblog-project/microblog-23-api/app/search.py
diff --git a/microblog/app/static/loading.gif b/microblog-project/microblog-23-api/app/static/loading.gif
similarity index 100%
rename from microblog/app/static/loading.gif
rename to microblog-project/microblog-23-api/app/static/loading.gif
diff --git a/microblog/app/static/styles.css b/microblog-project/microblog-23-api/app/static/styles.css
similarity index 100%
rename from microblog/app/static/styles.css
rename to microblog-project/microblog-23-api/app/static/styles.css
diff --git a/microblog/app/tasks.py b/microblog-project/microblog-23-api/app/tasks.py
similarity index 100%
rename from microblog/app/tasks.py
rename to microblog-project/microblog-23-api/app/tasks.py
diff --git a/microblog/app/templates/_post.html b/microblog-project/microblog-23-api/app/templates/_post.html
similarity index 100%
rename from microblog/app/templates/_post.html
rename to microblog-project/microblog-23-api/app/templates/_post.html
diff --git a/microblog/app/templates/auth/login.html b/microblog-project/microblog-23-api/app/templates/auth/login.html
similarity index 100%
rename from microblog/app/templates/auth/login.html
rename to microblog-project/microblog-23-api/app/templates/auth/login.html
diff --git a/microblog/app/templates/auth/register.html b/microblog-project/microblog-23-api/app/templates/auth/register.html
similarity index 100%
rename from microblog/app/templates/auth/register.html
rename to microblog-project/microblog-23-api/app/templates/auth/register.html
diff --git a/microblog/app/templates/auth/reset_password.html b/microblog-project/microblog-23-api/app/templates/auth/reset_password.html
similarity index 100%
rename from microblog/app/templates/auth/reset_password.html
rename to microblog-project/microblog-23-api/app/templates/auth/reset_password.html
diff --git a/microblog/app/templates/auth/reset_password_request.html b/microblog-project/microblog-23-api/app/templates/auth/reset_password_request.html
similarity index 100%
rename from microblog/app/templates/auth/reset_password_request.html
rename to microblog-project/microblog-23-api/app/templates/auth/reset_password_request.html
diff --git a/microblog/app/templates/base.html b/microblog-project/microblog-23-api/app/templates/base.html
similarity index 100%
rename from microblog/app/templates/base.html
rename to microblog-project/microblog-23-api/app/templates/base.html
diff --git a/microblog/app/templates/edit_profile.html b/microblog-project/microblog-23-api/app/templates/edit_profile.html
similarity index 100%
rename from microblog/app/templates/edit_profile.html
rename to microblog-project/microblog-23-api/app/templates/edit_profile.html
diff --git a/microblog/app/templates/email/export_posts.html b/microblog-project/microblog-23-api/app/templates/email/export_posts.html
similarity index 100%
rename from microblog/app/templates/email/export_posts.html
rename to microblog-project/microblog-23-api/app/templates/email/export_posts.html
diff --git a/microblog/app/templates/email/export_posts.txt b/microblog-project/microblog-23-api/app/templates/email/export_posts.txt
similarity index 100%
rename from microblog/app/templates/email/export_posts.txt
rename to microblog-project/microblog-23-api/app/templates/email/export_posts.txt
diff --git a/microblog/app/templates/email/reset_password.html b/microblog-project/microblog-23-api/app/templates/email/reset_password.html
similarity index 100%
rename from microblog/app/templates/email/reset_password.html
rename to microblog-project/microblog-23-api/app/templates/email/reset_password.html
diff --git a/microblog/app/templates/email/reset_password.txt b/microblog-project/microblog-23-api/app/templates/email/reset_password.txt
similarity index 100%
rename from microblog/app/templates/email/reset_password.txt
rename to microblog-project/microblog-23-api/app/templates/email/reset_password.txt
diff --git a/microblog/app/templates/errors/404.html b/microblog-project/microblog-23-api/app/templates/errors/404.html
similarity index 100%
rename from microblog/app/templates/errors/404.html
rename to microblog-project/microblog-23-api/app/templates/errors/404.html
diff --git a/microblog/app/templates/errors/500.html b/microblog-project/microblog-23-api/app/templates/errors/500.html
similarity index 100%
rename from microblog/app/templates/errors/500.html
rename to microblog-project/microblog-23-api/app/templates/errors/500.html
diff --git a/microblog/app/templates/hello.html b/microblog-project/microblog-23-api/app/templates/hello.html
similarity index 100%
rename from microblog/app/templates/hello.html
rename to microblog-project/microblog-23-api/app/templates/hello.html
diff --git a/microblog/app/templates/index.html b/microblog-project/microblog-23-api/app/templates/index.html
similarity index 100%
rename from microblog/app/templates/index.html
rename to microblog-project/microblog-23-api/app/templates/index.html
diff --git a/microblog/app/templates/messages.html b/microblog-project/microblog-23-api/app/templates/messages.html
similarity index 100%
rename from microblog/app/templates/messages.html
rename to microblog-project/microblog-23-api/app/templates/messages.html
diff --git a/microblog/app/templates/search.html b/microblog-project/microblog-23-api/app/templates/search.html
similarity index 100%
rename from microblog/app/templates/search.html
rename to microblog-project/microblog-23-api/app/templates/search.html
diff --git a/microblog/app/templates/send_message.html b/microblog-project/microblog-23-api/app/templates/send_message.html
similarity index 100%
rename from microblog/app/templates/send_message.html
rename to microblog-project/microblog-23-api/app/templates/send_message.html
diff --git a/microblog/app/templates/user.html b/microblog-project/microblog-23-api/app/templates/user.html
similarity index 100%
rename from microblog/app/templates/user.html
rename to microblog-project/microblog-23-api/app/templates/user.html
diff --git a/microblog/app/templates/user_popup.html b/microblog-project/microblog-23-api/app/templates/user_popup.html
similarity index 100%
rename from microblog/app/templates/user_popup.html
rename to microblog-project/microblog-23-api/app/templates/user_popup.html
diff --git a/microblog/app/translate.py b/microblog-project/microblog-23-api/app/translate.py
similarity index 100%
rename from microblog/app/translate.py
rename to microblog-project/microblog-23-api/app/translate.py
diff --git a/microblog/app/translations/es/LC_MESSAGES/messages.po b/microblog-project/microblog-23-api/app/translations/es/LC_MESSAGES/messages.po
similarity index 100%
rename from microblog/app/translations/es/LC_MESSAGES/messages.po
rename to microblog-project/microblog-23-api/app/translations/es/LC_MESSAGES/messages.po
diff --git a/microblog/babel.cfg b/microblog-project/microblog-23-api/babel.cfg
similarity index 100%
rename from microblog/babel.cfg
rename to microblog-project/microblog-23-api/babel.cfg
diff --git a/microblog/boot.sh b/microblog-project/microblog-23-api/boot.sh
similarity index 100%
rename from microblog/boot.sh
rename to microblog-project/microblog-23-api/boot.sh
diff --git a/microblog/config.py b/microblog-project/microblog-23-api/config.py
similarity index 100%
rename from microblog/config.py
rename to microblog-project/microblog-23-api/config.py
diff --git a/microblog/deployment/nginx/microblog b/microblog-project/microblog-23-api/deployment/nginx/microblog
similarity index 100%
rename from microblog/deployment/nginx/microblog
rename to microblog-project/microblog-23-api/deployment/nginx/microblog
diff --git a/microblog/deployment/supervisor/microblog-tasks.conf b/microblog-project/microblog-23-api/deployment/supervisor/microblog-tasks.conf
similarity index 100%
rename from microblog/deployment/supervisor/microblog-tasks.conf
rename to microblog-project/microblog-23-api/deployment/supervisor/microblog-tasks.conf
diff --git a/microblog/deployment/supervisor/microblog.conf b/microblog-project/microblog-23-api/deployment/supervisor/microblog.conf
similarity index 100%
rename from microblog/deployment/supervisor/microblog.conf
rename to microblog-project/microblog-23-api/deployment/supervisor/microblog.conf
diff --git a/microblog/microblog.py b/microblog-project/microblog-23-api/microblog.py
similarity index 100%
rename from microblog/microblog.py
rename to microblog-project/microblog-23-api/microblog.py
diff --git a/microblog/microvenv/pyvenv.cfg b/microblog-project/microblog-23-api/microvenv/pyvenv.cfg
similarity index 100%
rename from microblog/microvenv/pyvenv.cfg
rename to microblog-project/microblog-23-api/microvenv/pyvenv.cfg
diff --git a/microblog/microvenv/share/python-wheels/CacheControl-0.12.6-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/CacheControl-0.12.6-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/CacheControl-0.12.6-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/CacheControl-0.12.6-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/appdirs-1.4.3-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/appdirs-1.4.3-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/appdirs-1.4.3-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/appdirs-1.4.3-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/certifi-2019.11.28-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/certifi-2019.11.28-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/certifi-2019.11.28-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/certifi-2019.11.28-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/chardet-3.0.4-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/chardet-3.0.4-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/chardet-3.0.4-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/chardet-3.0.4-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/colorama-0.4.3-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/colorama-0.4.3-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/colorama-0.4.3-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/colorama-0.4.3-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/contextlib2-0.6.0-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/contextlib2-0.6.0-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/contextlib2-0.6.0-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/contextlib2-0.6.0-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/distlib-0.3.0-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/distlib-0.3.0-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/distlib-0.3.0-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/distlib-0.3.0-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/distro-1.4.0-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/distro-1.4.0-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/distro-1.4.0-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/distro-1.4.0-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/html5lib-1.0.1-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/html5lib-1.0.1-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/html5lib-1.0.1-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/html5lib-1.0.1-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/idna-2.8-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/idna-2.8-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/idna-2.8-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/idna-2.8-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/ipaddr-2.2.0-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/ipaddr-2.2.0-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/ipaddr-2.2.0-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/ipaddr-2.2.0-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/lockfile-0.12.2-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/lockfile-0.12.2-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/lockfile-0.12.2-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/lockfile-0.12.2-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/msgpack-0.6.2-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/msgpack-0.6.2-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/msgpack-0.6.2-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/msgpack-0.6.2-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/packaging-20.3-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/packaging-20.3-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/packaging-20.3-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/packaging-20.3-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/pep517-0.8.2-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/pep517-0.8.2-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/pep517-0.8.2-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/pep517-0.8.2-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/pip-20.0.2-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/pip-20.0.2-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/pip-20.0.2-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/pip-20.0.2-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/pkg_resources-0.0.0-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/pkg_resources-0.0.0-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/pkg_resources-0.0.0-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/pkg_resources-0.0.0-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/progress-1.5-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/progress-1.5-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/progress-1.5-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/progress-1.5-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/pyparsing-2.4.6-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/pyparsing-2.4.6-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/pyparsing-2.4.6-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/pyparsing-2.4.6-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/pytoml-0.1.21-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/pytoml-0.1.21-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/pytoml-0.1.21-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/pytoml-0.1.21-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/requests-2.22.0-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/requests-2.22.0-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/requests-2.22.0-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/requests-2.22.0-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/retrying-1.3.3-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/retrying-1.3.3-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/retrying-1.3.3-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/retrying-1.3.3-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/setuptools-44.0.0-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/setuptools-44.0.0-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/setuptools-44.0.0-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/setuptools-44.0.0-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/six-1.14.0-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/six-1.14.0-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/six-1.14.0-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/six-1.14.0-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/webencodings-0.5.1-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/webencodings-0.5.1-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/webencodings-0.5.1-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/webencodings-0.5.1-py2.py3-none-any.whl
diff --git a/microblog/microvenv/share/python-wheels/wheel-0.34.2-py2.py3-none-any.whl b/microblog-project/microblog-23-api/microvenv/share/python-wheels/wheel-0.34.2-py2.py3-none-any.whl
similarity index 100%
rename from microblog/microvenv/share/python-wheels/wheel-0.34.2-py2.py3-none-any.whl
rename to microblog-project/microblog-23-api/microvenv/share/python-wheels/wheel-0.34.2-py2.py3-none-any.whl
diff --git a/microblog-project/microblog-23-api/migrations/README b/microblog-project/microblog-23-api/migrations/README
new file mode 100755
index 000000000..98e4f9c44
--- /dev/null
+++ b/microblog-project/microblog-23-api/migrations/README
@@ -0,0 +1 @@
+Generic single-database configuration.
\ No newline at end of file
diff --git a/microblog-project/microblog-23-api/migrations/alembic.ini b/microblog-project/microblog-23-api/migrations/alembic.ini
new file mode 100644
index 000000000..f8ed4801f
--- /dev/null
+++ b/microblog-project/microblog-23-api/migrations/alembic.ini
@@ -0,0 +1,45 @@
+# A generic, single database configuration.
+
+[alembic]
+# template used to generate migration files
+# file_template = %%(rev)s_%%(slug)s
+
+# set to 'true' to run the environment during
+# the 'revision' command, regardless of autogenerate
+# revision_environment = false
+
+
+# Logging configuration
+[loggers]
+keys = root,sqlalchemy,alembic
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = WARN
+handlers = console
+qualname =
+
+[logger_sqlalchemy]
+level = WARN
+handlers =
+qualname = sqlalchemy.engine
+
+[logger_alembic]
+level = INFO
+handlers =
+qualname = alembic
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(levelname)-5.5s [%(name)s] %(message)s
+datefmt = %H:%M:%S
diff --git a/microblog/migrations/env.py b/microblog-project/microblog-23-api/migrations/env.py
similarity index 100%
rename from microblog/migrations/env.py
rename to microblog-project/microblog-23-api/migrations/env.py
diff --git a/microblog-project/microblog-23-api/migrations/script.py.mako b/microblog-project/microblog-23-api/migrations/script.py.mako
new file mode 100755
index 000000000..2c0156303
--- /dev/null
+++ b/microblog-project/microblog-23-api/migrations/script.py.mako
@@ -0,0 +1,24 @@
+"""${message}
+
+Revision ID: ${up_revision}
+Revises: ${down_revision | comma,n}
+Create Date: ${create_date}
+
+"""
+from alembic import op
+import sqlalchemy as sa
+${imports if imports else ""}
+
+# revision identifiers, used by Alembic.
+revision = ${repr(up_revision)}
+down_revision = ${repr(down_revision)}
+branch_labels = ${repr(branch_labels)}
+depends_on = ${repr(depends_on)}
+
+
+def upgrade():
+ ${upgrades if upgrades else "pass"}
+
+
+def downgrade():
+ ${downgrades if downgrades else "pass"}
diff --git a/microblog/migrations/versions/2b017edaa91f_add_language_to_posts.py b/microblog-project/microblog-23-api/migrations/versions/2b017edaa91f_add_language_to_posts.py
similarity index 100%
rename from microblog/migrations/versions/2b017edaa91f_add_language_to_posts.py
rename to microblog-project/microblog-23-api/migrations/versions/2b017edaa91f_add_language_to_posts.py
diff --git a/microblog/migrations/versions/37f06a334dbf_new_fields_in_user_model.py b/microblog-project/microblog-23-api/migrations/versions/37f06a334dbf_new_fields_in_user_model.py
similarity index 100%
rename from microblog/migrations/versions/37f06a334dbf_new_fields_in_user_model.py
rename to microblog-project/microblog-23-api/migrations/versions/37f06a334dbf_new_fields_in_user_model.py
diff --git a/microblog/migrations/versions/780739b227a7_posts_table.py b/microblog-project/microblog-23-api/migrations/versions/780739b227a7_posts_table.py
similarity index 100%
rename from microblog/migrations/versions/780739b227a7_posts_table.py
rename to microblog-project/microblog-23-api/migrations/versions/780739b227a7_posts_table.py
diff --git a/microblog/migrations/versions/834b1a697901_user_tokens.py b/microblog-project/microblog-23-api/migrations/versions/834b1a697901_user_tokens.py
similarity index 100%
rename from microblog/migrations/versions/834b1a697901_user_tokens.py
rename to microblog-project/microblog-23-api/migrations/versions/834b1a697901_user_tokens.py
diff --git a/microblog/migrations/versions/ae346256b650_followers.py b/microblog-project/microblog-23-api/migrations/versions/ae346256b650_followers.py
similarity index 100%
rename from microblog/migrations/versions/ae346256b650_followers.py
rename to microblog-project/microblog-23-api/migrations/versions/ae346256b650_followers.py
diff --git a/microblog/migrations/versions/c81bac34faab_tasks.py b/microblog-project/microblog-23-api/migrations/versions/c81bac34faab_tasks.py
similarity index 100%
rename from microblog/migrations/versions/c81bac34faab_tasks.py
rename to microblog-project/microblog-23-api/migrations/versions/c81bac34faab_tasks.py
diff --git a/microblog/migrations/versions/d049de007ccf_private_messages.py b/microblog-project/microblog-23-api/migrations/versions/d049de007ccf_private_messages.py
similarity index 100%
rename from microblog/migrations/versions/d049de007ccf_private_messages.py
rename to microblog-project/microblog-23-api/migrations/versions/d049de007ccf_private_messages.py
diff --git a/microblog/migrations/versions/e517276bb1c2_users_table.py b/microblog-project/microblog-23-api/migrations/versions/e517276bb1c2_users_table.py
similarity index 100%
rename from microblog/migrations/versions/e517276bb1c2_users_table.py
rename to microblog-project/microblog-23-api/migrations/versions/e517276bb1c2_users_table.py
diff --git a/microblog/migrations/versions/f7ac3d27bb1d_notifications.py b/microblog-project/microblog-23-api/migrations/versions/f7ac3d27bb1d_notifications.py
similarity index 100%
rename from microblog/migrations/versions/f7ac3d27bb1d_notifications.py
rename to microblog-project/microblog-23-api/migrations/versions/f7ac3d27bb1d_notifications.py
diff --git a/microblog/requirements.txt b/microblog-project/microblog-23-api/requirements.txt
similarity index 100%
rename from microblog/requirements.txt
rename to microblog-project/microblog-23-api/requirements.txt
diff --git a/microblog/tests.py b/microblog-project/microblog-23-api/tests.py
similarity index 100%
rename from microblog/tests.py
rename to microblog-project/microblog-23-api/tests.py
diff --git a/microblog/microvenv/bin/Activate.ps1 b/microblog/microvenv/bin/Activate.ps1
deleted file mode 100644
index 2fb3852c3..000000000
--- a/microblog/microvenv/bin/Activate.ps1
+++ /dev/null
@@ -1,241 +0,0 @@
-<#
-.Synopsis
-Activate a Python virtual environment for the current PowerShell session.
-
-.Description
-Pushes the python executable for a virtual environment to the front of the
-$Env:PATH environment variable and sets the prompt to signify that you are
-in a Python virtual environment. Makes use of the command line switches as
-well as the `pyvenv.cfg` file values present in the virtual environment.
-
-.Parameter VenvDir
-Path to the directory that contains the virtual environment to activate. The
-default value for this is the parent of the directory that the Activate.ps1
-script is located within.
-
-.Parameter Prompt
-The prompt prefix to display when this virtual environment is activated. By
-default, this prompt is the name of the virtual environment folder (VenvDir)
-surrounded by parentheses and followed by a single space (ie. '(.venv) ').
-
-.Example
-Activate.ps1
-Activates the Python virtual environment that contains the Activate.ps1 script.
-
-.Example
-Activate.ps1 -Verbose
-Activates the Python virtual environment that contains the Activate.ps1 script,
-and shows extra information about the activation as it executes.
-
-.Example
-Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
-Activates the Python virtual environment located in the specified location.
-
-.Example
-Activate.ps1 -Prompt "MyPython"
-Activates the Python virtual environment that contains the Activate.ps1 script,
-and prefixes the current prompt with the specified string (surrounded in
-parentheses) while the virtual environment is active.
-
-.Notes
-On Windows, it may be required to enable this Activate.ps1 script by setting the
-execution policy for the user. You can do this by issuing the following PowerShell
-command:
-
-PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
-
-For more information on Execution Policies:
-https://go.microsoft.com/fwlink/?LinkID=135170
-
-#>
-Param(
- [Parameter(Mandatory = $false)]
- [String]
- $VenvDir,
- [Parameter(Mandatory = $false)]
- [String]
- $Prompt
-)
-
-<# Function declarations --------------------------------------------------- #>
-
-<#
-.Synopsis
-Remove all shell session elements added by the Activate script, including the
-addition of the virtual environment's Python executable from the beginning of
-the PATH variable.
-
-.Parameter NonDestructive
-If present, do not remove this function from the global namespace for the
-session.
-
-#>
-function global:deactivate ([switch]$NonDestructive) {
- # Revert to original values
-
- # The prior prompt:
- if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
- Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
- Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
- }
-
- # The prior PYTHONHOME:
- if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
- Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
- Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
- }
-
- # The prior PATH:
- if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
- Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
- Remove-Item -Path Env:_OLD_VIRTUAL_PATH
- }
-
- # Just remove the VIRTUAL_ENV altogether:
- if (Test-Path -Path Env:VIRTUAL_ENV) {
- Remove-Item -Path env:VIRTUAL_ENV
- }
-
- # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
- if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
- Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
- }
-
- # Leave deactivate function in the global namespace if requested:
- if (-not $NonDestructive) {
- Remove-Item -Path function:deactivate
- }
-}
-
-<#
-.Description
-Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
-given folder, and returns them in a map.
-
-For each line in the pyvenv.cfg file, if that line can be parsed into exactly
-two strings separated by `=` (with any amount of whitespace surrounding the =)
-then it is considered a `key = value` line. The left hand string is the key,
-the right hand is the value.
-
-If the value starts with a `'` or a `"` then the first and last character is
-stripped from the value before being captured.
-
-.Parameter ConfigDir
-Path to the directory that contains the `pyvenv.cfg` file.
-#>
-function Get-PyVenvConfig(
- [String]
- $ConfigDir
-) {
- Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
-
- # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
- $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
-
- # An empty map will be returned if no config file is found.
- $pyvenvConfig = @{ }
-
- if ($pyvenvConfigPath) {
-
- Write-Verbose "File exists, parse `key = value` lines"
- $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
-
- $pyvenvConfigContent | ForEach-Object {
- $keyval = $PSItem -split "\s*=\s*", 2
- if ($keyval[0] -and $keyval[1]) {
- $val = $keyval[1]
-
- # Remove extraneous quotations around a string value.
- if ("'""".Contains($val.Substring(0, 1))) {
- $val = $val.Substring(1, $val.Length - 2)
- }
-
- $pyvenvConfig[$keyval[0]] = $val
- Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
- }
- }
- }
- return $pyvenvConfig
-}
-
-
-<# Begin Activate script --------------------------------------------------- #>
-
-# Determine the containing directory of this script
-$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
-$VenvExecDir = Get-Item -Path $VenvExecPath
-
-Write-Verbose "Activation script is located in path: '$VenvExecPath'"
-Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
-Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
-
-# Set values required in priority: CmdLine, ConfigFile, Default
-# First, get the location of the virtual environment, it might not be
-# VenvExecDir if specified on the command line.
-if ($VenvDir) {
- Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
-}
-else {
- Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
- $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
- Write-Verbose "VenvDir=$VenvDir"
-}
-
-# Next, read the `pyvenv.cfg` file to determine any required value such
-# as `prompt`.
-$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
-
-# Next, set the prompt from the command line, or the config file, or
-# just use the name of the virtual environment folder.
-if ($Prompt) {
- Write-Verbose "Prompt specified as argument, using '$Prompt'"
-}
-else {
- Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
- if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
- Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
- $Prompt = $pyvenvCfg['prompt'];
- }
- else {
- Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virutal environment)"
- Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
- $Prompt = Split-Path -Path $venvDir -Leaf
- }
-}
-
-Write-Verbose "Prompt = '$Prompt'"
-Write-Verbose "VenvDir='$VenvDir'"
-
-# Deactivate any currently active virtual environment, but leave the
-# deactivate function in place.
-deactivate -nondestructive
-
-# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
-# that there is an activated venv.
-$env:VIRTUAL_ENV = $VenvDir
-
-if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
-
- Write-Verbose "Setting prompt to '$Prompt'"
-
- # Set the prompt to include the env name
- # Make sure _OLD_VIRTUAL_PROMPT is global
- function global:_OLD_VIRTUAL_PROMPT { "" }
- Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
- New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
-
- function global:prompt {
- Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
- _OLD_VIRTUAL_PROMPT
- }
-}
-
-# Clear PYTHONHOME
-if (Test-Path -Path Env:PYTHONHOME) {
- Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
- Remove-Item -Path Env:PYTHONHOME
-}
-
-# Add the venv to the PATH
-Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
-$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"
diff --git a/microblog/microvenv/bin/activate b/microblog/microvenv/bin/activate
deleted file mode 100644
index ddd8ecd84..000000000
--- a/microblog/microvenv/bin/activate
+++ /dev/null
@@ -1,76 +0,0 @@
-# This file must be used with "source bin/activate" *from bash*
-# you cannot run it directly
-
-deactivate () {
- # reset old environment variables
- if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
- PATH="${_OLD_VIRTUAL_PATH:-}"
- export PATH
- unset _OLD_VIRTUAL_PATH
- fi
- if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
- PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
- export PYTHONHOME
- unset _OLD_VIRTUAL_PYTHONHOME
- fi
-
- # This should detect bash and zsh, which have a hash command that must
- # be called to get it to forget past commands. Without forgetting
- # past commands the $PATH changes we made may not be respected
- if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
- hash -r
- fi
-
- if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
- PS1="${_OLD_VIRTUAL_PS1:-}"
- export PS1
- unset _OLD_VIRTUAL_PS1
- fi
-
- unset VIRTUAL_ENV
- if [ ! "${1:-}" = "nondestructive" ] ; then
- # Self destruct!
- unset -f deactivate
- fi
-}
-
-# unset irrelevant variables
-deactivate nondestructive
-
-VIRTUAL_ENV="/home/codespace/workspace/elearning/microblog/microvenv"
-export VIRTUAL_ENV
-
-_OLD_VIRTUAL_PATH="$PATH"
-PATH="$VIRTUAL_ENV/bin:$PATH"
-export PATH
-
-# unset PYTHONHOME if set
-# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
-# could use `if (set -u; : $PYTHONHOME) ;` in bash
-if [ -n "${PYTHONHOME:-}" ] ; then
- _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
- unset PYTHONHOME
-fi
-
-if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
- _OLD_VIRTUAL_PS1="${PS1:-}"
- if [ "x(microvenv) " != x ] ; then
- PS1="(microvenv) ${PS1:-}"
- else
- if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then
- # special case for Aspen magic directories
- # see http://www.zetadev.com/software/aspen/
- PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1"
- else
- PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1"
- fi
- fi
- export PS1
-fi
-
-# This should detect bash and zsh, which have a hash command that must
-# be called to get it to forget past commands. Without forgetting
-# past commands the $PATH changes we made may not be respected
-if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
- hash -r
-fi
diff --git a/microblog/microvenv/bin/activate.csh b/microblog/microvenv/bin/activate.csh
deleted file mode 100644
index 8d62f0d35..000000000
--- a/microblog/microvenv/bin/activate.csh
+++ /dev/null
@@ -1,37 +0,0 @@
-# This file must be used with "source bin/activate.csh" *from csh*.
-# You cannot run it directly.
-# Created by Davide Di Blasi