[
  {
    "path": ".bowerrc",
    "content": "{\n    \"directory\": \"client/bower_components\"\n}\n"
  },
  {
    "path": ".buildignore",
    "content": ""
  },
  {
    "path": ".editorconfig",
    "content": "# EditorConfig helps developers define and maintain consistent\n# coding styles between different editors and IDEs\n# editorconfig.org\n\nroot = true\n\n\n[*]\n\n# Change these settings to your own preference\nindent_style = space\nindent_size = 2\n\n# We recommend you to keep these unchanged\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto\n\n# These files are text and should be normalized (Convert crlf => lf)\n*.php  text\n*.css  text\n*.js   text\n*.htm  text\n*.html text\n*.xml  text\n*.txt  text\n*.ini  text\n*.inc  text\n.htaccess text\n\n# Denote all files that are truly binary and should not be modified.\n# (binary is a macro for -text -diff)\n*.png  binary\n*.jpg  binary\n*.jpeg binary\n*.gif  binary\n*.ico  binary\n*.mov  binary\n*.mp4  binary\n*.mp3  binary\n*.flv  binary\n*.fla  binary\n*.swf  binary\n*.gz   binary\n*.zip  binary\n*.7z   binary\n*.ttf  binary\n\n# Documents\n*.doc  diff=astextplain\n*.DOC  diff=astextplain\n*.docx diff=astextplain\n*.DOCX diff=astextplain\n*.dot  diff=astextplain\n*.DOT  diff=astextplain\n*.pdf  diff=astextplain\n*.PDF  diff=astextplain\n*.rtf  diff=astextplain\n*.RTF  diff=astextplain\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\npublic\n.tmp\n.sass-cache\n.idea\nclient/bower_components\ndist\n/server/config/local.env.js\nnpm-debug.log\ncoverage\n.cache\n.config\n"
  },
  {
    "path": ".jscsrc",
    "content": "{\n  \"excludeFiles\": [\n    \"client/app/app.constant.js\"\n  ],\n  \"esnext\": true,\n  \"maximumLineLength\": {\n    \"value\": 100,\n    \"allowComments\": true,\n    \"allowRegex\": true\n  },\n  \"disallowMixedSpacesAndTabs\": true,\n  \"disallowMultipleLineStrings\": true,\n  \"disallowNewlineBeforeBlockStatements\": true,\n  \"disallowSpaceAfterObjectKeys\": true,\n  \"disallowSpaceAfterPrefixUnaryOperators\": [\"++\", \"--\", \"+\", \"-\", \"~\", \"!\"],\n  \"disallowSpaceBeforeBinaryOperators\": [\",\"],\n  \"disallowSpaceBeforePostfixUnaryOperators\": [\"++\", \"--\"],\n  \"disallowSpacesInAnonymousFunctionExpression\": {\n    \"beforeOpeningRoundBrace\": true\n  },\n  \"disallowSpacesInFunctionDeclaration\": {\n    \"beforeOpeningRoundBrace\": true\n  },\n  \"disallowSpacesInNamedFunctionExpression\": {\n    \"beforeOpeningRoundBrace\": true\n  },\n  \"disallowSpacesInsideArrayBrackets\": true,\n  \"disallowSpacesInsideParentheses\": true,\n  \"disallowTrailingComma\": true,\n  \"disallowTrailingWhitespace\": true,\n  \"requireCommaBeforeLineBreak\": true,\n  \"requireLineFeedAtFileEnd\": true,\n  \"requireSpaceAfterBinaryOperators\": [\"?\", \":\", \"+\", \"-\", \"/\", \"*\", \"%\", \"==\", \"===\", \"!=\", \"!==\", \">\", \">=\", \"<\", \"<=\", \"&&\", \"||\"],\n  \"requireSpaceBeforeBinaryOperators\": [\"?\", \":\", \"+\", \"-\", \"/\", \"*\", \"%\", \"==\", \"===\", \"!=\", \"!==\", \">\", \">=\", \"<\", \"<=\", \"&&\", \"||\"],\n  \"requireSpaceAfterKeywords\": [\"if\", \"else\", \"for\", \"while\", \"do\", \"switch\", \"return\", \"try\", \"catch\"],\n  \"requireSpaceBeforeBlockStatements\": true,\n  \"requireSpacesInConditionalExpression\": {\n    \"afterTest\": true,\n    \"beforeConsequent\": true,\n    \"afterConsequent\": true,\n    \"beforeAlternate\": true\n  },\n  \"requireSpacesInFunction\": {\n    \"beforeOpeningCurlyBrace\": true\n  },\n  \"validateLineBreaks\": \"LF\",\n  \"validateParameterSeparator\": \", \"\n}\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - 4.2.3\nmatrix:\n  fast_finish: true\n  allow_failures:\n    - node_js: 5.1.1\nbefore_script:\n  - npm install -g bower grunt-cli\n  - gem install sass\n  - bower install\nservices: mongodb\n"
  },
  {
    "path": ".yo-rc.json",
    "content": "{\n  \"generator-angular-fullstack\": {\n    \"generatorVersion\": \"3.3.0\",\n    \"endpointDirectory\": \"server/api/\",\n    \"insertRoutes\": true,\n    \"registerRoutesFile\": \"server/routes.js\",\n    \"routesNeedle\": \"// Insert routes below\",\n    \"routesBase\": \"/api/\",\n    \"pluralizeRoutes\": true,\n    \"insertSockets\": true,\n    \"registerSocketsFile\": \"server/config/socketio.js\",\n    \"socketsNeedle\": \"// Insert sockets below\",\n    \"insertModels\": true,\n    \"registerModelsFile\": \"server/sqldb/index.js\",\n    \"modelsNeedle\": \"// Insert models below\",\n    \"filters\": {\n      \"js\": true,\n      \"babel\": true,\n      \"html\": true,\n      \"sass\": true,\n      \"uirouter\": true,\n      \"bootstrap\": true,\n      \"uibootstrap\": true,\n      \"socketio\": true,\n      \"auth\": true,\n      \"models\": true,\n      \"mongooseModels\": true,\n      \"mongoose\": true,\n      \"oauth\": true,\n      \"googleAuth\": true,\n      \"facebookAuth\": true,\n      \"twitterAuth\": true,\n      \"grunt\": true,\n      \"jasmine\": true,\n      \"mocha\": false,\n      \"should\": false,\n      \"expect\": false\n    }\n  },\n  \"generator-ng-component\": {\n    \"routeDirectory\": \"client/app/\",\n    \"directiveDirectory\": \"client/app/\",\n    \"filterDirectory\": \"client/app/\",\n    \"serviceDirectory\": \"client/app/\",\n    \"basePath\": \"client\",\n    \"moduleName\": \"\",\n    \"filters\": [\n      \"uirouter\",\n      \"jasmine\",\n      \"uirouter\"\n    ],\n    \"extensions\": [\n      \"babel\",\n      \"js\",\n      \"html\",\n      \"scss\"\n    ],\n    \"directiveSimpleTemplates\": \"\",\n    \"directiveComplexTemplates\": \"\",\n    \"filterTemplates\": \"\",\n    \"serviceTemplates\": \"\",\n    \"factoryTemplates\": \"\",\n    \"controllerTemplates\": \"\",\n    \"decoratorTemplates\": \"\",\n    \"providerTemplates\": \"\",\n    \"routeTemplates\": \"\"\n  }\n}"
  },
  {
    "path": "Gruntfile.js",
    "content": "// Generated on 2016-03-08 using generator-angular-fullstack 3.3.0\n'use strict';\n\nmodule.exports = function (grunt) {\n  var localConfig;\n  try {\n    localConfig = require('./server/config/local.env');\n  } catch(e) {\n    localConfig = {};\n  }\n\n  // Load grunt tasks automatically, when needed\n  require('jit-grunt')(grunt, {\n    express: 'grunt-express-server',\n    useminPrepare: 'grunt-usemin',\n    ngtemplates: 'grunt-angular-templates',\n    cdnify: 'grunt-google-cdn',\n    protractor: 'grunt-protractor-runner',\n    buildcontrol: 'grunt-build-control',\n    istanbul_check_coverage: 'grunt-mocha-istanbul',\n    ngconstant: 'grunt-ng-constant'\n  });\n\n  // Time how long tasks take. Can help when optimizing build times\n  require('time-grunt')(grunt);\n\n  // Define the configuration for all the tasks\n  grunt.initConfig({\n\n    // Project settings\n    pkg: grunt.file.readJSON('package.json'),\n    yeoman: {\n      // configurable paths\n      client: require('./bower.json').appPath || 'client',\n      server: 'server',\n      dist: 'dist'\n    },\n    express: {\n      options: {\n        port: process.env.PORT || 9000\n      },\n      dev: {\n        options: {\n          script: '<%= yeoman.server %>',\n          debug: true\n        }\n      },\n      prod: {\n        options: {\n          script: '<%= yeoman.dist %>/<%= yeoman.server %>'\n        }\n      }\n    },\n    open: {\n      server: {\n        url: 'http://localhost:<%= express.options.port %>'\n      }\n    },\n    watch: {\n      babel: {\n        files: ['<%= yeoman.client %>/{app,components}/**/!(*.spec|*.mock).js'],\n        tasks: ['newer:babel:client']\n      },\n      ngconstant: {\n        files: ['<%= yeoman.server %>/config/environment/shared.js'],\n        tasks: ['ngconstant']\n      },\n      injectJS: {\n        files: [\n          '<%= yeoman.client %>/{app,components}/**/!(*.spec|*.mock).js',\n          '!<%= yeoman.client %>/app/app.js'\n        ],\n        tasks: ['injector:scripts']\n      },\n      injectCss: {\n        files: ['<%= yeoman.client %>/{app,components}/**/*.css'],\n        tasks: ['injector:css']\n      },\n      mochaTest: {\n        files: ['<%= yeoman.server %>/**/*.{spec,integration}.js'],\n        tasks: ['env:test', 'mochaTest']\n      },\n      jsTest: {\n        files: ['<%= yeoman.client %>/{app,components}/**/*.{spec,mock}.js'],\n        tasks: ['newer:jshint:all', 'wiredep:test', 'karma']\n      },\n      injectSass: {\n        files: ['<%= yeoman.client %>/{app,components}/**/*.{scss,sass}'],\n        tasks: ['injector:sass']\n      },\n      sass: {\n        files: ['<%= yeoman.client %>/{app,components}/**/*.{scss,sass}'],\n        tasks: ['sass', 'postcss']\n      },\n      gruntfile: {\n        files: ['Gruntfile.js']\n      },\n      livereload: {\n        files: [\n          '{.tmp,<%= yeoman.client %>}/{app,components}/**/*.{css,html}',\n          '{.tmp,<%= yeoman.client %>}/{app,components}/**/!(*.spec|*.mock).js',\n          '<%= yeoman.client %>/assets/images/{,*//*}*.{png,jpg,jpeg,gif,webp,svg}'\n        ],\n        options: {\n          livereload: true\n        }\n      },\n      express: {\n        files: ['<%= yeoman.server %>/**/*.{js,json}'],\n        tasks: ['express:dev', 'wait'],\n        options: {\n          livereload: true,\n          spawn: false //Without this option specified express won't be reloaded\n        }\n      },\n      bower: {\n        files: ['bower.json'],\n        tasks: ['wiredep']\n      },\n    },\n\n    // Make sure code styles are up to par and there are no obvious mistakes\n    jshint: {\n      options: {\n        jshintrc: '<%= yeoman.client %>/.jshintrc',\n        reporter: require('jshint-stylish')\n      },\n      server: {\n        options: {\n          jshintrc: '<%= yeoman.server %>/.jshintrc'\n        },\n        src: ['<%= yeoman.server %>/**/!(*.spec|*.integration).js']\n      },\n      serverTest: {\n        options: {\n          jshintrc: '<%= yeoman.server %>/.jshintrc-spec'\n        },\n        src: ['<%= yeoman.server %>/**/*.{spec,integration}.js']\n      },\n      all: ['<%= yeoman.client %>/{app,components}/**/!(*.spec|*.mock|app.constant).js'],\n      test: {\n        src: ['<%= yeoman.client %>/{app,components}/**/*.{spec,mock}.js']\n      }\n    },\n\n    jscs: {\n      options: {\n        config: \".jscsrc\"\n      },\n      main: {\n        files: {\n          src: [\n            '<%= yeoman.client %>/app/**/*.js',\n            '<%= yeoman.server %>/**/*.js'\n          ]\n        }\n      }\n    },\n\n    // Empties folders to start fresh\n    clean: {\n      dist: {\n        files: [{\n          dot: true,\n          src: [\n            '.tmp',\n            '<%= yeoman.dist %>/!(.git*|.openshift|Procfile)**'\n          ]\n        }]\n      },\n      server: '.tmp'\n    },\n\n    // Add vendor prefixed styles\n    postcss: {\n      options: {\n        map: true,\n        processors: [\n          require('autoprefixer')({browsers: ['last 2 version']})\n        ]\n      },\n      dist: {\n        files: [{\n          expand: true,\n          cwd: '.tmp/',\n          src: '{,*/}*.css',\n          dest: '.tmp/'\n        }]\n      }\n    },\n\n    // Debugging with node inspector\n    'node-inspector': {\n      custom: {\n        options: {\n          'web-host': 'localhost'\n        }\n      }\n    },\n\n    // Use nodemon to run server in debug mode with an initial breakpoint\n    nodemon: {\n      debug: {\n        script: '<%= yeoman.server %>',\n        options: {\n          nodeArgs: ['--debug-brk'],\n          env: {\n            PORT: process.env.PORT || 9000\n          },\n          callback: function (nodemon) {\n            nodemon.on('log', function (event) {\n              console.log(event.colour);\n            });\n\n            // opens browser on initial server start\n            nodemon.on('config:update', function () {\n              setTimeout(function () {\n                require('open')('http://localhost:8080/debug?port=5858');\n              }, 500);\n            });\n          }\n        }\n      }\n    },\n\n    // Automatically inject Bower components into the app and karma.conf.js\n    wiredep: {\n      options: {\n        exclude: [\n          /bootstrap.js/,\n          '/json3/',\n          '/es5-shim/',\n          /font-awesome\\.css/,\n          /bootstrap\\.css/,\n          /bootstrap-sass-official/,\n          /bootstrap-social\\.css/\n        ]\n      },\n      client: {\n        src: '<%= yeoman.client %>/index.html',\n        ignorePath: '<%= yeoman.client %>/',\n      },\n      test: {\n        src: './karma.conf.js',\n        devDependencies: true\n      }\n    },\n\n    // Renames files for browser caching purposes\n    filerev: {\n      dist: {\n        src: [\n          '<%= yeoman.dist %>/<%= yeoman.client %>/!(bower_components){,*/}*.{js,css}',\n          '<%= yeoman.dist %>/<%= yeoman.client %>/assets/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',\n          '<%= yeoman.dist %>/<%= yeoman.client %>/assets/fonts/*'\n        ]\n      }\n    },\n\n    // Reads HTML for usemin blocks to enable smart builds that automatically\n    // concat, minify and revision files. Creates configurations in memory so\n    // additional tasks can operate on them\n    useminPrepare: {\n      html: ['<%= yeoman.client %>/index.html'],\n      options: {\n        dest: '<%= yeoman.dist %>/<%= yeoman.client %>'\n      }\n    },\n\n    // Performs rewrites based on rev and the useminPrepare configuration\n    usemin: {\n      html: ['<%= yeoman.dist %>/<%= yeoman.client %>/{,!(bower_components)/**/}*.html'],\n      css: ['<%= yeoman.dist %>/<%= yeoman.client %>/!(bower_components){,*/}*.css'],\n      js: ['<%= yeoman.dist %>/<%= yeoman.client %>/!(bower_components){,*/}*.js'],\n      options: {\n        assetsDirs: [\n          '<%= yeoman.dist %>/<%= yeoman.client %>',\n          '<%= yeoman.dist %>/<%= yeoman.client %>/assets/images'\n        ],\n        // This is so we update image references in our ng-templates\n        patterns: {\n          js: [\n            [/(assets\\/images\\/.*?\\.(?:gif|jpeg|jpg|png|webp|svg))/gm, 'Update the JS to reference our revved images']\n          ]\n        }\n      }\n    },\n\n    // The following *-min tasks produce minified files in the dist folder\n    imagemin: {\n      dist: {\n        files: [{\n          expand: true,\n          cwd: '<%= yeoman.client %>/assets/images',\n          src: '{,*/}*.{png,jpg,jpeg,gif,svg}',\n          dest: '<%= yeoman.dist %>/<%= yeoman.client %>/assets/images'\n        }]\n      }\n    },\n\n    // Allow the use of non-minsafe AngularJS files. Automatically makes it\n    // minsafe compatible so Uglify does not destroy the ng references\n    ngAnnotate: {\n      dist: {\n        files: [{\n          expand: true,\n          cwd: '.tmp/concat',\n          src: '**/*.js',\n          dest: '.tmp/concat'\n        }]\n      }\n    },\n\n    // Dynamically generate angular constant `appConfig` from\n    // `server/config/environment/shared.js`\n    ngconstant: {\n      options: {\n        name: 'paizaqaApp.constants',\n        dest: '<%= yeoman.client %>/app/app.constant.js',\n        deps: [],\n        wrap: true,\n        configPath: '<%= yeoman.server %>/config/environment/shared'\n      },\n      app: {\n        constants: function() {\n          return {\n            appConfig: require('./' + grunt.config.get('ngconstant.options.configPath'))\n          };\n        }\n      }\n    },\n\n    // Package all the html partials into a single javascript payload\n    ngtemplates: {\n      options: {\n        // This should be the name of your apps angular module\n        module: 'paizaqaApp',\n        htmlmin: {\n          collapseBooleanAttributes: true,\n          collapseWhitespace: true,\n          removeAttributeQuotes: true,\n          removeEmptyAttributes: true,\n          removeRedundantAttributes: true,\n          removeScriptTypeAttributes: true,\n          removeStyleLinkTypeAttributes: true\n        },\n        usemin: 'app/app.js'\n      },\n      main: {\n        cwd: '<%= yeoman.client %>',\n        src: ['{app,components}/**/*.html'],\n        dest: '.tmp/templates.js'\n      },\n      tmp: {\n        cwd: '.tmp',\n        src: ['{app,components}/**/*.html'],\n        dest: '.tmp/tmp-templates.js'\n      }\n    },\n\n    // Replace Google CDN references\n    cdnify: {\n      dist: {\n        html: ['<%= yeoman.dist %>/<%= yeoman.client %>/*.html']\n      }\n    },\n\n    // Copies remaining files to places other tasks can use\n    copy: {\n      dist: {\n        files: [{\n          expand: true,\n          dot: true,\n          cwd: '<%= yeoman.client %>',\n          dest: '<%= yeoman.dist %>/<%= yeoman.client %>',\n          src: [\n            '*.{ico,png,txt}',\n            '.htaccess',\n            'bower_components/**/*',\n            'assets/images/{,*/}*.{webp}',\n            'assets/fonts/**/*',\n            'index.html'\n          ]\n        }, {\n          expand: true,\n          cwd: '.tmp/images',\n          dest: '<%= yeoman.dist %>/<%= yeoman.client %>/assets/images',\n          src: ['generated/*']\n        }, {\n          expand: true,\n          dest: '<%= yeoman.dist %>',\n          src: [\n            'package.json',\n            '<%= yeoman.server %>/**/*',\n            '!<%= yeoman.server %>/config/local.env.sample.js'\n          ]\n        }]\n      },\n      styles: {\n        expand: true,\n        cwd: '<%= yeoman.client %>',\n        dest: '.tmp/',\n        src: ['{app,components}/**/*.css']\n      }\n    },\n\n    buildcontrol: {\n      options: {\n        dir: '<%= yeoman.dist %>',\n        commit: true,\n        push: true,\n        connectCommits: false,\n        message: 'Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%'\n      },\n      heroku: {\n        options: {\n          remote: 'heroku',\n          branch: 'master'\n        }\n      },\n      openshift: {\n        options: {\n          remote: 'openshift',\n          branch: 'master'\n        }\n      }\n    },\n\n    // Run some tasks in parallel to speed up the build process\n    concurrent: {\n      pre: [\n        'injector:sass',\n        'ngconstant'\n      ],\n      server: [\n        'newer:babel:client',\n        'sass',\n      ],\n      test: [\n        'newer:babel:client',\n        'sass',\n      ],\n      debug: {\n        tasks: [\n          'nodemon',\n          'node-inspector'\n        ],\n        options: {\n          logConcurrentOutput: true\n        }\n      },\n      dist: [\n        'newer:babel:client',\n        'sass',\n        'imagemin'\n      ]\n    },\n\n    // Test settings\n    karma: {\n      unit: {\n        configFile: 'karma.conf.js',\n        singleRun: true\n      }\n    },\n\n    mochaTest: {\n      options: {\n        reporter: 'spec',\n        require: 'mocha.conf.js',\n        timeout: 5000 // set default mocha spec timeout\n      },\n      unit: {\n        src: ['<%= yeoman.server %>/**/*.spec.js']\n      },\n      integration: {\n        src: ['<%= yeoman.server %>/**/*.integration.js']\n      }\n    },\n\n    mocha_istanbul: {\n      unit: {\n        options: {\n          excludes: ['**/*.{spec,mock,integration}.js'],\n          reporter: 'spec',\n          require: ['mocha.conf.js'],\n          mask: '**/*.spec.js',\n          coverageFolder: 'coverage/server/unit'\n        },\n        src: '<%= yeoman.server %>'\n      },\n      integration: {\n        options: {\n          excludes: ['**/*.{spec,mock,integration}.js'],\n          reporter: 'spec',\n          require: ['mocha.conf.js'],\n          mask: '**/*.integration.js',\n          coverageFolder: 'coverage/server/integration'\n        },\n        src: '<%= yeoman.server %>'\n      }\n    },\n\n    istanbul_check_coverage: {\n      default: {\n        options: {\n          coverageFolder: 'coverage/**',\n          check: {\n            lines: 80,\n            statements: 80,\n            branches: 80,\n            functions: 80\n          }\n        }\n      }\n    },\n\n    protractor: {\n      options: {\n        configFile: 'protractor.conf.js'\n      },\n      chrome: {\n        options: {\n          args: {\n            browser: 'chrome'\n          }\n        }\n      }\n    },\n\n    env: {\n      test: {\n        NODE_ENV: 'test'\n      },\n      prod: {\n        NODE_ENV: 'production'\n      },\n      all: localConfig\n    },\n\n    // Compiles ES6 to JavaScript using Babel\n    babel: {\n      options: {\n        sourceMap: true,\n        optional: [\n          'es7.classProperties'\n        ]\n      },\n      client: {\n        files: [{\n          expand: true,\n          cwd: '<%= yeoman.client %>',\n          src: ['{app,components}/**/!(*.spec).js'],\n          dest: '.tmp'\n        }]\n      },\n      server: {\n        options: {\n          optional: ['runtime']\n        },\n        files: [{\n          expand: true,\n          cwd: '<%= yeoman.server %>',\n          src: ['**/*.js'],\n          dest: '<%= yeoman.dist %>/<%= yeoman.server %>'\n        }]\n      }\n    },\n\n    // Compiles Sass to CSS\n    sass: {\n      server: {\n        options: {\n          compass: false\n        },\n        files: {\n          '.tmp/app/app.css' : '<%= yeoman.client %>/app/app.scss'\n        }\n      }\n    },\n\n    injector: {\n      options: {},\n      // Inject application script files into index.html (doesn't include bower)\n      scripts: {\n        options: {\n          transform: function(filePath) {\n            var yoClient = grunt.config.get('yeoman.client');\n            filePath = filePath.replace('/' + yoClient + '/', '');\n            filePath = filePath.replace('/.tmp/', '');\n            return '<script src=\"' + filePath + '\"></script>';\n          },\n          sort: function(a, b) {\n            var module = /\\.module\\.js$/;\n            var aMod = module.test(a);\n            var bMod = module.test(b);\n            // inject *.module.js first\n            return (aMod === bMod) ? 0 : (aMod ? -1 : 1);\n          },\n          starttag: '<!-- injector:js -->',\n          endtag: '<!-- endinjector -->'\n        },\n        files: {\n          '<%= yeoman.client %>/index.html': [\n               [\n                 '<%= yeoman.client %>/{app,components}/**/!(*.spec|*.mock).js',\n                 '!{.tmp,<%= yeoman.client %>}/app/app.{js,ts}'\n               ]\n            ]\n        }\n      },\n\n      // Inject component scss into app.scss\n      sass: {\n        options: {\n          transform: function(filePath) {\n            var yoClient = grunt.config.get('yeoman.client');\n            filePath = filePath.replace('/' + yoClient + '/app/', '');\n            filePath = filePath.replace('/' + yoClient + '/components/', '../components/');\n            return '@import \\'' + filePath + '\\';';\n          },\n          starttag: '// injector',\n          endtag: '// endinjector'\n        },\n        files: {\n          '<%= yeoman.client %>/app/app.scss': [\n            '<%= yeoman.client %>/{app,components}/**/*.{scss,sass}',\n            '!<%= yeoman.client %>/app/app.{scss,sass}'\n          ]\n        }\n      },\n\n      // Inject component css into index.html\n      css: {\n        options: {\n          transform: function(filePath) {\n            var yoClient = grunt.config.get('yeoman.client');\n            filePath = filePath.replace('/' + yoClient + '/', '');\n            filePath = filePath.replace('/.tmp/', '');\n            return '<link rel=\"stylesheet\" href=\"' + filePath + '\">';\n          },\n          starttag: '<!-- injector:css -->',\n          endtag: '<!-- endinjector -->'\n        },\n        files: {\n          '<%= yeoman.client %>/index.html': [\n            '<%= yeoman.client %>/{app,components}/**/*.css'\n          ]\n        }\n      }\n    },\n  });\n\n  // Used for delaying livereload until after server has restarted\n  grunt.registerTask('wait', function () {\n    grunt.log.ok('Waiting for server reload...');\n\n    var done = this.async();\n\n    setTimeout(function () {\n      grunt.log.writeln('Done waiting!');\n      done();\n    }, 1500);\n  });\n\n  grunt.registerTask('express-keepalive', 'Keep grunt running', function() {\n    this.async();\n  });\n\n  grunt.registerTask('serve', function (target) {\n    if (target === 'dist') {\n      return grunt.task.run(['build', 'env:all', 'env:prod', 'express:prod', 'wait', 'open', 'express-keepalive']);\n    }\n\n    if (target === 'debug') {\n      return grunt.task.run([\n        'clean:server',\n        'env:all',\n        'concurrent:pre',\n        'concurrent:server',\n        'injector',\n        'wiredep:client',\n        'postcss',\n        'concurrent:debug'\n      ]);\n    }\n\n    grunt.task.run([\n      'clean:server',\n      'env:all',\n      'concurrent:pre',\n      'concurrent:server',\n      'injector',\n      'wiredep:client',\n      'postcss',\n      'express:dev',\n      'wait',\n      'open',\n      'watch'\n    ]);\n  });\n\n  grunt.registerTask('server', function () {\n    grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');\n    grunt.task.run(['serve']);\n  });\n\n  grunt.registerTask('test', function(target, option) {\n    if (target === 'server') {\n      return grunt.task.run([\n        'env:all',\n        'env:test',\n        'mochaTest:unit',\n        'mochaTest:integration'\n      ]);\n    }\n\n    else if (target === 'client') {\n      return grunt.task.run([\n        'clean:server',\n        'env:all',\n        'concurrent:pre',\n        'concurrent:test',\n        'injector',\n        'postcss',\n        'wiredep:test',\n        'karma'\n      ]);\n    }\n\n    else if (target === 'e2e') {\n\n      if (option === 'prod') {\n        return grunt.task.run([\n          'build',\n          'env:all',\n          'env:prod',\n          'express:prod',\n          'protractor'\n        ]);\n      }\n\n      else {\n        return grunt.task.run([\n          'clean:server',\n          'env:all',\n          'env:test',\n          'concurrent:pre',\n          'concurrent:test',\n          'injector',\n          'wiredep:client',\n          'postcss',\n          'express:dev',\n          'protractor'\n        ]);\n      }\n    }\n\n    else if (target === 'coverage') {\n\n      if (option === 'unit') {\n        return grunt.task.run([\n          'env:all',\n          'env:test',\n          'mocha_istanbul:unit'\n        ]);\n      }\n\n      else if (option === 'integration') {\n        return grunt.task.run([\n          'env:all',\n          'env:test',\n          'mocha_istanbul:integration'\n        ]);\n      }\n\n      else if (option === 'check') {\n        return grunt.task.run([\n          'istanbul_check_coverage'\n        ]);\n      }\n\n      else {\n        return grunt.task.run([\n          'env:all',\n          'env:test',\n          'mocha_istanbul',\n          'istanbul_check_coverage'\n        ]);\n      }\n\n    }\n\n    else grunt.task.run([\n      'test:server',\n      'test:client'\n    ]);\n  });\n\n  grunt.registerTask('build', [\n    'clean:dist',\n    'concurrent:pre',\n    'concurrent:dist',\n    'injector',\n    'wiredep:client',\n    'useminPrepare',\n    'postcss',\n    'ngtemplates',\n    'concat',\n    'ngAnnotate',\n    'copy:dist',\n    'babel:server',\n    'cdnify',\n    'cssmin',\n    'uglify',\n    'filerev',\n    'usemin'\n  ]);\n\n  grunt.registerTask('default', [\n    'newer:jshint',\n    'test',\n    'build'\n  ]);\n};\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Gino, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "# PaizaQA\n\nPaizaQA is a Open Source QA service(like StackOverflow) using MEAN stack.\n\nThis project was generated with the [Angular Full-Stack Generator](https://github.com/DaftMonk/generator-angular-fullstack) version 3.3.0.\n\n## Blog article\nThe following blog article explains how to build the QA service using MEAN stack.\n\nEnglish: [Building a QA web service in an hour - MEAN stack development(3)](http://engineering.paiza.io/entry/2016/03/10/115345)\n\nJapanese: [Webサービスを作りたい人に最適、たった1時間でJSベースのQAサイトを作る方法 - MEANスタック開発(3)](http://paiza.hatenablog.com/entry/meanstack_howto_3)\n\n\n\n## Demo\n[http://paizaqa.herokuapp.com](http://paizaqa.herokuapp.com)\n\n\n## Getting Started\n\n### Prerequisites\n\n- [Git](https://git-scm.com/)\n- [Node.js and npm](nodejs.org) Node ^4.2.3, npm ^2.14.7\n- [Bower](bower.io) (`npm install --global bower`)\n- [Ruby](https://www.ruby-lang.org) and then `gem install sass`\n- [Grunt](http://gruntjs.com/) (`npm install --global grunt-cli`)\n- [MongoDB](https://www.mongodb.org/) - Keep a running daemon with `mongod`\n\n### Developing\n\n1. Run `npm install` to install server dependencies.\n\n2. Run `bower install` to install front-end dependencies.\n\n3. Run `mongod` in a separate shell to keep an instance of the MongoDB Daemon running\n\n4. Run `grunt serve` to start the development server. It should automatically open the client in your browser when ready.\n\n## Build & development\n\nRun `grunt build` for building and `grunt serve` for preview.\n\n## Testing\n\nRunning `npm test` will run the unit tests with karma.\n"
  },
  {
    "path": "bower.json",
    "content": "{\n  \"name\": \"paizaqa\",\n  \"version\": \"0.0.0\",\n  \"dependencies\": {\n    \"angular\": \"~1.4.0\",\n    \"json3\": \"~3.3.1\",\n    \"es5-shim\": \"~3.0.1\",\n    \"bootstrap-sass-official\": \"~3.1.1\",\n    \"bootstrap\": \"~3.1.1\",\n    \"bootstrap-social\": \"~4.9.1\",\n    \"angular-resource\": \"~1.4.0\",\n    \"angular-cookies\": \"~1.4.0\",\n    \"angular-sanitize\": \"~1.4.0\",\n    \"angular-bootstrap\": \"~0.13.0\",\n    \"font-awesome\": \">=4.1.0\",\n    \"lodash\": \"~2.4.1\",\n    \"angular-socket-io\": \"~0.7.0\",\n    \"angular-ui-router\": \"~0.2.15\",\n    \"angular-validation-match\": \"~1.5.2\",\n    \"angular-pagedown\": \"^0.4.4\",\n    \"ng-tags-input\": \"^3.0.0\",\n    \"angular-messages\": \"^1.5.0\",\n    \"moment\": \"momentjs#^2.12.0\",\n    \"ngInfiniteScroll\": \"^1.2.2\"\n  },\n  \"devDependencies\": {\n    \"angular-mocks\": \"~1.4.0\"\n  },\n  \"overrides\": {\n    \"pagedown\": {\n      \"main\": [\n        \"Markdown.Converter.js\",\n        \"Markdown.Sanitizer.js\",\n        \"Markdown.Extra.js\",\n        \"Markdown.Editor.js\",\n        \"wmd-buttons.png\"\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "client/.htaccess",
    "content": "# Apache Configuration File\n\n# (!) Using `.htaccess` files slows down Apache, therefore, if you have access\n# to the main server config file (usually called `httpd.conf`), you should add\n# this logic there: http://httpd.apache.org/docs/current/howto/htaccess.html.\n\n# ##############################################################################\n# # CROSS-ORIGIN RESOURCE SHARING (CORS)                                       #\n# ##############################################################################\n\n# ------------------------------------------------------------------------------\n# | Cross-domain AJAX requests                                                 |\n# ------------------------------------------------------------------------------\n\n# Enable cross-origin AJAX requests.\n# http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity\n# http://enable-cors.org/\n\n# <IfModule mod_headers.c>\n#    Header set Access-Control-Allow-Origin \"*\"\n# </IfModule>\n\n# ------------------------------------------------------------------------------\n# | CORS-enabled images                                                        |\n# ------------------------------------------------------------------------------\n\n# Send the CORS header for images when browsers request it.\n# https://developer.mozilla.org/en/CORS_Enabled_Image\n# http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html\n# http://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/\n\n<IfModule mod_setenvif.c>\n    <IfModule mod_headers.c>\n        <FilesMatch \"\\.(gif|ico|jpe?g|png|svg|svgz|webp)$\">\n            SetEnvIf Origin \":\" IS_CORS\n            Header set Access-Control-Allow-Origin \"*\" env=IS_CORS\n        </FilesMatch>\n    </IfModule>\n</IfModule>\n\n# ------------------------------------------------------------------------------\n# | Web fonts access                                                           |\n# ------------------------------------------------------------------------------\n\n# Allow access from all domains for web fonts\n\n<IfModule mod_headers.c>\n    <FilesMatch \"\\.(eot|font.css|otf|ttc|ttf|woff)$\">\n        Header set Access-Control-Allow-Origin \"*\"\n    </FilesMatch>\n</IfModule>\n\n\n# ##############################################################################\n# # ERRORS                                                                     #\n# ##############################################################################\n\n# ------------------------------------------------------------------------------\n# | 404 error prevention for non-existing redirected folders                   |\n# ------------------------------------------------------------------------------\n\n# Prevent Apache from returning a 404 error for a rewrite if a directory\n# with the same name does not exist.\n# http://httpd.apache.org/docs/current/content-negotiation.html#multiviews\n# http://www.webmasterworld.com/apache/3808792.htm\n\nOptions -MultiViews\n\n# ------------------------------------------------------------------------------\n# | Custom error messages / pages                                              |\n# ------------------------------------------------------------------------------\n\n# You can customize what Apache returns to the client in case of an error (see\n# http://httpd.apache.org/docs/current/mod/core.html#errordocument), e.g.:\n\nErrorDocument 404 /404.html\n\n\n# ##############################################################################\n# # INTERNET EXPLORER                                                          #\n# ##############################################################################\n\n# ------------------------------------------------------------------------------\n# | Better website experience                                                  |\n# ------------------------------------------------------------------------------\n\n# Force IE to render pages in the highest available mode in the various\n# cases when it may not: http://hsivonen.iki.fi/doctype/ie-mode.pdf.\n\n<IfModule mod_headers.c>\n    Header set X-UA-Compatible \"IE=edge\"\n    # `mod_headers` can't match based on the content-type, however, we only\n    # want to send this header for HTML pages and not for the other resources\n    <FilesMatch \"\\.(appcache|crx|css|eot|gif|htc|ico|jpe?g|js|m4a|m4v|manifest|mp4|oex|oga|ogg|ogv|otf|pdf|png|safariextz|svg|svgz|ttf|vcf|webapp|webm|webp|woff|xml|xpi)$\">\n        Header unset X-UA-Compatible\n    </FilesMatch>\n</IfModule>\n\n# ------------------------------------------------------------------------------\n# | Cookie setting from iframes                                                |\n# ------------------------------------------------------------------------------\n\n# Allow cookies to be set from iframes in IE.\n\n# <IfModule mod_headers.c>\n#   Header set P3P \"policyref=\\\"/w3c/p3p.xml\\\", CP=\\\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\\\"\"\n# </IfModule>\n\n# ------------------------------------------------------------------------------\n# | Screen flicker                                                             |\n# ------------------------------------------------------------------------------\n\n# Stop screen flicker in IE on CSS rollovers (this only works in\n# combination with the `ExpiresByType` directives for images from below).\n\n# BrowserMatch \"MSIE\" brokenvary=1\n# BrowserMatch \"Mozilla/4.[0-9]{2}\" brokenvary=1\n# BrowserMatch \"Opera\" !brokenvary\n# SetEnvIf brokenvary 1 force-no-vary\n\n\n# ##############################################################################\n# # MIME TYPES AND ENCODING                                                    #\n# ##############################################################################\n\n# ------------------------------------------------------------------------------\n# | Proper MIME types for all files                                            |\n# ------------------------------------------------------------------------------\n\n<IfModule mod_mime.c>\n\n  # Audio\n    AddType audio/mp4                                   m4a f4a f4b\n    AddType audio/ogg                                   oga ogg\n\n  # JavaScript\n    # Normalize to standard type (it's sniffed in IE anyways):\n    # http://tools.ietf.org/html/rfc4329#section-7.2\n    AddType application/javascript                      js jsonp\n    AddType application/json                            json\n\n  # Video\n    AddType video/mp4                                   mp4 m4v f4v f4p\n    AddType video/ogg                                   ogv\n    AddType video/webm                                  webm\n    AddType video/x-flv                                 flv\n\n  # Web fonts\n    AddType application/font-woff                       woff\n    AddType application/vnd.ms-fontobject               eot\n\n    # Browsers usually ignore the font MIME types and sniff the content,\n    # however, Chrome shows a warning if other MIME types are used for the\n    # following fonts.\n    AddType application/x-font-ttf                      ttc ttf\n    AddType font/opentype                               otf\n\n    # Make SVGZ fonts work on iPad:\n    # https://twitter.com/FontSquirrel/status/14855840545\n    AddType     image/svg+xml                           svg svgz\n    AddEncoding gzip                                    svgz\n\n  # Other\n    AddType application/octet-stream                    safariextz\n    AddType application/x-chrome-extension              crx\n    AddType application/x-opera-extension               oex\n    AddType application/x-shockwave-flash               swf\n    AddType application/x-web-app-manifest+json         webapp\n    AddType application/x-xpinstall                     xpi\n    AddType application/xml                             atom rdf rss xml\n    AddType image/webp                                  webp\n    AddType image/x-icon                                ico\n    AddType text/cache-manifest                         appcache manifest\n    AddType text/vtt                                    vtt\n    AddType text/x-component                            htc\n    AddType text/x-vcard                                vcf\n\n</IfModule>\n\n# ------------------------------------------------------------------------------\n# | UTF-8 encoding                                                             |\n# ------------------------------------------------------------------------------\n\n# Use UTF-8 encoding for anything served as `text/html` or `text/plain`.\nAddDefaultCharset utf-8\n\n# Force UTF-8 for certain file formats.\n<IfModule mod_mime.c>\n    AddCharset utf-8 .atom .css .js .json .rss .vtt .webapp .xml\n</IfModule>\n\n\n# ##############################################################################\n# # URL REWRITES                                                               #\n# ##############################################################################\n\n# ------------------------------------------------------------------------------\n# | Rewrite engine                                                             |\n# ------------------------------------------------------------------------------\n\n# Turning on the rewrite engine and enabling the `FollowSymLinks` option is\n# necessary for the following directives to work.\n\n# If your web host doesn't allow the `FollowSymlinks` option, you may need to\n# comment it out and use `Options +SymLinksIfOwnerMatch` but, be aware of the\n# performance impact: http://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks\n\n# Also, some cloud hosting services require `RewriteBase` to be set:\n# http://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-mod-rewrite-not-working-on-my-site\n\n<IfModule mod_rewrite.c>\n    Options +FollowSymlinks\n  # Options +SymLinksIfOwnerMatch\n    RewriteEngine On\n  # RewriteBase /\n</IfModule>\n\n# ------------------------------------------------------------------------------\n# | Suppressing / Forcing the \"www.\" at the beginning of URLs                  |\n# ------------------------------------------------------------------------------\n\n# The same content should never be available under two different URLs especially\n# not with and without \"www.\" at the beginning. This can cause SEO problems\n# (duplicate content), therefore, you should choose one of the alternatives and\n# redirect the other one.\n\n# By default option 1 (no \"www.\") is activated:\n# http://no-www.org/faq.php?q=class_b\n\n# If you'd prefer to use option 2, just comment out all the lines from option 1\n# and uncomment the ones from option 2.\n\n# IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME!\n\n# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n\n# Option 1: rewrite www.example.com → example.com\n\n<IfModule mod_rewrite.c>\n    RewriteCond %{HTTPS} !=on\n    RewriteCond %{HTTP_HOST} ^www\\.(.+)$ [NC]\n    RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]\n</IfModule>\n\n# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n\n# Option 2: rewrite example.com → www.example.com\n\n# Be aware that the following might not be a good idea if you use \"real\"\n# subdomains for certain parts of your website.\n\n# <IfModule mod_rewrite.c>\n#    RewriteCond %{HTTPS} !=on\n#    RewriteCond %{HTTP_HOST} !^www\\..+$ [NC]\n#    RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]\n# </IfModule>\n\n\n# ##############################################################################\n# # SECURITY                                                                   #\n# ##############################################################################\n\n# ------------------------------------------------------------------------------\n# | Content Security Policy (CSP)                                              |\n# ------------------------------------------------------------------------------\n\n# You can mitigate the risk of cross-site scripting and other content-injection\n# attacks by setting a Content Security Policy which whitelists trusted sources\n# of content for your site.\n\n# The example header below allows ONLY scripts that are loaded from the current\n# site's origin (no inline scripts, no CDN, etc). This almost certainly won't\n# work as-is for your site!\n\n# To get all the details you'll need to craft a reasonable policy for your site,\n# read: http://html5rocks.com/en/tutorials/security/content-security-policy (or\n# see the specification: http://w3.org/TR/CSP).\n\n# <IfModule mod_headers.c>\n#    Header set Content-Security-Policy \"script-src 'self'; object-src 'self'\"\n#    <FilesMatch \"\\.(appcache|crx|css|eot|gif|htc|ico|jpe?g|js|m4a|m4v|manifest|mp4|oex|oga|ogg|ogv|otf|pdf|png|safariextz|svg|svgz|ttf|vcf|webapp|webm|webp|woff|xml|xpi)$\">\n#        Header unset Content-Security-Policy\n#    </FilesMatch>\n# </IfModule>\n\n# ------------------------------------------------------------------------------\n# | File access                                                                |\n# ------------------------------------------------------------------------------\n\n# Block access to directories without a default document.\n# Usually you should leave this uncommented because you shouldn't allow anyone\n# to surf through every directory on your server (which may includes rather\n# private places like the CMS's directories).\n\n<IfModule mod_autoindex.c>\n    Options -Indexes\n</IfModule>\n\n# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n\n# Block access to hidden files and directories.\n# This includes directories used by version control systems such as Git and SVN.\n\n<IfModule mod_rewrite.c>\n    RewriteCond %{SCRIPT_FILENAME} -d [OR]\n    RewriteCond %{SCRIPT_FILENAME} -f\n    RewriteRule \"(^|/)\\.\" - [F]\n</IfModule>\n\n# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n\n# Block access to backup and source files.\n# These files may be left by some text editors and can pose a great security\n# danger when anyone has access to them.\n\n<FilesMatch \"(^#.*#|\\.(bak|config|dist|fla|inc|ini|log|psd|sh|sql|sw[op])|~)$\">\n    Order allow,deny\n    Deny from all\n    Satisfy All\n</FilesMatch>\n\n# ------------------------------------------------------------------------------\n# | Secure Sockets Layer (SSL)                                                 |\n# ------------------------------------------------------------------------------\n\n# Rewrite secure requests properly to prevent SSL certificate warnings, e.g.:\n# prevent `https://www.example.com` when your certificate only allows\n# `https://secure.example.com`.\n\n# <IfModule mod_rewrite.c>\n#    RewriteCond %{SERVER_PORT} !^443\n#    RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L]\n# </IfModule>\n\n# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n\n# Force client-side SSL redirection.\n\n# If a user types \"example.com\" in his browser, the above rule will redirect him\n# to the secure version of the site. That still leaves a window of opportunity\n# (the initial HTTP connection) for an attacker to downgrade or redirect the\n# request. The following header ensures that browser will ONLY connect to your\n# server via HTTPS, regardless of what the users type in the address bar.\n# http://www.html5rocks.com/en/tutorials/security/transport-layer-security/\n\n# <IfModule mod_headers.c>\n#    Header set Strict-Transport-Security max-age=16070400;\n# </IfModule>\n\n# ------------------------------------------------------------------------------\n# | Server software information                                                |\n# ------------------------------------------------------------------------------\n\n# Avoid displaying the exact Apache version number, the description of the\n# generic OS-type and the information about Apache's compiled-in modules.\n\n# ADD THIS DIRECTIVE IN THE `httpd.conf` AS IT WILL NOT WORK IN THE `.htaccess`!\n\n# ServerTokens Prod\n\n\n# ##############################################################################\n# # WEB PERFORMANCE                                                            #\n# ##############################################################################\n\n# ------------------------------------------------------------------------------\n# | Compression                                                                |\n# ------------------------------------------------------------------------------\n\n<IfModule mod_deflate.c>\n\n    # Force compression for mangled headers.\n    # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping\n    <IfModule mod_setenvif.c>\n        <IfModule mod_headers.c>\n            SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\\s*,?\\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding\n            RequestHeader append Accept-Encoding \"gzip,deflate\" env=HAVE_Accept-Encoding\n        </IfModule>\n    </IfModule>\n\n    # Compress all output labeled with one of the following MIME-types\n    # (for Apache versions below 2.3.7, you don't need to enable `mod_filter`\n    #  and can remove the `<IfModule mod_filter.c>` and `</IfModule>` lines\n    #  as `AddOutputFilterByType` is still in the core directives).\n    <IfModule mod_filter.c>\n        AddOutputFilterByType DEFLATE application/atom+xml \\\n                                      application/javascript \\\n                                      application/json \\\n                                      application/rss+xml \\\n                                      application/vnd.ms-fontobject \\\n                                      application/x-font-ttf \\\n                                      application/x-web-app-manifest+json \\\n                                      application/xhtml+xml \\\n                                      application/xml \\\n                                      font/opentype \\\n                                      image/svg+xml \\\n                                      image/x-icon \\\n                                      text/css \\\n                                      text/html \\\n                                      text/plain \\\n                                      text/x-component \\\n                                      text/xml\n    </IfModule>\n\n</IfModule>\n\n# ------------------------------------------------------------------------------\n# | Content transformations                                                    |\n# ------------------------------------------------------------------------------\n\n# Prevent some of the mobile network providers from modifying the content of\n# your site: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5.\n\n# <IfModule mod_headers.c>\n#    Header set Cache-Control \"no-transform\"\n# </IfModule>\n\n# ------------------------------------------------------------------------------\n# | ETag removal                                                               |\n# ------------------------------------------------------------------------------\n\n# Since we're sending far-future expires headers (see below), ETags can\n# be removed: http://developer.yahoo.com/performance/rules.html#etags.\n\n# `FileETag None` is not enough for every server.\n<IfModule mod_headers.c>\n    Header unset ETag\n</IfModule>\n\nFileETag None\n\n# ------------------------------------------------------------------------------\n# | Expires headers (for better cache control)                                 |\n# ------------------------------------------------------------------------------\n\n# The following expires headers are set pretty far in the future. If you don't\n# control versioning with filename-based cache busting, consider lowering the\n# cache time for resources like CSS and JS to something like 1 week.\n\n<IfModule mod_expires.c>\n\n    ExpiresActive on\n    ExpiresDefault                                      \"access plus 1 month\"\n\n  # CSS\n    ExpiresByType text/css                              \"access plus 1 year\"\n\n  # Data interchange\n    ExpiresByType application/json                      \"access plus 0 seconds\"\n    ExpiresByType application/xml                       \"access plus 0 seconds\"\n    ExpiresByType text/xml                              \"access plus 0 seconds\"\n\n  # Favicon (cannot be renamed!)\n    ExpiresByType image/x-icon                          \"access plus 1 week\"\n\n  # HTML components (HTCs)\n    ExpiresByType text/x-component                      \"access plus 1 month\"\n\n  # HTML\n    ExpiresByType text/html                             \"access plus 0 seconds\"\n\n  # JavaScript\n    ExpiresByType application/javascript                \"access plus 1 year\"\n\n  # Manifest files\n    ExpiresByType application/x-web-app-manifest+json   \"access plus 0 seconds\"\n    ExpiresByType text/cache-manifest                   \"access plus 0 seconds\"\n\n  # Media\n    ExpiresByType audio/ogg                             \"access plus 1 month\"\n    ExpiresByType image/gif                             \"access plus 1 month\"\n    ExpiresByType image/jpeg                            \"access plus 1 month\"\n    ExpiresByType image/png                             \"access plus 1 month\"\n    ExpiresByType video/mp4                             \"access plus 1 month\"\n    ExpiresByType video/ogg                             \"access plus 1 month\"\n    ExpiresByType video/webm                            \"access plus 1 month\"\n\n  # Web feeds\n    ExpiresByType application/atom+xml                  \"access plus 1 hour\"\n    ExpiresByType application/rss+xml                   \"access plus 1 hour\"\n\n  # Web fonts\n    ExpiresByType application/font-woff                 \"access plus 1 month\"\n    ExpiresByType application/vnd.ms-fontobject         \"access plus 1 month\"\n    ExpiresByType application/x-font-ttf                \"access plus 1 month\"\n    ExpiresByType font/opentype                         \"access plus 1 month\"\n    ExpiresByType image/svg+xml                         \"access plus 1 month\"\n\n</IfModule>\n\n# ------------------------------------------------------------------------------\n# | Filename-based cache busting                                               |\n# ------------------------------------------------------------------------------\n\n# If you're not using a build process to manage your filename version revving,\n# you might want to consider enabling the following directives to route all\n# requests such as `/css/style.12345.css` to `/css/style.css`.\n\n# To understand why this is important and a better idea than `*.css?v231`, read:\n# http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring\n\n# <IfModule mod_rewrite.c>\n#    RewriteCond %{REQUEST_FILENAME} !-f\n#    RewriteCond %{REQUEST_FILENAME} !-d\n#    RewriteRule ^(.+)\\.(\\d+)\\.(js|css|png|jpg|gif)$ $1.$3 [L]\n# </IfModule>\n\n# ------------------------------------------------------------------------------\n# | File concatenation                                                         |\n# ------------------------------------------------------------------------------\n\n# Allow concatenation from within specific CSS and JS files, e.g.:\n# Inside of `script.combined.js` you could have\n#   <!--#include file=\"libs/jquery.js\" -->\n#   <!--#include file=\"plugins/jquery.idletimer.js\" -->\n# and they would be included into this single file.\n\n# <IfModule mod_include.c>\n#    <FilesMatch \"\\.combined\\.js$\">\n#        Options +Includes\n#        AddOutputFilterByType INCLUDES application/javascript application/json\n#        SetOutputFilter INCLUDES\n#    </FilesMatch>\n#    <FilesMatch \"\\.combined\\.css$\">\n#        Options +Includes\n#        AddOutputFilterByType INCLUDES text/css\n#        SetOutputFilter INCLUDES\n#    </FilesMatch>\n# </IfModule>\n\n# ------------------------------------------------------------------------------\n# | Persistent connections                                                     |\n# ------------------------------------------------------------------------------\n\n# Allow multiple requests to be sent over the same TCP connection:\n# http://httpd.apache.org/docs/current/en/mod/core.html#keepalive.\n\n# Enable if you serve a lot of static content but, be aware of the\n# possible disadvantages!\n\n# <IfModule mod_headers.c>\n#    Header set Connection Keep-Alive\n# </IfModule>\n"
  },
  {
    "path": "client/.jshintrc",
    "content": "{\n  \"node\": true,\n  \"browser\": true,\n  \"esnext\": true,\n  \"bitwise\": true,\n  \"camelcase\": true,\n  \"curly\": true,\n  \"eqeqeq\": true,\n  \"immed\": true,\n  \"latedef\": true,\n  \"newcap\": true,\n  \"noarg\": true,\n  \"quotmark\": \"single\",\n  \"undef\": true,\n  \"unused\": true,\n  \"strict\": true,\n  \"trailing\": true,\n  \"smarttabs\": true,\n  \"ignoreDelimiters\": [\n    { \"start\": \"start-non-standard\", \"end\": \"end-non-standard\" }\n  ],\n  \"globals\": {\n    \"jQuery\": true,\n    \"angular\": true,\n    \"console\": true,\n    \"$\": true,\n    \"_\": true,\n    \"moment\": true,\n    \"jasmine\": true,\n    \"describe\": true,\n    \"beforeEach\": true,\n    \"module\": true,\n    \"inject\": true,\n    \"it\": true,\n    \"expect\": true,\n    \"browser\": true,\n    \"element\": true,\n    \"by\": true\n  }\n}\n"
  },
  {
    "path": "client/app/account/account.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp')\n  .config(function($stateProvider) {\n    $stateProvider\n      .state('login', {\n        url: '/login',\n        templateUrl: 'app/account/login/login.html',\n        controller: 'LoginController',\n        controllerAs: 'vm'\n      })\n      .state('logout', {\n        url: '/logout?referrer',\n        referrer: 'main',\n        template: '',\n        controller: function($state, Auth) {\n          var referrer = $state.params.referrer ||\n                          $state.current.referrer ||\n                          'main';\n          Auth.logout();\n          $state.go(referrer);\n        }\n      })\n      .state('signup', {\n        url: '/signup',\n        templateUrl: 'app/account/signup/signup.html',\n        controller: 'SignupController',\n        controllerAs: 'vm'\n      })\n      .state('settings', {\n        url: '/settings',\n        templateUrl: 'app/account/settings/settings.html',\n        controller: 'SettingsController',\n        controllerAs: 'vm',\n        authenticate: true\n      });\n  })\n  .run(function($rootScope) {\n    $rootScope.$on('$stateChangeStart', function(event, next, nextParams, current) {\n      if (next.name === 'logout' && current && current.name && !current.authenticate) {\n        next.referrer = current.name;\n      }\n    });\n  });\n"
  },
  {
    "path": "client/app/account/login/login.controller.js",
    "content": "'use strict';\n\nclass LoginController {\n  constructor(Auth, $state) {\n    this.user = {};\n    this.errors = {};\n    this.submitted = false;\n\n    this.Auth = Auth;\n    this.$state = $state;\n  }\n\n  login(form) {\n    this.submitted = true;\n\n    if (form.$valid) {\n      this.Auth.login({\n        email: this.user.email,\n        password: this.user.password\n      })\n      .then(() => {\n        // Logged in, redirect to home\n        this.$state.go('main');\n      })\n      .catch(err => {\n        this.errors.other = err.message;\n      });\n    }\n  }\n}\n\nangular.module('paizaqaApp')\n  .controller('LoginController', LoginController);\n"
  },
  {
    "path": "client/app/account/login/login.html",
    "content": "<div class=\"container\">\n  <div class=\"row\">\n    <div class=\"col-sm-12\">\n      <h1>Login</h1>\n      <p>Accounts are reset on server restart from <code>server/config/seed.js</code>. Default account is <code>test@example.com</code> / <code>test</code></p>\n      <p>Admin account is <code>admin@example.com</code> / <code>admin</code></p>\n    </div>\n    <div class=\"col-sm-12\">\n      <form class=\"form\" name=\"form\" ng-submit=\"vm.login(form)\" novalidate>\n\n        <div class=\"form-group\">\n          <label>Email</label>\n\n          <input type=\"email\" name=\"email\" class=\"form-control\" ng-model=\"vm.user.email\" required>\n        </div>\n\n        <div class=\"form-group\">\n          <label>Password</label>\n\n          <input type=\"password\" name=\"password\" class=\"form-control\" ng-model=\"vm.user.password\" required>\n        </div>\n\n        <div class=\"form-group has-error\">\n          <p class=\"help-block\" ng-show=\"form.email.$error.required && form.password.$error.required && vm.submitted\">\n             Please enter your email and password.\n          </p>\n          <p class=\"help-block\" ng-show=\"form.email.$error.email && vm.submitted\">\n             Please enter a valid email.\n          </p>\n\n          <p class=\"help-block\">{{ vm.errors.other }}</p>\n        </div>\n\n        <div>\n          <button class=\"btn btn-inverse btn-lg btn-login\" type=\"submit\">\n            Login\n          </button>\n          <a class=\"btn btn-default btn-lg btn-register\" ui-sref=\"signup\">\n            Register\n          </a>\n        </div>\n\n        <hr/>\n        <div class=\"row\">\n          <div class=\"col-sm-4 col-md-3\">\n            <oauth-buttons classes=\"btn-block\"></oauth-buttons>\n          </div>\n        </div>\n      </form>\n    </div>\n  </div>\n  <hr>\n</div>\n"
  },
  {
    "path": "client/app/account/settings/settings.controller.js",
    "content": "'use strict';\n\nclass SettingsController {\n  constructor(Auth) {\n    this.errors = {};\n    this.submitted = false;\n\n    this.Auth = Auth;\n  }\n\n  changePassword(form) {\n    this.submitted = true;\n\n    if (form.$valid) {\n      this.Auth.changePassword(this.user.oldPassword, this.user.newPassword)\n        .then(() => {\n          this.message = 'Password successfully changed.';\n        })\n        .catch(() => {\n          form.password.$setValidity('mongoose', false);\n          this.errors.other = 'Incorrect password';\n          this.message = '';\n        });\n    }\n  }\n}\n\nangular.module('paizaqaApp')\n  .controller('SettingsController', SettingsController);\n"
  },
  {
    "path": "client/app/account/settings/settings.html",
    "content": "<div class=\"container\">\n  <div class=\"row\">\n    <div class=\"col-sm-12\">\n      <h1>Change Password</h1>\n    </div>\n    <div class=\"col-sm-12\">\n      <form class=\"form\" name=\"form\" ng-submit=\"vm.changePassword(form)\" novalidate>\n\n        <div class=\"form-group\">\n          <label>Current Password</label>\n\n          <input type=\"password\" name=\"password\" class=\"form-control\" ng-model=\"vm.user.oldPassword\"\n                 mongoose-error/>\n          <p class=\"help-block\" ng-show=\"form.password.$error.mongoose\">\n              {{ vm.errors.other }}\n          </p>\n        </div>\n\n        <div class=\"form-group\">\n          <label>New Password</label>\n\n          <input type=\"password\" name=\"newPassword\" class=\"form-control\" ng-model=\"vm.user.newPassword\"\n                 ng-minlength=\"3\"\n                 required/>\n          <p class=\"help-block\"\n             ng-show=\"(form.newPassword.$error.minlength || form.newPassword.$error.required) && (form.newPassword.$dirty || vm.submitted)\">\n            Password must be at least 3 characters.\n          </p>\n        </div>\n\n        <div class=\"form-group\">\n          <label>Confirm New Password</label>\n\n          <input type=\"password\" name=\"confirmPassword\" class=\"form-control\" ng-model=\"vm.user.confirmPassword\"\n                 match=\"vm.user.newPassword\"\n                 ng-minlength=\"3\"\n                 required=\"\"/>\n          <p class=\"help-block\"\n             ng-show=\"form.confirmPassword.$error.match && vm.submitted\">\n            Passwords must match.\n          </p>\n\n        </div>\n\n        <p class=\"help-block\"> {{ vm.message }} </p>\n\n        <button class=\"btn btn-lg btn-primary\" type=\"submit\">Save changes</button>\n      </form>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "client/app/account/signup/signup.controller.js",
    "content": "'use strict';\n\nclass SignupController {\n  //start-non-standard\n  user = {};\n  errors = {};\n  submitted = false;\n  //end-non-standard\n\n  constructor(Auth, $state) {\n    this.Auth = Auth;\n    this.$state = $state;\n  }\n\n  register(form) {\n    this.submitted = true;\n\n    if (form.$valid) {\n      this.Auth.createUser({\n        name: this.user.name,\n        email: this.user.email,\n        password: this.user.password\n      })\n      .then(() => {\n        // Account created, redirect to home\n        this.$state.go('main');\n      })\n      .catch(err => {\n        err = err.data;\n        this.errors = {};\n\n        // Update validity of form fields that match the mongoose errors\n        angular.forEach(err.errors, (error, field) => {\n          form[field].$setValidity('mongoose', false);\n          this.errors[field] = error.message;\n        });\n      });\n    }\n  }\n}\n\nangular.module('paizaqaApp')\n  .controller('SignupController', SignupController);\n"
  },
  {
    "path": "client/app/account/signup/signup.html",
    "content": "<div class=\"container\">\n  <div class=\"row\">\n    <div class=\"col-sm-12\">\n      <h1>Sign up</h1>\n    </div>\n    <div class=\"col-sm-12\">\n      <form class=\"form\" name=\"form\" ng-submit=\"vm.register(form)\" novalidate>\n\n        <div class=\"form-group\" ng-class=\"{ 'has-success': form.name.$valid && vm.submitted,\n                                            'has-error': form.name.$invalid && vm.submitted }\">\n          <label>Name</label>\n\n          <input type=\"text\" name=\"name\" class=\"form-control\" ng-model=\"vm.user.name\"\n                 required/>\n          <p class=\"help-block\" ng-show=\"form.name.$error.required && vm.submitted\">\n            A name is required\n          </p>\n        </div>\n\n        <div class=\"form-group\" ng-class=\"{ 'has-success': form.email.$valid && vm.submitted,\n                                            'has-error': form.email.$invalid && vm.submitted }\">\n          <label>Email</label>\n\n          <input type=\"email\" name=\"email\" class=\"form-control\" ng-model=\"vm.user.email\"\n                 required\n                 mongoose-error/>\n          <p class=\"help-block\" ng-show=\"form.email.$error.email && vm.submitted\">\n            Doesn't look like a valid email.\n          </p>\n          <p class=\"help-block\" ng-show=\"form.email.$error.required && vm.submitted\">\n            What's your email address?\n          </p>\n          <p class=\"help-block\" ng-show=\"form.email.$error.mongoose\">\n            {{ vm.errors.email }}\n          </p>\n        </div>\n\n        <div class=\"form-group\" ng-class=\"{ 'has-success': form.password.$valid && vm.submitted,\n                                            'has-error': form.password.$invalid && vm.submitted }\">\n          <label>Password</label>\n\n          <input type=\"password\" name=\"password\" class=\"form-control\" ng-model=\"vm.user.password\"\n                 ng-minlength=\"3\"\n                 required\n                 mongoose-error/>\n          <p class=\"help-block\"\n             ng-show=\"(form.password.$error.minlength || form.password.$error.required) && vm.submitted\">\n            Password must be at least 3 characters.\n          </p>\n          <p class=\"help-block\" ng-show=\"form.password.$error.mongoose\">\n            {{ vm.errors.password }}\n          </p>\n        </div>\n\n        <div class=\"form-group\" ng-class=\"{ 'has-success': form.confirmPassword.$valid && vm.submitted,\n                                            'has-error': form.confirmPassword.$invalid && vm.submitted }\">\n          <label>Confirm Password</label>\n          <input type=\"password\" name=\"confirmPassword\" class=\"form-control\" ng-model=\"vm.user.confirmPassword\"\n                 match=\"vm.user.password\"\n                 ng-minlength=\"3\" required/>\n          <p class=\"help-block\"\n             ng-show=\"form.confirmPassword.$error.match && vm.submitted\">\n            Passwords must match.\n          </p>\n        </div>\n\n        <div>\n          <button class=\"btn btn-inverse btn-lg btn-register\" type=\"submit\">\n            Sign up\n          </button>\n          <a class=\"btn btn-default btn-lg btn-login\" ui-sref=\"login\">\n            Login\n          </a>\n        </div>\n\n        <hr/>\n        <div class=\"row\">\n          <div class=\"col-sm-4 col-md-3\">\n            <oauth-buttons classes=\"btn-block\"></oauth-buttons>\n          </div>\n        </div>\n      </form>\n    </div>\n  </div>\n  <hr>\n</div>\n"
  },
  {
    "path": "client/app/admin/admin.controller.js",
    "content": "'use strict';\n\n(function() {\n\nclass AdminController {\n  constructor(User) {\n    // Use the User $resource to fetch all users\n    this.users = User.query();\n  }\n\n  delete(user) {\n    user.$remove();\n    this.users.splice(this.users.indexOf(user), 1);\n  }\n}\n\nangular.module('paizaqaApp.admin')\n  .controller('AdminController', AdminController);\n\n})();\n"
  },
  {
    "path": "client/app/admin/admin.html",
    "content": "<div class=\"container\">\n  <p>The delete user and user index api routes are restricted to users with the 'admin' role.</p>\n  <ul class=\"list-group user-list\">\n    <li class=\"list-group-item\" ng-repeat=\"user in admin.users\">\n\t    <div class=\"user-info\">\n\t        <strong>{{user.name}}</strong><br>\n\t        <span class=\"text-muted\">{{user.email}}</span>\n\t    </div>\n        <a ng-click=\"admin.delete(user)\" class=\"trash\"><span class=\"fa fa-trash fa-2x\"></span></a>\n    </li>\n  </ul>\n</div>\n"
  },
  {
    "path": "client/app/admin/admin.module.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp.admin', [\n  'paizaqaApp.auth',\n  'ui.router'\n]);\n"
  },
  {
    "path": "client/app/admin/admin.router.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp.admin')\n  .config(function($stateProvider) {\n    $stateProvider\n      .state('admin', {\n        url: '/admin',\n        templateUrl: 'app/admin/admin.html',\n        controller: 'AdminController',\n        controllerAs: 'admin',\n        authenticate: 'admin'\n      });\n  });\n"
  },
  {
    "path": "client/app/admin/admin.scss",
    "content": ".trash { color:rgb(209, 91, 71); }\n\n.user-list {\n\tli {\n\t\tdisplay: flex;\n\t\tborder: none;\n\t\tborder-bottom: 1px lightgray solid;\n\t\tmargin-bottom: 0;\n\t\t&:last-child { border-bottom: none; }\n\n\t\t.user-info {\n\t\t\tflex-grow: 1;\n\t\t}\n\t\t.trash {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\ttext-decoration: none;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "client/app/app.constant.js",
    "content": "(function(angular, undefined) {\n'use strict';\n\nangular.module('paizaqaApp.constants', [])\n\n.constant('appConfig', {userRoles:['guest','user','admin']})\n\n;\n})(angular);"
  },
  {
    "path": "client/app/app.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp', [\n  'paizaqaApp.auth',\n  'paizaqaApp.admin',\n  'paizaqaApp.constants',\n  'ngCookies',\n  'ngResource',\n  'ngSanitize',\n  'btford.socket-io',\n  'ui.router',\n  'ui.bootstrap',\n  'validation.match',\n  'ui.pagedown',\n  'ngTagsInput',\n  'ngMessages',\n  'infinite-scroll',\n])\n  .config(function($urlRouterProvider, $locationProvider) {\n    $urlRouterProvider\n      .otherwise('/');\n\n    $locationProvider.html5Mode(true);\n  });\n"
  },
  {
    "path": "client/app/app.scss",
    "content": "$icon-font-path: \"../bower_components/bootstrap-sass-official/vendor/assets/fonts/bootstrap/\";\n@import '../bower_components/bootstrap-sass-official/vendor/assets/stylesheets/bootstrap';\n@import '../bower_components/bootstrap-social/bootstrap-social.scss';\n$fa-font-path: \"../bower_components/font-awesome/fonts\";\n@import '../bower_components/font-awesome/scss/font-awesome';\n\n/**\n * App-wide Styles\n */\n\n.browserupgrade {\n  margin: 0.2em 0;\n  background: #ccc;\n  color: #000;\n  padding: 0.2em 0;\n}\n\n// Component styles are injected through grunt\n// injector\n@import 'admin/admin.scss';\n@import 'questionsCreate/questionsCreate.scss';\n@import 'questionsIndex/questionsIndex.scss';\n@import 'questionsShow/questionsShow.scss';\n@import '../components/footer/footer.scss';\n@import '../components/modal/modal.scss';\n@import '../components/oauth-buttons/oauth-buttons.scss';\n// endinjector\n"
  },
  {
    "path": "client/app/fromNow/fromNow.filter.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp')\n  .filter('fromNow', function () {\n    return function (input) {\n      return moment(input).locale(window.navigator.language).fromNow();\n    };\n  });\n"
  },
  {
    "path": "client/app/fromNow/fromNow.filter.spec.js",
    "content": "'use strict';\n\ndescribe('Filter: fromNow', function () {\n\n  // load the filter's module\n  beforeEach(module('paizaqaApp'));\n\n  // initialize a new instance of the filter before each test\n  var fromNow;\n  beforeEach(inject(function ($filter) {\n    fromNow = $filter('fromNow');\n  }));\n\n  it('return \"a few seconds ago\" for now', function () {\n    expect(fromNow(Date.now())).toBe('a few seconds ago');\n  });\n\n});\n"
  },
  {
    "path": "client/app/questionsCreate/questionsCreate.controller.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp')\n  .controller('QuestionsCreateCtrl', function ($scope, $http, $location, Auth) {\n    if(! Auth.isLoggedIn()){\n      $location.path('/login');\n      $location.replace();\n      return;\n    }\n    $scope.submit = function() {\n      $http.post('/api/questions', $scope.question).success(function(){\n        $location.path('/');\n      });\n    };\n  });\n"
  },
  {
    "path": "client/app/questionsCreate/questionsCreate.controller.spec.js",
    "content": "'use strict';\n\ndescribe('Controller: QuestionsCreateCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module('paizaqaApp'));\n\n  var QuestionsCreateCtrl, scope;\n\n  // Initialize the controller and a mock scope\n  beforeEach(inject(function ($controller, $rootScope) {\n    scope = $rootScope.$new();\n    QuestionsCreateCtrl = $controller('QuestionsCreateCtrl', {\n      $scope: scope\n    });\n  }));\n\n  it('should ...', function () {\n    expect(1).toEqual(1);\n  });\n});\n"
  },
  {
    "path": "client/app/questionsCreate/questionsCreate.html",
    "content": "<div class=\"container\">\n  <form name=\"form\" ng-submit=\"submit()\">\n    <h2>Title:</h2>\n    <input type=\"text\" class=\"form-control\" ng-model=\"question.title\" name=\"question_title\" required>\n    <span class=\"text-danger\" ng-messages=\"form.question_title.$error\">\n      <span ng-message=\"required\">Required</span>\n    </span>\n    <span class=\"text-success\" ng-show=\"form.question_title.$valid\">OK</span>\n    <br>\n    <h2>Question:</h2>\n    <pagedown-editor ng-model=\"question.content\" name=\"question_content\" required></pagedown-editor>\n    <span class=\"text-danger\" ng-messages=\"form.question_content.$error\">\n      <span ng-message=\"required\">Required</span>\n    </span>\n    <span class=\"text-success\" ng-show=\"form.question_content.$valid\">OK</span>\n    <h2>Tags:</h2>\n    <tags-input ng-model=\"question.tags\">\n      <!-- <auto-complete source=\"loadTags($query)\"></auto-complete> -->\n    </tags-input>\n    <input type=\"submit\" class=\"btn btn-primary\" ng-disabled=\"form.$invalid\" value=\"Post question\">\n  </form>\n</div>"
  },
  {
    "path": "client/app/questionsCreate/questionsCreate.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp')\n  .config(function ($stateProvider) {\n    $stateProvider\n      .state('questionsCreate', {\n        url: '/questions/create',\n        templateUrl: 'app/questionsCreate/questionsCreate.html',\n        controller: 'QuestionsCreateCtrl'\n      });\n  });\n"
  },
  {
    "path": "client/app/questionsCreate/questionsCreate.scss",
    "content": ""
  },
  {
    "path": "client/app/questionsIndex/questionsIndex.controller.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp')\n  .controller('QuestionsIndexCtrl', function ($scope, $http, $location, Auth, query) {\n    var keyword = $location.search().keyword;\n    if(keyword){\n      query = _.merge(query, {$text: {$search: keyword}});\n    }\n    $scope.busy = true;\n    $scope.noMoreData = false;\n\n    $http.get('/api/questions', {params: {query: query}}).success(function(questions) {\n      $scope.questions = questions;\n      if($scope.questions.length < 20){\n        $scope.noMoreData = true;\n      }\n      $scope.busy = false;\n    });\n    $scope.nextPage = function(){\n      if($scope.busy){ return; }\n      $scope.busy = true;\n      var lastId = $scope.questions[$scope.questions.length-1]._id;\n      var pageQuery = _.merge(query, {_id: {$lt: lastId}});\n      $http.get('/api/questions', {params: {query: pageQuery}}).success(function(questions){\n        $scope.questions = $scope.questions.concat(questions);\n        $scope.busy = false;\n        if(questions.length === 0){\n          $scope.noMoreData = true;\n        }\n      });\n    };\n    $scope.isStar = function(obj){\n      return Auth.isLoggedIn() && obj && obj.stars && obj.stars.indexOf(Auth.getCurrentUser()._id)!==-1;\n    };\n  });\n"
  },
  {
    "path": "client/app/questionsIndex/questionsIndex.controller.spec.js",
    "content": "'use strict';\n\ndescribe('Controller: QuestionsIndexCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module('paizaqaApp'));\n\n  var QuestionsIndexCtrl, scope;\n\n  // Initialize the controller and a mock scope\n  beforeEach(inject(function ($controller, $rootScope) {\n    scope = $rootScope.$new();\n    QuestionsIndexCtrl = $controller('QuestionsIndexCtrl', {\n      $scope: scope,\n      query: {},\n    });\n  }));\n\n  it('should ...', function () {\n    expect(1).toEqual(1);\n  });\n});\n"
  },
  {
    "path": "client/app/questionsIndex/questionsIndex.html",
    "content": "<header class=\"hero-unit\" id=\"banner\">\n  <div class=\"container\">\n    <h1>paizaQA</h1>\n    <p class=\"lead\">How to make QA sites like this: <a style=\"color: #c0c0c0;\" href=\"http://engineering.paiza.io/entry/2016/03/10/115345\">Building a QA web service in an hour - MEAN stack development(3)</a></p>\n    <img src=\"assets/images/yeoman.png\" alt=\"I'm Yeoman\">\n  </div>\n</header>\n\n<div class=\"container\" infinite-scroll='nextPage()' infinite-scroll-disabled='busy || noMoreData'>\n  <br/>\n  <div style=\"text-align: center\">\n    <a type=\"button\" class=\"btn btn-primary\" href=\"/questions/create\">Ask Question</a>\n  </div>\n\n  <table class=\"table table-striped\">\n    <thead>\n      <tr>\n        <th width=\"20\">Stars</th>\n        <th width=\"20\">Answers</th>\n        <th>Question</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr ng-repeat=\"question in questions\">\n        <td style=\"text-align: center; vertical-align:middle\">\n          <div style=\"font-size: xx-large;\">{{question.stars.length}}</div>\n        </td>\n        <td style=\"text-align: center; vertical-align:middle\">\n          <div style=\"font-size: xx-large;\">{{question.answers.length}}</div>\n        </td>\n        <td>\n          <div style=\"float: right;\">\n            <span ng-if=\" isStar(question)\" class=\"glyphicon glyphicon-star\" style=\"color: #CF7C00;\" ></span>\n            <span ng-if=\"!isStar(question)\" class=\"glyphicon glyphicon-star-empty\"></span>\n          </div>\n          <a ng-href=\"/questions/show/{{question._id}}\" style=\"font-size: large\">{{question.title}}</a>\n          <div class=\"clearfix\"></div>\n          <div style=\"float: right;\">\n            by <a ng-href=\"/users/{{question.user._id}}\">{{question.user.name}}</a>\n             - {{question.createdAt|fromNow}}\n          </div>\n          <div>\n            <span ng-repeat=\"tag in question.tags\">\n              <span class=\"label label-info\">\n                {{tag.text}}\n              </span>\n              &nbsp;\n            </span>\n          </div>\n          <div class=\"clearfix\"></div>\n        </td>\n      </tr>\n    </tbody>\n  </table>\n  <div ng-show='busy'>Loading data...</div>\n</div>\n"
  },
  {
    "path": "client/app/questionsIndex/questionsIndex.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp')\n  .config(function ($stateProvider) {\n    $stateProvider\n      .state('main', {\n        url: '/?keyword',\n        templateUrl: 'app/questionsIndex/questionsIndex.html',\n        controller: 'QuestionsIndexCtrl',\n        resolve: {\n          query: function(){return {};}\n        },\n      })\n      .state('starredQuestionsIndex', {\n        url: '/users/:userId/starred',\n        templateUrl: 'app/questionsIndex/questionsIndex.html',\n        controller: 'QuestionsIndexCtrl',\n        resolve: {\n          query: function($stateParams){\n            return {\n              $or: [\n                {'stars': $stateParams.userId},\n                {'answers.stars': $stateParams.userId},\n                {'comments.stars': $stateParams.userId},\n                {'answers.comments.stars': $stateParams.userId},\n              ]\n            };\n          }\n        },\n      })\n      .state('userQuestionsIndex', {\n        url: '/users/:userId',\n        templateUrl: 'app/questionsIndex/questionsIndex.html',\n        controller: 'QuestionsIndexCtrl',\n        resolve: {\n          query: function($stateParams){\n            return {user: $stateParams.userId};\n          }\n        },\n      });\n\n  });\n"
  },
  {
    "path": "client/app/questionsIndex/questionsIndex.scss",
    "content": "#banner {\n    border-bottom: none;\n    margin-top: -20px;\n}\n\n#banner h1 {\n    font-size: 60px;\n    line-height: 1;\n    letter-spacing: -1px;\n}\n\n.hero-unit {\n    position: relative;\n    padding: 30px 15px;\n    color: #F5F5F5;\n    text-align: center;\n    text-shadow: 0 1px 0 rgba(0, 0, 0, 0.1);\n    background: #4393B9;\n}\n\n"
  },
  {
    "path": "client/app/questionsShow/questionsShow.controller.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp')\n  .controller('QuestionsShowCtrl', function ($scope, $http, $stateParams, Auth, $location) {\n    var loadQuestions = function(){\n      $http.get('/api/questions/' + $stateParams.id).success(function(question) {\n        $scope.question = question;\n      });\n    };\n    loadQuestions();\n\n    $scope.newAnswer = {};\n    $scope.submitAnswer = function() {\n      $http.post('/api/questions/' + $stateParams.id + '/answers', $scope.newAnswer).success(function(){\n        loadQuestions();\n        $scope.newAnswer = {};\n      });\n    };\n    $scope.deleteQuestion = function() {\n      $http.delete('/api/questions/' + $stateParams.id).success(function(){\n        $location.path('/');\n      });\n    };\n    $scope.deleteAnswer = function(answer) {\n      $http.delete('/api/questions/' + $stateParams.id + '/answers/' + answer._id).success(function(){\n        loadQuestions();\n      });\n    };\n    $scope.updateQuestion = function() {\n      $http.put('/api/questions/' + $stateParams.id, $scope.question).success(function(){\n        loadQuestions();\n      });\n    };\n    $scope.updateAnswer = function(answer) {\n      $http.put('/api/questions/' + $stateParams.id + '/answers/' + answer._id, answer).success(function(){\n        loadQuestions();\n      });\n    };\n    $scope.isOwner = function(obj){\n      return Auth.isLoggedIn() && obj && obj.user && obj.user._id === Auth.getCurrentUser()._id;\n    };\n\n\n    $scope.newComment = {};\n    $scope.submitComment = function() {\n      $http.post('/api/questions/' + $stateParams.id + '/comments', $scope.newComment).success(function(){\n        loadQuestions();\n        $scope.newComment = {};\n        $scope.editNewComment = false;\n      });\n    };\n    $scope.submitAnswerComment = function(answer) {\n      $http.post('/api/questions/' + $stateParams.id + '/answers/' + answer._id + '/comments', answer.newAnswerComment).success(function(){\n        loadQuestions();\n      });\n    };\n    $scope.deleteComment = function(comment) {\n      $http.delete('/api/questions/' + $stateParams.id + '/comments/' + comment._id).success(function(){\n        loadQuestions();\n      });\n    };\n    $scope.deleteAnswerComment = function(answer, answerComment) {\n      $http.delete('/api/questions/' + $stateParams.id + '/answers/' + answer._id + '/comments/' + answerComment._id).success(function(){\n        loadQuestions();\n      });\n    };\n    $scope.updateComment = function(comment) {\n      $http.put('/api/questions/' + $stateParams.id + '/comments/' + comment._id, comment).success(function(){\n        loadQuestions();\n      });\n    };\n    $scope.updateAnswerComment = function(answer, answerComment) {\n      $http.put('/api/questions/' + $stateParams.id + '/answers/' + answer._id + '/comments/' + answerComment._id, answerComment).success(function(){\n        loadQuestions();\n      });\n    };\n\n    $scope.isStar = function(obj){\n      return Auth.isLoggedIn() && obj && obj.stars && obj.stars.indexOf(Auth.getCurrentUser()._id)!==-1;\n    };\n    $scope.star = function(subpath) {\n      $http.put('/api/questions/' + $scope.question._id + subpath + '/star').success(function(){\n        loadQuestions();\n      });\n    };\n    $scope.unstar = function(subpath) {\n      $http.delete('/api/questions/' + $scope.question._id + subpath + '/star').success(function(){\n        loadQuestions();\n      });\n    };\n  });\n\n"
  },
  {
    "path": "client/app/questionsShow/questionsShow.controller.spec.js",
    "content": "'use strict';\n\ndescribe('Controller: QuestionsShowCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module('paizaqaApp'));\n\n  var QuestionsShowCtrl, scope;\n\n  // Initialize the controller and a mock scope\n  beforeEach(inject(function ($controller, $rootScope) {\n    scope = $rootScope.$new();\n    QuestionsShowCtrl = $controller('QuestionsShowCtrl', {\n      $scope: scope\n    });\n  }));\n\n  it('should ...', function () {\n    expect(1).toEqual(1);\n  });\n});\n"
  },
  {
    "path": "client/app/questionsShow/questionsShow.html",
    "content": "<div class=\"container\" id=\"question-show-container\">\n  <div>\n    <button ng-if=\"isOwner(question)\" type=\"button\" class=\"close\" ng-click=\"deleteQuestion()\">&times;</button>\n\n    <div style=\"float: left;font-size: x-large; padding: 0; width: 2em; text-align: center;\">\n      <button ng-if=\" isStar(question)\" type=\"button\" style=\"background: transparent; border: 0;\" ng-click=\"unstar('')\">\n        <span class=\"glyphicon glyphicon-star\" style=\"color: #CF7C00;\" ></span>\n      </button>\n      <button ng-if=\"!isStar(question)\" type=\"button\" style=\"background: transparent; border: 0;\" ng-click=\"star('')\"  >\n        <span class=\"glyphicon glyphicon-star-empty\"></span>\n      </button>\n      <br/>\n      <div>{{question.stars.length}}</div>\n    </div>\n\n\n\n    <div>\n      <h1>\n        <div ng-if=\"! editting\">{{question.title}}</div>\n        <input type=text ng-model=\"question.title\" ng-if=\" editting\">\n      </h1>\n      <span ng-repeat=\"tag in question.tags\">\n        <span class=\"label label-info\">\n          {{tag.text}}\n        </span>\n      </span>\n    </div>\n  </div>\n  <hr/>\n\n  <pagedown-viewer content=\"question.content\" ng-if=\"!editting\"></pagedown-viewer>\n  <pagedown-editor ng-model=\"question.content\" ng-if=\" editting\"></pagedown-editor>\n  <button type=\"submit\" class=\"btn btn-primary\" ng-click=\"editting=false;updateQuestion()\" ng-show=\" editting\">Save</button>\n  <a ng-click=\"editting=!editting;\" ng-show=\"isOwner(question) && !editting\">Edit</a>\n\n  <div class=\"text-right\">by <a ng-href=\"/users/{{question.user._id}}\">{{question.user.name}}</a> - {{question.createdAt|fromNow}}</div>\n  &nbsp;\n  <div class=\"comment\">\n    <div ng-repeat=\"comment in question.comments\">\n      <hr/>\n      <button ng-if=\"isOwner(comment)\" type=\"button\" class=\"close\" ng-click=\"deleteComment(comment)\">&times;</button>\n\n      <div style=\"float: left;font-size: normal; padding: 0; width: 2em; text-align: center;\">\n        <button ng-if=\" isStar(comment)\" type=\"button\" style=\"background: transparent; border: 0;\" ng-click=\"unstar('/comments/' + comment._id)\">\n          <span class=\"glyphicon glyphicon-star\" style=\"color: #CF7C00;\" ></span>\n        </button>\n        <button ng-if=\"!isStar(comment)\" type=\"button\" style=\"background: transparent; border: 0;\" ng-click=\"  star('/comments/' + comment._id)\"  >\n          <span class=\"glyphicon glyphicon-star-empty\"></span>\n        </button>\n        <br/>\n        <div>{{comment.stars.length}}</div>\n      </div>\n\n\n      <pagedown-viewer content=\"comment.content\" ng-if=\"!editting\"></pagedown-viewer>\n      <pagedown-editor ng-model=\"comment.content\" ng-if=\" editting\"></pagedown-editor>\n      <button type=\"submit\" class=\"btn btn-primary\" ng-click=\"editting=false;updateComment(comment)\" ng-show=\" editting\">Save</button>\n      <a ng-click=\"editting=!editting;\" ng-show=\"isOwner(comment) && !editting\">Edit</a>\n\n      <div class=\"text-right\" style=\"vertical-align: bottom;\">by <a ng-href=\"/users/{{comment.user._id}}\">{{comment.user.name}}</a> - {{comment.createdAt|fromNow}}</div>\n      <div class=\"clearfix\"></div>\n    </div>\n    <hr/>\n    <a ng-click=\"editNewComment=!editNewComment;\">add a comment</a>\n    <form ng-if=\"editNewComment\" name=\"commentForm\">\n      <pagedown-editor ng-model=\"newComment.content\" editor-class=\"'comment-wmd-input'\"\n        name=\"commentEditor\" required>\n      </pagedown-editor>\n      <button type=\"button\" class=\"btn btn-primary\" ng-click=\"submitComment()\" ng-disabled=\"commentForm.$invalid\">Add Comment</button>\n    </form>\n  </div>\n\n\n\n\n  &nbsp;\n  <h3>{{question.answers.length}} Answers</h3>\n  <div ng-repeat=\"answer in question.answers\">\n    <hr/>\n\n    <div style=\"float: left;font-size: large; padding: 0; width: 2em; text-align: center;\">\n      <button ng-if=\" isStar(answer)\" type=\"button\" style=\"background: transparent; border: 0;\" ng-click=\"unstar('/answers/' + answer._id)\">\n        <span class=\"glyphicon glyphicon-star\" style=\"color: #CF7C00;\" ></span>\n      </button>\n      <button ng-if=\"!isStar(answer)\" type=\"button\" style=\"background: transparent; border: 0;\" ng-click=\"  star('/answers/' + answer._id)\"  >\n        <span class=\"glyphicon glyphicon-star-empty\"></span>\n      </button>\n      <br/>\n      <div>{{answer.stars.length}}</div>\n    </div>\n\n    <div class=\"answer\">\n      <button ng-if=\"isOwner(answer)\" type=\"button\" class=\"close\" ng-click=\"deleteAnswer(answer)\">&times;</button>\n      <pagedown-viewer content=\"answer.content\" ng-if=\"!editting\"></pagedown-viewer>\n      <pagedown-editor ng-model=\"answer.content\" ng-if=\" editting\"></pagedown-editor>\n      <button type=\"submit\" class=\"btn btn-primary\" ng-click=\"editting=false;updateAnswer(answer)\" ng-show=\" editting\">Save</button>\n      <a ng-click=\"editting=!editting;\" ng-show=\"isOwner(answer) && !editting\">Edit</a>\n    </div>\n\n\n\n\n\n    <div class=\"text-right\">by {{answer.user.name}} - {{answer.createdAt|fromNow}}</div>\n    <div class=\"comment\">\n      <div ng-repeat=\"comment in answer.comments\">\n        <hr/>\n        <button ng-if=\"isOwner(comment)\" type=\"button\" class=\"close\" ng-click=\"deleteAnswerComment(answer, comment)\">&times;</button>\n\n\n         <div style=\"float: left;font-size: normal; padding: 0; width: 2em; text-align: center;\">\n          <button ng-if=\" isStar(comment)\" type=\"button\" style=\"background: transparent; border: 0;\" ng-click=\"unstar('/answers/' + answer._id + '/comments/' + comment._id)\">\n            <span class=\"glyphicon glyphicon-star\" style=\"color: #CF7C00;\" ></span>\n          </button>\n          <button ng-if=\"!isStar(comment)\" type=\"button\" style=\"background: transparent; border: 0;\" ng-click=\"  star('/answers/' + answer._id + '/comments/' + comment._id)\"  >\n            <span class=\"glyphicon glyphicon-star-empty\"></span>\n          </button>\n          <br/>\n          <div>{{comment.stars.length}}</div>\n        </div>\n\n\n        <pagedown-viewer content=\"comment.content\" ng-if=\"!editting\"></pagedown-viewer>\n        <pagedown-editor ng-model=\"comment.content\" ng-if=\" editting\"></pagedown-editor>\n        <button type=\"submit\" class=\"btn btn-primary\" ng-click=\"editting=false;updateAnswerComment(answer, comment)\" ng-show=\" editting\">Save</button>\n        <a ng-click=\"editting=!editting;\" ng-show=\"isOwner(comment) && !editting\">Edit</a>\n\n        <div class=\"text-right\">by <a ng-href=\"/users/{{question.user._id}}\">{{comment.user.name}}</a> - {{comment.createdAt|fromNow}}</div>\n        <div class=\"clearfix\"></div>\n      </div>\n      <hr/>\n      <a ng-click=\"editNewAnswerComment=!editNewAnswerComment;answer.newAnswerComment={}\">add a comment</a>\n      <form ng-if=\"editNewAnswerComment\" name=\"answer_{{answer.id}}_comment\">\n        <hr/>\n        <pagedown-editor ng-model=\"answer.newAnswerComment.content\" editor-class=\"'comment-wmd-input'\"\n          required>\n        </pagedown-editor>\n        <button type=\"button\" class=\"btn btn-primary\" ng-click=\"submitAnswerComment(answer)\" ng-disabled=\"answer_{{answer.id}}_comment.$invalid\">Add Comment</button>\n      </form>\n    </div>\n  </div>\n  <hr/>\n  <h3>Your answer</h3>\n  <form name=\"answerForm\" ng-submit=\"submitAnswer()\">\n    <pagedown-editor ng-model=\"newAnswer.content\" name=\"answerEditor\" required></pagedown-editor>\n    <input type=\"submit\" class=\"btn btn-primary\" ng-disabled=\"answerForm.$invalid\" value=\"Submit your answer\">\n  </form>\n</div>\n\n\n"
  },
  {
    "path": "client/app/questionsShow/questionsShow.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp')\n  .config(function ($stateProvider) {\n    $stateProvider\n      .state('questionsShow', {\n        url: '/questions/show/:id',\n        templateUrl: 'app/questionsShow/questionsShow.html',\n        controller: 'QuestionsShowCtrl'\n      });\n  });\n"
  },
  {
    "path": "client/app/questionsShow/questionsShow.scss",
    "content": "#question-show-container .comment{\n  hr {\n    margin: 0;\n  };\n  p {\n    margin: 0;\n  };\n  margin-left: 100px;\n};\n#question-show-container .answer{\n  margin-left: 50px;\n};\n\n.comment-wmd-input {\n  height: 50px;\n  width: 100%;\n  background-color: Gainsboro;\n  border: 1px solid DarkGray;\n};\n"
  },
  {
    "path": "client/components/auth/auth.module.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp.auth', [\n  'paizaqaApp.constants',\n  'paizaqaApp.util',\n  'ngCookies',\n  'ui.router'\n])\n  .config(function($httpProvider) {\n    $httpProvider.interceptors.push('authInterceptor');\n  });\n"
  },
  {
    "path": "client/components/auth/auth.service.js",
    "content": "'use strict';\n\n(function() {\n\nfunction AuthService($location, $http, $cookies, $q, appConfig, Util, User) {\n  var safeCb = Util.safeCb;\n  var currentUser = {};\n  var userRoles = appConfig.userRoles || [];\n\n  if ($cookies.get('token') && $location.path() !== '/logout') {\n    currentUser = User.get();\n  }\n\n  var Auth = {\n\n    /**\n     * Authenticate user and save token\n     *\n     * @param  {Object}   user     - login info\n     * @param  {Function} callback - optional, function(error, user)\n     * @return {Promise}\n     */\n    login({email, password}, callback) {\n      return $http.post('/auth/local', {\n        email: email,\n        password: password\n      })\n        .then(res => {\n          $cookies.put('token', res.data.token);\n          currentUser = User.get();\n          return currentUser.$promise;\n        })\n        .then(user => {\n          safeCb(callback)(null, user);\n          return user;\n        })\n        .catch(err => {\n          Auth.logout();\n          safeCb(callback)(err.data);\n          return $q.reject(err.data);\n        });\n    },\n\n    /**\n     * Delete access token and user info\n     */\n    logout() {\n      $cookies.remove('token');\n      currentUser = {};\n    },\n\n    /**\n     * Create a new user\n     *\n     * @param  {Object}   user     - user info\n     * @param  {Function} callback - optional, function(error, user)\n     * @return {Promise}\n     */\n    createUser(user, callback) {\n      return User.save(user,\n        function(data) {\n          $cookies.put('token', data.token);\n          currentUser = User.get();\n          return safeCb(callback)(null, user);\n        },\n        function(err) {\n          Auth.logout();\n          return safeCb(callback)(err);\n        }).$promise;\n    },\n\n    /**\n     * Change password\n     *\n     * @param  {String}   oldPassword\n     * @param  {String}   newPassword\n     * @param  {Function} callback    - optional, function(error, user)\n     * @return {Promise}\n     */\n    changePassword(oldPassword, newPassword, callback) {\n      return User.changePassword({ id: currentUser._id }, {\n        oldPassword: oldPassword,\n        newPassword: newPassword\n      }, function() {\n        return safeCb(callback)(null);\n      }, function(err) {\n        return safeCb(callback)(err);\n      }).$promise;\n    },\n\n    /**\n     * Gets all available info on a user\n     *   (synchronous|asynchronous)\n     *\n     * @param  {Function|*} callback - optional, funciton(user)\n     * @return {Object|Promise}\n     */\n    getCurrentUser(callback) {\n      if (arguments.length === 0) {\n        return currentUser;\n      }\n\n      var value = (currentUser.hasOwnProperty('$promise')) ?\n        currentUser.$promise : currentUser;\n      return $q.when(value)\n        .then(user => {\n          safeCb(callback)(user);\n          return user;\n        }, () => {\n          safeCb(callback)({});\n          return {};\n        });\n    },\n\n    /**\n     * Check if a user is logged in\n     *   (synchronous|asynchronous)\n     *\n     * @param  {Function|*} callback - optional, function(is)\n     * @return {Bool|Promise}\n     */\n    isLoggedIn(callback) {\n      if (arguments.length === 0) {\n        return currentUser.hasOwnProperty('role');\n      }\n\n      return Auth.getCurrentUser(null)\n        .then(user => {\n          var is = user.hasOwnProperty('role');\n          safeCb(callback)(is);\n          return is;\n        });\n    },\n\n     /**\n      * Check if a user has a specified role or higher\n      *   (synchronous|asynchronous)\n      *\n      * @param  {String}     role     - the role to check against\n      * @param  {Function|*} callback - optional, function(has)\n      * @return {Bool|Promise}\n      */\n    hasRole(role, callback) {\n      var hasRole = function(r, h) {\n        return userRoles.indexOf(r) >= userRoles.indexOf(h);\n      };\n\n      if (arguments.length < 2) {\n        return hasRole(currentUser.role, role);\n      }\n\n      return Auth.getCurrentUser(null)\n        .then(user => {\n          var has = (user.hasOwnProperty('role')) ?\n            hasRole(user.role, role) : false;\n          safeCb(callback)(has);\n          return has;\n        });\n    },\n\n     /**\n      * Check if a user is an admin\n      *   (synchronous|asynchronous)\n      *\n      * @param  {Function|*} callback - optional, function(is)\n      * @return {Bool|Promise}\n      */\n    isAdmin() {\n      return Auth.hasRole\n        .apply(Auth, [].concat.apply(['admin'], arguments));\n    },\n\n    /**\n     * Get auth token\n     *\n     * @return {String} - a token string used for authenticating\n     */\n    getToken() {\n      return $cookies.get('token');\n    }\n  };\n\n  return Auth;\n}\n\nangular.module('paizaqaApp.auth')\n  .factory('Auth', AuthService);\n\n})();\n"
  },
  {
    "path": "client/components/auth/interceptor.service.js",
    "content": "'use strict';\n\n(function() {\n\nfunction authInterceptor($rootScope, $q, $cookies, $injector, Util) {\n  var state;\n  return {\n    // Add authorization token to headers\n    request(config) {\n      config.headers = config.headers || {};\n      if ($cookies.get('token') && Util.isSameOrigin(config.url)) {\n        config.headers.Authorization = 'Bearer ' + $cookies.get('token');\n      }\n      return config;\n    },\n\n    // Intercept 401s and redirect you to login\n    responseError(response) {\n      if (response.status === 401) {\n        (state || (state = $injector.get('$state'))).go('login');\n        // remove any stale tokens\n        $cookies.remove('token');\n      }\n      return $q.reject(response);\n    }\n  };\n}\n\nangular.module('paizaqaApp.auth')\n  .factory('authInterceptor', authInterceptor);\n\n})();\n"
  },
  {
    "path": "client/components/auth/router.decorator.js",
    "content": "'use strict';\n\n(function() {\n\nangular.module('paizaqaApp.auth')\n  .run(function($rootScope, $state, Auth) {\n    // Redirect to login if route requires auth and the user is not logged in, or doesn't have required role\n    $rootScope.$on('$stateChangeStart', function(event, next) {\n      if (!next.authenticate) {\n        return;\n      }\n\n      if (typeof next.authenticate === 'string') {\n        Auth.hasRole(next.authenticate, _.noop).then(has => {\n          if (has) {\n            return;\n          }\n\n          event.preventDefault();\n          return Auth.isLoggedIn(_.noop).then(is => {\n            $state.go(is ? 'main' : 'login');\n          });\n        });\n      } else {\n        Auth.isLoggedIn(_.noop).then(is => {\n          if (is) {\n            return;\n          }\n\n          event.preventDefault();\n          $state.go('main');\n        });\n      }\n    });\n  });\n\n})();\n"
  },
  {
    "path": "client/components/auth/user.service.js",
    "content": "'use strict';\n\n(function() {\n\nfunction UserResource($resource) {\n  return $resource('/api/users/:id/:controller', {\n    id: '@_id'\n  }, {\n    changePassword: {\n      method: 'PUT',\n      params: {\n        controller: 'password'\n      }\n    },\n    get: {\n      method: 'GET',\n      params: {\n        id: 'me'\n      }\n    }\n  });\n}\n\nangular.module('paizaqaApp.auth')\n  .factory('User', UserResource);\n\n})();\n"
  },
  {
    "path": "client/components/footer/footer.directive.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp')\n  .directive('footer', function() {\n    return {\n      templateUrl: 'components/footer/footer.html',\n      restrict: 'E',\n      link: function(scope, element) {\n        element.addClass('footer');\n      }\n    };\n  });\n"
  },
  {
    "path": "client/components/footer/footer.html",
    "content": "<div class=\"container\">\n  <p>Angular Fullstack v3.3.0 |\n    <a href=\"https://twitter.com/tyhenkel\">@tyhenkel</a> |\n    <a href=\"https://github.com/DaftMonk/generator-angular-fullstack/issues?state=open\">Issues</a>\n  </p>\n</div>\n"
  },
  {
    "path": "client/components/footer/footer.scss",
    "content": "footer.footer {\n  text-align: center;\n  padding: 30px 0;\n  margin-top: 70px;\n  border-top: 1px solid #E5E5E5;\n}\n"
  },
  {
    "path": "client/components/modal/modal.html",
    "content": "<div class=\"modal-header\">\n  <button ng-if=\"modal.dismissable\" type=\"button\" ng-click=\"$dismiss()\" class=\"close\">&times;</button>\n  <h4 ng-if=\"modal.title\" ng-bind=\"modal.title\" class=\"modal-title\"></h4>\n</div>\n<div class=\"modal-body\">\n  <p ng-if=\"modal.text\" ng-bind=\"modal.text\"></p>\n  <div ng-if=\"modal.html\" ng-bind-html=\"modal.html\"></div>\n</div>\n<div class=\"modal-footer\">\n  <button ng-repeat=\"button in modal.buttons\" ng-class=\"button.classes\" ng-click=\"button.click($event)\" ng-bind=\"button.text\" class=\"btn\"></button>\n</div>\n"
  },
  {
    "path": "client/components/modal/modal.scss",
    "content": ".modal-primary,\n.modal-info,\n.modal-success,\n.modal-warning,\n.modal-danger {\n  .modal-header {\n    color: #fff;\n    border-radius: 5px 5px 0 0;\n  }\n}\n.modal-primary .modal-header {\n  background: $brand-primary;\n}\n.modal-info .modal-header {\n  background: $brand-info;\n}\n.modal-success .modal-header {\n  background: $brand-success;\n}\n.modal-warning .modal-header {\n  background: $brand-warning;\n}\n.modal-danger .modal-header {\n  background: $brand-danger;\n}\n"
  },
  {
    "path": "client/components/modal/modal.service.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp')\n  .factory('Modal', function($rootScope, $modal) {\n    /**\n     * Opens a modal\n     * @param  {Object} scope      - an object to be merged with modal's scope\n     * @param  {String} modalClass - (optional) class(es) to be applied to the modal\n     * @return {Object}            - the instance $modal.open() returns\n     */\n    function openModal(scope = {}, modalClass = 'modal-default') {\n      var modalScope = $rootScope.$new();\n\n      angular.extend(modalScope, scope);\n\n      return $modal.open({\n        templateUrl: 'components/modal/modal.html',\n        windowClass: modalClass,\n        scope: modalScope\n      });\n    }\n\n    // Public API here\n    return {\n\n      /* Confirmation modals */\n      confirm: {\n\n        /**\n         * Create a function to open a delete confirmation modal (ex. ng-click='myModalFn(name, arg1, arg2...)')\n         * @param  {Function} del - callback, ran when delete is confirmed\n         * @return {Function}     - the function to open the modal (ex. myModalFn)\n         */\n        delete(del = angular.noop) {\n          /**\n           * Open a delete confirmation modal\n           * @param  {String} name   - name or info to show on modal\n           * @param  {All}           - any additional args are passed straight to del callback\n           */\n          return function() {\n            var args = Array.prototype.slice.call(arguments),\n                name = args.shift(),\n                deleteModal;\n\n            deleteModal = openModal({\n              modal: {\n                dismissable: true,\n                title: 'Confirm Delete',\n                html: '<p>Are you sure you want to delete <strong>' + name + '</strong> ?</p>',\n                buttons: [{\n                  classes: 'btn-danger',\n                  text: 'Delete',\n                  click: function(e) {\n                    deleteModal.close(e);\n                  }\n                }, {\n                  classes: 'btn-default',\n                  text: 'Cancel',\n                  click: function(e) {\n                    deleteModal.dismiss(e);\n                  }\n                }]\n              }\n            }, 'modal-danger');\n\n            deleteModal.result.then(function(event) {\n              del.apply(event, args);\n            });\n          };\n        }\n      }\n    };\n  });\n"
  },
  {
    "path": "client/components/mongoose-error/mongoose-error.directive.js",
    "content": "'use strict';\n\n/**\n * Removes server error when user updates input\n */\nangular.module('paizaqaApp')\n  .directive('mongooseError', function() {\n    return {\n      restrict: 'A',\n      require: 'ngModel',\n      link: function(scope, element, attrs, ngModel) {\n        element.on('keydown', () => ngModel.$setValidity('mongoose', true));\n      }\n    };\n  });\n"
  },
  {
    "path": "client/components/navbar/navbar.controller.js",
    "content": "'use strict';\n\nclass NavbarController {\n  //start-non-standard\n\n\n  isCollapsed = true;\n  //end-non-standard\n\n  constructor(Auth, $state) {\n    this.menu = [\n      {\n        'title': 'All',\n        'link': function(){return '/';},\n        'show': function(){return true;},\n      },\n      {\n        'title': 'Mine',\n        'link': function(){return '/users/' + Auth.getCurrentUser()._id;},\n        'show': Auth.isLoggedIn,\n      },\n      {\n        'title': 'Starred',\n        'link': function(){return '/users/' + Auth.getCurrentUser()._id + '/starred';},\n        'show': Auth.isLoggedIn,\n      },\n    ];\n    this.isLoggedIn = Auth.isLoggedIn;\n    this.isAdmin = Auth.isAdmin;\n    this.getCurrentUser = Auth.getCurrentUser;\n\n    this.search = function(keyword) {\n      $state.go('main', {keyword: keyword}, {reload: true});\n    };\n  }\n}\n\nangular.module('paizaqaApp')\n  .controller('NavbarController', NavbarController);\n"
  },
  {
    "path": "client/components/navbar/navbar.directive.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp')\n  .directive('navbar', () => ({\n    templateUrl: 'components/navbar/navbar.html',\n    restrict: 'E',\n    controller: 'NavbarController',\n    controllerAs: 'nav'\n  }));\n"
  },
  {
    "path": "client/components/navbar/navbar.html",
    "content": "<div class=\"navbar navbar-default navbar-static-top\" ng-controller=\"NavbarController\">\n  <div class=\"container\">\n    <div class=\"navbar-header\">\n      <button class=\"navbar-toggle\" type=\"button\" ng-click=\"nav.isCollapsed = !nav.isCollapsed\">\n        <span class=\"sr-only\">Toggle navigation</span>\n        <span class=\"icon-bar\"></span>\n        <span class=\"icon-bar\"></span>\n        <span class=\"icon-bar\"></span>\n      </button>\n      <a href=\"/\" class=\"navbar-brand\">paizaqa</a>\n    </div>\n    <div collapse=\"nav.isCollapsed\" class=\"navbar-collapse collapse\" id=\"navbar-main\">\n      <ul class=\"nav navbar-nav\">\n        <li ng-repeat=\"item in nav.menu\" ng-class=\"{active: isActive(item.link())}\" ng-show=\"item.show()\">\n            <a ng-href=\"{{item.link()}}\">{{item.title}}</a>\n        </li>\n      </ul>\n      <form class=\"navbar-form navbar-left\" role=\"search\" ng-submit=\"nav.search(keyword)\">\n        <div class=\"input-group\">\n          <input type=\"text\" class=\"form-control\" placeholder=\"Search\" ng-model=\"keyword\">\n          <span class=\"input-group-btn\">\n            <button type=\"submit\" class=\"btn btn-default\">\n              <span class=\"glyphicon glyphicon-search\">\n              </span>\n            </button>\n          </span>\n        </div>\n      </form>\n      <ul class=\"nav navbar-nav navbar-right\">\n        <li ng-hide=\"nav.isLoggedIn()\" ui-sref-active=\"active\"><a ui-sref=\"signup\">Sign up</a></li>\n        <li ng-hide=\"nav.isLoggedIn()\" ui-sref-active=\"active\"><a ui-sref=\"login\">Login</a></li>\n        <li ng-show=\"nav.isLoggedIn()\"><p class=\"navbar-text\">Hello {{ nav.getCurrentUser().name }}</p> </li>\n        <li ng-show=\"nav.isLoggedIn()\" ui-sref-active=\"active\"><a ui-sref=\"settings\"><span class=\"glyphicon glyphicon-cog\"></span></a></li>\n        <li ng-show=\"nav.isLoggedIn()\"><a ui-sref=\"logout\">Logout</a></li>\n      </ul>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "client/components/oauth-buttons/oauth-buttons.controller.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp')\n  .controller('OauthButtonsCtrl', function($window) {\n    this.loginOauth = function(provider) {\n      $window.location.href = '/auth/' + provider;\n    };\n  });\n"
  },
  {
    "path": "client/components/oauth-buttons/oauth-buttons.controller.spec.js",
    "content": "'use strict';\n\ndescribe('Controller: OauthButtonsCtrl', function() {\n\n  // load the controller's module\n  beforeEach(module('paizaqaApp'));\n\n  var OauthButtonsCtrl, $window;\n\n  // Initialize the controller and a mock $window\n  beforeEach(inject(function($controller) {\n    $window = {\n      location: {}\n    };\n\n    OauthButtonsCtrl = $controller('OauthButtonsCtrl', {\n      $window: $window\n    });\n  }));\n\n  it('should attach loginOauth', function() {\n    expect(OauthButtonsCtrl.loginOauth).toEqual(jasmine.any(Function));\n  });\n});\n"
  },
  {
    "path": "client/components/oauth-buttons/oauth-buttons.directive.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp')\n  .directive('oauthButtons', function() {\n    return {\n      templateUrl: 'components/oauth-buttons/oauth-buttons.html',\n      restrict: 'EA',\n      controller: 'OauthButtonsCtrl',\n      controllerAs: 'OauthButtons',\n      scope: {\n        classes: '@'\n      }\n    };\n  });\n"
  },
  {
    "path": "client/components/oauth-buttons/oauth-buttons.directive.spec.js",
    "content": "'use strict';\n\ndescribe('Directive: oauthButtons', function() {\n\n  // load the directive's module and view\n  beforeEach(module('paizaqaApp'));\n  beforeEach(module('components/oauth-buttons/oauth-buttons.html'));\n\n  var element, parentScope, elementScope;\n\n  var compileDirective = function(template) {\n    inject(function($compile) {\n      element = angular.element(template);\n      element = $compile(element)(parentScope);\n      parentScope.$digest();\n      elementScope = element.isolateScope();\n    });\n  };\n\n  beforeEach(inject(function($rootScope) {\n    parentScope = $rootScope.$new();\n  }));\n\n  it('should contain anchor buttons', function() {\n    compileDirective('<oauth-buttons></oauth-buttons>');\n    expect(element.find('a.btn.btn-social').length).toBeGreaterThan(0);\n  });\n\n  it('should evaluate and bind the classes attribute to scope.classes', function() {\n    parentScope.scopedClass = 'scopedClass1';\n    compileDirective('<oauth-buttons classes=\"testClass1 {{scopedClass}}\"></oauth-buttons>');\n    expect(elementScope.classes).toEqual('testClass1 scopedClass1');\n  });\n\n  it('should bind scope.classes to class names on the anchor buttons', function() {\n    compileDirective('<oauth-buttons></oauth-buttons>');\n    // Add classes\n    elementScope.classes = 'testClass1 testClass2';\n    elementScope.$digest();\n    expect(element.find('a.btn.btn-social.testClass1.testClass2').length).toBeGreaterThan(0);\n\n    // Remove classes\n    elementScope.classes = '';\n    elementScope.$digest();\n    expect(element.find('a.btn.btn-social.testClass1.testClass2').length).toEqual(0);\n  });\n});\n"
  },
  {
    "path": "client/components/oauth-buttons/oauth-buttons.html",
    "content": "<a ng-class=\"classes\" ng-click=\"OauthButtons.loginOauth('facebook')\" class=\"btn btn-social btn-facebook\">\n  <i class=\"fa fa-facebook\"></i>\n  Connect with Facebook\n</a>\n<a ng-class=\"classes\" ng-click=\"OauthButtons.loginOauth('google')\" class=\"btn btn-social btn-google\">\n  <i class=\"fa fa-google-plus\"></i>\n  Connect with Google+\n</a>\n<a ng-class=\"classes\" ng-click=\"OauthButtons.loginOauth('twitter')\" class=\"btn btn-social btn-twitter\">\n  <i class=\"fa fa-twitter\"></i>\n  Connect with Twitter\n</a>\n"
  },
  {
    "path": "client/components/oauth-buttons/oauth-buttons.scss",
    "content": "\n"
  },
  {
    "path": "client/components/socket/socket.mock.js",
    "content": "'use strict';\n\nangular.module('socketMock', [])\n  .factory('socket', function() {\n    return {\n      socket: {\n        connect: function() {},\n        on: function() {},\n        emit: function() {},\n        receive: function() {}\n      },\n\n      syncUpdates: function() {},\n      unsyncUpdates: function() {}\n    };\n  });\n"
  },
  {
    "path": "client/components/socket/socket.service.js",
    "content": "/* global io */\n'use strict';\n\nangular.module('paizaqaApp')\n  .factory('socket', function(socketFactory) {\n    // socket.io now auto-configures its connection when we ommit a connection url\n    var ioSocket = io('', {\n      // Send auth token on connection, you will need to DI the Auth service above\n      // 'query': 'token=' + Auth.getToken()\n      path: '/socket.io-client'\n    });\n\n    var socket = socketFactory({ ioSocket });\n\n    return {\n      socket,\n\n      /**\n       * Register listeners to sync an array with updates on a model\n       *\n       * Takes the array we want to sync, the model name that socket updates are sent from,\n       * and an optional callback function after new items are updated.\n       *\n       * @param {String} modelName\n       * @param {Array} array\n       * @param {Function} cb\n       */\n      syncUpdates(modelName, array, cb) {\n        cb = cb || angular.noop;\n\n        /**\n         * Syncs item creation/updates on 'model:save'\n         */\n        socket.on(modelName + ':save', function (item) {\n          var oldItem = _.find(array, {_id: item._id});\n          var index = array.indexOf(oldItem);\n          var event = 'created';\n\n          // replace oldItem if it exists\n          // otherwise just add item to the collection\n          if (oldItem) {\n            array.splice(index, 1, item);\n            event = 'updated';\n          } else {\n            array.push(item);\n          }\n\n          cb(event, item, array);\n        });\n\n        /**\n         * Syncs removed items on 'model:remove'\n         */\n        socket.on(modelName + ':remove', function (item) {\n          var event = 'deleted';\n          _.remove(array, {_id: item._id});\n          cb(event, item, array);\n        });\n      },\n\n      /**\n       * Removes listeners for a models updates on the socket\n       *\n       * @param modelName\n       */\n      unsyncUpdates(modelName) {\n        socket.removeAllListeners(modelName + ':save');\n        socket.removeAllListeners(modelName + ':remove');\n      }\n    };\n  });\n"
  },
  {
    "path": "client/components/ui-router/ui-router.mock.js",
    "content": "'use strict';\n\nangular.module('stateMock', []);\nangular.module('stateMock').service('$state', function($q) {\n    this.expectedTransitions = [];\n\n    this.transitionTo = function(stateName) {\n        if (this.expectedTransitions.length > 0) {\n            var expectedState = this.expectedTransitions.shift();\n            if (expectedState !== stateName) {\n                throw Error('Expected transition to state: ' + expectedState + ' but transitioned to ' + stateName);\n            }\n        } else {\n            throw Error('No more transitions were expected! Tried to transition to ' + stateName);\n        }\n        console.log('Mock transition to: ' + stateName);\n        var deferred = $q.defer();\n        var promise = deferred.promise;\n        deferred.resolve();\n        return promise;\n    };\n\n    this.go = this.transitionTo;\n\n    this.expectTransitionTo = function(stateName) {\n        this.expectedTransitions.push(stateName);\n    };\n\n    this.ensureAllTransitionsHappened = function() {\n        if (this.expectedTransitions.length > 0) {\n            throw Error('Not all transitions happened!');\n        }\n    };\n});\n"
  },
  {
    "path": "client/components/util/util.module.js",
    "content": "'use strict';\n\nangular.module('paizaqaApp.util', []);\n"
  },
  {
    "path": "client/components/util/util.service.js",
    "content": "'use strict';\n\n(function() {\n\n/**\n * The Util service is for thin, globally reusable, utility functions\n */\nfunction UtilService($window) {\n  var Util = {\n    /**\n     * Return a callback or noop function\n     *\n     * @param  {Function|*} cb - a 'potential' function\n     * @return {Function}\n     */\n    safeCb(cb) {\n      return (angular.isFunction(cb)) ? cb : angular.noop;\n    },\n\n    /**\n     * Parse a given url with the use of an anchor element\n     *\n     * @param  {String} url - the url to parse\n     * @return {Object}     - the parsed url, anchor element\n     */\n    urlParse(url) {\n      var a = document.createElement('a');\n      a.href = url;\n\n      // Special treatment for IE, see http://stackoverflow.com/a/13405933 for details\n      if (a.host === '') {\n        a.href = a.href;\n      }\n\n      return a;\n    },\n\n    /**\n     * Test whether or not a given url is same origin\n     *\n     * @param  {String}           url       - url to test\n     * @param  {String|String[]}  [origins] - additional origins to test against\n     * @return {Boolean}                    - true if url is same origin\n     */\n    isSameOrigin(url, origins) {\n      url = Util.urlParse(url);\n      origins = (origins && [].concat(origins)) || [];\n      origins = origins.map(Util.urlParse);\n      origins.push($window.location);\n      origins = origins.filter(function(o) {\n        return url.hostname === o.hostname &&\n          url.port === o.port &&\n          url.protocol === o.protocol;\n      });\n      return (origins.length >= 1);\n    }\n  };\n\n  return Util;\n}\n\nangular.module('paizaqaApp.util')\n  .factory('Util', UtilService);\n\n})();\n"
  },
  {
    "path": "client/index.html",
    "content": "<!doctype html>\n<!--[if lt IE 7]>      <html class=\"no-js lt-ie9 lt-ie8 lt-ie7\"> <![endif]-->\n<!--[if IE 7]>         <html class=\"no-js lt-ie9 lt-ie8\"> <![endif]-->\n<!--[if IE 8]>         <html class=\"no-js lt-ie9\"> <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\"> <!--<![endif]-->\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge\">\n    <base href=\"/\">\n    <title></title>\n    <meta name=\"description\" content=\"\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->\n    <!-- build:css(client) app/vendor.css -->\n      <!-- bower:css -->\n      <link rel=\"stylesheet\" href=\"bower_components/angular-pagedown/angular-pagedown.css\" />\n      <link rel=\"stylesheet\" href=\"bower_components/ng-tags-input/ng-tags-input.min.css\" />\n      <!-- endbower -->\n    <!-- endbuild -->\n    <!-- build:css({.tmp,client}) app/app.css -->\n      <link rel=\"stylesheet\" href=\"app/app.css\">\n      <!-- injector:css -->\n      <!-- endinjector -->\n    <!-- endbuild -->\n  </head>\n  <body ng-app=\"paizaqaApp\">\n    <!--[if lt IE 7]>\n      <p class=\"browserupgrade\">You are using an <strong>outdated</strong> browser. Please <a href=\"http://browsehappy.com/\">upgrade your browser</a> to improve your experience.</p>\n    <![endif]-->\n\n    <!-- Add your site or application content here -->\n    <navbar></navbar>\n    <div ui-view=\"\"></div>\n    <footer></footer>\n\n    <!-- Google Analytics: change UA-XXXXX-X to be your site's ID -->\n    <script>\n      (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n      (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\n      m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n      })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');\n\n      ga('create', 'UA-XXXXX-X');\n      ga('send', 'pageview');\n    </script>\n\n    <!--[if lt IE 9]>\n    <script src=\"bower_components/es5-shim/es5-shim.js\"></script>\n    <script src=\"bower_components/json3/lib/json3.min.js\"></script>\n    <![endif]-->\n    <!-- build:js({client,node_modules}) app/vendor.js -->\n      <!-- bower:js -->\n      <script src=\"bower_components/jquery/dist/jquery.js\"></script>\n      <script src=\"bower_components/angular/angular.js\"></script>\n      <script src=\"bower_components/angular-resource/angular-resource.js\"></script>\n      <script src=\"bower_components/angular-cookies/angular-cookies.js\"></script>\n      <script src=\"bower_components/angular-sanitize/angular-sanitize.js\"></script>\n      <script src=\"bower_components/angular-bootstrap/ui-bootstrap-tpls.js\"></script>\n      <script src=\"bower_components/lodash/dist/lodash.compat.js\"></script>\n      <script src=\"bower_components/angular-socket-io/socket.js\"></script>\n      <script src=\"bower_components/angular-ui-router/release/angular-ui-router.js\"></script>\n      <script src=\"bower_components/angular-validation-match/dist/angular-validation-match.min.js\"></script>\n      <script src=\"bower_components/pagedown/Markdown.Converter.js\"></script>\n      <script src=\"bower_components/pagedown/Markdown.Sanitizer.js\"></script>\n      <script src=\"bower_components/pagedown/Markdown.Extra.js\"></script>\n      <script src=\"bower_components/pagedown/Markdown.Editor.js\"></script>\n      <script src=\"bower_components/angular-pagedown/angular-pagedown.js\"></script>\n      <script src=\"bower_components/ng-tags-input/ng-tags-input.min.js\"></script>\n      <script src=\"bower_components/angular-messages/angular-messages.js\"></script>\n      <script src=\"bower_components/moment/moment.js\"></script>\n      <script src=\"bower_components/ngInfiniteScroll/build/ng-infinite-scroll.js\"></script>\n      <!-- endbower -->\n      <script src=\"bower_components/moment/min/moment-with-locales.min.js\"></script>\n      <script src=\"socket.io-client/socket.io.js\"></script>\n    <!-- endbuild -->\n    <!-- build:js(.tmp) app/app.js -->\n      <script src=\"app/app.js\"></script>\n      <!-- injector:js -->\n      <script src=\"components/auth/auth.module.js\"></script>\n      <script src=\"app/admin/admin.module.js\"></script>\n      <script src=\"components/util/util.module.js\"></script>\n      <script src=\"app/account/signup/signup.controller.js\"></script>\n      <script src=\"app/admin/admin.controller.js\"></script>\n      <script src=\"app/account/account.js\"></script>\n      <script src=\"app/admin/admin.router.js\"></script>\n      <script src=\"app/app.constant.js\"></script>\n      <script src=\"app/fromNow/fromNow.filter.js\"></script>\n      <script src=\"app/questionsCreate/questionsCreate.controller.js\"></script>\n      <script src=\"app/questionsCreate/questionsCreate.js\"></script>\n      <script src=\"app/questionsIndex/questionsIndex.controller.js\"></script>\n      <script src=\"app/questionsIndex/questionsIndex.js\"></script>\n      <script src=\"app/questionsShow/questionsShow.controller.js\"></script>\n      <script src=\"app/questionsShow/questionsShow.js\"></script>\n      <script src=\"app/account/login/login.controller.js\"></script>\n      <script src=\"components/auth/auth.service.js\"></script>\n      <script src=\"components/auth/interceptor.service.js\"></script>\n      <script src=\"components/auth/router.decorator.js\"></script>\n      <script src=\"components/auth/user.service.js\"></script>\n      <script src=\"components/footer/footer.directive.js\"></script>\n      <script src=\"components/modal/modal.service.js\"></script>\n      <script src=\"components/mongoose-error/mongoose-error.directive.js\"></script>\n      <script src=\"components/navbar/navbar.controller.js\"></script>\n      <script src=\"components/navbar/navbar.directive.js\"></script>\n      <script src=\"components/oauth-buttons/oauth-buttons.controller.js\"></script>\n      <script src=\"components/oauth-buttons/oauth-buttons.directive.js\"></script>\n      <script src=\"components/socket/socket.service.js\"></script>\n      <script src=\"app/account/settings/settings.controller.js\"></script>\n      <script src=\"components/util/util.service.js\"></script>\n      <!-- endinjector -->\n    <!-- endbuild -->\n  <a href=\"https://github.com/gi-no/paizaqa\"><img style=\"position: absolute; top: 50px; right: 0; border: 0;\" src=\"https://camo.githubusercontent.com/e7bbb0521b397edbd5fe43e7f760759336b5e05f/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f677265656e5f3030373230302e706e67\" alt=\"Fork me on GitHub\" data-canonical-src=\"https://s3.amazonaws.com/github/ribbons/forkme_right_green_007200.png\"></a>\n  </body>\n</html>\n"
  },
  {
    "path": "client/robots.txt",
    "content": "# robotstxt.org\n\nUser-agent: *\n"
  },
  {
    "path": "e2e/account/login/login.po.js",
    "content": "/**\n * This file uses the Page Object pattern to define the main page for tests\n * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ\n */\n\n'use strict';\n\nvar LoginPage = function() {\n  var form = this.form = element(by.css('.form'));\n  form.email = form.element(by.model('vm.user.email'));\n  form.password = form.element(by.model('vm.user.password'));\n  form.submit = form.element(by.css('.btn-login'));\n  form.oauthButtons = require('../../components/oauth-buttons/oauth-buttons.po').oauthButtons;\n\n  this.login = function(data) {\n    for (var prop in data) {\n      var formElem = form[prop];\n      if (data.hasOwnProperty(prop) && formElem && typeof formElem.sendKeys === 'function') {\n        formElem.sendKeys(data[prop]);\n      }\n    }\n\n    return form.submit.click();\n  };\n};\n\nmodule.exports = new LoginPage();\n\n"
  },
  {
    "path": "e2e/account/login/login.spec.js",
    "content": "'use strict';\n\nvar config = browser.params;\nvar UserModel = require(config.serverConfig.root + '/server/api/user/user.model');\n\ndescribe('Login View', function() {\n  var page;\n\n  var loadPage = function() {\n    browser.get(config.baseUrl + '/login');\n    page = require('./login.po');\n  };\n\n  var testUser = {\n    name: 'Test User',\n    email: 'test@example.com',\n    password: 'test'\n  };\n\n  beforeEach(function(done) {\n    UserModel.removeAsync()\n      .then(function() {\n        return UserModel.createAsync(testUser);\n      })\n      .then(loadPage)\n      .finally(function() {\n        browser.wait(function() {\n          //console.log('waiting for angular...');\n          return browser.executeScript('return !!window.angular');\n\n        }, 5000).then(done);\n\n      });\n  });\n\n  it('should include login form with correct inputs and submit button', function() {\n    expect(page.form.email.getAttribute('type')).toBe('email');\n    expect(page.form.email.getAttribute('name')).toBe('email');\n    expect(page.form.password.getAttribute('type')).toBe('password');\n    expect(page.form.password.getAttribute('name')).toBe('password');\n    expect(page.form.submit.getAttribute('type')).toBe('submit');\n    expect(page.form.submit.getText()).toBe('Login');\n  });\n\n  it('should include oauth buttons with correct classes applied', function() {\n    expect(page.form.oauthButtons.facebook.getText()).toBe('Connect with Facebook');\n    expect(page.form.oauthButtons.facebook.getAttribute('class')).toMatch('btn-block');\n    expect(page.form.oauthButtons.google.getText()).toBe('Connect with Google+');\n    expect(page.form.oauthButtons.google.getAttribute('class')).toMatch('btn-block');\n    expect(page.form.oauthButtons.twitter.getText()).toBe('Connect with Twitter');\n    expect(page.form.oauthButtons.twitter.getAttribute('class')).toMatch('btn-block');\n  });\n\n  describe('with local auth', function() {\n\n    it('should login a user and redirecting to \"/\"', function() {\n      page.login(testUser);\n\n      var navbar = require('../../components/navbar/navbar.po');\n\n      expect(browser.getCurrentUrl()).toBe(config.baseUrl + '/');\n      expect(navbar.navbarAccountGreeting.getText()).toBe('Hello ' + testUser.name);\n    });\n\n    it('should indicate login failures', function() {\n      page.login({\n        email: testUser.email,\n        password: 'badPassword'\n      });\n\n      expect(browser.getCurrentUrl()).toBe(config.baseUrl + '/login');\n\n      var helpBlock = page.form.element(by.css('.form-group.has-error .help-block.ng-binding'));\n      expect(helpBlock.getText()).toBe('This password is not correct.');\n    });\n\n  });\n});\n"
  },
  {
    "path": "e2e/account/logout/logout.spec.js",
    "content": "'use strict';\n\nvar config = browser.params;\nvar UserModel = require(config.serverConfig.root + '/server/api/user/user.model');\n\ndescribe('Logout View', function() {\n  var login = function(user) {\n    browser.get(config.baseUrl + '/login');\n    require('../login/login.po').login(user);\n  };\n\n  var testUser = {\n    name: 'Test User',\n    email: 'test@example.com',\n    password: 'test'\n  };\n\n  beforeEach(function(done) {\n    UserModel.removeAsync()\n      .then(function() {\n        return UserModel.createAsync(testUser);\n      })\n      .then(function() {\n        return login(testUser);\n      })\n      .finally(function() {\n        browser.wait(function() {\n            return browser.executeScript('return !!window.angular');\n        }, 5000).then(done);\n      });\n  });\n\n  describe('with local auth', function() {\n\n    it('should logout a user and redirecting to \"/\"', function() {\n      var navbar = require('../../components/navbar/navbar.po');\n\n      expect(browser.getCurrentUrl()).toBe(config.baseUrl + '/');\n      expect(navbar.navbarAccountGreeting.getText()).toBe('Hello ' + testUser.name);\n\n      browser.get(config.baseUrl + '/logout');\n\n      navbar = require('../../components/navbar/navbar.po');\n\n      expect(browser.getCurrentUrl()).toBe(config.baseUrl + '/');\n      expect(navbar.navbarAccountGreeting.isDisplayed()).toBe(false);\n    });\n\n  });\n});\n"
  },
  {
    "path": "e2e/account/signup/signup.po.js",
    "content": "/**\n * This file uses the Page Object pattern to define the main page for tests\n * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ\n */\n\n'use strict';\n\nvar SignupPage = function() {\n  var form = this.form = element(by.css('.form'));\n  form.name = form.element(by.model('vm.user.name'));\n  form.email = form.element(by.model('vm.user.email'));\n  form.password = form.element(by.model('vm.user.password'));\n  form.confirmPassword = form.element(by.model('vm.user.confirmPassword'));\n  form.submit = form.element(by.css('.btn-register'));\n  form.oauthButtons = require('../../components/oauth-buttons/oauth-buttons.po').oauthButtons;\n\n  this.signup = function(data) {\n    for (var prop in data) {\n      var formElem = form[prop];\n      if (data.hasOwnProperty(prop) && formElem && typeof formElem.sendKeys === 'function') {\n        formElem.sendKeys(data[prop]);\n      }\n    }\n\n    return form.submit.click();\n  };\n};\n\nmodule.exports = new SignupPage();\n\n"
  },
  {
    "path": "e2e/account/signup/signup.spec.js",
    "content": "'use strict';\n\nvar config = browser.params;\nvar UserModel = require(config.serverConfig.root + '/server/api/user/user.model');\n\ndescribe('Signup View', function() {\n  var page;\n\n  var loadPage = function() {\n    browser.manage().deleteAllCookies();\n    browser.get(config.baseUrl + '/signup');\n    page = require('./signup.po');\n  };\n\n  var testUser = {\n    name: 'Test',\n    email: 'test@example.com',\n    password: 'test',\n    confirmPassword: 'test'\n  };\n\n  beforeEach(function(done) {\n    loadPage();\n    browser.wait(function() {\n        return browser.executeScript('return !!window.angular');\n    }, 5000).then(done);\n  });\n\n  it('should include signup form with correct inputs and submit button', function() {\n    expect(page.form.name.getAttribute('type')).toBe('text');\n    expect(page.form.name.getAttribute('name')).toBe('name');\n    expect(page.form.email.getAttribute('type')).toBe('email');\n    expect(page.form.email.getAttribute('name')).toBe('email');\n    expect(page.form.password.getAttribute('type')).toBe('password');\n    expect(page.form.password.getAttribute('name')).toBe('password');\n    expect(page.form.confirmPassword.getAttribute('type')).toBe('password');\n    expect(page.form.confirmPassword.getAttribute('name')).toBe('confirmPassword');\n    expect(page.form.submit.getAttribute('type')).toBe('submit');\n    expect(page.form.submit.getText()).toBe('Sign up');\n  });\n\n  it('should include oauth buttons with correct classes applied', function() {\n    expect(page.form.oauthButtons.facebook.getText()).toBe('Connect with Facebook');\n    expect(page.form.oauthButtons.facebook.getAttribute('class')).toMatch('btn-block');\n    expect(page.form.oauthButtons.google.getText()).toBe('Connect with Google+');\n    expect(page.form.oauthButtons.google.getAttribute('class')).toMatch('btn-block');\n    expect(page.form.oauthButtons.twitter.getText()).toBe('Connect with Twitter');\n    expect(page.form.oauthButtons.twitter.getAttribute('class')).toMatch('btn-block');\n  });\n\n  describe('with local auth', function() {\n\n    beforeAll(function(done) {\n      UserModel.removeAsync().then(done);\n    });\n\n    it('should signup a new user, log them in, and redirecting to \"/\"', function() {\n      page.signup(testUser);\n\n      var navbar = require('../../components/navbar/navbar.po');\n\n      expect(browser.getCurrentUrl()).toBe(config.baseUrl + '/');\n      expect(navbar.navbarAccountGreeting.getText()).toBe('Hello ' + testUser.name);\n    });\n\n    it('should indicate signup failures', function() {\n      page.signup(testUser);\n\n      expect(browser.getCurrentUrl()).toBe(config.baseUrl + '/signup');\n      expect(page.form.email.getAttribute('class')).toContain('ng-invalid-mongoose');\n\n      var helpBlock = page.form.element(by.css('.form-group.has-error .help-block.ng-binding'));\n      expect(helpBlock.getText()).toBe('The specified email address is already in use.');\n    });\n\n  });\n});\n"
  },
  {
    "path": "e2e/components/navbar/navbar.po.js",
    "content": "/**\n * This file uses the Page Object pattern to define the main page for tests\n * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ\n */\n\n'use strict';\n\nvar NavbarComponent = function() {\n  this.navbar = element(by.css('.navbar'));\n  this.navbarHeader = this.navbar.element(by.css('.navbar-header'));\n  this.navbarNav = this.navbar.element(by.css('#navbar-main .nav.navbar-nav:not(.navbar-right)'));\n  this.navbarAccount = this.navbar.element(by.css('#navbar-main .nav.navbar-nav.navbar-right'));\n  this.navbarAccountGreeting = this.navbarAccount.element(by.binding('getCurrentUser().name'));\n};\n\nmodule.exports = new NavbarComponent();\n"
  },
  {
    "path": "e2e/components/oauth-buttons/oauth-buttons.po.js",
    "content": "/**\n * This file uses the Page Object pattern to define the main page for tests\n * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ\n */\n\n'use strict';\n\nvar OauthButtons = function() {\n  var oauthButtons = this.oauthButtons = element(by.css('oauth-buttons'));\n  oauthButtons.facebook = oauthButtons.element(by.css('.btn.btn-social.btn-facebook'));\n  oauthButtons.google = oauthButtons.element(by.css('.btn.btn-social.btn-google'));\n  oauthButtons.twitter = oauthButtons.element(by.css('.btn.btn-social.btn-twitter'));\n};\n\nmodule.exports = new OauthButtons();\n"
  },
  {
    "path": "e2e/main/main.po.js",
    "content": "/**\n * This file uses the Page Object pattern to define the main page for tests\n * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ\n */\n\n'use strict';\n\nvar MainPage = function() {\n  this.heroEl = element(by.css('.hero-unit'));\n  this.h1El = this.heroEl.element(by.css('h1'));\n  this.imgEl = this.heroEl.element(by.css('img'));\n};\n\nmodule.exports = new MainPage();\n\n"
  },
  {
    "path": "e2e/main/main.spec.js",
    "content": "'use strict';\n\nvar config = browser.params;\n\ndescribe('Main View', function() {\n  var page;\n\n  beforeEach(function() {\n    browser.get(config.baseUrl + '/');\n    page = require('./main.po');\n  });\n\n  it('should include jumbotron with correct data', function() {\n    expect(page.h1El.getText()).toBe('\\'Allo, \\'Allo!');\n    expect(page.imgEl.getAttribute('src')).toMatch(/yeoman.png$/);\n    expect(page.imgEl.getAttribute('alt')).toBe('I\\'m Yeoman');\n  });\n});\n"
  },
  {
    "path": "karma.conf.js",
    "content": "// Karma configuration\n// http://karma-runner.github.io/0.10/config/configuration-file.html\n\nmodule.exports = function(config) {\n  config.set({\n    // base path, that will be used to resolve files and exclude\n    basePath: '',\n\n    // testing framework to use (jasmine/mocha/qunit/...)\n    frameworks: ['jasmine'],\n\n    // list of files / patterns to load in the browser\n    files: [\n      // bower:js\n      'client/bower_components/jquery/dist/jquery.js',\n      'client/bower_components/angular/angular.js',\n      'client/bower_components/angular-resource/angular-resource.js',\n      'client/bower_components/angular-cookies/angular-cookies.js',\n      'client/bower_components/angular-sanitize/angular-sanitize.js',\n      'client/bower_components/angular-bootstrap/ui-bootstrap-tpls.js',\n      'client/bower_components/lodash/dist/lodash.compat.js',\n      'client/bower_components/angular-socket-io/socket.js',\n      'client/bower_components/angular-ui-router/release/angular-ui-router.js',\n      'client/bower_components/angular-validation-match/dist/angular-validation-match.min.js',\n      'client/bower_components/pagedown/Markdown.Converter.js',\n      'client/bower_components/pagedown/Markdown.Sanitizer.js',\n      'client/bower_components/pagedown/Markdown.Extra.js',\n      'client/bower_components/pagedown/Markdown.Editor.js',\n      'client/bower_components/angular-pagedown/angular-pagedown.js',\n      'client/bower_components/ng-tags-input/ng-tags-input.min.js',\n      'client/bower_components/angular-messages/angular-messages.js',\n      'client/bower_components/moment/moment.js',\n      'client/bower_components/ngInfiniteScroll/build/ng-infinite-scroll.js',\n      'client/bower_components/angular-mocks/angular-mocks.js',\n      // endbower\n      'node_modules/socket.io-client/socket.io.js',\n      'client/app/app.js',\n      'client/{app,components}/**/*.module.js',\n      'client/{app,components}/**/*.js',\n      'client/{app,components}/**/*.html'\n    ],\n\n    preprocessors: {\n      '**/*.html': 'ng-html2js',\n      'client/{app,components}/**/*.js': 'babel'\n    },\n\n    ngHtml2JsPreprocessor: {\n      stripPrefix: 'client/'\n    },\n\n    babelPreprocessor: {\n      options: {\n        sourceMap: 'inline',\n        optional: [\n          'es7.classProperties'\n        ]\n      },\n      filename: function (file) {\n        return file.originalPath.replace(/\\.js$/, '.es5.js');\n      },\n      sourceFileName: function (file) {\n        return file.originalPath;\n      }\n    },\n\n    // list of files / patterns to exclude\n    exclude: [],\n\n    // web server port\n    port: 8080,\n\n    // level of logging\n    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG\n    logLevel: config.LOG_INFO,\n\n    // reporter types:\n    // - dots\n    // - progress (default)\n    // - spec (karma-spec-reporter)\n    // - junit\n    // - growl\n    // - coverage\n    reporters: ['spec'],\n\n    // enable / disable watching file and executing tests whenever any file changes\n    autoWatch: false,\n\n    // Start these browsers, currently available:\n    // - Chrome\n    // - ChromeCanary\n    // - Firefox\n    // - Opera\n    // - Safari (only Mac)\n    // - PhantomJS\n    // - IE (only Windows)\n    browsers: ['PhantomJS'],\n\n    // Continuous Integration mode\n    // if true, it capture browsers, run tests and exit\n    singleRun: false\n  });\n};\n"
  },
  {
    "path": "mocha.conf.js",
    "content": "'use strict';\n\n// Register the Babel require hook\nrequire('babel-core/register');\n\nvar chai = require('chai');\n\n// Load Chai assertions\nglobal.expect = chai.expect;\nglobal.assert = chai.assert;\nchai.should();\n\n// Load Sinon\nglobal.sinon = require('sinon');\n\n// Initialize Chai plugins\nchai.use(require('sinon-chai'));\nchai.use(require('chai-as-promised'));\nchai.use(require('chai-things'))\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"paizaqa\",\n  \"version\": \"0.0.0\",\n  \"main\": \"server/app.js\",\n  \"dependencies\": {\n    \"babel-runtime\": \"^5.8.20\",\n    \"bluebird\": \"^2.9.34\",\n    \"body-parser\": \"^1.13.3\",\n    \"composable-middleware\": \"^0.3.0\",\n    \"compression\": \"^1.5.2\",\n    \"connect-mongo\": \"^0.8.1\",\n    \"cookie-parser\": \"^1.3.5\",\n    \"ejs\": \"^2.3.3\",\n    \"errorhandler\": \"^1.4.2\",\n    \"express\": \"^4.13.3\",\n    \"express-jwt\": \"^3.0.0\",\n    \"express-session\": \"^1.11.3\",\n    \"jsonwebtoken\": \"^5.0.0\",\n    \"lodash\": \"^3.10.1\",\n    \"lusca\": \"^1.3.0\",\n    \"method-override\": \"^2.3.5\",\n    \"mongoose\": \"^4.1.2\",\n    \"morgan\": \"~1.6.1\",\n    \"passport\": \"~0.3.0\",\n    \"passport-facebook\": \"^2.0.0\",\n    \"passport-google-oauth\": \"~0.2.0\",\n    \"passport-local\": \"^1.0.0\",\n    \"passport-twitter\": \"^1.0.3\",\n    \"serve-favicon\": \"^2.3.0\",\n    \"socket.io\": \"^1.3.5\",\n    \"socket.io-client\": \"^1.3.5\",\n    \"socketio-jwt\": \"^4.2.0\",\n    \"tiny-segmenter\": \"r7kamura/tiny-segmenter\"\n  },\n  \"devDependencies\": {\n    \"autoprefixer\": \"^6.0.0\",\n    \"babel-core\": \"^5.6.4\",\n    \"grunt\": \"~0.4.5\",\n    \"grunt-wiredep\": \"^2.0.0\",\n    \"grunt-concurrent\": \"^2.0.1\",\n    \"grunt-contrib-clean\": \"~0.7.0\",\n    \"grunt-contrib-concat\": \"^0.5.1\",\n    \"grunt-contrib-copy\": \"^0.8.0\",\n    \"grunt-contrib-cssmin\": \"~0.14.0\",\n    \"grunt-contrib-imagemin\": \"~1.0.0\",\n    \"grunt-contrib-jshint\": \"~0.11.2\",\n    \"grunt-contrib-uglify\": \"~0.11.0\",\n    \"grunt-contrib-watch\": \"~0.6.1\",\n    \"grunt-babel\": \"~5.0.0\",\n    \"grunt-google-cdn\": \"~0.4.0\",\n    \"grunt-jscs\": \"^2.1.0\",\n    \"grunt-newer\": \"^1.1.1\",\n    \"grunt-ng-annotate\": \"^1.0.1\",\n    \"grunt-ng-constant\": \"^1.1.0\",\n    \"grunt-filerev\": \"^2.3.1\",\n    \"grunt-usemin\": \"^3.0.0\",\n    \"grunt-env\": \"~0.4.1\",\n    \"grunt-node-inspector\": \"^0.4.1\",\n    \"grunt-nodemon\": \"^0.4.0\",\n    \"grunt-angular-templates\": \"^0.5.4\",\n    \"grunt-dom-munger\": \"^3.4.0\",\n    \"grunt-protractor-runner\": \"^2.0.0\",\n    \"grunt-injector\": \"^0.6.0\",\n    \"grunt-karma\": \"~0.12.0\",\n    \"grunt-build-control\": \"^0.6.0\",\n    \"grunt-contrib-sass\": \"^0.9.0\",\n    \"jit-grunt\": \"^0.9.1\",\n    \"grunt-express-server\": \"^0.5.1\",\n    \"grunt-postcss\": \"~0.7.1\",\n    \"grunt-open\": \"~0.2.3\",\n    \"time-grunt\": \"^1.2.1\",\n    \"grunt-mocha-test\": \"~0.12.7\",\n    \"grunt-mocha-istanbul\": \"^3.0.1\",\n    \"open\": \"~0.0.4\",\n    \"jshint-stylish\": \"~2.1.0\",\n    \"connect-livereload\": \"^0.5.3\",\n    \"istanbul\": \"~0.4.1\",\n    \"chai\": \"^3.2.0\",\n    \"sinon\": \"^1.16.1\",\n    \"chai-as-promised\": \"^5.1.0\",\n    \"chai-things\": \"^0.2.0\",\n    \"karma\": \"~0.13.3\",\n    \"karma-ng-scenario\": \"~0.1.0\",\n    \"karma-firefox-launcher\": \"~0.1.6\",\n    \"karma-script-launcher\": \"~0.1.0\",\n    \"karma-chrome-launcher\": \"~0.2.0\",\n    \"karma-requirejs\": \"~0.2.2\",\n    \"karma-jade-preprocessor\": \"0.0.11\",\n    \"karma-phantomjs-launcher\": \"~0.2.0\",\n    \"karma-ng-html2js-preprocessor\": \"~0.2.0\",\n    \"karma-spec-reporter\": \"~0.0.20\",\n    \"sinon-chai\": \"^2.8.0\",\n    \"mocha\": \"^2.2.5\",\n    \"jasmine-core\": \"^2.3.4\",\n    \"karma-jasmine\": \"~0.3.0\",\n    \"jasmine-spec-reporter\": \"^2.4.0\",\n    \"karma-babel-preprocessor\": \"^5.2.1\",\n    \"requirejs\": \"~2.1.11\",\n    \"phantomjs\": \"^1.9.18\",\n    \"proxyquire\": \"^1.0.1\",\n    \"supertest\": \"^1.1.0\"\n  },\n  \"engines\": {\n    \"node\": \"^4.2.3\",\n    \"npm\": \"^2.14.7\"\n  },\n  \"scripts\": {\n    \"start\": \"node server\",\n    \"test\": \"grunt test\",\n    \"update-webdriver\": \"node node_modules/grunt-protractor-runner/node_modules/protractor/bin/webdriver-manager update\"\n  },\n  \"private\": true\n}\n"
  },
  {
    "path": "protractor.conf.js",
    "content": "// Protractor configuration\n// https://github.com/angular/protractor/blob/master/referenceConf.js\n\n'use strict';\n\nvar config = {\n  // The timeout for each script run on the browser. This should be longer\n  // than the maximum time your application needs to stabilize between tasks.\n  allScriptsTimeout: 110000,\n\n  // A base URL for your application under test. Calls to protractor.get()\n  // with relative paths will be prepended with this.\n  baseUrl: 'http://localhost:' + (process.env.PORT || '9000'),\n\n  // Credientials for Saucelabs\n  sauceUser: process.env.SAUCE_USERNAME,\n\n  sauceKey: process.env.SAUCE_ACCESS_KEY,\n\n  // list of files / patterns to load in the browser\n  specs: [\n    'e2e/**/*.spec.js'\n  ],\n\n  // Patterns to exclude.\n  exclude: [],\n\n  // ----- Capabilities to be passed to the webdriver instance ----\n  //\n  // For a full list of available capabilities, see\n  // https://code.google.com/p/selenium/wiki/DesiredCapabilities\n  // and\n  // https://code.google.com/p/selenium/source/browse/javascript/webdriver/capabilities.js\n  capabilities: {\n    'browserName': 'chrome',\n    'name': 'Fullstack E2E',\n    'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER,\n    'build': process.env.TRAVIS_BUILD_NUMBER\n  },\n\n  // ----- The test framework -----\n  //\n  // Jasmine and Cucumber are fully supported as a test and assertion framework.\n  // Mocha has limited beta support. You will need to include your own\n  // assertion framework if working with mocha.\n  framework: 'jasmine2',\n\n  // ----- Options to be passed to minijasminenode -----\n  //\n  // See the full list at https://github.com/jasmine/jasmine-npm\n  jasmineNodeOpts: {\n    defaultTimeoutInterval: 30000,\n    print: function() {}  // for jasmine-spec-reporter\n  },\n\n  // Prepare environment for tests\n  params: {\n    serverConfig: require('./server/config/environment')\n  },\n\n  onPrepare: function() {\n    require('babel-core/register');\n    var SpecReporter = require('jasmine-spec-reporter');\n    // add jasmine spec reporter\n    jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: true}));\n\n    var serverConfig = config.params.serverConfig;\n\n    // Setup mongo for tests\n    var mongoose = require('mongoose');\n    mongoose.connect(serverConfig.mongo.uri, serverConfig.mongo.options); // Connect to database\n  }\n};\n\nconfig.params.baseUrl = config.baseUrl;\nexports.config = config;\n"
  },
  {
    "path": "server/.jshintrc",
    "content": "{\n  \"expr\": true,\n  \"node\": true,\n  \"esnext\": true,\n  \"bitwise\": true,\n  \"eqeqeq\": true,\n  \"immed\": true,\n  \"latedef\": \"nofunc\",\n  \"newcap\": true,\n  \"noarg\": true,\n  \"undef\": true,\n  \"smarttabs\": true,\n  \"asi\": true,\n  \"debug\": true\n}\n"
  },
  {
    "path": "server/.jshintrc-spec",
    "content": "{\n  \"extends\": \".jshintrc\",\n  \"globals\": {\n    \"jasmine\": true,\n    \"describe\": true,\n    \"it\": true,\n    \"before\": true,\n    \"beforeEach\": true,\n    \"after\": true,\n    \"afterEach\": true,\n    \"expect\": true,\n    \"assert\": true,\n    \"sinon\": true\n  }\n}\n"
  },
  {
    "path": "server/api/question/index.js",
    "content": "'use strict';\n\nvar express = require('express');\nvar controller = require('./question.controller');\n\nvar router = express.Router();\n\nvar auth = require('../../auth/auth.service');\n\nrouter.get('/', controller.index);\nrouter.get('/:id', controller.show);\nrouter.post('/', auth.isAuthenticated(), controller.create);\nrouter.put('/:id', auth.isAuthenticated(), controller.update);\nrouter.patch('/:id', auth.isAuthenticated(), controller.update);\nrouter.delete('/:id', auth.isAuthenticated(), controller.destroy);\n\nrouter.post('/:id/answers', auth.isAuthenticated(), controller.createAnswer);\nrouter.put('/:id/answers/:answerId', auth.isAuthenticated(), controller.updateAnswer);\nrouter.delete('/:id/answers/:answerId', auth.isAuthenticated(), controller.destroyAnswer);\n\nrouter.post('/:id/comments', auth.isAuthenticated(), controller.createComment);\nrouter.put('/:id/comments/:commentId', auth.isAuthenticated(), controller.updateComment);\nrouter.delete('/:id/comments/:commentId', auth.isAuthenticated(), controller.destroyComment);\n\nrouter.post('/:id/answers/:answerId/comments', auth.isAuthenticated(), controller.createAnswerComment);\nrouter.put('/:id/answers/:answerId/comments/:commentId', auth.isAuthenticated(), controller.updateAnswerComment);\nrouter.delete('/:id/answers/:answerId/comments/:commentId', auth.isAuthenticated(), controller.destroyAnswerComment);\n\n\nrouter.put('/:id/star', auth.isAuthenticated(), controller.star);\nrouter.delete('/:id/star', auth.isAuthenticated(), controller.unstar);\nrouter.put('/:id/answers/:answerId/star', auth.isAuthenticated(), controller.starAnswer);\nrouter.delete('/:id/answers/:answerId/star', auth.isAuthenticated(), controller.unstarAnswer);\nrouter.put('/:id/comments/:commentId/star', auth.isAuthenticated(), controller.starComment);\nrouter.delete('/:id/comments/:commentId/star', auth.isAuthenticated(), controller.unstarComment);\nrouter.put('/:id/answers/:answerId/comments/:commentId/star', auth.isAuthenticated(), controller.starAnswerComment);\nrouter.delete('/:id/answers/:answerId/comments/:commentId/star', auth.isAuthenticated(), controller.unstarAnswerComment);\n\nmodule.exports = router;\n"
  },
  {
    "path": "server/api/question/question.controller.js",
    "content": "/**\n * Using Rails-like standard naming convention for endpoints.\n * GET     /api/questions              ->  index\n * POST    /api/questions              ->  create\n * GET     /api/questions/:id          ->  show\n * PUT     /api/questions/:id          ->  update\n * DELETE  /api/questions/:id          ->  destroy\n */\n\n'use strict';\n\nimport _ from 'lodash';\nimport Question from './question.model';\n\nfunction respondWithResult(res, statusCode) {\n  statusCode = statusCode || 200;\n  return function(entity) {\n    if (entity) {\n      res.status(statusCode).json(entity);\n    }\n  };\n}\n\nfunction saveUpdates(updates) {\n  return function(entity) {\n    var updated = _.merge(entity, updates);\n    return updated.saveAsync()\n      .spread(updated => {\n        return updated;\n      });\n  };\n}\n\nfunction removeEntity(res) {\n  return function(entity) {\n    if (entity) {\n      return entity.removeAsync()\n        .then(() => {\n          res.status(204).end();\n        });\n    }\n  };\n}\n\nfunction handleEntityNotFound(res) {\n  return function(entity) {\n    if (!entity) {\n      res.status(404).end();\n      return null;\n    }\n    return entity;\n  };\n}\n\nfunction handleError(res, statusCode) {\n  statusCode = statusCode || 500;\n  return function(err) {\n    res.status(statusCode).send(err);\n  };\n}\nfunction handleUnauthorized(req, res) {\n  return function(entity) {\n    if (!entity) {return null;}\n    if(entity.user._id.toString() !== req.user._id.toString()){\n      res.send(403).end();\n      return null;\n    }\n    return entity;\n  }\n}\n// Gets a list of Questions\nexport function index(req, res) {\n  var query = req.query.query && JSON.parse(req.query.query);\n  Question.find(query).sort({createdAt: -1}).limit(20).execAsync()\n    .then(respondWithResult(res))\n    .catch(handleError(res));\n}\n\n// Gets a single Question from the DB\nexport function show(req, res) {\n  Question.findByIdAsync(req.params.id)\n    .then(handleEntityNotFound(res))\n    .then(respondWithResult(res))\n    .catch(handleError(res));\n}\n\n// Creates a new Question in the DB\nexport function create(req, res) {\n  req.body.user = req.user;\n  Question.createAsync(req.body)\n    .then(respondWithResult(res, 201))\n    .catch(handleError(res));\n}\n\n// Updates an existing Question in the DB\nexport function update(req, res) {\n  if (req.body._id) {\n    delete req.body._id;\n  }\n  Question.findByIdAsync(req.params.id)\n    .then(handleEntityNotFound(res))\n    .then(handleUnauthorized(req, res))\n    .then(saveUpdates(req.body))\n    .then(respondWithResult(res))\n    .catch(handleError(res));\n}\n\n// Deletes a Question from the DB\nexport function destroy(req, res) {\n  Question.findByIdAsync(req.params.id)\n    .then(handleEntityNotFound(res))\n    .then(handleUnauthorized(req, res))\n    .then(removeEntity(res))\n    .catch(handleError(res));\n}\n\nexport function createAnswer(req, res) {\n  req.body.user = req.user;\n  Question.update({_id: req.params.id}, {$push: {answers: req.body}}, function(err, num) {\n    if(err) { return handleError(res)(err); }\n    if(num === 0) { return res.send(404).end(); }\n    exports.show(req, res);\n    Question.updateSearchText(req.params.id);\n  });\n}\n\nexport function destroyAnswer(req, res) {\n  Question.update({_id: req.params.id}, {$pull: {answers: {_id: req.params.answerId , 'user': req.user._id}}}, function(err, num) {\n    if(err) { return handleError(res)(err); }\n    if(num === 0) { return res.send(404).end(); }\n    exports.show(req, res);\n    Question.updateSearchText(req.params.id);\n  });\n}\n\nexport function updateAnswer(req, res) {\n  Question.update({_id: req.params.id, 'answers._id': req.params.answerId}, {'answers.$.content': req.body.content, 'answers.$.user': req.user.id}, function(err, num){\n    if(err) { return handleError(res)(err); }\n    if(num === 0) { return res.send(404).end(); }\n    exports.show(req, res);\n    Question.updateSearchText(req.params.id);\n  });\n}\n\n/* comments APIs */\nexport function createComment(req, res) {\n  req.body.user = req.user.id;\n  Question.update({_id: req.params.id}, {$push: {comments: req.body}}, function(err, num){\n    if(err) {return handleError(res)(err); }\n    if(num === 0) { return res.send(404).end(); }\n    exports.show(req, res);\n    Question.updateSearchText(req.params.id);\n  })\n}\nexport function destroyComment(req, res) {\n  Question.update({_id: req.params.id}, {$pull: {comments: {_id: req.params.commentId , 'user': req.user._id}}}, function(err, num) {\n    if(err) { return handleError(res)(err); }\n    if(num === 0) { return res.send(404).end(); }\n    exports.show(req, res);\n    Question.updateSearchText(req.params.id);\n  });\n}\nexport function updateComment(req, res) {\n  Question.update({_id: req.params.id, 'comments._id': req.params.commentId}, {'comments.$.content': req.body.content, 'comments.$.user': req.user.id}, function(err, num){\n    if(err) { return handleError(res)(err); }\n    if(num === 0) { return res.send(404).end(); }\n    exports.show(req, res);\n    Question.updateSearchText(req.params.id);\n  });\n}\n\n/* answersComments APIs */\nexport function createAnswerComment(req, res) {\n  req.body.user = req.user.id;\n  Question.update({_id: req.params.id, 'answers._id': req.params.answerId}, {$push: {'answers.$.comments': req.body}}, function(err, num){\n    if(err) {return handleError(res)(err); }\n    if(num === 0) { return res.send(404).end(); }\n    exports.show(req, res);\n    Question.updateSearchText(req.params.id);\n  })\n}\nexport function destroyAnswerComment(req, res) {\n  Question.update({_id: req.params.id, 'answers._id': req.params.answerId}, {$pull: {'answers.$.comments': {_id: req.params.commentId , 'user': req.user._id}}}, function(err, num) {\n    if(err) { return handleError(res)(err); }\n    if(num === 0) { return res.send(404).end(); }\n    exports.show(req, res);\n    Question.updateSearchText(req.params.id);\n  });\n}\nexport function updateAnswerComment(req, res) {\n  Question.find({_id: req.params.id}).exec(function(err, questions){\n    if(err) { return handleError(res)(err); }\n    if(questions.length === 0) { return res.send(404).end(); }\n    var question = questions[0];\n    var found = false;\n    for(var i=0; i < question.answers.length; i++){\n      if(question.answers[i]._id.toString() === req.params.answerId){\n        found = true;\n        var conditions = {};\n        conditions._id = req.params.id;\n        conditions['answers.' + i + '.comments._id'] = req.params.commentId;\n        conditions['answers.' + i + '.comments.user'] = req.user._id;\n        var doc = {};\n        doc['answers.' + i + '.comments.$.content'] = req.body.content;\n        /*jshint -W083 */\n        Question.update(conditions, doc, function(err, num){\n          if(err) { return handleError(res)(err); }\n          if(num === 0) { return res.send(404).end(); }\n          exports.show(req, res);\n          Question.updateSearchText(req.params.id);\n          return;\n        });\n      }\n    }\n    if(!found){\n      return res.send(404).end();\n    }\n  });\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/* star/unstar question */\nexport function star(req, res) {\n  Question.update({_id: req.params.id}, {$push: {stars: req.user.id}}, function(err, num){\n    if(err) { return handleError(res)(err); }\n    if(num === 0) { return res.send(404).end(); }\n    exports.show(req, res);\n  });\n}\nexport function unstar(req, res) {\n  Question.update({_id: req.params.id}, {$pull: {stars: req.user.id}}, function(err, num){\n    if(err) { return handleError(res, err); }\n    if(num === 0) { return res.send(404).end(); }\n    exports.show(req, res);\n  });\n}\n\n/* star/unstar answer */\nexport function starAnswer(req, res) {\n  Question.update({_id: req.params.id, 'answers._id': req.params.answerId}, {$push: {'answers.$.stars': req.user.id}}, function(err, num){\n    if(err) { return handleError(res)(err); }\n    if(num === 0) { return res.send(404).end(); }\n    exports.show(req, res);\n  });\n}\nexport function unstarAnswer(req, res) {\n  Question.update({_id: req.params.id, 'answers._id': req.params.answerId}, {$pull: {'answers.$.stars': req.user.id}}, function(err, num){\n    if(err) { return handleError(res)(err); }\n    if(num === 0) { return res.send(404).end(); }\n    exports.show(req, res);\n  });\n}\n\n/* star/unstar question comment */\nexport function starComment(req, res) {\n  Question.update({_id: req.params.id, 'comments._id': req.params.commentId}, {$push: {'comments.$.stars': req.user.id}}, function(err, num){\n    if(err) { return handleError(res)(err); }\n    if(num === 0) { return res.send(404).end(); }\n    exports.show(req, res);\n  });\n}\nexport function unstarComment(req, res) {\n  Question.update({_id: req.params.id, 'comments._id': req.params.commentId}, {$pull: {'comments.$.stars': req.user.id}}, function(err, num){\n    if(err) { return handleError(res)(err); }\n    if(num === 0) { return res.send(404).end(); }\n    exports.show(req, res);\n  });\n}\n\n/* star/unstar question answer comment */\nvar pushOrPullStarAnswerComment = function(op, req, res) {\n  Question.find({_id: req.params.id}).exec(function(err, questions){\n    if(err) { return handleError(res)(err); }\n    if(questions.length === 0) { return res.send(404).end(); }\n    var question = questions[0];\n    var found = false;\n    for(var i=0; i < question.answers.length; i++){\n      if(question.answers[i]._id.toString() === req.params.answerId){\n        found = true;\n        var conditions = {};\n        conditions._id = req.params.id;\n        conditions['answers.' + i + '.comments._id'] = req.params.commentId;\n        var doc = {};\n        doc[op] = {};\n        doc[op]['answers.' + i + '.comments.$.stars'] = req.user.id;\n        // Question.update({_id: req.params.id, 'answers.' + i + '.comments._id': req.params.commentId}, {op: {('answers.' + i + '.comments.$.stars'): req.user.id}}, function(err, num){\n        /*jshint -W083 */\n        Question.update(conditions, doc, function(err, num){\n          if(err) { return handleError(res)(err); }\n          if(num === 0) { return res.send(404).end(); }\n          exports.show(req, res);\n          return;\n        });\n      }\n    }\n    if(!found){\n      return res.send(404).end();\n    }\n  });\n};\nexport function starAnswerComment(req, res) {\n  pushOrPullStarAnswerComment('$push', req, res);\n}\nexport function unstarAnswerComment(req, res) {\n  pushOrPullStarAnswerComment('$pull', req, res);\n}\n"
  },
  {
    "path": "server/api/question/question.events.js",
    "content": "/**\n * Question model events\n */\n\n'use strict';\n\nimport {EventEmitter} from 'events';\nvar Question = require('./question.model');\nvar QuestionEvents = new EventEmitter();\n\n// Set max event listeners (0 == unlimited)\nQuestionEvents.setMaxListeners(0);\n\n// Model events\nvar events = {\n  'save': 'save',\n  'remove': 'remove'\n};\n\n// Register the event emitter to the model events\nfor (var e in events) {\n  var event = events[e];\n  Question.schema.post(e, emitEvent(event));\n}\n\nfunction emitEvent(event) {\n  return function(doc) {\n    QuestionEvents.emit(event + ':' + doc._id, doc);\n    QuestionEvents.emit(event, doc);\n  }\n}\n\nexport default QuestionEvents;\n"
  },
  {
    "path": "server/api/question/question.integration.js",
    "content": "'use strict';\n\nvar app = require('../..');\nimport request from 'supertest';\nvar User = require('../user/user.model');\n\nvar newQuestion;\n\ndescribe('Question API:', function() {\n  var user;\n  before(function() {\n    return User.removeAsync().then(function() {\n      user = new User({\n        name: 'Fake User',\n        email: 'test@test.com',\n        password: 'password'\n      });\n\n      return user.saveAsync();\n    });\n  });\n\n  var token;\n  before(function(done) {\n    request(app)\n      .post('/auth/local')\n      .send({\n        email: 'test@test.com',\n        password: 'password'\n      })\n      .expect(200)\n      .expect('Content-Type', /json/)\n      .end(function(err, res) {\n        token = res.body.token;\n        done();\n      });\n  });\n  \n  describe('GET /api/questions', function() {\n    var questions;\n\n    beforeEach(function(done) {\n      request(app)\n        .get('/api/questions')\n        .expect(200)\n        .expect('Content-Type', /json/)\n        .end((err, res) => {\n          if (err) {\n            return done(err);\n          }\n          questions = res.body;\n          done();\n        });\n    });\n\n    it('should respond with JSON array', function() {\n      questions.should.be.instanceOf(Array);\n    });\n\n  });\n\n  describe('POST /api/questions', function() {\n    beforeEach(function(done) {\n      request(app)\n        .post('/api/questions')\n        .set('authorization', 'Bearer ' + token)\n        .send({\n          title: 'New Question',\n          content: 'This is the brand new question!!!'\n        })\n        .expect(201)\n        .expect('Content-Type', /json/)\n        .end((err, res) => {\n          if (err) {\n            return done(err);\n          }\n          newQuestion = res.body;\n          console.warn(\"newQuestion:test1\",newQuestion);\n          done();\n        });\n    });\n\n    it('should respond with the newly created question', function() {\n          console.warn(\"newQuestion:test2\",newQuestion);\n      newQuestion.title.should.equal('New Question');\n      newQuestion.content.should.equal('This is the brand new question!!!');\n    });\n\n  });\n\n  describe('GET /api/questions/:id', function() {\n    var question;\n\n    beforeEach(function(done) {\n      request(app)\n        .get('/api/questions/' + newQuestion._id)\n        .expect(200)\n        .expect('Content-Type', /json/)\n        .end((err, res) => {\n          if (err) {\n            return done(err);\n          }\n          question = res.body;\n          done();\n        });\n    });\n\n    afterEach(function() {\n      question = {};\n    });\n\n    it('should respond with the requested question', function() {\n      question.title.should.equal('New Question');\n      question.content.should.equal('This is the brand new question!!!');\n    });\n\n  });\n\n/*\n  describe('PUT /api/questions/:id', function() {\n    var updatedQuestion;\n\n    beforeEach(function(done) {\n      request(app)\n        .put('/api/questions/' + newQuestion._id)\n        .set('authorization', 'Bearer ' + token)\n        .send({\n          title: 'Updated Question',\n          content: 'This is the updated question!!!'\n        })\n        .expect(200)\n        .expect('Content-Type', /json/)\n        .end(function(err, res) {\n          if (err) {\n            return done(err);\n          }\n          updatedQuestion = res.body;\n          done();\n        });\n    });\n    afterEach(function() {\n      updatedQuestion = {};\n    });\n\n    it('should respond with the updated question', function() {\n      updatedQuestion.title.should.equal('Updated Question');\n      updatedQuestion.content.should.equal('This is the updated question!!!');\n    });\n\n  });\n*/\n\n  describe('DELETE /api/questions/:id', function() {\n\n    it('should respond with 204 on successful removal', function(done) {\n      request(app)\n        .delete('/api/questions/' + newQuestion._id)\n        .set('authorization', 'Bearer ' + token)\n        .expect(204)\n        .end((err, res) => {\n          if (err) {\n            return done(err);\n          }\n          done();\n        });\n    });\n\n    it('should respond with 404 when question does not exist', function(done) {\n      request(app)\n        .delete('/api/questions/' + newQuestion._id)\n        .set('authorization', 'Bearer ' + token)\n        .expect(404)\n        .end((err, res) => {\n          if (err) {\n            return done(err);\n          }\n          done();\n        });\n    });\n\n  });\n\n});\n"
  },
  {
    "path": "server/api/question/question.model.js",
    "content": "'use strict';\n\nvar mongoose = require('bluebird').promisifyAll(require('mongoose'));\n\nvar QuestionSchema = new mongoose.Schema({\n  title: String,\n  content: String,\n  answers: [{\n    content: String,\n    user: {\n      type: mongoose.Schema.ObjectId,\n      ref: 'User'\n    },\n    createdAt: {\n      type: Date,\n      default: Date.now,\n    },\n    comments: [{\n      content: String,\n      stars: [{\n        type: mongoose.Schema.ObjectId,\n        ref: 'User'\n      }],\n      user: {\n        type: mongoose.Schema.ObjectId,\n        ref: 'User'\n      },\n      createdAt: {\n        type: Date,\n        default: Date.now,\n      }\n    }],\n    stars: [{\n      type: mongoose.Schema.ObjectId,\n      ref: 'User'\n    }],\n  }],\n  tags: [{\n    text: String,\n  }],\n  user: {\n    type: mongoose.Schema.ObjectId,\n    ref: 'User'\n  },\n  createdAt: {\n    type: Date,\n    default: Date.now\n  },\n  comments: [{\n    content: String,\n    stars: [{\n      type: mongoose.Schema.ObjectId,\n      ref: 'User'\n    }],\n    user: {\n      type: mongoose.Schema.ObjectId,\n      ref: 'User'\n    },\n    createdAt: {\n      type: Date,\n      default: Date.now,\n    }\n  }],\n  stars: [{\n    type: mongoose.Schema.ObjectId,\n    ref: 'User'\n  }],\n  searchText: String,\n});\nQuestionSchema.pre('find', function(next){\n  this.populate('user', 'name');\n  this.populate('comments.user', 'name');\n  this.populate('answers.user', 'name');\n  this.populate('answers.comments.user', 'name');\n  next();\n});\nQuestionSchema.pre('findOne', function(next){\n  this.populate('user', 'name');\n  this.populate('comments.user', 'name');\n  this.populate('answers.user', 'name');\n  this.populate('answers.comments.user', 'name');\n  next();\n});\n\nQuestionSchema.index({\n  'title': 'text',\n  'content': 'text',\n  'tags.text': 'text',\n  'answers.content': 'text',\n  'comments.content': 'text',\n  'answers.comments.content': 'text',\n  'searchText': 'text',\n}, {name: 'question_schema_index'});\n\nvar TinySegmenter = require('tiny-segmenter');\n\nvar getSearchText = function(question){\n  var tinySegmenter = new TinySegmenter();\n  var searchText = \"\";\n  searchText += tinySegmenter.segment(question.title).join(' ') + \" \";\n  searchText += tinySegmenter.segment(question.content).join(' ') + \" \";\n  question.answers.forEach(function(answer){\n    searchText += tinySegmenter.segment(answer.content).join(' ') + \" \";\n    answer.comments.forEach(function(comment){\n      searchText += tinySegmenter.segment(comment.content).join(' ') + \" \";\n    });\n  });\n  question.comments.forEach(function(comment){\n    searchText += tinySegmenter.segment(comment.content).join(' ') + \" \";\n  });\n  console.log(\"searchText\", searchText);\n  return searchText;\n};\nQuestionSchema.statics.updateSearchText = function(id, cb){\n  this.findOne({_id: id}).exec(function(err, question){\n    if(err){ if(cb){cb(err);} return; }\n    var searchText = getSearchText(question);\n    this.update({_id: id}, {searchText: searchText}, function(err, num){\n      if(cb){cb(err);}\n    });\n  }.bind(this));\n};\n\nQuestionSchema.pre('save', function(next){\n  this.searchText = getSearchText(this);\n  next();\n});\n\nexport default mongoose.model('Question', QuestionSchema);\n"
  },
  {
    "path": "server/api/question/question.socket.js",
    "content": "/**\n * Broadcast updates to client when the model changes\n */\n\n'use strict';\n\nvar QuestionEvents = require('./question.events');\n\n// Model events to emit\nvar events = ['save', 'remove'];\n\nexport function register(socket) {\n  // Bind model events to socket events\n  for (var i = 0, eventsLength = events.length; i < eventsLength; i++) {\n    var event = events[i];\n    var listener = createListener('question:' + event, socket);\n\n    QuestionEvents.on(event, listener);\n    socket.on('disconnect', removeListener(event, listener));\n  }\n}\n\n\nfunction createListener(event, socket) {\n  return function(doc) {\n    socket.emit(event, doc);\n  };\n}\n\nfunction removeListener(event, listener) {\n  return function() {\n    QuestionEvents.removeListener(event, listener);\n  };\n}\n"
  },
  {
    "path": "server/api/thing/index.js",
    "content": "'use strict';\n\nvar express = require('express');\nvar controller = require('./thing.controller');\n\nvar router = express.Router();\n\nrouter.get('/', controller.index);\nrouter.get('/:id', controller.show);\nrouter.post('/', controller.create);\nrouter.put('/:id', controller.update);\nrouter.patch('/:id', controller.update);\nrouter.delete('/:id', controller.destroy);\n\nmodule.exports = router;\n"
  },
  {
    "path": "server/api/thing/index.spec.js",
    "content": "'use strict';\n\nvar proxyquire = require('proxyquire').noPreserveCache();\n\nvar thingCtrlStub = {\n  index: 'thingCtrl.index',\n  show: 'thingCtrl.show',\n  create: 'thingCtrl.create',\n  update: 'thingCtrl.update',\n  destroy: 'thingCtrl.destroy'\n};\n\nvar routerStub = {\n  get: sinon.spy(),\n  put: sinon.spy(),\n  patch: sinon.spy(),\n  post: sinon.spy(),\n  delete: sinon.spy()\n};\n\n// require the index with our stubbed out modules\nvar thingIndex = proxyquire('./index.js', {\n  'express': {\n    Router: function() {\n      return routerStub;\n    }\n  },\n  './thing.controller': thingCtrlStub\n});\n\ndescribe('Thing API Router:', function() {\n\n  it('should return an express router instance', function() {\n    thingIndex.should.equal(routerStub);\n  });\n\n  describe('GET /api/things', function() {\n\n    it('should route to thing.controller.index', function() {\n      routerStub.get\n        .withArgs('/', 'thingCtrl.index')\n        .should.have.been.calledOnce;\n    });\n\n  });\n\n  describe('GET /api/things/:id', function() {\n\n    it('should route to thing.controller.show', function() {\n      routerStub.get\n        .withArgs('/:id', 'thingCtrl.show')\n        .should.have.been.calledOnce;\n    });\n\n  });\n\n  describe('POST /api/things', function() {\n\n    it('should route to thing.controller.create', function() {\n      routerStub.post\n        .withArgs('/', 'thingCtrl.create')\n        .should.have.been.calledOnce;\n    });\n\n  });\n\n  describe('PUT /api/things/:id', function() {\n\n    it('should route to thing.controller.update', function() {\n      routerStub.put\n        .withArgs('/:id', 'thingCtrl.update')\n        .should.have.been.calledOnce;\n    });\n\n  });\n\n  describe('PATCH /api/things/:id', function() {\n\n    it('should route to thing.controller.update', function() {\n      routerStub.patch\n        .withArgs('/:id', 'thingCtrl.update')\n        .should.have.been.calledOnce;\n    });\n\n  });\n\n  describe('DELETE /api/things/:id', function() {\n\n    it('should route to thing.controller.destroy', function() {\n      routerStub.delete\n        .withArgs('/:id', 'thingCtrl.destroy')\n        .should.have.been.calledOnce;\n    });\n\n  });\n\n});\n"
  },
  {
    "path": "server/api/thing/thing.controller.js",
    "content": "/**\n * Using Rails-like standard naming convention for endpoints.\n * GET     /api/things              ->  index\n * POST    /api/things              ->  create\n * GET     /api/things/:id          ->  show\n * PUT     /api/things/:id          ->  update\n * DELETE  /api/things/:id          ->  destroy\n */\n\n'use strict';\n\nimport _ from 'lodash';\nimport Thing from './thing.model';\n\nfunction respondWithResult(res, statusCode) {\n  statusCode = statusCode || 200;\n  return function(entity) {\n    if (entity) {\n      res.status(statusCode).json(entity);\n    }\n  };\n}\n\nfunction saveUpdates(updates) {\n  return function(entity) {\n    var updated = _.merge(entity, updates);\n    return updated.saveAsync()\n      .spread(updated => {\n        return updated;\n      });\n  };\n}\n\nfunction removeEntity(res) {\n  return function(entity) {\n    if (entity) {\n      return entity.removeAsync()\n        .then(() => {\n          res.status(204).end();\n        });\n    }\n  };\n}\n\nfunction handleEntityNotFound(res) {\n  return function(entity) {\n    if (!entity) {\n      res.status(404).end();\n      return null;\n    }\n    return entity;\n  };\n}\n\nfunction handleError(res, statusCode) {\n  statusCode = statusCode || 500;\n  return function(err) {\n    res.status(statusCode).send(err);\n  };\n}\n\n// Gets a list of Things\nexport function index(req, res) {\n  Thing.findAsync()\n    .then(respondWithResult(res))\n    .catch(handleError(res));\n}\n\n// Gets a single Thing from the DB\nexport function show(req, res) {\n  Thing.findByIdAsync(req.params.id)\n    .then(handleEntityNotFound(res))\n    .then(respondWithResult(res))\n    .catch(handleError(res));\n}\n\n// Creates a new Thing in the DB\nexport function create(req, res) {\n  Thing.createAsync(req.body)\n    .then(respondWithResult(res, 201))\n    .catch(handleError(res));\n}\n\n// Updates an existing Thing in the DB\nexport function update(req, res) {\n  if (req.body._id) {\n    delete req.body._id;\n  }\n  Thing.findByIdAsync(req.params.id)\n    .then(handleEntityNotFound(res))\n    .then(saveUpdates(req.body))\n    .then(respondWithResult(res))\n    .catch(handleError(res));\n}\n\n// Deletes a Thing from the DB\nexport function destroy(req, res) {\n  Thing.findByIdAsync(req.params.id)\n    .then(handleEntityNotFound(res))\n    .then(removeEntity(res))\n    .catch(handleError(res));\n}\n"
  },
  {
    "path": "server/api/thing/thing.events.js",
    "content": "/**\n * Thing model events\n */\n\n'use strict';\n\nimport {EventEmitter} from 'events';\nvar Thing = require('./thing.model');\nvar ThingEvents = new EventEmitter();\n\n// Set max event listeners (0 == unlimited)\nThingEvents.setMaxListeners(0);\n\n// Model events\nvar events = {\n  'save': 'save',\n  'remove': 'remove'\n};\n\n// Register the event emitter to the model events\nfor (var e in events) {\n  var event = events[e];\n  Thing.schema.post(e, emitEvent(event));\n}\n\nfunction emitEvent(event) {\n  return function(doc) {\n    ThingEvents.emit(event + ':' + doc._id, doc);\n    ThingEvents.emit(event, doc);\n  }\n}\n\nexport default ThingEvents;\n"
  },
  {
    "path": "server/api/thing/thing.integration.js",
    "content": "'use strict';\n\nvar app = require('../..');\nimport request from 'supertest';\n\nvar newThing;\n\ndescribe('Thing API:', function() {\n\n  describe('GET /api/things', function() {\n    var things;\n\n    beforeEach(function(done) {\n      request(app)\n        .get('/api/things')\n        .expect(200)\n        .expect('Content-Type', /json/)\n        .end((err, res) => {\n          if (err) {\n            return done(err);\n          }\n          things = res.body;\n          done();\n        });\n    });\n\n    it('should respond with JSON array', function() {\n      things.should.be.instanceOf(Array);\n    });\n\n  });\n\n  describe('POST /api/things', function() {\n    beforeEach(function(done) {\n      request(app)\n        .post('/api/things')\n        .send({\n          name: 'New Thing',\n          info: 'This is the brand new thing!!!'\n        })\n        .expect(201)\n        .expect('Content-Type', /json/)\n        .end((err, res) => {\n          if (err) {\n            return done(err);\n          }\n          newThing = res.body;\n          done();\n        });\n    });\n\n    it('should respond with the newly created thing', function() {\n      newThing.name.should.equal('New Thing');\n      newThing.info.should.equal('This is the brand new thing!!!');\n    });\n\n  });\n\n  describe('GET /api/things/:id', function() {\n    var thing;\n\n    beforeEach(function(done) {\n      request(app)\n        .get('/api/things/' + newThing._id)\n        .expect(200)\n        .expect('Content-Type', /json/)\n        .end((err, res) => {\n          if (err) {\n            return done(err);\n          }\n          thing = res.body;\n          done();\n        });\n    });\n\n    afterEach(function() {\n      thing = {};\n    });\n\n    it('should respond with the requested thing', function() {\n      thing.name.should.equal('New Thing');\n      thing.info.should.equal('This is the brand new thing!!!');\n    });\n\n  });\n\n  describe('PUT /api/things/:id', function() {\n    var updatedThing;\n\n    beforeEach(function(done) {\n      request(app)\n        .put('/api/things/' + newThing._id)\n        .send({\n          name: 'Updated Thing',\n          info: 'This is the updated thing!!!'\n        })\n        .expect(200)\n        .expect('Content-Type', /json/)\n        .end(function(err, res) {\n          if (err) {\n            return done(err);\n          }\n          updatedThing = res.body;\n          done();\n        });\n    });\n\n    afterEach(function() {\n      updatedThing = {};\n    });\n\n    it('should respond with the updated thing', function() {\n      updatedThing.name.should.equal('Updated Thing');\n      updatedThing.info.should.equal('This is the updated thing!!!');\n    });\n\n  });\n\n  describe('DELETE /api/things/:id', function() {\n\n    it('should respond with 204 on successful removal', function(done) {\n      request(app)\n        .delete('/api/things/' + newThing._id)\n        .expect(204)\n        .end((err, res) => {\n          if (err) {\n            return done(err);\n          }\n          done();\n        });\n    });\n\n    it('should respond with 404 when thing does not exist', function(done) {\n      request(app)\n        .delete('/api/things/' + newThing._id)\n        .expect(404)\n        .end((err, res) => {\n          if (err) {\n            return done(err);\n          }\n          done();\n        });\n    });\n\n  });\n\n});\n"
  },
  {
    "path": "server/api/thing/thing.model.js",
    "content": "'use strict';\n\nvar mongoose = require('bluebird').promisifyAll(require('mongoose'));\n\nvar ThingSchema = new mongoose.Schema({\n  name: String,\n  info: String,\n  active: Boolean\n});\n\nexport default mongoose.model('Thing', ThingSchema);\n"
  },
  {
    "path": "server/api/thing/thing.socket.js",
    "content": "/**\n * Broadcast updates to client when the model changes\n */\n\n'use strict';\n\nvar ThingEvents = require('./thing.events');\n\n// Model events to emit\nvar events = ['save', 'remove'];\n\nexport function register(socket) {\n  // Bind model events to socket events\n  for (var i = 0, eventsLength = events.length; i < eventsLength; i++) {\n    var event = events[i];\n    var listener = createListener('thing:' + event, socket);\n\n    ThingEvents.on(event, listener);\n    socket.on('disconnect', removeListener(event, listener));\n  }\n}\n\n\nfunction createListener(event, socket) {\n  return function(doc) {\n    socket.emit(event, doc);\n  };\n}\n\nfunction removeListener(event, listener) {\n  return function() {\n    ThingEvents.removeListener(event, listener);\n  };\n}\n"
  },
  {
    "path": "server/api/user/index.js",
    "content": "'use strict';\n\nimport {Router} from 'express';\nimport * as controller from './user.controller';\nimport * as auth from '../../auth/auth.service';\n\nvar router = new Router();\n\nrouter.get('/', auth.hasRole('admin'), controller.index);\nrouter.delete('/:id', auth.hasRole('admin'), controller.destroy);\nrouter.get('/me', auth.isAuthenticated(), controller.me);\nrouter.put('/:id/password', auth.isAuthenticated(), controller.changePassword);\nrouter.get('/:id', auth.isAuthenticated(), controller.show);\nrouter.post('/', controller.create);\n\nexport default router;\n"
  },
  {
    "path": "server/api/user/index.spec.js",
    "content": "'use strict';\n\nvar proxyquire = require('proxyquire').noPreserveCache();\n\nvar userCtrlStub = {\n  index: 'userCtrl.index',\n  destroy: 'userCtrl.destroy',\n  me: 'userCtrl.me',\n  changePassword: 'userCtrl.changePassword',\n  show: 'userCtrl.show',\n  create: 'userCtrl.create'\n};\n\nvar authServiceStub = {\n  isAuthenticated() {\n    return 'authService.isAuthenticated';\n  },\n  hasRole(role) {\n    return 'authService.hasRole.' + role;\n  }\n};\n\nvar routerStub = {\n  get: sinon.spy(),\n  put: sinon.spy(),\n  post: sinon.spy(),\n  delete: sinon.spy()\n};\n\n// require the index with our stubbed out modules\nvar userIndex = proxyquire('./index', {\n  'express': {\n    Router() {\n      return routerStub;\n    }\n  },\n  './user.controller': userCtrlStub,\n  '../../auth/auth.service': authServiceStub\n});\n\ndescribe('User API Router:', function() {\n\n  it('should return an express router instance', function() {\n    userIndex.should.equal(routerStub);\n  });\n\n  describe('GET /api/users', function() {\n\n    it('should verify admin role and route to user.controller.index', function() {\n      routerStub.get\n        .withArgs('/', 'authService.hasRole.admin', 'userCtrl.index')\n        .should.have.been.calledOnce;\n    });\n\n  });\n\n  describe('DELETE /api/users/:id', function() {\n\n    it('should verify admin role and route to user.controller.destroy', function() {\n      routerStub.delete\n        .withArgs('/:id', 'authService.hasRole.admin', 'userCtrl.destroy')\n        .should.have.been.calledOnce;\n    });\n\n  });\n\n  describe('GET /api/users/me', function() {\n\n    it('should be authenticated and route to user.controller.me', function() {\n      routerStub.get\n        .withArgs('/me', 'authService.isAuthenticated', 'userCtrl.me')\n        .should.have.been.calledOnce;\n    });\n\n  });\n\n  describe('PUT /api/users/:id/password', function() {\n\n    it('should be authenticated and route to user.controller.changePassword', function() {\n      routerStub.put\n        .withArgs('/:id/password', 'authService.isAuthenticated', 'userCtrl.changePassword')\n        .should.have.been.calledOnce;\n    });\n\n  });\n\n  describe('GET /api/users/:id', function() {\n\n    it('should be authenticated and route to user.controller.show', function() {\n      routerStub.get\n        .withArgs('/:id', 'authService.isAuthenticated', 'userCtrl.show')\n        .should.have.been.calledOnce;\n    });\n\n  });\n\n  describe('POST /api/users', function() {\n\n    it('should route to user.controller.create', function() {\n      routerStub.post\n        .withArgs('/', 'userCtrl.create')\n        .should.have.been.calledOnce;\n    });\n\n  });\n\n});\n"
  },
  {
    "path": "server/api/user/user.controller.js",
    "content": "'use strict';\n\nimport User from './user.model';\nimport passport from 'passport';\nimport config from '../../config/environment';\nimport jwt from 'jsonwebtoken';\n\nfunction validationError(res, statusCode) {\n  statusCode = statusCode || 422;\n  return function(err) {\n    res.status(statusCode).json(err);\n  }\n}\n\nfunction handleError(res, statusCode) {\n  statusCode = statusCode || 500;\n  return function(err) {\n    res.status(statusCode).send(err);\n  };\n}\n\n/**\n * Get list of users\n * restriction: 'admin'\n */\nexport function index(req, res) {\n  User.findAsync({}, '-salt -password')\n    .then(users => {\n      res.status(200).json(users);\n    })\n    .catch(handleError(res));\n}\n\n/**\n * Creates a new user\n */\nexport function create(req, res, next) {\n  var newUser = new User(req.body);\n  newUser.provider = 'local';\n  newUser.role = 'user';\n  newUser.saveAsync()\n    .spread(function(user) {\n      var token = jwt.sign({ _id: user._id }, config.secrets.session, {\n        expiresIn: 60 * 60 * 5\n      });\n      res.json({ token });\n    })\n    .catch(validationError(res));\n}\n\n/**\n * Get a single user\n */\nexport function show(req, res, next) {\n  var userId = req.params.id;\n\n  User.findByIdAsync(userId)\n    .then(user => {\n      if (!user) {\n        return res.status(404).end();\n      }\n      res.json(user.profile);\n    })\n    .catch(err => next(err));\n}\n\n/**\n * Deletes a user\n * restriction: 'admin'\n */\nexport function destroy(req, res) {\n  User.findByIdAndRemoveAsync(req.params.id)\n    .then(function() {\n      res.status(204).end();\n    })\n    .catch(handleError(res));\n}\n\n/**\n * Change a users password\n */\nexport function changePassword(req, res, next) {\n  var userId = req.user._id;\n  var oldPass = String(req.body.oldPassword);\n  var newPass = String(req.body.newPassword);\n\n  User.findByIdAsync(userId)\n    .then(user => {\n      if (user.authenticate(oldPass)) {\n        user.password = newPass;\n        return user.saveAsync()\n          .then(() => {\n            res.status(204).end();\n          })\n          .catch(validationError(res));\n      } else {\n        return res.status(403).end();\n      }\n    });\n}\n\n/**\n * Get my info\n */\nexport function me(req, res, next) {\n  var userId = req.user._id;\n\n  User.findOneAsync({ _id: userId }, '-salt -password')\n    .then(user => { // don't ever give out the password or salt\n      if (!user) {\n        return res.status(401).end();\n      }\n      res.json(user);\n    })\n    .catch(err => next(err));\n}\n\n/**\n * Authentication callback\n */\nexport function authCallback(req, res, next) {\n  res.redirect('/');\n}\n"
  },
  {
    "path": "server/api/user/user.events.js",
    "content": "/**\n * User model events\n */\n\n'use strict';\n\nimport {EventEmitter} from 'events';\nimport User from './user.model';\nvar UserEvents = new EventEmitter();\n\n// Set max event listeners (0 == unlimited)\nUserEvents.setMaxListeners(0);\n\n// Model events\nvar events = {\n  'save': 'save',\n  'remove': 'remove'\n};\n\n// Register the event emitter to the model events\nfor (var e in events) {\n  var event = events[e];\n  User.schema.post(e, emitEvent(event));\n}\n\nfunction emitEvent(event) {\n  return function(doc) {\n    UserEvents.emit(event + ':' + doc._id, doc);\n    UserEvents.emit(event, doc);\n  }\n}\n\nexport default UserEvents;\n"
  },
  {
    "path": "server/api/user/user.integration.js",
    "content": "'use strict';\n\nimport app from '../..';\nimport User from './user.model';\nimport request from 'supertest';\n\ndescribe('User API:', function() {\n  var user;\n\n  // Clear users before testing\n  before(function() {\n    return User.removeAsync().then(function() {\n      user = new User({\n        name: 'Fake User',\n        email: 'test@example.com',\n        password: 'password'\n      });\n\n      return user.saveAsync();\n    });\n  });\n\n  // Clear users after testing\n  after(function() {\n    return User.removeAsync();\n  });\n\n  describe('GET /api/users/me', function() {\n    var token;\n\n    before(function(done) {\n      request(app)\n        .post('/auth/local')\n        .send({\n          email: 'test@example.com',\n          password: 'password'\n        })\n        .expect(200)\n        .expect('Content-Type', /json/)\n        .end((err, res) => {\n          token = res.body.token;\n          done();\n        });\n    });\n\n    it('should respond with a user profile when authenticated', function(done) {\n      request(app)\n        .get('/api/users/me')\n        .set('authorization', 'Bearer ' + token)\n        .expect(200)\n        .expect('Content-Type', /json/)\n        .end((err, res) => {\n          res.body._id.toString().should.equal(user._id.toString());\n          done();\n        });\n    });\n\n    it('should respond with a 401 when not authenticated', function(done) {\n      request(app)\n        .get('/api/users/me')\n        .expect(401)\n        .end(done);\n    });\n  });\n});\n"
  },
  {
    "path": "server/api/user/user.model.js",
    "content": "'use strict';\n\nimport crypto from 'crypto';\nvar mongoose = require('bluebird').promisifyAll(require('mongoose'));\nimport {Schema} from 'mongoose';\n\nconst authTypes = ['github', 'twitter', 'facebook', 'google'];\n\nvar UserSchema = new Schema({\n  name: String,\n  email: {\n    type: String,\n    lowercase: true\n  },\n  role: {\n    type: String,\n    default: 'user'\n  },\n  password: String,\n  provider: String,\n  salt: String,\n  facebook: {},\n  twitter: {},\n  google: {},\n  github: {}\n});\n\n/**\n * Virtuals\n */\n\n// Public profile information\nUserSchema\n  .virtual('profile')\n  .get(function() {\n    return {\n      'name': this.name,\n      'role': this.role\n    };\n  });\n\n// Non-sensitive info we'll be putting in the token\nUserSchema\n  .virtual('token')\n  .get(function() {\n    return {\n      '_id': this._id,\n      'role': this.role\n    };\n  });\n\n/**\n * Validations\n */\n\n// Validate empty email\nUserSchema\n  .path('email')\n  .validate(function(email) {\n    if (authTypes.indexOf(this.provider) !== -1) {\n      return true;\n    }\n    return email.length;\n  }, 'Email cannot be blank');\n\n// Validate empty password\nUserSchema\n  .path('password')\n  .validate(function(password) {\n    if (authTypes.indexOf(this.provider) !== -1) {\n      return true;\n    }\n    return password.length;\n  }, 'Password cannot be blank');\n\n// Validate email is not taken\nUserSchema\n  .path('email')\n  .validate(function(value, respond) {\n    var self = this;\n    return this.constructor.findOneAsync({ email: value })\n      .then(function(user) {\n        if (user) {\n          if (self.id === user.id) {\n            return respond(true);\n          }\n          return respond(false);\n        }\n        return respond(true);\n      })\n      .catch(function(err) {\n        throw err;\n      });\n  }, 'The specified email address is already in use.');\n\nvar validatePresenceOf = function(value) {\n  return value && value.length;\n};\n\n/**\n * Pre-save hook\n */\nUserSchema\n  .pre('save', function(next) {\n    // Handle new/update passwords\n    if (!this.isModified('password')) {\n      return next();\n    }\n\n    if (!validatePresenceOf(this.password) && authTypes.indexOf(this.provider) === -1) {\n      next(new Error('Invalid password'));\n    }\n\n    // Make salt with a callback\n    this.makeSalt((saltErr, salt) => {\n      if (saltErr) {\n        next(saltErr);\n      }\n      this.salt = salt;\n      this.encryptPassword(this.password, (encryptErr, hashedPassword) => {\n        if (encryptErr) {\n          next(encryptErr);\n        }\n        this.password = hashedPassword;\n        next();\n      });\n    });\n  });\n\n/**\n * Methods\n */\nUserSchema.methods = {\n  /**\n   * Authenticate - check if the passwords are the same\n   *\n   * @param {String} password\n   * @param {Function} callback\n   * @return {Boolean}\n   * @api public\n   */\n  authenticate(password, callback) {\n    if (!callback) {\n      return this.password === this.encryptPassword(password);\n    }\n\n    this.encryptPassword(password, (err, pwdGen) => {\n      if (err) {\n        return callback(err);\n      }\n\n      if (this.password === pwdGen) {\n        callback(null, true);\n      } else {\n        callback(null, false);\n      }\n    });\n  },\n\n  /**\n   * Make salt\n   *\n   * @param {Number} byteSize Optional salt byte size, default to 16\n   * @param {Function} callback\n   * @return {String}\n   * @api public\n   */\n  makeSalt(byteSize, callback) {\n    var defaultByteSize = 16;\n\n    if (typeof arguments[0] === 'function') {\n      callback = arguments[0];\n      byteSize = defaultByteSize;\n    } else if (typeof arguments[1] === 'function') {\n      callback = arguments[1];\n    }\n\n    if (!byteSize) {\n      byteSize = defaultByteSize;\n    }\n\n    if (!callback) {\n      return crypto.randomBytes(byteSize).toString('base64');\n    }\n\n    return crypto.randomBytes(byteSize, (err, salt) => {\n      if (err) {\n        callback(err);\n      } else {\n        callback(null, salt.toString('base64'));\n      }\n    });\n  },\n\n  /**\n   * Encrypt password\n   *\n   * @param {String} password\n   * @param {Function} callback\n   * @return {String}\n   * @api public\n   */\n  encryptPassword(password, callback) {\n    if (!password || !this.salt) {\n      return null;\n    }\n\n    var defaultIterations = 10000;\n    var defaultKeyLength = 64;\n    var salt = new Buffer(this.salt, 'base64');\n\n    if (!callback) {\n      return crypto.pbkdf2Sync(password, salt, defaultIterations, defaultKeyLength)\n                   .toString('base64');\n    }\n\n    return crypto.pbkdf2(password, salt, defaultIterations, defaultKeyLength, (err, key) => {\n      if (err) {\n        callback(err);\n      } else {\n        callback(null, key.toString('base64'));\n      }\n    });\n  }\n};\n\nexport default mongoose.model('User', UserSchema);\n"
  },
  {
    "path": "server/api/user/user.model.spec.js",
    "content": "'use strict';\n\nimport app from '../..';\nimport User from './user.model';\nvar user;\nvar genUser = function() {\n  user = new User({\n    provider: 'local',\n    name: 'Fake User',\n    email: 'test@example.com',\n    password: 'password'\n  });\n  return user;\n};\n\ndescribe('User Model', function() {\n  before(function() {\n    // Clear users before testing\n    return User.removeAsync();\n  });\n\n  beforeEach(function() {\n    genUser();\n  });\n\n  afterEach(function() {\n    return User.removeAsync();\n  });\n\n  it('should begin with no users', function() {\n    return User.findAsync({}).should\n      .eventually.have.length(0);\n  });\n\n  it('should fail when saving a duplicate user', function() {\n    return user.saveAsync()\n      .then(function() {\n        var userDup = genUser();\n        return userDup.saveAsync();\n      }).should.be.rejected;\n  });\n\n  describe('#email', function() {\n    it('should fail when saving without an email', function() {\n      user.email = '';\n      return user.saveAsync().should.be.rejected;\n    });\n  });\n\n  describe('#password', function() {\n    beforeEach(function() {\n      return user.saveAsync();\n    });\n\n    it('should authenticate user if valid', function() {\n      user.authenticate('password').should.be.true;\n    });\n\n    it('should not authenticate user if invalid', function() {\n      user.authenticate('blah').should.not.be.true;\n    });\n\n    it('should remain the same hash unless the password is updated', function() {\n      user.name = 'Test User';\n      return user.saveAsync()\n        .spread(function(u) {\n          return u.authenticate('password');\n        }).should.eventually.be.true;\n    });\n  });\n\n});\n"
  },
  {
    "path": "server/app.js",
    "content": "/**\n * Main application file\n */\n\n'use strict';\n\nimport express from 'express';\nimport mongoose from 'mongoose';\nmongoose.Promise = require('bluebird');\nimport config from './config/environment';\nimport http from 'http';\n\n// Connect to MongoDB\nmongoose.connect(config.mongo.uri, config.mongo.options);\nmongoose.connection.on('error', function(err) {\n  console.error('MongoDB connection error: ' + err);\n  process.exit(-1);\n});\n\n// Populate databases with sample data\nif (config.seedDB) { require('./config/seed'); }\n\n// Setup server\nvar app = express();\nvar server = http.createServer(app);\nvar socketio = require('socket.io')(server, {\n  serveClient: config.env !== 'production',\n  path: '/socket.io-client'\n});\nrequire('./config/socketio')(socketio);\nrequire('./config/express')(app);\nrequire('./routes')(app);\n\n// Start server\nfunction startServer() {\n  app.angularFullstack = server.listen(config.port, config.ip, function() {\n    console.log('Express server listening on %d, in %s mode', config.port, app.get('env'));\n  });\n}\n\nsetImmediate(startServer);\n\n// Expose app\nexports = module.exports = app;\n"
  },
  {
    "path": "server/auth/auth.service.js",
    "content": "'use strict';\n\nimport passport from 'passport';\nimport config from '../config/environment';\nimport jwt from 'jsonwebtoken';\nimport expressJwt from 'express-jwt';\nimport compose from 'composable-middleware';\nimport User from '../api/user/user.model';\n\nvar validateJwt = expressJwt({\n  secret: config.secrets.session\n});\n\n/**\n * Attaches the user object to the request if authenticated\n * Otherwise returns 403\n */\nexport function isAuthenticated() {\n  return compose()\n    // Validate jwt\n    .use(function(req, res, next) {\n      // allow access_token to be passed through query parameter as well\n      if (req.query && req.query.hasOwnProperty('access_token')) {\n        req.headers.authorization = 'Bearer ' + req.query.access_token;\n      }\n      validateJwt(req, res, next);\n    })\n    // Attach user to request\n    .use(function(req, res, next) {\n      User.findByIdAsync(req.user._id)\n        .then(user => {\n          if (!user) {\n            return res.status(401).end();\n          }\n          req.user = user;\n          next();\n        })\n        .catch(err => next(err));\n    });\n}\n\n/**\n * Checks if the user role meets the minimum requirements of the route\n */\nexport function hasRole(roleRequired) {\n  if (!roleRequired) {\n    throw new Error('Required role needs to be set');\n  }\n\n  return compose()\n    .use(isAuthenticated())\n    .use(function meetsRequirements(req, res, next) {\n      if (config.userRoles.indexOf(req.user.role) >=\n          config.userRoles.indexOf(roleRequired)) {\n        next();\n      } else {\n        res.status(403).send('Forbidden');\n      }\n    });\n}\n\n/**\n * Returns a jwt token signed by the app secret\n */\nexport function signToken(id, role) {\n  return jwt.sign({ _id: id, role: role }, config.secrets.session, {\n    expiresIn: 60 * 60 * 5\n  });\n}\n\n/**\n * Set token cookie directly for oAuth strategies\n */\nexport function setTokenCookie(req, res) {\n  if (!req.user) {\n    return res.status(404).send('It looks like you aren\\'t logged in, please try again.');\n  }\n  var token = signToken(req.user._id, req.user.role);\n  res.cookie('token', token);\n  res.redirect('/');\n}\n"
  },
  {
    "path": "server/auth/facebook/index.js",
    "content": "'use strict';\n\nimport express from 'express';\nimport passport from 'passport';\nimport {setTokenCookie} from '../auth.service';\n\nvar router = express.Router();\n\nrouter\n  .get('/', passport.authenticate('facebook', {\n    scope: ['email', 'user_about_me'],\n    failureRedirect: '/signup',\n    session: false\n  }))\n  .get('/callback', passport.authenticate('facebook', {\n    failureRedirect: '/signup',\n    session: false\n  }), setTokenCookie);\n\nexport default router;\n"
  },
  {
    "path": "server/auth/facebook/passport.js",
    "content": "import passport from 'passport';\nimport {Strategy as FacebookStrategy} from 'passport-facebook';\n\nexport function setup(User, config) {\n  passport.use(new FacebookStrategy({\n    clientID: config.facebook.clientID,\n    clientSecret: config.facebook.clientSecret,\n    callbackURL: config.facebook.callbackURL,\n    profileFields: [\n      'displayName',\n      'emails'\n    ]\n  },\n  function(accessToken, refreshToken, profile, done) {\n    User.findOneAsync({\n      'facebook.id': profile.id\n    })\n      .then(user => {\n        if (user) {\n          return done(null, user);\n        }\n\n        user = new User({\n          name: profile.displayName,\n          email: profile.emails[0].value,\n          role: 'user',\n          provider: 'facebook',\n          facebook: profile._json\n        });\n        user.save()\n          .then(user => done(null, user))\n          .catch(err => done(err));\n      })\n      .catch(err => done(err));\n  }));\n}\n"
  },
  {
    "path": "server/auth/google/index.js",
    "content": "'use strict';\n\nimport express from 'express';\nimport passport from 'passport';\nimport {setTokenCookie} from '../auth.service';\n\nvar router = express.Router();\n\nrouter\n  .get('/', passport.authenticate('google', {\n    failureRedirect: '/signup',\n    scope: [\n      'profile',\n      'email'\n    ],\n    session: false\n  }))\n  .get('/callback', passport.authenticate('google', {\n    failureRedirect: '/signup',\n    session: false\n  }), setTokenCookie);\n\nexport default router;\n"
  },
  {
    "path": "server/auth/google/passport.js",
    "content": "import passport from 'passport';\nimport {OAuth2Strategy as GoogleStrategy} from 'passport-google-oauth';\n\nexport function setup(User, config) {\n  passport.use(new GoogleStrategy({\n    clientID: config.google.clientID,\n    clientSecret: config.google.clientSecret,\n    callbackURL: config.google.callbackURL\n  },\n  function(accessToken, refreshToken, profile, done) {\n    User.findOneAsync({\n      'google.id': profile.id\n    })\n      .then(user => {\n        if (user) {\n          return done(null, user);\n        }\n\n        user = new User({\n          name: profile.displayName,\n          email: profile.emails[0].value,\n          role: 'user',\n          username: profile.emails[0].value.split('@')[0],\n          provider: 'google',\n          google: profile._json\n        });\n        user.save()\n          .then(user => done(null, user))\n          .catch(err => done(err));\n      })\n      .catch(err => done(err));\n  }));\n}\n"
  },
  {
    "path": "server/auth/index.js",
    "content": "'use strict';\n\nimport express from 'express';\nimport passport from 'passport';\nimport config from '../config/environment';\nimport User from '../api/user/user.model';\n\n// Passport Configuration\nrequire('./local/passport').setup(User, config);\nrequire('./facebook/passport').setup(User, config);\nrequire('./google/passport').setup(User, config);\nrequire('./twitter/passport').setup(User, config);\n\nvar router = express.Router();\n\nrouter.use('/local', require('./local'));\nrouter.use('/facebook', require('./facebook'));\nrouter.use('/twitter', require('./twitter'));\nrouter.use('/google', require('./google'));\n\nexport default router;\n"
  },
  {
    "path": "server/auth/local/index.js",
    "content": "'use strict';\n\nimport express from 'express';\nimport passport from 'passport';\nimport {signToken} from '../auth.service';\n\nvar router = express.Router();\n\nrouter.post('/', function(req, res, next) {\n  passport.authenticate('local', function(err, user, info) {\n    var error = err || info;\n    if (error) {\n      return res.status(401).json(error);\n    }\n    if (!user) {\n      return res.status(404).json({message: 'Something went wrong, please try again.'});\n    }\n\n    var token = signToken(user._id, user.role);\n    res.json({ token });\n  })(req, res, next)\n});\n\nexport default router;\n"
  },
  {
    "path": "server/auth/local/passport.js",
    "content": "import passport from 'passport';\nimport {Strategy as LocalStrategy} from 'passport-local';\n\nfunction localAuthenticate(User, email, password, done) {\n  User.findOneAsync({\n    email: email.toLowerCase()\n  })\n    .then(user => {\n      if (!user) {\n        return done(null, false, {\n          message: 'This email is not registered.'\n        });\n      }\n      user.authenticate(password, function(authError, authenticated) {\n        if (authError) {\n          return done(authError);\n        }\n        if (!authenticated) {\n          return done(null, false, { message: 'This password is not correct.' });\n        } else {\n          return done(null, user);\n        }\n      });\n    })\n    .catch(err => done(err));\n}\n\nexport function setup(User, config) {\n  passport.use(new LocalStrategy({\n    usernameField: 'email',\n    passwordField: 'password' // this is the virtual field on the model\n  }, function(email, password, done) {\n    return localAuthenticate(User, email, password, done);\n  }));\n}\n"
  },
  {
    "path": "server/auth/twitter/index.js",
    "content": "'use strict';\n\nimport express from 'express';\nimport passport from 'passport';\nimport {setTokenCookie} from '../auth.service';\n\nvar router = express.Router();\n\nrouter\n  .get('/', passport.authenticate('twitter', {\n    failureRedirect: '/signup',\n    session: false\n  }))\n  .get('/callback', passport.authenticate('twitter', {\n    failureRedirect: '/signup',\n    session: false\n  }), setTokenCookie);\n\nexport default router;\n"
  },
  {
    "path": "server/auth/twitter/passport.js",
    "content": "import passport from 'passport';\nimport {Strategy as TwitterStrategy} from 'passport-twitter';\n\nexport function setup(User, config) {\n  passport.use(new TwitterStrategy({\n    consumerKey: config.twitter.clientID,\n    consumerSecret: config.twitter.clientSecret,\n    callbackURL: config.twitter.callbackURL\n  },\n  function(token, tokenSecret, profile, done) {\n    User.findOneAsync({\n      'twitter.id_str': profile.id\n    })\n      .then(user => {\n        if (user) {\n          return done(null, user);\n        }\n\n        user = new User({\n          name: profile.displayName,\n          username: profile.username,\n          role: 'user',\n          provider: 'twitter',\n          twitter: profile._json\n        });\n        user.save()\n          .then(user => done(null, user))\n          .catch(err => done(err));\n      })\n      .catch(err => done(err));\n  }));\n}\n"
  },
  {
    "path": "server/components/errors/index.js",
    "content": "/**\n * Error responses\n */\n\n'use strict';\n\nmodule.exports[404] = function pageNotFound(req, res) {\n  var viewFilePath = '404';\n  var statusCode = 404;\n  var result = {\n    status: statusCode\n  };\n\n  res.status(result.status);\n  res.render(viewFilePath, {}, function(err, html) {\n    if (err) {\n      return res.json(result, result.status);\n    }\n\n    res.send(html);\n  });\n};\n"
  },
  {
    "path": "server/config/environment/development.js",
    "content": "'use strict';\n\n// Development specific configuration\n// ==================================\nmodule.exports = {\n\n  // MongoDB connection options\n  mongo: {\n    uri: 'mongodb://localhost/paizaqa-dev'\n  },\n\n  // Seed database on startup\n  seedDB: true\n\n};\n"
  },
  {
    "path": "server/config/environment/index.js",
    "content": "'use strict';\n\nvar path = require('path');\nvar _ = require('lodash');\n\nfunction requiredProcessEnv(name) {\n  if (!process.env[name]) {\n    throw new Error('You must set the ' + name + ' environment variable');\n  }\n  return process.env[name];\n}\n\n// All configurations will extend these options\n// ============================================\nvar all = {\n  env: process.env.NODE_ENV,\n\n  // Root path of server\n  root: path.normalize(__dirname + '/../../..'),\n\n  // Server port\n  port: process.env.PORT || 9000,\n\n  // Server IP\n  ip: process.env.IP || '0.0.0.0',\n\n  // Should we populate the DB with sample data?\n  seedDB: false,\n\n  // Secret for session, you will want to change this and make it an environment variable\n  secrets: {\n    session: 'paizaqa-secret'\n  },\n\n  // MongoDB connection options\n  mongo: {\n    options: {\n      db: {\n        safe: true\n      }\n    }\n  },\n\n  facebook: {\n    clientID:     process.env.FACEBOOK_ID || 'id',\n    clientSecret: process.env.FACEBOOK_SECRET || 'secret',\n    callbackURL:  (process.env.DOMAIN || '') + '/auth/facebook/callback'\n  },\n\n  twitter: {\n    clientID:     process.env.TWITTER_ID || 'id',\n    clientSecret: process.env.TWITTER_SECRET || 'secret',\n    callbackURL:  (process.env.DOMAIN || '') + '/auth/twitter/callback'\n  },\n\n  google: {\n    clientID:     process.env.GOOGLE_ID || 'id',\n    clientSecret: process.env.GOOGLE_SECRET || 'secret',\n    callbackURL:  (process.env.DOMAIN || '') + '/auth/google/callback'\n  }\n};\n\n// Export the config object based on the NODE_ENV\n// ==============================================\nmodule.exports = _.merge(\n  all,\n  require('./shared'),\n  require('./' + process.env.NODE_ENV + '.js') || {});\n"
  },
  {
    "path": "server/config/environment/production.js",
    "content": "'use strict';\n\n// Production specific configuration\n// =================================\nmodule.exports = {\n  // Server IP\n  ip:     process.env.OPENSHIFT_NODEJS_IP ||\n          process.env.IP ||\n          undefined,\n\n  // Server port\n  port:   process.env.OPENSHIFT_NODEJS_PORT ||\n          process.env.PORT ||\n          8080,\n\n  // MongoDB connection options\n  mongo: {\n    uri:  process.env.MONGOLAB_URI ||\n          process.env.MONGOHQ_URL ||\n          process.env.OPENSHIFT_MONGODB_DB_URL +\n          process.env.OPENSHIFT_APP_NAME ||\n          'mongodb://localhost/paizaqa'\n  }\n};\n"
  },
  {
    "path": "server/config/environment/shared.js",
    "content": "'use strict';\n\nexports = module.exports = {\n  // List of user roles\n  userRoles: ['guest', 'user', 'admin']\n};\n"
  },
  {
    "path": "server/config/environment/test.js",
    "content": "'use strict';\n\n// Test specific configuration\n// ===========================\nmodule.exports = {\n  // MongoDB connection options\n  mongo: {\n    uri: 'mongodb://localhost/paizaqa-test'\n  },\n  sequelize: {\n    uri: 'sqlite://',\n    options: {\n      logging: false,\n      storage: 'test.sqlite',\n      define: {\n        timestamps: false\n      }\n    }\n  }\n};\n"
  },
  {
    "path": "server/config/express.js",
    "content": "/**\n * Express configuration\n */\n\n'use strict';\n\nimport express from 'express';\nimport favicon from 'serve-favicon';\nimport morgan from 'morgan';\nimport compression from 'compression';\nimport bodyParser from 'body-parser';\nimport methodOverride from 'method-override';\nimport cookieParser from 'cookie-parser';\nimport errorHandler from 'errorhandler';\nimport path from 'path';\nimport lusca from 'lusca';\nimport config from './environment';\nimport passport from 'passport';\nimport session from 'express-session';\nimport connectMongo from 'connect-mongo';\nimport mongoose from 'mongoose';\nvar mongoStore = connectMongo(session);\n\nexport default function(app) {\n  var env = app.get('env');\n\n  app.set('views', config.root + '/server/views');\n  app.engine('html', require('ejs').renderFile);\n  app.set('view engine', 'html');\n  app.use(compression());\n  app.use(bodyParser.urlencoded({ extended: false }));\n  app.use(bodyParser.json());\n  app.use(methodOverride());\n  app.use(cookieParser());\n  app.use(passport.initialize());\n\n  // Persist sessions with mongoStore / sequelizeStore\n  // We need to enable sessions for passport-twitter because it's an\n  // oauth 1.0 strategy, and Lusca depends on sessions\n  app.use(session({\n    secret: config.secrets.session,\n    saveUninitialized: true,\n    resave: false,\n    store: new mongoStore({\n      mongooseConnection: mongoose.connection,\n      db: 'paizaqa'\n    })\n  }));\n\n  /**\n   * Lusca - express server security\n   * https://github.com/krakenjs/lusca\n   */\n  if ('test' !== env) {\n    app.use(lusca({\n      csrf: {\n        angular: true\n      },\n      xframe: 'SAMEORIGIN',\n      hsts: {\n        maxAge: 31536000, //1 year, in seconds\n        includeSubDomains: true,\n        preload: true\n      },\n      xssProtection: true\n    }));\n  }\n\n  app.set('appPath', path.join(config.root, 'client'));\n\n  if ('production' === env) {\n    app.use(favicon(path.join(config.root, 'client', 'favicon.ico')));\n    app.use(express.static(app.get('appPath')));\n    app.use(morgan('dev'));\n  }\n\n  if ('development' === env) {\n    app.use(require('connect-livereload')());\n  }\n\n  if ('development' === env || 'test' === env) {\n    app.use(express.static(path.join(config.root, '.tmp')));\n    app.use(express.static(app.get('appPath')));\n    app.use(morgan('dev'));\n    app.use(errorHandler()); // Error handler - has to be last\n  }\n}\n"
  },
  {
    "path": "server/config/local.env.sample.js",
    "content": "'use strict';\n\n// Use local.env.js for environment variables that grunt will set when the server starts locally.\n// Use for your api keys, secrets, etc. This file should not be tracked by git.\n//\n// You will need to set these on the server you deploy to.\n\nmodule.exports = {\n  DOMAIN:           'http://localhost:9000',\n  SESSION_SECRET:   'paizaqa-secret',\n\n  FACEBOOK_ID:      'app-id',\n  FACEBOOK_SECRET:  'secret',\n\n  TWITTER_ID:       'app-id',\n  TWITTER_SECRET:   'secret',\n\n  GOOGLE_ID:        'app-id',\n  GOOGLE_SECRET:    'secret',\n\n  // Control debug level for modules using visionmedia/debug\n  DEBUG: ''\n};\n"
  },
  {
    "path": "server/config/seed.js",
    "content": "/**\n * Populate DB with sample data on server start\n * to disable, edit config/environment/index.js, and set `seedDB: false`\n */\n\n'use strict';\nimport Thing from '../api/thing/thing.model';\nimport User from '../api/user/user.model';\n\nThing.find({}).removeAsync()\n  .then(() => {\n    Thing.create({\n      name: 'Development Tools',\n      info: 'Integration with popular tools such as Bower, Grunt, Babel, Karma, ' +\n             'Mocha, JSHint, Node Inspector, Livereload, Protractor, Jade, ' +\n             'Stylus, Sass, and Less.'\n    }, {\n      name: 'Server and Client integration',\n      info: 'Built with a powerful and fun stack: MongoDB, Express, ' +\n             'AngularJS, and Node.'\n    }, {\n      name: 'Smart Build System',\n      info: 'Build system ignores `spec` files, allowing you to keep ' +\n             'tests alongside code. Automatic injection of scripts and ' +\n             'styles into your index.html'\n    }, {\n      name: 'Modular Structure',\n      info: 'Best practice client and server structures allow for more ' +\n             'code reusability and maximum scalability'\n    }, {\n      name: 'Optimized Build',\n      info: 'Build process packs up your templates as a single JavaScript ' +\n             'payload, minifies your scripts/css/images, and rewrites asset ' +\n             'names for caching.'\n    }, {\n      name: 'Deployment Ready',\n      info: 'Easily deploy your app to Heroku or Openshift with the heroku ' +\n             'and openshift subgenerators'\n    });\n  });\n\nUser.find({}).removeAsync()\n  .then(() => {\n    User.createAsync({\n      provider: 'local',\n      name: 'Test User',\n      email: 'test@example.com',\n      password: 'test'\n    }, {\n      provider: 'local',\n      role: 'admin',\n      name: 'Admin',\n      email: 'admin@example.com',\n      password: 'admin'\n    })\n    .then(() => {\n      console.log('finished populating users');\n    });\n  });\n"
  },
  {
    "path": "server/config/socketio.js",
    "content": "/**\n * Socket.io configuration\n */\n'use strict';\n\nimport config from './environment';\n\n// When the user disconnects.. perform this\nfunction onDisconnect(socket) {\n}\n\n// When the user connects.. perform this\nfunction onConnect(socket) {\n  // When the client emits 'info', this listens and executes\n  socket.on('info', data => {\n    socket.log(JSON.stringify(data, null, 2));\n  });\n\n  // Insert sockets below\n  require('../api/question/question.socket').register(socket);\n  require('../api/thing/thing.socket').register(socket);\n\n}\n\nexport default function(socketio) {\n  // socket.io (v1.x.x) is powered by debug.\n  // In order to see all the debug output, set DEBUG (in server/config/local.env.js) to including the desired scope.\n  //\n  // ex: DEBUG: \"http*,socket.io:socket\"\n\n  // We can authenticate socket.io users and access their token through socket.decoded_token\n  //\n  // 1. You will need to send the token in `client/components/socket/socket.service.js`\n  //\n  // 2. Require authentication here:\n  // socketio.use(require('socketio-jwt').authorize({\n  //   secret: config.secrets.session,\n  //   handshake: true\n  // }));\n\n  socketio.on('connection', function(socket) {\n    socket.address = socket.request.connection.remoteAddress +\n      ':' + socket.request.connection.remotePort;\n\n    socket.connectedAt = new Date();\n\n    socket.log = function(...data) {\n      console.log(`SocketIO ${socket.nsp.name} [${socket.address}]`, ...data);\n    };\n\n    // Call onDisconnect.\n    socket.on('disconnect', () => {\n      onDisconnect(socket);\n      socket.log('DISCONNECTED');\n    });\n\n    // Call onConnect.\n    onConnect(socket);\n    socket.log('CONNECTED');\n  });\n}\n"
  },
  {
    "path": "server/index.js",
    "content": "'use strict';\n\n// Set default node environment to development\nvar env = process.env.NODE_ENV = process.env.NODE_ENV || 'development';\n\nif (env === 'development' || env === 'test') {\n  // Register the Babel require hook\n  require('babel-core/register');\n}\n\n// Export the application\nexports = module.exports = require('./app');\n"
  },
  {
    "path": "server/routes.js",
    "content": "/**\n * Main application routes\n */\n\n'use strict';\n\nimport errors from './components/errors';\nimport path from 'path';\n\nexport default function(app) {\n  // Insert routes below\n  app.use('/api/questions', require('./api/question'));\n  app.use('/api/things', require('./api/thing'));\n  app.use('/api/users', require('./api/user'));\n\n  app.use('/auth', require('./auth'));\n\n  // All undefined asset or api routes should return a 404\n  app.route('/:url(api|auth|components|app|bower_components|assets)/*')\n   .get(errors[404]);\n\n  // All other routes should redirect to the index.html\n  app.route('/*')\n    .get((req, res) => {\n      res.sendFile(path.resolve(app.get('appPath') + '/index.html'));\n    });\n}\n"
  },
  {
    "path": "server/views/404.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Page Not Found :(</title>\n    <style>\n      ::-moz-selection {\n        background: #b3d4fc;\n        text-shadow: none;\n      }\n\n      ::selection {\n        background: #b3d4fc;\n        text-shadow: none;\n      }\n\n      html {\n        padding: 30px 10px;\n        font-size: 20px;\n        line-height: 1.4;\n        color: #737373;\n        background: #f0f0f0;\n        -webkit-text-size-adjust: 100%;\n        -ms-text-size-adjust: 100%;\n      }\n\n      html,\n      input {\n        font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n      }\n\n      body {\n        max-width: 500px;\n        _width: 500px;\n        padding: 30px 20px 50px;\n        border: 1px solid #b3b3b3;\n        border-radius: 4px;\n        margin: 0 auto;\n        box-shadow: 0 1px 10px #a7a7a7, inset 0 1px 0 #fff;\n        background: #fcfcfc;\n      }\n\n      h1 {\n        margin: 0 10px;\n        font-size: 50px;\n        text-align: center;\n      }\n\n      h1 span {\n        color: #bbb;\n      }\n\n      h3 {\n        margin: 1.5em 0 0.5em;\n      }\n\n      p {\n        margin: 1em 0;\n      }\n\n      ul {\n        padding: 0 0 0 40px;\n        margin: 1em 0;\n      }\n\n      .container {\n        max-width: 380px;\n        _width: 380px;\n        margin: 0 auto;\n      }\n\n      /* google search */\n\n      #goog-fixurl ul {\n        list-style: none;\n        padding: 0;\n        margin: 0;\n      }\n\n      #goog-fixurl form {\n        margin: 0;\n      }\n\n      #goog-wm-qt,\n      #goog-wm-sb {\n        border: 1px solid #bbb;\n        font-size: 16px;\n        line-height: normal;\n        vertical-align: top;\n        color: #444;\n        border-radius: 2px;\n      }\n\n      #goog-wm-qt {\n        width: 220px;\n        height: 20px;\n        padding: 5px;\n        margin: 5px 10px 0 0;\n        box-shadow: inset 0 1px 1px #ccc;\n      }\n\n      #goog-wm-sb {\n        display: inline-block;\n        height: 32px;\n        padding: 0 10px;\n        margin: 5px 0 0;\n        white-space: nowrap;\n        cursor: pointer;\n        background-color: #f5f5f5;\n        background-image: -webkit-linear-gradient(rgba(255,255,255,0), #f1f1f1);\n        background-image: -moz-linear-gradient(rgba(255,255,255,0), #f1f1f1);\n        background-image: -ms-linear-gradient(rgba(255,255,255,0), #f1f1f1);\n        background-image: -o-linear-gradient(rgba(255,255,255,0), #f1f1f1);\n        -webkit-appearance: none;\n        -moz-appearance: none;\n        appearance: none;\n        *overflow: visible;\n        *display: inline;\n        *zoom: 1;\n      }\n\n      #goog-wm-sb:hover,\n      #goog-wm-sb:focus {\n        border-color: #aaa;\n        box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);\n        background-color: #f8f8f8;\n      }\n\n      #goog-wm-qt:hover,\n      #goog-wm-qt:focus {\n        border-color: #105cb6;\n        outline: 0;\n        color: #222;\n      }\n\n      input::-moz-focus-inner {\n        padding: 0;\n        border: 0;\n      }\n    </style>\n  </head>\n  <body>\n    <div class=\"container\">\n      <h1>Not found <span>:(</span></h1>\n      <p>Sorry, but the page you were trying to view does not exist.</p>\n      <p>It looks like this was the result of either:</p>\n      <ul>\n        <li>a mistyped address</li>\n        <li>an out-of-date link</li>\n      </ul>\n      <script>\n        var GOOG_FIXURL_LANG = (navigator.language || '').slice(0,2),GOOG_FIXURL_SITE = location.host;\n      </script>\n      <script src=\"//linkhelp.clients.google.com/tbproxy/lh/wm/fixurl.js\"></script>\n    </div>\n  </body>\n</html>\n"
  }
]