Repository: shoumma/ReForum Branch: master Commit: f4b209b579f1 Files: 126 Total size: 634.6 KB Directory structure: gitextract_bfqsak_0/ ├── .babelrc ├── .editorconfig ├── .eslintrc ├── .gitignore ├── LICENSE ├── README.md ├── backend/ │ ├── dev.js │ ├── entities/ │ │ ├── admin/ │ │ │ ├── api.js │ │ │ └── controller.js │ │ ├── discussion/ │ │ │ ├── api.js │ │ │ ├── controller.js │ │ │ └── model.js │ │ ├── forum/ │ │ │ ├── api.js │ │ │ ├── controller.js │ │ │ └── model.js │ │ ├── opinion/ │ │ │ ├── api.js │ │ │ ├── controller.js │ │ │ └── model.js │ │ └── user/ │ │ ├── api.js │ │ ├── controller.js │ │ └── model.js │ ├── express.js │ ├── mockData/ │ │ ├── discussions.js │ │ ├── forum.js │ │ ├── opinions.js │ │ └── users.js │ ├── passport.js │ ├── routes.js │ └── utilities/ │ └── tools.js ├── config/ │ ├── credentials.js │ ├── serverConfig.js │ ├── webpack.dev.config.js │ └── webpack.prod.config.js ├── docs/ │ ├── api.md │ └── system_overview.md ├── frontend/ │ ├── App/ │ │ ├── Admin.js │ │ ├── App.js │ │ ├── actions.js │ │ ├── api.js │ │ ├── constants.js │ │ ├── index.js │ │ ├── reducers.js │ │ ├── store.js │ │ └── styles.css │ ├── Components/ │ │ ├── Button/ │ │ │ ├── index.js │ │ │ └── styles.css │ │ ├── Dashboard/ │ │ │ ├── Counts/ │ │ │ │ ├── index.js │ │ │ │ └── styles.css │ │ │ └── ForumBox/ │ │ │ ├── index.js │ │ │ └── styles.css │ │ ├── FeedBox/ │ │ │ ├── DiscussionBox/ │ │ │ │ ├── index.js │ │ │ │ └── styles.css │ │ │ ├── index.js │ │ │ └── styles.css │ │ ├── Footer/ │ │ │ ├── index.js │ │ │ └── styles.css │ │ ├── Header/ │ │ │ ├── Logo/ │ │ │ │ ├── index.js │ │ │ │ └── styles.css │ │ │ ├── NavigationBar/ │ │ │ │ ├── index.js │ │ │ │ └── styles.css │ │ │ └── UserMenu/ │ │ │ ├── index.js │ │ │ └── styles.css │ │ ├── NewDiscussion/ │ │ │ ├── PinButton/ │ │ │ │ ├── index.js │ │ │ │ └── styles.css │ │ │ └── TagsInput/ │ │ │ ├── index.js │ │ │ └── styles.css │ │ ├── RichEditor/ │ │ │ ├── BlockStyleControls.js │ │ │ ├── InlineStyleControls.js │ │ │ ├── StyleButton.js │ │ │ ├── index.js │ │ │ └── styles.css │ │ ├── SideBar/ │ │ │ ├── index.js │ │ │ └── styles.css │ │ ├── SingleDiscussion/ │ │ │ ├── Discussion/ │ │ │ │ ├── index.js │ │ │ │ └── styles.css │ │ │ ├── Opinion/ │ │ │ │ ├── index.js │ │ │ │ └── styles.css │ │ │ └── ReplyBox/ │ │ │ ├── index.js │ │ │ └── styles.css │ │ ├── Tag/ │ │ │ ├── index.js │ │ │ └── styles.css │ │ └── UserProfile/ │ │ └── Profile/ │ │ ├── index.js │ │ └── styles.css │ ├── Containers/ │ │ ├── AdminHeader/ │ │ │ ├── index.js │ │ │ └── styles.css │ │ └── Header/ │ │ ├── index.js │ │ └── styles.css │ ├── SharedStyles/ │ │ ├── appLayout.css │ │ └── globalStyles.css │ └── Views/ │ ├── AdminDashboard/ │ │ ├── actions.js │ │ ├── api.js │ │ ├── constants.js │ │ ├── index.js │ │ ├── reducers.js │ │ └── styles.css │ ├── ForumFeed/ │ │ ├── actions.js │ │ ├── api.js │ │ ├── constants.js │ │ ├── index.js │ │ ├── reducers.js │ │ ├── styles.css │ │ └── tests/ │ │ └── actions.test.js │ ├── NewDiscussion/ │ │ ├── actions.js │ │ ├── api.js │ │ ├── constants.js │ │ ├── index.js │ │ ├── reducers.js │ │ └── styles.css │ ├── NotFound/ │ │ └── index.js │ ├── SingleDiscussion/ │ │ ├── actions.js │ │ ├── api.js │ │ ├── constants.js │ │ ├── index.js │ │ ├── reducers.js │ │ └── styles.css │ └── UserProfile/ │ ├── actions.js │ ├── api.js │ ├── constants.js │ ├── index.js │ ├── reducers.js │ └── styles.css ├── package.json ├── public/ │ ├── build/ │ │ ├── bundle.js │ │ └── style.css │ └── index.html └── server.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .babelrc ================================================ { "presets": [ "es2015", "stage-2", "react" ] } ================================================ FILE: .editorconfig ================================================ [*] indent_style = space end_of_line = lf indent_size = 2 charset = utf-8 trim_trailing_whitespace = true [*.md] max_line_length = 0 trim_trailing_whitespace = false ================================================ FILE: .eslintrc ================================================ { "ecmaFeatures": { "jsx": true, "modules": true }, "env": { "browser": true, "node": true }, "parser": "babel-eslint", "rules": { "comma-dangle": ["error", "always-multiline"], "semi": ["error", "always"], "quotes": [2, "single"], "strict": [2, "never"], "react/jsx-uses-react": 2, "react/jsx-uses-vars": 2, "react/react-in-jsx-scope": 2 }, "plugins": [ "react" ] } ================================================ FILE: .gitignore ================================================ # dependency node_modules # yarn yarn.lock # npm cache .npm # Logs logs *.log npm-debug.log* # coverages coverage # OSX stuffs .DS_Store ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2016 Provash Shoumma 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. ================================================ FILE: README.md ================================================ ![logo](./docs/design_assets/logo.png) # ReForum A minimal forum application built with the following technologies: * [React](https://facebook.github.io/react/) * [Redux](http://redux.js.org/) * [Webpack](https://webpack.js.org/) * [ExpressJS](https://expressjs.com/) * [PassportJS](http://passportjs.org/) * [MongoDB](https://www.mongodb.com/) ### Application Features * Users can post a discussion * Users can reply their opinions regarding discussion * Users can favorite discussions * Users have their own profile page * Admin can create new forum categories * Admin have a lot of power over every users discussions and opinions :-p ### Documentations * [API Docs](https://github.com/shoumma/ReForum/blob/master/docs/api.md) * [System Overview](https://github.com/shoumma/ReForum/blob/master/docs/system_overview.md) ### Home View ![home view](./docs/design_assets/home_view.jpg) ### Admin View ![admin view](./docs/design_assets/admin_view.jpg) ## Deploy on you own server Please make sure you have following software installed in your system: * Node.js > 6.0 * NPM / Yarn * Git * MongoDB First we need to clone the repository: ``` $ git clone https://github.com/shoumma/ReForum ``` Then we have to install the necessary dependencies using either NPM or Yarn: ``` $ npm i ``` ``` $ yarn ``` Since the app currently uses GitHub authentication, we need to configure a GitHub OAuth application. You can register a new application from this link https://github.com/settings/developers We need to grab the following information from the OAuth application. * Client ID * Client Secret * Callback URL The `Callback URL` is the domain where GitHub will redirect the user after a successful login. You can use a domain name or local host. But we need to append the URL with the path `/api/user/authViaGitHub/callback`. So, the complete url will look like: `https://localhost:8080/api/user/authViaGitHub/callback` Now, we need to configure the credentials inside of the codebase. Open the file `config/credentials.js` add the necessary information. The file looks like this: ```js module.exports = { GITHUB_CLIENT_ID: '', GITHUB_CLIENT_SECRET: '', GITHUB_CALLBACK_URL: '', DBURL: '', }; ``` We need to provide all the information here. You can notice that we need the database url here too. My `local` MongoDB url looks like: ``` mongodb://localhost:27017/reforum ``` Now we are ready to run the application. You can run either run the development environment of the application which will include Hot-Reload for JS codes using Webpack and the Redux dev tool extension, or you can run the production edition. The default port for developer edition is `8080`, and for production is `process.env.PORT`. To run the app in development environment: ``` $ npm run start:dev ``` To run the app in production environment: ``` $ npm run start ``` Now, if you visit [http://localhost:8080](http://localhost:8080) (if you ran the dev), or the production URL, you will see that the application is up and running. Congratulation! But, wait a minute, it's showing you `Sorry, couldn't find the forum`. That is because, we didn't create any forum yet. You can now sign up via github and then visit the admin panel with the url [http://localhost:8080/admin](http://localhost:8080/admin). The application is currently configured in a way that, the first user will become the admin for the system. Here we can create new forums and that forum will be displayed in the application. The first forum will be used as default forum. Congratulation! You now have a clone of this application in your server. :-) ## Path for Future Work * Add search functionality * Add unit tests for both backend and frontend * Ability to change the name and logo of the site from admin panel. * Make the installation process more interactive * Add multiple theme support. ## License [MIT License](https://github.com/shoumma/Mister-Poster/blob/master/LICENSE). Do whatever you want to do. :-) ## Conclusion The application is created with lots of ♥. Any pull request, issues and contribution is very appreciated. It would be really great if we can take this application to the next level, where it can be used as a platform for forums. [Provash Shoumma](https://twitter.com/proshoumma) ================================================ FILE: backend/dev.js ================================================ /** * module dependencies for development */ const webpack = require('webpack'); const webpackDevMiddleware = require('webpack-dev-middleware'); const webpackHotMiddleware = require('webpack-hot-middleware'); /** * development configuration */ const devConfigs = (app) => { // webpack development configuration const webpackConfig = require('../config/webpack.dev.config'); const webpackCompiler = webpack(webpackConfig); // apply dev middleware app.use(webpackDevMiddleware(webpackCompiler, { publicPath: webpackConfig.output.publicPath, hot: true, stats: true, })); // apply hot middleware app.use(webpackHotMiddleware(webpackCompiler)); }; module.exports = devConfigs; ================================================ FILE: backend/entities/admin/api.js ================================================ // controllers const getAdminDashInfo = require('./controller').getAdminDashInfo; const createForum = require('./controller').createForum; const deleteForum = require('./controller').deleteForum; const deleteUser = require('./controller').deleteUser; const deleteDiscussion = require('./controller').deleteDiscussion; /** * admin apis * @param {Object} app */ const adminAPI = (app) => { // get all info for admin dashboard app.get('/api/admin/admin_dashboard_info', (req, res) => { if (req.user && req.user.role === 'admin') { getAdminDashInfo().then( (data) => { res.send(data); }, (error) => { res.send(error); } ); } else res.send({ error: 'You are not admin buddy 😛' }); }); // create a forum app.post('/api/admin/create_forum', (req, res) => { if (req.user && req.user.role === 'admin') { const { title, slug, } = req.body; createForum({ forum_name: title, forum_slug: slug }).then( (data) => { res.send(data); }, (error) => { res.send(error); } ); } else res.send({ error: 'You are not admin buddy 😛' }); }); // delete a forum app.post('/api/admin/delete_forum', (req, res) => { if (req.user && req.user.role === 'admin') { deleteForum(req.body).then( (data) => { res.send(data); }, (error) => { res.send(error); } ); } else res.send({ error: 'You are not admin buddy 😛' }); }); // delete an user app.post('/api/admin/delete_user', (req, res) => { if (req.user && req.user.role === 'admin') { deleteUser(req.body).then( (data) => { res.send(data); }, (error) => { res.send(error); } ); } else res.send({ error: 'You are not admin buddy 😛' }); }); // delete a discussion app.post('/api/admin/delete_discussion', (req, res) => { if (req.user && req.user.role === 'admin') { deleteDiscussion(req.body).then( (data) => { res.send(data); }, (error) => { res.send(error); } ); } else res.send({ error: 'You are not admin buddy 😛' }); }); }; module.exports = adminAPI; ================================================ FILE: backend/entities/admin/controller.js ================================================ const waterfall = require('async/waterfall'); // models const Discussion = require('../discussion/model'); const Opinion = require('../opinion/model'); const Forum = require('../forum/model'); const User = require('../user/model'); /** * get the information for admin dashboard * @return {Promise} */ const getAdminDashInfo = () => { return new Promise((resolve, reject) => { waterfall([ (callback) => { Discussion.count().exec((error, count) => { callback(null, { discussionCount: count }); }); }, (lastResult, callback) => { Opinion.count().exec((error, count) => { callback(null, Object.assign(lastResult, { opinionCount: count })); }); }, (lastResult, callback) => { Forum.count().exec((error, count) => { callback(null, Object.assign(lastResult, { forumCount: count })); }); }, (lastResult, callback) => { User.count().exec((error, count) => { callback(null, Object.assign(lastResult, { userCount: count })); }); }, (lastResult, callback) => { Forum .find({}) .sort({ date: -1 }) .lean() .exec((error, forums) => { callback(null, Object.assign(lastResult, { forums })); }); }, ], (error, result) => { if (error) { console.log(error); reject(error); } else resolve(result); }); }); }; /** * create a new forum * @param {String} forum_name * @param {String} forum_slug * @return {Promise} */ const createForum = ({ forum_name, forum_slug }) => { return new Promise((resolve, reject) => { // check if the forum exists Forum .findOne({ forum_slug }) .exec((error, forum) => { if (error) { console.log(error); reject({ serverError: true }); } else if (forum) { reject({ alreadyExists: true }); } else { // forum does not exists, so create a new one const newForum = new Forum({ forum_slug, forum_name, }); newForum.save((error) => { if (error) { console.log(error); reject({ created: false }); } else { resolve(Object.assign({}, newForum, { created: true })); } }); } }); }); }; /** * delete an entire forum * @param {String} forum_id * @return {Promise} */ const deleteForum = ({ forum_id }) => { return new Promise((resolve, reject) => { // first remove any discussion regarding the forum Discussion.remove({ forum_id }).exec((error) => { if (error) { console.log(error); reject({ deleted: false }); } else { // remove any opinion regarding the forum Opinion.remove({ forum_id }).exec((error) => { if (error) { console.log(error); reject({ deleted: false }); } else { // now we can remove the forum Forum.remove({ _id: forum_id }).exec((error) => { if (error) { console.log(error); reject({ deleted: false }); } else { resolve({ deleted: true }); } }); } }); } }); }); }; /** * delete an user * @param {String} user_id * @return {Promise} */ const deleteUser = ({ user_id }) => { return new Promise((resolve, reject) => { // first we need to remvoe any discussion the user created Discussion.remove({ user_id }).exec((error) => { if (error) { console.log(error); reject({ deleted: false }); } else { // now we need to remove any opinions that are created by the user Opinion.remove({ user_id }).exec((error) => { if (error) { console.log(error); reject({ deleted: false }); } else { // finally we can remove the user User.remove({ _id: user_id }).exec((error) => { if (error) { console.log(error); reject({ deleted: false }); } else { resolve({ deleted: true }); } }); } }); } }); }); }; /** * delete a single discussion * @param {String} discussion_id * @return {Promise} */ const deleteDiscussion = ({ discussion_id }) => { return new Promise((resolve, reject) => { // first we need to remove any opinion regarding the discussion Opinion.remove({ discussion_id }).exec((error) => { if (error) { console.log(error); reject({ deleted: false }); } else { // now we need to remove the discussion Discussion.remove({ _id: discussion_id }).exec((error) => { if (error) { console.log(error); reject({ deleted: false }); } else { resolve({ deleted: true }); } }); } }); }); }; module.exports = { getAdminDashInfo, createForum, deleteForum, deleteUser, deleteDiscussion, }; ================================================ FILE: backend/entities/discussion/api.js ================================================ // discussion controllers const getDiscussion = require('./controller').getDiscussion; const createDiscussion = require('./controller').createDiscussion; const toggleFavorite = require('./controller').toggleFavorite; const deleteDiscussion = require('./controller').deleteDiscussion; /** * discussion apis */ const discussionAPI = (app) => { // get signle discussion app.get('/api/discussion/:discussion_slug', (req, res) => { const { discussion_slug } = req.params; getDiscussion(discussion_slug).then( (result) => { res.send(result); }, (error) => { res.send(error); } ); }); // toggle favorite to the discussion app.put('/api/discussion/toggleFavorite/:discussion_id', (req, res) => { const { discussion_id } = req.params; if (req.user) { // TODO: describe the toggle process with comments toggleFavorite(discussion_id, req.user._id).then( (result) => { getDiscussion(result.discussion_slug).then( (result) => { res.send(result); }, (error) => { res.send({ discussionUpdated: false }); } ); }, (error) => { res.send({ discussionUpdated: false }); } ); } else { res.send({ discussionUpdated: false }); } }); // create a new discussion app.post('/api/discussion/newDiscussion', (req, res) => { if (req.user) { createDiscussion(req.body).then( (result) => { res.send(Object.assign({}, result._doc, { postCreated: true })); }, (error) => { res.send({ postCreated: false }); } ); } else { res.send({ postCreated: false }); } }); // delete a discussion app.delete('/api/discussion/deleteDiscussion/:discussion_slug', (req, res) => { if (req.user) { deleteDiscussion(req.params.discussion_slug).then( (result) => { res.send({ deleted: true }); }, (error) => { res.send({ deleted: false }); } ); } else { res.send({ deleted: false }); } }); }; module.exports = discussionAPI; ================================================ FILE: backend/entities/discussion/controller.js ================================================ const generateDiscussionSlug = require('../../utilities/tools').generateDiscussionSlug; const getAllOpinions = require('../opinion/controller').getAllOpinions; const getUser = require('../user/controller').getUser; const Discussion = require('./model'); const Opinion = require('../opinion/model'); /** * get a single discussion * @param {String} discussion_slug * @param {String} discussion_id * @return {Promise} */ const getDiscussion = (discussion_slug, discussion_id) => { return new Promise((resolve, reject) => { let findObject = {}; if (discussion_slug) findObject.discussion_slug = discussion_slug; if (discussion_id) findObject._id = discussion_id; Discussion .findOne(findObject) .populate('forum') .populate('user') .lean() .exec((error, result) => { if (error) { console.log(error); reject(error); } else if (!result) reject(null); else { // add opinions to the discussion object getAllOpinions(result._id).then( (opinions) => { result.opinions = opinions; resolve(result); }, (error) => { { console.log(error); reject(error); } } ); } }); }); }; /** * Create a new discussion * @param {Object} discussion * @return {Promise} */ const createDiscussion = (discussion) => { return new Promise((resolve, reject) => { const newDiscussion = new Discussion({ forum_id: discussion.forumId, forum: discussion.forumId, user_id: discussion.userId, user: discussion.userId, discussion_slug: generateDiscussionSlug(discussion.title), date: new Date(), title: discussion.title, content: discussion.content, favorites: [], tags: discussion.tags, pinned: discussion.pinned, }); newDiscussion.save((error) => { if (error) { console.log(error); reject(error); } resolve(newDiscussion); }); }); }; /** * toggle favorite status of discussion * @param {ObjectId} discussion_id * @param {ObjectId} user_id * @return {Promise} */ const toggleFavorite = (discussion_id, user_id) => { return new Promise((resolve, reject) => { Discussion.findById(discussion_id, (error, discussion) => { if (error) { console.log(error); reject(error); } else if (!discussion) reject(null); else { // add or remove favorite let matched = null; for (let i = 0; i < discussion.favorites.length; i++) { if (String(discussion.favorites[i]) === String(user_id)) { matched = i; } } if (matched === null) { discussion.favorites.push(user_id); } else { discussion.favorites = [ ...discussion.favorites.slice(0, matched), ...discussion.favorites.slice(matched + 1, discussion.favorites.length), ]; } discussion.save((error, updatedDiscussion) => { if (error) { console.log(error); reject(error); } resolve(updatedDiscussion); }); } }); }); }; const updateDiscussion = (forum_id, discussion_slug) => { // TODO: implement update feature }; const deleteDiscussion = (discussion_slug) => { return new Promise((resolve, reject) => { // find the discussion id first Discussion .findOne({ discussion_slug }) .exec((error, discussion) => { if (error) { console.log(error); reject(error); } // get the discussion id const discussion_id = discussion._id; // remove any opinion regarding the discussion Opinion .remove({ discussion_id }) .exec((error) => { if (error) { console.log(error); reject(error); } // finally remove the discussion else { Discussion .remove({ discussion_slug }) .exec((error) => { if (error) { console.log(error); reject(error); } else { resolve({ deleted: true }); } }); } }); }); }); }; module.exports = { getDiscussion, createDiscussion, updateDiscussion, deleteDiscussion, toggleFavorite, }; ================================================ FILE: backend/entities/discussion/model.js ================================================ /** * discussion model */ const mongoose = require('mongoose'); const discussionSchema = mongoose.Schema({ forum_id: mongoose.Schema.ObjectId, forum: { type: mongoose.Schema.ObjectId, ref: 'forum' }, discussion_slug: String, user_id: mongoose.Schema.ObjectId, user: { type: mongoose.Schema.ObjectId, ref: 'user' }, date: Date, title: String, content: Object, favorites: Array, tags: Array, pinned: Boolean, }); module.exports = mongoose.model('discussion', discussionSchema); ================================================ FILE: backend/entities/forum/api.js ================================================ // forum controllers const getAllForums = require('./controller').getAllForums; const getDiscussions = require('./controller').getDiscussions; /** * forum apis */ const forumAPI = (app) => { // get all forums app.get('/api/forum', (req, res) => { getAllForums().then( (result) => { res.send(result); }, (error) => { res.send(error); } ); }); // get discussions of a forum app.get('/api/forum/:forum_id/discussions', (req, res) => { getDiscussions(req.params.forum_id, false, req.query.sorting_method).then( (result) => { res.send(result); }, (error) => { res.send([]); } ); }); // get pinned discussions of a forum app.get('/api/forum/:forum_id/pinned_discussions', (req, res) => { getDiscussions(req.params.forum_id, true).then( (result) => { res.send(result); }, (error) => { res.send([]); } ); }); }; module.exports = forumAPI; ================================================ FILE: backend/entities/forum/controller.js ================================================ const asyncEach = require('async/each'); // models const Forum = require('./model'); const Discussion = require('../discussion/model'); // controllers const getAllOpinions = require('../opinion/controller').getAllOpinions; const getUser = require('../user/controller').getUser; /** * get all forums list * @type {Promise} */ const getAllForums = () => { return new Promise((resolve, reject) => { Forum .find({}) .exec((error, results) => { if (error) { console.log(error); reject(error); } else if (!results) reject(null); else resolve(results); }); }); }; /** * get discussions of a forum * @param {ObjectId} forum_id * @param {Boolean} pinned * @return {Promise} */ const getDiscussions = (forum_id, pinned, sorting_method='date') => { return new Promise((resolve, reject) => { // define sorthing method const sortWith = { }; if (sorting_method === 'date') sortWith.date = -1; if (sorting_method === 'popularity') sortWith.favorites = -1; // match discussion id and pinned status Discussion .find({ forum_id: forum_id, pinned: pinned }) .sort(sortWith) .populate('forum') .populate('user') .lean() .exec((error, discussions) => { if (error) { console.error(error); reject(error); } else if (!discussions) reject(null); else { // attach opinion count to each discussion asyncEach(discussions, (eachDiscussion, callback) => { // add opinion count getAllOpinions(eachDiscussion._id).then( (opinions) => { // add opinion count to discussion doc eachDiscussion.opinion_count = opinions ? opinions.length : 0; callback(); }, (error) => { console.error(error); callback(error); } ); }, (error) => { if (error) { console.error(error); reject(error); } else resolve(discussions); }); } }); }); }; module.exports = { getAllForums, getDiscussions, }; ================================================ FILE: backend/entities/forum/model.js ================================================ /** * forum model */ const mongoose = require('mongoose'); const forumSchema = mongoose.Schema({ forum_slug: String, forum_name: String, }); module.exports = mongoose.model('forum', forumSchema); ================================================ FILE: backend/entities/opinion/api.js ================================================ // controllers const getAllOpinions = require('./controller').getAllOpinions; const createOpinion = require('./controller').createOpinion; const deleteOpinion = require('./controller').deleteOpinion; /** * opinion apis */ const opinionAPI = (app) => { // create an opinion app.post('/api/opinion/newOpinion', (req, res) => { if(req.user) { createOpinion(req.body).then( (result) => { res.send(result); }, (error) => { res.send(error); } ); } else { res.send({ authenticated: false }); } }); // remove an opinion app.delete('/api/opinion/deleteOpinion/:opinion_id', (req, res) => { if(req.user) { deleteOpinion(req.params.opinion_id).then( (result) => { res.send({ deleted: true }); }, (error) => { res.send({ deleted: false }); } ); } }); }; module.exports = opinionAPI; ================================================ FILE: backend/entities/opinion/controller.js ================================================ // models const Opinion = require('./model'); /** * get all opinion regarding a single discussion * @param {ObjectId} discussion_id * @return {Promise} */ const getAllOpinions = (discussion_id) => { return new Promise((resolve, reject) => { Opinion .find({ discussion_id }) .populate('user') .sort({ date: -1 }) .exec((error, opinions) => { if (error) { console.log(error); reject(error); } else if (!opinions) reject(null); else resolve(opinions); }); }); }; /** * create an opinion regarding a discussion * @param {ObjectId} forum_id * @param {ObjectId} discussion_id * @param {ObjectId} user_id * @param {Object} content * @return {Promise} */ const createOpinion = ({ forum_id, discussion_id, user_id, content }) => { return new Promise((resolve, reject) => { const newOpinion = new Opinion({ forum_id, discussion_id, discussion: discussion_id, user_id, user: user_id, content, date: new Date(), }); newOpinion.save((error) => { if (error) { console.log(error); reject(error); } else { resolve(newOpinion); } }); }); }; const updateOpinion = (opinion_id) => { // TODO: implement update for opinion }; /** * delete a single opinion * @param {ObjectId} opinion_id * @return {Promise} */ const deleteOpinion = (opinion_id) => { return new Promise((resolve, reject) => { Opinion .remove({ _id: opinion_id }) .exec((error) => { if (error) { console.log(error); reject(error); } else resolve('deleted'); }); }); }; module.exports = { getAllOpinions, createOpinion, updateOpinion, deleteOpinion, }; ================================================ FILE: backend/entities/opinion/model.js ================================================ /** * opinion model */ const mongoose = require('mongoose'); const opinionSchema = mongoose.Schema({ forum_id: mongoose.Schema.ObjectId, forum: { type: mongoose.Schema.ObjectId, ref: 'forum' }, discussion_id: mongoose.Schema.ObjectId, discussion: { type: mongoose.Schema.ObjectId, ref: 'discussion' }, user_id: mongoose.Schema.ObjectId, user: { type: mongoose.Schema.ObjectId, ref: 'user' }, date: Date, content: Object, }); module.exports = mongoose.model('opinion', opinionSchema); ================================================ FILE: backend/entities/user/api.js ================================================ const passport = require('passport'); const signIn = require('./controller').signIn; const getFullProfile = require('./controller').getFullProfile; /** * user apis */ const userAPI = (app) => { // get authenticated user app.get('/api/user/getUser', (req, res) => { if (req.user) res.send(req.user); else res.send(null); }); // github authentication route app.get( '/api/user/authViaGitHub', passport.authenticate('github') ); // callback route from github app.get( // this should match callback url of github app '/api/user/authViaGitHub/callback', passport.authenticate('github', { failureRedirect: '/signIn/failed' }), (req, res) => { res.redirect('/'); } ); // signout the user app.get('/api/user/signout', (req, res) => { req.logout(); res.redirect('/'); }); // get user full profile app.get('/api/user/profile/:username', (req, res) => { getFullProfile(req.params.username).then( result => { res.send(result); }, error => { res.send({ error }); } ); }); }; module.exports = userAPI; ================================================ FILE: backend/entities/user/controller.js ================================================ const _ = require('lodash'); const asyncEach = require('async/each'); // controllers const getAllOpinions = require('../opinion/controller').getAllOpinions; // models const User = require('./model'); const Discussion = require('../discussion/model'); const Opinion = require('../opinion/model'); /** * get user doc by user id * @param {ObjectId} user_id * @return {promise} */ const getUser = (user_id) => { return new Promise((resolve, reject) => { User.findOne({ _id: user_id }, (error, user) => { if (error) { console.log(error); reject(error); } else if (!user) reject(null); else resolve(user); }); }); }; /** * sign in/up user via github provided info * this will signin the user if user existed * or will create a new user using git infos * @param {Object} gitProfile profile information provided by github * @return {promise} user doc */ const signInViaGithub = (gitProfile) => { return new Promise((resolve, reject) => { // find if user exist on db User.findOne({ username: gitProfile.username }, (error, user) => { if (error) { console.log(error); reject(error); } else { // get the email from emails array of gitProfile const email = _.find(gitProfile.emails, { verified: true }).value; // user existed on db if (user) { // update the user with latest git profile info user.name = gitProfile.displayName; user.username = gitProfile.username; user.avatarUrl = gitProfile._json.avatar_url; user.email = email; user.github.id = gitProfile._json.id, user.github.url = gitProfile._json.html_url, user.github.company = gitProfile._json.company, user.github.location = gitProfile._json.location, user.github.hireable = gitProfile._json.hireable, user.github.bio = gitProfile._json.bio, user.github.followers = gitProfile._json.followers, user.github.following = gitProfile._json.following, // save the info and resolve the user doc user.save((error) => { if (error) { console.log(error); reject(error); } else { resolve(user); } }); } // user doesn't exists on db else { // check if it is the first user (adam/eve) :-p // assign him/her as the admin User.count({}, (err, count) => { console.log('usercount: ' + count); let assignAdmin = false; if (count === 0) assignAdmin = true; // create a new user const newUser = new User({ name: gitProfile.displayName, username: gitProfile.username, avatarUrl: gitProfile._json.avatar_url, email: email, role: assignAdmin ? 'admin' : 'user', github: { id: gitProfile._json.id, url: gitProfile._json.html_url, company: gitProfile._json.company, location: gitProfile._json.location, hireable: gitProfile._json.hireable, bio: gitProfile._json.bio, followers: gitProfile._json.followers, following: gitProfile._json.following, }, }); // save the user and resolve the user doc newUser.save((error) => { if (error) { console.log(error); reject(error); } else { resolve(newUser); } }); }); } } }); }); }; /** * get the full profile of a user * @param {String} username * @return {Promise} */ const getFullProfile = (username) => { return new Promise((resolve, reject) => { User .findOne({ username }) .lean() .exec((error, result) => { if (error) { console.log(error); reject(error); } else if (!result) reject('not_found'); else { // we got the user, now we need all discussions by the user Discussion .find({ user_id: result._id }) .populate('forum') .lean() .exec((error, discussions) => { if (error) { console.log(error); reject(error); } else { // we got the discussions by the user // we need to add opinion count to each discussion asyncEach(discussions, (eachDiscussion, callback) => { getAllOpinions(eachDiscussion._id).then( (opinions) => { // add opinion count to discussion doc eachDiscussion.opinion_count = opinions ? opinions.length : 0; callback(); }, (error) => { console.error(error); callback(error); } ); }, (error) => { if (error) { console.log(error); reject(error); } else { result.discussions = discussions; resolve(result); } }); } }); } }); }); }; module.exports = { signInViaGithub, getUser, getFullProfile, }; ================================================ FILE: backend/entities/user/model.js ================================================ /** * user model */ const mongoose = require('mongoose'); const userSchema = mongoose.Schema({ name: String, username: String, avatarUrl: String, email: String, role: { type: String, default: 'user' }, // ['admin', 'moderator', 'user'] github: { id: Number, url: String, company: String, location: String, bio: String, hireable: Boolean, followers: Number, following: Number, }, }); module.exports = mongoose.model('user', userSchema); ================================================ FILE: backend/express.js ================================================ /** * module dependencies for express configuration */ const passport = require('passport'); const morgan = require('morgan'); const compress = require('compression'); const cookieParser = require('cookie-parser'); const bodyParser = require('body-parser'); const session = require('express-session'); const mongoStore = require('connect-mongo')(session); const flash = require('connect-flash'); /** * express configuration */ const expressConfig = (app, serverConfigs) => { // apply gzip compression (should be placed before express.static) app.use(compress()); // log server requests to console !serverConfigs.PRODUCTION && app.use(morgan('dev')); // get data from html froms app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); // read cookies (should be above session) app.use(cookieParser()); // use session with mongo app.use(session({ resave: false, saveUninitialized: true, secret: 'secret', store: new mongoStore({ url: serverConfigs.DBURL, collection : 'sessions', }), })); // use passport session app.use(passport.initialize()); app.use(passport.session()); // apply passport configs require('./passport')(app); // connect flash for flash messages (should be declared after sessions) app.use(flash()); // apply development environment additionals if (!serverConfigs.PRODUCTION) { require('./dev')(app); } // apply route configs require('./routes')(app); }; module.exports = expressConfig; ================================================ FILE: backend/mockData/discussions.js ================================================ const discussions = [ { 'forum_id': '58c23d2efce8810b6f20b0b3', 'discussion_slug': 'a_pinned_discussion_' + ObjectId, 'user_id': '58c242a96ba2030d170f86f9', 'date': 1486450269704, 'title': 'A pinned discussion', 'content': 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', 'favorites': 2, 'tags': ['react', 'redux', 'mongodb'], 'pinned': true, }, { 'forum_id': '58c23d2efce8810b6f20b0b3', 'discussion_slug': 'another_pinned_discussion_' + ObjectId, 'user_id': '58c242a96ba2030d170f86f9', 'date': 1486450269704, 'title': 'Another pinned discussion', 'content': 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', 'favorites': 3, 'tags': ['react', 'redux'], 'pinned': true, }, { 'forum_id': '58c23d2efce8810b6f20b0b3', 'discussion_slug': 'one_another_pinned_discussion_' + ObjectId, 'user_id': '58c242e2fb2e150d2570e02b', 'date': 1486450269704, 'title': 'One another pinned discussion', 'content': 'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', 'favorites': 5, 'tags': ['express', 'mongodb'], 'pinned': true, }, { 'forum_id': '58c23d2efce8810b6f20b0b3', 'discussion_slug': 'a_discussion_from_general_forum_' + ObjectId, 'user_id': '58c242e2fb2e150d2570e02b', 'date': 1486450269704, 'title': 'A discussion from general forum', 'content': 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', 'favorites': 2, 'tags': ['react', 'redux', 'mongodb'], 'pinned': false, }, ]; module.exports = discussions; ================================================ FILE: backend/mockData/forum.js ================================================ const forums = [ { 'forum_id': 0, 'forum_slug': 'general', 'forum_name': 'General', }, { 'forum_id': 1, 'forum_slug': 'react', 'forum_name': 'React', }, { 'forum_id': 2, 'forum_slug': 'redux', 'forum_name': 'Redux', }, ]; module.exports = forums; ================================================ FILE: backend/mockData/opinions.js ================================================ const opinions = [ { 'discussion_id': '58c641904e457708a7147417', 'user_id': '58c242e2fb2e150d2570e02b', 'date': 1486450269704, 'content': 'Awesome stuffs!', }, { 'discussion_id': '58c641904e457708a7147417', 'user_id': '58c242e2fb2e150d2570e02b', 'date': 1486450269704, 'content': 'Awesome stuffs really!', }, { 'discussion_id': '58c641cf88336b08c76f3b50', 'user_id': '58c242a96ba2030d170f86f9', 'date': 1486450269704, 'content': 'Great job dude!', }, { 'discussion_id': '58c641cf88336b08c76f3b50', 'user_id': '58c242a96ba2030d170f86f9', 'date': 1486450269704, 'content': 'These discussions!!!', }, ]; module.exports = opinions; ================================================ FILE: backend/mockData/users.js ================================================ const users = [ { 'user_id': 0, 'username': 'testuser1', 'email': 'testuser1@reforum.abc', 'avatarUrl': 'https://robohash.org/quisapientelibero.png?size=50x50&set=set1', 'name': 'Test User 1', }, { 'user_id': 1, 'username': 'testuser2', 'email': 'testuser2@reforum.abc', 'avatarUrl': 'https://robohash.org/magnidictadeserunt.png?size=50x50&set=set1', 'name': 'Test User 2', }, { 'user_id': 2, 'username': 'testuser3', 'email': 'testuser3@reforum.abc', 'avatarUrl': 'https://robohash.org/ducimusnostrumillo.jpg?size=50x50&set=set1', 'name': 'Test User 3', }, { 'user_id': 3, 'username': 'testuser4', 'email': 'testuser4@reforum.abc', 'avatarUrl': 'https://robohash.org/autemharumvitae.bmp?size=50x50&set=set1', 'name': 'Test User 4', }, { 'user_id': 4, 'username': 'testuser5', 'email': 'testuser5@reforum.abc', 'avatarUrl': 'https://robohash.org/similiquealiquidmaiores.jpg?size=50x50&set=set1', 'name': 'Test User 5', }, ]; module.exports = users; ================================================ FILE: backend/passport.js ================================================ /** * module dependencies for passport configuration */ const passport = require('passport'); const GitHubStrategy = require('passport-github').Strategy; const GITHUB_CLIENT_ID = require('../config/credentials').GITHUB_CLIENT_ID; const GITHUB_CLIENT_SECRET = require('../config/credentials').GITHUB_CLIENT_SECRET; const GITHUB_CALLBACK_URL = require('../config/credentials').GITHUB_CALLBACK_URL; // controllers const getUser = require('./entities/user/controller').getUser; const signInViaGithub = require('./entities/user/controller').signInViaGithub; /** * passport configuration */ const passportConfig = (app) => { passport.serializeUser((user, done) => { done(null, user._id); }); passport.deserializeUser((id, done) => { getUser(id).then( (user) => { done(null, user); }, (error) => { done(error); } ); }); // github strategy for passport using OAuth passport.use(new GitHubStrategy( { clientID: GITHUB_CLIENT_ID, clientSecret: GITHUB_CLIENT_SECRET, callbackURL: GITHUB_CALLBACK_URL, scope: 'user:email', }, (accessToken, refreshToken, gitProfile, done) => { signInViaGithub(gitProfile).then( (user) => { console.log('got the user'); done(null, user); }, (error) => { console.log('something error occurs'); done(error); } ); } )); }; module.exports = passportConfig; ================================================ FILE: backend/routes.js ================================================ /** * module dependencies for routes configuration */ const path = require('path'); const express = require('express'); const userAPI = require('./entities/user/api'); const forumAPI = require('./entities/forum/api'); const discussionAPI = require('./entities/discussion/api'); const opinionAPI = require('./entities/opinion/api'); const adminAPI = require('./entities/admin/api'); /** * routes configurations */ const routesConfig = (app) => { // serves static files from public directory const publicPath = path.resolve(__dirname, '../public'); app.use(express.static(publicPath)); // serve api endpoint app.get('/api', (req, res) => { res.send('Hello from API endpoint'); }); // apply user apis userAPI(app); // apply forum apis forumAPI(app); // apply discussion apis discussionAPI(app); // apply opinion apis opinionAPI(app); // apply admin apis adminAPI(app); // all get request will send index.html for react-router // to handle the route request app.get('*', (req, res) => { res.sendFile(path.resolve(__dirname, '../public', 'index.html')); }); }; module.exports = routesConfig; ================================================ FILE: backend/utilities/tools.js ================================================ /** * Search object properties recursively and * perform callback action on each * @param {Object} obj [object to search props] * @param {Function} callback [action to perform on each props, two parameters (property, object)] * @return {Object} [new modified object] */ const deepPropSearch = (obj, callback) => { // new object for immutability const newObj = Object.assign({}, obj); // recursive search function const deepSearch = (obj) => { for (const prop in obj) { // perform callback for each property callback && callback(prop, obj); // recursive search inside objects/arrays if (typeof obj[prop] === 'object') { if (obj[prop].length && obj[prop].length > 0) { obj[prop].forEach((deepObj) => { deepSearch(deepObj); }); } else { deepSearch(obj[prop]); } } } }; // start deep searching for properties deepSearch(newObj, callback); // return new object, maintain immutability return newObj; }; const generateDiscussionSlug = (discussionTitle) => { const ObjectId = require('mongoose').Types.ObjectId(); return discussionTitle.replace(/[^a-z0-9]/gi, '_').toLowerCase() + '_' + ObjectId; }; module.exports = { deepPropSearch, generateDiscussionSlug, }; ================================================ FILE: config/credentials.js ================================================ module.exports = { GITHUB_CLIENT_ID: '', GITHUB_CLIENT_SECRET: '', GITHUB_CALLBACK_URL: '', DBURL: '', }; ================================================ FILE: config/serverConfig.js ================================================ /** * module dependencies for server configuration */ const path = require('path'); const databaseUrl = require('./credentials').DBURL; /** * server configurations */ const serverConfigs = { PRODUCTION: process.env.NODE_ENV === 'production', PORT: process.env.PORT || 8080, ROOT: path.resolve(__dirname, '..'), DBURL: databaseUrl, }; module.exports = serverConfigs; ================================================ FILE: config/webpack.dev.config.js ================================================ /** * module dependencies for webpack dev configuration */ const path = require('path'); const webpack = require('webpack'); // define paths const nodeModulesPath = path.resolve(__dirname, '../node_modules'); const buildPath = path.resolve(__dirname, '../public', 'build'); const mainAppPath = path.resolve(__dirname, '../frontend', 'App', 'index.js'); const sharedStylesPath = path.resolve(__dirname, '../frontend', 'SharedStyles'); const componentsPath = path.resolve(__dirname, '../frontend', 'Components'); const containersPath = path.resolve(__dirname, '../frontend', 'Containers'); const viewsPath = path.resolve(__dirname, '../frontend', 'Views'); /** * webpack development configuration */ module.exports = { target : 'web', devtool: 'inline-source-map', entry: [ 'webpack-hot-middleware/client', mainAppPath, ], output: { filename: 'bundle.js', path: buildPath, publicPath: '/build/', }, module: { loaders: [ { test: /\.js$/, loaders: [ 'react-hot', 'babel-loader' ], exclude: [nodeModulesPath], }, { test: /\.css$/, loaders: [ 'style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]', 'postcss-loader?sourceMap=inline', ], }, { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' }, { test: /\.svg$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml' }, ], }, postcss: [ require('autoprefixer'), require('postcss-nesting') ], plugins: [ new webpack.HotModuleReplacementPlugin(), new webpack.NoErrorsPlugin(), ], resolve : { extensions: ['', '.js', '.css'], alias: { SharedStyles: sharedStylesPath, Components: componentsPath, Containers: containersPath, Views: viewsPath, }, }, }; ================================================ FILE: config/webpack.prod.config.js ================================================ /** * module dependencies for webpack production configuration */ const path = require('path'); const webpack = require('webpack'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); // define paths const nodeModulesPath = path.resolve(__dirname, '../node_modules'); const buildPath = path.resolve(__dirname, '../public', 'build'); const mainAppPath = path.resolve(__dirname, '../frontend', 'App', 'index.js'); const sharedStylesPath = path.resolve(__dirname, '../frontend', 'SharedStyles'); const componentsPath = path.resolve(__dirname, '../frontend', 'Components'); const containersPath = path.resolve(__dirname, '../frontend', 'Containers'); const viewsPath = path.resolve(__dirname, '../frontend', 'Views'); /** * webpack production configuration */ module.exports = { target : 'web', entry: [ mainAppPath, ], output: { filename: 'bundle.js', path: buildPath, }, module: { loaders: [ { test: /\.js$/, loaders: [ 'react-hot', 'babel-loader' ], exclude: [nodeModulesPath], }, { test: /\.css$/, loader: ExtractTextPlugin.extract( 'style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader?sourceMap=inline' ), }, { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' }, { test: /\.svg$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml' }, ], }, postcss: [ require('autoprefixer'), require('postcss-nesting') ], plugins: [ new webpack.optimize.DedupePlugin(), new webpack.optimize.OccurrenceOrderPlugin(), new webpack.optimize.UglifyJsPlugin(), new ExtractTextPlugin('style.css', { allChunks: true }), ], resolve: { extensions: ['', '.js', '.css'], alias: { SharedStyles: sharedStylesPath, Components: componentsPath, Containers: containersPath, Views: viewsPath, }, }, externals: { 'react': 'React', 'react-dom': 'ReactDOM', 'redux': 'Redux', 'react-router': 'ReactRouter', 'moment': 'moment', }, }; ================================================ FILE: docs/api.md ================================================ # API Docs Work in progress :-) ================================================ FILE: docs/system_overview.md ================================================ # System Overview Work in progress :-) ================================================ FILE: frontend/App/Admin.js ================================================ import React, { Component } from 'react'; import { Link, browserHistory } from 'react-router'; import { connect } from 'react-redux'; import { Helmet } from 'react-helmet'; import { getUser } from './actions'; import AdminHeader from 'Containers/AdminHeader'; import appLayout from 'SharedStyles/appLayout.css'; import styles from './styles.css'; class AdminContainer extends Component { componentDidMount() { // fetch the user this.props.getUser(); } render() { const { user } = this.props; if (user.fetchingUser) { return (
Loading users profile...
); } if (user.role === 'admin') { return (
ReForum | Admin {this.props.children}
); } else { return (
We are cordially sorry that you are not allowed to view admin panel!
Please go back to root page.
); } return (
Something went wrong.
Please go back to root page.
); } } export default connect( (state) => { return { user: state.user, }; }, (dispatch) => { return { getUser: () => { dispatch(getUser()); }, }; } )(AdminContainer); ================================================ FILE: frontend/App/App.js ================================================ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { Helmet } from 'react-helmet'; import Header from 'Containers/Header'; import Footer from 'Components/Footer'; import appLayout from 'SharedStyles/appLayout.css'; import styles from './styles.css'; import { getForums, updateCurrentForum, getUser } from './actions'; class AppContainer extends Component { componentDidMount() { const { params, updateCurrentForum, getForums, getUser, } = this.props; // get all forum list getForums(); // check for authenticated user getUser(); // set current forum based on route const currentForum = params.forum || ''; updateCurrentForum(currentForum); } componentDidUpdate() { const { forums, params, currentForum, updateCurrentForum, } = this.props; let newCurrentForum = ''; if (params.forum) newCurrentForum = params.forum; else if (forums) newCurrentForum = forums[0].forum_slug; // update current forum if necessery if (newCurrentForum !== currentForum) updateCurrentForum(newCurrentForum); } render() { const { forums } = this.props; // render only if we get the forum lists if (forums) { return (
ReForum
Fork on Github
{this.props.children}
); } return (
Loading...
); } } export default connect( (state) => { return { forums: state.app.forums, currentForum: state.app.currentForum, }; }, (dispatch) => { return { getForums: () => { dispatch(getForums()); }, updateCurrentForum: (currentForum) => { dispatch(updateCurrentForum(currentForum)); }, getUser: () => { dispatch(getUser()); }, }; } )(AppContainer); ================================================ FILE: frontend/App/actions.js ================================================ import _ from 'lodash'; import { START_FETCHING_FORUMS, STOP_FETCHING_FORUMS, FETCHING_FORUMS_SUCCESS, FETCHING_FORUMS_FAILURE, UPDATECURRENTFORUM, START_FETCHING_USER, FETCHING_USER_SUCCESS, FETCHING_USER_FAILURE, } from './constants'; import { fetchForums, fetchUser, signOut, } from './api'; /** * get all forum list * @return {action} */ export const getForums = () => { return (dispatch, getState) => { dispatch({ type: START_FETCHING_FORUMS }); fetchForums().then( data => dispatch({ type: FETCHING_FORUMS_SUCCESS, payload: data.data }), error => dispatch({ type: FETCHING_FORUMS_FAILURE }) ); }; }; /** * update current forum when route change occurs * @param {String} currentForum * @return {action} */ export const updateCurrentForum = (currentForum) => { return { type: UPDATECURRENTFORUM, payload: currentForum, }; }; /** * get the current user from server * @return {action} */ export const getUser = () => { return (dispatch, getState) => { dispatch({ type: START_FETCHING_USER }); fetchUser().then( data => { if (!data.data._id) dispatch({ type: FETCHING_USER_FAILURE }); else dispatch({ type: FETCHING_USER_SUCCESS, payload: data.data }); }, error => dispatch({ type: FETCHING_USER_FAILURE }) ); }; }; ================================================ FILE: frontend/App/api.js ================================================ import axios from 'axios'; export const fetchForums = (forum_id) => { return axios.get('/api/forum'); }; export const fetchUser = () => { return axios.get('/api/user/getUser'); }; ================================================ FILE: frontend/App/constants.js ================================================ export const UPDATECURRENTFORUM = 'update_current_forum'; export const START_FETCHING_FORUMS = 'start_fetching_forums'; export const STOP_FETCHING_FORUMS = 'stop_fetching_forums'; export const FETCHING_FORUMS_SUCCESS = 'fetching_forums_success'; export const FETCHING_FORUMS_FAILURE = 'fetching_forums_failure'; export const START_FETCHING_USER = 'start_fetching_user'; export const FETCHING_USER_SUCCESS = 'fetching_user_success'; export const FETCHING_USER_FAILURE = 'fetching_user_failure'; export const SIGNOUT_USER_SUCCESS = 'signOut_user_success'; export const SIGNOUT_USER_FAILURE = 'signOut_user_failure'; ================================================ FILE: frontend/App/index.js ================================================ import React from 'react'; import ReactDOM from 'react-dom'; import { Router, Route, browserHistory, IndexRoute } from 'react-router'; import { Provider } from 'react-redux'; import styles from './styles'; // app store import appStore from './store'; // app views import AppContainer from './App'; import AdminContainer from './Admin'; import Dashboard from '../Views/AdminDashboard'; import Header from 'Containers/Header'; import ForumFeed from '../Views/ForumFeed'; import SingleDiscussion from '../Views/SingleDiscussion'; import NewDiscussion from '../Views/NewDiscussion'; import UserProfile from '../Views/UserProfile'; import NotFound from '../Views/NotFound'; ReactDOM.render ( , document.getElementById('root') ); ================================================ FILE: frontend/App/reducers.js ================================================ import { START_FETCHING_FORUMS, STOP_FETCHING_FORUMS, FETCHING_FORUMS_SUCCESS, FETCHING_FORUMS_FAILURE, UPDATECURRENTFORUM, START_FETCHING_USER, FETCHING_USER_SUCCESS, FETCHING_USER_FAILURE, } from './constants'; const initialState = { fetchingForums: false, forums: null, currentForum: 'general', error: false, }; /** * reducer for top level app state */ export const appReducer = (state = initialState, action) => { switch (action.type) { case START_FETCHING_FORUMS: return Object.assign({}, state, { fetchingForums: true, });; case STOP_FETCHING_FORUMS: return Object.assign({}, state, { fetchingForums: false, });; case FETCHING_FORUMS_SUCCESS: return Object.assign({}, state, { forums: action.payload, fetchingForums: false, error: false, }); case FETCHING_FORUMS_FAILURE: return Object.assign({}, state, { fetchingForums: false, error: 'Unable to fetch forums', }); case UPDATECURRENTFORUM: return Object.assign({}, state, { currentForum: action.payload, }); default: return state; } }; /** * reducer for user */ const initialUserState = { fetchingUser: true, authenticated: false, error: null, _id: null, name: null, email: null, username: null, avatarUrl: null, githubUrl: null, githubLocation: null, githubBio: null, role: null, }; export const userReducer = (state = initialUserState, action) => { switch (action.type) { case START_FETCHING_USER: return Object.assign({}, state, { fetchUser: true, }); case FETCHING_USER_SUCCESS: const { _id, name, username, avatarUrl, email, githubBio, githubUrl, githubLocation, role, } = action.payload; return Object.assign({}, state), { fetchingUser: false, authenticated: true, error: null, _id, name, username, avatarUrl, email, githubBio, githubUrl, githubLocation, role, }; case FETCHING_USER_FAILURE: return Object.assign({}, initialUserState, { fetchingUser: false, error: 'Unable to fetch user!', }); default: return state; } }; ================================================ FILE: frontend/App/store.js ================================================ import { createStore, applyMiddleware, compose } from 'redux'; import { combineReducers } from 'redux'; import thunk from 'redux-thunk'; import { appReducer, userReducer } from './reducers'; import { feedReducer } from '../Views/ForumFeed/reducers'; import { singleDiscussionReducer } from '../Views/SingleDiscussion/reducers'; import { newDiscussionReducer } from '../Views/NewDiscussion/reducers'; import { adminInfoReducer } from '../Views/AdminDashboard/reducers'; import { userProfileReducer } from '../Views/UserProfile/reducers'; // root reducer for app const rootReducer = combineReducers({ user: userReducer, app: appReducer, feed: feedReducer, discussion: singleDiscussionReducer, newDiscussion: newDiscussionReducer, adminInfo: adminInfoReducer, userProfile: userProfileReducer, }); // dev tool extension const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; // application store let store = createStore( rootReducer, /* preloaded state, */ composeEnhancers( applyMiddleware(thunk) ) ); export default store; ================================================ FILE: frontend/App/styles.css ================================================ /** * Application container stylings */ .loadingWrapper { height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } .gitForkTag { position: fixed; bottom:0px; right: 0px; background-color: #f9f9f9; border-top: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8; padding: 5px 50px; transform: rotate(-45deg) translateY(-5px) translateX(54px); z-index: 1; } .gitLink { text-decoration: none; color: black; } ================================================ FILE: frontend/Components/Button/index.js ================================================ import React, { Component } from 'react'; import classnames from 'classnames'; import styles from './styles'; class Button extends Component { render() { const { type, fullWidth, noUppercase, className, style, onClick, alwaysActive, } = this.props; return ( ); } } Button.defaultProps = { type: 'default', fullWidth: false, noUppercase: false, alwaysActive: false, className: '', style: {}, onClick: () => { }, }; Button.propTypes = { type: React.PropTypes.oneOf(['default', 'outline']), fullWidth: React.PropTypes.bool, noUppercase: React.PropTypes.bool, alwaysActive: React.PropTypes.bool, className: React.PropTypes.string, style: React.PropTypes.object, onClick: React.PropTypes.func, }; export default Button; ================================================ FILE: frontend/Components/Button/styles.css ================================================ @value borderColor, secondaryFontColor, primaryFontColor from 'SharedStyles/globalStyles.css'; /** * Button styles */ /* resetting all default button styles */ button { background: none; border: 0; color: inherit; font: inherit; line-height: normal; overflow: visible; padding: 0; user-select: none; outline: none; cursor: pointer; } .buttonDefaults { padding: 10px 20px; text-transform: uppercase; font-weight: 700; font-size: 13px; letter-spacing: 0.5px; } .default { color: secondaryFontColor; transition: color 0.3s; &:hover { color: primaryFontColor; } } .outline { color: secondaryFontColor; border: 1px solid borderColor; transition: color 0.3s, border 0.3s; &:hover { color: primaryFontColor; border: 1px solid secondaryFontColor; } } .fullWidth { width: 100%; } .noUppercase { text-transform: none; } .alwaysActive { color: primaryFontColor; border-color: primaryFontColor; } ================================================ FILE: frontend/Components/Dashboard/Counts/index.js ================================================ import React, { Component } from 'react'; import classnames from 'classnames'; import styles from './styles'; class Counts extends Component { render() { const { count, label, } = this.props; return (
{count}
{label}
); } } Counts.defaultProps = { count: 0, label: 'default', }; Counts.propTypes = { count: React.PropTypes.number, label: React.PropTypes.string, }; export default Counts; ================================================ FILE: frontend/Components/Dashboard/Counts/styles.css ================================================ @value primaryFontColor, secondaryFontColor, borderColor from 'SharedStyles/globalStyles.css'; @value smallBP from 'SharedStyles/globalStyles.css'; .container { flex: 1; margin: 0px 10px 10px 10px; padding: 20px 10px; max-width: 200px; display: flex; align-items: center; border: 1px solid borderColor; } .count { font-size: 40px; font-weight: lighter; } .label { margin-left: 20px; } ================================================ FILE: frontend/Components/Dashboard/ForumBox/index.js ================================================ import React, { Component } from 'react'; import classnames from 'classnames'; import styles from './styles'; import Button from 'Components/Button'; class ForumBox extends Component { constructor(props) { super(props); this.state = { newForumTitle: '', newForumSlug: '', errorMsg: null, }; this.handleCreateForum = this.handleCreateForum.bind(this); } handleCreateForum() { // remove any error messages this.setState({ errorMsg: null }); const { newForumTitle, newForumSlug, } = this.state; let convertedTitle = null; let convertedSlug = null; // check and convert forum title if (newForumTitle !== '') { // trim any leading or ending white spaces convertedTitle = newForumTitle.trim(); // check the length, 4 is hardcoded here if (convertedTitle.length < 4) { return this.setState({ errorMsg: 'Forum title should have at least 4 charecters.' }); } } else { return this.setState({ errorMsg: 'Forum title is empty. Please provide a valid Forum Title.' }); } // check and confirm forum slug if (convertedSlug !== '') { const slugRegex = /^[a-z\_]+$/; convertedSlug = newForumSlug.match(slugRegex) ? newForumSlug : null; // length check if (convertedSlug && convertedSlug.length < 4) { return this.setState({ errorMsg: 'Forum slug should have at least 4 charecters.' }); } } else { return this.setState({ errorMsg: 'Forum slug is empty. Please provide a valid Forum Slug.' }); } if (!convertedTitle) { return this.setState({ errorMsg: 'Please provide a valid Forum Title.' }); } if (!convertedSlug) { return this.setState({ errorMsg: 'Please provide a valid Forum Slug. Slug can only contain small case alphabets and underscore.' }); } if (convertedTitle && convertedSlug) { this.props.createAction({ title: convertedTitle, slug: convertedSlug }); } } render() { const { forums, creatingForum, deleteAction, deletingForum, } = this.props; const { newForumTitle, newForumSlug, errorMsg, } = this.state; return (
Current Forums
{ deletingForum &&
Removing forum, please wait...
} { forums.map((forum) =>
{ forum.name }
({ forum.slug })
) }
{ creatingForum &&
Creating forum, please wait...
}
Create New Forum
Title:
{ this.setState({ newForumTitle: e.target.value }); }} />
Slug:
{ this.setState({ newForumSlug: e.target.value }); }} />
{ errorMsg &&
{errorMsg}
}
); } } ForumBox.defaultProps = { }; ForumBox.propTypes = { forums: React.PropTypes.array, deletingForum: React.PropTypes.bool, deleteAction: React.PropTypes.func, creatingForum: React.PropTypes.bool, createAction: React.PropTypes.func, }; export default ForumBox; ================================================ FILE: frontend/Components/Dashboard/ForumBox/styles.css ================================================ @value primaryFontColor, secondaryFontColor, borderColor from 'SharedStyles/globalStyles.css'; @value smallBP from 'SharedStyles/globalStyles.css'; .container { display: flex; flex-direction: column; border: 1px solid borderColor; } .title { padding: 10px 10px; border-bottom: 1px solid borderColor; } .forumsContainer { position: relative; & .forum { padding: 0px 20px; display: flex; align-items: center; border-bottom: 1px solid borderColor; & .forumTitle { font-weight: bold; } & .forumSlug { color: secondaryFontColor; margin-left: 10px; } } } .createForumContainer { position: relative; & .createTitle { border-bottom: none; padding: 10px 10px 0px 10px; } & .createForum { padding: 10px 10px; display: flex; align-items: center; & .createInputContainer { display: flex; align-items: center; margin-left: 20px; &:first-child { margin-left: 0px; } & .inputLabel { margin-right: 10px; } & .createInput { outline: none; padding: 5px 10px; } } } } .errorMsg { font-weight: bold; padding: 5px 10px 10px 10px; color: rgba(231, 76, 60,1.0); font-size: 12px; line-height: 14px; } .loadingMsg { position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; background-color: rgba(255, 255, 255, 0.9); border-bottom: 1px solid borderColor; display: flex; justify-content: center; align-items: center; } ================================================ FILE: frontend/Components/FeedBox/DiscussionBox/index.js ================================================ import React, { Component } from 'react'; import { Link } from 'react-router'; import classnames from 'classnames'; import Moment from 'moment'; import styles from './styles'; import Tag from 'Components/Tag'; class DiscussionBox extends Component { render() { const { voteCount, userName, userGitHandler, discussionTitle, time, opinionCount, tags, link, userProfile, } = this.props; const postTime = Moment(time); const timeDisplay = postTime.from(Moment()); return (
{discussionTitle}
{ !userProfile &&
{userName} - {userGitHandler}
}
{ tags.map((tag) => ) }
{timeDisplay} {voteCount} favorites {opinionCount} opinions
); } } DiscussionBox.defaultProps = { discussionId: 1, voteCount: 20, userName: 'Hello World', userGitHandler: 'github', discussionTitle: 'This is a default post title', time: Moment(), opinionCount: 12, tags: ['react', 'redux', 'nodejs'], link: '', userProfile: false, }; DiscussionBox.propTypes = { discussionId: React.PropTypes.number, voteCount: React.PropTypes.number, userName: React.PropTypes.string, userGitHandler: React.PropTypes.string, discussionTitle: React.PropTypes.string, time: React.PropTypes.any, opinionCount: React.PropTypes.number, tags: React.PropTypes.array, link: React.PropTypes.string, userProfile: React.PropTypes.bool, }; export default DiscussionBox; ================================================ FILE: frontend/Components/FeedBox/DiscussionBox/styles.css ================================================ @value primaryFontColor, secondaryFontColor, borderColor, backShade from 'SharedStyles/globalStyles'; @value smallBP from 'SharedStyles/globalStyles'; /** * PostBox styles */ .container { display: flex; flex-direction: column; padding: 10px; border-bottom: 1px solid borderColor; &:last-child { border-bottom: none; } } .title { font-size: 18px; font-weight: 300; & a { text-decoration: none; color: primaryFontColor; } } .titleBottomMargin { margin-bottom: 10px; } .posterInfo { margin-top: 10px; font-size: 13px; & .name { font-weight: 700; color: secondaryFontColor; text-decoration: none; transition: color 0.3s; &:hover { color: primaryFontColor; } } & .gitHandler { margin-left: 5px; text-decoration: none; color: secondaryFontColor; transition: color 0.3s; & .gitIcon { font-size: 16px; padding: 0 5px; } &:hover { color: primaryFontColor; } } } .boxFooter { margin-top: 10px; display: flex; align-items: center; justify-content: space-between; @media smallBP { margin-top: 0px; flex-direction: column-reverse; align-items: flex-start; } } .tagsArea { display: flex; align-items: center; @media smallBP { margin-top: 5px; } } .postInfo { & .info { margin-left: 20px; font-size: 12px; font-weight: 700; text-transform: lowercase; color: secondaryFontColor; &:first-child { margin-left: 0px; } } } ================================================ FILE: frontend/Components/FeedBox/index.js ================================================ import React, { Component } from 'react'; import classnames from 'classnames'; import Moment from 'moment'; import styles from './styles'; import DiscussionBox from './DiscussionBox'; class FeedBox extends Component { renderSort() { const { activeSortingMethod, onChangeSortingMethod, } = this.props; if (this.props.type === 'general') { return (
onChangeSortingMethod('date')} > Latest onChangeSortingMethod('popularity')} > Popular
); } return null; } renderEmptyDiscussionLine(loading, discussions) { if (!loading) { if (!discussions || discussions.length === 0) { return
No discussions...
; } } } render() { const { type, loading, discussions, currentForum, userProfile, } = this.props; let discussionBoxTitle = ''; if (type === 'general') discussionBoxTitle = 'Discussions'; if (type === 'pinned') discussionBoxTitle = 'Pinned'; return (
{discussionBoxTitle} { !userProfile && this.renderSort() }
{ loading &&
Loading...
} { this.renderEmptyDiscussionLine(loading, discussions) } { !loading &&
{ discussions && discussions.map((discussion) => ) }
}
); } } FeedBox.defaultProps = { type: 'general', loading: false, discussions: [], currentForum: 'general', activeSortingMethod: 'date', onChangeSortingMethod: (val) => { }, userProfile: false, }; FeedBox.propTypes = { type: React.PropTypes.oneOf(['general', 'pinned']), loading: React.PropTypes.bool, discussions: React.PropTypes.array, currentForum: React.PropTypes.string, activeSortingMethod: React.PropTypes.string, onChangeSortingMethod: React.PropTypes.func, userProfile: React.PropTypes.bool, }; export default FeedBox; ================================================ FILE: frontend/Components/FeedBox/styles.css ================================================ @value borderColor, backShade, secondaryFontColor, primaryFontColor from 'SharedStyles/globalStyles.css'; /** * FeedBox styles */ .container { margin-top: 20px; border: 1px solid borderColor; &:first-child { margin-top: 0px; } } .header { border-bottom: 1px solid borderColor; height: 30px; display: flex; flex-flow: row nowrap; align-items: center; justify-content: space-between; background-color: backShade; } .title { padding-left: 10px; font-size: 13px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; } .sortList { & .sort { color: secondaryFontColor; display: inline-block; height: 30px; line-height: 30px; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; padding: 0px 10px; cursor: pointer; user-select: none; &.sortActive { color: primaryFontColor; } } } .posts { display: flex; flex-direction: column; } .loading { font-size: 12px; letter-spacing: 0.5px; color: secondaryFontColor; padding: 20px 0px; text-align: center; } ================================================ FILE: frontend/Components/Footer/index.js ================================================ import React, { Component } from 'react'; import classnames from 'classnames'; import styles from './styles'; import appLayout from 'SharedStyles/appLayout.css'; class Footer extends Component { render() { return (
{/* Copyright? Who cares? :-) */}
); } } Footer.defaultProps = { }; Footer.propTypes = { }; export default Footer; ================================================ FILE: frontend/Components/Footer/styles.css ================================================ @value smallBP, mediumBP, largeBP from 'SharedStyles/globalStyles'; /** * Footer styles */ .contentArea { margin-top: 40px; margin-bottom: 40px; text-align: center; } ================================================ FILE: frontend/Components/Header/Logo/index.js ================================================ import React, { Component } from 'react'; import styles from './styles'; const Logo = () => { return (
ReForum
); }; export default Logo; ================================================ FILE: frontend/Components/Header/Logo/styles.css ================================================ /* logo */ .logoContainer { display: flex; flex-flow: row nowrap; align-items: center; } .logo { width: 40px; height: 40px; } .logoTitle { margin-left: 10px; font-size: 20px; font-weight: 700; } ================================================ FILE: frontend/Components/Header/NavigationBar/index.js ================================================ import React, { Component } from 'react'; import { Link, IndexLink } from 'react-router'; import classnames from 'classnames'; import _ from 'lodash'; import styles from './styles'; class NavigationBar extends Component { render() { const { navigationLinks, } = this.props; if (navigationLinks) { return ( ); } return null; } } NavigationBar.defaultProps = { navigationLinks: [ { id: 0, name: 'General', link: '/', }, ], }; NavigationBar.propTypes = { navigationLinks: React.PropTypes.array, }; export default NavigationBar; ================================================ FILE: frontend/Components/Header/NavigationBar/styles.css ================================================ @value primaryFontColor, secondaryFontColor, borderColor from 'SharedStyles/globalStyles.css'; @value smallBP from 'SharedStyles/globalStyles.css'; /** * NavigationBar styles */ .navigationBar { border-top: 1px solid borderColor; border-bottom: 1px solid borderColor; list-style-type: none; display: flex; margin: 0px; padding: 0px; @media smallBP { padding: 0px 10px; } } .links { display: block; padding: 0px 15px; height: 38px; line-height: 38px; text-decoration: none; font-size: 14px; color: secondaryFontColor; user-select: none; transition: color 0.3s; } .links:hover { color: primaryFontColor; } .linkActive { color: primaryFontColor; background-color: #f9f9f9; } ================================================ FILE: frontend/Components/Header/UserMenu/index.js ================================================ import React, { Component } from 'react'; import { Link } from 'react-router'; import classnames from 'classnames'; import onClickOutside from 'react-onclickoutside'; import styles from './styles'; import Button from 'Components/Button'; class UserMenu extends Component { constructor(props) { super(props); this.state = { activeSubMenu: false }; this.toggleSubMenu = this.toggleSubMenu.bind(this); } handleClickOutside() { this.setState({ activeSubMenu: false }); } toggleSubMenu() { this.setState((prevState) => { return { activeSubMenu: !prevState.activeSubMenu }; }); } renderSubMenu() { const { activeSubMenu } = this.state; const { signedIn, gitHandler, } = this.props; if (activeSubMenu) { return (
{ !signedIn && } { signedIn && My Profile } {/* { signedIn && Settings } */} { signedIn && Sign Out }
); } return null; } render() { const { signedIn, userName, avatar, signOutAction, } = this.props; if (signedIn) { return (
{`${userName} {userName}
{this.renderSubMenu()}
); } return (
{this.renderSubMenu()}
); } } UserMenu.defaultProps = { signedIn: false, userName: '', gitHandler: '', avatar: '', }; UserMenu.propTypes = { signedIn: React.PropTypes.bool.isRequired, userName: React.PropTypes.string, gitHandler: React.PropTypes.string, avatar: React.PropTypes.string, }; export default onClickOutside(UserMenu); ================================================ FILE: frontend/Components/Header/UserMenu/styles.css ================================================ @value primaryFontColor, secondaryFontColor, borderColor from 'SharedStyles/globalStyles.css'; @value smallBP, mediumBP, largeBP from 'SharedStyles/globalStyles.css'; /** * UserMenu styles */ .container { cursor: pointer; position: relative; display: flex; align-items: center; flex-flow: row nowrap; } .userAvatar { width: 40px; height: 40px; border-radius: 50px; } .title { margin-left: 15px; font-size: 14px; font-weight: 700; } .signInLink { color: primaryFontColor; text-decoration: none; } .signInBtn { padding-left: 0px; padding-right: 0px; height: 40px; display: flex; align-items: center; } .subMenu { z-index: 1; padding: 10px 0px; position: absolute; top: 42px; right: 0px; width: 240px; background-color: white; border: 1px solid borderColor; display: flex; flex-direction: column; justify-content: center; align-items: center; @media smallBP { position: fixed; top: 0; left: 0; height: 100%; width: 100%; background-color: rgba(255,255,255, 0.8); border: none; } } .subMenuItem { width: 100%; color: secondaryFontColor; text-decoration: none; text-align: center; line-height: 32px; &:hover { color: primaryFontColor; } @media smallBP { color: primaryFontColor; line-height: 42px; } } .subMenuClose { position: absolute; top: 10px; right: 10px; @media mediumBP { display: none; } @media largeBP { display: none; } } .gitLoginBtn { width: 100%; display: flex; justify-content: center; align-items: center; padding: 15px 0px; } .subMenuOcto { font-size: 24px; margin-right: 15px; } ================================================ FILE: frontend/Components/NewDiscussion/PinButton/index.js ================================================ import React, { Component } from 'react'; import classnames from 'classnames'; import styles from './styles'; import Button from 'Components/Button'; class PinButton extends Component { constructor(props) { super(props); this.state = { value: false }; } componentWillReceiveProps(nextProps) { const { value } = nextProps; this.setState({ value }); } updateValue(value) { this.props.onChange(value); this.setState({ value }); } render() { const { value } = this.state; return (
Is it a pinned discussion?
); } } PinButton.defaultProps = { onChange: (val) => {}, value: false, }; PinButton.propTypes = { onChange: React.PropTypes.func, value: React.PropTypes.bool, }; export default PinButton; ================================================ FILE: frontend/Components/NewDiscussion/PinButton/styles.css ================================================ @value primaryFontColor, secondaryFontColor, borderColor from 'SharedStyles/globalStyles.css'; @value smallBP from 'SharedStyles/globalStyles.css'; .container { display: flex; align-items: center; margin: 5px 0px 0px 10px; } .label { margin-right: 10px; } .btnContainer { } .button { padding: 10px 20px; border: 1px solid borderColor; } ================================================ FILE: frontend/Components/NewDiscussion/TagsInput/index.js ================================================ import React, { Component } from 'react'; import classnames from 'classnames'; import _ from 'lodash'; import styles from './styles'; import Button from 'Components/Button'; import Tag from 'Components/Tag'; class TagsInput extends Component { constructor(props) { super(props); this.state = { errorMsg: null, tags: [], tagName: '', }; } componentWillReceiveProps(nextProps) { const { value } = nextProps; this.setState({ tags: value, errorMsg: null }); } validateTag(tagName) { const regex = /^[a-z0-9.\-_$@*!]{4,20}$/; return regex.test(tagName); } sameTag(tagName) { const { tags } = this.state; let matched = false; tags.map((tag) => { if (tag === tagName) matched = true; }); return matched; } addTag() { const { tagName, tags, errorMsg, } = this.state; if (this.validateTag(tagName)) { if (!this.sameTag(tagName)) { const newTags = tags.concat(tagName); this.setState({ tags: newTags, errorMsg: null, tagName: '', }); this.props.onChange(newTags); } else { this.setState({ errorMsg: 'Same tag!!!' }); } } else { this.setState({ errorMsg: 'Tags can only contain small letters and numbers. No space or special characters please. Min 4 and max 20 chars.' }); } } removeTag(position) { const { tags } = this.state; const newTags = [...tags.slice(0, position), ...tags.slice(position + 1, tags.length)]; this.setState({ tags: newTags }); this.props.onChange(newTags); } renderTags() { const { tags } = this.state; return tags.map((tag, i) => { return ( { this.removeTag(i); }} /> ); }); } renderInput() { const { tagName, tags, } = this.state; const { maxTagCount } = this.props; if ( tags.length < maxTagCount ) { return (
{ this.setState({ tagName: e.target.value }); }} />
); } return null; } render() { const { errorMsg, tagName, tags, } = this.state; const { maxTagCount } = this.props; return (
Tags :
{ this.renderTags() } { this.renderInput() }
{ errorMsg &&
{errorMsg}
}
); } } TagsInput.defaultProps = { value: [], maxTagCount: 3, onChange: (tags) => {}, }; TagsInput.propTypes = { value: React.PropTypes.array, maxTagCount: React.PropTypes.number, onChange: React.PropTypes.func, }; export default TagsInput; ================================================ FILE: frontend/Components/NewDiscussion/TagsInput/styles.css ================================================ @value primaryFontColor, secondaryFontColor, borderColor from 'SharedStyles/globalStyles.css'; @value smallBP from 'SharedStyles/globalStyles.css'; .container { margin: 0px 0px 0px 10px; } .tagContainer { height: 36px; display: flex; flex-wrap: wrap; align-items: center; } .label { } .inputContainer { display: flex; align-items: center; } .tagInput { width: 100px; padding: 10px 10px; border: none; outline: none; background-color: none; } .addButton { padding: 5px 10px; font-size: 20px; } .errorMsg { font-weight: bold; margin-top: 5px; color: rgba(231, 76, 60,1.0); font-size: 12px; line-height: 14px; } ================================================ FILE: frontend/Components/RichEditor/BlockStyleControls.js ================================================ import React, { Component } from 'react'; import classnames from 'classnames'; import styles from './styles.css'; import Button from 'Components/Button'; import StyleButton from './StyleButton'; class BlockStyleControls extends Component { render() { const { onToggle, editorState, type, } = this.props; const blockTypes = [ // {label: 'H1', style: 'header-one'}, // {label: 'H2', style: 'header-two'}, {label: 'H3', style: 'header-three'}, {label: 'H4', style: 'header-four'}, {label: 'H5', style: 'header-five'}, // {label: 'H6', style: 'header-six'}, {label: 'Blockquote', style: 'blockquote'}, // {label: 'UL', style: 'unordered-list-item'}, // {label: 'OL', style: 'ordered-list-item'}, {label: 'Code Block', style: 'code-block'}, ]; const selection = editorState.getSelection(); const blockType = editorState .getCurrentContent() .getBlockForKey(selection.getStartKey()) .getType(); return (
{ blockTypes.map((eachType) => ) }
); } } BlockStyleControls.propTypes = { onToggle: React.PropTypes.func.isRequired, editorState: React.PropTypes.any.isRequired, type: React.PropTypes.oneOf(['newDiscussion', 'newOpinion']), }; export default BlockStyleControls; ================================================ FILE: frontend/Components/RichEditor/InlineStyleControls.js ================================================ import React, { Component } from 'react'; import classnames from 'classnames'; import styles from './styles.css'; import Button from 'Components/Button'; import StyleButton from './StyleButton'; class InlineStyleControls extends Component { render() { const { onToggle, editorState, } = this.props; const inlineStyles = [ {label: 'Bold', style: 'BOLD'}, {label: 'Italic', style: 'ITALIC'}, // {label: 'Underline', style: 'UNDERLINE'}, {label: 'Monospace', style: 'CODE'}, ]; const currentStyle = editorState.getCurrentInlineStyle(); return (
{ inlineStyles.map((eachType) => ) }
); } } InlineStyleControls.propTypes = { onToggle: React.PropTypes.func.isRequired, editorState: React.PropTypes.any.isRequired, type: React.PropTypes.oneOf(['newDiscussion', 'newOpinion']), }; export default InlineStyleControls; ================================================ FILE: frontend/Components/RichEditor/StyleButton.js ================================================ import React, { Component } from 'react'; import classnames from 'classnames'; import styles from './styles.css'; class StyleButton extends React.Component { constructor() { super(); this.onToggle = (e) => { e.preventDefault(); this.props.onToggle(this.props.style); }; } render() { let className = `${styles.controlButton}`; if (this.props.active) { className += ` ${styles.controlButtonActive}`; } return (
{this.props.label}
); } } StyleButton.propTypes = { onToggle: React.PropTypes.func.isRequired, active: React.PropTypes.any.isRequired, label: React.PropTypes.string.isRequired, style: React.PropTypes.string.isRequired, }; export default StyleButton; ================================================ FILE: frontend/Components/RichEditor/index.js ================================================ import React, { Component } from 'react'; import { Editor, EditorState, ContentState, RichUtils, convertToRaw, convertFromRaw, } from 'draft-js'; import classnames from 'classnames'; import styles from './styles'; import Button from 'Components/Button'; import BlockStyleControls from './BlockStyleControls'; import InlineStyleControls from './InlineStyleControls'; class RichEditor extends Component { constructor(props) { super(props); this.state = { editorState: EditorState.createEmpty(), }; this.focus = () => this.refs.editor.focus(); this.onEditorStateChange = this.onEditorStateChange.bind(this); this.handleKeyCommand = this.handleKeyCommand.bind(this); this.onTab = this.onTab.bind(this); this.toggleBlockType = this.toggleBlockType.bind(this); this.toggleInlineStyle = this.toggleInlineStyle.bind(this); } componentDidMount() { const { value } = this.props; if (value) { const contentState = convertFromRaw(JSON.parse(value)); const editorState = EditorState.createWithContent(contentState); this.setState({ editorState }); } } onEditorStateChange(editorState) { const { onChange } = this.props; this.setState({ editorState }); // trigger on change converting the ContentState to raw object onChange(JSON.stringify(convertToRaw(editorState.getCurrentContent()))); } handleKeyCommand(command) { const newState = RichUtils.handleKeyCommand(this.state.editorState, command); if (newState) { this.onEditorStateChange(newState); return true; } return false; } onTab(event) { const maxDepth = 4; this.onEditorStateChange(RichUtils.onTab(event, this.state.editorState, maxDepth)); } toggleBlockType(blockType) { this.onEditorStateChange( RichUtils.toggleBlockType( this.state.editorState, blockType ) ); } toggleInlineStyle(inlineStyle) { this.onEditorStateChange( RichUtils.toggleInlineStyle( this.state.editorState, inlineStyle ) ); } customBlockStyles(contentBlock) { const type = contentBlock.getType(); if (type === 'blockquote') return styles.editorBlockquoteStyle; if (type === 'code-block') return styles.editorCodeStyle; if (type === 'header-one') return styles.editorH1Style; if (type === 'header-two') return styles.editorH2Style; if (type === 'header-three') return styles.editorH3Style; } render() { const { type, onSave, readOnly, } = this.props; // styling for inline styles const inlineStyleMap = { 'CODE': { color: '#e74c3c', backgroundColor: '#f9f9f9', border: '1px solid #e8e8e8', fontFamily: 'monospace', padding: '2px 5px', margin: '0px 5px', }, }; let saveButtonLabel = ''; if (type === 'newOpinion') saveButtonLabel = 'Reply'; if (type === 'newDiscussion') saveButtonLabel = 'Post Discussion'; let placeholder = ''; if (type === 'newOpinion') placeholder = 'Your opinion...'; if (type === 'newDiscussion') placeholder = 'Discussion summary...'; return (
{ !readOnly &&
}
{ !readOnly && }
); } } RichEditor.defaultProps = { readOnly: false, value: null, type: 'newDiscussion', onChange: () => { }, onSave: () => { }, }; RichEditor.propTypes = { readOnly: React.PropTypes.bool, value: React.PropTypes.any, type: React.PropTypes.oneOf(['newDiscussion', 'newOpinion']), onChange: React.PropTypes.func, onSave: React.PropTypes.func, }; export default RichEditor; ================================================ FILE: frontend/Components/RichEditor/styles.css ================================================ @value borderColor, secondaryFontColor, primaryFontColor, backShade from 'SharedStyles/globalStyles.css'; @value smallBP from 'SharedStyles/globalStyles'; /** * RichEditor styles */ .container { margin-top: 10px; margin-bottom: 20px; display: flex; flex-direction: column; align-items: flex-start; border: 1px solid borderColor; } .readOnlyContainer { border: none; } .editorContainer { padding: 10px 10px; width: 100%; min-height: 60px; border-bottom: 1px solid borderColor; cursor: text; & :global .public-DraftEditorPlaceholder-root { position: absolute; color: secondaryFontColor; } } .readOnlyEditorContainer { padding: 0px; border-bottom: none; } .buttonClass { margin-top: 20px; } .newDiscussion { min-height: 300px; } /** * Controls */ .controlsContainer { width: 100%; display: flex; flex-direction: row; border-bottom: 1px solid borderColor; @media smallBP { flex-direction: column-reverse; } } .controls { display: flex; } .controlButton { padding: 10px 10px; user-select: none; cursor: pointer; text-transform: uppercase; color: secondaryFontColor; font-weight: 700; font-size: 12px; letter-spacing: 0.5px; transition: color 0.3s; &:hover { color: primaryFontColor; } @media smallBP { padding: 5px 10px; } } .controlButtonActive { color: primaryFontColor; } /** * editor text styles */ .editorBlockquoteStyle { display: inline-block; position: relative; margin: 10px 0px 10px 20px; padding: 10px 20px; background-color: backShade; font-style: italic; } .editorBlockquoteStyle::before { content: ''; position: absolute; height: 100%; width: 5px; left: 0px; top: 0px; background-color: borderColor; } .editorCodeStyle { margin: 0px; padding: 0px; line-height: 18px; overflow-x: hidden; } :global .public-DraftStyleDefault-pre { margin: 10px 0px; padding: 5px 5px; background-color: backShade; border: 1px solid borderColor; } .editorH1Style, .editorH2Style, .editorH3Style { color: #4c4c4c; } .editorH1Style { font-size: 1.6em; } .editorH2Style { font-size: 1.3em; } .editorH3Style { font-size: 1.1em; } ================================================ FILE: frontend/Components/SideBar/index.js ================================================ import React, { Component } from 'react'; import { Link } from 'react-router'; import styles from './styles'; import Button from 'Components/Button'; class SideBar extends Component { render() { const { currentForum, } = this.props; return (
); } } SideBar.defaultProps = { currentForum: 'general', }; SideBar.propTypes = { currentForum: React.PropTypes.string, }; export default SideBar; ================================================ FILE: frontend/Components/SideBar/styles.css ================================================ @value smallBP, mediumBP, largeBP from 'SharedStyles/globalStyles'; /** * SideBar component styles */ .sidebarContainer { width: 250px; margin-left: 10px; } ================================================ FILE: frontend/Components/SingleDiscussion/Discussion/index.js ================================================ import _ from 'lodash'; import React, { Component } from 'react'; import { Link } from 'react-router'; import moment from 'moment'; import classnames from 'classnames'; import styles from './styles.css'; import PlaceholderImage from 'SharedStyles/placeholder.jpg'; import Button from 'Components/Button'; import Tag from 'Components/Tag'; import RichEditor from 'Components/RichEditor'; class Discussion extends Component { render() { const { id, userAvatar, userName, userGitHandler, discTitle, discDate, discContent, tags, favoriteCount, favoriteAction, userFavorited, toggleingFavorite, allowDelete, deletingDiscussion, deleteAction, } = this.props; let dateDisplay = moment(discDate); dateDisplay = dateDisplay.from(moment()); let favCount = ''; if (toggleingFavorite) favCount = 'Toggling Favorite...'; else if (userFavorited) favCount = `Favorited (${favoriteCount})`; else if (favoriteCount === 0) favCount = 'Make favorite'; else if (favoriteCount === 1) favCount = '1 favorite'; else favCount = `${favoriteCount} favorites`; return (
{userName || userGitHandler} {userGitHandler}
{dateDisplay}
{discTitle}
{ tags.map(tag => )}
{ allowDelete && }
{ deletingDiscussion &&
Deleting Discussion...
}
); } } Discussion.defaultProps = { id: 0, userAvatar: PlaceholderImage, userName: 'User name', userGitHandler: 'github', discTitle: 'Default Discussion Title', discDate: 'a day ago', discContent: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', tags: [ 'react', 'redux', 'webkit' ], favoriteCount: 1, favoriteAction: () => { }, userFavorited: false, toggleingFavorite: false, allowDelete: false, deletingDiscussion: false, deleteAction: () => { }, }; Discussion.propTypes = { id: React.PropTypes.any, userAvatar: React.PropTypes.string, userName: React.PropTypes.string, userGitHandler: React.PropTypes.string, discTitle: React.PropTypes.string, discDate: React.PropTypes.any, discContent: React.PropTypes.any, tags: React.PropTypes.array, favoriteCount: React.PropTypes.number, favoriteAction: React.PropTypes.func, userFavorited: React.PropTypes.bool, toggleingFavorite: React.PropTypes.bool, allowDelete: React.PropTypes.bool, deletingDiscussion: React.PropTypes.bool, deleteAction: React.PropTypes.func, }; export default Discussion; ================================================ FILE: frontend/Components/SingleDiscussion/Discussion/styles.css ================================================ @value borderColor, secondaryFontColor, primaryFontColor from 'SharedStyles/globalStyles.css'; @value smallBP from 'SharedStyles/globalStyles.css'; /** * Discussion styles */ .container { padding: 20px 10px 0px 10px; position: relative; } .infoContainer { display: flex; align-items: center; & .avatar { width: 42px; height: 42px; border-radius: 50px; } & .columnOnSmallBP { flex: 1; display: flex; @media smallBP { flex-direction: column; } } & .userInfo { margin-left: 10px; flex: 1; display: flex; & .name { font-weight: 700; color: primaryFontColor; text-decoration: none; } & .gitHandler { margin-left: 15px; text-decoration: none; color: secondaryFontColor; transition: color 0.3s; &:hover { color: primaryFontColor; } & .gitIcon { margin-right: 5px; } } } & .dateInfo { font-size: 13px; color: secondaryFontColor; @media smallBP { margin-left: 10px; } } } .discTitle { margin-top: 15px; font-size: 24px; line-height: 32px; font-weight: 400; } .discContent { margin-top: 10px; font-size: 15px; line-height: 26px; } .discFooter { margin-top: 10px; display: flex; align-items: center; @media smallBP { flex-direction: column; align-items: flex-start; } & .tags { flex: 1; } & .favoriteButton, & .deleteButton { @media smallBP { margin-top: 5px; padding-left: 0px; padding-right: 0px; } & i { font-size: 20px; margin-right: 10px; } } } .deletingDiscussion { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(255, 255, 255, 0.9); display: flex; justify-content: center; align-items: center; } ================================================ FILE: frontend/Components/SingleDiscussion/Opinion/index.js ================================================ import React, { Component } from 'react'; import { Link } from 'react-router'; import moment from 'moment'; import classnames from 'classnames'; import styles from './styles.css'; import PlaceholderImage from 'SharedStyles/placeholder.jpg'; import Button from 'Components/Button'; import RichEditor from 'Components/RichEditor'; class Opinion extends Component { render() { const { opinionId, userAvatar, userName, userGitHandler, opDate, opContent, userId, currentUserId, currentUserRole, deleteAction, deletingOpinion, } = this.props; let dateDisplay = moment(opDate); dateDisplay = dateDisplay.from(moment()); const allowDelete = (userId === currentUserId) || (currentUserRole === 'admin'); return (
{userName || userGitHandler} {userGitHandler}
{dateDisplay}
{ allowDelete && } {/* */}
{ (deletingOpinion === opinionId) &&
Deleting Opinion ...
}
); } } Opinion.defaultProps = { opinionId: '12345', userAvatar: PlaceholderImage, userName: 'User name', userGitHandler: 'github', opDate: 'a day ago', opContent: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', userId: '12345', currentUserId: '12345', currentUserRole: 'user', deleteAction: () => {}, deletingOpinion: null, }; Opinion.propTypes = { opinionId: React.PropTypes.string, userAvatar: React.PropTypes.string, userName: React.PropTypes.string, userGitHandler: React.PropTypes.string, opDate: React.PropTypes.any, opContent: React.PropTypes.string, userId: React.PropTypes.string, currentUserId: React.PropTypes.string, currentUserRole: React.PropTypes.string, deleteAction: React.PropTypes.func, deletingOpinion: React.PropTypes.any, }; export default Opinion; ================================================ FILE: frontend/Components/SingleDiscussion/Opinion/styles.css ================================================ @value borderColor, secondaryFontColor, primaryFontColor from 'SharedStyles/globalStyles.css'; @value smallBP from 'SharedStyles/globalStyles.css'; /** * Opinion styles */ .container { position: relative; margin-bottom: 10px; padding: 0px 10px 0px 10px; border: 1px solid borderColor; /*border-bottom: none; &:last-child { border-bottom: 1px solid borderColor; }*/ & .deletingOpinion { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; background-color: rgba(255, 255, 255, 0.9); } } .infoContainer { padding: 5px 0px; display: flex; align-items: center; border-bottom: 1px solid borderColor; & .avatar { width: 32px; height: 32px; border-radius: 50px; } & .userInfo { margin-left: 10px; flex: 1; display: flex; & .name { font-weight: 700; color: primaryFontColor; text-decoration: none; } & .gitHandler { margin-left: 15px; text-decoration: none; color: secondaryFontColor; transition: color 0.3s; &:hover { color: primaryFontColor; } & .gitIcon { margin-right: 5px; } } } & .dateInfo { font-size: 13px; line-height: 13px; color: secondaryFontColor; @media smallBP { margin-left: 10px; } } & .deleteButton { padding: 5px 10px; font-weight: normal; & .trashIcon { margin-right: 5px; font-size: 16px; } } } .opContent { margin-top: 10px; margin-bottom: 20px; min-height: 60px; font-size: 15px; line-height: 26px; } .commentFooter { display: flex; align-items: center; & .favoriteButton { padding: 10px 10px; display: flex; align-items: center; color: secondaryFontColor; cursor: pointer; user-select: none; transition: color 0.3s; &:hover { color: primaryFontColor; } & i { font-size: 20px; margin-right: 10px; } } } ================================================ FILE: frontend/Components/SingleDiscussion/ReplyBox/index.js ================================================ import React, { Component } from 'react'; import styles from './styles.css'; import RichEditor from 'Components/RichEditor'; class ReplyBox extends Component { render() { const { posting, onSubmit, onChange, } = this.props; if (posting) return
Posting your opinion...
; return ( ); } } ReplyBox.defaultProps = { posting: false, onSubmit: () => { }, onChange: (value) => { }, }; ReplyBox.propTypes = { posting: React.PropTypes.bool, onSubmit: React.PropTypes.func, onChange: React.PropTypes.func, }; export default ReplyBox; ================================================ FILE: frontend/Components/SingleDiscussion/ReplyBox/styles.css ================================================ @value primaryFontColor, secondaryFontColor from 'SharedStyles/globalStyles.css'; /** * Reply styles */ .loadingWrapper { font-size: 12px; font-weight: bold; text-align: center; padding: 30px 0px; color: secondaryFontColor; } ================================================ FILE: frontend/Components/Tag/index.js ================================================ import React, { Component } from 'react'; import classnames from 'classnames'; import styles from './styles'; import Button from 'Components/Button'; class Tag extends Component { render() { const { name, withRemove, removeAction, } = this.props; return (
{name} { withRemove && }
); } } Tag.defaultProps = { name: '', withRemove: false, removeAction: () => {}, }; Tag.propTypes = { name: React.PropTypes.string.isRequired, withRemove: React.PropTypes.bool, removeAction: React.PropTypes.func, }; export default Tag; ================================================ FILE: frontend/Components/Tag/styles.css ================================================ @value secondaryFontColor, backShade from 'SharedStyles/globalStyles'; /** * Tag styles */ .tag { display: inline-block; height: 25px; margin-left: 10px; padding: 0 10px; background-color: backShade; color: secondaryFontColor; font-size: 12px; line-height: 25px; user-select: none; &:first-child { margin-left: 0; } } .tagWithRemove { display: flex; align-items: center; padding-right: 0px; } .removeButton { padding: 4px 10px; } ================================================ FILE: frontend/Components/UserProfile/Profile/index.js ================================================ import React, { Component } from 'react'; import classnames from 'classnames'; import styles from './styles.css'; class Profile extends Component { render() { const { name, gitHandler, location, avatarUrl, } = this.props; return (
{`${name}
{ name }
{ gitHandler }
{ location }
); } } Profile.defaultProps = { name: 'Hello World', gitHandler: 'helloWorld', location: 'Somewhere in the world', avatarUrl: 'https://google.com', }; Profile.propTypes = { name: React.PropTypes.string, gitHandler: React.PropTypes.string, location: React.PropTypes.string, avatarUrl: React.PropTypes.string, }; export default Profile; ================================================ FILE: frontend/Components/UserProfile/Profile/styles.css ================================================ @value primaryFontColor, secondaryFontColor from 'SharedStyles/globalStyles.css'; .container { display: flex; align-items: center; } .avatarContainer { & .avatar { width: 100px; height: 100px; border-radius: 10px; } } .infoContainer { margin-left: 20px; letter-spacing: 0.5px; & .name { font-size: 24px; margin-bottom: 10px; } & .gitHandler { font-size: 14px; font-weight: bold; } & .location { font-size: 14px; } } ================================================ FILE: frontend/Containers/AdminHeader/index.js ================================================ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { Link } from 'react-router'; import classnames from 'classnames'; import appLayout from 'SharedStyles/appLayout'; import styles from './styles'; // components for AdminHeader import UserMenu from 'Components/Header/UserMenu'; import Logo from 'Components/Header/Logo'; import NavigationBar from 'Components/Header/NavigationBar'; import PlaceholderImage from 'SharedStyles/placeholder.jpg'; class AdminHeader extends Component { renderNavLinks() { return [ { name: 'Dashboard', link: '/admin' }, ]; } render() { const { authenticated, name, username, avatarUrl, } = this.props.user; return (
Welcome Admin
); } } export default connect( (state) => { return { user: state.user, forums: state.app.forums, }; } )(AdminHeader); ================================================ FILE: frontend/Containers/AdminHeader/styles.css ================================================ @value smallBP from 'SharedStyles/globalStyles.css'; /** * Header Styles */ .headerTop { height: 50px; display: flex; align-items: center; justify-content: space-between; @media smallBP { padding: 0px 10px; } } ================================================ FILE: frontend/Containers/Header/index.js ================================================ import React, { Component } from 'react'; import { connect } from 'react-redux'; import classnames from 'classnames'; import appLayout from 'SharedStyles/appLayout'; import styles from './styles'; // components for Header import UserMenu from 'Components/Header/UserMenu'; import Logo from 'Components/Header/Logo'; import NavigationBar from 'Components/Header/NavigationBar'; import PlaceholderImage from 'SharedStyles/placeholder.jpg'; class Header extends Component { renderNavLinks() { const { forums } = this.props; if (forums) { return forums.map((forum) => { return { id: forum._id, name: forum.forum_name, link: `/${forum.forum_slug}`, }; }); } return null; } render() { const { authenticated, name, username, avatarUrl, } = this.props.user; return (
); } } export default connect( (state) => { return { user: state.user, forums: state.app.forums, }; } )(Header); ================================================ FILE: frontend/Containers/Header/styles.css ================================================ @value smallBP from 'SharedStyles/globalStyles.css'; /** * Header Styles */ .headerTop { height: 50px; display: flex; align-items: center; justify-content: space-between; @media smallBP { padding: 0px 10px; } } ================================================ FILE: frontend/SharedStyles/appLayout.css ================================================ @value largeBP, mediumBP, smallBP from 'SharedStyles/globalStyles'; /** * application layout styles */ .constraintWidth { margin: 0px auto; min-width: 320px; max-width: 1100px; @media largeBP { padding: 0px; } @media mediumBP { padding: 0px 15px; } } .primaryContent { flex: 1; } .secondaryContent { width: 260px; @media mediumBP { display: none; } @media smallBP { display: none; } } .showOnMediumBP { display: none; @media mediumBP { display: inherit; } @media smallBP { display: inherit; } } ================================================ FILE: frontend/SharedStyles/globalStyles.css ================================================ /** * color variables */ @value themeColor: #F1C40F; @value primaryFontColor: #000; @value secondaryFontColor: #999; @value borderColor: #e8e8e8; @value backShade: #f9f9f9; /** * media query breakpoints */ @value largeBP: (min-width: 1100px); @value mediumBP: (min-width: 769px) and (max-width: 1099px); @value smallBP: (max-width: 768px); /** * global stylings */ * { box-sizing: border-box; } /** * typography */ body { font-size: 14px; line-height: 22px; font-family: 'Lato', helvetica, arial, sans-serif; } ================================================ FILE: frontend/Views/AdminDashboard/actions.js ================================================ import { GET_ALL_INFO_START, GET_ALL_INFO_SUCCESS, GET_ALL_INFO_FAILURE, CREATE_FORUM, CREATE_FORUM_SUCCESS, CREATE_FORUM_FAILURE, DELETE_FORUM, DELETE_FORUM_SUCCESS, DELETE_FORUM_FAILURE, } from './constants'; import { getAdminDashboardInfoAPI, createForumAPI, deleteForumAPI, } from './api'; /** * get all the info needed for dashboard * @return {action} */ export const getAdminDashboardInfo = () => { return (dispatch, getState) => { dispatch({ type: GET_ALL_INFO_START }); getAdminDashboardInfoAPI().then( data => dispatch({ type: GET_ALL_INFO_SUCCESS, payload: data.data }), error => dispatch({ type: FETCHING_DISCUSSIONS_FAILURE, payload: error }) ); }; }; /** * create a new forum * @param {Object} forumObj * @return {action} */ export const createForum = (forumObj) => { return (dispatch, getState) => { dispatch({ type: CREATE_FORUM }); // call the create forum api createForumAPI(forumObj).then( forumData => { // get admin info again to refresh the infos getAdminDashboardInfoAPI().then( data => { // data is refreshed dispatch({ type: GET_ALL_INFO_SUCCESS, payload: data.data }); // check if the forum was created if (forumData.data.created) { dispatch({ type: CREATE_FORUM_SUCCESS }); } else dispatch({ type: CREATE_FORUM_FAILURE }); }, error => dispatch({ type: FETCHING_DISCUSSIONS_FAILURE, payload: error }) ); }, error => dispatch({ type: CREATE_FORUM_FAILURE }) ); }; }; export const deleteForum = (forumId) => { return (dispatch, getState) => { dispatch({ type: DELETE_FORUM }); deleteForumAPI(forumId).then( forumData => { dispatch({ type: GET_ALL_INFO_START }); // get admin info again to refresh the infos getAdminDashboardInfoAPI().then( data => { dispatch({ type: GET_ALL_INFO_SUCCESS, payload: data.data }); // check if th eforum was deleted if (forumData.data.deleted) { dispatch({ type: DELETE_FORUM_SUCCESS }); } else dispatch({ type: DELETE_FORUM_FAILURE }); }, error => dispatch({ type: FETCHING_DISCUSSIONS_FAILURE, payload: error }) ); }, error => dispatch({ type: DELETE_FORUM_FAILURE }) ); }; }; ================================================ FILE: frontend/Views/AdminDashboard/api.js ================================================ import axios from 'axios'; export const getAdminDashboardInfoAPI = () => { return (axios.get('/api/admin/admin_dashboard_info')); }; export const createForumAPI = (forum_obj) => { return (axios.post('/api/admin/create_forum', forum_obj)); }; export const deleteForumAPI = (forum_id) => { return (axios.post('/api/admin/delete_forum', { forum_id })); }; ================================================ FILE: frontend/Views/AdminDashboard/constants.js ================================================ export const GET_ALL_INFO_START = 'get_all_info_start'; export const GET_ALL_INFO_SUCCESS = 'get_all_info_success'; export const GET_ALL_INFO_FAILURE = 'get_all_info_failure'; export const CREATE_FORUM = 'create_forum'; export const CREATE_FORUM_SUCCESS = 'create_forum_success'; export const CREATE_FORUM_FAILURE = 'create_forum_failure'; export const DELETE_FORUM = 'delete_forum'; export const DELETE_FORUM_SUCCESS = 'delete_forum_success'; export const DELETE_FORUM_FAILURE = 'delete_forum_failure'; ================================================ FILE: frontend/Views/AdminDashboard/index.js ================================================ import React, { Component } from 'react'; import { Link } from 'react-router'; import { connect } from 'react-redux'; import classnames from 'classnames'; import appLayout from 'SharedStyles/appLayout.css'; import styles from './styles.css'; import { getAdminDashboardInfo, getForums, createForum, deleteForum, } from './actions'; import Counts from 'Components/Dashboard/Counts'; import ForumBox from 'Components/Dashboard/ForumBox'; class Dashboard extends Component { componentDidMount() { // get information needed for dashboard this.props.getAdminDashboardInfo(); } render() { const { discussionCount, opinionCount, forumCount, userCount, forums, } = this.props.adminInfo.info; const { loadingInfo, creatingForum, creatingForumError, deletingForum, deletingForumError, } = this.props; const forumsArray = forums.map((forum) => { return { id: forum._id, name: forum.forum_name, slug: forum.forum_slug }; }); return (
{ loadingInfo &&
Loading dashboard info...
}
{ this.props.deleteForum(forumId); }} creatingForum={creatingForum} createAction={(forumObj) => { this.props.createForum(forumObj); }} /> { creatingForumError &&
{creatingForumError}
} { deletingForumError &&
{deletingForumError}
}
); } } export default connect( (state) => { return { adminInfo: state.adminInfo, loadingInfo: state.adminInfo.loadingInfo, creatingForum: state.adminInfo.creatingForum, creatingForumError: state.adminInfo.creatingForumError, deletingForum: state.adminInfo.deletingForum, deletingForumError: state.adminInfo.deletingForumError, }; }, (dispatch) => { return { getAdminDashboardInfo: () => { dispatch(getAdminDashboardInfo()); }, getForums: () => { dispatch(getForums()); }, deleteForum: (forumId) => { dispatch(deleteForum(forumId)); }, createForum: (forumObj) => { dispatch(createForum(forumObj)); }, }; } )(Dashboard); ================================================ FILE: frontend/Views/AdminDashboard/reducers.js ================================================ import { GET_ALL_INFO_START, GET_ALL_INFO_SUCCESS, GET_ALL_INFO_FAILURE, CREATE_FORUM, CREATE_FORUM_SUCCESS, CREATE_FORUM_FAILURE, DELETE_FORUM, DELETE_FORUM_SUCCESS, DELETE_FORUM_FAILURE, } from './constants'; const initialState = { loadingInfo: false, info: { discussionCount: 0, opinionCount: 0, forumCount: 0, userCount: 0, forums: [], }, error: null, creatingForum: false, creatingForumError: null, deletingForum: false, deletingForumError: null, }; export const adminInfoReducer = (state = initialState, action) => { switch (action.type) { case GET_ALL_INFO_START: return Object.assign({}, state, { loadingInfo: true, error: null, }); case GET_ALL_INFO_SUCCESS: return Object.assign({}, state, { loadingInfo: false, info: action.payload, error: null, }); case GET_ALL_INFO_FAILURE: return Object.assign({}, state, { loadingInfo: false, error: 'Something went wrong while loading admin level information.', }); case CREATE_FORUM: return Object.assign({}, state, { creatingForumError: null, creatingForum: true, }); case CREATE_FORUM_SUCCESS: return Object.assign({}, state, { creatingForum: false, creatingForumError: null, }); case CREATE_FORUM_FAILURE: return Object.assign({}, state, { creatingForum: false, creatingForumError: 'Something went wrong while trying to create the forum. Please try again. Also check out if the forum already exists.', }); case DELETE_FORUM: return Object.assign({}, state, { deletingForum: true, deletingForumError: null, }); case DELETE_FORUM_SUCCESS: return Object.assign({}, state, { deletingForum: false, deletingForumError: null, }); case DELETE_FORUM_FAILURE: return Object.assign({}, state, { deletingForum: false, deletingForumError: 'Something went wrong while trying to delete the forum. Please try again later.', }); default: return state; } }; ================================================ FILE: frontend/Views/AdminDashboard/styles.css ================================================ @value smallBP from 'SharedStyles/globalStyles'; .container { margin-top: 20px; position: relative; } .countsContainer { margin-top: 40px; margin-bottom: 40px; display: flex; justify-content: space-around; @media smallBP { flex-wrap: wrap; } } .loadingMsg { margin-top: -30px; position: absolute; top: 0px; left: 0px; width: 100%; text-align: center; } .errorMsg { font-weight: bold; padding: 10px 0px; color: rgba(231, 76, 60,1.0); font-size: 12px; line-height: 14px; text-align: center; } ================================================ FILE: frontend/Views/ForumFeed/actions.js ================================================ import _ from 'lodash'; import { START_FETCHING_DISCUSSIONS, STOP_FETCHING_DISCUSSIONS, FETCHING_DISCUSSIONS_SUCCESS, FETCHING_DISCUSSIONS_FAILURE, START_FETCHING_PINNED_DISCUSSIONS, STOP_FETCHING_PINNED_DISCUSSIONS, FETCHING_PINNED_DISCUSSIONS_SUCCESS, FETCHING_PINNED_DISCUSSIONS_FAILURE, UPDATE_SORTING_METHOD, INVALID_FORUM, } from './constants'; import { fetchDiscussions, fetchPinnedDiscussions, } from './api'; /** * find the id for current forum * @param {Object} state the state object * @param {String} forum current forum * @return {Number} the forum id */ const findForumId = (state, forum) => { const { forums } = state.app; const forumId = _.find(forums, { forum_slug: forum }); if (forumId) { return forumId._id; } else { return null; } }; /** * action to fetch forum discussions * @param {String} forum current forum slug * @param {Boolean} feedChanged if the feed has been changed, default is false * @param {String} sortingMethod define the sorting method, default is 'date' * @param {Boolean} sortingChanged if user chagned the sorting method * @return {thunk} */ export const getDiscussions = (forumId, feedChanged=false, sortingChanged=false) => { return (dispatch, getState) => { const sortingMethod = getState().feed.sortingMethod; // show the loading message when user change forum or change sorting method if (feedChanged || sortingChanged) dispatch({ type: START_FETCHING_DISCUSSIONS }); if (!forumId) { dispatch({ type: INVALID_FORUM }); } else { // start fetching discussions fetchDiscussions(forumId, sortingMethod).then( data => dispatch({ type: FETCHING_DISCUSSIONS_SUCCESS, payload: data.data }), error => dispatch({ type: FETCHING_DISCUSSIONS_FAILURE }) ); } }; }; /** * action to fetch forum pinned discussions * @param {String} forum current forum * @param {Boolean} [feedChanged=false] if the feed has been changed * @return {thunk} */ export const getPinnedDiscussions = (forumId, feedChanged) => { return (dispatch, getState) => { // show the loading message when user change forum if (feedChanged) dispatch({ type: START_FETCHING_PINNED_DISCUSSIONS });; if (!forumId) { dispatch({ type: INVALID_FORUM }); } else { // start fetching pinned discussions return fetchPinnedDiscussions(forumId).then( data => dispatch({ type: FETCHING_PINNED_DISCUSSIONS_SUCCESS, payload: data.data }), error => { console.log(error); dispatch({ type: FETCHING_PINNED_DISCUSSIONS_FAILURE }); } ); } }; }; /** * Update sorting method * @param {String} method * @return {action} */ export const updateSortingMethod = (method) => { return { type: UPDATE_SORTING_METHOD, payload: method }; }; ================================================ FILE: frontend/Views/ForumFeed/api.js ================================================ import axios from 'axios'; /** * feed apis */ export const fetchDiscussions = (forum_id, sortingMethod) => { return axios.get(`/api/forum/${forum_id}/discussions?sorting_method=${sortingMethod}`); }; export const fetchPinnedDiscussions = (forum_id) => { return axios.get(`/api/forum/${forum_id}/pinned_discussions`); }; ================================================ FILE: frontend/Views/ForumFeed/constants.js ================================================ export const START_FETCHING_DISCUSSIONS = 'start_fetching_discussions'; export const STOP_FETCHING_DISCUSSIONS = 'stop_fetching_discussions'; export const FETCHING_DISCUSSIONS_SUCCESS = 'fetching_discussions_success'; export const FETCHING_DISCUSSIONS_FAILURE = 'fetching_discussions_failure'; export const START_FETCHING_PINNED_DISCUSSIONS = 'start_fetching_pinned_discussions'; export const STOP_FETCHING_PINNED_DISCUSSIONS = 'stop_fetching_pinned_discussions'; export const FETCHING_PINNED_DISCUSSIONS_SUCCESS = 'fetching_pinned_discussions_success'; export const FETCHING_PINNED_DISCUSSIONS_FAILURE = 'fetching_pinned_discussions_failure'; export const UPDATE_SORTING_METHOD = 'update_sorting_method'; export const INVALID_FORUM = 'invalid_forum'; ================================================ FILE: frontend/Views/ForumFeed/index.js ================================================ import React, { Component } from 'react'; import { Link } from 'react-router'; import { connect } from 'react-redux'; import { Helmet } from 'react-helmet'; import classnames from 'classnames'; import { getDiscussions, getPinnedDiscussions, updateSortingMethod, } from './actions'; import Button from 'Components/Button'; import FeedBox from 'Components/FeedBox'; import SideBar from 'Components/SideBar'; import appLayout from 'SharedStyles/appLayout.css'; import styles from './styles.css'; class ForumFeed extends Component { componentDidMount() { const { currentForumId, getDiscussions, getPinnedDiscussions, } = this.props; // get the discussions and pinned discussions getDiscussions(currentForumId()); getPinnedDiscussions(currentForumId()); } componentDidUpdate(prevProps) { const { currentForum, currentForumId, getDiscussions, getPinnedDiscussions, } = this.props; // get the discussions again // if the forum didn't matched if (prevProps.currentForum !== currentForum) { const feedChanged = true; getDiscussions(currentForumId(), feedChanged); getPinnedDiscussions(currentForumId(), feedChanged); } } handleSortingChange(newSortingMethod) { const { currentForum, getDiscussions, updateSortingMethod, sortingMethod, } = this.props; if (sortingMethod !== newSortingMethod) { updateSortingMethod(newSortingMethod); getDiscussions(currentForum, false, true); } } renderNewDiscussionButtion() { const { currentForum } = this.props; return (
); } render() { const { currentForum, discussions, fetchingDiscussions, pinnedDiscussions, fetchingPinnedDiscussions, sortingMethod, error, } = this.props; if (error) { return (
{error}
); } return (
{`ReForum | ${currentForum}`}
{ this.renderNewDiscussionButtion() }
); } } export default connect( (state) => { return { currentForum: state.app.currentForum, currentForumId: () => { const currentForumObj = _.find(state.app.forums, { forum_slug: state.app.currentForum }); if (currentForumObj) return currentForumObj._id; else return null; }, fetchingDiscussions: state.feed.fetchingDiscussions, discussions: state.feed.discussions, fetchingPinnedDiscussions: state.feed.fetchingPinnedDiscussions, sortingMethod: state.feed.sortingMethod, pinnedDiscussions: state.feed.pinnedDiscussions, error: state.feed.error, }; }, (dispatch) => { return { getDiscussions: (currentForumId, feedChanged, sortingMethod, sortingChanged) => { dispatch(getDiscussions(currentForumId, feedChanged, sortingMethod, sortingChanged)); }, getPinnedDiscussions: (currentForumId, feedChanged) => { dispatch(getPinnedDiscussions(currentForumId, feedChanged)); }, updateSortingMethod: (method) => { dispatch(updateSortingMethod(method)); }, }; } )(ForumFeed); ================================================ FILE: frontend/Views/ForumFeed/reducers.js ================================================ import { START_FETCHING_DISCUSSIONS, STOP_FETCHING_DISCUSSIONS, FETCHING_DISCUSSIONS_SUCCESS, FETCHING_DISCUSSIONS_FAILURE, START_FETCHING_PINNED_DISCUSSIONS, STOP_FETCHING_PINNED_DISCUSSIONS, FETCHING_PINNED_DISCUSSIONS_SUCCESS, FETCHING_PINNED_DISCUSSIONS_FAILURE, UPDATE_SORTING_METHOD, INVALID_FORUM, } from './constants'; const initialState = { fetchingDiscussions: true, discussions: null, fetchingPinnedDiscussions: true, pinnedDiscussions: null, sortingMethod: 'date', error: null, }; export const feedReducer = (state = initialState, action) => { switch(action.type) { case START_FETCHING_DISCUSSIONS: return Object.assign({}, state, { fetchingDiscussions: true, error: null, });; case STOP_FETCHING_DISCUSSIONS: return Object.assign({}, state, { fetchingDiscussions: false, });; case FETCHING_DISCUSSIONS_SUCCESS: return Object.assign({}, state, { discussions: action.payload, fetchingDiscussions: false, error: null, }); case FETCHING_DISCUSSIONS_FAILURE: return Object.assign({}, state, { fetchingDiscussions: false, error: 'Unable to fetch discussions at the moment.', }); case START_FETCHING_PINNED_DISCUSSIONS: return Object.assign({}, state, { fetchingPinnedDiscussions: true, error: null, });; case STOP_FETCHING_PINNED_DISCUSSIONS: return Object.assign({}, state, { fetchingPinnedDiscussions: false, });; case FETCHING_PINNED_DISCUSSIONS_SUCCESS: return Object.assign({}, state, { pinnedDiscussions: action.payload, fetchingPinnedDiscussions: false, error: null, }); case FETCHING_PINNED_DISCUSSIONS_FAILURE: return Object.assign({}, state, { fetchingPinnedDiscussions: false, error: 'Unable to fetch pinned discussions at the moment.', }); case UPDATE_SORTING_METHOD: return Object.assign({}, state, { sortingMethod: action.payload, }); case INVALID_FORUM: return Object.assign({}, state, { error: 'Sorry, couldn\'t find the forum.', fetchingPinnedDiscussions: false, fetchingDiscussions: false, }); default: return state; } }; ================================================ FILE: frontend/Views/ForumFeed/styles.css ================================================ @value largeBP from 'SharedStyles/globalStyles'; /** * Forum view styles */ .contentArea { display: flex; margin-top: 15px; @media largeBP { flex-flow: row nowrap; } } .newDiscussionBtn { margin-top: 20px; } .errorMsg { margin-top: 20px; color: rgba(231, 76, 60,1.0); text-align: center; font-size: 12px; font-weight: bold; } ================================================ FILE: frontend/Views/ForumFeed/tests/actions.test.js ================================================ import configureStore from 'redux-mock-store'; import thunk from 'redux-thunk'; import nock from 'nock'; import axios from 'axios'; import httpAdapter from 'axios/lib/adapters/http'; import * as actions from '../actions'; import * as constants from '../constants'; // configure axios const host = 'http://localhost:8080'; axios.defaults.host = host; axios.defaults.adapter = httpAdapter; // configure the mock store const middlewares = [thunk]; const mockStore = configureStore(middlewares); /** * testing getPinnedDiscussions action * @type {String} */ describe('getPinnedDiscussions', () => { afterEach(() => { // clean nock instances after each test nock.cleanAll(); }); it('should call FETCHING_PINNED_DISCUSSIONS_SUCCESS when fetching pinned discussion has been done', () => { // define a mock forumId const forumId = '1122334455'; // intercept axios calls with nock nock(host) .get(`/api/forum/${forumId}/pinned_discussions`) .reply(200, { pinnedDiscussions: [], }); // expected action list const expectedActions = [ { type: constants.START_FETCHING_PINNED_DISCUSSIONS }, { type: constants.FETCHING_PINNED_DISCUSSIONS_SUCCESS, payload: { pinnedDiscussions: [] }, }, ]; // initialize store with empty object const store = mockStore({}); // perform the test return store.dispatch(actions.getPinnedDiscussions(forumId, true)).then(() => { expect(store.getActions()).toEqual(expectedActions); }); }); }); /** * test updateSortingMethod action * @type {String} */ describe('updateSortingMethod', () => { it('should update the sorting method', () => { const method = 'popularity'; const expectedAction = { type: constants.UPDATE_SORTING_METHOD, payload: method, }; expect(actions.updateSortingMethod(method)).toEqual(expectedAction); }); }); ================================================ FILE: frontend/Views/NewDiscussion/actions.js ================================================ import { browserHistory } from 'react-router'; import { POSTING_DISCUSSION_START, POSTING_DISCUSSION_END, POSTING_DISCUSSION_SUCCESS, POSTING_DISCUSSION_FAILURE, UPDATE_DISCUSSION_TITLE, UPDATE_DISCUSSION_CONTENT, UPDATE_DISCUSSION_PIN_STATUS, UPDATE_DISCUSSION_TAGS, CLEAR_SUCCESS_MESSAGE, } from './constants'; import { postDiscussionApi } from './api'; /** * post a new discussion * @param {ObjectId} userId * @param {ObjectId} forumId * @param {String} currentForum * @return {action} */ export const postDiscussion = (userId, forumId, currentForum) => { return (dispatch, getState) => { dispatch({ type: POSTING_DISCUSSION_START }); // validate discussion inputs // discussion values are in redux state const { title, content, tags, pinned, } = getState().newDiscussion; let validated = true; if (!userId || !forumId) { validated = false; return dispatch({ type: POSTING_DISCUSSION_FAILURE, payload: 'Something is wrong with user/forum.', }); } if (title === null || title.length < 15) { validated = false; return dispatch({ type: POSTING_DISCUSSION_FAILURE, payload: 'Title should be at least 15 characters.', }); } if (content === null || content.length === 0) { validated = false; return dispatch({ type: POSTING_DISCUSSION_FAILURE, payload: 'Please write some content before posting.', }); } if (tags === null || tags.length === 0) { validated = false; return dispatch({ type: POSTING_DISCUSSION_FAILURE, payload: 'Please provide some tags.', }); } // make api call if post is validated if (validated) { postDiscussionApi({ userId, forumId, title, content, tags, pinned, }).then( (data) => { if (data.data.postCreated === true) { dispatch({ type: POSTING_DISCUSSION_SUCCESS }); setTimeout(() => { dispatch({ type: CLEAR_SUCCESS_MESSAGE }); }, 2000); // issue a redirect to the newly reacted discussion browserHistory.push(`/${currentForum}/discussion/${data.data.discussion_slug}`); } else { dispatch({ type: POSTING_DISCUSSION_FAILURE, payload: 'Something is wrong at our server end. Please try again later', }); } }, (error) => { dispatch({ type: POSTING_DISCUSSION_FAILURE, payload: error, }); } ); } }; }; /** * update the discussion title in redux state (controlled input) * @param {String} value * @return {action} */ export const updateDiscussionTitle = (value) => { return { type: UPDATE_DISCUSSION_TITLE, payload: value, }; }; /** * update discussion content in redux state (controlled input) * @param {Object} value * @return {action} */ export const updateDiscussionContent = (value) => { return { type: UPDATE_DISCUSSION_CONTENT, payload: value, }; }; /** * update discussion pinned status in redux state (controlled input) * @param {Boolean} value * @return {action} */ export const updateDiscussionPinStatus = (value) => { return { type: UPDATE_DISCUSSION_PIN_STATUS, payload: value, }; }; /** * update discussion tags in redux state (controlled input) * @param {Array} value * @return {action} */ export const updateDiscussionTags = (value) => { return { type: UPDATE_DISCUSSION_TAGS, payload: value, }; }; ================================================ FILE: frontend/Views/NewDiscussion/api.js ================================================ import axios from 'axios'; export const postDiscussionApi = (discussion) => { return axios.post('/api/discussion/newDiscussion', discussion); }; ================================================ FILE: frontend/Views/NewDiscussion/constants.js ================================================ export const POSTING_DISCUSSION_START = 'posting_discussion_start'; export const POSTING_DISCUSSION_END = 'posting_discussion_end'; export const POSTING_DISCUSSION_SUCCESS = 'posting_discussion_success'; export const POSTING_DISCUSSION_FAILURE = 'posting_discussion_failure'; export const UPDATE_DISCUSSION_TITLE = 'update_discussion_title'; export const UPDATE_DISCUSSION_CONTENT = 'update_discussion_content'; export const UPDATE_DISCUSSION_PIN_STATUS = 'update_discussion_pin_status'; export const UPDATE_DISCUSSION_TAGS = 'update_discussion_tags'; export const CLEAR_SUCCESS_MESSAGE = 'clear_success_message'; ================================================ FILE: frontend/Views/NewDiscussion/index.js ================================================ import _ from 'lodash'; import React, { Component } from 'react'; import { connect } from 'react-redux'; import { Helmet } from 'react-helmet'; import classnames from 'classnames'; import RichEditor from 'Components/RichEditor'; import PinButton from 'Components/NewDiscussion/PinButton'; import TagsInput from 'Components/NewDiscussion/TagsInput'; import { postDiscussion, updateDiscussionTitle, updateDiscussionContent, updateDiscussionPinStatus, updateDiscussionTags, } from './actions'; import styles from './styles.css'; import appLayout from 'SharedStyles/appLayout.css'; class NewDiscussion extends Component { constructor(props) { super(props); this.state = { forumId: null, userId: null, fatalError: null, }; } componentDidMount() { const { user, currentForum, forums, } = this.props; this.setUserAndForumID(user, forums, currentForum); } componentWillReceiveProps(nextProps) { const { user, currentForum, forums, } = nextProps; this.setUserAndForumID(user, forums, currentForum); } setUserAndForumID(user, forums, currentForum) { const forumId = _.find(forums, { forum_slug: currentForum }); if (forumId) { const currentForumId = forumId._id; this.setState({ forumId: currentForumId, userId: user._id, }); } else { this.setState({ fatalError: 'Invalid forum buddy, go for the right one!', }); } } renderEditor() { const { authenticated, role, } = this.props.user; const { updateDiscussionTitle, updateDiscussionContent, updateDiscussionPinStatus, updateDiscussionTags, postDiscussion, currentForum, } = this.props; const { title, content, tags, pinned, } = this.props.newDiscussion; const { forumId, userId, } = this.state; // only show the editor when user is authenticated if (authenticated) { return [ { updateDiscussionTitle(event.target.value); }} />, (role === 'admin') && { updateDiscussionPinStatus(value); }} />, { updateDiscussionTags(tags); }} />, { updateDiscussionContent(value); }} onSave={() => { postDiscussion(userId, forumId, currentForum); }} />, ]; } return (
Please sign in before posting a new discussion.
); } render() { const { fatalError } = this.state; if (fatalError) { return (
{fatalError}
); } const { currentForum } = this.props; const { errorMsg, postingSuccess, postingDiscussion, } = this.props.newDiscussion; return (
ReForum | New Discussion
You are creating a new discussion on {currentForum} forum.
{errorMsg}
{ postingSuccess &&
Your discussion is created :-)
} { this.renderEditor() } { postingDiscussion &&
Posting discussion...
}
); } } export default connect( (state) => { return { user: state.user, forums: state.app.forums, currentForum: state.app.currentForum, newDiscussion: state.newDiscussion, }; }, (dispatch) => { return { postDiscussion: (userId, forumId, currentForum) => { dispatch(postDiscussion(userId, forumId, currentForum)); }, updateDiscussionTitle: (value) => { dispatch(updateDiscussionTitle(value)); }, updateDiscussionContent: (value) => { dispatch(updateDiscussionContent(value)); }, updateDiscussionPinStatus: (value) => { dispatch(updateDiscussionPinStatus(value)); }, updateDiscussionTags: (value) => { dispatch(updateDiscussionTags(value)); }, }; } )(NewDiscussion); ================================================ FILE: frontend/Views/NewDiscussion/reducers.js ================================================ import { POSTING_DISCUSSION_START, POSTING_DISCUSSION_SUCCESS, POSTING_DISCUSSION_FAILURE, UPDATE_DISCUSSION_TITLE, UPDATE_DISCUSSION_CONTENT, UPDATE_DISCUSSION_PIN_STATUS, UPDATE_DISCUSSION_TAGS, CLEAR_SUCCESS_MESSAGE, } from './constants'; const initialState = { postingSuccess: false, errorMsg: null, postingDiscussion: false, title: '', content: null, tags: [], pinned: false, }; export const newDiscussionReducer = (state = initialState, action) => { switch (action.type) { case POSTING_DISCUSSION_START: return Object.assign({}, state, { postingDiscussion: true, }); case POSTING_DISCUSSION_SUCCESS: return Object.assign({}, initialState, { postingSuccess: true, postingDiscussion: false, errorMsg: null, }); case POSTING_DISCUSSION_FAILURE: return Object.assign({}, state, { postingSuccess: false, postingDiscussion: false, errorMsg: action.payload || 'Unable to post discussion.', }); case CLEAR_SUCCESS_MESSAGE: return Object.assign({}, initialState, { postingSuccess: false, }); case UPDATE_DISCUSSION_TITLE: return Object.assign({}, state, { title: action.payload, }); case UPDATE_DISCUSSION_CONTENT: return Object.assign({}, state, { content: action.payload, }); case UPDATE_DISCUSSION_PIN_STATUS: return Object.assign({}, state, { pinned: action.payload, }); case UPDATE_DISCUSSION_TAGS: return Object.assign({}, state, { tags: action.payload, }); default: return state; } }; ================================================ FILE: frontend/Views/NewDiscussion/styles.css ================================================ @value largeBP, borderColor, secondaryFontColor from 'SharedStyles/globalStyles'; .content { margin-top: 10px; position: relative; } .forumName { font-weight: bold; } .errorMsg { margin-top: 5px; color: rgba(231, 76, 60,1.0); font-size: 12px; font-weight: bold; line-height: 14px; } .fatalError { margin-top: 20px; text-align: center; } .titleInput { margin: 20px 0px 0px 0px; padding: 10px 10px; width: 100%; border: none; outline: none; background-color: none; font-size: 24px; font-weight: 300; /*border-bottom: 1px solid borderColor;*/ } .signInMsg { padding: 80px 0px; color: secondaryFontColor; text-align: center; } .postingMsg { position: absolute; width: 100%; height: 100%; top: 0px; display: flex; justify-content: center; align-items: center; background-color: rgba(255, 255, 255, 0.8); } ================================================ FILE: frontend/Views/NotFound/index.js ================================================ import React, { Component } from 'react'; class NotFound extends Component { render() { return (

Coudn't found the url buddy. Please check it out.

); } } export default NotFound; ================================================ FILE: frontend/Views/SingleDiscussion/actions.js ================================================ import { FETCHING_SINGLE_DISC_START, FETCHING_SINGLE_DISC_END, FETCHING_SINGLE_DISC_SUCCESS, FETCHING_SINGLE_DISC_FAILURE, TOGGLE_FAVORITE_START, TOGGLE_FAVORITE_SUCCESS, TOGGLE_FAVORITE_FAILURE, UPDATE_OPINION_CONTENT, POSTING_OPINION_START, POSTING_OPINION_SUCCESS, POSTING_OPINION_FAILURE, DELETE_DISC_START, DELETE_DISC_SUCCESS, DELETE_DISC_REDIRECT, DELETE_DISC_FAILURE, DELETE_OPINION_START, DELETE_OPINION_SUCCESS, DELETE_OPINION_FAILURE, } from './constants'; import { fetchSingleDiscussion, fetchOpinions, toggleFavoriteApi, postOpinionApi, deletePostApi, deleteOpinionApi, } from './api'; /** * get the discussion from server * @param {String} discussionSlug * @return {action} */ export const getDiscussion = (discussionSlug) => { return (dispatch, getState) => { dispatch({ type: FETCHING_SINGLE_DISC_START }); fetchSingleDiscussion(discussionSlug).then( data => { if (data.data) dispatch({ type: FETCHING_SINGLE_DISC_SUCCESS, payload: data.data }); else dispatch({ type: FETCHING_SINGLE_DISC_FAILURE }); }, error => dispatch({ type: FETCHING_SINGLE_DISC_FAILURE }) ); }; }; /** * toggle favorite status of the discussion * @param {ObjectId} discussionId * @return {action} */ export const toggleFavorite = (discussionId) => { return (dispatch, getState) => { dispatch({ type: TOGGLE_FAVORITE_START }); toggleFavoriteApi(discussionId).then( data => { if (data.data._id) { dispatch({ type: TOGGLE_FAVORITE_SUCCESS }); dispatch({ type: FETCHING_SINGLE_DISC_SUCCESS, payload: data.data }); } else dispatch({ type: TOGGLE_FAVORITE_FAILURE }); }, error => dispatch({ type: TOGGLE_FAVORITE_FAILURE }) ); }; }; /** * update opinion content in redux state (controlled input) * @param {Object} value * @return {action} */ export const updateOpinionContent = (value) => { return { type: UPDATE_OPINION_CONTENT, payload: value, }; }; /** * post an opinion * @param {Object} opinion * @param {String} discussionSlug * @return {action} */ export const postOpinion = (opinion, discussionSlug) => { return (dispatch, getState) => { // dispatch to show the posting message dispatch({ type: POSTING_OPINION_START }); // validate the opinion if (!opinion.content || opinion.content.length < 20) { dispatch({ type: POSTING_OPINION_FAILURE, payload: 'Please provide a bit more info in your opinion....at least 20 characters.' }); } else { // call the api to post the opinion postOpinionApi(opinion).then( data => { if (data.data._id) { // fetch the discussion to refresh the opinion list fetchSingleDiscussion(discussionSlug).then( data => { dispatch({ type: FETCHING_SINGLE_DISC_SUCCESS, payload: data.data }); dispatch({ type: POSTING_OPINION_SUCCESS }); }, error => dispatch({ type: FETCHING_SINGLE_DISC_FAILURE }) ); } else dispatch({ type: POSTING_OPINION_FAILURE }); }, error => dispatch({ type: POSTING_OPINION_FAILURE }) ); } }; }; /** * delete the discussion post * @param {String} discussionSlug * @return {action} */ export const deletePost = (discussionSlug) => { return (dispatch, getState) => { dispatch({ type: DELETE_DISC_START }); deletePostApi(discussionSlug).then( data => { if (data.data.deleted) { dispatch({ type: DELETE_DISC_SUCCESS }); } else { dispatch({ type: DELETE_DISC_FAILURE }); } }, error => dispatch({ type: DELETE_DISC_FAILURE }) ); }; }; /** * after a successfull deletion of a discussion * the user should be redirected to the home page * @return {action} */ export const deletedDiscussionRedirect = () => { return (dispatch, getState) => { dispatch({ type: DELETE_DISC_REDIRECT }); }; }; /** * delete an opinion * @param {ObjectId} opinionId * @param {String} discussionSlug * @return {action} */ export const deleteOpinion = (opinionId, discussionSlug) => { return (dispatch, getState) => { // show the loading message dispatch({ type: DELETE_OPINION_START, payload: opinionId }); // call the api deleteOpinionApi(opinionId).then( data => { if (data.data.deleted) { // fetch the discussion again to refresh the opinions fetchSingleDiscussion(discussionSlug).then( data => { dispatch({ type: DELETE_OPINION_SUCCESS }); dispatch({ type: FETCHING_SINGLE_DISC_SUCCESS, payload: data.data }); }, error => dispatch({ type: FETCHING_SINGLE_DISC_FAILURE }) ); } else { dispatch({ type: DELETE_OPINION_FAILURE }); } }, error => dispatch({ type: DELETE_OPINION_FAILURE }) ); }; }; ================================================ FILE: frontend/Views/SingleDiscussion/api.js ================================================ import axios from 'axios'; /** * single discussion apis */ export const fetchSingleDiscussion = (discussion_slug) => { return axios.get(`/api/discussion/${discussion_slug}`); }; export const toggleFavoriteApi = (discussion_id) => { return axios.put(`/api/discussion/toggleFavorite/${discussion_id}`); }; export const postOpinionApi = (opinion) => { return axios.post('/api/opinion/newOpinion', opinion); }; export const deletePostApi = (discussionSlug) => { return axios.delete(`/api/discussion/deleteDiscussion/${discussionSlug}`); }; export const deleteOpinionApi = (opinionId) => { return axios.delete(`/api/opinion/deleteOpinion/${opinionId}`); }; ================================================ FILE: frontend/Views/SingleDiscussion/constants.js ================================================ export const FETCHING_SINGLE_DISC_START = 'fetching_single_discussion_start'; export const FETCHING_SINGLE_DISC_END = 'fetching_single_discussion_end'; export const FETCHING_SINGLE_DISC_SUCCESS = 'fetching_single_discussion_success'; export const FETCHING_SINGLE_DISC_FAILURE = 'fetching_single_discussion_failure'; export const TOGGLE_FAVORITE_START = 'toggle_favorite_start'; export const TOGGLE_FAVORITE_SUCCESS = 'toggle_favorite_success'; export const TOGGLE_FAVORITE_FAILURE = 'toggle_favorite_failure'; export const UPDATE_OPINION_CONTENT = 'update_opinion_content'; export const POSTING_OPINION_START = 'posting_opinion_start'; export const POSTING_OPINION_SUCCESS = 'posting_opinion_success'; export const POSTING_OPINION_FAILURE = 'posting_opinion_failure'; export const DELETE_DISC_START = 'delete_disc_start'; export const DELETE_DISC_SUCCESS = 'delete_disc_success'; export const DELETE_DISC_FAILURE = 'delete_disc_failure'; export const DELETE_DISC_REDIRECT = 'delete_disc_redirect'; export const DELETE_OPINION_START = 'delete_opinion_start'; export const DELETE_OPINION_SUCCESS = 'delete_opinion_success'; export const DELETE_OPINION_FAILURE = 'delete_opinion_failure'; ================================================ FILE: frontend/Views/SingleDiscussion/index.js ================================================ import _ from 'lodash'; import React, { Component } from 'react'; import { browserHistory } from 'react-router'; import { connect } from 'react-redux'; import { Helmet } from 'react-helmet'; import classnames from 'classnames'; import { getDiscussion, toggleFavorite, updateOpinionContent, postOpinion, deletePost, deletedDiscussionRedirect, deleteOpinion, } from './actions'; import Discussion from 'Components/SingleDiscussion/Discussion'; import ReplyBox from 'Components/SingleDiscussion/ReplyBox'; import Opinion from 'Components/SingleDiscussion/Opinion'; import styles from './styles.css'; import appLayout from 'SharedStyles/appLayout.css'; class SingleDiscussion extends Component { constructor(props) { super(props); this.state = { opinionContent: '' }; } componentDidMount() { const { forum, discussion, } = this.props.params; this.props.getDiscussion(discussion); } componentDidUpdate() { const { deletedDiscussion, deletedDiscussionRedirect, } = this.props; const { forum } = this.props.params; // check if the discussion is deleted and redirect the user if (deletedDiscussion) { browserHistory.push(`/${forum}`); setTimeout(() => { deletedDiscussionRedirect(); }, 100); } } componentWillUnmount() { // remove any existing opinion texts this.props.updateOpinionContent(null); } userFavoritedDiscussion(userId, favorites) { let favorited = false; for(let i = 0; i < favorites.length; i++) { if (favorites[i] === userId) favorited = true; } return favorited; } handleReplySubmit() { const { forums, postOpinion, discussion, opinionContent, userId, } = this.props; const discussion_slug = this.props.params.discussion; const forumSlug = this.props.params.forum; const forumId = _.find(forums, { forum_slug: forumSlug })._id; postOpinion( { forum_id: forumId, discussion_id: discussion._id, user_id: userId, content: opinionContent, }, discussion_slug ); } deleteDiscussion() { const { discussion } = this.props.params; const { deletePost } = this.props; deletePost(discussion); } deleteOpinion(opinionId) { const { discussion } = this.props.params; const { deleteOpinion } = this.props; deleteOpinion(opinionId, discussion); } render() { const { userAuthenticated, fetchingDiscussion, discussion, toggleFavorite, toggleingFavorite, updateOpinionContent, postingOpinion, opinionError, deletingOpinion, deletingDiscussion, error, } = this.props; if (error) { return (
{error}
); } // return loading status if discussion is not fetched yet if (fetchingDiscussion) { return
Loading discussion ...
; } const { _id, content, date, favorites, title, tags, opinions, } = discussion; const { avatarUrl, name, username, } = discussion.user; // check if logged in user is owner of the discussion let allowDelete = false; if ( (discussion.user._id === this.props.userId) || this.props.userRole === 'admin' ) allowDelete = true; // check if user favorated the discussion const userFavorited = this.userFavoritedDiscussion(this.props.userId, favorites); return (
{`${title} | ReForum`} { opinionError &&
{opinionError}
} { !userAuthenticated &&
Please sign in to post a reply.
} { userAuthenticated && { updateOpinionContent(content); }} /> } { opinions && opinions.map((opinion) => { return ( ); }) }
); } } export default connect( (state) => { return { forums: state.app.forums, userAuthenticated: state.user.authenticated, userId: state.user._id, userRole: state.user.role, fetchingDiscussion: state.discussion.fetchingDiscussion, toggleingFavorite: state.discussion.toggleingFavorite, deletingDiscussion: state.discussion.deletingDiscussion, deletedDiscussion: state.discussion.deletedDiscussion, opinionContent: state.discussion.opinionContent, postingOpinion: state.discussion.postingOpinion, opinionError: state.discussion.opinionError, deletingOpinion: state.discussion.deletingOpinion, discussion: state.discussion.discussion, error: state.discussion.error, }; }, (dispatch) => { return { getDiscussion: (discussionSlug) => { dispatch(getDiscussion(discussionSlug)); }, toggleFavorite: (discussionId) => { dispatch(toggleFavorite(discussionId)); }, updateOpinionContent: (content) => { dispatch(updateOpinionContent(content)); }, postOpinion: (opinion, discussionSlug) => { dispatch(postOpinion(opinion, discussionSlug)); }, deletePost: (discussionSlug) => { dispatch(deletePost(discussionSlug)); }, deletedDiscussionRedirect: () => { dispatch(deletedDiscussionRedirect()); }, deleteOpinion: (opinionId, discussionSlug) => { dispatch(deleteOpinion(opinionId, discussionSlug)); }, }; } )(SingleDiscussion); ================================================ FILE: frontend/Views/SingleDiscussion/reducers.js ================================================ import { FETCHING_SINGLE_DISC_START, FETCHING_SINGLE_DISC_END, FETCHING_SINGLE_DISC_SUCCESS, FETCHING_SINGLE_DISC_FAILURE, TOGGLE_FAVORITE_START, TOGGLE_FAVORITE_SUCCESS, TOGGLE_FAVORITE_FAILURE, UPDATE_OPINION_CONTENT, POSTING_OPINION_START, POSTING_OPINION_SUCCESS, POSTING_OPINION_FAILURE, DELETE_DISC_START, DELETE_DISC_SUCCESS, DELETE_DISC_FAILURE, DELETE_DISC_REDIRECT, DELETE_OPINION_START, DELETE_OPINION_SUCCESS, DELETE_OPINION_FAILURE, } from './constants'; const initialState = { fetchingDiscussion: true, toggleingFavorite: false, postingOpinion: false, opinionContent: null, opinionError: null, deletingDiscussion: false, deletedDiscussion: false, deletingOpinion: null, discussion: null, error: null, }; export const singleDiscussionReducer = (state = initialState, action) => { switch(action.type) { case FETCHING_SINGLE_DISC_START: return Object.assign({}, state, { fetchingDiscussion: true, }); case FETCHING_SINGLE_DISC_END: return Object.assign({}, state, { fetchingDiscussion: false, }); case FETCHING_SINGLE_DISC_SUCCESS: return Object.assign({}, state, { discussion: action.payload, fetchingDiscussion: false, error: null, }); case FETCHING_SINGLE_DISC_FAILURE: return Object.assign({}, state, { fetchingDiscussion: false, error: 'Unable to fetch discussion. Please check out the url.', }); case TOGGLE_FAVORITE_START: return Object.assign({}, state, { toggleingFavorite: true, }); case TOGGLE_FAVORITE_SUCCESS: case TOGGLE_FAVORITE_FAILURE: return Object.assign({}, state, { toggleingFavorite: false, }); case UPDATE_OPINION_CONTENT: return Object.assign({}, state, { opinionContent: action.payload, }); case POSTING_OPINION_START: return Object.assign({}, state, { postingOpinion: true, opinionError: null, }); case POSTING_OPINION_SUCCESS: return Object.assign({}, state, { postingOpinion: false, opinionContent: null, opinionError: null, }); case POSTING_OPINION_FAILURE: return Object.assign({}, state, { postingOpinion: false, opinionContent: null, opinionError: action.payload, }); case DELETE_DISC_START: return Object.assign({}, state, { deletingDiscussion: true, }); case DELETE_DISC_SUCCESS: return Object.assign({}, state, { deletingDiscussion: false, deletedDiscussion: true, }); case DELETE_DISC_FAILURE: return Object.assign({}, state, { deletingDiscussion: false, deletedDiscussion: false, }); case DELETE_DISC_REDIRECT: return Object.assign({}, state, { deletedDiscussion: false, }); case DELETE_OPINION_START: return Object.assign({}, state, { deletingOpinion: action.payload, }); case DELETE_OPINION_SUCCESS: case DELETE_OPINION_FAILURE: return Object.assign({}, state, { deletingOpinion: null, }); default: return state; } }; ================================================ FILE: frontend/Views/SingleDiscussion/styles.css ================================================ @value primaryFontColor, secondaryFontColor from 'SharedStyles/globalStyles.css'; .loadingWrapper { padding: 20px 0px; font-size: 12px; font-weight: bold; text-align: center; color: secondaryFontColor; } .errorMsg { margin-top: 20px; margin-left: 10px; font-size: 12px; font-weight: bold; color: rgba(231, 76, 60,1.0); text-align: center; } .signInMsg { color: secondaryFontColor; font-size: 12px; font-weight: bold; text-align: center; padding: 20px 0px; } ================================================ FILE: frontend/Views/UserProfile/actions.js ================================================ import { FETCH_USER_PROFILE_START, FETCH_USER_PROFILE_SUCCESS, FETCH_USER_PROFILE_FAILURE, } from './constants'; import { fetchUserProfileApi, } from './api'; /** * fetch the users profile from the server * @param {String} userSlug * @return {action} */ export const fetchUserProfile = (userSlug) => { return (dispatch, getState) => { dispatch({ type: FETCH_USER_PROFILE_START }); fetchUserProfileApi(userSlug).then( data => { if (data.data.error) dispatch({ type: FETCH_USER_PROFILE_FAILURE }); else dispatch({ type: FETCH_USER_PROFILE_SUCCESS, payload: data.data }); }, error => dispatch({ type: FETCH_USER_PROFILE_FAILURE }) ); }; }; ================================================ FILE: frontend/Views/UserProfile/api.js ================================================ /** * user profile apis */ import axios from 'axios'; export const fetchUserProfileApi = (userSlug) => { return axios.get(`/api/user/profile/${userSlug}`); }; ================================================ FILE: frontend/Views/UserProfile/constants.js ================================================ export const FETCH_USER_PROFILE_START = 'fetch_user_profile_start'; export const FETCH_USER_PROFILE_SUCCESS = 'fetch_user_profile_success'; export const FETCH_USER_PROFILE_FAILURE = 'fetch_user_profile_failure'; ================================================ FILE: frontend/Views/UserProfile/index.js ================================================ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { Helmet } from 'react-helmet'; import classnames from 'classnames'; import appLayout from 'SharedStyles/appLayout.css'; import styles from './styles.css'; // components used in this view import Profile from 'Components/UserProfile/Profile'; import FeedBox from 'Components/FeedBox'; // actions import { fetchUserProfile, } from './actions'; class UserProfile extends Component { componentDidMount() { const { fetchUserProfile } = this.props; const { username } = this.props.params; fetchUserProfile(username); } componentWillReceiveProps(newProps) { // fetch profile if different username const { username: oldUsername } = this.props.params; const { username: futureUsername } = newProps.params; // only update if different usernames if (oldUsername !== futureUsername) { const { fetchUserProfile } = this.props; fetchUserProfile(futureUsername); } } render() { const { fetchingProfile, profile, error, } = this.props; if (error) { return
{ error }
; } const { name, username, avatarUrl, github, discussions, } = profile; if (fetchingProfile) { return (
Loading users profile ...
); } return (
{`${name || username} | ReForum`}
); } } export default connect( (state) => { return { fetchingProfile: state.userProfile.fetchingProfile, profile: state.userProfile.profile, error: state.userProfile.error, }; }, (dispatch) => { return { fetchUserProfile: (userSlug) => { dispatch(fetchUserProfile(userSlug)); }, }; } )(UserProfile); ================================================ FILE: frontend/Views/UserProfile/reducers.js ================================================ import { FETCH_USER_PROFILE_START, FETCH_USER_PROFILE_SUCCESS, FETCH_USER_PROFILE_FAILURE, } from './constants'; const initialState = { fetchingProfile: true, profile: {}, error: null, }; export const userProfileReducer = (state = initialState, action) => { switch (action.type) { case FETCH_USER_PROFILE_START: return Object.assign({}, state, { fetchingProfile: true, error: null, }); case FETCH_USER_PROFILE_SUCCESS: return Object.assign({}, state, { fetchingProfile: false, profile: action.payload, error: null, }); case FETCH_USER_PROFILE_FAILURE: return Object.assign({}, state, { fetchingProfile: false, error: 'Unable to fetch user profile. Please check out for correct username.', }); default: return state; } }; ================================================ FILE: frontend/Views/UserProfile/styles.css ================================================ @value largeBP from 'SharedStyles/globalStyles'; .container { margin-top: 20px; display: flex; @media largeBP { flex-flow: row nowrap; } } .loadingMsg { margin-top: 20px; text-align: center; } .errorMsg { margin-top: 20px; color: rgba(231, 76, 60,1.0); font-size: 12px; font-weight: bold; text-align: center; } ================================================ FILE: package.json ================================================ { "name": "reforum", "version": "1.0.0", "description": "A forum application built with ReactJS, Redux, Express and MongoDB", "author": "Provash Shoumma", "license": "MIT", "bugs": { "url": "https://github.com/shoumma/ReForum/issues" }, "homepage": "https://github.com/shoumma/ReForum#readme", "repository": { "type": "git", "url": "git+https://github.com/shoumma/ReForum.git" }, "keywords": [ "forum", "react", "redux", "express", "mongodb" ], "main": "server.js", "engines": { "node": "7.1.0" }, "scripts": { "test": "jest", "start": "better-npm-run start", "start:dev": "better-npm-run start:dev", "build": "webpack --config config/webpack.prod.config.js" }, "betterScripts": { "start": { "command": "node server.js", "env": { "NODE_ENV": "production", "PORT": 3030 } }, "start:dev": { "command": "node server.js", "env": { "NODE_ENV": "development", "PORT": 8080 } } }, "dependencies": { "better-npm-run": "^0.0.13", "body-parser": "^1.15.2", "compression": "^1.6.2", "connect-flash": "^0.1.1", "connect-mongo": "^1.3.2", "cookie-parser": "^1.4.3", "express": "^4.14.0", "express-session": "^1.14.2", "help": "^3.0.2", "lodash": "^4.17.4", "mongoose": "^4.7.4", "morgan": "^1.7.0", "passport": "^0.3.2", "passport-github": "^1.1.0", "passport-local": "^1.0.0" }, "devDependencies": { "async": "^2.1.5", "autoprefixer": "^6.6.1", "axios": "^0.15.3", "babel": "^6.5.2", "babel-core": "^6.20.0", "babel-eslint": "^7.1.1", "babel-jest": "^20.0.3", "babel-loader": "^6.2.9", "babel-preset-es2015": "^6.18.0", "babel-preset-react": "^6.16.0", "babel-preset-stage-2": "^6.18.0", "classnames": "^2.2.5", "css-loader": "^0.26.1", "draft-js": "^0.10.0", "eslint": "^3.12.1", "eslint-plugin-react": "^6.8.0", "extract-text-webpack-plugin": "^1.0.1", "file-loader": "^0.9.0", "jest": "^20.0.4", "moment": "^2.17.1", "nock": "^9.0.13", "postcss-loader": "^1.2.2", "postcss-nesting": "^2.3.1", "react": "^15.4.1", "react-dom": "^15.4.1", "react-helmet": "^5.0.3", "react-hot-loader": "^1.3.1", "react-onclickoutside": "^5.10.0", "react-redux": "^5.0.2", "react-router": "^3.0.0", "redux": "^3.6.0", "redux-mock-store": "^1.2.3", "redux-thunk": "^2.2.0", "style-loader": "^0.13.1", "url-loader": "^0.5.7", "webpack": "^1.14.0", "webpack-dev-middleware": "^1.8.4", "webpack-hot-middleware": "^2.13.2" } } ================================================ FILE: public/build/bundle.js ================================================ !function(t){function e(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return t[r].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){t.exports=n(257)},function(t,e){t.exports=React},function(t,e){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function o(t){if(l===setTimeout)return setTimeout(t,0);if((l===n||!l)&&setTimeout)return l=setTimeout,setTimeout(t,0);try{return l(t,0)}catch(e){try{return l.call(null,t,0)}catch(e){return l.call(this,t,0)}}}function i(t){if(f===clearTimeout)return clearTimeout(t);if((f===r||!f)&&clearTimeout)return f=clearTimeout,clearTimeout(t);try{return f(t)}catch(e){try{return f.call(null,t)}catch(e){return f.call(this,t)}}}function u(){y&&d&&(y=!1,d.length?h=d.concat(h):_=-1,h.length&&a())}function a(){if(!y){var t=o(u);y=!0;for(var e=h.length;e;){for(d=h,h=[];++_1)for(var n=1;n0?o.getInlineStyleAt(r-1):o.getLength()?o.getInlineStyleAt(0):f(t,n)}function l(t,e){var n=e.getStartKey(),r=e.getStartOffset(),o=t.getBlockForKey(n);return r0?o.getInlineStyleAt(r-1):f(t,n)}function f(t,e){for(var n,r=t.getBlockBefore(e);r;){if(n=r.getLength())return r.getInlineStyleAt(n-1);r=t.getBlockBefore(r.getKey())}return m()}var p=n(17),d=p||function(t){for(var e=1;e>>0;if(""+n!==e||4294967295===n)return NaN;e=n}return e<0?h(t)+e:e}function _(){return!0}function g(t,e,n){return(0===t||void 0!==n&&t<=-n)&&(void 0===e||void 0!==n&&e>=n)}function v(t,e){return b(t,e,0)}function m(t,e){return b(t,e,e)}function b(t,e,n){return void 0===t?n:t<0?Math.max(0,e+t):void 0===e?t:Math.min(e,t)}function E(t){this.next=t}function S(t,e,n,r){var o=0===t?e:1===t?n:[e,n];return r?r.value=o:r={value:o,done:!1},r}function w(){return{value:void 0,done:!0}}function O(t){return!!I(t)}function T(t){return t&&"function"==typeof t.next}function C(t){var e=I(t);return e&&e.call(t)}function I(t){var e=t&&(wn&&t[wn]||t[On]);if("function"==typeof e)return e}function N(t){return t&&"number"==typeof t.length}function A(t){return null===t||void 0===t?L():i(t)?t.toSeq():K(t)}function D(t){return null===t||void 0===t?L().toKeyedSeq():i(t)?u(t)?t.toSeq():t.fromEntrySeq():U(t)}function x(t){return null===t||void 0===t?L():i(t)?u(t)?t.entrySeq():t.toIndexedSeq():B(t)}function P(t){return(null===t||void 0===t?L():i(t)?u(t)?t.entrySeq():t:B(t)).toSetSeq()}function k(t){this._array=t,this.size=t.length}function M(t){var e=Object.keys(t);this._object=t,this._keys=e,this.size=e.length}function R(t){this._iterable=t,this.size=t.length||t.size}function F(t){this._iterator=t,this._iteratorCache=[]}function j(t){return!(!t||!t[Cn])}function L(){return In||(In=new k([]))}function U(t){var e=Array.isArray(t)?new k(t).fromEntrySeq():T(t)?new F(t).fromEntrySeq():O(t)?new R(t).fromEntrySeq():"object"==typeof t?new M(t):void 0;if(!e)throw new TypeError("Expected Array or iterable object of [k, v] entries, or keyed object: "+t);return e}function B(t){var e=H(t);if(!e)throw new TypeError("Expected Array or iterable object of values: "+t);return e}function K(t){var e=H(t)||"object"==typeof t&&new M(t);if(!e)throw new TypeError("Expected Array or iterable object of values, or keyed object: "+t);return e}function H(t){return N(t)?new k(t):T(t)?new F(t):O(t)?new R(t):void 0}function G(t,e,n,r){var o=t._cache;if(o){for(var i=o.length-1,u=0;u<=i;u++){var a=o[n?i-u:u];if(e(a[1],r?a[0]:u,t)===!1)return u+1}return u}return t.__iterateUncached(e,n)}function z(t,e,n,r){var o=t._cache;if(o){var i=o.length-1,u=0;return new E(function(){var t=o[n?i-u:u];return u++>i?w():S(e,r?t[0]:u-1,t[1])})}return t.__iteratorUncached(e,n)}function q(t,e){return e?W(e,t,"",{"":t}):V(t)}function W(t,e,n,r){return Array.isArray(e)?t.call(r,n,x(e).map(function(n,r){return W(t,n,r,e)})):Y(e)?t.call(r,n,D(e).map(function(n,r){return W(t,n,r,e)})):e}function V(t){return Array.isArray(t)?x(t).map(V).toList():Y(t)?D(t).map(V).toMap():t}function Y(t){return t&&(t.constructor===Object||void 0===t.constructor)}function X(t,e){if(t===e||t!==t&&e!==e)return!0;if(!t||!e)return!1;if("function"==typeof t.valueOf&&"function"==typeof e.valueOf){if(t=t.valueOf(),e=e.valueOf(),t===e||t!==t&&e!==e)return!0;if(!t||!e)return!1}return!("function"!=typeof t.equals||"function"!=typeof e.equals||!t.equals(e))}function $(t,e){if(t===e)return!0;if(!i(e)||void 0!==t.size&&void 0!==e.size&&t.size!==e.size||void 0!==t.__hash&&void 0!==e.__hash&&t.__hash!==e.__hash||u(t)!==u(e)||a(t)!==a(e)||c(t)!==c(e))return!1;if(0===t.size&&0===e.size)return!0;var n=!s(t);if(c(t)){var r=t.entries();return e.every(function(t,e){var o=r.next().value;return o&&X(o[1],t)&&(n||X(o[0],e))})&&r.next().done}var o=!1;if(void 0===t.size)if(void 0===e.size)"function"==typeof t.cacheResult&&t.cacheResult();else{o=!0;var l=t;t=e,e=l}var f=!0,p=e.__iterate(function(e,r){if(n?!t.has(e):o?!X(e,t.get(r,gn)):!X(t.get(r,gn),e))return f=!1,!1});return f&&t.size===p}function J(t,e){if(!(this instanceof J))return new J(t,e);if(this._value=t,this.size=void 0===e?1/0:Math.max(0,e),0===this.size){if(Nn)return Nn;Nn=this}}function Z(t,e){if(!t)throw new Error(e)}function Q(t,e,n){if(!(this instanceof Q))return new Q(t,e,n);if(Z(0!==n,"Cannot step a Range by 0"),t=t||0,void 0===e&&(e=1/0),n=void 0===n?1:Math.abs(n),e>>1&1073741824|3221225471&t}function it(t){if(t===!1||null===t||void 0===t)return 0;if("function"==typeof t.valueOf&&(t=t.valueOf(),t===!1||null===t||void 0===t))return 0;if(t===!0)return 1;var e=typeof t;if("number"===e){var n=0|t;for(n!==t&&(n^=4294967295*t);t>4294967295;)t/=4294967295,n^=t;return ot(n)}if("string"===e)return t.length>jn?ut(t):at(t);if("function"==typeof t.hashCode)return t.hashCode();if("object"===e)return st(t);if("function"==typeof t.toString)return at(t.toString());throw new Error("Value type "+e+" cannot be hashed.")}function ut(t){var e=Bn[t];return void 0===e&&(e=at(t),Un===Ln&&(Un=0,Bn={}),Un++,Bn[t]=e),e}function at(t){for(var e=0,n=0;n0)switch(t.nodeType){case 1:return t.uniqueID;case 9:return t.documentElement&&t.documentElement.uniqueID}}function lt(t){Z(t!==1/0,"Cannot perform this action with an infinite size.")}function ft(t){return null===t||void 0===t?St():pt(t)&&!c(t)?t:St().withMutations(function(e){var r=n(t);lt(r.size),r.forEach(function(t,n){return e.set(n,t)})})}function pt(t){return!(!t||!t[Kn])}function dt(t,e){this.ownerID=t,this.entries=e}function ht(t,e,n){this.ownerID=t,this.bitmap=e,this.nodes=n}function yt(t,e,n){this.ownerID=t,this.count=e,this.nodes=n}function _t(t,e,n){this.ownerID=t,this.keyHash=e,this.entries=n}function gt(t,e,n){this.ownerID=t,this.keyHash=e,this.entry=n}function vt(t,e,n){this._type=e,this._reverse=n,this._stack=t._root&&bt(t._root)}function mt(t,e){return S(t,e[0],e[1])}function bt(t,e){return{node:t,index:0,__prev:e}}function Et(t,e,n,r){var o=Object.create(Hn);return o.size=t,o._root=e,o.__ownerID=n,o.__hash=r,o.__altered=!1,o}function St(){return Gn||(Gn=Et(0))}function wt(t,e,n){var r,o;if(t._root){var i=l(vn),u=l(mn);if(r=Ot(t._root,t.__ownerID,0,void 0,e,n,i,u),!u.value)return t;o=t.size+(i.value?n===gn?-1:1:0)}else{if(n===gn)return t;o=1,r=new dt(t.__ownerID,[[e,n]])}return t.__ownerID?(t.size=o,t._root=r,t.__hash=void 0,t.__altered=!0,t):r?Et(o,r):St()}function Ot(t,e,n,r,o,i,u,a){return t?t.update(e,n,r,o,i,u,a):i===gn?t:(f(a),f(u),new gt(e,r,[o,i]))}function Tt(t){return t.constructor===gt||t.constructor===_t}function Ct(t,e,n,r,o){if(t.keyHash===r)return new _t(e,r,[t.entry,o]);var i,u=(0===n?t.keyHash:t.keyHash>>>n)&_n,a=(0===n?r:r>>>n)&_n,s=u===a?[Ct(t,e,n+hn,r,o)]:(i=new gt(e,r,o),u>>=1)u[a]=1&n?e[i++]:void 0;return u[r]=o,new yt(t,i+1,u)}function Dt(t,e,r){for(var o=[],u=0;u>1&1431655765,t=(858993459&t)+(t>>2&858993459),t=t+(t>>4)&252645135,t+=t>>8,t+=t>>16,127&t}function Ft(t,e,n,r){var o=r?t:d(t);return o[e]=n,o}function jt(t,e,n,r){var o=t.length+1;if(r&&e+1===o)return t[e]=n,t;for(var i=new Array(o),u=0,a=0;a0&&oi?0:i-n,c=u-n;return c>yn&&(c=yn),function(){if(o===c)return $n;var t=e?--c:o++;return r&&r[t]}}function o(t,r,o){var a,s=t&&t.array,c=o>i?0:i-o>>r,l=(u-o>>r)+1;return l>yn&&(l=yn),function(){for(;;){if(a){var t=a();if(t!==$n)return t;a=null}if(c===l)return $n;var i=e?--l:c++;a=n(s&&s[i],r-hn,o+(i<=t.size||e<0)return t.withMutations(function(t){e<0?Xt(t,e).set(0,n):Xt(t,0,e+1).set(e,n)});e+=t._origin;var r=t._tail,o=t._root,i=l(mn);return e>=Jt(t._capacity)?r=Wt(r,t.__ownerID,0,e,n,i):o=Wt(o,t.__ownerID,t._level,e,n,i),i.value?t.__ownerID?(t._root=o,t._tail=r,t.__hash=void 0,t.__altered=!0,t):Gt(t._origin,t._capacity,t._level,o,r):t}function Wt(t,e,n,r,o,i){var u=r>>>n&_n,a=t&&u0){var c=t&&t.array[u],l=Wt(c,e,n-hn,r,o,i);return l===c?t:(s=Vt(t,e),s.array[u]=l,s)}return a&&t.array[u]===o?t:(f(i),s=Vt(t,e),void 0===o&&u===s.array.length-1?s.array.pop():s.array[u]=o,s)}function Vt(t,e){return e&&t&&e===t.ownerID?t:new Kt(t?t.array.slice():[],e)}function Yt(t,e){if(e>=Jt(t._capacity))return t._tail;if(e<1<0;)n=n.array[e>>>r&_n],r-=hn;return n}}function Xt(t,e,n){void 0!==e&&(e|=0),void 0!==n&&(n|=0);var r=t.__ownerID||new p,o=t._origin,i=t._capacity,u=o+e,a=void 0===n?i:n<0?i+n:o+n;if(u===o&&a===i)return t;if(u>=a)return t.clear();for(var s=t._level,c=t._root,l=0;u+l<0;)c=new Kt(c&&c.array.length?[void 0,c]:[],r),s+=hn,l+=1<=1<f?new Kt([],r):h;if(h&&d>f&&uhn;g-=hn){var v=f>>>g&_n;_=_.array[v]=Vt(_.array[v],r)}_.array[f>>>hn&_n]=h}if(a=d)u-=d,a-=d,s=hn,c=null,y=y&&y.removeBefore(r,0,u);else if(u>o||d>>s&_n;if(m!==d>>>s&_n)break;m&&(l+=(1<o&&(c=c.removeBefore(r,s,u-l)),c&&du&&(u=c.size),i(s)||(c=c.map(function(t){return q(t)})),o.push(c)}return u>t.size&&(t=t.setSize(u)),kt(t,e,o)}function Jt(t){return t>>hn<=yn&&u.size>=2*i.size?(o=u.filter(function(t,e){return void 0!==t&&a!==e}),r=o.toKeyedSeq().map(function(t){return t[0]}).flip().toMap(),t.__ownerID&&(r.__ownerID=o.__ownerID=t.__ownerID)):(r=i.remove(e),o=a===u.size-1?u.pop():u.set(a,void 0))}else if(s){if(n===u.get(a)[1])return t;r=i,o=u.set(a,[e,n])}else r=i.set(e,u.size),o=u.set(u.size,[e,n]);return t.__ownerID?(t.size=r.size,t._map=r,t._list=o,t.__hash=void 0,t):te(r,o)}function re(t,e){this._iter=t,this._useKeys=e,this.size=t.size}function oe(t){this._iter=t,this.size=t.size}function ie(t){this._iter=t,this.size=t.size}function ue(t){this._iter=t,this.size=t.size}function ae(t){var e=Ne(t);return e._iter=t,e.size=t.size,e.flip=function(){return t},e.reverse=function(){var e=t.reverse.apply(this);return e.flip=function(){return t.reverse()},e},e.has=function(e){return t.includes(e)},e.includes=function(e){return t.has(e)},e.cacheResult=Ae,e.__iterateUncached=function(e,n){var r=this;return t.__iterate(function(t,n){return e(n,t,r)!==!1},n)},e.__iteratorUncached=function(e,n){if(e===Sn){var r=t.__iterator(e,n);return new E(function(){var t=r.next();if(!t.done){var e=t.value[0];t.value[0]=t.value[1],t.value[1]=e}return t})}return t.__iterator(e===En?bn:En,n)},e}function se(t,e,n){var r=Ne(t);return r.size=t.size,r.has=function(e){return t.has(e)},r.get=function(r,o){var i=t.get(r,gn);return i===gn?o:e.call(n,i,r,t)},r.__iterateUncached=function(r,o){var i=this;return t.__iterate(function(t,o,u){return r(e.call(n,t,o,u),o,i)!==!1},o)},r.__iteratorUncached=function(r,o){var i=t.__iterator(Sn,o);return new E(function(){var o=i.next();if(o.done)return o;var u=o.value,a=u[0];return S(r,a,e.call(n,u[1],a,t),o)})},r}function ce(t,e){var n=Ne(t);return n._iter=t,n.size=t.size,n.reverse=function(){return t},t.flip&&(n.flip=function(){var e=ae(t);return e.reverse=function(){return t.flip()},e}),n.get=function(n,r){return t.get(e?n:-1-n,r)},n.has=function(n){return t.has(e?n:-1-n)},n.includes=function(e){return t.includes(e)},n.cacheResult=Ae,n.__iterate=function(e,n){var r=this;return t.__iterate(function(t,n){return e(t,n,r)},!n)},n.__iterator=function(e,n){return t.__iterator(e,!n)},n}function le(t,e,n,r){var o=Ne(t);return r&&(o.has=function(r){var o=t.get(r,gn);return o!==gn&&!!e.call(n,o,r,t)},o.get=function(r,o){var i=t.get(r,gn);return i!==gn&&e.call(n,i,r,t)?i:o}),o.__iterateUncached=function(o,i){var u=this,a=0;return t.__iterate(function(t,i,s){if(e.call(n,t,i,s))return a++,o(t,r?i:a-1,u)},i),a},o.__iteratorUncached=function(o,i){var u=t.__iterator(Sn,i),a=0;return new E(function(){for(;;){var i=u.next();if(i.done)return i;var s=i.value,c=s[0],l=s[1];if(e.call(n,l,c,t))return S(o,r?c:a++,l,i)}})},o}function fe(t,e,n){var r=ft().asMutable();return t.__iterate(function(o,i){r.update(e.call(n,o,i,t),0,function(t){return t+1})}),r.asImmutable()}function pe(t,e,n){var r=u(t),o=(c(t)?Zt():ft()).asMutable();t.__iterate(function(i,u){o.update(e.call(n,i,u,t),function(t){return t=t||[],t.push(r?[u,i]:i),t})});var i=Ie(t);return o.map(function(e){return Oe(t,i(e))})}function de(t,e,n,r){var o=t.size;if(void 0!==e&&(e|=0),void 0!==n&&(n|=0),g(e,n,o))return t;var i=v(e,o),u=m(n,o);if(i!==i||u!==u)return de(t.toSeq().cacheResult(),e,n,r);var a,s=u-i;s===s&&(a=s<0?0:s);var c=Ne(t);return c.size=0===a?a:t.size&&a||void 0,!r&&j(t)&&a>=0&&(c.get=function(e,n){return e=y(this,e),e>=0&&ea)return w();var t=o.next();return r||e===En?t:e===bn?S(e,s-1,void 0,t):S(e,s-1,t.value[1],t)})},c}function he(t,e,n){var r=Ne(t);return r.__iterateUncached=function(r,o){var i=this;if(o)return this.cacheResult().__iterate(r,o);var u=0;return t.__iterate(function(t,o,a){return e.call(n,t,o,a)&&++u&&r(t,o,i)}),u},r.__iteratorUncached=function(r,o){var i=this;if(o)return this.cacheResult().__iterator(r,o);var u=t.__iterator(Sn,o),a=!0;return new E(function(){if(!a)return w();var t=u.next();if(t.done)return t;var o=t.value,s=o[0],c=o[1];return e.call(n,c,s,i)?r===Sn?t:S(r,s,c,t):(a=!1,w())})},r}function ye(t,e,n,r){var o=Ne(t);return o.__iterateUncached=function(o,i){var u=this;if(i)return this.cacheResult().__iterate(o,i);var a=!0,s=0;return t.__iterate(function(t,i,c){if(!a||!(a=e.call(n,t,i,c)))return s++,o(t,r?i:s-1,u)}),s},o.__iteratorUncached=function(o,i){var u=this;if(i)return this.cacheResult().__iterator(o,i);var a=t.__iterator(Sn,i),s=!0,c=0;return new E(function(){var t,i,l;do{if(t=a.next(),t.done)return r||o===En?t:o===bn?S(o,c++,void 0,t):S(o,c++,t.value[1],t);var f=t.value;i=f[0],l=f[1],s&&(s=e.call(n,l,i,u))}while(s);return o===Sn?t:S(o,i,l,t)})},o}function _e(t,e){var r=u(t),o=[t].concat(e).map(function(t){return i(t)?r&&(t=n(t)):t=r?U(t):B(Array.isArray(t)?t:[t]),t}).filter(function(t){return 0!==t.size});if(0===o.length)return t;if(1===o.length){var s=o[0];if(s===t||r&&u(s)||a(t)&&a(s))return s}var c=new k(o);return r?c=c.toKeyedSeq():a(t)||(c=c.toSetSeq()),c=c.flatten(!0),c.size=o.reduce(function(t,e){if(void 0!==t){var n=e.size;if(void 0!==n)return t+n}},0),c}function ge(t,e,n){var r=Ne(t);return r.__iterateUncached=function(r,o){function u(t,c){var l=this;t.__iterate(function(t,o){return(!e||c0}function we(t,n,r){var o=Ne(t);return o.size=new k(r).map(function(t){return t.size}).min(),o.__iterate=function(t,e){for(var n,r=this.__iterator(En,e),o=0;!(n=r.next()).done&&t(n.value,o++,this)!==!1;);return o},o.__iteratorUncached=function(t,o){var i=r.map(function(t){return t=e(t),C(o?t.reverse():t)}),u=0,a=!1;return new E(function(){var e;return a||(e=i.map(function(t){return t.next()}),a=e.some(function(t){return t.done})),a?w():S(t,u++,n.apply(null,e.map(function(t){return t.value})))})},o}function Oe(t,e){return j(t)?e:t.constructor(e)}function Te(t){if(t!==Object(t))throw new TypeError("Expected [K, V] tuple: "+t)}function Ce(t){return lt(t.size),h(t)}function Ie(t){return u(t)?n:a(t)?r:o}function Ne(t){return Object.create((u(t)?D:a(t)?x:P).prototype)}function Ae(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):A.prototype.cacheResult.call(this)}function De(t,e){return t>e?1:te?-1:0}function on(t){if(t.size===1/0)return 0;var e=c(t),n=u(t),r=e?1:0,o=t.__iterate(n?e?function(t,e){r=31*r+an(it(t),it(e))|0}:function(t,e){r=r+an(it(t),it(e))|0}:e?function(t){r=31*r+it(t)|0}:function(t){r=r+it(t)|0});return un(o,r)}function un(t,e){return e=xn(e,3432918353),e=xn(e<<15|e>>>-15,461845907),e=xn(e<<13|e>>>-13,5),e=(e+3864292196|0)^t,e=xn(e^e>>>16,2246822507),e=xn(e^e>>>13,3266489909),e=ot(e^e>>>16)}function an(t,e){return t^e+2654435769+(t<<6)+(t>>2)|0}var sn=Array.prototype.slice;t(n,e),t(r,e),t(o,e),e.isIterable=i,e.isKeyed=u,e.isIndexed=a,e.isAssociative=s,e.isOrdered=c,e.Keyed=n,e.Indexed=r,e.Set=o;var cn="@@__IMMUTABLE_ITERABLE__@@",ln="@@__IMMUTABLE_KEYED__@@",fn="@@__IMMUTABLE_INDEXED__@@",pn="@@__IMMUTABLE_ORDERED__@@",dn="delete",hn=5,yn=1<r?w():S(t,o,n[e?r-o++:o++])})},t(M,D),M.prototype.get=function(t,e){return void 0===e||this.has(t)?this._object[t]:e},M.prototype.has=function(t){return this._object.hasOwnProperty(t)},M.prototype.__iterate=function(t,e){for(var n=this._object,r=this._keys,o=r.length-1,i=0;i<=o;i++){var u=r[e?o-i:i];if(t(n[u],u,this)===!1)return i+1}return i},M.prototype.__iterator=function(t,e){var n=this._object,r=this._keys,o=r.length-1,i=0;return new E(function(){var u=r[e?o-i:i];return i++>o?w():S(t,u,n[u])})},M.prototype[pn]=!0,t(R,x),R.prototype.__iterateUncached=function(t,e){if(e)return this.cacheResult().__iterate(t,e);var n=this._iterable,r=C(n),o=0;if(T(r))for(var i;!(i=r.next()).done&&t(i.value,o++,this)!==!1;);return o},R.prototype.__iteratorUncached=function(t,e){if(e)return this.cacheResult().__iterator(t,e);var n=this._iterable,r=C(n);if(!T(r))return new E(w);var o=0;return new E(function(){var e=r.next();return e.done?e:S(t,o++,e.value)})},t(F,x),F.prototype.__iterateUncached=function(t,e){if(e)return this.cacheResult().__iterate(t,e);for(var n=this._iterator,r=this._iteratorCache,o=0;o=r.length){var e=n.next();if(e.done)return e;r[o]=e.value}return S(t,o,r[o++])})};var In;t(J,x),J.prototype.toString=function(){return 0===this.size?"Repeat []":"Repeat [ "+this._value+" "+this.size+" times ]"},J.prototype.get=function(t,e){return this.has(t)?this._value:e},J.prototype.includes=function(t){return X(this._value,t)},J.prototype.slice=function(t,e){var n=this.size;return g(t,e,n)?this:new J(this._value,m(e,n)-v(t,n))},J.prototype.reverse=function(){return this},J.prototype.indexOf=function(t){return X(this._value,t)?0:-1},J.prototype.lastIndexOf=function(t){return X(this._value,t)?this.size:-1},J.prototype.__iterate=function(t,e){for(var n=0;n1?" by "+this._step:"")+" ]"},Q.prototype.get=function(t,e){return this.has(t)?this._start+y(this,t)*this._step:e},Q.prototype.includes=function(t){var e=(t-this._start)/this._step;return e>=0&&e=0&&nn?w():S(t,i++,u)})},Q.prototype.equals=function(t){return t instanceof Q?this._start===t._start&&this._end===t._end&&this._step===t._step:$(this,t)};var An;t(tt,e),t(et,tt),t(nt,tt),t(rt,tt),tt.Keyed=et,tt.Indexed=nt,tt.Set=rt;var Dn,xn="function"==typeof Math.imul&&Math.imul(4294967295,2)===-2?Math.imul:function(t,e){t|=0,e|=0;var n=65535&t,r=65535&e;return n*r+((t>>>16)*r+n*(e>>>16)<<16>>>0)|0},Pn=Object.isExtensible,kn=function(){try{return Object.defineProperty({},"@",{}),!0}catch(t){return!1}}(),Mn="function"==typeof WeakMap;Mn&&(Dn=new WeakMap);var Rn=0,Fn="__immutablehash__";"function"==typeof Symbol&&(Fn=Symbol(Fn));var jn=16,Ln=255,Un=0,Bn={};t(ft,et),ft.prototype.toString=function(){return this.__toString("Map {","}")},ft.prototype.get=function(t,e){return this._root?this._root.get(0,void 0,t,e):e},ft.prototype.set=function(t,e){return wt(this,t,e)},ft.prototype.setIn=function(t,e){return this.updateIn(t,gn,function(){return e})},ft.prototype.remove=function(t){return wt(this,t,gn)},ft.prototype.deleteIn=function(t){return this.updateIn(t,function(){return gn})},ft.prototype.update=function(t,e,n){return 1===arguments.length?t(this):this.updateIn([t],e,n)},ft.prototype.updateIn=function(t,e,n){n||(n=e,e=void 0);var r=Mt(this,xe(t),e,n);return r===gn?void 0:r},ft.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):St()},ft.prototype.merge=function(){return Dt(this,void 0,arguments)},ft.prototype.mergeWith=function(t){var e=sn.call(arguments,1);return Dt(this,t,e)},ft.prototype.mergeIn=function(t){var e=sn.call(arguments,1);return this.updateIn(t,St(),function(t){return"function"==typeof t.merge?t.merge.apply(t,e):e[e.length-1]})},ft.prototype.mergeDeep=function(){return Dt(this,xt,arguments)},ft.prototype.mergeDeepWith=function(t){var e=sn.call(arguments,1);return Dt(this,Pt(t),e)},ft.prototype.mergeDeepIn=function(t){var e=sn.call(arguments,1);return this.updateIn(t,St(),function(t){return"function"==typeof t.mergeDeep?t.mergeDeep.apply(t,e):e[e.length-1]})},ft.prototype.sort=function(t){return Zt(be(this,t))},ft.prototype.sortBy=function(t,e){return Zt(be(this,e,t))},ft.prototype.withMutations=function(t){var e=this.asMutable();return t(e),e.wasAltered()?e.__ensureOwner(this.__ownerID):this},ft.prototype.asMutable=function(){return this.__ownerID?this:this.__ensureOwner(new p)},ft.prototype.asImmutable=function(){return this.__ensureOwner()},ft.prototype.wasAltered=function(){return this.__altered},ft.prototype.__iterator=function(t,e){return new vt(this,t,e)},ft.prototype.__iterate=function(t,e){var n=this,r=0;return this._root&&this._root.iterate(function(e){return r++,t(e[1],e[0],n)},e),r},ft.prototype.__ensureOwner=function(t){return t===this.__ownerID?this:t?Et(this.size,this._root,t,this.__hash):(this.__ownerID=t,this.__altered=!1,this)},ft.isMap=pt;var Kn="@@__IMMUTABLE_MAP__@@",Hn=ft.prototype;Hn[Kn]=!0,Hn[dn]=Hn.remove,Hn.removeIn=Hn.deleteIn,dt.prototype.get=function(t,e,n,r){for(var o=this.entries,i=0,u=o.length;i=zn)return It(t,s,r,o);var h=t&&t===this.ownerID,y=h?s:d(s);return p?a?c===l-1?y.pop():y[c]=y.pop():y[c]=[r,o]:y.push([r,o]),h?(this.entries=y,this):new dt(t,y)}},ht.prototype.get=function(t,e,n,r){void 0===e&&(e=it(n));var o=1<<((0===t?e:e>>>t)&_n),i=this.bitmap;return 0===(i&o)?r:this.nodes[Rt(i&o-1)].get(t+hn,e,n,r)},ht.prototype.update=function(t,e,n,r,o,i,u){void 0===n&&(n=it(r));var a=(0===e?n:n>>>e)&_n,s=1<=qn)return At(t,p,c,a,h);if(l&&!h&&2===p.length&&Tt(p[1^f]))return p[1^f];if(l&&h&&1===p.length&&Tt(h))return h;var y=t&&t===this.ownerID,_=l?h?c:c^s:c|s,g=l?h?Ft(p,f,h,y):Lt(p,f,y):jt(p,f,h,y);return y?(this.bitmap=_,this.nodes=g,this):new ht(t,_,g)},yt.prototype.get=function(t,e,n,r){void 0===e&&(e=it(n));var o=(0===t?e:e>>>t)&_n,i=this.nodes[o];return i?i.get(t+hn,e,n,r):r},yt.prototype.update=function(t,e,n,r,o,i,u){void 0===n&&(n=it(r));var a=(0===e?n:n>>>e)&_n,s=o===gn,c=this.nodes,l=c[a];if(s&&!l)return this;var f=Ot(l,t,e+hn,n,r,o,i,u);if(f===l)return this;var p=this.count;if(l){if(!f&&(p--,p=0&&t>>e&_n;if(r>=this.array.length)return new Kt([],t);var o,i=0===r;if(e>0){var u=this.array[r];if(o=u&&u.removeBefore(t,e-hn,n),o===u&&i)return this}if(i&&!o)return this;var a=Vt(this,t);if(!i)for(var s=0;s>>e&_n;if(r>=this.array.length)return this;var o;if(e>0){var i=this.array[r];if(o=i&&i.removeAfter(t,e-hn,n),o===i&&r===this.array.length-1)return this}var u=Vt(this,t);return u.array.splice(r+1),o&&(u.array[r]=o),u};var Xn,$n={};t(Zt,ft),Zt.of=function(){return this(arguments)},Zt.prototype.toString=function(){return this.__toString("OrderedMap {","}")},Zt.prototype.get=function(t,e){var n=this._map.get(t);return void 0!==n?this._list.get(n)[1]:e},Zt.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._map.clear(),this._list.clear(),this):ee()},Zt.prototype.set=function(t,e){return ne(this,t,e)},Zt.prototype.remove=function(t){return ne(this,t,gn)},Zt.prototype.wasAltered=function(){return this._map.wasAltered()||this._list.wasAltered()},Zt.prototype.__iterate=function(t,e){var n=this;return this._list.__iterate(function(e){return e&&t(e[1],e[0],n)},e)},Zt.prototype.__iterator=function(t,e){return this._list.fromEntrySeq().__iterator(t,e)},Zt.prototype.__ensureOwner=function(t){if(t===this.__ownerID)return this;var e=this._map.__ensureOwner(t),n=this._list.__ensureOwner(t);return t?te(e,n,t,this.__hash):(this.__ownerID=t,this._map=e,this._list=n,this)},Zt.isOrderedMap=Qt,Zt.prototype[pn]=!0,Zt.prototype[dn]=Zt.prototype.remove;var Jn;t(re,D),re.prototype.get=function(t,e){return this._iter.get(t,e)},re.prototype.has=function(t){return this._iter.has(t)},re.prototype.valueSeq=function(){return this._iter.valueSeq()},re.prototype.reverse=function(){var t=this,e=ce(this,!0);return this._useKeys||(e.valueSeq=function(){return t._iter.toSeq().reverse()}),e},re.prototype.map=function(t,e){var n=this,r=se(this,t,e);return this._useKeys||(r.valueSeq=function(){return n._iter.toSeq().map(t,e)}),r},re.prototype.__iterate=function(t,e){var n,r=this;return this._iter.__iterate(this._useKeys?function(e,n){return t(e,n,r)}:(n=e?Ce(this):0,function(o){return t(o,e?--n:n++,r)}),e)},re.prototype.__iterator=function(t,e){if(this._useKeys)return this._iter.__iterator(t,e);var n=this._iter.__iterator(En,e),r=e?Ce(this):0;return new E(function(){var o=n.next();return o.done?o:S(t,e?--r:r++,o.value,o)})},re.prototype[pn]=!0,t(oe,x),oe.prototype.includes=function(t){return this._iter.includes(t)},oe.prototype.__iterate=function(t,e){var n=this,r=0;return this._iter.__iterate(function(e){return t(e,r++,n)},e)},oe.prototype.__iterator=function(t,e){var n=this._iter.__iterator(En,e),r=0;return new E(function(){var e=n.next();return e.done?e:S(t,r++,e.value,e)})},t(ie,P),ie.prototype.has=function(t){return this._iter.includes(t)},ie.prototype.__iterate=function(t,e){var n=this;return this._iter.__iterate(function(e){return t(e,e,n)},e)},ie.prototype.__iterator=function(t,e){var n=this._iter.__iterator(En,e);return new E(function(){var e=n.next();return e.done?e:S(t,e.value,e.value,e)})},t(ue,D),ue.prototype.entrySeq=function(){return this._iter.toSeq()},ue.prototype.__iterate=function(t,e){var n=this;return this._iter.__iterate(function(e){if(e){Te(e);var r=i(e);return t(r?e.get(1):e[1],r?e.get(0):e[0],n)}},e)},ue.prototype.__iterator=function(t,e){var n=this._iter.__iterator(En,e);return new E(function(){for(;;){var e=n.next();if(e.done)return e;var r=e.value;if(r){Te(r);var o=i(r);return S(t,o?r.get(0):r[0],o?r.get(1):r[1],e)}}})},oe.prototype.cacheResult=re.prototype.cacheResult=ie.prototype.cacheResult=ue.prototype.cacheResult=Ae,t(Pe,et),Pe.prototype.toString=function(){return this.__toString(Me(this)+" {","}")},Pe.prototype.has=function(t){return this._defaultValues.hasOwnProperty(t)},Pe.prototype.get=function(t,e){if(!this.has(t))return e;var n=this._defaultValues[t];return this._map?this._map.get(t,n):n},Pe.prototype.clear=function(){if(this.__ownerID)return this._map&&this._map.clear(),this;var t=this.constructor;return t._empty||(t._empty=ke(this,St()))},Pe.prototype.set=function(t,e){if(!this.has(t))throw new Error('Cannot set unknown key "'+t+'" on '+Me(this));var n=this._map&&this._map.set(t,e);return this.__ownerID||n===this._map?this:ke(this,n)},Pe.prototype.remove=function(t){if(!this.has(t))return this;var e=this._map&&this._map.remove(t);return this.__ownerID||e===this._map?this:ke(this,e)},Pe.prototype.wasAltered=function(){return this._map.wasAltered()},Pe.prototype.__iterator=function(t,e){var r=this;return n(this._defaultValues).map(function(t,e){return r.get(e)}).__iterator(t,e)},Pe.prototype.__iterate=function(t,e){var r=this;return n(this._defaultValues).map(function(t,e){return r.get(e)}).__iterate(t,e)},Pe.prototype.__ensureOwner=function(t){if(t===this.__ownerID)return this;var e=this._map&&this._map.__ensureOwner(t);return t?ke(this,e,t):(this.__ownerID=t,this._map=e,this)};var Zn=Pe.prototype;Zn[dn]=Zn.remove,Zn.deleteIn=Zn.removeIn=Hn.removeIn,Zn.merge=Hn.merge,Zn.mergeWith=Hn.mergeWith,Zn.mergeIn=Hn.mergeIn,Zn.mergeDeep=Hn.mergeDeep,Zn.mergeDeepWith=Hn.mergeDeepWith,Zn.mergeDeepIn=Hn.mergeDeepIn,Zn.setIn=Hn.setIn,Zn.update=Hn.update,Zn.updateIn=Hn.updateIn,Zn.withMutations=Hn.withMutations,Zn.asMutable=Hn.asMutable,Zn.asImmutable=Hn.asImmutable,t(je,rt),je.of=function(){return this(arguments)},je.fromKeys=function(t){return this(n(t).keySeq())},je.prototype.toString=function(){return this.__toString("Set {","}")},je.prototype.has=function(t){return this._map.has(t)},je.prototype.add=function(t){return Ue(this,this._map.set(t,!0))},je.prototype.remove=function(t){return Ue(this,this._map.remove(t))},je.prototype.clear=function(){return Ue(this,this._map.clear())},je.prototype.union=function(){var t=sn.call(arguments,0);return t=t.filter(function(t){return 0!==t.size}),0===t.length?this:0!==this.size||this.__ownerID||1!==t.length?this.withMutations(function(e){for(var n=0;n=0;n--)e={value:arguments[n],next:e};return this.__ownerID?(this.size=t,this._head=e,this.__hash=void 0,this.__altered=!0,this):Ye(t,e)},We.prototype.pushAll=function(t){if(t=r(t),0===t.size)return this;lt(t.size);var e=this.size,n=this._head;return t.reverse().forEach(function(t){e++,n={value:t,next:n}}),this.__ownerID?(this.size=e,this._head=n,this.__hash=void 0,this.__altered=!0,this):Ye(e,n)},We.prototype.pop=function(){return this.slice(1)},We.prototype.unshift=function(){return this.push.apply(this,arguments)},We.prototype.unshiftAll=function(t){return this.pushAll(t)},We.prototype.shift=function(){return this.pop.apply(this,arguments)},We.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._head=void 0,this.__hash=void 0,this.__altered=!0,this):Xe()},We.prototype.slice=function(t,e){if(g(t,e,this.size))return this;var n=v(t,this.size),r=m(e,this.size);if(r!==this.size)return nt.prototype.slice.call(this,t,e);for(var o=this.size-n,i=this._head;n--;)i=i.next;return this.__ownerID?(this.size=o,this._head=i,this.__hash=void 0,this.__altered=!0,this):Ye(o,i)},We.prototype.__ensureOwner=function(t){return t===this.__ownerID?this:t?Ye(this.size,this._head,t,this.__hash):(this.__ownerID=t,this.__altered=!1,this)},We.prototype.__iterate=function(t,e){if(e)return this.reverse().__iterate(t);for(var n=0,r=this._head;r&&t(r.value,n++,this)!==!1;)r=r.next;return n},We.prototype.__iterator=function(t,e){if(e)return this.reverse().__iterator(t);var n=0,r=this._head;return new E(function(){if(r){var e=r.value;return r=r.next,S(t,n++,e)}return w()})},We.isStack=Ve;var or="@@__IMMUTABLE_STACK__@@",ir=We.prototype;ir[or]=!0,ir.withMutations=Hn.withMutations,ir.asMutable=Hn.asMutable,ir.asImmutable=Hn.asImmutable,ir.wasAltered=Hn.wasAltered;var ur;e.Iterator=E,$e(e,{toArray:function(){lt(this.size);var t=new Array(this.size||0);return this.valueSeq().__iterate(function(e,n){t[n]=e}),t},toIndexedSeq:function(){return new oe(this)},toJS:function(){return this.toSeq().map(function(t){return t&&"function"==typeof t.toJS?t.toJS():t}).__toJS()},toJSON:function(){return this.toSeq().map(function(t){return t&&"function"==typeof t.toJSON?t.toJSON():t}).__toJS()},toKeyedSeq:function(){return new re(this,!0)},toMap:function(){return ft(this.toKeyedSeq())},toObject:function(){lt(this.size);var t={};return this.__iterate(function(e,n){t[n]=e}),t},toOrderedMap:function(){return Zt(this.toKeyedSeq())},toOrderedSet:function(){return He(u(this)?this.valueSeq():this)},toSet:function(){return je(u(this)?this.valueSeq():this)},toSetSeq:function(){return new ie(this)},toSeq:function(){return a(this)?this.toIndexedSeq():u(this)?this.toKeyedSeq():this.toSetSeq()},toStack:function(){return We(u(this)?this.valueSeq():this)},toList:function(){return Ut(u(this)?this.valueSeq():this)},toString:function(){return"[Iterable]"},__toString:function(t,e){return 0===this.size?t+e:t+" "+this.toSeq().map(this.__toStringMapper).join(", ")+" "+e},concat:function(){var t=sn.call(arguments,0);return Oe(this,_e(this,t))},includes:function(t){return this.some(function(e){return X(e,t)})},entries:function(){return this.__iterator(Sn)},every:function(t,e){lt(this.size);var n=!0;return this.__iterate(function(r,o,i){if(!t.call(e,r,o,i))return n=!1,!1}),n},filter:function(t,e){return Oe(this,le(this,t,e,!0))},find:function(t,e,n){var r=this.findEntry(t,e);return r?r[1]:n},findEntry:function(t,e){var n;return this.__iterate(function(r,o,i){if(t.call(e,r,o,i))return n=[o,r],!1}),n},findLastEntry:function(t,e){return this.toSeq().reverse().findEntry(t,e)},forEach:function(t,e){return lt(this.size),this.__iterate(e?t.bind(e):t)},join:function(t){lt(this.size),t=void 0!==t?""+t:",";var e="",n=!0;return this.__iterate(function(r){n?n=!1:e+=t,e+=null!==r&&void 0!==r?r.toString():""}),e},keys:function(){return this.__iterator(bn)},map:function(t,e){return Oe(this,se(this,t,e))},reduce:function(t,e,n){lt(this.size);var r,o;return arguments.length<2?o=!0:r=e,this.__iterate(function(e,i,u){o?(o=!1,r=e):r=t.call(n,r,e,i,u)}),r},reduceRight:function(t,e,n){var r=this.toKeyedSeq().reverse();return r.reduce.apply(r,arguments)},reverse:function(){return Oe(this,ce(this,!0))},slice:function(t,e){return Oe(this,de(this,t,e,!0))},some:function(t,e){return!this.every(Qe(t),e)},sort:function(t){return Oe(this,be(this,t))},values:function(){return this.__iterator(En)},butLast:function(){return this.slice(0,-1)},isEmpty:function(){return void 0!==this.size?0===this.size:!this.some(function(){return!0})},count:function(t,e){return h(t?this.toSeq().filter(t,e):this)},countBy:function(t,e){return fe(this,t,e)},equals:function(t){return $(this,t)},entrySeq:function(){var t=this;if(t._cache)return new k(t._cache);var e=t.toSeq().map(Ze).toIndexedSeq();return e.fromEntrySeq=function(){return t.toSeq()},e},filterNot:function(t,e){return this.filter(Qe(t),e)},findLast:function(t,e,n){return this.toKeyedSeq().reverse().find(t,e,n)},first:function(){return this.find(_)},flatMap:function(t,e){return Oe(this,ve(this,t,e))},flatten:function(t){return Oe(this,ge(this,t,!0))},fromEntrySeq:function(){return new ue(this)},get:function(t,e){return this.find(function(e,n){return X(n,t)},void 0,e)},getIn:function(t,e){for(var n,r=this,o=xe(t);!(n=o.next()).done;){var i=n.value;if(r=r&&r.get?r.get(i,gn):gn,r===gn)return e}return r},groupBy:function(t,e){return pe(this,t,e)},has:function(t){return this.get(t,gn)!==gn},hasIn:function(t){return this.getIn(t,gn)!==gn},isSubset:function(t){return t="function"==typeof t.includes?t:e(t),this.every(function(e){return t.includes(e)})},isSuperset:function(t){return t="function"==typeof t.isSubset?t:e(t),t.isSubset(this)},keySeq:function(){return this.toSeq().map(Je).toIndexedSeq()},last:function(){return this.toSeq().reverse().first()},max:function(t){return Ee(this,t)},maxBy:function(t,e){return Ee(this,e,t)},min:function(t){return Ee(this,t?tn(t):rn)},minBy:function(t,e){return Ee(this,e?tn(e):rn,t)},rest:function(){return this.slice(1)},skip:function(t){return this.slice(Math.max(0,t))},skipLast:function(t){return Oe(this,this.toSeq().reverse().skip(t).reverse())},skipWhile:function(t,e){return Oe(this,ye(this,t,e,!0))},skipUntil:function(t,e){return this.skipWhile(Qe(t),e)},sortBy:function(t,e){return Oe(this,be(this,e,t))},take:function(t){return this.slice(0,Math.max(0,t))},takeLast:function(t){return Oe(this,this.toSeq().reverse().take(t).reverse())},takeWhile:function(t,e){return Oe(this,he(this,t,e))},takeUntil:function(t,e){return this.takeWhile(Qe(t),e)},valueSeq:function(){return this.toIndexedSeq()},hashCode:function(){return this.__hash||(this.__hash=on(this))}});var ar=e.prototype;ar[cn]=!0,ar[Tn]=ar.values,ar.__toJS=ar.toArray,ar.__toStringMapper=en,ar.inspect=ar.toSource=function(){return this.toString()},ar.chain=ar.flatMap,ar.contains=ar.includes,function(){try{Object.defineProperty(ar,"length",{get:function(){if(!e.noLengthWarning){var t;try{throw new Error}catch(e){t=e.stack}if(t.indexOf("_wrapObject")===-1)return console&&console.warn&&console.warn("iterable.length has been deprecated, use iterable.size or iterable.count(). This warning will become a silent error in a future version. "+t),this.size}}})}catch(t){}}(),$e(n,{flip:function(){return Oe(this,ae(this))},findKey:function(t,e){var n=this.findEntry(t,e);return n&&n[0]},findLastKey:function(t,e){return this.toSeq().reverse().findKey(t,e)},keyOf:function(t){return this.findKey(function(e){return X(e,t)})},lastKeyOf:function(t){return this.findLastKey(function(e){return X(e,t)})},mapEntries:function(t,e){var n=this,r=0;return Oe(this,this.toSeq().map(function(o,i){return t.call(e,[i,o],r++,n)}).fromEntrySeq())},mapKeys:function(t,e){var n=this;return Oe(this,this.toSeq().flip().map(function(r,o){return t.call(e,r,o,n)}).flip())}});var sr=n.prototype;sr[ln]=!0,sr[Tn]=ar.entries,sr.__toJS=ar.toObject,sr.__toStringMapper=function(t,e){return JSON.stringify(e)+": "+en(t)},$e(r,{toKeyedSeq:function(){return new re(this,!1)},filter:function(t,e){return Oe(this,le(this,t,e,!1)); },findIndex:function(t,e){var n=this.findEntry(t,e);return n?n[0]:-1},indexOf:function(t){var e=this.toKeyedSeq().keyOf(t);return void 0===e?-1:e},lastIndexOf:function(t){var e=this.toKeyedSeq().reverse().keyOf(t);return void 0===e?-1:e},reverse:function(){return Oe(this,ce(this,!1))},slice:function(t,e){return Oe(this,de(this,t,e,!1))},splice:function(t,e){var n=arguments.length;if(e=Math.max(0|e,0),0===n||2===n&&!e)return this;t=v(t,t<0?this.count():this.size);var r=this.slice(0,t);return Oe(this,1===n?r:r.concat(d(arguments,2),this.slice(t+e)))},findLastIndex:function(t,e){var n=this.toKeyedSeq().findLastKey(t,e);return void 0===n?-1:n},first:function(){return this.get(0)},flatten:function(t){return Oe(this,ge(this,t,!1))},get:function(t,e){return t=y(this,t),t<0||this.size===1/0||void 0!==this.size&&t>this.size?e:this.find(function(e,n){return n===t},void 0,e)},has:function(t){return t=y(this,t),t>=0&&(void 0!==this.size?this.size===1/0||tr||n<=0)return"";var o=0;if(e>0){for(;e>0&&o=r)return""}else if(e<0){for(o=r;e<0&&00&&a-1}function h(t,e,n){for(var r=-1,o=null==t?0:t.length;++r-1;);return n}function U(t,e){for(var n=t.length;n--&&O(e,t[n],0)>-1;);return n}function B(t,e){for(var n=t.length,r=0;n--;)t[n]===e&&++r;return r}function K(t){return"\\"+nr[t]}function H(t,e){return null==t?ot:t[e]}function G(t){return Vn.test(t)}function z(t){return Yn.test(t)}function q(t){for(var e,n=[];!(e=t.next()).done;)n.push(e.value);return n}function W(t){var e=-1,n=Array(t.size);return t.forEach(function(t,r){n[++e]=[r,t]}),n}function V(t,e){return function(n){return t(e(n))}}function Y(t,e){for(var n=-1,r=t.length,o=0,i=[];++n>>1,Kt=[["ary",Ot],["bind",gt],["bindKey",vt],["curry",bt],["curryRight",Et],["flip",Ct],["partial",St],["partialRight",wt],["rearg",Tt]],Ht="[object Arguments]",Gt="[object Array]",zt="[object AsyncFunction]",qt="[object Boolean]",Wt="[object Date]",Vt="[object DOMException]",Yt="[object Error]",Xt="[object Function]",$t="[object GeneratorFunction]",Jt="[object Map]",Zt="[object Number]",Qt="[object Null]",te="[object Object]",ee="[object Promise]",ne="[object Proxy]",re="[object RegExp]",oe="[object Set]",ie="[object String]",ue="[object Symbol]",ae="[object Undefined]",se="[object WeakMap]",ce="[object WeakSet]",le="[object ArrayBuffer]",fe="[object DataView]",pe="[object Float32Array]",de="[object Float64Array]",he="[object Int8Array]",ye="[object Int16Array]",_e="[object Int32Array]",ge="[object Uint8Array]",ve="[object Uint8ClampedArray]",me="[object Uint16Array]",be="[object Uint32Array]",Ee=/\b__p \+= '';/g,Se=/\b(__p \+=) '' \+/g,we=/(__e\(.*?\)|\b__t\)) \+\n'';/g,Oe=/&(?:amp|lt|gt|quot|#39);/g,Te=/[&<>"']/g,Ce=RegExp(Oe.source),Ie=RegExp(Te.source),Ne=/<%-([\s\S]+?)%>/g,Ae=/<%([\s\S]+?)%>/g,De=/<%=([\s\S]+?)%>/g,xe=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,Pe=/^\w*$/,ke=/^\./,Me=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,Re=/[\\^$.*+?()[\]{}|]/g,Fe=RegExp(Re.source),je=/^\s+|\s+$/g,Le=/^\s+/,Ue=/\s+$/,Be=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Ke=/\{\n\/\* \[wrapped with (.+)\] \*/,He=/,? & /,Ge=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,ze=/\\(\\)?/g,qe=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,We=/\w*$/,Ve=/^[-+]0x[0-9a-f]+$/i,Ye=/^0b[01]+$/i,Xe=/^\[object .+?Constructor\]$/,$e=/^0o[0-7]+$/i,Je=/^(?:0|[1-9]\d*)$/,Ze=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,Qe=/($^)/,tn=/['\n\r\u2028\u2029\\]/g,en="\\ud800-\\udfff",nn="\\u0300-\\u036f",rn="\\ufe20-\\ufe2f",on="\\u20d0-\\u20ff",un=nn+rn+on,an="\\u2700-\\u27bf",sn="a-z\\xdf-\\xf6\\xf8-\\xff",cn="\\xac\\xb1\\xd7\\xf7",ln="\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf",fn="\\u2000-\\u206f",pn=" \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",dn="A-Z\\xc0-\\xd6\\xd8-\\xde",hn="\\ufe0e\\ufe0f",yn=cn+ln+fn+pn,_n="['’]",gn="["+en+"]",vn="["+yn+"]",mn="["+un+"]",bn="\\d+",En="["+an+"]",Sn="["+sn+"]",wn="[^"+en+yn+bn+an+sn+dn+"]",On="\\ud83c[\\udffb-\\udfff]",Tn="(?:"+mn+"|"+On+")",Cn="[^"+en+"]",In="(?:\\ud83c[\\udde6-\\uddff]){2}",Nn="[\\ud800-\\udbff][\\udc00-\\udfff]",An="["+dn+"]",Dn="\\u200d",xn="(?:"+Sn+"|"+wn+")",Pn="(?:"+An+"|"+wn+")",kn="(?:"+_n+"(?:d|ll|m|re|s|t|ve))?",Mn="(?:"+_n+"(?:D|LL|M|RE|S|T|VE))?",Rn=Tn+"?",Fn="["+hn+"]?",jn="(?:"+Dn+"(?:"+[Cn,In,Nn].join("|")+")"+Fn+Rn+")*",Ln="\\d*(?:(?:1st|2nd|3rd|(?![123])\\dth)\\b)",Un="\\d*(?:(?:1ST|2ND|3RD|(?![123])\\dTH)\\b)",Bn=Fn+Rn+jn,Kn="(?:"+[En,In,Nn].join("|")+")"+Bn,Hn="(?:"+[Cn+mn+"?",mn,In,Nn,gn].join("|")+")",Gn=RegExp(_n,"g"),zn=RegExp(mn,"g"),qn=RegExp(On+"(?="+On+")|"+Hn+Bn,"g"),Wn=RegExp([An+"?"+Sn+"+"+kn+"(?="+[vn,An,"$"].join("|")+")",Pn+"+"+Mn+"(?="+[vn,An+xn,"$"].join("|")+")",An+"?"+xn+"+"+kn,An+"+"+Mn,Un,Ln,bn,Kn].join("|"),"g"),Vn=RegExp("["+Dn+en+un+hn+"]"),Yn=/[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Xn=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],$n=-1,Jn={};Jn[pe]=Jn[de]=Jn[he]=Jn[ye]=Jn[_e]=Jn[ge]=Jn[ve]=Jn[me]=Jn[be]=!0,Jn[Ht]=Jn[Gt]=Jn[le]=Jn[qt]=Jn[fe]=Jn[Wt]=Jn[Yt]=Jn[Xt]=Jn[Jt]=Jn[Zt]=Jn[te]=Jn[re]=Jn[oe]=Jn[ie]=Jn[se]=!1;var Zn={};Zn[Ht]=Zn[Gt]=Zn[le]=Zn[fe]=Zn[qt]=Zn[Wt]=Zn[pe]=Zn[de]=Zn[he]=Zn[ye]=Zn[_e]=Zn[Jt]=Zn[Zt]=Zn[te]=Zn[re]=Zn[oe]=Zn[ie]=Zn[ue]=Zn[ge]=Zn[ve]=Zn[me]=Zn[be]=!0,Zn[Yt]=Zn[Xt]=Zn[se]=!1;var Qn={"À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","Ç":"C","ç":"c","Ð":"D","ð":"d","È":"E","É":"E","Ê":"E","Ë":"E","è":"e","é":"e","ê":"e","ë":"e","Ì":"I","Í":"I","Î":"I","Ï":"I","ì":"i","í":"i","î":"i","ï":"i","Ñ":"N","ñ":"n","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","Ù":"U","Ú":"U","Û":"U","Ü":"U","ù":"u","ú":"u","û":"u","ü":"u","Ý":"Y","ý":"y","ÿ":"y","Æ":"Ae","æ":"ae","Þ":"Th","þ":"th","ß":"ss","Ā":"A","Ă":"A","Ą":"A","ā":"a","ă":"a","ą":"a","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","ć":"c","ĉ":"c","ċ":"c","č":"c","Ď":"D","Đ":"D","ď":"d","đ":"d","Ē":"E","Ĕ":"E","Ė":"E","Ę":"E","Ě":"E","ē":"e","ĕ":"e","ė":"e","ę":"e","ě":"e","Ĝ":"G","Ğ":"G","Ġ":"G","Ģ":"G","ĝ":"g","ğ":"g","ġ":"g","ģ":"g","Ĥ":"H","Ħ":"H","ĥ":"h","ħ":"h","Ĩ":"I","Ī":"I","Ĭ":"I","Į":"I","İ":"I","ĩ":"i","ī":"i","ĭ":"i","į":"i","ı":"i","Ĵ":"J","ĵ":"j","Ķ":"K","ķ":"k","ĸ":"k","Ĺ":"L","Ļ":"L","Ľ":"L","Ŀ":"L","Ł":"L","ĺ":"l","ļ":"l","ľ":"l","ŀ":"l","ł":"l","Ń":"N","Ņ":"N","Ň":"N","Ŋ":"N","ń":"n","ņ":"n","ň":"n","ŋ":"n","Ō":"O","Ŏ":"O","Ő":"O","ō":"o","ŏ":"o","ő":"o","Ŕ":"R","Ŗ":"R","Ř":"R","ŕ":"r","ŗ":"r","ř":"r","Ś":"S","Ŝ":"S","Ş":"S","Š":"S","ś":"s","ŝ":"s","ş":"s","š":"s","Ţ":"T","Ť":"T","Ŧ":"T","ţ":"t","ť":"t","ŧ":"t","Ũ":"U","Ū":"U","Ŭ":"U","Ů":"U","Ű":"U","Ų":"U","ũ":"u","ū":"u","ŭ":"u","ů":"u","ű":"u","ų":"u","Ŵ":"W","ŵ":"w","Ŷ":"Y","ŷ":"y","Ÿ":"Y","Ź":"Z","Ż":"Z","Ž":"Z","ź":"z","ż":"z","ž":"z","IJ":"IJ","ij":"ij","Œ":"Oe","œ":"oe","ʼn":"'n","ſ":"s"},tr={"&":"&","<":"<",">":">",'"':""","'":"'"},er={"&":"&","<":"<",">":">",""":'"',"'":"'"},nr={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},rr=parseFloat,or=parseInt,ir="object"==typeof t&&t&&t.Object===Object&&t,ur="object"==typeof self&&self&&self.Object===Object&&self,ar=ir||ur||Function("return this")(),sr="object"==typeof e&&e&&!e.nodeType&&e,cr=sr&&"object"==typeof o&&o&&!o.nodeType&&o,lr=cr&&cr.exports===sr,fr=lr&&ir.process,pr=function(){try{return fr&&fr.binding&&fr.binding("util")}catch(t){}}(),dr=pr&&pr.isArrayBuffer,hr=pr&&pr.isDate,yr=pr&&pr.isMap,_r=pr&&pr.isRegExp,gr=pr&&pr.isSet,vr=pr&&pr.isTypedArray,mr=N("length"),br=A(Qn),Er=A(tr),Sr=A(er),wr=function t(e){function n(t){if(cs(t)&&!Ep(t)&&!(t instanceof b)){if(t instanceof o)return t;if(bl.call(t,"__wrapped__"))return uu(t)}return new o(t)}function r(){}function o(t,e){this.__wrapped__=t,this.__actions__=[],this.__chain__=!!e,this.__index__=0,this.__values__=ot}function b(t){this.__wrapped__=t,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=Lt,this.__views__=[]}function A(){var t=new b(this.__wrapped__);return t.__actions__=Ko(this.__actions__),t.__dir__=this.__dir__,t.__filtered__=this.__filtered__,t.__iteratees__=Ko(this.__iteratees__),t.__takeCount__=this.__takeCount__,t.__views__=Ko(this.__views__),t}function J(){if(this.__filtered__){var t=new b(this);t.__dir__=-1,t.__filtered__=!0}else t=this.clone(),t.__dir__*=-1;return t}function et(){var t=this.__wrapped__.value(),e=this.__dir__,n=Ep(t),r=e<0,o=n?t.length:0,i=Di(0,o,this.__views__),u=i.start,a=i.end,s=a-u,c=r?a:u-1,l=this.__iteratees__,f=l.length,p=0,d=$l(s,this.__takeCount__);if(!n||!r&&o==s&&d==s)return So(t,this.__actions__);var h=[];t:for(;s--&&p-1}function fn(t,e){var n=this.__data__,r=kn(n,t);return r<0?(++this.size,n.push([t,e])):n[r][1]=e,this}function pn(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e=e?t:e)),t}function Bn(t,e,n,r,o,i){var u,a=e&pt,s=e&dt,l=e&ht;if(n&&(u=o?n(t,r,o,i):n(t)),u!==ot)return u;if(!ss(t))return t;var f=Ep(t);if(f){if(u=ki(t),!a)return Ko(t,u)}else{var p=xf(t),d=p==Xt||p==$t;if(wp(t))return Ao(t,a);if(p==te||p==Ht||d&&!o){if(u=s||d?{}:Mi(t),!a)return s?zo(t,Fn(u,t)):Go(t,Rn(u,t))}else{if(!Zn[p])return o?t:{};u=Ri(t,p,Bn,a)}}i||(i=new En);var h=i.get(t);if(h)return h;i.set(t,u);var y=l?s?Si:Ei:s?qs:zs,_=f?ot:y(t);return c(_||t,function(r,o){_&&(o=r,r=t[o]),Pn(u,o,Bn(r,e,n,o,t,i))}),u}function Kn(t){var e=zs(t);return function(n){return Hn(n,t,e)}}function Hn(t,e,n){var r=n.length;if(null==t)return!r;for(t=fl(t);r--;){var o=n[r],i=e[o],u=t[o];if(u===ot&&!(o in t)||!i(u))return!1}return!0}function qn(t,e,n){if("function"!=typeof t)throw new hl(st);return Mf(function(){t.apply(ot,n)},e)}function Wn(t,e,n,r){var o=-1,i=d,u=!0,a=t.length,s=[],c=e.length;if(!a)return s;n&&(e=y(e,R(n))),r?(i=h,u=!1):e.length>=ut&&(i=j,u=!1,e=new vn(e));t:for(;++oo?0:o+n),r=r===ot||r>o?o:Cs(r),r<0&&(r+=o),r=n>r?0:Is(r);n0&&n(a)?e>1?er(a,e-1,n,r,o):_(o,a):r||(o[o.length]=a)}return o}function nr(t,e){return t&&Ef(t,e,zs)}function ir(t,e){return t&&Sf(t,e,zs)}function ur(t,e){return p(e,function(e){return is(t[e])})}function sr(t,e){e=Io(e,t);for(var n=0,r=e.length;null!=t&&ne}function mr(t,e){return null!=t&&bl.call(t,e)}function wr(t,e){return null!=t&&e in fl(t)}function Tr(t,e,n){return t>=$l(e,n)&&t=120&&l.length>=120)?new vn(u&&l):ot}l=t[0];var f=-1,p=a[0];t:for(;++f-1;)a!==t&&Ml.call(a,s,1),Ml.call(t,s,1);return t}function eo(t,e){for(var n=t?e.length:0,r=n-1;n--;){var o=e[n];if(n==r||o!==i){var i=o;Li(o)?Ml.call(t,o,1):mo(t,o)}}return t}function no(t,e){return t+Gl(Ql()*(e-t+1))}function ro(t,e,n,r){for(var o=-1,i=Xl(Hl((e-t)/(n||1)),0),u=ul(i);i--;)u[r?i:++o]=t,t+=n;return u}function oo(t,e){var n="";if(!t||e<1||e>Rt)return n;do e%2&&(n+=t),e=Gl(e/2),e&&(t+=t);while(e);return n}function io(t,e){return Rf(Ji(t,e,Mc),t+"")}function uo(t){return Nn(rc(t))}function ao(t,e){var n=rc(t);return nu(n,Un(e,0,n.length))}function so(t,e,n,r){if(!ss(t))return t;e=Io(e,t);for(var o=-1,i=e.length,u=i-1,a=t;null!=a&&++oo?0:o+e),n=n>o?o:n,n<0&&(n+=o),o=e>n?0:n-e>>>0,e>>>=0;for(var i=ul(o);++r>>1,u=t[i];null!==u&&!bs(u)&&(n?u<=e:u=ut){var c=e?null:If(t);if(c)return X(c);u=!1,o=j,s=new vn}else s=e?[]:a;t:for(;++r=r?t:lo(t,e,n)}function Ao(t,e){if(e)return t.slice();var n=t.length,r=Dl?Dl(n):new t.constructor(n);return t.copy(r),r}function Do(t){var e=new t.constructor(t.byteLength);return new Al(e).set(new Al(t)),e}function xo(t,e){var n=e?Do(t.buffer):t.buffer;return new t.constructor(n,t.byteOffset,t.byteLength)}function Po(t,e,n){var r=e?n(W(t),pt):W(t);return g(r,i,new t.constructor)}function ko(t){var e=new t.constructor(t.source,We.exec(t));return e.lastIndex=t.lastIndex,e}function Mo(t,e,n){var r=e?n(X(t),pt):X(t);return g(r,u,new t.constructor)}function Ro(t){return _f?fl(_f.call(t)):{}}function Fo(t,e){var n=e?Do(t.buffer):t.buffer;return new t.constructor(n,t.byteOffset,t.length)}function jo(t,e){if(t!==e){var n=t!==ot,r=null===t,o=t===t,i=bs(t),u=e!==ot,a=null===e,s=e===e,c=bs(e);if(!a&&!c&&!i&&t>e||i&&u&&s&&!a&&!c||r&&u&&s||!n&&s||!o)return 1;if(!r&&!i&&!c&&t=a)return s;var c=n[r];return s*("desc"==c?-1:1)}}return t.index-e.index}function Uo(t,e,n,r){for(var o=-1,i=t.length,u=n.length,a=-1,s=e.length,c=Xl(i-u,0),l=ul(s+c),f=!r;++a1?n[o-1]:ot,u=o>2?n[2]:ot;for(i=t.length>3&&"function"==typeof i?(o--,i):ot,u&&Ui(n[0],n[1],u)&&(i=o<3?ot:i,o=1),e=fl(e);++r-1?o[i?e[u]:u]:ot}}function ei(t){return bi(function(e){var n=e.length,r=n,i=o.prototype.thru;for(t&&e.reverse();r--;){var u=e[r];if("function"!=typeof u)throw new hl(st);if(i&&!a&&"wrapper"==wi(u))var a=new o([],!0)}for(r=a?r:n;++r1&&v.reverse(),f&&sa))return!1;var c=i.get(t);if(c&&i.get(e))return c==e;var l=-1,f=!0,p=n&_t?new vn:ot;for(i.set(t,e),i.set(e,t);++l1?"& ":"")+e[r],e=e.join(n>2?", ":" "),t.replace(Be,"{\n/* [wrapped with "+e+"] */\n")}function ji(t){return Ep(t)||bp(t)||!!(Rl&&t&&t[Rl])}function Li(t,e){return e=null==e?Rt:e,!!e&&("number"==typeof t||Je.test(t))&&t>-1&&t%1==0&&t0){if(++e>=At)return arguments[0]}else e=0;return t.apply(ot,arguments)}}function nu(t,e){var n=-1,r=t.length,o=r-1;for(e=e===ot?r:e;++n=this.__values__.length,e=t?ot:this.__values__[this.__index__++];return{done:t,value:e}}function ua(){return this}function aa(t){for(var e,n=this;n instanceof r;){var o=uu(n);o.__index__=0,o.__values__=ot,e?i.__wrapped__=o:e=o;var i=o;n=n.__wrapped__}return i.__wrapped__=t,e}function sa(){var t=this.__wrapped__;if(t instanceof b){var e=t;return this.__actions__.length&&(e=new b(this)),e=e.reverse(),e.__actions__.push({func:na,args:[Pu],thisArg:ot}),new o(e,this.__chain__)}return this.thru(Pu)}function ca(){return So(this.__wrapped__,this.__actions__)}function la(t,e,n){var r=Ep(t)?f:Vn;return n&&Ui(t,e,n)&&(e=ot),r(t,Ti(e,3))}function fa(t,e){var n=Ep(t)?p:tr;return n(t,Ti(e,3))}function pa(t,e){return er(va(t,e),1)}function da(t,e){return er(va(t,e),Mt)}function ha(t,e,n){return n=n===ot?1:Cs(n),er(va(t,e),n)}function ya(t,e){var n=Ep(t)?c:mf;return n(t,Ti(e,3))}function _a(t,e){var n=Ep(t)?l:bf;return n(t,Ti(e,3))}function ga(t,e,n,r){t=$a(t)?t:rc(t),n=n&&!r?Cs(n):0;var o=t.length;return n<0&&(n=Xl(o+n,0)),ms(t)?n<=o&&t.indexOf(e,n)>-1:!!o&&O(t,e,n)>-1}function va(t,e){var n=Ep(t)?y:zr;return n(t,Ti(e,3))}function ma(t,e,n,r){return null==t?[]:(Ep(e)||(e=null==e?[]:[e]),n=r?ot:n,Ep(n)||(n=null==n?[]:[n]),$r(t,e,n))}function ba(t,e,n){var r=Ep(t)?g:D,o=arguments.length<3;return r(t,Ti(e,4),n,o,mf)}function Ea(t,e,n){var r=Ep(t)?v:D,o=arguments.length<3;return r(t,Ti(e,4),n,o,bf)}function Sa(t,e){var n=Ep(t)?p:tr;return n(t,Fa(Ti(e,3)))}function wa(t){var e=Ep(t)?Nn:uo;return e(t)}function Oa(t,e,n){e=(n?Ui(t,e,n):e===ot)?1:Cs(e);var r=Ep(t)?An:ao;return r(t,e)}function Ta(t){var e=Ep(t)?Dn:co;return e(t)}function Ca(t){if(null==t)return 0;if($a(t))return ms(t)?Q(t):t.length;var e=xf(t);return e==Jt||e==oe?t.size:Kr(t).length}function Ia(t,e,n){var r=Ep(t)?m:fo;return n&&Ui(t,e,n)&&(e=ot),r(t,Ti(e,3))}function Na(t,e){if("function"!=typeof e)throw new hl(st);return t=Cs(t),function(){if(--t<1)return e.apply(this,arguments)}}function Aa(t,e,n){return e=n?ot:e,e=t&&null==e?t.length:e,di(t,Ot,ot,ot,ot,ot,e)}function Da(t,e){var n;if("function"!=typeof e)throw new hl(st);return t=Cs(t),function(){return--t>0&&(n=e.apply(this,arguments)),t<=1&&(e=ot),n}}function xa(t,e,n){e=n?ot:e;var r=di(t,bt,ot,ot,ot,ot,ot,e);return r.placeholder=xa.placeholder,r}function Pa(t,e,n){e=n?ot:e;var r=di(t,Et,ot,ot,ot,ot,ot,e);return r.placeholder=Pa.placeholder,r}function ka(t,e,n){function r(e){var n=p,r=d;return p=d=ot,v=e,y=t.apply(r,n)}function o(t){return v=t,_=Mf(a,e),m?r(t):y}function i(t){var n=t-g,r=t-v,o=e-n;return b?$l(o,h-r):o}function u(t){var n=t-g,r=t-v;return g===ot||n>=e||n<0||b&&r>=h}function a(){var t=cp();return u(t)?s(t):void(_=Mf(a,i(t)))}function s(t){return _=ot,E&&p?r(t):(p=d=ot,y)}function c(){_!==ot&&Cf(_),v=0,p=g=d=_=ot}function l(){return _===ot?y:s(cp())}function f(){var t=cp(),n=u(t);if(p=arguments,d=this,g=t,n){if(_===ot)return o(g);if(b)return _=Mf(a,e),r(g)}return _===ot&&(_=Mf(a,e)),y}var p,d,h,y,_,g,v=0,m=!1,b=!1,E=!0;if("function"!=typeof t)throw new hl(st);return e=Ns(e)||0,ss(n)&&(m=!!n.leading,b="maxWait"in n,h=b?Xl(Ns(n.maxWait)||0,e):h,E="trailing"in n?!!n.trailing:E),f.cancel=c,f.flush=l,f}function Ma(t){return di(t,Ct)}function Ra(t,e){if("function"!=typeof t||null!=e&&"function"!=typeof e)throw new hl(st);var n=function(){var r=arguments,o=e?e.apply(this,r):r[0],i=n.cache;if(i.has(o))return i.get(o);var u=t.apply(this,r);return n.cache=i.set(o,u)||i,u};return n.cache=new(Ra.Cache||pn),n}function Fa(t){if("function"!=typeof t)throw new hl(st);return function(){var e=arguments;switch(e.length){case 0:return!t.call(this);case 1:return!t.call(this,e[0]);case 2:return!t.call(this,e[0],e[1]);case 3:return!t.call(this,e[0],e[1],e[2])}return!t.apply(this,e)}}function ja(t){return Da(2,t)}function La(t,e){if("function"!=typeof t)throw new hl(st);return e=e===ot?e:Cs(e),io(t,e)}function Ua(t,e){if("function"!=typeof t)throw new hl(st);return e=null==e?0:Xl(Cs(e),0),io(function(n){var r=n[e],o=No(n,0,e);return r&&_(o,r),a(t,this,o)})}function Ba(t,e,n){var r=!0,o=!0;if("function"!=typeof t)throw new hl(st);return ss(n)&&(r="leading"in n?!!n.leading:r,o="trailing"in n?!!n.trailing:o),ka(t,e,{leading:r,maxWait:e,trailing:o})}function Ka(t){return Aa(t,1)}function Ha(t,e){return yp(Co(e),t)}function Ga(){if(!arguments.length)return[];var t=arguments[0];return Ep(t)?t:[t]}function za(t){return Bn(t,ht)}function qa(t,e){return e="function"==typeof e?e:ot,Bn(t,ht,e)}function Wa(t){return Bn(t,pt|ht)}function Va(t,e){return e="function"==typeof e?e:ot,Bn(t,pt|ht,e)}function Ya(t,e){return null==e||Hn(t,e,zs(e))}function Xa(t,e){return t===e||t!==t&&e!==e}function $a(t){return null!=t&&as(t.length)&&!is(t)}function Ja(t){return cs(t)&&$a(t)}function Za(t){return t===!0||t===!1||cs(t)&&fr(t)==qt}function Qa(t){return cs(t)&&1===t.nodeType&&!gs(t)}function ts(t){if(null==t)return!0;if($a(t)&&(Ep(t)||"string"==typeof t||"function"==typeof t.splice||wp(t)||Np(t)||bp(t)))return!t.length;var e=xf(t);if(e==Jt||e==oe)return!t.size;if(zi(t))return!Kr(t).length;for(var n in t)if(bl.call(t,n))return!1;return!0}function es(t,e){return Pr(t,e)}function ns(t,e,n){n="function"==typeof n?n:ot;var r=n?n(t,e):ot;return r===ot?Pr(t,e,ot,n):!!r}function rs(t){if(!cs(t))return!1;var e=fr(t);return e==Yt||e==Vt||"string"==typeof t.message&&"string"==typeof t.name&&!gs(t)}function os(t){return"number"==typeof t&&Wl(t)}function is(t){if(!ss(t))return!1;var e=fr(t);return e==Xt||e==$t||e==zt||e==ne}function us(t){return"number"==typeof t&&t==Cs(t)}function as(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=Rt}function ss(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)}function cs(t){return null!=t&&"object"==typeof t}function ls(t,e){return t===e||Rr(t,e,Ii(e))}function fs(t,e,n){return n="function"==typeof n?n:ot,Rr(t,e,Ii(e),n)}function ps(t){return _s(t)&&t!=+t}function ds(t){if(Pf(t))throw new sl(at);return Fr(t)}function hs(t){return null===t}function ys(t){return null==t}function _s(t){return"number"==typeof t||cs(t)&&fr(t)==Zt}function gs(t){if(!cs(t)||fr(t)!=te)return!1;var e=xl(t);if(null===e)return!0;var n=bl.call(e,"constructor")&&e.constructor;return"function"==typeof n&&n instanceof n&&ml.call(n)==Ol}function vs(t){return us(t)&&t>=-Rt&&t<=Rt}function ms(t){return"string"==typeof t||!Ep(t)&&cs(t)&&fr(t)==ie}function bs(t){return"symbol"==typeof t||cs(t)&&fr(t)==ue}function Es(t){return t===ot}function Ss(t){return cs(t)&&xf(t)==se}function ws(t){return cs(t)&&fr(t)==ce}function Os(t){if(!t)return[];if($a(t))return ms(t)?tt(t):Ko(t);if(Fl&&t[Fl])return q(t[Fl]());var e=xf(t),n=e==Jt?W:e==oe?X:rc;return n(t)}function Ts(t){if(!t)return 0===t?t:0;if(t=Ns(t),t===Mt||t===-Mt){var e=t<0?-1:1;return e*Ft}return t===t?t:0}function Cs(t){var e=Ts(t),n=e%1;return e===e?n?e-n:e:0}function Is(t){return t?Un(Cs(t),0,Lt):0}function Ns(t){if("number"==typeof t)return t;if(bs(t))return jt;if(ss(t)){var e="function"==typeof t.valueOf?t.valueOf():t;t=ss(e)?e+"":e}if("string"!=typeof t)return 0===t?t:+t;t=t.replace(je,"");var n=Ye.test(t);return n||$e.test(t)?or(t.slice(2),n?2:8):Ve.test(t)?jt:+t}function As(t){return Ho(t,qs(t))}function Ds(t){return t?Un(Cs(t),-Rt,Rt):0===t?t:0}function xs(t){return null==t?"":go(t)}function Ps(t,e){var n=vf(t);return null==e?n:Rn(n,e)}function ks(t,e){return S(t,Ti(e,3),nr)}function Ms(t,e){return S(t,Ti(e,3),ir)}function Rs(t,e){return null==t?t:Ef(t,Ti(e,3),qs)}function Fs(t,e){return null==t?t:Sf(t,Ti(e,3),qs)}function js(t,e){return t&&nr(t,Ti(e,3))}function Ls(t,e){return t&&ir(t,Ti(e,3))}function Us(t){return null==t?[]:ur(t,zs(t))}function Bs(t){return null==t?[]:ur(t,qs(t))}function Ks(t,e,n){var r=null==t?ot:sr(t,e);return r===ot?n:r}function Hs(t,e){return null!=t&&Pi(t,e,mr)}function Gs(t,e){return null!=t&&Pi(t,e,wr)}function zs(t){return $a(t)?In(t):Kr(t)}function qs(t){return $a(t)?In(t,!0):Hr(t)}function Ws(t,e){var n={};return e=Ti(e,3),nr(t,function(t,r,o){jn(n,e(t,r,o),t)}),n}function Vs(t,e){var n={};return e=Ti(e,3),nr(t,function(t,r,o){jn(n,r,e(t,r,o))}),n}function Ys(t,e){return Xs(t,Fa(Ti(e)))}function Xs(t,e){if(null==t)return{};var n=y(Si(t),function(t){return[t]});return e=Ti(e),Zr(t,n,function(t,n){return e(t,n[0])})}function $s(t,e,n){e=Io(e,t);var r=-1,o=e.length;for(o||(o=1,t=ot);++re){var r=t;t=e,e=r}if(n||t%1||e%1){var o=Ql();return $l(t+o*(e-t+rr("1e-"+((o+"").length-1))),e)}return no(t,e)}function sc(t){return td(xs(t).toLowerCase())}function cc(t){return t=xs(t),t&&t.replace(Ze,br).replace(zn,"")}function lc(t,e,n){t=xs(t),e=go(e);var r=t.length;n=n===ot?r:Un(Cs(n),0,r);var o=n;return n-=e.length,n>=0&&t.slice(n,o)==e}function fc(t){return t=xs(t),t&&Ie.test(t)?t.replace(Te,Er):t}function pc(t){return t=xs(t),t&&Fe.test(t)?t.replace(Re,"\\$&"):t}function dc(t,e,n){t=xs(t),e=Cs(e);var r=e?Q(t):0;if(!e||r>=e)return t;var o=(e-r)/2;return ui(Gl(o),n)+t+ui(Hl(o),n)}function hc(t,e,n){t=xs(t),e=Cs(e);var r=e?Q(t):0;return e&&r>>0)?(t=xs(t),t&&("string"==typeof e||null!=e&&!Cp(e))&&(e=go(e),!e&&G(t))?No(tt(t),0,n):t.split(e,n)):[]}function bc(t,e,n){return t=xs(t),n=null==n?0:Un(Cs(n),0,t.length),e=go(e),t.slice(n,n+e.length)==e}function Ec(t,e,r){var o=n.templateSettings;r&&Ui(t,e,r)&&(e=ot),t=xs(t),e=kp({},e,o,hi);var i,u,a=kp({},e.imports,o.imports,hi),s=zs(a),c=F(a,s),l=0,f=e.interpolate||Qe,p="__p += '",d=pl((e.escape||Qe).source+"|"+f.source+"|"+(f===De?qe:Qe).source+"|"+(e.evaluate||Qe).source+"|$","g"),h="//# sourceURL="+("sourceURL"in e?e.sourceURL:"lodash.templateSources["+ ++$n+"]")+"\n";t.replace(d,function(e,n,r,o,a,s){return r||(r=o),p+=t.slice(l,s).replace(tn,K),n&&(i=!0,p+="' +\n__e("+n+") +\n'"),a&&(u=!0,p+="';\n"+a+";\n__p += '"),r&&(p+="' +\n((__t = ("+r+")) == null ? '' : __t) +\n'"),l=s+e.length,e}),p+="';\n";var y=e.variable;y||(p="with (obj) {\n"+p+"\n}\n"),p=(u?p.replace(Ee,""):p).replace(Se,"$1").replace(we,"$1;"),p="function("+(y||"obj")+") {\n"+(y?"":"obj || (obj = {});\n")+"var __t, __p = ''"+(i?", __e = _.escape":"")+(u?", __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\n":";\n")+p+"return __p\n}";var _=ed(function(){return cl(s,h+"return "+p).apply(ot,c)});if(_.source=p,rs(_))throw _;return _}function Sc(t){return xs(t).toLowerCase()}function wc(t){return xs(t).toUpperCase()}function Oc(t,e,n){if(t=xs(t),t&&(n||e===ot))return t.replace(je,"");if(!t||!(e=go(e)))return t;var r=tt(t),o=tt(e),i=L(r,o),u=U(r,o)+1;return No(r,i,u).join("")}function Tc(t,e,n){if(t=xs(t),t&&(n||e===ot))return t.replace(Ue,"");if(!t||!(e=go(e)))return t;var r=tt(t),o=U(r,tt(e))+1;return No(r,0,o).join("")}function Cc(t,e,n){if(t=xs(t),t&&(n||e===ot))return t.replace(Le,"");if(!t||!(e=go(e)))return t;var r=tt(t),o=L(r,tt(e));return No(r,o).join("")}function Ic(t,e){var n=It,r=Nt;if(ss(e)){var o="separator"in e?e.separator:o;n="length"in e?Cs(e.length):n,r="omission"in e?go(e.omission):r}t=xs(t);var i=t.length;if(G(t)){var u=tt(t);i=u.length}if(n>=i)return t;var a=n-Q(r);if(a<1)return r;var s=u?No(u,0,a).join(""):t.slice(0,a);if(o===ot)return s+r;if(u&&(a+=s.length-a),Cp(o)){if(t.slice(a).search(o)){var c,l=s;for(o.global||(o=pl(o.source,xs(We.exec(o))+"g")),o.lastIndex=0;c=o.exec(l);)var f=c.index;s=s.slice(0,f===ot?a:f)}}else if(t.indexOf(go(o),a)!=a){var p=s.lastIndexOf(o);p>-1&&(s=s.slice(0,p))}return s+r}function Nc(t){return t=xs(t),t&&Ce.test(t)?t.replace(Oe,Sr):t}function Ac(t,e,n){return t=xs(t),e=n?ot:e,e===ot?z(t)?rt(t):E(t):t.match(e)||[]}function Dc(t){var e=null==t?0:t.length,n=Ti();return t=e?y(t,function(t){if("function"!=typeof t[1])throw new hl(st);return[n(t[0]),t[1]]}):[],io(function(n){for(var r=-1;++rRt)return[];var n=Lt,r=$l(t,Lt);e=Ti(e),t-=Lt;for(var o=k(r,e);++n1?t[e-1]:ot;return n="function"==typeof n?(t.pop(),n):ot,Ju(t,n)}),tp=bi(function(t){var e=t.length,n=e?t[0]:0,r=this.__wrapped__,i=function(e){return Ln(e,t)};return!(e>1||this.__actions__.length)&&r instanceof b&&Li(n)?(r=r.slice(n,+n+(e?1:0)),r.__actions__.push({func:na,args:[i],thisArg:ot}),new o(r,this.__chain__).thru(function(t){return e&&!t.length&&t.push(ot),t})):this.thru(i)}),ep=qo(function(t,e,n){bl.call(t,n)?++t[n]:jn(t,n,1)}),np=ti(yu),rp=ti(_u),op=qo(function(t,e,n){bl.call(t,n)?t[n].push(e):jn(t,n,[e])}),ip=io(function(t,e,n){var r=-1,o="function"==typeof e,i=$a(t)?ul(t.length):[];return mf(t,function(t){i[++r]=o?a(e,t,n):Nr(t,e,n)}),i}),up=qo(function(t,e,n){jn(t,n,e)}),ap=qo(function(t,e,n){t[n?0:1].push(e)},function(){return[[],[]]}),sp=io(function(t,e){if(null==t)return[];var n=e.length;return n>1&&Ui(t,e[0],e[1])?e=[]:n>2&&Ui(e[0],e[1],e[2])&&(e=[e[0]]),$r(t,er(e,1),[])}),cp=Bl||function(){return ar.Date.now()},lp=io(function(t,e,n){var r=gt;if(n.length){var o=Y(n,Oi(lp));r|=St}return di(t,r,e,n,o)}),fp=io(function(t,e,n){var r=gt|vt;if(n.length){var o=Y(n,Oi(fp));r|=St}return di(e,r,t,n,o)}),pp=io(function(t,e){return qn(t,1,e)}),dp=io(function(t,e,n){return qn(t,Ns(e)||0,n)});Ra.Cache=pn;var hp=Tf(function(t,e){e=1==e.length&&Ep(e[0])?y(e[0],R(Ti())):y(er(e,1),R(Ti()));var n=e.length;return io(function(r){for(var o=-1,i=$l(r.length,n);++o=e}),bp=Ar(function(){return arguments}())?Ar:function(t){return cs(t)&&bl.call(t,"callee")&&!kl.call(t,"callee")},Ep=ul.isArray,Sp=dr?R(dr):Dr,wp=ql||qc,Op=hr?R(hr):xr,Tp=yr?R(yr):Mr,Cp=_r?R(_r):jr,Ip=gr?R(gr):Lr,Np=vr?R(vr):Ur,Ap=ci(Gr),Dp=ci(function(t,e){return t<=e}),xp=Wo(function(t,e){if(zi(e)||$a(e))return void Ho(e,zs(e),t);for(var n in e)bl.call(e,n)&&Pn(t,n,e[n])}),Pp=Wo(function(t,e){Ho(e,qs(e),t)}),kp=Wo(function(t,e,n,r){Ho(e,qs(e),t,r)}),Mp=Wo(function(t,e,n,r){Ho(e,zs(e),t,r)}),Rp=bi(Ln),Fp=io(function(t){return t.push(ot,hi),a(kp,ot,t)}),jp=io(function(t){return t.push(ot,yi),a(Hp,ot,t)}),Lp=ri(function(t,e,n){t[e]=n},Pc(Mc)),Up=ri(function(t,e,n){bl.call(t,e)?t[e].push(n):t[e]=[n]},Ti),Bp=io(Nr),Kp=Wo(function(t,e,n){Vr(t,e,n)}),Hp=Wo(function(t,e,n,r){Vr(t,e,n,r)}),Gp=bi(function(t,e){var n={};if(null==t)return n;var r=!1;e=y(e,function(e){return e=Io(e,t),r||(r=e.length>1),e}),Ho(t,Si(t),n),r&&(n=Bn(n,pt|dt|ht,_i));for(var o=e.length;o--;)mo(n,e[o]);return n}),zp=bi(function(t,e){return null==t?{}:Jr(t,e)}),qp=pi(zs),Wp=pi(qs),Vp=Jo(function(t,e,n){return e=e.toLowerCase(),t+(n?sc(e):e)}),Yp=Jo(function(t,e,n){return t+(n?"-":"")+e.toLowerCase()}),Xp=Jo(function(t,e,n){return t+(n?" ":"")+e.toLowerCase()}),$p=$o("toLowerCase"),Jp=Jo(function(t,e,n){return t+(n?"_":"")+e.toLowerCase()}),Zp=Jo(function(t,e,n){return t+(n?" ":"")+td(e)}),Qp=Jo(function(t,e,n){return t+(n?" ":"")+e.toUpperCase()}),td=$o("toUpperCase"),ed=io(function(t,e){try{return a(t,ot,e)}catch(t){return rs(t)?t:new sl(t)}}),nd=bi(function(t,e){return c(e,function(e){e=ru(e),jn(t,e,lp(t[e],t))}),t}),rd=ei(),od=ei(!0),id=io(function(t,e){return function(n){return Nr(n,t,e)}}),ud=io(function(t,e){return function(n){return Nr(t,n,e)}}),ad=ii(y),sd=ii(f),cd=ii(m),ld=si(),fd=si(!0),pd=oi(function(t,e){return t+e},0),dd=fi("ceil"),hd=oi(function(t,e){return t/e},1),yd=fi("floor"),_d=oi(function(t,e){return t*e},1),gd=fi("round"),vd=oi(function(t,e){return t-e},0);return n.after=Na,n.ary=Aa,n.assign=xp,n.assignIn=Pp,n.assignInWith=kp,n.assignWith=Mp,n.at=Rp,n.before=Da,n.bind=lp,n.bindAll=nd,n.bindKey=fp,n.castArray=Ga,n.chain=ta,n.chunk=au,n.compact=su,n.concat=cu,n.cond=Dc,n.conforms=xc,n.constant=Pc,n.countBy=ep,n.create=Ps,n.curry=xa,n.curryRight=Pa,n.debounce=ka,n.defaults=Fp,n.defaultsDeep=jp,n.defer=pp,n.delay=dp,n.difference=jf,n.differenceBy=Lf,n.differenceWith=Uf,n.drop=lu,n.dropRight=fu,n.dropRightWhile=pu,n.dropWhile=du,n.fill=hu,n.filter=fa,n.flatMap=pa,n.flatMapDeep=da,n.flatMapDepth=ha,n.flatten=gu,n.flattenDeep=vu,n.flattenDepth=mu,n.flip=Ma,n.flow=rd,n.flowRight=od,n.fromPairs=bu,n.functions=Us,n.functionsIn=Bs,n.groupBy=op,n.initial=wu,n.intersection=Bf,n.intersectionBy=Kf,n.intersectionWith=Hf,n.invert=Lp,n.invertBy=Up,n.invokeMap=ip,n.iteratee=Rc,n.keyBy=up,n.keys=zs,n.keysIn=qs,n.map=va,n.mapKeys=Ws,n.mapValues=Vs,n.matches=Fc,n.matchesProperty=jc,n.memoize=Ra,n.merge=Kp,n.mergeWith=Hp,n.method=id,n.methodOf=ud,n.mixin=Lc,n.negate=Fa,n.nthArg=Kc,n.omit=Gp,n.omitBy=Ys,n.once=ja,n.orderBy=ma,n.over=ad,n.overArgs=hp,n.overEvery=sd,n.overSome=cd,n.partial=yp,n.partialRight=_p,n.partition=ap,n.pick=zp,n.pickBy=Xs,n.property=Hc,n.propertyOf=Gc,n.pull=Gf,n.pullAll=Nu,n.pullAllBy=Au,n.pullAllWith=Du,n.pullAt=zf,n.range=ld,n.rangeRight=fd,n.rearg=gp,n.reject=Sa,n.remove=xu,n.rest=La,n.reverse=Pu,n.sampleSize=Oa,n.set=Js,n.setWith=Zs,n.shuffle=Ta,n.slice=ku,n.sortBy=sp,n.sortedUniq=Bu,n.sortedUniqBy=Ku,n.split=mc,n.spread=Ua,n.tail=Hu,n.take=Gu,n.takeRight=zu,n.takeRightWhile=qu,n.takeWhile=Wu,n.tap=ea,n.throttle=Ba,n.thru=na,n.toArray=Os,n.toPairs=qp,n.toPairsIn=Wp,n.toPath=$c,n.toPlainObject=As,n.transform=Qs,n.unary=Ka,n.union=qf,n.unionBy=Wf,n.unionWith=Vf,n.uniq=Vu,n.uniqBy=Yu,n.uniqWith=Xu,n.unset=tc,n.unzip=$u,n.unzipWith=Ju,n.update=ec,n.updateWith=nc,n.values=rc,n.valuesIn=oc,n.without=Yf,n.words=Ac,n.wrap=Ha,n.xor=Xf,n.xorBy=$f,n.xorWith=Jf,n.zip=Zf,n.zipObject=Zu,n.zipObjectDeep=Qu,n.zipWith=Qf,n.entries=qp,n.entriesIn=Wp,n.extend=Pp,n.extendWith=kp,Lc(n,n),n.add=pd,n.attempt=ed,n.camelCase=Vp,n.capitalize=sc,n.ceil=dd,n.clamp=ic,n.clone=za,n.cloneDeep=Wa,n.cloneDeepWith=Va,n.cloneWith=qa,n.conformsTo=Ya,n.deburr=cc,n.defaultTo=kc,n.divide=hd,n.endsWith=lc,n.eq=Xa,n.escape=fc,n.escapeRegExp=pc,n.every=la,n.find=np,n.findIndex=yu,n.findKey=ks,n.findLast=rp,n.findLastIndex=_u,n.findLastKey=Ms,n.floor=yd,n.forEach=ya,n.forEachRight=_a,n.forIn=Rs,n.forInRight=Fs,n.forOwn=js,n.forOwnRight=Ls,n.get=Ks,n.gt=vp,n.gte=mp,n.has=Hs,n.hasIn=Gs,n.head=Eu,n.identity=Mc,n.includes=ga,n.indexOf=Su,n.inRange=uc,n.invoke=Bp,n.isArguments=bp,n.isArray=Ep,n.isArrayBuffer=Sp,n.isArrayLike=$a,n.isArrayLikeObject=Ja,n.isBoolean=Za,n.isBuffer=wp,n.isDate=Op,n.isElement=Qa,n.isEmpty=ts,n.isEqual=es,n.isEqualWith=ns,n.isError=rs,n.isFinite=os,n.isFunction=is,n.isInteger=us,n.isLength=as,n.isMap=Tp,n.isMatch=ls,n.isMatchWith=fs,n.isNaN=ps,n.isNative=ds,n.isNil=ys,n.isNull=hs,n.isNumber=_s,n.isObject=ss,n.isObjectLike=cs,n.isPlainObject=gs,n.isRegExp=Cp,n.isSafeInteger=vs,n.isSet=Ip,n.isString=ms,n.isSymbol=bs,n.isTypedArray=Np,n.isUndefined=Es,n.isWeakMap=Ss,n.isWeakSet=ws,n.join=Ou,n.kebabCase=Yp,n.last=Tu,n.lastIndexOf=Cu,n.lowerCase=Xp,n.lowerFirst=$p,n.lt=Ap,n.lte=Dp,n.max=Zc,n.maxBy=Qc,n.mean=tl,n.meanBy=el,n.min=nl,n.minBy=rl,n.stubArray=zc,n.stubFalse=qc,n.stubObject=Wc,n.stubString=Vc,n.stubTrue=Yc,n.multiply=_d,n.nth=Iu,n.noConflict=Uc,n.noop=Bc,n.now=cp,n.pad=dc,n.padEnd=hc,n.padStart=yc,n.parseInt=_c,n.random=ac,n.reduce=ba,n.reduceRight=Ea,n.repeat=gc,n.replace=vc,n.result=$s,n.round=gd,n.runInContext=t,n.sample=wa,n.size=Ca,n.snakeCase=Jp,n.some=Ia,n.sortedIndex=Mu,n.sortedIndexBy=Ru,n.sortedIndexOf=Fu,n.sortedLastIndex=ju,n.sortedLastIndexBy=Lu,n.sortedLastIndexOf=Uu,n.startCase=Zp,n.startsWith=bc,n.subtract=vd,n.sum=ol,n.sumBy=il,n.template=Ec,n.times=Xc,n.toFinite=Ts,n.toInteger=Cs,n.toLength=Is,n.toLower=Sc,n.toNumber=Ns,n.toSafeInteger=Ds,n.toString=xs,n.toUpper=wc,n.trim=Oc,n.trimEnd=Tc,n.trimStart=Cc,n.truncate=Ic,n.unescape=Nc,n.uniqueId=Jc,n.upperCase=Qp,n.upperFirst=td,n.each=ya,n.eachRight=_a,n.first=Eu,Lc(n,function(){var t={};return nr(n,function(e,r){bl.call(n.prototype,r)||(t[r]=e)}),t}(),{chain:!1}),n.VERSION=it,c(["bind","bindKey","curry","curryRight","partial","partialRight"],function(t){n[t].placeholder=n}),c(["drop","take"],function(t,e){b.prototype[t]=function(n){n=n===ot?1:Xl(Cs(n),0);var r=this.__filtered__&&!e?new b(this):this.clone();return r.__filtered__?r.__takeCount__=$l(n,r.__takeCount__):r.__views__.push({size:$l(n,Lt),type:t+(r.__dir__<0?"Right":"")}),r},b.prototype[t+"Right"]=function(e){return this.reverse()[t](e).reverse()}}),c(["filter","map","takeWhile"],function(t,e){var n=e+1,r=n==xt||n==kt;b.prototype[t]=function(t){var e=this.clone();return e.__iteratees__.push({iteratee:Ti(t,3),type:n}),e.__filtered__=e.__filtered__||r,e}}),c(["head","last"],function(t,e){var n="take"+(e?"Right":"");b.prototype[t]=function(){return this[n](1).value()[0]}}),c(["initial","tail"],function(t,e){var n="drop"+(e?"":"Right");b.prototype[t]=function(){return this.__filtered__?new b(this):this[n](1)}}),b.prototype.compact=function(){return this.filter(Mc)},b.prototype.find=function(t){return this.filter(t).head()},b.prototype.findLast=function(t){return this.reverse().find(t)},b.prototype.invokeMap=io(function(t,e){return"function"==typeof t?new b(this):this.map(function(n){return Nr(n,t,e)})}),b.prototype.reject=function(t){return this.filter(Fa(Ti(t)))},b.prototype.slice=function(t,e){t=Cs(t);var n=this;return n.__filtered__&&(t>0||e<0)?new b(n):(t<0?n=n.takeRight(-t):t&&(n=n.drop(t)),e!==ot&&(e=Cs(e),n=e<0?n.dropRight(-e):n.take(e-t)),n)},b.prototype.takeRightWhile=function(t){return this.reverse().takeWhile(t).reverse()},b.prototype.toArray=function(){return this.take(Lt)},nr(b.prototype,function(t,e){var r=/^(?:filter|find|map|reject)|While$/.test(e),i=/^(?:head|last)$/.test(e),u=n[i?"take"+("last"==e?"Right":""):e],a=i||/^find/.test(e);u&&(n.prototype[e]=function(){var e=this.__wrapped__,s=i?[1]:arguments,c=e instanceof b,l=s[0],f=c||Ep(e),p=function(t){var e=u.apply(n,_([t],s));return i&&d?e[0]:e};f&&r&&"function"==typeof l&&1!=l.length&&(c=f=!1);var d=this.__chain__,h=!!this.__actions__.length,y=a&&!d,g=c&&!h;if(!a&&f){e=g?e:new b(this);var v=t.apply(e,s);return v.__actions__.push({func:na,args:[p],thisArg:ot}),new o(v,d)}return y&&g?t.apply(this,s):(v=this.thru(p),y?i?v.value()[0]:v.value():v)})}),c(["pop","push","shift","sort","splice","unshift"],function(t){var e=yl[t],r=/^(?:push|sort|unshift)$/.test(t)?"tap":"thru",o=/^(?:pop|shift)$/.test(t);n.prototype[t]=function(){var t=arguments;if(o&&!this.__chain__){var n=this.value();return e.apply(Ep(n)?n:[],t)}return this[r](function(n){return e.apply(Ep(n)?n:[],t)})}}),nr(b.prototype,function(t,e){var r=n[e];if(r){var o=r.name+"",i=cf[o]||(cf[o]=[]);i.push({name:e,func:r})}}),cf[ni(ot,vt).name]=[{name:"wrapper",func:ot}],b.prototype.clone=A,b.prototype.reverse=J,b.prototype.value=et,n.prototype.at=tp,n.prototype.chain=ra,n.prototype.commit=oa,n.prototype.next=ia,n.prototype.plant=aa,n.prototype.reverse=sa,n.prototype.toJSON=n.prototype.valueOf=n.prototype.value=ca,n.prototype.first=n.prototype.head,Fl&&(n.prototype[Fl]=ua),n},Or=wr();ar._=Or,r=function(){return Or}.call(e,n,e,o),!(r!==ot&&(o.exports=r))}).call(this)}).call(e,function(){return this}(),n(311)(t))},function(t,e,n){(function(t){function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){var n={};for(var r in t)e.indexOf(r)>=0||Object.prototype.hasOwnProperty.call(t,r)&&(n[r]=t[r]);return n}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function u(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function a(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}e.__esModule=!0,e.Helmet=void 0;var s=Object.assign||function(t){for(var e=1;e elements are self-closing and can not contain children. Refer to our API for more information.")},r.prototype.flattenArrayTypeChildren=function(t){var e,n=t.child,r=t.arrayTypeChildren,o=t.newChildProps,i=t.nestedChildren;return s({},r,(e={},e[n.type]=[].concat(r[n.type]||[],[s({},o,this.mapNestedChildrenToProps(n,i))]),e))},r.prototype.mapObjectTypeChildren=function(t){var e,n,r=t.child,o=t.newProps,i=t.newChildProps,u=t.nestedChildren;switch(r.type){case m.TAG_NAMES.TITLE:return s({},o,(e={},e[r.type]=u,e.titleAttributes=s({},i),e));case m.TAG_NAMES.BODY:return s({},o,{bodyAttributes:s({},i)});case m.TAG_NAMES.HTML:return s({},o,{htmlAttributes:s({},i)})}return s({},o,(n={},n[r.type]=s({},i),n))},r.prototype.mapArrayTypeChildrenToProps=function(t,e){var n=s({},e);return Object.keys(t).forEach(function(e){var r;n=s({},n,(r={},r[e]=t[e],r))}),n},r.prototype.warnOnInvalidChildren=function(e,n){if("production"!==t.env.NODE_ENV){if(!m.VALID_TAG_NAMES.some(function(t){return e.type===t}))return"function"==typeof e.type?(0,v.warn)("You may be attempting to nest components within each other, which is not allowed. Refer to our API for more information."):(0,v.warn)("Only elements types "+m.VALID_TAG_NAMES.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information.");if(n&&"string"!=typeof n&&(!Array.isArray(n)||n.some(function(t){return"string"!=typeof t})))throw new Error("Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``} ) Refer to our API for more information.")}return!0},r.prototype.mapChildrenToProps=function(t,e){var n=this,r={};return f.default.Children.forEach(t,function(t){if(t&&t.props){var i=t.props,u=i.children,a=o(i,["children"]),s=(0,v.convertReactPropstoHtmlAttributes)(a);switch(n.warnOnInvalidChildren(t,u),t.type){case m.TAG_NAMES.LINK:case m.TAG_NAMES.META:case m.TAG_NAMES.NOSCRIPT:case m.TAG_NAMES.SCRIPT:case m.TAG_NAMES.STYLE:r=n.flattenArrayTypeChildren({child:t,arrayTypeChildren:r,newChildProps:s,nestedChildren:u});break;default:e=n.mapObjectTypeChildren({child:t,newProps:e,newChildProps:s,nestedChildren:u})}}}),e=this.mapArrayTypeChildrenToProps(r,e)},r.prototype.render=function(){var t=this.props,n=t.children,r=o(t,["children"]),i=s({},r);return n&&(i=this.mapChildrenToProps(n,i)),f.default.createElement(e,i)},c(r,null,[{key:"canUseDOM",set:function(t){e.canUseDOM=t}}]),r}(f.default.Component),n.propTypes={base:d.default.object,bodyAttributes:d.default.object,children:d.default.oneOfType([d.default.arrayOf(d.default.node),d.default.node]),defaultTitle:d.default.string,encodeSpecialCharacters:d.default.bool,htmlAttributes:d.default.object,link:d.default.arrayOf(d.default.object),meta:d.default.arrayOf(d.default.object),noscript:d.default.arrayOf(d.default.object),onChangeClientState:d.default.func,script:d.default.arrayOf(d.default.object),style:d.default.arrayOf(d.default.object),title:d.default.string,titleAttributes:d.default.object,titleTemplate:d.default.string},n.defaultProps={encodeSpecialCharacters:!0},n.peek=e.peek,n.rewind=function(){var t=e.rewind();return t||(t=(0,v.mapStateOnServer)({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}})),t},r},E=function(){return null},S=(0,y.default)(v.reducePropsToState,v.handleClientStateChange,v.mapStateOnServer)(E),w=b(S);w.renderStatic=w.rewind,e.Helmet=w,e.default=w}).call(e,n(2))},function(t,e,n){"use strict";var r=n(5),o=r.OrderedMap,i={createFromArray:function(t){return o(t.map(function(t){return[t.getKey(),t]}))}};t.exports=i},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var u=n(5),a=u.Record,s={anchorKey:"",anchorOffset:0,focusKey:"",focusOffset:0,isBackward:!1,hasFocus:!1},c=a(s),l=function(t){function e(){return r(this,e),o(this,t.apply(this,arguments))}return i(e,t),e.prototype.serialize=function(){return"Anchor: "+this.getAnchorKey()+":"+this.getAnchorOffset()+", Focus: "+this.getFocusKey()+":"+this.getFocusOffset()+", Is Backward: "+String(this.getIsBackward())+", Has Focus: "+String(this.getHasFocus())},e.prototype.getAnchorKey=function(){return this.get("anchorKey")},e.prototype.getAnchorOffset=function(){return this.get("anchorOffset")},e.prototype.getFocusKey=function(){return this.get("focusKey")},e.prototype.getFocusOffset=function(){return this.get("focusOffset")},e.prototype.getIsBackward=function(){return this.get("isBackward")},e.prototype.getHasFocus=function(){return this.get("hasFocus")},e.prototype.hasEdgeWithin=function(t,e,n){var r=this.getAnchorKey(),o=this.getFocusKey();if(r===o&&r===t){var i=this.getStartOffset(),u=this.getEndOffset();return e<=u&&i<=n}if(t!==r&&t!==o)return!1;var a=t===r?this.getAnchorOffset():this.getFocusOffset();return e<=a&&n>=a},e.prototype.isCollapsed=function(){return this.getAnchorKey()===this.getFocusKey()&&this.getAnchorOffset()===this.getFocusOffset()},e.prototype.getStartKey=function(){return this.getIsBackward()?this.getFocusKey():this.getAnchorKey()},e.prototype.getStartOffset=function(){return this.getIsBackward()?this.getFocusOffset():this.getAnchorOffset()},e.prototype.getEndKey=function(){return this.getIsBackward()?this.getAnchorKey():this.getFocusKey()},e.prototype.getEndOffset=function(){return this.getIsBackward()?this.getAnchorOffset():this.getFocusOffset()},e.createEmpty=function(t){return new e({anchorKey:t,anchorOffset:0,focusKey:t,focusOffset:0,isBackward:!1,hasFocus:!1})},e}(c);t.exports=l},function(t,e,n){"use strict";function r(t,e,n){var r=t.getSelection(),i=t.getCurrentContent(),u=r;if(r.isCollapsed()){if("forward"===n){if(t.isSelectionAtEndOfContent())return i}else if(t.isSelectionAtStartOfContent())return i;if(u=e(t),u===r)return i}return o.removeRange(i,u,n)}var o=n(7);t.exports=r},function(t,e){"use strict";function n(t){return"object"==typeof t?Object.keys(t).filter(function(e){return t[e]}).map(r).join(" "):Array.prototype.map.call(arguments,r).join(" ")}function r(t){return t.replace(/\//g,"-")}t.exports=n},function(t,e,n){(function(e){"use strict";function r(t,e){console.warn("WARNING: "+t+' will be deprecated soon!\nPlease use "'+e+'" instead.')}var o=n(17),i=o||function(t){for(var e=1;e=200&&t<300}};c.headers={common:{Accept:"application/json, text/plain, */*"}},i.forEach(["delete","get","head"],function(t){c.headers[t]={}}),i.forEach(["post","put","patch"],function(t){c.headers[t]=i.merge(s)}),t.exports=c}).call(e,n(2))},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var u=n(25),a=n(12),s=n(18),c=n(29),l=n(5),f=n(26),p=n(13),d=n(45),h=l.List,y=l.Record,_=l.Repeat,g={entityMap:null,blockMap:null,selectionBefore:null,selectionAfter:null},v=y(g),m=function(t){function e(){return r(this,e),o(this,t.apply(this,arguments))}return i(e,t),e.prototype.getEntityMap=function(){return c},e.prototype.getBlockMap=function(){return this.get("blockMap")},e.prototype.getSelectionBefore=function(){return this.get("selectionBefore")},e.prototype.getSelectionAfter=function(){return this.get("selectionAfter")},e.prototype.getBlockForKey=function(t){var e=this.getBlockMap().get(t);return e},e.prototype.getKeyBefore=function(t){return this.getBlockMap().reverse().keySeq().skipUntil(function(e){return e===t}).skip(1).first()},e.prototype.getKeyAfter=function(t){return this.getBlockMap().keySeq().skipUntil(function(e){return e===t}).skip(1).first()},e.prototype.getBlockAfter=function(t){return this.getBlockMap().skipUntil(function(e,n){return n===t}).skip(1).first()},e.prototype.getBlockBefore=function(t){return this.getBlockMap().reverse().skipUntil(function(e,n){return n===t}).skip(1).first()},e.prototype.getBlocksAsArray=function(){return this.getBlockMap().toArray()},e.prototype.getFirstBlock=function(){return this.getBlockMap().first()},e.prototype.getLastBlock=function(){return this.getBlockMap().last()},e.prototype.getPlainText=function(t){return this.getBlockMap().map(function(t){return t?t.getText():""}).join(t||"\n")},e.prototype.getLastCreatedEntityKey=function(){return c.__getLastCreatedEntityKey()},e.prototype.hasText=function(){var t=this.getBlockMap();return t.size>1||t.first().getLength()>0},e.prototype.createEntity=function(t,e,n){return c.__create(t,e,n),this},e.prototype.mergeEntityData=function(t,e){return c.__mergeData(t,e),this},e.prototype.replaceEntityData=function(t,e){return c.__replaceData(t,e),this},e.prototype.addEntity=function(t){return c.__add(t),this},e.prototype.getEntity=function(t){return c.__get(t)},e.createFromBlockArray=function(t,n){var r=Array.isArray(t)?t:t.contentBlocks,o=u.createFromArray(r),i=o.isEmpty()?new f:f.createEmpty(o.first().getKey());return new e({blockMap:o,entityMap:n||c,selectionBefore:i,selectionAfter:i})},e.createFromText=function(t){var n=arguments.length<=1||void 0===arguments[1]?/\r\n?|\n/g:arguments[1],r=t.split(n),o=r.map(function(t){return t=d(t),new s({key:p(),text:t,type:"unstyled", characterList:h(_(a.EMPTY,t.length))})});return e.createFromBlockArray(o)},e}(v);t.exports=m},function(t,e,n){"use strict";var r=n(5),o=r.Map,i=n(1),u=n(28),a=i.createElement("ul",{className:u("public/DraftStyleDefault/ul")}),s=i.createElement("ol",{className:u("public/DraftStyleDefault/ol")}),c=i.createElement("pre",{className:u("public/DraftStyleDefault/pre")}),l=o({"header-one":{element:"h1"},"header-two":{element:"h2"},"header-three":{element:"h3"},"header-four":{element:"h4"},"header-five":{element:"h5"},"header-six":{element:"h6"},"unordered-list-item":{element:"li",wrapper:a},"ordered-list-item":{element:"li",wrapper:s},blockquote:{element:"blockquote"},atomic:{element:"figure"},"code-block":{element:"pre",wrapper:c},unstyled:{element:"div",aliasedElements:["p"]}});t.exports=l},function(t,e,n){"use strict";var r=n(15),o=r.isPlatform("Mac OS X"),i={isCtrlKeyCommand:function(t){return!!t.ctrlKey&&!t.altKey},isOptionKeyCommand:function(t){return o&&t.altKey},hasCommandModifier:function(t){return o?!!t.metaKey&&!t.altKey:i.isCtrlKeyCommand(t)}};t.exports=i},function(t,e,n){"use strict";function r(t){for(var e=t;e&&e!==document.documentElement;){var n=o(e);if(null!=n)return n;e=e.parentNode}return null}var o=n(74);t.exports=r},function(t,e){"use strict";function n(t,e){var n;if(e.isCollapsed()){var o=e.getAnchorKey(),i=e.getAnchorOffset();return i>0?(n=t.getBlockForKey(o).getEntityAt(i-1),r(t.getEntityMap(),n)):null}var u=e.getStartKey(),a=e.getStartOffset(),s=t.getBlockForKey(u);return n=a===s.getLength()?null:s.getEntityAt(a),r(t.getEntityMap(),n)}function r(t,e){if(e){var n=t.__get(e);return"MUTABLE"===n.getMutability()?e:null}return null}t.exports=n},function(t,e){"use strict";function n(t,e){var n=t.getSelection(),r=t.getCurrentContent(),o=n.getStartKey(),i=n.getStartOffset(),u=o,a=0;if(e>i){var s=r.getKeyBefore(o);if(null==s)u=o;else{u=s;var c=r.getBlockForKey(s);a=c.getText().length}}else a=i-e;return n.merge({focusKey:u,focusOffset:a,isBackward:!0})}t.exports=n},function(t,e){"use strict";function n(t){return t.replace(r,"")}var r=new RegExp("\r","g");t.exports=n},function(t,e){t.exports={loadingWrapper:"styles__loadingWrapper___3oy4O"}},function(t,e){"use strict";t.exports={BACKSPACE:8,TAB:9,RETURN:13,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46,COMMA:188,PERIOD:190,A:65,Z:90,ZERO:48,NUMPAD_0:96,NUMPAD_9:105}},function(t,e,n){"use strict";function r(t,e){var n=i.get(t,e);return"auto"===n||"scroll"===n}var o=n(229),i={get:o,getScrollParent:function(t){if(!t)return null;for(var e=t.ownerDocument;t&&t!==e.body;){if(r(t,"overflow")||r(t,"overflowY")||r(t,"overflowX"))return t;t=t.parentNode}return e.defaultView||e.parentWindow}};t.exports=i},function(t,e,n){(function(e){"use strict";function r(t){return t===f||t===p}function o(t){return r(t)?void 0:"production"!==e.env.NODE_ENV?c(!1,"`dir` must be a strong direction to be converted to HTML Direction"):c(!1),t===f?"ltr":"rtl"}function i(t,n){return r(t)?void 0:"production"!==e.env.NODE_ENV?c(!1,"`dir` must be a strong direction to be converted to HTML Direction"):c(!1),r(n)?void 0:"production"!==e.env.NODE_ENV?c(!1,"`otherDir` must be a strong direction to be converted to HTML Direction"):c(!1),t===n?null:o(t)}function u(t){d=t}function a(){u(f)}function s(){return d||this.initGlobalDir(),d?void 0:"production"!==e.env.NODE_ENV?c(!1,"Global direction not set."):c(!1),d}var c=n(3),l="NEUTRAL",f="LTR",p="RTL",d=null,h={NEUTRAL:l,LTR:f,RTL:p,isStrong:r,getHTMLDir:o,getHTMLDirIfDifferent:i,setGlobalDir:u,initGlobalDir:a,getGlobalDir:s};t.exports=h}).call(e,n(2))},function(t,e,n){"use strict";function r(t){var e=o(t.ownerDocument||t.document);t.Window&&t instanceof t.Window&&(t=e);var n=i(t),r=t===e?t.ownerDocument.documentElement:t,u=t.scrollWidth-r.clientWidth,a=t.scrollHeight-r.clientHeight;return n.x=Math.max(0,Math.min(n.x,u)),n.y=Math.max(0,Math.min(n.y,a)),n}var o=n(226),i=n(230);t.exports=r},function(t,e,n){(function(e){"use strict";var r=n(22),o=r;"production"!==e.env.NODE_ENV&&!function(){var t=function(t){for(var e=arguments.length,n=Array(e>1?e-1:0),r=1;r2?r-2:0),i=2;i0&&window.scrollTo(u.x,u.y+r+w)}else{o instanceof HTMLElement?void 0:"production"!==e.env.NODE_ENV?E(!1,"blockNode is not an HTMLElement"):E(!1);var l=o.offsetHeight+o.offsetTop,f=i.offsetHeight+u.y;r=l-f,r>0&&d.setTop(i,d.getTop(i)+r+w)}}},n.prototype._renderChildren=function(){var t=this,e=this.props.block,n=e.getKey(),r=e.getText(),o=this.props.tree.size-1,i=u(this.props.selection,n);return this.props.tree.map(function(u,a){var p=u.get("leaves"),d=p.size-1,h=p.map(function(u,s){var p=l.encode(n,a,s),h=u.get("start"),y=u.get("end");return f.createElement(c,{key:p,offsetKey:p,block:e,start:h,selection:i?t.props.selection:void 0,forceSelection:t.props.forceSelection,text:r.slice(h,y),styleSet:e.getInlineStyleAt(h),customStyleMap:t.props.customStyleMap,customStyleFn:t.props.customStyleFn,isLast:a===o&&s===d})}).toArray(),g=u.get("decoratorKey");if(null==g)return h;if(!t.props.decorator)return h;var v=S(t.props.decorator),m=v.getComponentForKey(g);if(!m)return h;var b=v.getPropsForKey(g),E=l.encode(n,a,0),w=r.slice(p.first().get("start"),p.last().get("end")),O=_.getHTMLDirIfDifferent(y.getDirection(w),t.props.direction);return f.createElement(m,s({},b,{contentState:t.props.contentState,decoratedText:w,dir:O,key:E,entityKey:e.getEntityAt(u.get("start")),offsetKey:E}),h)}).toArray()},n.prototype.render=function(){var t=this.props,e=t.direction,n=t.offsetKey,r=g({"public/DraftStyleDefault/block":!0,"public/DraftStyleDefault/ltr":"LTR"===e,"public/DraftStyleDefault/rtl":"RTL"===e});return f.createElement("div",{"data-offset-key":n,className:r},this._renderChildren())},n}(f.Component);t.exports=O}).call(e,n(2))},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var u=n(5),a=u.Record,s=a({type:"TOKEN",mutability:"IMMUTABLE",data:Object}),c=function(t){function e(){return r(this,e),o(this,t.apply(this,arguments))}return i(e,t),e.prototype.getType=function(){return this.get("type")},e.prototype.getMutability=function(){return this.get("mutability")},e.prototype.getData=function(){return this.get("data")},e}(s);t.exports=c},function(t,e){"use strict";var n={draft_killswitch_allow_nontextnodes:!1,draft_segmented_entities_behavior:!1};t.exports=n},function(t,e,n){"use strict";function r(t,e){var n=e?f.exec(t):c.exec(t);return n?n[0]:t}var o=n(218),i=o.getPunctuation(),u="['‘’]",a="\\s|(?![_])"+i,s="^(?:"+a+")*(?:"+u+"|(?!"+a+").)*(?:(?!"+a+").)",c=new RegExp(s),l="(?:(?!"+a+").)(?:"+u+"|(?!"+a+").)*(?:"+a+")*$",f=new RegExp(l),p={getBackward:function(t){return r(t,!0)},getForward:function(t){return r(t,!1)}};t.exports=p},function(t,e){"use strict";var n={stringify:function(t){return"_"+String(t)},unstringify:function(t){return t.slice(1)}};t.exports=n},function(t,e,n){(function(e){"use strict";function r(){return{text:"",inlines:[],entities:[],blocks:[]}}function o(t){var e=new Array(1);return t&&(e[0]=t),{text:R,inlines:[k()],entities:e,blocks:[]}}function i(){return{text:"\n",inlines:[k()],entities:new Array(1),blocks:[]}}function u(t,e){return{text:"\r",inlines:[k()],entities:new Array(1),blocks:[{type:t,depth:Math.max(0,Math.min(F,e))}]}}function a(t,e){return"li"===t?"ol"===e?"ordered-list-item":"unordered-list-item":null}function s(t){var e=t.get("unstyled").element,n=new x([]);return t.forEach(function(t){t.aliasedElements&&t.aliasedElements.forEach(function(t){n=n.add(t)}),n=n.add(t.element)}),n.filter(function(t){return t&&t!==e}).toArray().sort()}function c(t,e,n){for(var r=0;r=0?e.add("BOLD"):G.indexOf(n)>=0&&e.remove("BOLD"),"italic"===r?e.add("ITALIC"):"normal"===r&&e.remove("ITALIC"),"underline"===o&&e.add("UNDERLINE"),"line-through"===o&&e.add("STRIKETHROUGH"),"none"===o&&(e.remove("UNDERLINE"),e.remove("STRIKETHROUGH"))}).toOrderedSet()}(),n}function p(t,e){var n=t.text.slice(-1),r=e.text.slice(0,1);if("\r"===n&&"\r"===r&&(t.text=t.text.slice(0,-1),t.inlines.pop(),t.entities.pop(),t.blocks.pop()),"\r"===n){if(e.text===R||"\n"===e.text)return t;r!==R&&"\n"!==r||(e.text=e.text.slice(1),e.inlines.shift(),e.entities.shift())}return{text:t.text+e.text,inlines:t.inlines.concat(e.inlines),entities:t.entities.concat(e.entities),blocks:t.blocks.concat(e.blocks)}}function d(t,e){return e.some(function(e){return t.indexOf("<"+e)!==-1})}function h(t){t instanceof HTMLAnchorElement?void 0:"production"!==e.env.NODE_ENV?I(!1,"Link must be an HTMLAnchorElement."):I(!1);var n=t.protocol;return"http:"===n||"https:"===n||"mailto:"===n}function y(t,e,n,a,s,c,d,_,g){var m=e.nodeName.toLowerCase(),b=!1,E="unstyled",w=v,T=t;if("#text"===m){var C=e.textContent;return""===C.trim()&&"pre"!==s?{chunk:o(g),entityMap:t}:("pre"!==s&&(C=C.replace(L,R)),v=m,{chunk:{text:C,inlines:Array(C.length).fill(n),entities:Array(C.length).fill(g),blocks:[]},entityMap:t})}if(v=m,"br"===m)return"br"!==w||s&&"unstyled"!==l(s,a,_)?{chunk:i(),entityMap:t}:{chunk:u("unstyled",d),entityMap:t};"img"===m&&e instanceof HTMLImageElement&&e.attributes.getNamedItem("src")&&e.attributes.getNamedItem("src").value&&!function(){var t=e,n={};W.forEach(function(e){var r=t.getAttribute(e);r&&(n[e]=r)});var r=new O(n.src).toString();e.textContent=r,g=S.__create("IMAGE","MUTABLE",n||{})}();var I=r(),N=null;n=f(m,e,n),"ul"!==m&&"ol"!==m||(a&&(d+=1),a=m),s||c.indexOf(m)===-1?a&&"li"===s&&"li"===m&&(I=u(l(m,a,_),d),s=m,b=!0,E="ul"===a?"unordered-list-item":"ordered-list-item"):(I=u(l(m,a,_),d),s=m,b=!0);var A=e.firstChild;null!=A&&(m=A.nodeName.toLowerCase());for(var D=null;A;){A instanceof HTMLAnchorElement&&A.href&&h(A)?!function(){var t=A,e={};q.forEach(function(n){var r=t.getAttribute(n);r&&(e[n]=r)}),e.url=new O(t.href).toString(),D=S.__create("LINK","MUTABLE",e||{})}():D=void 0;var x=y(T,A,n,a,s,c,d,_,D||g),P=x.chunk,k=x.entityMap;N=P,T=k,I=p(I,N);var M=A.nextSibling;M&&c.indexOf(m)>=0&&s&&(I=p(I,i())),M&&(m=M.nodeName.toLowerCase()),A=M}return b&&(I=p(I,u(E,d))),{chunk:I,entityMap:T}}function _(t,e,n,r){t=t.trim().replace(j,"").replace(U,R).replace(B,"").replace(K,"");var o=s(n),i=e(t);if(!i)return null;v=null;var u=d(t,o)?o:["div"],a=y(r,i,k(),"ul",null,u,-1,n),c=a.chunk,l=a.entityMap;return 0===c.text.indexOf("\r")&&(c={text:c.text.slice(1),inlines:c.inlines.slice(1),entities:c.entities.slice(1),blocks:c.blocks}),"\r"===c.text.slice(-1)&&(c.text=c.text.slice(0,-1),c.inlines=c.inlines.slice(0,-1),c.entities=c.entities.slice(0,-1),c.blocks.pop()),0===c.blocks.length&&c.blocks.push({type:"unstyled",depth:0}),c.text.split("\r").length===c.blocks.length+1&&c.blocks.unshift({type:"unstyled",depth:0}),{chunk:c,entityMap:l}}function g(t){var e=arguments.length<=1||void 0===arguments[1]?C:arguments[1],n=arguments.length<=2||void 0===arguments[2]?E:arguments[2],r=_(t,e,n,S);if(null==r)return null;var o=r.chunk,i=r.entityMap,u=0;return{contentBlocks:o.text.split("\r").map(function(t,e){t=A(t);var n=u+t.length,r=N(o).inlines.slice(u,n),i=N(o).entities.slice(u,n),a=P(r.map(function(t,e){var n={style:t,entity:null};return i[e]&&(n.entity=i[e]),m.create(n)}));return u=n+1,new b({key:T(),type:N(o).blocks[e].type,depth:N(o).blocks[e].depth,text:t,characterList:a})}),entityMap:i}}var v,m=n(12),b=n(18),E=n(40),S=n(29),w=n(5),O=n(219),T=n(13),C=n(73),I=n(3),N=n(10),A=n(45),D=n(5),x=D.Set,P=w.List,k=w.OrderedSet,M=" ",R=" ",F=4,j=new RegExp("\r","g"),L=new RegExp("\n","g"),U=new RegExp(M,"g"),B=new RegExp(" ?","g"),K=new RegExp("​?","g"),H=["bold","bolder","500","600","700","800","900"],G=["light","lighter","100","200","300","400"],z={b:"BOLD",code:"CODE",del:"STRIKETHROUGH",em:"ITALIC",i:"ITALIC",s:"STRIKETHROUGH",strike:"STRIKETHROUGH",strong:"BOLD",u:"UNDERLINE"},q=["className","href","rel","target","title"],W=["alt","className","height","src","width"];t.exports=g}).call(e,n(2))},function(t,e,n){"use strict";function r(t){return f&&t.altKey||y(t)}function o(t){return h(t)?t.shiftKey?"redo":"undo":null}function i(t){return p&&t.shiftKey?null:r(t)?"delete-word":"delete"}function u(t){return h(t)&&f?"backspace-to-start-of-line":r(t)?"backspace-word":"backspace"}function a(t){switch(t.keyCode){case 66:return h(t)?"bold":null;case 68:return y(t)?"delete":null;case 72:return y(t)?"backspace":null;case 73:return h(t)?"italic":null;case 74:return h(t)?"code":null;case 75:return!p&&y(t)?"secondary-cut":null;case 77:return y(t)?"split-block":null;case 79:return y(t)?"split-block":null;case 84:return f&&y(t)?"transpose-characters":null;case 85:return h(t)?"underline":null;case 87:return f&&y(t)?"backspace-word":null;case 89:return y(t)?p?"redo":"secondary-paste":null;case 90:return o(t)||null;case c.RETURN:return"split-block";case c.DELETE:return i(t);case c.BACKSPACE:return u(t);case c.LEFT:return d&&h(t)?"move-selection-to-start-of-block":null;case c.RIGHT:return d&&h(t)?"move-selection-to-end-of-block":null;default:return null}}var s=n(41),c=n(47),l=n(15),f=l.isPlatform("Mac OS X"),p=l.isPlatform("Windows"),d=f&&l.isBrowser("Firefox < 29"),h=s.hasCommandModifier,y=s.isCtrlKeyCommand;t.exports=a},function(t,e,n){(function(e){"use strict";function r(t,e,n,r,o,i){var a=n.nodeType===Node.TEXT_NODE,c=o.nodeType===Node.TEXT_NODE;if(a&&c)return{selectionState:l(t,p(s(n)),r,p(s(o)),i),needsRecovery:!1};var f=null,d=null,h=!0;return a?(f={key:p(s(n)),offset:r},d=u(e,o,i)):c?(d={key:p(s(o)),offset:i},f=u(e,n,r)):(f=u(e,n,r),d=u(e,o,i),n===o&&r===i&&(h=!!n.firstChild&&"BR"!==n.firstChild.nodeName)),{selectionState:l(t,f.key,f.offset,d.key,d.offset),needsRecovery:h}}function o(t){for(;t.firstChild&&c(t.firstChild);)t=t.firstChild;return t}function i(t){for(;t.lastChild&&c(t.lastChild);)t=t.lastChild;return t}function u(t,n,r){var u=n,l=s(u);if(null!=l||t&&(t===u||t.firstChild===u)?void 0:"production"!==e.env.NODE_ENV?f(!1,"Unknown node in selection range."):f(!1),t===u&&(u=u.firstChild,u instanceof Element&&"true"===u.getAttribute("data-contents")?void 0:"production"!==e.env.NODE_ENV?f(!1,"Invalid DraftEditorContents structure."):f(!1),r>0&&(r=u.childNodes.length)),0===r){var d=null;if(null!=l)d=l;else{var h=o(u);d=p(c(h))}return{key:d,offset:0}}var y=u.childNodes[r-1],_=null,g=null;if(c(y)){var v=i(y);_=p(c(v)),g=a(v)}else _=p(l),g=a(y);return{key:_,offset:g}}function a(t){var e=t.textContent;return"\n"===e?0:e.length}var s=n(42),c=n(74),l=n(76),f=n(3),p=n(10);t.exports=r}).call(e,n(2))},function(t,e,n){"use strict";function r(t){var e=t.getSelection();return e.isCollapsed()?null:o(t.getCurrentContent(),e)}var o=n(32);t.exports=r},function(t,e,n){(function(e){"use strict";function r(t){for(var n=t.cloneRange(),r=[],o=t.endContainer;null!=o;o=o.parentNode){var u=o===t.commonAncestorContainer;u?n.setStart(t.startContainer,t.startOffset):n.setStart(n.endContainer,0);var a=Array.from(n.getClientRects());if(r.push(a),u){var s;return r.reverse(),(s=[]).concat.apply(s,r)}n.setEndBefore(o)}"production"!==e.env.NODE_ENV?i(!1,"Found an unexpected detached subtree when getting range client rects."):i(!1)}var o=n(15),i=n(3),u=o.isBrowser("Chrome"),a=u?r:function(t){return Array.from(t.getClientRects())};t.exports=a}).call(e,n(2))},function(t,e,n){(function(e){"use strict";function r(t){var n,r=null;return!u&&document.implementation&&document.implementation.createHTMLDocument&&(n=document.implementation.createHTMLDocument("foo"),n.documentElement?void 0:"production"!==e.env.NODE_ENV?i(!1,"Missing doc.documentElement"):i(!1),n.documentElement.innerHTML=t,r=n.getElementsByTagName("body")[0]),r}var o=n(15),i=n(3),u=o.isBrowser("IE <= 9");t.exports=r}).call(e,n(2))},function(t,e){"use strict";function n(t){if(t instanceof Element){var e=t.getAttribute("data-offset-key");if(e)return e;for(var r=0;rs.getText().length-i?(a=u.getKeyAfter(o),n=0):n=i+e,r.merge({focusKey:a,focusOffset:n})}t.exports=n},function(t,e,n){(function(e){"use strict";function r(t,e){var n=t.getBlockMap(),r=t.getEntityMap(),o={},u=e.getStartKey(),a=e.getStartOffset(),s=n.get(u),c=i(r,s,a);c!==s&&(o[u]=c);var l=e.getEndKey(),f=e.getEndOffset(),p=n.get(l);u===l&&(p=c);var d=i(r,p,f);return d!==p&&(o[l]=d),Object.keys(o).length?t.merge({blockMap:n.merge(o),selectionAfter:e}):t.set("selectionAfter",e)}function o(t,n,r){var o;return a(t,function(t,e){return t.getEntity()===e.getEntity()},function(t){return t.getEntity()===n},function(t,e){t<=r&&e>=r&&(o={start:t,end:e})}),"object"!=typeof o?"production"!==e.env.NODE_ENV?s(!1,"Removal range must exist within character list."):s(!1):void 0,o}function i(t,e,n){var r=e.getCharacterList(),i=n>0?r.get(n-1):void 0,a=n0},t}();t.exports=f},function(t,e){"use strict";function n(t,e){return!!e&&(t===e.documentElement||t===e.body)}var r={getTop:function(t){var e=t.ownerDocument;return n(t,e)?e.body.scrollTop||e.documentElement.scrollTop:t.scrollTop},setTop:function(t,e){var r=t.ownerDocument;n(t,r)?r.body.scrollTop=r.documentElement.scrollTop=e:t.scrollTop=e},getLeft:function(t){var e=t.ownerDocument;return n(t,e)?e.body.scrollLeft||e.documentElement.scrollLeft:t.scrollLeft},setLeft:function(t,e){var r=t.ownerDocument;n(t,r)?r.body.scrollLeft=r.documentElement.scrollLeft=e:t.scrollLeft=e}};t.exports=r},function(t,e,n){(function(e){"use strict";function r(t){var e=p.exec(t);return null==e?null:e[0]}function o(t){var e=r(t);return null==e?c.NEUTRAL:d.exec(e)?c.RTL:c.LTR}function i(t,e){if(e=e||c.NEUTRAL,!t.length)return e;var n=o(t);return n===c.NEUTRAL?e:n}function u(t,n){return n||(n=c.getGlobalDir()),c.isStrong(n)?void 0:"production"!==e.env.NODE_ENV?l(!1,"Fallback direction must be a strong direction"):l(!1),i(t,n)}function a(t,e){return u(t,e)===c.LTR}function s(t,e){return u(t,e)===c.RTL}var c=n(49),l=n(3),f={L:"A-Za-zªµºÀ-ÖØ-öø-ƺƻƼ-ƿǀ-ǃDŽ-ʓʔʕ-ʯʰ-ʸʻ-ˁː-ˑˠ-ˤˮͰ-ͳͶ-ͷͺͻ-ͽͿΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁ҂Ҋ-ԯԱ-Ֆՙ՚-՟ա-և։ःऄ-हऻऽा-ीॉ-ौॎ-ॏॐक़-ॡ।-॥०-९॰ॱॲ-ঀং-ঃঅ-ঌএ-ঐও-নপ-রলশ-হঽা-ীে-ৈো-ৌৎৗড়-ঢ়য়-ৡ০-৯ৰ-ৱ৴-৹৺ਃਅ-ਊਏ-ਐਓ-ਨਪ-ਰਲ-ਲ਼ਵ-ਸ਼ਸ-ਹਾ-ੀਖ਼-ੜਫ਼੦-੯ੲ-ੴઃઅ-ઍએ-ઑઓ-નપ-રલ-ળવ-હઽા-ીૉો-ૌૐૠ-ૡ૦-૯૰ଂ-ଃଅ-ଌଏ-ଐଓ-ନପ-ରଲ-ଳଵ-ହଽାୀେ-ୈୋ-ୌୗଡ଼-ଢ଼ୟ-ୡ୦-୯୰ୱ୲-୷ஃஅ-ஊஎ-ஐஒ-கங-சஜஞ-டண-தந-பம-ஹா-ிு-ூெ-ைொ-ௌௐௗ௦-௯௰-௲ఁ-ఃఅ-ఌఎ-ఐఒ-నప-హఽు-ౄౘ-ౙౠ-ౡ౦-౯౿ಂ-ಃಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽಾಿೀ-ೄೆೇ-ೈೊ-ೋೕ-ೖೞೠ-ೡ೦-೯ೱ-ೲം-ഃഅ-ഌഎ-ഐഒ-ഺഽാ-ീെ-ൈൊ-ൌൎൗൠ-ൡ൦-൯൰-൵൹ൺ-ൿං-ඃඅ-ඖක-නඳ-රලව-ෆා-ෑෘ-ෟ෦-෯ෲ-ෳ෴ก-ะา-ำเ-ๅๆ๏๐-๙๚-๛ກ-ຂຄງ-ຈຊຍດ-ທນ-ຟມ-ຣລວສ-ຫອ-ະາ-ຳຽເ-ໄໆ໐-໙ໜ-ໟༀ༁-༃༄-༒༓༔༕-༗༚-༟༠-༩༪-༳༴༶༸༾-༿ཀ-ཇཉ-ཬཿ྅ྈ-ྌ྾-࿅࿇-࿌࿎-࿏࿐-࿔࿕-࿘࿙-࿚က-ဪါ-ာေးျ-ြဿ၀-၉၊-၏ၐ-ၕၖ-ၗၚ-ၝၡၢ-ၤၥ-ၦၧ-ၭၮ-ၰၵ-ႁႃ-ႄႇ-ႌႎႏ႐-႙ႚ-ႜ႞-႟Ⴀ-ჅჇჍა-ჺ჻ჼჽ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚ፠-፨፩-፼ᎀ-ᎏᎠ-Ᏼᐁ-ᙬ᙭-᙮ᙯ-ᙿᚁ-ᚚᚠ-ᛪ᛫-᛭ᛮ-ᛰᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱ᜵-᜶ᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳាើ-ៅះ-ៈ។-៖ៗ៘-៚ៜ០-៩᠐-᠙ᠠ-ᡂᡃᡄ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤞᤣ-ᤦᤩ-ᤫᤰ-ᤱᤳ-ᤸ᥆-᥏ᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧀᧁ-ᧇᧈ-ᧉ᧐-᧙᧚ᨀ-ᨖᨙ-ᨚ᨞-᨟ᨠ-ᩔᩕᩗᩡᩣ-ᩤᩭ-ᩲ᪀-᪉᪐-᪙᪠-᪦ᪧ᪨-᪭ᬄᬅ-ᬳᬵᬻᬽ-ᭁᭃ-᭄ᭅ-ᭋ᭐-᭙᭚-᭠᭡-᭪᭴-᭼ᮂᮃ-ᮠᮡᮦ-ᮧ᮪ᮮ-ᮯ᮰-᮹ᮺ-ᯥᯧᯪ-ᯬᯮ᯲-᯳᯼-᯿ᰀ-ᰣᰤ-ᰫᰴ-ᰵ᰻-᰿᱀-᱉ᱍ-ᱏ᱐-᱙ᱚ-ᱷᱸ-ᱽ᱾-᱿᳀-᳇᳓᳡ᳩ-ᳬᳮ-ᳱᳲ-ᳳᳵ-ᳶᴀ-ᴫᴬ-ᵪᵫ-ᵷᵸᵹ-ᶚᶛ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼ‎ⁱⁿₐ-ₜℂℇℊ-ℓℕℙ-ℝℤΩℨK-ℭℯ-ℴℵ-ℸℹℼ-ℿⅅ-ⅉⅎ⅏Ⅰ-ↂↃ-ↄↅ-ↈ⌶-⍺⎕⒜-ⓩ⚬⠀-⣿Ⰰ-Ⱞⰰ-ⱞⱠ-ⱻⱼ-ⱽⱾ-ⳤⳫ-ⳮⳲ-ⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯ⵰ⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞ々〆〇〡-〩〮-〯〱-〵〸-〺〻〼ぁ-ゖゝ-ゞゟァ-ヺー-ヾヿㄅ-ㄭㄱ-ㆎ㆐-㆑㆒-㆕㆖-㆟ㆠ-ㆺㇰ-ㇿ㈀-㈜㈠-㈩㈪-㉇㉈-㉏㉠-㉻㉿㊀-㊉㊊-㊰㋀-㋋㋐-㋾㌀-㍶㍻-㏝㏠-㏾㐀-䶵一-鿌ꀀ-ꀔꀕꀖ-ꒌꓐ-ꓷꓸ-ꓽ꓾-꓿ꔀ-ꘋꘌꘐ-ꘟ꘠-꘩ꘪ-ꘫꙀ-ꙭꙮꚀ-ꚛꚜ-ꚝꚠ-ꛥꛦ-ꛯ꛲-꛷Ꜣ-ꝯꝰꝱ-ꞇ꞉-꞊Ꞌ-ꞎꞐ-ꞭꞰ-Ʇꟷꟸ-ꟹꟺꟻ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꠣ-ꠤꠧ꠰-꠵꠶-꠷ꡀ-ꡳꢀ-ꢁꢂ-ꢳꢴ-ꣃ꣎-꣏꣐-꣙ꣲ-ꣷ꣸-꣺ꣻ꤀-꤉ꤊ-ꤥ꤮-꤯ꤰ-ꥆꥒ-꥓꥟ꥠ-ꥼꦃꦄ-ꦲꦴ-ꦵꦺ-ꦻꦽ-꧀꧁-꧍ꧏ꧐-꧙꧞-꧟ꧠ-ꧤꧦꧧ-ꧯ꧰-꧹ꧺ-ꧾꨀ-ꨨꨯ-ꨰꨳ-ꨴꩀ-ꩂꩄ-ꩋꩍ꩐-꩙꩜-꩟ꩠ-ꩯꩰꩱ-ꩶ꩷-꩹ꩺꩻꩽꩾ-ꪯꪱꪵ-ꪶꪹ-ꪽꫀꫂꫛ-ꫜꫝ꫞-꫟ꫠ-ꫪꫫꫮ-ꫯ꫰-꫱ꫲꫳ-ꫴꫵꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚ꭛ꭜ-ꭟꭤ-ꭥꯀ-ꯢꯣ-ꯤꯦ-ꯧꯩ-ꯪ꯫꯬꯰-꯹가-힣ힰ-ퟆퟋ-ퟻ-豈-舘並-龎ff-stﬓ-ﬗA-Za-zヲ-ッーア-ン゙-゚ᅠ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ", R:"֐־׀׃׆׈-׏א-ת׫-ׯװ-ײ׳-״׵-׿߀-߉ߊ-ߪߴ-ߵߺ߻-߿ࠀ-ࠕࠚࠤࠨ࠮-࠯࠰-࠾࠿ࡀ-ࡘ࡜-࡝࡞࡟-࢟‏יִײַ-ﬨשׁ-זּ﬷טּ-לּ﬽מּ﬿נּ-סּ﭂ףּ-פּ﭅צּ-ﭏ",AL:"؈؋؍؛؜؝؞-؟ؠ-ؿـف-ي٭ٮ-ٯٱ-ۓ۔ەۥ-ۦۮ-ۯۺ-ۼ۽-۾ۿ܀-܍܎܏ܐܒ-ܯ݋-݌ݍ-ޥޱ޲-޿ࢠ-ࢲࢳ-ࣣﭐ-ﮱ﮲-﯁﯂-﯒ﯓ-ﴽ﵀-﵏ﵐ-ﶏ﶐-﶑ﶒ-ﷇ﷈-﷏ﷰ-ﷻ﷼﷾-﷿ﹰ-ﹴ﹵ﹶ-ﻼ﻽-﻾"},p=new RegExp("["+f.L+f.R+f.AL+"]"),d=new RegExp("["+f.R+f.AL+"]"),h={firstStrongChar:r,firstStrongCharDir:o,resolveBlockDir:i,getDirection:u,isDirectionLTR:a,isDirectionRTL:s};t.exports=h}).call(e,n(2))},function(t,e,n){"use strict";function r(t,e){return!(!t||!e)&&(t===e||!o(t)&&(o(e)?r(t,e.parentNode):"contains"in t?t.contains(e):!!t.compareDocumentPosition&&!!(16&t.compareDocumentPosition(e))))}var o=n(234);t.exports=r},function(t,e){"use strict";function n(t){if(t=t||("undefined"!=typeof document?document:void 0),"undefined"==typeof t)return null;try{return t.activeElement||t.body}catch(e){return t.body}}t.exports=n},function(t,e,n){var r=n(247),o=r.Symbol;t.exports=o},function(t,e){e.__esModule=!0;var n=(e.ATTRIBUTE_NAMES={BODY:"bodyAttributes",HTML:"htmlAttributes",TITLE:"titleAttributes"},e.TAG_NAMES={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title"}),r=(e.VALID_TAG_NAMES=Object.keys(n).map(function(t){return n[t]}),e.TAG_PROPERTIES={CHARSET:"charset",CSS_TEXT:"cssText",HREF:"href",HTTPEQUIV:"http-equiv",INNER_HTML:"innerHTML",ITEM_PROP:"itemprop",NAME:"name",PROPERTY:"property",REL:"rel",SRC:"src"},e.REACT_TAG_MAP={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"});e.HELMET_PROPS={DEFAULT_TITLE:"defaultTitle",ENCODE_SPECIAL_CHARACTERS:"encodeSpecialCharacters",ON_CHANGE_CLIENT_STATE:"onChangeClientState",TITLE_TEMPLATE:"titleTemplate"},e.HTML_TAG_MAP=Object.keys(r).reduce(function(t,e){return t[r[e]]=e,t},{}),e.SELF_CLOSING_TAGS=[n.NOSCRIPT,n.SCRIPT,n.STYLE],e.HELMET_ATTRIBUTE="data-react-helmet"},function(t,e,n){try{(function(){"use strict";function t(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0}),e.getUser=e.updateCurrentForum=e.getForums=void 0;var r=n(23),o=(t(r),n(89)),i=n(256);e.getForums=function(){return function(t,e){t({type:o.START_FETCHING_FORUMS}),(0,i.fetchForums)().then(function(e){return t({type:o.FETCHING_FORUMS_SUCCESS,payload:e.data})},function(e){return t({type:o.FETCHING_FORUMS_FAILURE})})}},e.updateCurrentForum=function(t){return{type:o.UPDATECURRENTFORUM,payload:t}},e.getUser=function(){return function(t,e){t({type:o.START_FETCHING_USER}),(0,i.fetchUser)().then(function(e){t(e.data._id?{type:o.FETCHING_USER_SUCCESS,payload:e.data}:{type:o.FETCHING_USER_FAILURE})},function(e){return t({type:o.FETCHING_USER_FAILURE})})}}}).call(this)}finally{}},function(t,e,n){try{(function(){"use strict";Object.defineProperty(e,"__esModule",{value:!0});e.UPDATECURRENTFORUM="update_current_forum",e.START_FETCHING_FORUMS="start_fetching_forums",e.STOP_FETCHING_FORUMS="stop_fetching_forums",e.FETCHING_FORUMS_SUCCESS="fetching_forums_success",e.FETCHING_FORUMS_FAILURE="fetching_forums_failure",e.START_FETCHING_USER="start_fetching_user",e.FETCHING_USER_SUCCESS="fetching_user_success",e.FETCHING_USER_FAILURE="fetching_user_failure",e.SIGNOUT_USER_SUCCESS="signOut_user_success",e.SIGNOUT_USER_FAILURE="signOut_user_failure"}).call(this)}finally{}},function(t,e,n){try{(function(){"use strict";function t(t){return t&&t.__esModule?t:{default:t}}function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var u=function(){function t(t,e){for(var n=0;n=0||Object.prototype.hasOwnProperty.call(t,r)&&(n[r]=t[r]);return n}function s(){}function c(t,e){var n={run:function(r){try{var o=t(e.getState(),r);(o!==n.props||n.error)&&(n.shouldComponentUpdate=!0,n.props=o,n.error=null)}catch(t){n.shouldComponentUpdate=!0,n.error=t}}};return n}function l(e){var n,r,l=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},p=l.getDisplayName,h=void 0===p?function(t){return"ConnectAdvanced("+t+")"}:p,g=l.methodName,S=void 0===g?"connectAdvanced":g,w=l.renderCountProp,O=void 0===w?void 0:w,T=l.shouldHandleStateChanges,C=void 0===T||T,I=l.storeKey,N=void 0===I?"store":I,A=l.withRef,D=void 0!==A&&A,x=a(l,["getDisplayName","methodName","renderCountProp","shouldHandleStateChanges","storeKey","withRef"]),P=N+"Subscription",k=b++,M=(n={},n[N]=m.storeShape,n[P]=m.subscriptionShape,n),R=(r={},r[P]=m.subscriptionShape,r);return function(n){(0,y.default)("function"==typeof n,"You must pass a component to the function returned by connect. Instead received "+JSON.stringify(n));var r=n.displayName||n.name||"Component",a=h(r),l=f({},x,{getDisplayName:h,methodName:S,renderCountProp:O,shouldHandleStateChanges:C,storeKey:N,withRef:D,displayName:a,wrappedComponentName:r,WrappedComponent:n}),p=function(t){function r(e,n){o(this,r);var u=i(this,t.call(this,e,n));return u.version=k,u.state={},u.renderCount=0,u.store=e[N]||n[N],u.propsMode=Boolean(e[N]),u.setWrappedInstance=u.setWrappedInstance.bind(u),(0,y.default)(u.store,'Could not find "'+N+'" in either the context or props of '+('"'+a+'". Either wrap the root component in a , ')+('or explicitly pass "'+N+'" as a prop to "'+a+'".')),u.initSelector(),u.initSubscription(),u}return u(r,t),r.prototype.getChildContext=function(){var t,e=this.propsMode?null:this.subscription;return t={},t[P]=e||this.context[P],t},r.prototype.componentDidMount=function(){C&&(this.subscription.trySubscribe(),this.selector.run(this.props),this.selector.shouldComponentUpdate&&this.forceUpdate())},r.prototype.componentWillReceiveProps=function(t){this.selector.run(t)},r.prototype.shouldComponentUpdate=function(){return this.selector.shouldComponentUpdate},r.prototype.componentWillUnmount=function(){this.subscription&&this.subscription.tryUnsubscribe(),this.subscription=null,this.notifyNestedSubs=s,this.store=null,this.selector.run=s,this.selector.shouldComponentUpdate=!1},r.prototype.getWrappedInstance=function(){return(0,y.default)(D,"To access the wrapped instance, you need to specify "+("{ withRef: true } in the options argument of the "+S+"() call.")),this.wrappedInstance},r.prototype.setWrappedInstance=function(t){this.wrappedInstance=t},r.prototype.initSelector=function(){var t=e(this.store.dispatch,l);this.selector=c(t,this.store),this.selector.run(this.props)},r.prototype.initSubscription=function(){if(C){var t=(this.propsMode?this.props:this.context)[P];this.subscription=new v.default(this.store,t,this.onStateChange.bind(this)),this.notifyNestedSubs=this.subscription.notifyNestedSubs.bind(this.subscription)}},r.prototype.onStateChange=function(){this.selector.run(this.props),this.selector.shouldComponentUpdate?(this.componentDidUpdate=this.notifyNestedSubsOnComponentDidUpdate,this.setState(E)):this.notifyNestedSubs()},r.prototype.notifyNestedSubsOnComponentDidUpdate=function(){this.componentDidUpdate=void 0,this.notifyNestedSubs()},r.prototype.isSubscribed=function(){return Boolean(this.subscription)&&this.subscription.isSubscribed()},r.prototype.addExtraProps=function(t){if(!(D||O||this.propsMode&&this.subscription))return t;var e=f({},t);return D&&(e.ref=this.setWrappedInstance),O&&(e[O]=this.renderCount++),this.propsMode&&this.subscription&&(e[P]=this.subscription),e},r.prototype.render=function(){var t=this.selector;if(t.shouldComponentUpdate=!1,t.error)throw t.error;return(0,_.createElement)(n,this.addExtraProps(t.props))},r}(_.Component);return p.WrappedComponent=n,p.displayName=a,p.childContextTypes=R,p.contextTypes=M,p.propTypes=M,"production"!==t.env.NODE_ENV&&(p.prototype.componentWillUpdate=function(){this.version!==k&&(this.version=k,this.initSelector(),this.subscription&&this.subscription.tryUnsubscribe(),this.initSubscription(),C&&this.subscription.trySubscribe())}),(0,d.default)(p,n)}}e.__esModule=!0;var f=Object.assign||function(t){for(var e=1;e>8-a%1*8)){if(r=i.charCodeAt(a+=.75),r>255)throw new n;e=e<<8|r}return u}var o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";n.prototype=new Error,n.prototype.code=5,n.prototype.name="InvalidCharacterError",t.exports=r},function(t,e,n){"use strict";function r(t){return encodeURIComponent(t).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(9);t.exports=function(t,e,n){if(!e)return t;var i;if(n)i=n(e);else if(o.isURLSearchParams(e))i=e.toString();else{var u=[];o.forEach(e,function(t,e){null!==t&&"undefined"!=typeof t&&(o.isArray(t)&&(e+="[]"),o.isArray(t)||(t=[t]),o.forEach(t,function(t){o.isDate(t)?t=t.toISOString():o.isObject(t)&&(t=JSON.stringify(t)),u.push(r(e)+"="+r(t))}))}),i=u.join("&")}return i&&(t+=(t.indexOf("?")===-1?"?":"&")+i),t}},function(t,e){"use strict";t.exports=function(t,e){return t.replace(/\/+$/,"")+"/"+e.replace(/^\/+/,"")}},function(t,e,n){"use strict";var r=n(9);t.exports=r.isStandardBrowserEnv()?function(){return{write:function(t,e,n,o,i,u){var a=[];a.push(t+"="+encodeURIComponent(e)),r.isNumber(n)&&a.push("expires="+new Date(n).toGMTString()),r.isString(o)&&a.push("path="+o),r.isString(i)&&a.push("domain="+i),u===!0&&a.push("secure"),document.cookie=a.join("; ")},read:function(t){var e=document.cookie.match(new RegExp("(^|;\\s*)("+t+")=([^;]*)"));return e?decodeURIComponent(e[3]):null},remove:function(t){this.write(t,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){} }}()},function(t,e){"use strict";t.exports=function(t){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(t)}},function(t,e,n){"use strict";var r=n(9);t.exports=r.isStandardBrowserEnv()?function(){function t(t){var e=t;return n&&(o.setAttribute("href",e),e=o.href),o.setAttribute("href",e),{href:o.href,protocol:o.protocol?o.protocol.replace(/:$/,""):"",host:o.host,search:o.search?o.search.replace(/^\?/,""):"",hash:o.hash?o.hash.replace(/^#/,""):"",hostname:o.hostname,port:o.port,pathname:"/"===o.pathname.charAt(0)?o.pathname:"/"+o.pathname}}var e,n=/(msie|trident)/i.test(navigator.userAgent),o=document.createElement("a");return e=t(window.location.href),function(n){var o=r.isString(n)?t(n):n;return o.protocol===e.protocol&&o.host===e.host}}():function(){return function(){return!0}}()},function(t,e,n){"use strict";var r=n(9);t.exports=function(t,e){r.forEach(t,function(n,r){r!==e&&r.toUpperCase()===e.toUpperCase()&&(t[e]=n,delete t[r])})}},function(t,e,n){"use strict";var r=n(9);t.exports=function(t){var e,n,o,i={};return t?(r.forEach(t.split("\n"),function(t){o=t.indexOf(":"),e=r.trim(t.substr(0,o)).toLowerCase(),n=r.trim(t.substr(o+1)),e&&(i[e]=i[e]?i[e]+", "+n:n)}),i):i}},function(t,e){"use strict";t.exports=function(t){return function(e){return t.apply(null,e)}}},function(t,e,n){(function(e){"use strict";function r(t){return t}function o(t,n,o){function f(t,n,r){for(var o in n)n.hasOwnProperty(o)&&("production"!==e.env.NODE_ENV?s("function"==typeof n[o],"%s: %s type `%s` is invalid; it must be a function, usually from React.PropTypes.",t.displayName||"ReactClass",c[r],o):void 0)}function p(t,e){var n=S.hasOwnProperty(e)?S[e]:null;T.hasOwnProperty(e)&&a("OVERRIDE_BASE"===n,"ReactClassInterface: You are attempting to override `%s` from your class specification. Ensure that your method names do not overlap with React methods.",e),t&&a("DEFINE_MANY"===n||"DEFINE_MANY_MERGED"===n,"ReactClassInterface: You are attempting to define `%s` on your component more than once. This conflict may be due to a mixin.",e)}function d(t,r){if(r){a("function"!=typeof r,"ReactClass: You're attempting to use a component class or function as a mixin. Instead, just use a regular object."),a(!n(r),"ReactClass: You're attempting to use a component as a mixin. Instead, just use a regular object.");var o=t.prototype,i=o.__reactAutoBindPairs;r.hasOwnProperty(l)&&w.mixins(t,r.mixins);for(var u in r)if(r.hasOwnProperty(u)&&u!==l){var c=r[u],f=o.hasOwnProperty(u);if(p(f,u),w.hasOwnProperty(u))w[u](t,c);else{var d=S.hasOwnProperty(u),h="function"==typeof c,y=h&&!d&&!f&&r.autobind!==!1;if(y)i.push(u,c),o[u]=c;else if(f){var v=S[u];a(d&&("DEFINE_MANY_MERGED"===v||"DEFINE_MANY"===v),"ReactClass: Unexpected spec policy %s for key %s when mixing in component specs.",v,u),"DEFINE_MANY_MERGED"===v?o[u]=_(o[u],c):"DEFINE_MANY"===v&&(o[u]=g(o[u],c))}else o[u]=c,"production"!==e.env.NODE_ENV&&"function"==typeof c&&r.displayName&&(o[u].displayName=r.displayName+"_"+u)}}}else if("production"!==e.env.NODE_ENV){var m=typeof r,b="object"===m&&null!==r;"production"!==e.env.NODE_ENV?s(b,"%s: You're attempting to include a mixin that is either null or not an object. Check the mixins included by the component, as well as any mixins they include themselves. Expected object but got %s.",t.displayName||"ReactClass",null===r?null:m):void 0}}function h(t,e){if(e)for(var n in e){var r=e[n];if(e.hasOwnProperty(n)){var o=n in w;a(!o,'ReactClass: You are attempting to define a reserved property, `%s`, that shouldn\'t be on the "statics" key. Define it as an instance property instead; it will still be accessible on the constructor.',n);var i=n in t;a(!i,"ReactClass: You are attempting to define `%s` on your component more than once. This conflict may be due to a mixin.",n),t[n]=r}}}function y(t,e){a(t&&e&&"object"==typeof t&&"object"==typeof e,"mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.");for(var n in e)e.hasOwnProperty(n)&&(a(void 0===t[n],"mergeIntoWithNoDuplicateKeys(): Tried to merge two objects with the same key: `%s`. This conflict may be due to a mixin; in particular, this may be caused by two getInitialState() or getDefaultProps() methods returning objects with clashing keys.",n),t[n]=e[n]);return t}function _(t,e){return function(){var n=t.apply(this,arguments),r=e.apply(this,arguments);if(null==n)return r;if(null==r)return n;var o={};return y(o,n),y(o,r),o}}function g(t,e){return function(){t.apply(this,arguments),e.apply(this,arguments)}}function v(t,n){var r=n.bind(t);if("production"!==e.env.NODE_ENV){r.__reactBoundContext=t,r.__reactBoundMethod=n,r.__reactBoundArguments=null;var o=t.constructor.displayName,i=r.bind;r.bind=function(u){for(var a=arguments.length,c=Array(a>1?a-1:0),l=1;l0&&"number"!=typeof t[0]))}function i(t,e,n){var i,l;if(r(t)||r(e))return!1;if(t.prototype!==e.prototype)return!1;if(s(t))return!!s(e)&&(t=u.call(t),e=u.call(e),c(t,e,n));if(o(t)){if(!o(e))return!1;if(t.length!==e.length)return!1;for(i=0;i=0;i--)if(f[i]!=p[i])return!1;for(i=f.length-1;i>=0;i--)if(l=f[i],!c(t[l],e[l],n))return!1;return typeof t==typeof e}var u=Array.prototype.slice,a=n(127),s=n(126),c=t.exports=function(t,e,n){return n||(n={}),t===e||(t instanceof Date&&e instanceof Date?t.getTime()===e.getTime():!t||!e||"object"!=typeof t&&"object"!=typeof e?n.strict?t===e:t==e:i(t,e,n))}},function(t,e){function n(t){return"[object Arguments]"==Object.prototype.toString.call(t)}function r(t){return t&&"object"==typeof t&&"number"==typeof t.length&&Object.prototype.hasOwnProperty.call(t,"callee")&&!Object.prototype.propertyIsEnumerable.call(t,"callee")||!1}var o="[object Arguments]"==function(){return Object.prototype.toString.call(arguments)}();e=t.exports=o?n:r,e.supported=n,e.unsupported=r},function(t,e){function n(t){var e=[];for(var n in t)e.push(n);return e}e=t.exports="function"==typeof Object.keys?Object.keys:n,e.shim=n},function(t,e,n){"use strict";var r=n(25),o=n(12),i=n(18),u=n(7),a=n(4),s=(n(26),n(5)),c=n(13),l=n(187),f=s.List,p=s.Repeat,d={insertAtomicBlock:function(t,e,n){var s=t.getCurrentContent(),l=t.getSelection(),d=u.removeRange(s,l,"backward"),h=d.getSelectionAfter(),y=u.splitBlock(d,h),_=y.getSelectionAfter(),g=u.setBlockType(y,_,"atomic"),v=o.create({entity:e}),m=[new i({key:c(),type:"atomic",text:n,characterList:f(p(v,n.length))}),new i({key:c(),type:"unstyled",text:"",characterList:f()})],b=r.createFromArray(m),E=u.replaceWithFragment(g,_,b),S=E.merge({selectionBefore:l,selectionAfter:E.getSelectionAfter().set("hasFocus",!0)});return a.push(t,S,"insert-fragment")},moveAtomicBlock:function(t,e,n,r){var o=t.getCurrentContent(),i=t.getSelection(),s=void 0;if("before"===r||"after"===r){var c=o.getBlockForKey("before"===r?n.getStartKey():n.getEndKey());s=l(o,e,c,r)}else{var f=u.removeRange(o,n,"backward"),p=f.getSelectionAfter(),d=f.getBlockForKey(p.getFocusKey());if(0===p.getStartOffset())s=l(f,e,d,"before");else if(p.getEndOffset()===d.getLength())s=l(f,e,d,"after");else{var h=u.splitBlock(f,p),y=h.getSelectionAfter(),_=h.getBlockForKey(y.getFocusKey());s=l(h,e,_,"before")}}var g=s.merge({selectionBefore:i,selectionAfter:s.getSelectionAfter().set("hasFocus",!0)});return a.push(t,g,"move-block")}};t.exports=d},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e,n){for(var r=e;r0||null!==s;if(p&&t.restoreEditorDOM(),t.exitCurrentMode(),e){var d=r.replaceText(n.getCurrentContent(),n.getSelection(),e,i,s);return void t.update(o.push(n,d,"insert-characters"))}p&&t.update(o.set(n,{nativelyRenderedContent:null,forceSelection:!0}))}}};t.exports=p},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function u(t,e,n,r){return p({"public/DraftStyleDefault/unorderedListItem":"unordered-list-item"===t,"public/DraftStyleDefault/orderedListItem":"ordered-list-item"===t,"public/DraftStyleDefault/reset":n,"public/DraftStyleDefault/depth0":0===e,"public/DraftStyleDefault/depth1":1===e,"public/DraftStyleDefault/depth2":2===e,"public/DraftStyleDefault/depth3":3===e,"public/DraftStyleDefault/depth4":4===e,"public/DraftStyleDefault/listLTR":"LTR"===r,"public/DraftStyleDefault/listRTL":"RTL"===r})}var a=n(17),s=a||function(t){for(var e=1;eb;L=d(L,u(T,j,U,x))}var B=I||c,K={className:L,"data-block":!0,"data-editor":this.props.editorKey,"data-offset-key":P,key:O};void 0!==A&&(K=s({},K,{contentEditable:A,suppressContentEditableWarning:!0}));var H=f.createElement(F,K,f.createElement(B,k));m.push({block:H,wrapperTemplate:R,key:O,offsetKey:P}),b=R?w.getDepth():null,E=R}for(var G=[],z=0;z0){if(t.props.handleDroppedFiles&&d(t.props.handleDroppedFiles(s,c)))return;return void l(c,function(e){e&&t.update(i(a,s,e))})}var f=t._internalDrag?"internal":"external";if(!t.props.handleDrop||!d(t.props.handleDrop(s,n,f)))return t._internalDrag?void t.update(o(a,s)):void t.update(i(a,s,n.getText()))}}};t.exports=h},function(t,e,n){"use strict";var r=n(154),o=n(155),i=n(156),u=n(157),a=n(158),s=n(159),c=n(160),l=n(161),f=n(162),p=n(163),d=n(164),h=n(165),y={onBeforeInput:r,onBlur:o,onCompositionStart:i,onCopy:u,onCut:a,onDragOver:s,onDragStart:c,onFocus:l,onInput:f,onKeyDown:p,onPaste:d,onSelect:h};t.exports=y},function(t,e,n){(function(e){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var u=n(17),a=(n(18),n(139)),s=n(1),c=n(20),l=n(3),f=n(189),p=function(t){function n(){return r(this,n),o(this,t.apply(this,arguments))}return i(n,t),n.prototype._setSelection=function(){var t=this.props.selection;if(null!=t&&t.getHasFocus()){var n=this.props,r=n.block,o=n.start,i=n.text,u=r.getKey(),a=o+i.length;if(t.hasEdgeWithin(u,o,a)){var s=c.findDOMNode(this);s?void 0:"production"!==e.env.NODE_ENV?l(!1,"Missing node"):l(!1);var p=s.firstChild;p?void 0:"production"!==e.env.NODE_ENV?l(!1,"Missing child"):l(!1);var d=void 0;p.nodeType===Node.TEXT_NODE?d=p:"BR"===p.tagName?d=s:(d=p.firstChild,d?void 0:"production"!==e.env.NODE_ENV?l(!1,"Missing targetNode"):l(!1)),f(t,d,u,o,a)}}},n.prototype.shouldComponentUpdate=function(t){var n=c.findDOMNode(this.refs.leaf);return n?void 0:"production"!==e.env.NODE_ENV?l(!1,"Missing leafNode"):l(!1),n.textContent!==t.text||t.styleSet!==this.props.styleSet||t.forceSelection},n.prototype.componentDidUpdate=function(){this._setSelection()},n.prototype.componentDidMount=function(){this._setSelection()},n.prototype.render=function(){var t=this.props.block,e=this.props.text;e.endsWith("\n")&&this.props.isLast&&(e+="\n");var n=this.props,r=n.customStyleMap,o=n.customStyleFn,i=n.offsetKey,c=n.styleSet,l=c.reduce(function(t,e){var n={},o=r[e];return void 0!==o&&t.textDecoration!==o.textDecoration&&(n.textDecoration=[t.textDecoration,o.textDecoration].join(" ").trim()),u(t,o,n)},{});if(o){var f=o(c,t);l=u(l,f)}return s.createElement("span",{"data-offset-key":i,ref:"leaf",style:l},s.createElement(a,null,e))},n}(s.Component);t.exports=p}).call(e,n(2))},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var u=n(1),a=n(28),s=function(t){function e(){return r(this,e),o(this,t.apply(this,arguments))}return i(e,t),e.prototype.shouldComponentUpdate=function(t){return this.props.text!==t.text||this.props.editorState.getSelection().getHasFocus()!==t.editorState.getSelection().getHasFocus()},e.prototype.render=function(){var t=this.props.editorState.getSelection().getHasFocus(),e=a({"public/DraftEditorPlaceholder/root":!0,"public/DraftEditorPlaceholder/hasFocus":t});return u.createElement("div",{className:e},u.createElement("div",{className:a("public/DraftEditorPlaceholder/inner"),id:this.props.accessibilityID},this.props.text))},e}(u.Component);t.exports=s},function(t,e,n){(function(e){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function u(t){return f?"\n"===t.textContent:"BR"===t.tagName}var a=n(1),s=n(20),c=n(15),l=n(3),f=c.isBrowser("IE <= 11"),p=f?a.createElement("span",{key:"A","data-text":"true"},"\n"):a.createElement("br",{key:"A","data-text":"true"}),d=f?a.createElement("span",{key:"B","data-text":"true"},"\n"):a.createElement("br",{key:"B","data-text":"true"}),h=function(t){function n(e){r(this,n);var i=o(this,t.call(this,e));return i._forceFlag=!1,i}return i(n,t),n.prototype.shouldComponentUpdate=function(t){var n=s.findDOMNode(this),r=""===t.children;return n instanceof Element?void 0:"production"!==e.env.NODE_ENV?l(!1,"node is not an Element"):l(!1),r?!u(n):n.textContent!==t.children},n.prototype.componentWillUpdate=function(){this._forceFlag=!this._forceFlag},n.prototype.render=function(){return""===this.props.children?this._forceFlag?p:d:a.createElement("span",{key:this._forceFlag?"A":"B","data-text":"true"},this.props.children)},n}(a.Component);t.exports=h}).call(e,n(2)); },function(t,e){"use strict";var n={getRemovalRange:function(t,e,n,r,o){var i=n.split(" ");i=i.map(function(t,e){if("forward"===o){if(e>0)return" "+t}else if(e0)return null;var a=u.getType(),s=i.getBlockBefore(o);if("code-block"===a&&s&&"code-block"===s.getType())return null;if("unstyled"!==a)return r.setBlockType(i,e,"unstyled")}return null}};t.exports=a},function(t,e,n){"use strict";var r=n(7),o=n(4),i=n(32),u=n(10),a=null,s={cut:function(t){var e=t.getCurrentContent(),n=t.getSelection(),s=null;if(n.isCollapsed()){var c=n.getAnchorKey(),l=e.getBlockForKey(c).getLength();if(l===n.getAnchorOffset())return t;s=n.set("focusOffset",l)}else s=n;s=u(s),a=i(e,s);var f=r.removeRange(e,s,"forward");return f===e?t:o.push(t,f,"remove-range")},paste:function(t){if(!a)return t;var e=r.replaceWithFragment(t.getCurrentContent(),t.getSelection(),a);return o.push(t,e,"insert-fragment")}};t.exports=s},function(t,e){"use strict";function n(t,e,n,r){var o=e.getStartKey(),i=e.getEndKey(),u=t.getBlockMap(),a=u.toSeq().skipUntil(function(t,e){return e===o}).takeUntil(function(t,e){return e===i}).concat([[i,u.get(i)]]).map(function(t){var e=t.getDepth()+n;return e=Math.max(0,Math.min(e,r)),t.set("depth",e)});return u=u.merge(a),t.merge({blockMap:u,selectionBefore:e,selectionAfter:e})}t.exports=n},function(t,e,n){"use strict";function r(t,e,n,r){for(var i=t.getCharacterList();e0){if(t.props.handlePastedFiles&&h(t.props.handlePastedFiles(r)))return;return void d(r,function(e){if(e=e||_){var n=t._latestEditorState,r=y(e),o=a.create({style:n.getCurrentInlineStyle(),entity:p(n.getCurrentContent(),n.getSelection())}),i=l.processText(r,o),s=u.createFromArray(i),d=c.replaceWithFragment(n.getCurrentContent(),n.getSelection(),s);t.update(f.push(n,d,"insert-fragment"))}})}}var g=[],v=n.getText(),m=n.getHTML(),b=t._latestEditorState;if(!t.props.handlePastedText||!h(t.props.handlePastedText(v,m,b))){if(v&&(g=y(v)),!t.props.stripPastedStyles){var E=t.getClipboard();if(n.isRichText()&&E){if(m.indexOf(t.getEditorKey())!==-1||1===g.length&&1===E.size&&E.first().getText()===v)return void t.update(o(t._latestEditorState,E))}else if(E&&n.types.includes("com.apple.webarchive")&&!n.types.includes("text/html")&&i(g,E))return void t.update(o(t._latestEditorState,E));if(m){var S=l.processHTML(m,t.props.blockRenderMap);if(S){var w=S.contentBlocks,O=S.entityMap;if(w){var T=u.createFromArray(w);return void t.update(o(t._latestEditorState,T,O))}}}t.setClipboard(null)}if(g.length){var C=a.create({style:b.getCurrentInlineStyle(),entity:p(b.getCurrentContent(),b.getSelection())}),I=l.processText(g,C),N=u.createFromArray(I);t.update(o(t._latestEditorState,N))}}}function o(t,e,n){var r=c.replaceWithFragment(t.getCurrentContent(),t.getSelection(),e);return f.push(t,r.set("entityMap",n),"insert-fragment")}function i(t,e){return t.length===e.size&&e.valueSeq().every(function(e,n){return e.getText()===t[n]})}var u=n(25),a=n(12),s=n(81),c=n(7),l=n(142),f=n(4),p=n(43),d=n(75),h=n(33),y=n(191);t.exports=r},function(t,e,n){(function(e){"use strict";function r(t){if(!t._blockSelectEvents&&t._latestEditorState===t.props.editorState){var n=t.props.editorState,r=i.findDOMNode(t.refs.editorContainer);r?void 0:"production"!==e.env.NODE_ENV?a(!1,"Missing editorNode"):a(!1),r.firstChild instanceof HTMLElement?void 0:"production"!==e.env.NODE_ENV?a(!1,"editorNode.firstChild is not an HTMLElement"):a(!1);var s=u(n,r.firstChild),c=s.selectionState;c!==n.getSelection()&&(n=s.needsRecovery?o.forceSelection(n,c):o.acceptSelection(n,c),t.update(n))}}var o=n(4),i=n(20),u=n(170),a=n(3);t.exports=r}).call(e,n(2))},function(t,e,n){"use strict";function r(t,e){var n=[];return t.findEntityRanges(function(t){return!!t.getEntity()},function(r,i){var a=t.getText(),s=t.getEntityAt(r);n.push({offset:u(a.slice(0,r)),length:u(a.slice(r,i)),key:Number(e[o.stringify(s)])})}),n}var o=n(67),i=n(19),u=i.strlen;t.exports=r},function(t,e,n){"use strict";function r(t,e,n){var r=[],o=e.map(function(t){return t.has(n)}).toList();return u(o,a,s,function(e,o){var u=t.getText();r.push({offset:i.strlen(u.slice(0,e)),length:i.strlen(u.slice(e,o)),style:n})}),r}function o(t){var e=t.getCharacterList().map(function(t){return t.getStyle()}).toList(),n=e.flatten().toSet().map(function(n){return r(t,e,n)});return Array.prototype.concat.apply(c,n.toJS())}var i=n(19),u=n(31),a=function(t,e){return t===e},s=function(t){return!!t},c=[];t.exports=o},function(t,e,n){(function(e){"use strict";function r(t){var n=getComputedStyle(t),r=document.createElement("div");r.style.fontFamily=n.fontFamily,r.style.fontSize=n.fontSize,r.style.fontStyle=n.fontStyle,r.style.fontWeight=n.fontWeight,r.style.lineHeight=n.lineHeight,r.style.position="absolute",r.textContent="M";var o=document.body;o?void 0:"production"!==e.env.NODE_ENV?c(!1,"Missing document.body"):c(!1),o.appendChild(r);var i=r.getBoundingClientRect();return o.removeChild(r),i.height}function o(t,e){for(var n=1/0,r=1/0,o=-(1/0),i=-(1/0),u=0;u=0;y--)if(!(null!=h&&y>0&&a.isSurrogatePair(h,y-1))){if(t.setStart(p,y),!o(s(t),u))break;l=p,f=y}if(y===-1||0===p.childNodes.length)break;p=p.childNodes[y],d=i(p)}return t.setStart(l,f),t}var a=n(19),s=n(72),c=n(3);t.exports=u}).call(e,n(2))},function(t,e,n){(function(e){"use strict";function r(t,e,n,r,i){var u=r.getStartOffset(),a=r.getEndOffset(),s=e.getEntityAt(u),c=n.getEntityAt(a-1);if(!s&&!c)return r;var l=r;if(s&&s===c)l=o(t,e,l,i,s,!0,!0);else if(s&&c){var f=o(t,e,l,i,s,!1,!0),p=o(t,n,l,i,c,!1,!1);l=l.merge({anchorOffset:f.getAnchorOffset(),focusOffset:p.getFocusOffset(),isBackward:!1})}else if(s){var d=o(t,e,l,i,s,!1,!0);l=l.merge({anchorOffset:d.getStartOffset(),isBackward:!1})}else if(c){var h=o(t,n,l,i,c,!1,!1);l=l.merge({focusOffset:h.getEndOffset(),isBackward:!1})}return l}function o(t,n,r,o,s,c,l){var f=r.getStartOffset(),p=r.getEndOffset(),d=t.__get(s),h=d.getMutability(),y=l?f:p;if("MUTABLE"===h)return r;var _=u(n,s).filter(function(t){return y<=t.end&&y>=t.start});1!=_.length?"production"!==e.env.NODE_ENV?a(!1,"There should only be one entity range within this removal range."):a(!1):void 0;var g=_[0];if("IMMUTABLE"===h)return r.merge({anchorOffset:g.start,focusOffset:g.end,isBackward:!1});c||(l?p=g.end:f=g.start);var v=i.getRemovalRange(f,p,n.getText().slice(g.start,g.end),g.start,o);return r.merge({anchorOffset:v.start,focusOffset:v.end,isBackward:!1})}var i=n(140),u=n(172),a=n(3);t.exports=r}).call(e,n(2))},function(t,e,n){(function(e){"use strict";function r(t,n){var r=e.getSelection();return 0===r.rangeCount?{selectionState:t.getSelection().set("hasFocus",!1),needsRecovery:!1}:o(t,n,r.anchorNode,r.anchorOffset,r.focusNode,r.focusOffset)}var o=n(70);t.exports=r}).call(e,function(){return this}())},function(t,e,n){"use strict";function r(t){var e=o(t),n=0,r=0,i=0,u=0;if(e.length){if(e.length>1&&0===e[0].width){var a=e[1];n=a.top,r=a.right,i=a.bottom,u=a.left}else{var s=e[0];n=s.top,r=s.right,i=s.bottom,u=s.left}for(var c=1;ce;)t=t.pop(),n--;else{var r=t.slice(0,e),o=t.slice(n);t=r.concat(o).toList()}return t}var i=n(5);t.exports=r},function(t,e,n){(function(e,r){"use strict";function o(t){if(!t)return"[empty]";var n=i(t);return n.nodeType===Node.TEXT_NODE?n.textContent:(n instanceof Element?void 0:"production"!==e.env.NODE_ENV?h(!1,"Node must be an Element if it is not a text node."):h(!1),n.innerHTML)}function i(t){if(t.nodeType===Node.TEXT_NODE){var e=t.textContent.length;return document.createTextNode("[text "+e+"]")}for(var n=t.cloneNode(),r=t.childNodes,o=0;o=s,v=f===n&&o<=d&&i>=d;if(g&&v)return u.removeAllRanges(),l(u,e,s-o,t),void c(u,e,d-o,t);if(h){if(v&&(u.removeAllRanges(),l(u,e,d-o,t)),g){var m=u.focusNode,b=u.focusOffset;u.removeAllRanges(),l(u,e,s-o,t),c(u,m,b,t)}}else g&&(u.removeAllRanges(),l(u,e,s-o,t)),v&&c(u,e,d-o,t)}}function c(t,e,n,r){if(t.extend&&p(d(),e))n>a(e)&&f.logSelectionStateFailure({anonymizedDom:u(e),extraParams:JSON.stringify({offset:n}),selectionState:JSON.stringify(r.toJS()) }),t.extend(e,n);else{var o=t.getRangeAt(0);o.setEnd(e,n),t.addRange(o.cloneRange())}}function l(t,e,n,r){var o=document.createRange();n>a(e)&&f.logSelectionStateFailure({anonymizedDom:u(e),extraParams:JSON.stringify({offset:n}),selectionState:JSON.stringify(r.toJS())}),o.setStart(e,n),t.addRange(o)}var f=n(141),p=n(84),d=n(85),h=n(3);t.exports=s}).call(e,n(2),function(){return this}())},function(t,e,n){(function(e){"use strict";function r(t,n){n.isCollapsed()?void 0:"production"!==e.env.NODE_ENV?u(!1,"Selection range must be collapsed."):u(!1);var r=n.getAnchorKey(),o=n.getAnchorOffset(),s=t.getBlockMap(),c=s.get(r),l=c.getText(),f=c.getCharacterList(),p=c.merge({text:l.slice(0,o),characterList:f.slice(0,o)}),d=i(),h=p.merge({key:d,text:l.slice(o),characterList:f.slice(o),data:a()}),y=s.toSeq().takeUntil(function(t){return t===c}),_=s.toSeq().skipUntil(function(t){return t===c}).rest(),g=y.concat([[p.getKey(),p],[h.getKey(),h]],_).toOrderedMap();return t.merge({blockMap:g,selectionBefore:n,selectionAfter:n.merge({anchorKey:d,anchorOffset:0,focusKey:d,focusOffset:0,isBackward:!1})})}var o=n(5),i=n(13),u=n(3),a=o.Map;t.exports=r}).call(e,n(2))},function(t,e){"use strict";function n(t){return t.split(r)}var r=/\r\n?|\n/g;t.exports=n},function(t,e,n){var r;/*! Copyright (c) 2015 Jed Watson. Based on code that is Copyright 2013-2015, Facebook, Inc. All rights reserved. */ !function(){"use strict";var o=!("undefined"==typeof window||!window.document||!window.document.createElement),i={canUseDOM:o,canUseWorkers:"undefined"!=typeof Worker,canUseEventListeners:o&&!(!window.addEventListener&&!window.attachEvent),canUseViewport:o&&!!window.screen};r=function(){return i}.call(e,n,e,t),!(void 0!==r&&(t.exports=r))}()},function(t,e){t.exports={borderColor:"#e8e8e8",secondaryFontColor:"#999",primaryFontColor:"#000",buttonDefaults:"styles__buttonDefaults___3oGQ3",default:"styles__default___2g5MD",outline:"styles__outline___1lCxC",fullWidth:"styles__fullWidth___2am33",noUppercase:"styles__noUppercase___1oklF",alwaysActive:"styles__alwaysActive___xpIKs"}},function(t,e){t.exports={primaryFontColor:"#000",secondaryFontColor:"#999",borderColor:"#e8e8e8",smallBP:"(max-width: 768px)",container:"styles__container___9e-CF",count:"styles__count___1Hz84",label:"styles__label___wruYF"}},function(t,e){t.exports={primaryFontColor:"#000",secondaryFontColor:"#999",borderColor:"#e8e8e8",smallBP:"(max-width: 768px)",container:"styles__container___27hQe",title:"styles__title___i6J36",forumsContainer:"styles__forumsContainer___25k9j",forum:"styles__forum___3irCC",forumTitle:"styles__forumTitle___2uLm8",forumSlug:"styles__forumSlug___UKlk6",createForumContainer:"styles__createForumContainer___23xVV",createTitle:"styles__createTitle___3QiXx",createForum:"styles__createForum___3sXG5",createInputContainer:"styles__createInputContainer___3iDOy",inputLabel:"styles__inputLabel___FvpWO",createInput:"styles__createInput___3-KLM",errorMsg:"styles__errorMsg___33m3k",loadingMsg:"styles__loadingMsg___2D258"}},function(t,e){t.exports={primaryFontColor:"#000",secondaryFontColor:"#999",borderColor:"#e8e8e8",backShade:"#f9f9f9",smallBP:"(max-width: 768px)",container:"styles__container___NQp7m",title:"styles__title___ndZKE",titleBottomMargin:"styles__titleBottomMargin___2vh27",posterInfo:"styles__posterInfo___2ZXs_",name:"styles__name___2gQp6",gitHandler:"styles__gitHandler___2iekf",gitIcon:"styles__gitIcon___114uy",boxFooter:"styles__boxFooter___2J-V6",tagsArea:"styles__tagsArea___1iHnX",postInfo:"styles__postInfo___mIXO-",info:"styles__info___2qtij"}},function(t,e){t.exports={borderColor:"#e8e8e8",backShade:"#f9f9f9",secondaryFontColor:"#999",primaryFontColor:"#000",container:"styles__container___2Zc9g",header:"styles__header___2QRy3",title:"styles__title___1C1s4",sortList:"styles__sortList___34ysa",sort:"styles__sort___x6iwf",sortActive:"styles__sortActive___1jxqE",posts:"styles__posts___2dUQ8",loading:"styles__loading___W47Qm"}},function(t,e){t.exports={smallBP:"(max-width: 768px)",mediumBP:"(min-width: 769px) and (max-width: 1099px)",largeBP:"(min-width: 1100px)",contentArea:"styles__contentArea___WZYS4"}},function(t,e){t.exports={logoContainer:"styles__logoContainer___cfrEN",logo:"styles__logo___NxPQF",logoTitle:"styles__logoTitle___x3mHL"}},function(t,e){t.exports={primaryFontColor:"#000",secondaryFontColor:"#999",borderColor:"#e8e8e8",smallBP:"(max-width: 768px)",navigationBar:"styles__navigationBar___KeAy9",links:"styles__links___1xyDG",linkActive:"styles__linkActive___2Y2ja"}},function(t,e){t.exports={primaryFontColor:"#000",secondaryFontColor:"#999",borderColor:"#e8e8e8",smallBP:"(max-width: 768px)",mediumBP:"(min-width: 769px) and (max-width: 1099px)",largeBP:"(min-width: 1100px)",container:"styles__container___2G0s1",userAvatar:"styles__userAvatar___2x2U9",title:"styles__title___3YZUE",signInLink:"styles__signInLink___3ZKxV",signInBtn:"styles__signInBtn___1BFGn",subMenu:"styles__subMenu___1JknN",subMenuItem:"styles__subMenuItem___1KmrY",subMenuClose:"styles__subMenuClose____N_WK",gitLoginBtn:"styles__gitLoginBtn___3NFM7",subMenuOcto:"styles__subMenuOcto___LP6hs"}},function(t,e){t.exports={primaryFontColor:"#000",secondaryFontColor:"#999",borderColor:"#e8e8e8",smallBP:"(max-width: 768px)",container:"styles__container___6rE5a",label:"styles__label___16pu4",btnContainer:"styles__btnContainer___1AKy9",button:"styles__button___2WL76"}},function(t,e){t.exports={primaryFontColor:"#000",secondaryFontColor:"#999",borderColor:"#e8e8e8",smallBP:"(max-width: 768px)",container:"styles__container___NvgJU",tagContainer:"styles__tagContainer___3loPa",label:"styles__label___33VaT",inputContainer:"styles__inputContainer___2CRQc",tagInput:"styles__tagInput___DdDal",addButton:"styles__addButton___1AQ5e",errorMsg:"styles__errorMsg___1PUBU"}},function(t,e){t.exports={smallBP:"(max-width: 768px)",mediumBP:"(min-width: 769px) and (max-width: 1099px)",largeBP:"(min-width: 1100px)",sidebarContainer:"styles__sidebarContainer___HAOwb"}},function(t,e){t.exports={borderColor:"#e8e8e8",secondaryFontColor:"#999",primaryFontColor:"#000",smallBP:"(max-width: 768px)",container:"styles__container___3ag3D",infoContainer:"styles__infoContainer___1tSHN",avatar:"styles__avatar___376XZ",columnOnSmallBP:"styles__columnOnSmallBP___3xMyn",userInfo:"styles__userInfo___1s-_s",name:"styles__name___131nz",gitHandler:"styles__gitHandler___3YZ6H",gitIcon:"styles__gitIcon___1gL9A",dateInfo:"styles__dateInfo___29yAX",discTitle:"styles__discTitle___7Xb4z",discContent:"styles__discContent___atQHi",discFooter:"styles__discFooter___1m4IN",tags:"styles__tags___2sgC-",favoriteButton:"styles__favoriteButton___1fys7",deleteButton:"styles__deleteButton___3Fuge",deletingDiscussion:"styles__deletingDiscussion___31KKR"}},function(t,e){t.exports={borderColor:"#e8e8e8",secondaryFontColor:"#999",primaryFontColor:"#000",smallBP:"(max-width: 768px)",container:"styles__container___rYBS1",deletingOpinion:"styles__deletingOpinion___3OvgA",infoContainer:"styles__infoContainer___11miR",avatar:"styles__avatar___2t9RT",userInfo:"styles__userInfo___1WfED",name:"styles__name___1pyUc",gitHandler:"styles__gitHandler___2NsxB",gitIcon:"styles__gitIcon___1jwLm",dateInfo:"styles__dateInfo___1sNRb",deleteButton:"styles__deleteButton___7DU3C",trashIcon:"styles__trashIcon___10LOT",opContent:"styles__opContent___3uhOR",commentFooter:"styles__commentFooter___jLIS_",favoriteButton:"styles__favoriteButton___1p64L"}},function(t,e){t.exports={primaryFontColor:"#000",secondaryFontColor:"#999",loadingWrapper:"styles__loadingWrapper___wu9So"}},function(t,e){t.exports={secondaryFontColor:"#999",backShade:"#f9f9f9",tag:"styles__tag___2zdjL",tagWithRemove:"styles__tagWithRemove___23VDZ",removeButton:"styles__removeButton___16ijs"}},function(t,e){t.exports={primaryFontColor:"#000",secondaryFontColor:"#999",container:"styles__container___2Pi24",avatarContainer:"styles__avatarContainer___37DQE",avatar:"styles__avatar___16Tnl",infoContainer:"styles__infoContainer___igQvO",name:"styles__name___3fv6x",gitHandler:"styles__gitHandler____b2zz",location:"styles__location___26u56"}},function(t,e){t.exports={smallBP:"(max-width: 768px)",headerTop:"styles__headerTop___3bbXK"}},function(t,e){t.exports={smallBP:"(max-width: 768px)",headerTop:"styles__headerTop___CXJuh"}},function(t,e){t.exports={smallBP:"(max-width: 768px)",container:"styles__container___hbucR",countsContainer:"styles__countsContainer___2lFrb",loadingMsg:"styles__loadingMsg___eZLyT",errorMsg:"styles__errorMsg___26G-n"}},function(t,e){t.exports={largeBP:"(min-width: 1100px)",contentArea:"styles__contentArea___Vl0kO",newDiscussionBtn:"styles__newDiscussionBtn___3kHGs",errorMsg:"styles__errorMsg___3Nrkg"}},function(t,e){t.exports={largeBP:"(min-width: 1100px)",borderColor:"#e8e8e8",secondaryFontColor:"#999",content:"styles__content___3IxIG",forumName:"styles__forumName___2ba7X",errorMsg:"styles__errorMsg___2JPWM",fatalError:"styles__fatalError___2LDsp",titleInput:"styles__titleInput___2t3D2",signInMsg:"styles__signInMsg___1bvy8",postingMsg:"styles__postingMsg___ClCfQ"}},function(t,e){t.exports={primaryFontColor:"#000",secondaryFontColor:"#999",loadingWrapper:"styles__loadingWrapper___3BujS",errorMsg:"styles__errorMsg___vja8k",signInMsg:"styles__signInMsg___PeG2-"}},function(t,e){t.exports={largeBP:"(min-width: 1100px)",container:"styles__container___DqS3K",loadingMsg:"styles__loadingMsg___27gCw",errorMsg:"styles__errorMsg___D92D_"}},function(t,e){"use strict";function n(t){return t.split("/")}var r={isImage:function(t){return"image"===n(t)[0]},isJpeg:function(t){var e=n(t);return r.isImage(t)&&("jpeg"===e[1]||"pjpeg"===e[1])}};t.exports=r},function(t,e){"use strict";var n="[.,+*?$|#{}()'\\^\\-\\[\\]\\\\\\/!@%\"~=<>_:;・、。〈-】〔-〟:-?!-/[-`{-・⸮؟٪-٬؛،؍﴾﴿᠁।၊။‐-‧‰-⁞¡-±´-¸º»¿]";t.exports={getPunctuation:function(){return n}}},function(t,e){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(e){n(this,t),this._uri=e}return t.prototype.toString=function(){return this._uri},t}();t.exports=r},function(t,e,n){(function(e){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var o=n(83),i=n(49),u=n(3),a=function(){function t(n){r(this,t),n?i.isStrong(n)?void 0:"production"!==e.env.NODE_ENV?u(!1,"Default direction must be a strong direction (LTR or RTL)"):u(!1):n=i.getGlobalDir(),this._defaultDir=n,this.reset()}return t.prototype.reset=function(){this._lastDir=this._defaultDir},t.prototype.getDirection=function(t){return this._lastDir=o.getDirection(t,this._lastDir),this._lastDir},t}();t.exports=a}).call(e,n(2))},function(t,e,n){"use strict";function r(t){return a[t]||t}function o(t){if(!t)return{major:"",minor:""};var e=t.split(".");return{major:e[0],minor:e[1]}}var i=n(309),u="Unknown",a={"Mac OS":"Mac OS X"},s=new i,c=s.getResult(),l=o(c.browser.version),f={browserArchitecture:c.cpu.architecture||u,browserFullVersion:c.browser.version||u,browserMinorVersion:l.minor||u,browserName:c.browser.name||u,browserVersion:c.browser.major||u,deviceName:c.device.model||u,engineName:c.engine.name||u,engineVersion:c.engine.version||u,platformArchitecture:c.cpu.architecture||u,platformName:r(c.os.name)||u,platformVersion:c.os.version||u,platformFullVersion:c.os.version||u};t.exports=f},function(t,e,n){(function(e){"use strict";function r(t,e){var n=t.split(S);return n.length>1?n.some(function(t){return C.contains(t,e)}):(t=n[0].trim(),o(t,e))}function o(t,n){var r=t.split(w);if(r.length>0&&r.length<=2?void 0:"production"!==e.env.NODE_ENV?b(!1,'the "-" operator expects exactly 2 operands'):b(!1),1===r.length)return i(r[0],n);var o=r[0],u=r[1];return h(o)&&h(u)?void 0:"production"!==e.env.NODE_ENV?b(!1,'operands to the "-" operator must be simple (no modifiers)'):b(!1),i(">="+o,n)&&i("<="+u,n)}function i(t,e){if(t=t.trim(),""===t)return!0;var n=e.split(E),r=p(t),o=r.modifier,i=r.rangeComponents;switch(o){case"<":return u(n,i);case"<=":return a(n,i);case">=":return c(n,i);case">":return l(n,i);case"~":case"~>":return f(n,i);default:return s(n,i)}}function u(t,e){return m(t,e)===-1}function a(t,e){var n=m(t,e);return n===-1||0===n}function s(t,e){return 0===m(t,e)}function c(t,e){var n=m(t,e);return 1===n||0===n}function l(t,e){return 1===m(t,e)}function f(t,e){var n=e.slice(),r=e.slice();r.length>1&&r.pop();var o=r.length-1,i=parseInt(r[o],10);return d(i)&&(r[o]=i+1+""),c(t,n)&&u(t,r)}function p(t){var n=t.split(E),r=n[0].match(O);return r?void 0:"production"!==e.env.NODE_ENV?b(!1,"expected regex to match but it did not"):b(!1),{modifier:r[1],rangeComponents:[r[2]].concat(n.slice(1))}}function d(t){return!isNaN(t)&&isFinite(t)}function h(t){return!p(t).modifier}function y(t,e){for(var n=t.length;nn?1:t=|~>|~|>|)?\s*(.+)/,T=/^(\d*)(.*)/,C={contains:function(t,e){return r(t.trim(),e.trim())}};t.exports=C}).call(e,n(2))},function(t,e){"use strict";function n(t){return t.replace(r,function(t,e){return e.toUpperCase()})}var r=/-(.)/g;t.exports=n},function(t,e,n){(function(e){"use strict";function r(t){var n=t.length;if(Array.isArray(t)||"object"!=typeof t&&"function"!=typeof t?"production"!==e.env.NODE_ENV?u(!1,"toArray: Array-like object expected"):u(!1):void 0,"number"!=typeof n?"production"!==e.env.NODE_ENV?u(!1,"toArray: Object needs a length property"):u(!1):void 0,0===n||n-1 in t?void 0:"production"!==e.env.NODE_ENV?u(!1,"toArray: Object should have keys for indices"):u(!1),"function"==typeof t.callee?"production"!==e.env.NODE_ENV?u(!1,"toArray: Object can't be `arguments`. Use rest params (function(...args) {}) or Array.from() instead."):u(!1):void 0,t.hasOwnProperty)try{return Array.prototype.slice.call(t)}catch(t){}for(var r=Array(n),o=0;o-1;t.exports=n},function(t,e,n){"use strict";function r(t){var e=o(t);return{x:e.left,y:e.top,width:e.right-e.left,height:e.bottom-e.top}}var o=n(228);t.exports=r},function(t,e,n){"use strict";function r(t){var e=t.ownerDocument.documentElement;if(!("getBoundingClientRect"in t&&o(e,t)))return{left:0,right:0,top:0,bottom:0};var n=t.getBoundingClientRect();return{left:Math.round(n.left)-e.clientLeft,right:Math.round(n.right)-e.clientLeft,top:Math.round(n.top)-e.clientTop,bottom:Math.round(n.bottom)-e.clientTop}}var o=n(84);t.exports=r},function(t,e,n){"use strict";function r(t){return null==t?t:String(t)}function o(t,e){var n=void 0;if(window.getComputedStyle&&(n=window.getComputedStyle(t,null)))return r(n.getPropertyValue(u(e)));if(document.defaultView&&document.defaultView.getComputedStyle){if(n=document.defaultView.getComputedStyle(t,null))return r(n.getPropertyValue(u(e)));if("display"===e)return"none"}return r(t.currentStyle?"float"===e?t.currentStyle.cssFloat||t.currentStyle.styleFloat:t.currentStyle[i(e)]:t.style&&t.style[i(e)])}var i=n(223),u=n(232);t.exports=o},function(t,e){"use strict";function n(t){return t.Window&&t instanceof t.Window?{x:t.pageXOffset||t.document.documentElement.scrollLeft,y:t.pageYOffset||t.document.documentElement.scrollTop}:{x:t.scrollLeft,y:t.scrollTop}}t.exports=n},function(t,e){"use strict";function n(){var t=void 0;return document.documentElement&&(t=document.documentElement.clientWidth),!t&&document.body&&(t=document.body.clientWidth),t||0}function r(){var t=void 0;return document.documentElement&&(t=document.documentElement.clientHeight),!t&&document.body&&(t=document.body.clientHeight),t||0}function o(){return{width:window.innerWidth||n(),height:window.innerHeight||r()}}o.withoutScrollbars=function(){return{width:n(),height:r()}},t.exports=o},function(t,e){"use strict";function n(t){return t.replace(r,"-$1").toLowerCase()}var r=/([A-Z])/g;t.exports=n},function(t,e){"use strict";function n(t){var e=t?t.ownerDocument||t:document,n=e.defaultView||window;return!(!t||!("function"==typeof n.Node?t instanceof n.Node:"object"==typeof t&&"number"==typeof t.nodeType&&"string"==typeof t.nodeName))}t.exports=n},function(t,e,n){"use strict";function r(t){return o(t)&&3==t.nodeType}var o=n(233);t.exports=r},function(t,e){"use strict";function n(t){t||(t="");var e=void 0,n=arguments.length;if(n>1)for(var r=1;r1&&void 0!==arguments[1])||arguments[1];return e===!1?String(t):String(t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")},p=function(t){var e=g(t,l.TAG_NAMES.TITLE),n=g(t,l.HELMET_PROPS.TITLE_TEMPLATE);if(n&&e)return n.replace(/%s/g,function(){return e});var r=g(t,l.HELMET_PROPS.DEFAULT_TITLE);return e||r||void 0},d=function(t){return g(t,l.HELMET_PROPS.ON_CHANGE_CLIENT_STATE)||function(){}},h=function(t,e){return e.filter(function(e){return"undefined"!=typeof e[t]}).map(function(e){return e[t]}).reduce(function(t,e){return i({},t,e)},{})},y=function(t,e){return e.filter(function(t){return"undefined"!=typeof t[l.TAG_NAMES.BASE]}).map(function(t){return t[l.TAG_NAMES.BASE]}).reverse().reduce(function(e,n){if(!e.length)for(var r=Object.keys(n),o=0;o=0;n--){var r=t[n];if(r.hasOwnProperty(e))return r[e]}return null},v=function(t){return{baseTag:y([l.TAG_PROPERTIES.HREF],t),bodyAttributes:h(l.ATTRIBUTE_NAMES.BODY,t),encode:g(t,l.HELMET_PROPS.ENCODE_SPECIAL_CHARACTERS),htmlAttributes:h(l.ATTRIBUTE_NAMES.HTML,t),linkTags:_(l.TAG_NAMES.LINK,[l.TAG_PROPERTIES.REL,l.TAG_PROPERTIES.HREF],t),metaTags:_(l.TAG_NAMES.META,[l.TAG_PROPERTIES.NAME,l.TAG_PROPERTIES.CHARSET,l.TAG_PROPERTIES.HTTPEQUIV,l.TAG_PROPERTIES.PROPERTY,l.TAG_PROPERTIES.ITEM_PROP],t),noscriptTags:_(l.TAG_NAMES.NOSCRIPT,[l.TAG_PROPERTIES.INNER_HTML],t),onChangeClientState:d(t),scriptTags:_(l.TAG_NAMES.SCRIPT,[l.TAG_PROPERTIES.SRC,l.TAG_PROPERTIES.INNER_HTML],t),styleTags:_(l.TAG_NAMES.STYLE,[l.TAG_PROPERTIES.CSS_TEXT],t),title:p(t),titleAttributes:h(l.ATTRIBUTE_NAMES.TITLE,t)}},m=function(){return"undefined"!=typeof window&&"undefined"!=typeof window.requestIdleCallback?window.requestIdleCallback:function(t){var e=Date.now();return setTimeout(function(){t({didTimeout:!1,timeRemaining:function(){return Math.max(0,50-(Date.now()-e))}})},1)}}(),b=function(){return"undefined"!=typeof window&&"undefined"!=typeof window.cancelIdleCallback?window.cancelIdleCallback:function(t){return clearTimeout(t)}}(),E=function(t){return console&&"function"==typeof console.warn&&console.warn(t)},S=null,w=function(t){var e=t.baseTag,n=t.bodyAttributes,r=t.htmlAttributes,o=t.linkTags,i=t.metaTags,u=t.noscriptTags,a=t.onChangeClientState,s=t.scriptTags,c=t.styleTags,f=t.title,p=t.titleAttributes;S&&b(S),S=m(function(){T(l.TAG_NAMES.BODY,n),T(l.TAG_NAMES.HTML,r),O(f,p);var d={baseTag:C(l.TAG_NAMES.BASE,e),linkTags:C(l.TAG_NAMES.LINK,o),metaTags:C(l.TAG_NAMES.META,i),noscriptTags:C(l.TAG_NAMES.NOSCRIPT,u),scriptTags:C(l.TAG_NAMES.SCRIPT,s),styleTags:C(l.TAG_NAMES.STYLE,c)},h={},y={};Object.keys(d).forEach(function(t){var e=d[t],n=e.newTags,r=e.oldTags;n.length&&(h[t]=n),r.length&&(y[t]=d[t].oldTags)}),S=null,a(t,h,y)})},O=function(t,e){"undefined"!=typeof t&&document.title!==t&&(document.title=Array.isArray(t)?t.join(""):t),T(l.TAG_NAMES.TITLE,e)},T=function(t,e){var n=document.getElementsByTagName(t)[0];if(n){for(var r=n.getAttribute(l.HELMET_ATTRIBUTE),o=r?r.split(","):[],i=[].concat(o),u=Object.keys(e),a=0;a=0;p--)n.removeAttribute(i[p]);o.length===i.length?n.removeAttribute(l.HELMET_ATTRIBUTE):n.getAttribute(l.HELMET_ATTRIBUTE)!==u.join(",")&&n.setAttribute(l.HELMET_ATTRIBUTE,u.join(","))}},C=function(t,e){var n=document.head||document.querySelector(l.TAG_NAMES.HEAD),r=n.querySelectorAll(t+"["+l.HELMET_ATTRIBUTE+"]"),o=Array.prototype.slice.call(r),i=[],u=void 0;return e&&e.length&&e.forEach(function(e){var n=document.createElement(t);for(var r in e)if(e.hasOwnProperty(r))if(r===l.TAG_PROPERTIES.INNER_HTML)n.innerHTML=e.innerHTML;else if(r===l.TAG_PROPERTIES.CSS_TEXT)n.styleSheet?n.styleSheet.cssText=e.cssText:n.appendChild(document.createTextNode(e.cssText));else{var a="undefined"==typeof e[r]?"":e[r];n.setAttribute(r,a)}n.setAttribute(l.HELMET_ATTRIBUTE,"true"),o.some(function(t,e){return u=e,n.isEqualNode(t)})?o.splice(u,1):i.push(n)}),o.forEach(function(t){return t.parentNode.removeChild(t)}),i.forEach(function(t){return n.appendChild(t)}),{oldTags:o,newTags:i}},I=function(t){return Object.keys(t).reduce(function(e,n){var r="undefined"!=typeof t[n]?n+'="'+t[n]+'"':""+n;return e?e+" "+r:r},"")},N=function(t,e,n,r){var o=I(n);return o?"<"+t+" "+l.HELMET_ATTRIBUTE+'="true" '+o+">"+f(e,r)+"":"<"+t+" "+l.HELMET_ATTRIBUTE+'="true">'+f(e,r)+""; },A=function(t,e,n){return e.reduce(function(e,r){var o=Object.keys(r).filter(function(t){return!(t===l.TAG_PROPERTIES.INNER_HTML||t===l.TAG_PROPERTIES.CSS_TEXT)}).reduce(function(t,e){var o="undefined"==typeof r[e]?e:e+'="'+f(r[e],n)+'"';return t?t+" "+o:o},""),i=r.innerHTML||r.cssText||"",u=l.SELF_CLOSING_TAGS.indexOf(t)===-1;return e+"<"+t+" "+l.HELMET_ATTRIBUTE+'="true" '+o+(u?"/>":">"+i+"")},"")},D=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return Object.keys(t).reduce(function(e,n){return e[l.REACT_TAG_MAP[n]||n]=t[n],e},e)},x=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return Object.keys(t).reduce(function(e,n){return e[l.HTML_TAG_MAP[n]||n]=t[n],e},e)},P=function(t,e,n){var r,o=(r={key:e},r[l.HELMET_ATTRIBUTE]=!0,r),i=D(n,o);return[a.default.createElement(l.TAG_NAMES.TITLE,i,e)]},k=function(t,e){return e.map(function(e,n){var r,o=(r={key:n},r[l.HELMET_ATTRIBUTE]=!0,r);return Object.keys(e).forEach(function(t){var n=l.REACT_TAG_MAP[t]||t;if(n===l.TAG_PROPERTIES.INNER_HTML||n===l.TAG_PROPERTIES.CSS_TEXT){var r=e.innerHTML||e.cssText;o.dangerouslySetInnerHTML={__html:r}}else o[n]=e[t]}),a.default.createElement(t,o)})},M=function(t,e,n){switch(t){case l.TAG_NAMES.TITLE:return{toComponent:function(){return P(t,e.title,e.titleAttributes,n)},toString:function(){return N(t,e.title,e.titleAttributes,n)}};case l.ATTRIBUTE_NAMES.BODY:case l.ATTRIBUTE_NAMES.HTML:return{toComponent:function(){return D(e)},toString:function(){return I(e)}};default:return{toComponent:function(){return k(t,e)},toString:function(){return A(t,e,n)}}}},R=function(t){var e=t.baseTag,n=t.bodyAttributes,r=t.encode,o=t.htmlAttributes,i=t.linkTags,u=t.metaTags,a=t.noscriptTags,s=t.scriptTags,c=t.styleTags,f=t.title,p=void 0===f?"":f,d=t.titleAttributes;return{base:M(l.TAG_NAMES.BASE,e,r),bodyAttributes:M(l.ATTRIBUTE_NAMES.BODY,n,r),htmlAttributes:M(l.ATTRIBUTE_NAMES.HTML,o,r),link:M(l.TAG_NAMES.LINK,i,r),meta:M(l.TAG_NAMES.META,u,r),noscript:M(l.TAG_NAMES.NOSCRIPT,a,r),script:M(l.TAG_NAMES.SCRIPT,s,r),style:M(l.TAG_NAMES.STYLE,c,r),title:M(l.TAG_NAMES.TITLE,{title:p,titleAttributes:d},r)}};e.convertReactPropstoHtmlAttributes=x,e.handleClientStateChange=w,e.mapStateOnServer=R,e.reducePropsToState=v,e.requestIdleCallback=m,e.warn=E},function(t,e,n){try{(function(){"use strict";function t(t){return t&&t.__esModule?t:{default:t}}function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var u=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:r,n=arguments[1];switch(n.type){case t.START_FETCHING_FORUMS:return Object.assign({},e,{fetchingForums:!0});case t.STOP_FETCHING_FORUMS:return Object.assign({},e,{fetchingForums:!1});case t.FETCHING_FORUMS_SUCCESS:return Object.assign({},e,{forums:n.payload,fetchingForums:!1,error:!1});case t.FETCHING_FORUMS_FAILURE:return Object.assign({},e,{fetchingForums:!1,error:"Unable to fetch forums"});case t.UPDATECURRENTFORUM:return Object.assign({},e,{currentForum:n.payload});default:return e}},{fetchingUser:!0,authenticated:!1,error:null,_id:null,name:null,email:null,username:null,avatarUrl:null,githubUrl:null,githubLocation:null,githubBio:null,role:null});e.userReducer=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:o,n=arguments[1];switch(n.type){case t.START_FETCHING_USER:return Object.assign({},e,{fetchUser:!0});case t.FETCHING_USER_SUCCESS:var r=n.payload,i=r._id,u=r.name,a=r.username,s=r.avatarUrl,c=r.email,l=r.githubBio,f=r.githubUrl,p=r.githubLocation,d=r.role;return Object.assign({},e),{fetchingUser:!1,authenticated:!0,error:null,_id:i,name:u,username:a,avatarUrl:s,email:c,githubBio:l,githubUrl:f,githubLocation:p,role:d};case t.FETCHING_USER_FAILURE:return Object.assign({},o,{fetchingUser:!1,error:"Unable to fetch user!"});default:return e}}}).call(this)}finally{}},function(t,e,n){try{(function(){"use strict";function t(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var r=n(105),o=n(306),i=t(o),u=n(258),a=n(281),s=n(290),c=n(285),l=n(277),f=n(294),p=(0,r.combineReducers)({user:u.userReducer,app:u.appReducer,feed:a.feedReducer,discussion:s.singleDiscussionReducer,newDiscussion:c.newDiscussionReducer,adminInfo:l.adminInfoReducer,userProfile:f.userProfileReducer}),d=window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__||r.compose,h=(0,r.createStore)(p,d((0,r.applyMiddleware)(i.default)));e.default=h}).call(this)}finally{}},function(t,e,n){try{(function(){"use strict";function t(t){return t&&t.__esModule?t:{default:t}}function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var u=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:r,n=arguments[1];switch(n.type){case t.GET_ALL_INFO_START:return Object.assign({},e,{loadingInfo:!0,error:null});case t.GET_ALL_INFO_SUCCESS:return Object.assign({},e,{loadingInfo:!1,info:n.payload,error:null});case t.GET_ALL_INFO_FAILURE:return Object.assign({},e,{loadingInfo:!1,error:"Something went wrong while loading admin level information."});case t.CREATE_FORUM:return Object.assign({},e,{creatingForumError:null,creatingForum:!0});case t.CREATE_FORUM_SUCCESS:return Object.assign({},e,{creatingForum:!1,creatingForumError:null});case t.CREATE_FORUM_FAILURE:return Object.assign({},e,{creatingForum:!1,creatingForumError:"Something went wrong while trying to create the forum. Please try again. Also check out if the forum already exists."});case t.DELETE_FORUM:return Object.assign({},e,{deletingForum:!0,deletingForumError:null});case t.DELETE_FORUM_SUCCESS:return Object.assign({},e,{deletingForum:!1,deletingForumError:null});case t.DELETE_FORUM_FAILURE:return Object.assign({},e,{deletingForum:!1,deletingForumError:"Something went wrong while trying to delete the forum. Please try again later."});default:return e}}}).call(this)}finally{}},function(t,e,n){try{(function(){"use strict";function t(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0}),e.updateSortingMethod=e.getPinnedDiscussions=e.getDiscussions=void 0;var r=n(23),o=t(r),i=n(97),u=n(279),a=function(t,e){var n=t.app.forums,r=o.default.find(n,{forum_slug:e});return r?r._id:null};e.getDiscussions=function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return function(r,o){var s=a(o(),t),c=o().feed.sortingMethod;(e||n)&&r({type:i.START_FETCHING_DISCUSSIONS}),s?(0,u.fetchDiscussions)(s,c).then(function(t){return r({type:i.FETCHING_DISCUSSIONS_SUCCESS,payload:t.data})},function(t){return r({type:i.FETCHING_DISCUSSIONS_FAILURE})}):r({type:i.INVALID_FORUM})}},e.getPinnedDiscussions=function(t,e){return function(n,r){var o=a(r(),t);e&&n({type:i.START_FETCHING_PINNED_DISCUSSIONS}),o?(0,u.fetchPinnedDiscussions)(o).then(function(t){return n({type:i.FETCHING_PINNED_DISCUSSIONS_SUCCESS,payload:t.data})},function(t){return n({type:i.FETCHING_PINNED_DISCUSSIONS_FAILURE})}):n({type:i.INVALID_FORUM})}},e.updateSortingMethod=function(t){return{type:i.UPDATE_SORTING_METHOD,payload:t}}}).call(this)}finally{}},function(t,e,n){try{(function(){"use strict";function t(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0}),e.fetchPinnedDiscussions=e.fetchDiscussions=void 0;var r=n(21),o=t(r);e.fetchDiscussions=function(t,e){return o.default.get("/api/forum/"+t+"/discussions?sorting_method="+e)},e.fetchPinnedDiscussions=function(t){return o.default.get("/api/forum/"+t+"/pinned_discussions")}}).call(this)}finally{}},function(t,e,n){try{(function(){"use strict";function t(t){return t&&t.__esModule?t:{default:t}}function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var u=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:r,n=arguments[1];switch(n.type){case t.START_FETCHING_DISCUSSIONS:return Object.assign({},e,{fetchingDiscussions:!0,error:null});case t.STOP_FETCHING_DISCUSSIONS:return Object.assign({},e,{fetchingDiscussions:!1});case t.FETCHING_DISCUSSIONS_SUCCESS:return Object.assign({},e,{discussions:n.payload,fetchingDiscussions:!1,error:null});case t.FETCHING_DISCUSSIONS_FAILURE:return Object.assign({},e,{fetchingDiscussions:!1,error:"Unable to fetch discussions at the moment."});case t.START_FETCHING_PINNED_DISCUSSIONS:return Object.assign({},e,{fetchingPinnedDiscussions:!0,error:null});case t.STOP_FETCHING_PINNED_DISCUSSIONS:return Object.assign({},e,{fetchingPinnedDiscussions:!1});case t.FETCHING_PINNED_DISCUSSIONS_SUCCESS:return Object.assign({},e,{pinnedDiscussions:n.payload,fetchingPinnedDiscussions:!1,error:null});case t.FETCHING_PINNED_DISCUSSIONS_FAILURE:return Object.assign({},e,{fetchingPinnedDiscussions:!1,error:"Unable to fetch pinned discussions at the moment."});case t.UPDATE_SORTING_METHOD:return Object.assign({},e,{sortingMethod:n.payload});case t.INVALID_FORUM:return Object.assign({},e,{error:"Sorry, couldn't find the forum.",fetchingPinnedDiscussions:!1,fetchingDiscussions:!1});default:return e}}}).call(this)}finally{}},function(t,e,n){try{(function(){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.updateDiscussionTags=e.updateDiscussionPinStatus=e.updateDiscussionContent=e.updateDiscussionTitle=e.postDiscussion=void 0;var t=n(8),r=n(98),o=n(283);e.postDiscussion=function(e,n,i){return function(u,a){u({type:r.POSTING_DISCUSSION_START});var s=a().newDiscussion,c=s.title,l=s.content,f=s.tags,p=s.pinned,d=!0;return e&&n?null===c||c.length<15?(d=!1,u({type:r.POSTING_DISCUSSION_FAILURE,payload:"Title should be at least 15 characters."})):null===l||0===l.length?(d=!1,u({type:r.POSTING_DISCUSSION_FAILURE,payload:"Please write some content before posting."})):null===f||0===f.length?(d=!1,u({type:r.POSTING_DISCUSSION_FAILURE,payload:"Please provide some tags."})):void(d&&(0,o.postDiscussionApi)({userId:e,forumId:n,title:c,content:l,tags:f,pinned:p}).then(function(e){e.data.postCreated===!0?(u({type:r.POSTING_DISCUSSION_SUCCESS}),setTimeout(function(){u({type:r.CLEAR_SUCCESS_MESSAGE})},2e3),t.browserHistory.push("/"+i+"/discussion/"+e.data.discussion_slug)):u({type:r.POSTING_DISCUSSION_FAILURE,payload:"Something is wrong at our server end. Please try again later"})},function(t){u({type:r.POSTING_DISCUSSION_FAILURE,payload:t})})):(d=!1,u({type:r.POSTING_DISCUSSION_FAILURE,payload:"Something is wrong with user/forum."}))}},e.updateDiscussionTitle=function(t){return{type:r.UPDATE_DISCUSSION_TITLE,payload:t}},e.updateDiscussionContent=function(t){return{type:r.UPDATE_DISCUSSION_CONTENT,payload:t}},e.updateDiscussionPinStatus=function(t){return{type:r.UPDATE_DISCUSSION_PIN_STATUS,payload:t}},e.updateDiscussionTags=function(t){return{type:r.UPDATE_DISCUSSION_TAGS,payload:t}}}).call(this)}finally{}},function(t,e,n){try{(function(){"use strict";function t(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0}),e.postDiscussionApi=void 0;var r=n(21),o=t(r);e.postDiscussionApi=function(t){return o.default.post("/api/discussion/newDiscussion",t)}}).call(this)}finally{}},function(t,e,n){try{(function(){"use strict";function t(t){return t&&t.__esModule?t:{default:t}}function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var u=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:r,n=arguments[1];switch(n.type){case t.POSTING_DISCUSSION_START:return Object.assign({},e,{postingDiscussion:!0});case t.POSTING_DISCUSSION_SUCCESS:return Object.assign({},r,{postingSuccess:!0,postingDiscussion:!1,errorMsg:null});case t.POSTING_DISCUSSION_FAILURE:return Object.assign({},e,{postingSuccess:!1,postingDiscussion:!1,errorMsg:n.payload||"Unable to post discussion."});case t.CLEAR_SUCCESS_MESSAGE:return Object.assign({},r,{postingSuccess:!1});case t.UPDATE_DISCUSSION_TITLE:return Object.assign({},e,{title:n.payload});case t.UPDATE_DISCUSSION_CONTENT:return Object.assign({},e,{content:n.payload});case t.UPDATE_DISCUSSION_PIN_STATUS:return Object.assign({},e,{pinned:n.payload});case t.UPDATE_DISCUSSION_TAGS:return Object.assign({},e,{tags:n.payload});default:return e}}}).call(this)}finally{}},function(t,e,n){try{(function(){"use strict";function t(t){return t&&t.__esModule?t:{default:t}}function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var u=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:r,n=arguments[1];switch(n.type){case t.FETCHING_SINGLE_DISC_START:return Object.assign({},e,{fetchingDiscussion:!0});case t.FETCHING_SINGLE_DISC_END:return Object.assign({},e,{fetchingDiscussion:!1});case t.FETCHING_SINGLE_DISC_SUCCESS:return Object.assign({},e,{discussion:n.payload,fetchingDiscussion:!1,error:null});case t.FETCHING_SINGLE_DISC_FAILURE:return Object.assign({},e,{fetchingDiscussion:!1,error:"Unable to fetch discussion. Please check out the url."});case t.TOGGLE_FAVORITE_START:return Object.assign({},e,{toggleingFavorite:!0});case t.TOGGLE_FAVORITE_SUCCESS:case t.TOGGLE_FAVORITE_FAILURE:return Object.assign({},e,{toggleingFavorite:!1});case t.UPDATE_OPINION_CONTENT:return Object.assign({},e,{opinionContent:n.payload});case t.POSTING_OPINION_START:return Object.assign({},e,{postingOpinion:!0,opinionError:null});case t.POSTING_OPINION_SUCCESS:return Object.assign({},e,{postingOpinion:!1,opinionContent:null,opinionError:null});case t.POSTING_OPINION_FAILURE:return Object.assign({},e,{postingOpinion:!1,opinionContent:null,opinionError:n.payload});case t.DELETE_DISC_START:return Object.assign({},e,{deletingDiscussion:!0});case t.DELETE_DISC_SUCCESS:return Object.assign({},e,{deletingDiscussion:!1,deletedDiscussion:!0});case t.DELETE_DISC_FAILURE:return Object.assign({},e,{deletingDiscussion:!1,deletedDiscussion:!1});case t.DELETE_DISC_REDIRECT:return Object.assign({},e,{deletedDiscussion:!1});case t.DELETE_OPINION_START:return Object.assign({},e,{deletingOpinion:n.payload});case t.DELETE_OPINION_SUCCESS:case t.DELETE_OPINION_FAILURE:return Object.assign({},e,{deletingOpinion:null});default:return e}}}).call(this)}finally{}},function(t,e,n){try{(function(){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.fetchUserProfile=void 0;var t=n(100),r=n(292);e.fetchUserProfile=function(e){return function(n,o){n({type:t.FETCH_USER_PROFILE_START}),(0,r.fetchUserProfileApi)(e).then(function(e){n(e.data.error?{type:t.FETCH_USER_PROFILE_FAILURE}:{type:t.FETCH_USER_PROFILE_SUCCESS,payload:e.data})},function(e){return n({type:t.FETCH_USER_PROFILE_FAILURE})})}}}).call(this)}finally{}},function(t,e,n){try{(function(){"use strict";function t(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0}),e.fetchUserProfileApi=void 0;var r=n(21),o=t(r);e.fetchUserProfileApi=function(t){return o.default.get("/api/user/profile/"+t)}}).call(this)}finally{}},function(t,e,n){try{(function(){"use strict";function t(t){return t&&t.__esModule?t:{default:t}}function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var u=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:r,n=arguments[1];switch(n.type){case t.FETCH_USER_PROFILE_START:return Object.assign({},e,{fetchingProfile:!0,error:null});case t.FETCH_USER_PROFILE_SUCCESS:return Object.assign({},e,{fetchingProfile:!1,profile:n.payload,error:null});case t.FETCH_USER_PROFILE_FAILURE:return Object.assign({},e,{fetchingProfile:!1,error:"Unable to fetch user profile. Please check out for correct username."});default:return e}}}).call(this)}finally{}},function(t,e,n){var r,o;!function(i){function u(t,e,n,r){return function(t,o){var i=r({statics:{getClass:function(){return t.getClass?t.getClass():t}},getInstance:function(){return t.prototype.isReactComponent?this.refs.instance:this},__outsideClickHandler:function(){},getDefaultProps:function(){return{excludeScrollbar:o&&o.excludeScrollbar}},componentDidMount:function(){if("undefined"!=typeof document&&document.createElement){var t,r=this.getInstance();if(o&&"function"==typeof o.handleClickOutside){if(t=o.handleClickOutside(r),"function"!=typeof t)throw new Error("Component lacks a function for processing outside click events specified by the handleClickOutside config option.")}else if("function"==typeof r.handleClickOutside)t=e.Component.prototype.isPrototypeOf(r)?r.handleClickOutside.bind(r):r.handleClickOutside;else{if("function"!=typeof r.props.handleClickOutside)throw new Error("Component lacks a handleClickOutside(event) function for processing outside click events.");t=r.props.handleClickOutside}var i=n.findDOMNode(r);null===i&&(console.warn("Antipattern warning: there was no DOM node associated with the component that is being wrapped by outsideClick."),console.warn(["This is typically caused by having a component that starts life with a render function that","returns `null` (due to a state or props value), so that the component 'exist' in the React","chain of components, but not in the DOM.\n\nInstead, you need to refactor your code so that the","decision of whether or not to show your component is handled by the parent, in their render()","function.\n\nIn code, rather than:\n\n A{render(){return check? <.../> : null;}\n B{render(){}\n\nmake sure that you","use:\n\n A{render(){return <.../>}\n B{render(){return <...>{ check ? : null }<...>}}\n\nThat is:","the parent is always responsible for deciding whether or not to render any of its children.","It is not the child's responsibility to decide whether a render instruction from above should","get ignored or not by returning `null`.\n\nWhen any component gets its render() function called,","that is the signal that it should be rendering its part of the UI. It may in turn decide not to","render all of *its* children, but it should never return `null` for itself. It is not responsible","for that decision."].join(" ")));var u=this.__outsideClickHandler=y(i,r,t,this.props.outsideClickIgnoreClass||l,this.props.excludeScrollbar,this.props.preventDefault||!1,this.props.stopPropagation||!1),a=s.length;s.push(this),c[a]=u,this.props.disableOnClickOutside||this.enableOnClickOutside()}},componentWillReceiveProps:function(t){this.props.disableOnClickOutside&&!t.disableOnClickOutside?this.enableOnClickOutside():!this.props.disableOnClickOutside&&t.disableOnClickOutside&&this.disableOnClickOutside()},componentWillUnmount:function(){this.disableOnClickOutside(),this.__outsideClickHandler=!1;var t=s.indexOf(this);t>-1&&(c[t]&&c.splice(t,1),s.splice(t,1))},enableOnClickOutside:function(){var t=this.__outsideClickHandler;if("undefined"!=typeof document){var e=this.props.eventTypes||f;e.forEach||(e=[e]),e.forEach(function(e){document.addEventListener(e,t)})}},disableOnClickOutside:function(){var t=this.__outsideClickHandler;if("undefined"!=typeof document){var e=this.props.eventTypes||f;e.forEach||(e=[e]),e.forEach(function(e){document.removeEventListener(e,t)})}},render:function(){var n=this.props,r={};return Object.keys(this.props).forEach(function(t){"excludeScrollbar"!==t&&(r[t]=n[t])}),t.prototype.isReactComponent&&(r.ref="instance"),r.disableOnClickOutside=this.disableOnClickOutside,r.enableOnClickOutside=this.enableOnClickOutside,e.createElement(t,r)}});return function(t,e){var n=t.displayName||t.name||"Component";e.displayName="OnClickOutside("+n+")"}(t,i),i}}function a(i,u){r=[n(1),n(20),n(124)],o=function(t,e,n){return n||(n=t.createClass),u(i,t,e,n)}.apply(e,r),!(void 0!==o&&(t.exports=o))}var s=[],c=[],l="ignore-react-onclickoutside",f=["mousedown","touchstart"],p=function(t,e,n){return t===e||(t.correspondingElement?t.correspondingElement.classList.contains(n):t.classList.contains(n))},d=function(t,e,n){if(t===e)return!0;for(;t.parentNode;){if(p(t,e,n))return!0;t=t.parentNode}return t},h=function(t){return document.documentElement.clientWidth<=t.clientX||document.documentElement.clientHeight<=t.clientY},y=function(t,e,n,r,o,i,u){return function(e){i&&e.preventDefault(),u&&e.stopPropagation();var a=e.target;o&&h(e)||d(a,t,r)!==document||n(e)}};a(i,u)}(this)},function(t,e,n){(function(t){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function u(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function a(){y||(y=!0,(0,h.default)(" does not support changing `store` on the fly. It is most likely that you see this error because you updated to Redux 2.x and React Redux 2.x which no longer hot reload reducers automatically. See https://github.com/reactjs/react-redux/releases/tag/v2.0.0 for the migration instructions."))}function s(){var e,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"store",r=arguments[1],s=r||n+"Subscription",l=function(t){function e(r,u){o(this,e);var a=i(this,t.call(this,r,u));return a[n]=r.store,a}return u(e,t),e.prototype.getChildContext=function(){var t;return t={},t[n]=this[n],t[s]=null,t},e.prototype.render=function(){return c.Children.only(this.props.children)},e}(c.Component);return"production"!==t.env.NODE_ENV&&(l.prototype.componentWillReceiveProps=function(t){this[n]!==t.store&&a()}),l.propTypes={store:p.storeShape.isRequired,children:f.default.element.isRequired},l.childContextTypes=(e={},e[n]=p.storeShape.isRequired,e[s]=p.subscriptionShape,e),l.displayName="Provider",l}e.__esModule=!0,e.createProvider=s;var c=n(1),l=n(52),f=r(l),p=n(103),d=n(55),h=r(d),y=!1;e.default=s()}).call(e,n(2))},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){var n={};for(var r in t)e.indexOf(r)>=0||Object.prototype.hasOwnProperty.call(t,r)&&(n[r]=t[r]);return n}function i(t,e,n){for(var r=e.length-1;r>=0;r--){var o=e[r](t);if(o)return o}return function(e,r){throw new Error("Invalid value of type "+typeof t+" for "+n+" argument when connecting component "+r.wrappedComponentName+".")}}function u(t,e){return t===e}function a(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=t.connectHOC,n=void 0===e?l.default:e,r=t.mapStateToPropsFactories,a=void 0===r?_.default:r,c=t.mapDispatchToPropsFactories,f=void 0===c?h.default:c,d=t.mergePropsFactories,y=void 0===d?v.default:d,g=t.selectorFactory,m=void 0===g?b.default:g;return function(t,e,r){var c=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},l=c.pure,d=void 0===l||l,h=c.areStatesEqual,_=void 0===h?u:h,g=c.areOwnPropsEqual,v=void 0===g?p.default:g,b=c.areStatePropsEqual,E=void 0===b?p.default:b,S=c.areMergedPropsEqual,w=void 0===S?p.default:S,O=o(c,["pure","areStatesEqual","areOwnPropsEqual","areStatePropsEqual","areMergedPropsEqual"]),T=i(t,a,"mapStateToProps"),C=i(e,f,"mapDispatchToProps"),I=i(r,y,"mergeProps");return n(m,s({methodName:"connect",getDisplayName:function(t){return"Connect("+t+")"},shouldHandleStateChanges:Boolean(t),initMapStateToProps:T,initMapDispatchToProps:C,initMergeProps:I,pure:d,areStatesEqual:_,areOwnPropsEqual:v,areStatePropsEqual:E,areMergedPropsEqual:w},O))}}e.__esModule=!0;var s=Object.assign||function(t){for(var e=1;e=0||Object.prototype.hasOwnProperty.call(t,r)&&(n[r]=t[r]);return n}function i(t,e,n,r){return function(o,i){return n(t(o,i),e(r,i),i)}}function u(t,e,n,r,o){function i(o,i){return h=o,y=i,_=t(h,y),g=e(r,y),v=n(_,g,y),d=!0,v}function u(){return _=t(h,y),e.dependsOnOwnProps&&(g=e(r,y)),v=n(_,g,y)}function a(){return t.dependsOnOwnProps&&(_=t(h,y)),e.dependsOnOwnProps&&(g=e(r,y)),v=n(_,g,y)}function s(){var e=t(h,y),r=!p(e,_);return _=e,r&&(v=n(_,g,y)),v}function c(t,e){var n=!f(e,y),r=!l(t,h);return h=t,y=e,n&&r?u():n?a():r?s():v}var l=o.areStatesEqual,f=o.areOwnPropsEqual,p=o.areStatePropsEqual,d=!1,h=void 0,y=void 0,_=void 0,g=void 0,v=void 0;return function(t,e){return d?c(t,e):i(t,e)}}function a(e,n){var r=n.initMapStateToProps,a=n.initMapDispatchToProps,s=n.initMergeProps,l=o(n,["initMapStateToProps","initMapDispatchToProps","initMergeProps"]),f=r(e,l),p=a(e,l),d=s(e,l);"production"!==t.env.NODE_ENV&&(0,c.default)(f,p,d,l.displayName);var h=l.pure?u:i;return h(f,p,d,e,l)}e.__esModule=!0,e.impureFinalPropsSelectorFactory=i,e.pureFinalPropsSelectorFactory=u,e.default=a;var s=n(302),c=r(s)}).call(e,n(2))},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e,n){if(!t)throw new Error("Unexpected value for "+e+" in "+n+".");"mapStateToProps"!==e&&"mapDispatchToProps"!==e||t.hasOwnProperty("dependsOnOwnProps")||(0,a.default)("The selector for "+e+" of "+n+" did not specify a value for dependsOnOwnProps.")}function i(t,e,n,r){o(t,"mapStateToProps",r),o(e,"mapDispatchToProps",r),o(n,"mergeProps",r)}e.__esModule=!0,e.default=i;var u=n(55),a=r(u)},function(t,e){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function r(){var t=[],e=[];return{clear:function(){e=o,t=o},notify:function(){for(var n=t=e,r=0;r0?2==o.length?typeof o[1]==c?t[o[0]]=o[1].call(this,a):t[o[0]]=o[1]:3==o.length?typeof o[1]!==c||o[1].exec&&o[1].test?t[o[0]]=a?a.replace(o[1],o[2]):i:t[o[0]]=a?o[1].call(this,a,o[2]):i:4==o.length&&(t[o[0]]=a?o[3].call(this,a.replace(o[1],o[2])):i):t[o]=a?a:i;s+=2}return t},str:function(t,e){for(var n in e)if(typeof e[n]===f&&e[n].length>0){for(var r=0;r
================================================ FILE: server.js ================================================ // modules for server const path = require('path'); const express = require('express'); const mongoose = require('mongoose'); const passport = require('passport'); // server configurations const serverConfigs = require('./config/serverConfig'); // connect to database mongoose.connect(serverConfigs.DBURL); // initialize express const app = express(); // apply express configs require('./backend/express')(app, serverConfigs); // fire up the server app.listen(serverConfigs.PORT, (error) => { if (error) throw error; console.log('Server running on port: ' + serverConfigs.PORT); });