From 9321d4d27e0282105de0b91e8aa6bc45d795bb76 Mon Sep 17 00:00:00 2001 From: Shantagouda B K Date: Sat, 23 Sep 2017 09:25:11 -0700 Subject: [PATCH 01/15] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1fd837b..cff4580 100644 --- a/README.md +++ b/README.md @@ -1 +1,3 @@ # cmpe281-starks + +Recommedantion Engine for Cloud hosted real time retail application. From 4371055a38fd13d21ca7e9a99db7fdf4b68a694b Mon Sep 17 00:00:00 2001 From: Shantagouda B K Date: Tue, 26 Sep 2017 10:56:50 -0700 Subject: [PATCH 02/15] Add files via upload --- Recommendation_Engine_Architecture_Diagram.png | Bin 0 -> 66999 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Recommendation_Engine_Architecture_Diagram.png diff --git a/Recommendation_Engine_Architecture_Diagram.png b/Recommendation_Engine_Architecture_Diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..c3ceea8afba4b1aee225aed67e80d0bcb7d0fe27 GIT binary patch literal 66999 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 z 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 z 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 _@UEz2Gd`Ycr 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 tGXJS6rWK1*0DZOp{un?L?f?G%)~_Rks Date: Sun, 22 Oct 2017 03:50:56 -0700 Subject: [PATCH 03/15] Create Functional Flow --- Recommendation System/Functional Flow | 1 + 1 file changed, 1 insertion(+) create mode 100644 Recommendation System/Functional Flow diff --git a/Recommendation System/Functional Flow b/Recommendation System/Functional Flow new file mode 100644 index 0000000..d9b46cc --- /dev/null +++ b/Recommendation System/Functional Flow @@ -0,0 +1 @@ +RE From 7f609cad68c0f0601a0140ccde2d4bf40f0d05c4 Mon Sep 17 00:00:00 2001 From: Shantagouda B K Date: Sun, 22 Oct 2017 03:58:52 -0700 Subject: [PATCH 04/15] Basic Web Servers using Flask and Neo4j --- Recommendation System/app.py | 107 +++++++++++++++++++++++++ Recommendation System/requirements.txt | 13 +++ 2 files changed, 120 insertions(+) create mode 100644 Recommendation System/app.py create mode 100644 Recommendation System/requirements.txt diff --git a/Recommendation System/app.py b/Recommendation System/app.py new file mode 100644 index 0000000..6c08a94 --- /dev/null +++ b/Recommendation System/app.py @@ -0,0 +1,107 @@ +#!flask/bin/python +from flask import Flask, jsonify, abort, make_response, request +from neo4j.v1 import GraphDatabase, basic_auth + +app = Flask(__name__) + +# Connection String to connect Neo4j Garph DB +driver = GraphDatabase.driver("bolt://localhost:7687", auth=basic_auth("neo4j", "password")) + +# Sample DB imported to neo4j available here - https://code.google.com/archive/p/northwindextended/downloads + +# Sample wishlist (Not Stored in DB) +wishlist = [ + { + 'id': 3, + 'title': u'Shirt', + 'description': u'Lewis 40 Slimfit', + 'category': u'Fashion', + 'price': u'$40', + 'imageURL': u'www.xyz.com' + }, + { + + 'id': 4, + 'title': u'Book', + 'description': u'Learning from Data', + 'category': u'Education', + 'price': u'$30', + 'imageURL': u'www.xyz.com' + } +] + +# Sample Search History +searchHistory = [ + { + 'id': 5, + 'title': u'Shirt', + 'description': u'Lewis 40 Slimfit', + 'category': u'Fashion', + 'price': u'$40', + 'imageURL': u'www.xyz.com' + }, + { + + 'id': 6, + 'title': u'Book', + 'description': u'Learning from Data', + 'category': u'Education', + 'price': u'$30', + 'imageURL': u'www.xyz.com' + } +] + +# Get the list of products in Wishlist +@app.route('/wishlist', methods=['GET']) +def get_wishlists(): + return jsonify({'wishlist': wishlist}) + +# Get the list of products in Search History +@app.route('/searchlist', methods=['GET']) +def get_searchlist(): + return jsonify({'searchHistory': searchHistory}) + +# Get the product in wishlist with product ID +@app.route('/wishlist/', methods=['GET']) +def get_wishlist(wishlist_id): + wl = [wl for wl in wishlist if wl['id'] == wishlist_id] + if len(wl) == 0: + abort(404) + return jsonify({'task': wl[0]}) + +# Add a product to wishlist +@app.route('/wishlist', methods=['POST']) +def create_wishlist(): + if not request.json or not 'title' in request.json: + abort(400) + wl = { + 'id': wishlist[-1]['id'] + 1, + 'title': request.json['title'], + 'description': request.json.get('description', ""), + 'category': request.json.get('category',""), + 'price': request.json.get('price',""), + 'imageURL': request.json.get('imageURL', "") + } + wishlist.append(wl) + return jsonify({'wl': wl}), 201 + +# Get Supplier and Category of products they supply. +@app.route('/neo', methods=['GET']) +def get_neo(): + session = driver.session() + result = session.run("MATCH (s:Supplier)-->(:Product)-->(c:Category)" + "RETURN s.companyName as Company, collect(distinct c.categoryName) as Categories") + for record in result: + print("%s %s" % (record["Company"], record["Categories"])) + session.close() + return 'OK' + + +@app.errorhandler(404) +def not_found(error): + return make_response(jsonify({'error': 'Not found'}), 404) + +if __name__ == '__main__': + app.run(debug=True) + + diff --git a/Recommendation System/requirements.txt b/Recommendation System/requirements.txt new file mode 100644 index 0000000..797d5e6 --- /dev/null +++ b/Recommendation System/requirements.txt @@ -0,0 +1,13 @@ +bcrypt==3.1.0 +cffi==1.7.0 +click==6.6 +Flask==0.11.1 +itsdangerous==0.24 +Jinja2==2.8 +MarkupSafe==0.23 +passlib==1.6.5 +py2neo==3.1.1 +pycparser==2.14 +six==1.10.0 +Werkzeug==0.11.10 + From 9ddcc26d50513986a3fce27665a3aaa20822fe40 Mon Sep 17 00:00:00 2001 From: Shantagouda B K Date: Sun, 22 Oct 2017 04:01:34 -0700 Subject: [PATCH 05/15] Rename README.md to README for RE.md --- README.md => README for RE.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README.md => README for RE.md (100%) diff --git a/README.md b/README for RE.md similarity index 100% rename from README.md rename to README for RE.md From 68ddb32c1849de028d5b76f8f43b17f14111315e Mon Sep 17 00:00:00 2001 From: Shantagouda B K Date: Mon, 23 Oct 2017 01:13:34 -0700 Subject: [PATCH 06/15] Update app.py --- Recommendation System/app.py | 110 ++--------------------------------- 1 file changed, 5 insertions(+), 105 deletions(-) diff --git a/Recommendation System/app.py b/Recommendation System/app.py index 6c08a94..7e89198 100644 --- a/Recommendation System/app.py +++ b/Recommendation System/app.py @@ -1,107 +1,7 @@ -#!flask/bin/python -from flask import Flask, jsonify, abort, make_response, request -from neo4j.v1 import GraphDatabase, basic_auth - -app = Flask(__name__) - -# Connection String to connect Neo4j Garph DB -driver = GraphDatabase.driver("bolt://localhost:7687", auth=basic_auth("neo4j", "password")) - -# Sample DB imported to neo4j available here - https://code.google.com/archive/p/northwindextended/downloads - -# Sample wishlist (Not Stored in DB) -wishlist = [ - { - 'id': 3, - 'title': u'Shirt', - 'description': u'Lewis 40 Slimfit', - 'category': u'Fashion', - 'price': u'$40', - 'imageURL': u'www.xyz.com' - }, - { - - 'id': 4, - 'title': u'Book', - 'description': u'Learning from Data', - 'category': u'Education', - 'price': u'$30', - 'imageURL': u'www.xyz.com' - } -] - -# Sample Search History -searchHistory = [ - { - 'id': 5, - 'title': u'Shirt', - 'description': u'Lewis 40 Slimfit', - 'category': u'Fashion', - 'price': u'$40', - 'imageURL': u'www.xyz.com' - }, - { - - 'id': 6, - 'title': u'Book', - 'description': u'Learning from Data', - 'category': u'Education', - 'price': u'$30', - 'imageURL': u'www.xyz.com' - } -] - -# Get the list of products in Wishlist -@app.route('/wishlist', methods=['GET']) -def get_wishlists(): - return jsonify({'wishlist': wishlist}) - -# Get the list of products in Search History -@app.route('/searchlist', methods=['GET']) -def get_searchlist(): - return jsonify({'searchHistory': searchHistory}) - -# Get the product in wishlist with product ID -@app.route('/wishlist/', methods=['GET']) -def get_wishlist(wishlist_id): - wl = [wl for wl in wishlist if wl['id'] == wishlist_id] - if len(wl) == 0: - abort(404) - return jsonify({'task': wl[0]}) - -# Add a product to wishlist -@app.route('/wishlist', methods=['POST']) -def create_wishlist(): - if not request.json or not 'title' in request.json: - abort(400) - wl = { - 'id': wishlist[-1]['id'] + 1, - 'title': request.json['title'], - 'description': request.json.get('description', ""), - 'category': request.json.get('category',""), - 'price': request.json.get('price',""), - 'imageURL': request.json.get('imageURL', "") - } - wishlist.append(wl) - return jsonify({'wl': wl}), 201 - -# Get Supplier and Category of products they supply. -@app.route('/neo', methods=['GET']) -def get_neo(): - session = driver.session() - result = session.run("MATCH (s:Supplier)-->(:Product)-->(c:Category)" - "RETURN s.companyName as Company, collect(distinct c.categoryName) as Categories") - for record in result: - print("%s %s" % (record["Company"], record["Categories"])) - session.close() - return 'OK' - - -@app.errorhandler(404) -def not_found(error): - return make_response(jsonify({'error': 'Not found'}), 404) - -if __name__ == '__main__': - app.run(debug=True) +from re import app +import os +app.secret_key = os.urandom(24) +port = int(os.environ.get('PORT', 5000)) +app.run(host='0.0.0.0', port=port) From b15869af1156820bbf164f49af2ac77662b354a2 Mon Sep 17 00:00:00 2001 From: Shantagouda B K Date: Mon, 23 Oct 2017 01:14:48 -0700 Subject: [PATCH 07/15] Create views.py --- Recommendation System/re/views.py | 109 ++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 Recommendation System/re/views.py diff --git a/Recommendation System/re/views.py b/Recommendation System/re/views.py new file mode 100644 index 0000000..dee8ddd --- /dev/null +++ b/Recommendation System/re/views.py @@ -0,0 +1,109 @@ +from .models import User, get_todays_recent_posts +from flask import Flask, request, session, redirect, url_for, render_template, flash + +app = Flask(__name__) + +@app.route('/') +def index(): + posts = get_todays_recent_posts() + return render_template('index.html', posts=posts) + +@app.route('/register', methods=['GET','POST']) +def register(): + if request.method == 'POST': + username = request.form['username'] + password = request.form['password'] + + if len(username) < 1: + flash('Your username must be at least one character.') + elif len(password) < 5: + flash('Your password must be at least 5 characters.') + elif not User(username).register(password): + flash('A user with that username already exists.') + else: + session['username'] = username + flash('Logged in.') + return redirect(url_for('index')) + + return render_template('register.html') + +@app.route('/login', methods=['GET', 'POST']) +def login(): + if request.method == 'POST': + username = request.form['username'] + password = request.form['password'] + + if not User(username).verify_password(password): + flash('Invalid login.') + else: + session['username'] = username + flash('Logged in.') + return redirect(url_for('index')) + + return render_template('login.html') + +@app.route('/logout') +def logout(): + session.pop('username', None) + flash('Logged out.') + return redirect(url_for('index')) + +@app.route('/add_product', methods=['POST']) +def add_product(): + title = request.form['title'] + tags = request.form['tags'] + text = request.form['text'] + + if not title: + flash('You must give your post a title.') + elif not tags: + flash('You must give your post at least one tag.') + elif not text: + flash('You must give your post a text body.') + else: + User(session['username']).add_post(title, tags, text) + + return redirect(url_for('index')) + +@app.route('/like_post/') +def like_post(post_id): + username = session.get('username') + + if not username: + flash('You must be logged in to like a post.') + return redirect(url_for('login')) + + User(username).like_post(post_id) + + flash('Liked post.') + return redirect(request.referrer) + +@app.route('/profile/') +def profile(username): + logged_in_username = session.get('username') + user_being_viewed_username = username + + user_being_viewed = User(user_being_viewed_username) + posts = user_being_viewed.get_recent_posts() + + similar = [] + common = [] + products = [] + + if logged_in_username: + logged_in_user = User(logged_in_username) + + if logged_in_user.username == user_being_viewed.username: + similar = logged_in_user.get_similar_users() + products = logged_in_user.get_products() + else: + common = logged_in_user.get_commonality_of_user(user_being_viewed) + + return render_template( + 'profile.html', + username=username, + posts=posts, + similar=similar, + common=common, + products=products + ) From f50cbf229cda3c3f85fb19f5b4563af48e46c169 Mon Sep 17 00:00:00 2001 From: Shantagouda B K Date: Mon, 23 Oct 2017 01:15:36 -0700 Subject: [PATCH 08/15] Create models.py --- Recommendation System/re/models.py | 125 +++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 Recommendation System/re/models.py diff --git a/Recommendation System/re/models.py b/Recommendation System/re/models.py new file mode 100644 index 0000000..1f7700a --- /dev/null +++ b/Recommendation System/re/models.py @@ -0,0 +1,125 @@ +from py2neo import Graph, Node, Relationship +from passlib.hash import bcrypt +from datetime import datetime +import os +import uuid + +url = os.environ.get('GRAPHENEDB_URL', 'http://localhost:7474') +username = os.environ.get('NEO4J_USERNAME') +password = os.environ.get('NEO4J_PASSWORD') + +graph = Graph(url + '/db/data/', username=username, password=password) + +class User: + def __init__(self, username): + self.username = username + + def find(self): + user = graph.find_one('User', 'username', self.username) + return user + + def register(self, password): + if not self.find(): + user = Node('User', username=self.username, password=bcrypt.encrypt(password)) + graph.create(user) + return True + else: + return False + + def verify_password(self, password): + user = self.find() + if user: + return bcrypt.verify(password, user['password']) + else: + return False + + def add_post(self, title, tags, text): + user = self.find() + post = Node( + 'Post', + id=str(uuid.uuid4()), + title=title, + text=text, + timestamp=timestamp(), + date=date() + ) + rel = Relationship(user, 'PUBLISHED', post) + graph.create(rel) + + tags = [x.strip() for x in tags.lower().split(',')] + for name in set(tags): + tag = Node('Tag', name=name) + graph.merge(tag) + + rel = Relationship(tag, 'TAGGED', post) + graph.create(rel) + + def like_post(self, post_id): + user = self.find() + post = graph.find_one('Post', 'id', post_id) + graph.merge(Relationship(user, 'LIKED', post)) + + def get_recent_posts(self): + query = ''' + MATCH (user:User)-[:PUBLISHED]->(post:Post)<-[:TAGGED]-(tag:Tag) + WHERE user.username = {username} + RETURN post, COLLECT(tag.name) AS tags + ORDER BY post.timestamp DESC LIMIT 5 + ''' + + return graph.run(query, username=self.username) + + def get_products(self): + query = ''' + MATCH (user:User)-[:PUBLISHED]->(post:Post)<-[:TAGGED]-(tag:Tag) + WHERE user.username = {username} + RETURN post, COLLECT(tag.name) AS tags + ORDER BY post.timestamp DESC LIMIT 5 + ''' + + return graph.run(query, username=self.username) + + def get_similar_users(self): + + query = ''' + MATCH (you:User)-[:PUBLISHED]->(:Post)<-[:TAGGED]-(tag:Tag), + (they:User)-[:PUBLISHED]->(:Post)<-[:TAGGED]-(tag) + WHERE you.username = {username} AND you <> they + WITH they, COLLECT(DISTINCT tag.name) AS tags + ORDER BY SIZE(tags) DESC LIMIT 3 + RETURN they.username AS similar_user, tags + ''' + + return graph.run(query, username=self.username) + + def get_commonality_of_user(self, other): + + query = ''' + MATCH (they:User {username: {they} }) + MATCH (you:User {username: {you} }) + OPTIONAL MATCH (they)-[:PUBLISHED]->(:Post)<-[:TAGGED]-(tag:Tag), + (you)-[:PUBLISHED]->(:Post)<-[:TAGGED]-(tag) + RETURN SIZE((they)-[:LIKED]->(:Post)<-[:PUBLISHED]-(you)) AS likes, + COLLECT(DISTINCT tag.name) AS tags + ''' + + return graph.run(query, they=other.username, you=self.username).next + +def get_todays_recent_posts(): + query = ''' + MATCH (user:User)-[:PUBLISHED]->(post:Post)<-[:TAGGED]-(tag:Tag) + WHERE post.date = {today} + RETURN user.username AS username, post, COLLECT(tag.name) AS tags + ORDER BY post.timestamp DESC LIMIT 5 + ''' + + return graph.run(query, today=date()) + +def timestamp(): + epoch = datetime.utcfromtimestamp(0) + now = datetime.now() + delta = now - epoch + return delta.total_seconds() + +def date(): + return datetime.now().strftime('%Y-%m-%d') From 806ebe3569d51ab32d52d9d197cb5703e4176226 Mon Sep 17 00:00:00 2001 From: Shantagouda B K Date: Mon, 23 Oct 2017 01:16:34 -0700 Subject: [PATCH 09/15] Create __init__.py --- Recommendation System/re/__init__.py | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Recommendation System/re/__init__.py diff --git a/Recommendation System/re/__init__.py b/Recommendation System/re/__init__.py new file mode 100644 index 0000000..11e246c --- /dev/null +++ b/Recommendation System/re/__init__.py @@ -0,0 +1,2 @@ +from .views import app +from .models import graph From a9ec13b9785f25c27675f6df12d9cdc1a5b775b1 Mon Sep 17 00:00:00 2001 From: Shantagouda B K Date: Mon, 23 Oct 2017 01:17:50 -0700 Subject: [PATCH 10/15] Create profile.html --- .../re/templates/profile.html | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Recommendation System/re/templates/profile.html diff --git a/Recommendation System/re/templates/profile.html b/Recommendation System/re/templates/profile.html new file mode 100644 index 0000000..968d1c0 --- /dev/null +++ b/Recommendation System/re/templates/profile.html @@ -0,0 +1,51 @@ +{% extends "layout.html" %} +{% block body %} + +

{{ username }}'s profile

+ +{% if session.username %} + {% if session.username == username %} +

Users who brought items similar to you:

+ + {% for user in similar %} +
+ {% else %} +

There aren't any users who've purchased products the same category as you!

+ {% endfor %} + +

Recommendations for you

+ Based on your previous purchases + {% for product in products %} +

+ {{ product.post.title }} +

+ + + {% else %} +

There aren't any users who've purchased products the same category as you!

+ {% endfor %} + +

Your recent purchases:

+ + + {% else %} + +

{{ username }} has liked {{ common.likes }} of your purchases and + {% if common.tags %} + also purchased {{ ", ".join(common.tags) }} + {% else %} + hasn't purchased any of the same category + {% endif %} +

+ +

{{ username }}'s recent purchases:

+ + {% endif %} +{% endif %} + +{% include "display_posts.html" %} + +{% endblock %} From 4abf4bdafd7cc4c519d5f74f04111a6bb5b4da1a Mon Sep 17 00:00:00 2001 From: Shantagouda B K Date: Mon, 23 Oct 2017 01:18:13 -0700 Subject: [PATCH 11/15] Create index.html --- Recommendation System/re/templates/index.html | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Recommendation System/re/templates/index.html diff --git a/Recommendation System/re/templates/index.html b/Recommendation System/re/templates/index.html new file mode 100644 index 0000000..9e0b361 --- /dev/null +++ b/Recommendation System/re/templates/index.html @@ -0,0 +1,25 @@ +{% extends "layout.html" %} +{% block body %} + +

Home

+ {% if session.username %} +

Purchase New Items

+
+
+
Product Name:
+
+
Categories (separated by commas):
+
+
Description:
+
+
+ +
+ {% endif %} + +
+ +

Today's Recent Purchases

+{% include "display_posts.html" %} + +{% endblock %} From 5a7c912ca94a40af231ea994163671389151a6e5 Mon Sep 17 00:00:00 2001 From: Shantagouda B K Date: Mon, 23 Oct 2017 01:18:35 -0700 Subject: [PATCH 12/15] Create display_host --- Recommendation System/re/templates/display_host | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 Recommendation System/re/templates/display_host diff --git a/Recommendation System/re/templates/display_host b/Recommendation System/re/templates/display_host new file mode 100644 index 0000000..c51578f --- /dev/null +++ b/Recommendation System/re/templates/display_host @@ -0,0 +1,15 @@ +
    + {% for row in posts %} +
  • + {{ row.post.title }} + {% if request.path == "/" %} + by {{ row.username }} + {% endif %} + on {{ row.post.date }} + like
    + {{ ", ".join(row.tags) }}
    + {{ row.post.text }} + {% else %} +
  • There aren't any purchases yet! + {% endfor %} +
From f00b398b716b5474fbcef05c0406a2dbfd12306e Mon Sep 17 00:00:00 2001 From: Shantagouda B K Date: Mon, 23 Oct 2017 01:19:18 -0700 Subject: [PATCH 13/15] Create layout.html --- .../re/templates/layout.html | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Recommendation System/re/templates/layout.html diff --git a/Recommendation System/re/templates/layout.html b/Recommendation System/re/templates/layout.html new file mode 100644 index 0000000..d13041b --- /dev/null +++ b/Recommendation System/re/templates/layout.html @@ -0,0 +1,23 @@ + +My Recommendation Engine + +
+

My Recommendation Site

+
+ {% if session.username %} + Logged in as {{ session.username }} + {% endif %} + Home + {% if not session.username %} + Register + Login + {% else %} + Profile + Logout + {% endif %} +
+ {% for message in get_flashed_messages() %} +
{{ message }}
+ {% endfor %} + {% block body %}{% endblock %} +
From 025ee7de7fc87da6b75b2f603550d36c2c3bcd56 Mon Sep 17 00:00:00 2001 From: Shantagouda B K Date: Mon, 23 Oct 2017 01:19:45 -0700 Subject: [PATCH 14/15] Create style.css --- Recommendation System/re/static/style.css | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 Recommendation System/re/static/style.css diff --git a/Recommendation System/re/static/style.css b/Recommendation System/re/static/style.css new file mode 100644 index 0000000..c6b030f --- /dev/null +++ b/Recommendation System/re/static/style.css @@ -0,0 +1,15 @@ +body { font-family: sans-serif; background: #eee; } +a, h1, h3 { color: #377ba8; } +h1, h2, h3 { font-family: 'Georgia', serif; margin: 0; } +h1, h2 { border-bottom: 2px solid #eee; padding: 3px; } +h3 { padding: 3px; } +dd { display: block; margin-left: 0px; } +dl { font-weight: bold; } +a:visited { color: #800080; } +.page { margin: 2em auto; width: 35em; border: 5px solid #ccc; padding: 0.8em; background: white; } +.posts { list-style: none; margin: 0; padding: 0; } +.posts li { margin: 0.8em 1.2em; } +.posts li h2 { margin-left: -1em; } +.metanav { text-align: right; font-size: 0.8em; padding: 0.3em; margin-bottom: 1em; background: #fafafa; } +.flash { background: #cee5F5; padding: 0.5em; border: 1px solid #aacbe2; } +.error { background: #f0d6d6; padding: 0.5em; } From d80dd6450189e171556096d9bcfd6a4943d045ec Mon Sep 17 00:00:00 2001 From: Shantagouda B K Date: Mon, 23 Oct 2017 01:21:06 -0700 Subject: [PATCH 15/15] Delete README for RE.md --- README for RE.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 README for RE.md diff --git a/README for RE.md b/README for RE.md deleted file mode 100644 index cff4580..0000000 --- a/README for RE.md +++ /dev/null @@ -1,3 +0,0 @@ -# cmpe281-starks - -Recommedantion Engine for Cloud hosted real time retail application.

+ {{ user.similar_user }} + also purchased {{ ", ".join(user.tags) }} {{ ", ".join(user.posts) }} +