diff options
| author | mo khan <mo@mokhan.ca> | 2015-01-18 22:48:26 -0700 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2015-01-18 22:48:26 -0700 |
| commit | b50664795c3f4b6c672c5b1dd7248180fd096322 (patch) | |
| tree | 8a23c44af4c09f61963caf6c9e421a214e190ce2 /week-2 | |
| parent | fbf1ae7f45148a180083ef79d6ccf2983660e4d1 (diff) | |
add hw2-3 package.
Diffstat (limited to 'week-2')
| -rw-r--r-- | week-2/hw2-3/blog/README.md | 13 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/app.js | 27 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/package.json | 22 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/posts.js | 89 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/routes/content.js | 187 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/routes/error.js | 9 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/routes/index.js | 44 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/routes/session.js | 170 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/sessions.js | 65 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/users.js | 68 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/views/blog_template.html | 40 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/views/entry_template.html | 54 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/views/error_template.html | 12 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/views/login.html | 47 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/views/newpost_template.html | 29 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/views/signup.html | 75 | ||||
| -rw-r--r-- | week-2/hw2-3/blog/views/welcome.html | 28 | ||||
| -rw-r--r-- | week-2/hw2-3/validate/README.md | 10 | ||||
| -rw-r--r-- | week-2/hw2-3/validate/package.json | 20 | ||||
| -rw-r--r-- | week-2/hw2-3/validate/validate.js | 1 |
20 files changed, 1010 insertions, 0 deletions
diff --git a/week-2/hw2-3/blog/README.md b/week-2/hw2-3/blog/README.md new file mode 100644 index 0000000..fd885ed --- /dev/null +++ b/week-2/hw2-3/blog/README.md @@ -0,0 +1,13 @@ +Blog project for M101JS + +./app.js - entry point +./package.json - npm package description +./posts.js - Posts Data Access Helper +./sessions.js - Sessions Data Access Helper +./users.js - Users Data Access Helper +./views/ - html templates + +Getting started + +npm install +node app.js diff --git a/week-2/hw2-3/blog/app.js b/week-2/hw2-3/blog/app.js new file mode 100644 index 0000000..f773876 --- /dev/null +++ b/week-2/hw2-3/blog/app.js @@ -0,0 +1,27 @@ +var express = require('express') + , app = express() // Web framework to handle routing requests + , cons = require('consolidate') // Templating library adapter for Express + , MongoClient = require('mongodb').MongoClient // Driver for connecting to MongoDB + , routes = require('./routes'); // Routes for our application + +MongoClient.connect('mongodb://localhost:27017/blog', function(err, db) { + "use strict"; + if(err) throw err; + + // Register our templating engine + app.engine('html', cons.swig); + app.set('view engine', 'html'); + app.set('views', __dirname + '/views'); + + // Express middleware to populate 'req.cookies' so we can access cookies + app.use(express.cookieParser()); + + // Express middleware to populate 'req.body' so we can access POST variables + app.use(express.bodyParser()); + + // Application routes + routes(app, db); + + app.listen(3000); + console.log('Express server listening on port 3000'); +}); diff --git a/week-2/hw2-3/blog/package.json b/week-2/hw2-3/blog/package.json new file mode 100644 index 0000000..bdec04a --- /dev/null +++ b/week-2/hw2-3/blog/package.json @@ -0,0 +1,22 @@ +{ + "name": "blog", + "version": "0.0.0", + "description": "Blog Project for M101JS", + "main": "app.js", + "dependencies": { + "bcrypt-nodejs": "~0.0.3", + "consolidate": "~0.9.1", + "express": "^3.x", + "mongodb": "~1.3.9", + "swig": "~0.14.0", + "validator": "~1.1.3" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": "", + "author": "Shaun Verch <shaun.verch@10gen.com>", + "license": "BSD", + "private": true +} diff --git a/week-2/hw2-3/blog/posts.js b/week-2/hw2-3/blog/posts.js new file mode 100644 index 0000000..4cae444 --- /dev/null +++ b/week-2/hw2-3/blog/posts.js @@ -0,0 +1,89 @@ +/* The PostsDAO must be constructed with a connected database object */ +function PostsDAO(db) { + "use strict"; + + /* If this constructor is called without the "new" operator, "this" points + * to the global object. Log a warning and call it correctly. */ + if (false === (this instanceof PostsDAO)) { + console.log('Warning: PostsDAO constructor called without "new" operator'); + return new PostsDAO(db); + } + + var posts = db.collection("posts"); + + this.insertEntry = function (title, body, tags, author, callback) { + "use strict"; + console.log("inserting blog entry" + title + body); + + // fix up the permalink to not include whitespace + var permalink = title.replace( /\s/g, '_' ); + permalink = permalink.replace( /\W/g, '' ); + + // Build a new post + var post = {"title": title, + "author": author, + "body": body, + "permalink":permalink, + "tags": tags, + "comments": [], + "date": new Date()} + + // now insert the post + // hw3.2 TODO + callback(Error("insertEntry Not Yet Implemented!"), null); + } + + this.getPosts = function(num, callback) { + "use strict"; + + posts.find().sort('date', -1).limit(num).toArray(function(err, items) { + "use strict"; + + if (err) return callback(err, null); + + console.log("Found " + items.length + " posts"); + + callback(err, items); + }); + } + + this.getPostsByTag = function(tag, num, callback) { + "use strict"; + + posts.find({ tags : tag }).sort('date', -1).limit(num).toArray(function(err, items) { + "use strict"; + + if (err) return callback(err, null); + + console.log("Found " + items.length + " posts"); + + callback(err, items); + }); + } + + this.getPostByPermalink = function(permalink, callback) { + "use strict"; + posts.findOne({'permalink': permalink}, function(err, post) { + "use strict"; + + if (err) return callback(err, null); + + callback(err, post); + }); + } + + this.addComment = function(permalink, name, email, body, callback) { + "use strict"; + + var comment = {'author': name, 'body': body} + + if (email != "") { + comment['email'] = email + } + + // hw3.3 TODO + callback(Error("addComment Not Yet Implemented!"), null); + } +} + +module.exports.PostsDAO = PostsDAO; diff --git a/week-2/hw2-3/blog/routes/content.js b/week-2/hw2-3/blog/routes/content.js new file mode 100644 index 0000000..abdada8 --- /dev/null +++ b/week-2/hw2-3/blog/routes/content.js @@ -0,0 +1,187 @@ +var PostsDAO = require('../posts').PostsDAO + , sanitize = require('validator').sanitize; // Helper to sanitize form input + +/* The ContentHandler must be constructed with a connected db */ +function ContentHandler (db) { + "use strict"; + + var posts = new PostsDAO(db); + + this.displayMainPage = function(req, res, next) { + "use strict"; + + posts.getPosts(10, function(err, results) { + "use strict"; + + if (err) return next(err); + + return res.render('blog_template', { + title: 'blog homepage', + username: req.username, + myposts: results + }); + }); + } + + this.displayMainPageByTag = function(req, res, next) { + "use strict"; + + var tag = req.params.tag; + + posts.getPostsByTag(tag, 10, function(err, results) { + "use strict"; + + if (err) return next(err); + + return res.render('blog_template', { + title: 'blog homepage', + username: req.username, + myposts: results + }); + }); + } + + this.displayPostByPermalink = function(req, res, next) { + "use strict"; + + var permalink = req.params.permalink; + + posts.getPostByPermalink(permalink, function(err, post) { + "use strict"; + + if (err) return next(err); + + if (!post) return res.redirect("/post_not_found"); + + // init comment form fields for additional comment + var comment = {'name': req.username, 'body': "", 'email': ""} + + return res.render('entry_template', { + title: 'blog post', + username: req.username, + post: post, + comment: comment, + errors: "" + }); + }); + } + + this.handleNewComment = function(req, res, next) { + "use strict"; + var name = req.body.commentName; + var email = req.body.commentEmail; + var body = req.body.commentBody; + var permalink = req.body.permalink; + + // Override the comment with our actual user name if found + if (req.username) { + name = req.username; + } + + if (!name || !body) { + // user did not fill in enough information + + posts.getPostByPermalink(permalink, function(err, post) { + "use strict"; + + if (err) return next(err); + + if (!post) return res.redirect("/post_not_found"); + + // init comment form fields for additional comment + var comment = {'name': name, 'body': "", 'email': ""} + + var errors = "Post must contain your name and an actual comment." + return res.render('entry_template', { + title: 'blog post', + username: req.username, + post: post, + comment: comment, + errors: errors + }); + }); + + return; + } + + // even if there is no logged in user, we can still post a comment + posts.addComment(permalink, name, email, body, function(err, updated) { + "use strict"; + + if (err) return next(err); + + if (updated == 0) return res.redirect("/post_not_found"); + + return res.redirect("/post/" + permalink); + }); + } + + this.displayPostNotFound = function(req, res, next) { + "use strict"; + return res.send('Sorry, post not found', 404); + } + + this.displayNewPostPage = function(req, res, next) { + "use strict"; + + if (!req.username) return res.redirect("/login"); + + return res.render('newpost_template', { + subject: "", + body: "", + errors: "", + tags: "", + username: req.username + }); + } + + function extract_tags(tags) { + "use strict"; + + var cleaned = []; + + var tags_array = tags.split(','); + + for (var i = 0; i < tags_array.length; i++) { + if ((cleaned.indexOf(tags_array[i]) == -1) && tags_array[i] != "") { + cleaned.push(tags_array[i].replace(/\s/g,'')); + } + } + + return cleaned + } + + this.handleNewPost = function(req, res, next) { + "use strict"; + + var title = req.body.subject + var post = req.body.body + var tags = req.body.tags + + if (!req.username) return res.redirect("/signup"); + + if (!title || !post) { + var errors = "Post must contain a title and blog entry"; + return res.render("newpost_template", {subject:title, username:req.username, body:post, tags:tags, errors:errors}); + } + + var tags_array = extract_tags(tags) + + // looks like a good entry, insert it escaped + var escaped_post = sanitize(post).escape(); + + // substitute some <br> for the paragraph breaks + var formatted_post = escaped_post.replace(/\r?\n/g,'<br>'); + + posts.insertEntry(title, formatted_post, tags_array, req.username, function(err, permalink) { + "use strict"; + + if (err) return next(err); + + // now redirect to the blog permalink + return res.redirect("/post/" + permalink) + }); + } +} + +module.exports = ContentHandler; diff --git a/week-2/hw2-3/blog/routes/error.js b/week-2/hw2-3/blog/routes/error.js new file mode 100644 index 0000000..f50f2b6 --- /dev/null +++ b/week-2/hw2-3/blog/routes/error.js @@ -0,0 +1,9 @@ +// Error handling middleware + +exports.errorHandler = function(err, req, res, next) { + "use strict"; + console.error(err.message); + console.error(err.stack); + res.status(500); + res.render('error_template', { error: err }); +} diff --git a/week-2/hw2-3/blog/routes/index.js b/week-2/hw2-3/blog/routes/index.js new file mode 100644 index 0000000..7fe6535 --- /dev/null +++ b/week-2/hw2-3/blog/routes/index.js @@ -0,0 +1,44 @@ +var SessionHandler = require('./session') + , ContentHandler = require('./content') + , ErrorHandler = require('./error').errorHandler; + +module.exports = exports = function(app, db) { + + var sessionHandler = new SessionHandler(db); + var contentHandler = new ContentHandler(db); + + // Middleware to see if a user is logged in + app.use(sessionHandler.isLoggedInMiddleware); + + // The main page of the blog + app.get('/', contentHandler.displayMainPage); + + // The main page of the blog, filtered by tag + app.get('/tag/:tag', contentHandler.displayMainPageByTag); + + // A single post, which can be commented on + app.get("/post/:permalink", contentHandler.displayPostByPermalink); + app.post('/newcomment', contentHandler.handleNewComment); + app.get("/post_not_found", contentHandler.displayPostNotFound); + + // Displays the form allowing a user to add a new post. Only works for logged in users + app.get('/newpost', contentHandler.displayNewPostPage); + app.post('/newpost', contentHandler.handleNewPost); + + // Login form + app.get('/login', sessionHandler.displayLoginPage); + app.post('/login', sessionHandler.handleLoginRequest); + + // Logout page + app.get('/logout', sessionHandler.displayLogoutPage); + + // Welcome page + app.get("/welcome", sessionHandler.displayWelcomePage); + + // Signup form + app.get('/signup', sessionHandler.displaySignupPage); + app.post('/signup', sessionHandler.handleSignup); + + // Error handling middleware + app.use(ErrorHandler); +} diff --git a/week-2/hw2-3/blog/routes/session.js b/week-2/hw2-3/blog/routes/session.js new file mode 100644 index 0000000..73fe6d9 --- /dev/null +++ b/week-2/hw2-3/blog/routes/session.js @@ -0,0 +1,170 @@ +var UsersDAO = require('../users').UsersDAO + , SessionsDAO = require('../sessions').SessionsDAO; + +/* The SessionHandler must be constructed with a connected db */ +function SessionHandler (db) { + "use strict"; + + var users = new UsersDAO(db); + var sessions = new SessionsDAO(db); + + this.isLoggedInMiddleware = function(req, res, next) { + var session_id = req.cookies.session; + sessions.getUsername(session_id, function(err, username) { + "use strict"; + + if (!err && username) { + req.username = username; + } + return next(); + }); + } + + this.displayLoginPage = function(req, res, next) { + "use strict"; + return res.render("login", {username:"", password:"", login_error:""}) + } + + this.handleLoginRequest = function(req, res, next) { + "use strict"; + + var username = req.body.username; + var password = req.body.password; + + console.log("user submitted username: " + username + " pass: " + password); + + users.validateLogin(username, password, function(err, user) { + "use strict"; + + if (err) { + if (err.no_such_user) { + return res.render("login", {username:username, password:"", login_error:"No such user"}); + } + else if (err.invalid_password) { + return res.render("login", {username:username, password:"", login_error:"Invalid password"}); + } + else { + // Some other kind of error + return next(err); + } + } + + sessions.startSession(user['_id'], function(err, session_id) { + "use strict"; + + if (err) return next(err); + + res.cookie('session', session_id); + return res.redirect('/welcome'); + }); + }); + } + + this.displayLogoutPage = function(req, res, next) { + "use strict"; + + var session_id = req.cookies.session; + sessions.endSession(session_id, function (err) { + "use strict"; + + // Even if the user wasn't logged in, redirect to home + res.cookie('session', ''); + return res.redirect('/'); + }); + } + + this.displaySignupPage = function(req, res, next) { + "use strict"; + res.render("signup", {username:"", password:"", + password_error:"", + email:"", username_error:"", email_error:"", + verify_error :""}); + } + + function validateSignup(username, password, verify, email, errors) { + "use strict"; + var USER_RE = /^[a-zA-Z0-9_-]{3,20}$/; + var PASS_RE = /^.{3,20}$/; + var EMAIL_RE = /^[\S]+@[\S]+\.[\S]+$/; + + errors['username_error'] = ""; + errors['password_error'] = ""; + errors['verify_error'] = ""; + errors['email_error'] = ""; + + if (!USER_RE.test(username)) { + errors['username_error'] = "invalid username. try just letters and numbers"; + return false; + } + if (!PASS_RE.test(password)) { + errors['password_error'] = "invalid password."; + return false; + } + if (password != verify) { + errors['verify_error'] = "password must match"; + return false; + } + if (email != "") { + if (!EMAIL_RE.test(email)) { + errors['email_error'] = "invalid email address"; + return false; + } + } + return true; + } + + this.handleSignup = function(req, res, next) { + "use strict"; + + var email = req.body.email + var username = req.body.username + var password = req.body.password + var verify = req.body.verify + + // set these up in case we have an error case + var errors = {'username': username, 'email': email} + if (validateSignup(username, password, verify, email, errors)) { + users.addUser(username, password, email, function(err, user) { + "use strict"; + + if (err) { + // this was a duplicate + if (err.code == '11000') { + errors['username_error'] = "Username already in use. Please choose another"; + return res.render("signup", errors); + } + // this was a different error + else { + return next(err); + } + } + + sessions.startSession(user['_id'], function(err, session_id) { + "use strict"; + + if (err) return next(err); + + res.cookie('session', session_id); + return res.redirect('/welcome'); + }); + }); + } + else { + console.log("user did not validate"); + return res.render("signup", errors); + } + } + + this.displayWelcomePage = function(req, res, next) { + "use strict"; + + if (!req.username) { + console.log("welcome: can't identify user...redirecting to signup"); + return res.redirect("/signup"); + } + + return res.render("welcome", {'username':req.username}) + } +} + +module.exports = SessionHandler; diff --git a/week-2/hw2-3/blog/sessions.js b/week-2/hw2-3/blog/sessions.js new file mode 100644 index 0000000..3af169f --- /dev/null +++ b/week-2/hw2-3/blog/sessions.js @@ -0,0 +1,65 @@ +var crypto = require('crypto'); + +/* The SessionsDAO must be constructed with a connected database object */ +function SessionsDAO(db) { + "use strict"; + + /* If this constructor is called without the "new" operator, "this" points + * to the global object. Log a warning and call it correctly. */ + if (false === (this instanceof SessionsDAO)) { + console.log('Warning: SessionsDAO constructor called without "new" operator'); + return new SessionsDAO(db); + } + + var sessions = db.collection("sessions"); + + this.startSession = function(username, callback) { + "use strict"; + + // Generate session id + var current_date = (new Date()).valueOf().toString(); + var random = Math.random().toString(); + var session_id = crypto.createHash('sha1').update(current_date + random).digest('hex'); + + // Create session document + var session = {'username': username, '_id': session_id} + + // Insert session document + sessions.insert(session, function (err, result) { + "use strict"; + callback(err, session_id); + }); + } + + this.endSession = function(session_id, callback) { + "use strict"; + // Remove session document + sessions.remove({ '_id' : session_id }, function (err, numRemoved) { + "use strict"; + callback(err); + }); + } + this.getUsername = function(session_id, callback) { + "use strict"; + + if (!session_id) { + callback(Error("Session not set"), null); + return; + } + + sessions.findOne({ '_id' : session_id }, function(err, session) { + "use strict"; + + if (err) return callback(err, null); + + if (!session) { + callback(new Error("Session: " + session + " does not exist"), null); + return; + } + + callback(null, session.username); + }); + } +} + +module.exports.SessionsDAO = SessionsDAO; diff --git a/week-2/hw2-3/blog/users.js b/week-2/hw2-3/blog/users.js new file mode 100644 index 0000000..9a93882 --- /dev/null +++ b/week-2/hw2-3/blog/users.js @@ -0,0 +1,68 @@ +var bcrypt = require('bcrypt-nodejs'); + +/* The UsersDAO must be constructed with a connected database object */ +function UsersDAO(db) { + "use strict"; + + /* If this constructor is called without the "new" operator, "this" points + * to the global object. Log a warning and call it correctly. */ + if (false === (this instanceof UsersDAO)) { + console.log('Warning: UsersDAO constructor called without "new" operator'); + return new UsersDAO(db); + } + + var users = db.collection("users"); + + this.addUser = function(username, password, email, callback) { + "use strict"; + + // Generate password hash + var salt = bcrypt.genSaltSync(); + var password_hash = bcrypt.hashSync(password, salt); + + // Create user document + var user = {'_id': username, 'password': password_hash}; + + // Add email if set + if (email != "") { + user['email'] = email; + } + + // TODO: hw2.3 + callback(Error("addUser Not Yet Implemented!"), null); + } + + this.validateLogin = function(username, password, callback) { + "use strict"; + + // Callback to pass to MongoDB that validates a user document + function validateUserDoc(err, user) { + "use strict"; + + if (err) return callback(err, null); + + if (user) { + if (bcrypt.compareSync(password, user.password)) { + callback(null, user); + } + else { + var invalid_password_error = new Error("Invalid password"); + // Set an extra field so we can distinguish this from a db error + invalid_password_error.invalid_password = true; + callback(invalid_password_error, null); + } + } + else { + var no_such_user_error = new Error("User: " + user + " does not exist"); + // Set an extra field so we can distinguish this from a db error + no_such_user_error.no_such_user = true; + callback(no_such_user_error, null); + } + } + + // TODO: hw2.3 + callback(Error("validateLogin Not Yet Implemented!"), null); + } +} + +module.exports.UsersDAO = UsersDAO; diff --git a/week-2/hw2-3/blog/views/blog_template.html b/week-2/hw2-3/blog/views/blog_template.html new file mode 100644 index 0000000..6af803d --- /dev/null +++ b/week-2/hw2-3/blog/views/blog_template.html @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<html> +<head> +<title>My Blog</title> +</head> +<body> + +{% if username %} +Welcome {{username}} <a href="/logout">Logout</a> | <a href="/newpost">New Post</a><p> +{% else %} +You are not logged in! <a href="/login">Login</a> | <a href="/signup">Sign Up</a><p> +{% endif %} + +<h1>My Blog</h1> + +{% for post in myposts %} +<h2><a href="/post/{{post['permalink']}}">{{post['title']}}</a></h2> +Posted {{post['date']}} <i>By {{post['author']}}</i><br> +Comments: +<a href="/post/{{post['permalink']}}">{{post['comments']|length}}</a> +<hr> +{% autoescape false %} +{{post['body']}} +{% endautoescape %} +<p> +<p> +<em>Filed Under</em>: +{% for tag in post.tags %} + {% if loop.first %} + <a href="/tag/{{tag}}">{{tag}}</a> + {% else %} + , <a href="/tag/{{tag}}">{{tag}}</a> + {% endif %} +{% endfor %} +{% endfor %} +<p> +</body> +</html> + + diff --git a/week-2/hw2-3/blog/views/entry_template.html b/week-2/hw2-3/blog/views/entry_template.html new file mode 100644 index 0000000..3f5d2a4 --- /dev/null +++ b/week-2/hw2-3/blog/views/entry_template.html @@ -0,0 +1,54 @@ +<!doctype HTML> +<html +<head> +<title> +Blog Post +</title> +</head> +<body> +{% if username %} +Welcome {{username}} <a href="/logout">Logout</a> | <a href="/newpost">New Post</a><p> +{% else %} +You are not logged in! <a href="/login">Login</a> | <a href="/signup">Sign Up</a><p> +{% endif %} +<a href="/">Blog Home</a><br><br> + +<h2>{{post['title']}}</h2> +Posted {{post['date']}}<i> By {{post['author']}}</i><br> +<hr> +{% autoescape false %} +{{post['body']}} +{% endautoescape %} +<p> +<em>Filed Under</em>: +{% for tag in post.tags %} + {% if loop.first %} + <a href="/tag/{{tag}}">{{tag}}</a> + {% else %} + , <a href="/tag/{{tag}}">{{tag}}</a> + {% endif %} +{% endfor %} +<p> +Comments: +<ul> +{% for comment in post.comments %} +Author: {{comment['author']}}<br> +{{comment['body']}}<br> +<hr> +{% endfor %} +<h3>Add a comment</h3> +<form action="/newcomment" method="POST"> +<input type="hidden" name="permalink", value="{{post['permalink']}}"> +<h4>{{errors}}</h4> +<b>Name</b> (required)<br> +<input type="text" name="commentName" size="60" value="{{comment['name']}}"><br> +<b>Email</b> (optional)<br> +<input type="text" name="commentEmail" size="60" value="{{comment['email']}}"><br> +<b>Comment</b><br> +<textarea name="commentBody" cols="60" rows="10">{{comment['body']}}</textarea><br> +<input type="submit" value="Submit"> +</ul> +</body> +</html> + + diff --git a/week-2/hw2-3/blog/views/error_template.html b/week-2/hw2-3/blog/views/error_template.html new file mode 100644 index 0000000..c37339f --- /dev/null +++ b/week-2/hw2-3/blog/views/error_template.html @@ -0,0 +1,12 @@ +<!doctype HTML> +<html> +<head> +<title>Internal Error</title> +</head> +<body> + +Oops..<br> +{{error}} +</body> +</html> + diff --git a/week-2/hw2-3/blog/views/login.html b/week-2/hw2-3/blog/views/login.html new file mode 100644 index 0000000..4041d5c --- /dev/null +++ b/week-2/hw2-3/blog/views/login.html @@ -0,0 +1,47 @@ +<!DOCTYPE html> + +<html> + <head> + <title>Login</title> + <style type="text/css"> + .label {text-align: right} + .error {color: red} + </style> + + </head> + + <body> + <h2>Login</h2> + <form method="post"> + <table> + <tr> + <td class="label"> + Username + </td> + <td> + <input type="text" name="username" value="{{username}}"> + </td> + <td class="error"> + </td> + </tr> + + <tr> + <td class="label"> + Password + </td> + <td> + <input type="password" name="password" value=""> + </td> + <td class="error"> + {{login_error}} + + </td> + </tr> + + </table> + + <input type="submit"> + </form> + </body> + +</html> diff --git a/week-2/hw2-3/blog/views/newpost_template.html b/week-2/hw2-3/blog/views/newpost_template.html new file mode 100644 index 0000000..bd67f9c --- /dev/null +++ b/week-2/hw2-3/blog/views/newpost_template.html @@ -0,0 +1,29 @@ +<!doctype HTML> +<html> +<head> +<title>Create a new post</title> +</head> +<body> + +{% if username %} +Welcome {{username}} <a href="/logout">Logout</a><p> +{% else %} +You are not logged in! <a href="/login">Login</a> | <a href="/signup">Sign Up</a><p> +{% endif %} +<a href="/">Blog Home</a><br><br> + +<form action="/newpost" method="POST"> +{{errors}} +<h2>Title</h2> +<input type="text" name="subject" size="120" value="{{subject}}"><br> +<h2>Blog Entry<h2> +<textarea name="body" cols="120" rows="20">{{body}}</textarea><br> +<h2>Tags</h2> +Comma separated, please<br> +<input type="text" name="tags" size="120" value="{{tags}}"><br> +<p> +<input type="submit" value="Submit"> + +</body> +</html> + diff --git a/week-2/hw2-3/blog/views/signup.html b/week-2/hw2-3/blog/views/signup.html new file mode 100644 index 0000000..76bee7f --- /dev/null +++ b/week-2/hw2-3/blog/views/signup.html @@ -0,0 +1,75 @@ +<!DOCTYPE html> + +<html> + <head> + <title>Sign Up</title> + <style type="text/css"> + .label {text-align: right} + .error {color: red} + </style> + + </head> + + <body> + Already a user? <a href="/login">Login</a><p> + <h2>Signup</h2> + <form method="post"> + <table> + <tr> + <td class="label"> + Username + </td> + <td> + <input type="text" name="username" value="{{username}}"> + </td> + <td class="error"> + {{username_error}} + + </td> + </tr> + + <tr> + <td class="label"> + Password + </td> + <td> + <input type="password" name="password" value=""> + </td> + <td class="error"> + {{password_error}} + + </td> + </tr> + + <tr> + <td class="label"> + Verify Password + </td> + <td> + <input type="password" name="verify" value=""> + </td> + <td class="error"> + {{verify_error}} + + </td> + </tr> + + <tr> + <td class="label"> + Email (optional) + </td> + <td> + <input type="text" name="email" value="{{email}}"> + </td> + <td class="error"> + {{email_error}} + + </td> + </tr> + </table> + + <input type="submit"> + </form> + </body> + +</html> diff --git a/week-2/hw2-3/blog/views/welcome.html b/week-2/hw2-3/blog/views/welcome.html new file mode 100644 index 0000000..64f5929 --- /dev/null +++ b/week-2/hw2-3/blog/views/welcome.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> + +<html> + <head> + <title>Welcome</title> + <style type="text/css"> + .label {text-align: right} + .error {color: red} + </style> + + </head> + + <body> + Welcome {{username}} +<p> +<ul> +<li><a href="/">Goto Blog Home</a></li> +<li> +<a href="/logout">Logout</a> +</li> +<li> +<a href="/newpost">Create a New Post</a> +</li> + + + </body> + +</html> diff --git a/week-2/hw2-3/validate/README.md b/week-2/hw2-3/validate/README.md new file mode 100644 index 0000000..87d21b6 --- /dev/null +++ b/week-2/hw2-3/validate/README.md @@ -0,0 +1,10 @@ +Validation script for hw2-3 + +To run: + +npm install +node validate.js + +To see extra options (if you are running the blog or mongodb on different hosts or ports): + +node validate.js --help diff --git a/week-2/hw2-3/validate/package.json b/week-2/hw2-3/validate/package.json new file mode 100644 index 0000000..77e5b6c --- /dev/null +++ b/week-2/hw2-3/validate/package.json @@ -0,0 +1,20 @@ +{ + "name": "ta", + "version": "0.0.0", + "description": "ERROR: No README.md file found!", + "main": "validate.js", + "dependencies": { + "bcrypt-nodejs": "~0.0.3", + "commander": "~2.0.0", + "mongodb": "~1.3.18", + "request": "~2.27.0" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": "", + "author": "", + "license": "BSD", + "private": true +} diff --git a/week-2/hw2-3/validate/validate.js b/week-2/hw2-3/validate/validate.js new file mode 100644 index 0000000..6ab1488 --- /dev/null +++ b/week-2/hw2-3/validate/validate.js @@ -0,0 +1 @@ +var _0x2d80=["\x72\x65\x71\x75\x65\x73\x74","\x62\x63\x72\x79\x70\x74\x2D\x6E\x6F\x64\x65\x6A\x73","\x4D\x6F\x6E\x67\x6F\x43\x6C\x69\x65\x6E\x74","\x6D\x6F\x6E\x67\x6F\x64\x62","\x63\x6F\x6D\x6D\x61\x6E\x64\x65\x72","\x63\x72\x79\x70\x74\x6F","\x49\x66\x20\x79\x6F\x75\x20\x61\x72\x65\x20\x6C\x6F\x6F\x6B\x69\x6E\x67\x20\x61\x74\x20\x74\x68\x69\x73\x20\x74\x68\x65\x6E\x20\x53\x48\x41\x4D\x45\x20\x4F\x4E\x20\x59\x4F\x55","\x61\x72\x67\x76","\x70\x61\x72\x73\x65","\x2D\x64\x2C\x20\x2D\x2D\x64\x62\x20\x5B\x63\x6F\x6E\x6E\x65\x63\x74\x69\x6F\x6E\x20\x73\x74\x72\x69\x6E\x67\x5D","\x4D\x6F\x6E\x67\x6F\x44\x42\x20\x64\x61\x74\x61\x62\x61\x73\x65\x20\x63\x6F\x6E\x6E\x65\x63\x74\x69\x6F\x6E\x20\x73\x74\x72\x69\x6E\x67\x2E\x20\x20\x44\x65\x66\x61\x75\x6C\x74\x20\x69\x73\x20\x27\x6D\x6F\x6E\x67\x6F\x64\x62\x3A\x2F\x2F\x6C\x6F\x63\x61\x6C\x68\x6F\x73\x74\x3A\x32\x37\x30\x31\x37\x2F\x62\x6C\x6F\x67\x27","\x6D\x6F\x6E\x67\x6F\x64\x62\x3A\x2F\x2F\x6C\x6F\x63\x61\x6C\x68\x6F\x73\x74\x3A\x32\x37\x30\x31\x37\x2F\x62\x6C\x6F\x67","\x6F\x70\x74\x69\x6F\x6E","\x2D\x70\x2C\x20\x2D\x2D\x70\x6F\x72\x74\x20\x5B\x70\x6F\x72\x74\x5D","\x57\x65\x62\x73\x65\x72\x76\x65\x72\x20\x75\x72\x6C\x2E\x20\x20\x44\x65\x66\x61\x75\x6C\x74\x20\x69\x73\x20\x27\x33\x30\x30\x30\x27","\x2D\x68\x2C\x20\x2D\x2D\x68\x6F\x73\x74\x20\x5B\x68\x6F\x73\x74\x5D","\x57\x65\x62\x73\x65\x72\x76\x65\x72\x20\x68\x6F\x73\x74\x2E\x20\x20\x44\x65\x66\x61\x75\x6C\x74\x20\x69\x73\x20\x27\x6C\x6F\x63\x61\x6C\x68\x6F\x73\x74\x27","\x6C\x6F\x63\x61\x6C\x68\x6F\x73\x74","\x64\x62","\x75\x73\x65\x72\x73","\x63\x6F\x6C\x6C\x65\x63\x74\x69\x6F\x6E","\x73\x65\x73\x73\x69\x6F\x6E\x73","\x6A\x61\x72","\x64\x65\x66\x61\x75\x6C\x74\x73","\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F\x50\x51\x52\x53\x54\x55\x56\x57\x58\x54\x5A\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A","","\x72\x61\x6E\x64\x6F\x6D","\x6C\x65\x6E\x67\x74\x68","\x66\x6C\x6F\x6F\x72","\x73\x75\x62\x73\x74\x72\x69\x6E\x67","\x75\x73\x65\x20\x73\x74\x72\x69\x63\x74","\x70\x61\x73\x73\x77\x6F\x72\x64","\x63\x6F\x6D\x70\x61\x72\x65\x53\x79\x6E\x63","\x65\x6D\x61\x69\x6C","\x45\x6D\x61\x69\x6C\x20\x6E\x6F\x74\x20\x73\x65\x74\x20\x63\x6F\x72\x72\x65\x63\x74\x6C\x79\x20\x69\x6E\x20\x75\x73\x65\x72\x20\x64\x6F\x63\x75\x6D\x65\x6E\x74\x20\x61\x66\x74\x65\x72\x20\x63\x72\x65\x61\x74\x69\x6E\x67\x20\x61\x6E\x20\x61\x63\x63\x6F\x75\x6E\x74\x20\x6F\x6E\x20\x74\x68\x65\x20\x73\x69\x67\x6E\x75\x70\x20\x70\x61\x67\x65","\x50\x61\x73\x73\x77\x6F\x72\x64\x20\x6E\x6F\x74\x20\x73\x65\x74\x20\x63\x6F\x72\x72\x65\x63\x74\x6C\x79\x20\x69\x6E\x20\x75\x73\x65\x72\x20\x64\x6F\x63\x75\x6D\x65\x6E\x74\x20\x61\x66\x74\x65\x72\x20\x63\x72\x65\x61\x74\x69\x6E\x67\x20\x61\x6E\x20\x61\x63\x63\x6F\x75\x6E\x74\x20\x6F\x6E\x20\x74\x68\x65\x20\x73\x69\x67\x6E\x75\x70\x20\x70\x61\x67\x65","\x43\x6F\x75\x6C\x64\x20\x6E\x6F\x74\x20\x66\x69\x6E\x64\x20\x75\x73\x65\x72\x20\x64\x6F\x63\x75\x6D\x65\x6E\x74\x20\x61\x66\x74\x65\x72\x20\x63\x72\x65\x61\x74\x69\x6E\x67\x20\x61\x6E\x20\x61\x63\x63\x6F\x75\x6E\x74\x20\x6F\x6E\x20\x74\x68\x65\x20\x73\x69\x67\x6E\x75\x70\x20\x70\x61\x67\x65","\x66\x69\x6E\x64\x4F\x6E\x65","\x6E\x61\x6D\x65","\x73\x65\x73\x73\x69\x6F\x6E","\x76\x61\x6C\x75\x65","\x53\x65\x73\x73\x69\x6F\x6E\x20\x63\x6F\x6F\x6B\x69\x65\x20\x6E\x6F\x74\x20\x70\x72\x6F\x70\x65\x72\x6C\x79\x20\x73\x65\x74\x20\x61\x66\x74\x65\x72\x20\x6C\x6F\x67\x67\x69\x6E\x67\x20\x69\x6E","\x43\x6F\x75\x6C\x64\x20\x6E\x6F\x74\x20\x66\x69\x6E\x64\x20\x73\x65\x73\x73\x69\x6F\x6E\x20\x64\x6F\x63\x75\x6D\x65\x6E\x74\x20\x61\x66\x74\x65\x72\x20\x6C\x6F\x67\x67\x69\x6E\x67\x20\x69\x6E","\x75\x73\x65\x72\x6E\x61\x6D\x65","\x55\x73\x65\x72\x6E\x61\x6D\x65\x20\x6E\x6F\x74\x20\x73\x65\x74\x20\x70\x72\x6F\x70\x65\x72\x6C\x79\x20\x69\x6E\x20\x73\x65\x73\x73\x69\x6F\x6E\x20\x64\x6F\x63\x75\x6D\x65\x6E\x74\x20\x61\x66\x74\x65\x72\x20\x6C\x6F\x67\x67\x69\x6E\x67\x20\x69\x6E","\x46\x6F\x75\x6E\x64\x20\x73\x65\x73\x73\x69\x6F\x6E\x20\x64\x6F\x63\x75\x6D\x65\x6E\x74\x20\x61\x66\x74\x65\x72\x20\x6C\x6F\x67\x67\x69\x6E\x67\x20\x6F\x75\x74","\x66\x6F\x72\x6D","\x68\x74\x74\x70\x3A\x2F\x2F","\x68\x6F\x73\x74","\x3A","\x70\x6F\x72\x74","\x2F\x73\x69\x67\x6E\x75\x70","\x46\x61\x69\x6C\x65\x64\x20\x74\x6F\x20\x63\x6F\x6E\x6E\x65\x63\x74\x20\x74\x6F\x20\x62\x6C\x6F\x67\x20\x61\x74\x20\x27","\x27\x3A\x20","\x63\x6F\x6F\x6B\x69\x65\x73","\x70\x6F\x73\x74","\x2F\x6C\x6F\x67\x69\x6E","\x2F\x6C\x6F\x67\x6F\x75\x74","\x40","\x2E","\x42\x6C\x6F\x67\x20\x64\x69\x64\x20\x6E\x6F\x74\x20\x76\x61\x6C\x69\x64\x61\x74\x65\x20\x64\x75\x65\x20\x74\x6F\x20\x65\x72\x72\x6F\x72\x20\x63\x72\x65\x61\x74\x69\x6E\x67\x20\x75\x73\x65\x72\x21","\x6C\x6F\x67","\x6D\x65\x73\x73\x61\x67\x65","\x63\x6C\x6F\x73\x65","\x53\x75\x63\x63\x65\x73\x73\x66\x75\x6C\x6C\x79\x20\x63\x72\x65\x61\x74\x65\x64\x20\x75\x73\x65\x72","\x42\x6C\x6F\x67\x20\x64\x69\x64\x20\x6E\x6F\x74\x20\x76\x61\x6C\x69\x64\x61\x74\x65\x20\x64\x75\x65\x20\x74\x6F\x20\x65\x72\x72\x6F\x72\x20\x6C\x6F\x67\x67\x69\x6E\x67\x20\x6F\x75\x74\x21","\x53\x75\x63\x63\x65\x73\x73\x66\x75\x6C\x6C\x79\x20\x6C\x6F\x67\x67\x65\x64\x20\x6F\x75\x74","\x42\x6C\x6F\x67\x20\x64\x69\x64\x20\x6E\x6F\x74\x20\x76\x61\x6C\x69\x64\x61\x74\x65\x20\x64\x75\x65\x20\x74\x6F\x20\x65\x72\x72\x6F\x72\x20\x63\x72\x65\x61\x74\x69\x6E\x67\x20\x6C\x6F\x67\x69\x6E\x20\x73\x65\x73\x73\x69\x6F\x6E\x21","\x53\x75\x63\x63\x65\x73\x73\x66\x75\x6C\x6C\x79\x20\x6C\x6F\x67\x67\x65\x64\x20\x69\x6E","\x42\x6C\x6F\x67\x20\x76\x61\x6C\x69\x64\x61\x74\x65\x64\x20\x73\x75\x63\x63\x65\x73\x73\x66\x75\x6C\x6C\x79\x21","\x61\x65\x73\x32\x35\x36","\x63\x72\x65\x61\x74\x65\x44\x65\x63\x69\x70\x68\x65\x72","\x68\x65\x78","\x75\x74\x66\x38","\x75\x70\x64\x61\x74\x65","\x66\x69\x6E\x61\x6C","\x59\x6F\x75\x72\x20\x76\x61\x6C\x69\x64\x61\x74\x69\x6F\x6E\x20\x63\x6F\x64\x65\x20\x69\x73\x3A\x20","\x66\x30\x33\x63\x64\x64\x62\x30\x35\x36\x34\x35\x35\x65\x63\x33\x62\x61\x66\x62\x30\x65\x30\x39\x32\x66\x30\x33\x33\x39\x30\x30\x61\x31\x61\x63\x66\x33\x31\x38\x36\x35\x38\x30\x66\x38\x36\x38\x37\x37\x64\x33\x34\x39\x35\x66\x31\x63\x34\x31\x38\x37\x35\x36","\x50\x32\x38\x31\x55\x6D\x47\x68\x71\x78\x31\x4E\x69\x47\x71\x4F\x67\x4D\x38\x37","\x63\x6F\x6E\x6E\x65\x63\x74"];var request=require(_0x2d80[0]);var bcrypt=require(_0x2d80[1]);var MongoClient=require(_0x2d80[3])[_0x2d80[2]];var program=require(_0x2d80[4]);var crypto=require(_0x2d80[5]);var reprimand=_0x2d80[6];program[_0x2d80[12]](_0x2d80[15],_0x2d80[16],_0x2d80[17])[_0x2d80[12]](_0x2d80[13],_0x2d80[14],3000)[_0x2d80[12]](_0x2d80[9],_0x2d80[10],_0x2d80[11])[_0x2d80[8]](process[_0x2d80[7]]);MongoClient[_0x2d80[79]](program[_0x2d80[18]],function (_0x9596x7,_0x9596x8){if(_0x9596x7){throw _0x9596x7;} ;var _0x9596x9=_0x9596x8[_0x2d80[20]](_0x2d80[19]);var _0x9596xa=_0x9596x8[_0x2d80[20]](_0x2d80[21]);var _0x9596xb=request[_0x2d80[22]]();request=request[_0x2d80[23]]({"\x6A\x61\x72":_0x9596xb});function _0x9596xc(_0x9596xd){var _0x9596xe=_0x2d80[24];_0x9596xd=_0x9596xd?_0x9596xd:32;var _0x9596xf=_0x2d80[25];for(var _0x9596x10=0;_0x9596x10<_0x9596xd;_0x9596x10++){var _0x9596x11=Math[_0x2d80[28]](Math[_0x2d80[26]]()*_0x9596xe[_0x2d80[27]]);_0x9596xf+=_0x9596xe[_0x2d80[29]](_0x9596x11,_0x9596x11+1);} ;return _0x9596xf;} ;function _0x9596x12(_0x9596x13,_0x9596x14,_0x9596x15,_0x9596x16){_0x9596x9[_0x2d80[37]]({"\x5F\x69\x64":_0x9596x13},function (_0x9596x7,_0x9596x17){_0x2d80[30];if(_0x9596x7){return _0x9596x16(_0x9596x7,null);} ;if(_0x9596x17){if(bcrypt[_0x2d80[32]](_0x9596x14,_0x9596x17[_0x2d80[31]])){if(_0x9596x17[_0x2d80[33]]!=_0x9596x15){_0x9596x16( new Error(_0x2d80[34]));} else {_0x9596x16(null);} ;} else {_0x9596x16( new Error(_0x2d80[35]));} ;} else {_0x9596x16( new Error(_0x2d80[36]));} ;} );} ;function _0x9596x18(_0x9596x13,_0x9596x19,_0x9596x16){_0x2d80[30];var _0x9596x1a;for(var _0x9596x10=0;_0x9596x10<_0x9596x19[_0x2d80[27]];_0x9596x10++){if(_0x9596x19[_0x9596x10][_0x2d80[38]]===_0x2d80[39]){_0x9596x1a=_0x9596x19[_0x9596x10][_0x2d80[40]];} ;} ;if(!_0x9596x1a){_0x9596x16(Error(_0x2d80[41]));return ;} ;_0x9596xa[_0x2d80[37]]({"\x5F\x69\x64":_0x9596x1a},function (_0x9596x7,_0x9596x1b){if(_0x9596x7){return _0x9596x16(_0x9596x7);} ;if(!_0x9596x1b){_0x9596x16( new Error(_0x2d80[42]));return ;} ;if(_0x9596x1b[_0x2d80[43]]!=_0x9596x13){_0x9596x16( new Error(_0x2d80[44]));return ;} ;_0x9596x16(null);} );} ;function _0x9596x1c(_0x9596x1a,_0x9596x16){_0x2d80[30];_0x9596xa[_0x2d80[37]]({"\x5F\x69\x64":_0x9596x1a},function (_0x9596x7,_0x9596x1b){if(_0x9596x7){return _0x9596x16(_0x9596x7);} ;if(_0x9596x1b){_0x9596x16( new Error(_0x2d80[45]));return ;} ;_0x9596x16(null);} );} ;function _0x9596x1d(_0x9596x13,_0x9596x14,_0x9596x15,_0x9596x16){request[_0x2d80[55]](_0x2d80[47]+program[_0x2d80[48]]+_0x2d80[49]+program[_0x2d80[50]]+_0x2d80[51],function (_0x9596x1e,_0x9596x1f,_0x9596x20){if(_0x9596x1e){return _0x9596x16(Error(_0x2d80[52]+program[_0x2d80[48]]+_0x2d80[49]+program[_0x2d80[50]]+_0x2d80[53]+_0x9596x1e.toString()));} ;_0x9596x12(_0x9596x13,_0x9596x14,_0x9596x15,function (_0x9596x7){if(_0x9596x7){return _0x9596x16(_0x9596x7);} ;_0x9596x18(_0x9596x13,_0x9596xb[_0x2d80[54]],_0x9596x16);} );} )[_0x2d80[46]]({"\x75\x73\x65\x72\x6E\x61\x6D\x65":_0x9596x13,"\x70\x61\x73\x73\x77\x6F\x72\x64":_0x9596x14,"\x76\x65\x72\x69\x66\x79":_0x9596x14,"\x65\x6D\x61\x69\x6C":_0x9596x15});} ;function _0x9596x21(_0x9596x13,_0x9596x14,_0x9596x16){request[_0x2d80[55]](_0x2d80[47]+program[_0x2d80[48]]+_0x2d80[49]+program[_0x2d80[50]]+_0x2d80[56],function (_0x9596x1e,_0x9596x1f,_0x9596x20){if(_0x9596x1e){return _0x9596x16(Error(_0x2d80[52]+program[_0x2d80[48]]+_0x2d80[49]+program[_0x2d80[50]]+_0x2d80[53]+_0x9596x1e.toString()));} ;_0x9596x18(_0x9596x13,_0x9596xb[_0x2d80[54]],_0x9596x16);} )[_0x2d80[46]]({"\x75\x73\x65\x72\x6E\x61\x6D\x65":_0x9596x13,"\x70\x61\x73\x73\x77\x6F\x72\x64":_0x9596x14});} ;function _0x9596x22(_0x9596x16){var _0x9596x1a;for(var _0x9596x10=0;_0x9596x10<_0x9596xb[_0x2d80[54]][_0x2d80[27]];_0x9596x10++){if(_0x9596xb[_0x2d80[54]][_0x9596x10][_0x2d80[38]]===_0x2d80[39]){_0x9596x1a=_0x9596xb[_0x2d80[54]][_0x9596x10][_0x2d80[40]];} ;} ;request(_0x2d80[47]+program[_0x2d80[48]]+_0x2d80[49]+program[_0x2d80[50]]+_0x2d80[57],function (_0x9596x1e,_0x9596x1f,_0x9596x20){if(_0x9596x1e){return _0x9596x16(Error(_0x2d80[52]+program[_0x2d80[48]]+_0x2d80[49]+program[_0x2d80[50]]+_0x2d80[53]+_0x9596x1e.toString()));} ;_0x9596x1c(_0x9596x1a,_0x9596x16);} );} ;var _0x9596x13=_0x9596xc(20);var _0x9596x14=_0x9596xc(10);var _0x9596x15=_0x9596xc(10)+_0x2d80[58]+_0x9596xc(5)+_0x2d80[59]+_0x9596xc(3);_0x9596x1d(_0x9596x13,_0x9596x14,_0x9596x15,function (_0x9596x7){if(_0x9596x7){console[_0x2d80[61]](_0x2d80[60]);console[_0x2d80[61]](_0x9596x7[_0x2d80[62]]);return _0x9596x8[_0x2d80[63]]();} ;console[_0x2d80[61]](_0x2d80[64]);_0x9596x22(function (_0x9596x7){if(_0x9596x7){console[_0x2d80[61]](_0x2d80[65]);console[_0x2d80[61]](_0x9596x7[_0x2d80[62]]);return _0x9596x8[_0x2d80[63]]();} ;console[_0x2d80[61]](_0x2d80[66]);_0x9596x21(_0x9596x13,_0x9596x14,function (_0x9596x7){if(_0x9596x7){console[_0x2d80[61]](_0x2d80[67]);console[_0x2d80[61]](_0x9596x7[_0x2d80[62]]);return _0x9596x8[_0x2d80[63]]();} else {console[_0x2d80[61]](_0x2d80[68]);console[_0x2d80[61]](_0x2d80[69]);function _0x9596x23(_0x9596x24,_0x9596x25){var _0x9596x26=_0x2d80[70];var _0x9596x27=crypto[_0x2d80[71]](_0x9596x26,_0x9596x25);var _0x9596x28=_0x9596x27[_0x2d80[74]](_0x9596x24,_0x2d80[72],_0x2d80[73])+_0x9596x27[_0x2d80[75]](_0x2d80[73]);return _0x9596x28;} ;console[_0x2d80[61]](_0x2d80[76]+_0x9596x23(_0x2d80[77],_0x2d80[78]));} ;_0x9596x8[_0x2d80[63]]();} );} );} );} ); |
