[
  {
    "path": ".gitignore",
    "content": "\n.DS_Store\n\n.gradle/*\n\nbuild/*\n\nout/*\n\n*.iml\n\n*.ipr\n\n*.iws\n/build/\n/bin/\n\n# eclipse\n.settings/\n.project\n.classpath\n\n# Intellij\n.idea/\n*.iml\n*.iws\n"
  },
  {
    "path": "LICENSE.md",
    "content": "Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n"
  },
  {
    "path": "README.md",
    "content": "JAVA REST Application\r\n====================\r\n\r\nSimple and easily understandable web project that demonstrates the use of:\r\n\r\n * Jersey + JAX-RS\r\n * Spring Integration\r\n * Spring Data + Hibernate\r\n * Groovy Integration tests\r\n * OAuth\r\n * Velocity + Java Mail\r\n * Facebook Login\r\n * Password Reset\r\n * Login/Sign Up + Email Verification\r\n * JSR 303 Validation\r\n\r\n NOTE. For a similar project that uses most of the same components but is built around OAuth2 see\r\n  <a href=\"http://porterhead.blogspot.co.uk/2014/05/securing-rest-services-with-spring.html\">Securing Rest Services with OAuth2 and Spring Security</a>\r\n\r\nto build:\r\n\r\ngradle clean build integrationTest\r\n\r\nor use the gradle wrapper:\r\n\r\n./gradlew clean build integrationTest\r\n\r\ngo to /build/reports/emma for test coverage reports\r\n\r\nto run:\r\n\r\ngradle tomcatRun\r\n\r\nnavigate to http://localhost:8080/java-rest/\r\n\r\nsee blog posts:\r\nTHANK YOU\r\n\r\n<ul>\r\n<li><a href=\"http://porterhead.blogspot.co.uk/2013/01/writing-rest-services-in-java-part-1.html\">Part 1: An introduction to writing REST Services in Java</a></li>\r\n<li><a href=\"http://porterhead.blogspot.co.uk/2013/01/writing-rest-services-in-java-part-2.html\">Part 2: User sign up and login</a></li>\r\n<li><a href=\"http://porterhead.blogspot.co.uk/2013/01/writing-rest-services-in-java-part-3.html\">Part 3: Email Verification</a></li>\r\n<li><a href=\"http://porterhead.blogspot.co.uk/2013/01/writing-rest-services-in-java-part-4.html\">Part 4: Facebook Authentication</a></li>\r\n<li><a href=\"http://porterhead.blogspot.co.uk/2013/01/writing-rest-services-in-java-part-5.html\">Part 5: Lost Password</a></li>\r\n<li><a href=\"http://porterhead.blogspot.co.uk/2013/01/writing-rest-services-in-java-part-6.html\">Part 6: Security &amp; Authorization</a></li>\r\n<li><a href=\"http://porterhead.blogspot.co.uk/2013/03/writing-rest-services-in-java-part-7.html\">Part 7: Moving to Production</a></li>\r\n<li><a href=\"http://porterhead.blogspot.co.uk/2013/05/writing-rest-services-in-java-part-8.html\">Part 8: JSR 303 Validation</a></li>\r\n</ul>\r\n\r\n"
  },
  {
    "path": "build.gradle",
    "content": "apply plugin: 'idea'\napply plugin: 'java'\napply plugin: 'tomcat'\napply plugin: 'war'\napply plugin: 'groovy'\napply plugin: 'eclipse'\napply plugin: 'jetty'\n\n\next {\n    springVersion = \"4.1.5.RELEASE\"\n    h2Version = \"1.3.155\"\n    springDataVersion = \"1.1.0.RELEASE\"\n    springSocialVersion = \"1.0.2.RELEASE\"\n    springSocialFacebookVersion = \"1.0.1.RELEASE\"\n    springSocialTwitterVersion = \"1.0.2.RELEASE\"\n    springSecurity = \"3.1.2.RELEASE\"\n    springIntegrationVersion = \"4.1.2.RELEASE\"\n    aspectjrtVersion = \"1.6.11\"\n    jacksonVersion = \"1.9.3\"\n    commonsIoVersion = \"1.4\"\n    jerseyVersion = \"1.9.1\"\n    hibernateVersion = \"3.6.7.Final\"\n    h2Version = \"1.3.154\"\n    slf4jVersion = \"1.6.1\"\n    logbackVersion = \"1.0.1\"\n    velocityVersion = \"1.7\"\n    groovyVersion = \"2.0.0\"\n    guavaVersion = \"12.0\"\n    hibernateValidatorVersion = \"4.3.1.Final\"\n    environmentBase = 'src/main/config/'\n    env = \"ci\"\n    tomcatVersion = '7.0.25'\n\n}\n\nconfigurations {\n    emma\n}\n\n\nbuildscript {\n\n    repositories {\n        mavenCentral()\n        jcenter()\n\n    }\n\n    dependencies {\n\n        classpath 'org.gradle.api.plugins:gradle-tomcat-plugin:1.0'\n\n    }\n}\n\nrepositories {\n    mavenCentral()\n    maven {\n        url \"http://maven.springframework.org/milestone\"\n    }\n}\n\n// A list of all of our project dependencies.\ndependencies {\n\n    compile \"org.hibernate:hibernate-core:$hibernateVersion\",\n            \"org.hibernate:hibernate-entitymanager:$hibernateVersion\",\n            \"org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.0.Final\",\n            \"org.hibernate:hibernate-validator:4.1.0.Final\",\n            \"org.springframework.data:spring-data-jpa:$springDataVersion\",\n            \"com.h2database:h2:$h2Version\",\n            \"mysql:mysql-connector-java:5.1.16\",\n            \"commons-dbcp:commons-dbcp:1.3\",\n            \"commons-codec:commons-codec:1.6\",\n            \"org.springframework.social:spring-social-core:$springSocialVersion\",\n            \"org.springframework.social:spring-social-facebook:$springSocialFacebookVersion\",\n            \"org.springframework.social:spring-social-twitter:$springSocialTwitterVersion\",\n            \"org.springframework.social:spring-social-test:$springSocialVersion\",\n            \"org.springframework.security:spring-security-core:$springSecurity\",\n\n            \"org.aspectj:aspectjrt:$aspectjrtVersion\",\n            \"org.codehaus.jackson:jackson-core-asl:$jacksonVersion\",\n            \"org.codehaus.jackson:jackson-mapper-asl:$jacksonVersion\",\n            \"org.codehaus.jackson:jackson-xc:$jacksonVersion\",\n            \"commons-io:commons-io:$commonsIoVersion\",\n            \"javax.ws.rs:jsr311-api:1.1\",\n            \"javax.annotation:jsr250-api:1.0\",\n            \"com.sun.jersey:jersey-core:$jerseyVersion\",\n            \"com.sun.jersey:jersey-server:$jerseyVersion\",\n            \"com.sun.jersey:jersey-json:$jerseyVersion\",\n            \"com.sun.jersey.contribs:jersey-spring:$jerseyVersion\",\n            \"org.springframework:spring-core:$springVersion\",\n            \"org.springframework:spring-beans:$springVersion\",\n            \"org.springframework:spring-context:$springVersion\",\n            \"org.springframework:spring-aop:$springVersion\",\n            \"org.springframework:spring-webmvc:$springVersion\",\n            \"org.springframework:spring-tx:$springVersion\",\n            \"org.springframework:spring-orm:$springVersion\",\n            \"org.springframework:spring-jdbc:$springVersion\",\n            \"org.springframework:spring-aspects:$springVersion\",\n            \"org.aspectj:aspectjweaver:1.5.4\",\n            \"cglib:cglib:2.2\",\n            \"com.google.guava:guava:$guavaVersion\",\n            \"org.hibernate:hibernate-validator:$hibernateValidatorVersion\",\n            \"javax.validation:validation-api:1.1.0.Final\",\n\n            \"org.slf4j:slf4j-api:$slf4jVersion\",\n            \"ch.qos.logback:logback-classic:$logbackVersion\",\n            \"ch.qos.logback:logback-core:$logbackVersion\",\n            \"org.mockito:mockito-all:1.8.5\",\n\n            \"org.springframework.integration:spring-integration-core:$springIntegrationVersion\",\n            \"org.springframework.integration:spring-integration-jdbc:$springIntegrationVersion\",\n            \"org.springframework.integration:spring-integration-mail:$springIntegrationVersion\",\n            \"org.springframework.integration:spring-integration-http:$springIntegrationVersion\",\n            \"org.apache.velocity:velocity:$velocityVersion\",\n            \"javax.mail:mail:1.4.5\",\n            \"joda-time:joda-time:2.1\",\n            \"commons-lang:commons-lang:2.6\",\n            \"commons-cli:commons-cli:1.2\"\n\n    // Pull in test-time dependencies.\n    testCompile \"junit:junit:4.12\",\n            \"org.springframework:spring-test:$springVersion\",\n            //\"org.codehaus.groovy.modules.http-builder:http-builder:0.5.2\",\n            //\"org.codehaus.groovy:groovy-all:$groovyVersion\",\n            \"org.hamcrest:hamcrest-all:1.1\",\n\n\n\n            \"com.sun.jersey:jersey-test-framework:$jerseyVersion\",\n            \"com.sun.jersey.jersey-test-framework:jersey-test-framework-grizzly2:$jerseyVersion\",\n            \"com.sun.jersey.jersey-test-framework:jersey-test-framework-core:$jerseyVersion\",\n            \"com.sun.jersey:jersey-grizzly2:$jerseyVersion\",\n            \"org.glassfish.grizzly:grizzly-http:2.1.2\",\n            \"org.glassfish.gmbal:gmbal-api-only:3.0.0-b023\",\n            \"org.glassfish.external:management-api:3.0.0-b012\",\n            \"org.glassfish.grizzly:grizzly-http-server:2.1.2\",\n            \"org.glassfish.grizzly:grizzly-rcm:2.1.2\",\n            \"org.glassfish.grizzly:grizzly-http-servlet:2.1.2\",\n            \"org.glassfish:javax.servlet:3.1\",\n            \"com.sun.jersey:jersey-client:$jerseyVersion\"\n\n    testCompile(\"org.codehaus.groovy.modules.http-builder:http-builder:0.5.2\") {\n        exclude group: 'org.codehaus.groovy'\n    }\n    testCompile \"org.codehaus.groovy:groovy-all:2.0.0\"\n\n\n\n    providedCompile \"javax.servlet:servlet-api:2.5\"\n\n\n    // Pull in tomcat dependencies\n\n    tomcat \"org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}\",\n            \"org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}\"\n    tomcat(\"org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}\") {\n        exclude group: \"org.eclipse.jdt.core.compiler\", module: \"ecj\"\n    }\n\n    emma \"emma:emma:2.1.5320\"\n    emma \"emma:emma_ant:2.1.5320\"\n\n}\n\nwar {\n    baseName = \"java-rest\"\n}\n\n\ntest {\n    exclude(\"**/*IntegrationTest*\")\n//    jvmArgs \"-XX:-UseSplitVerifier\", \"-Demma.coverage.out.file=$buildDir/tmp/emma/metadata.emma\", \"-Demma.coverage.out.merge=true\"\n//\n//    doFirst {\n//        println \"Instrumenting the classes at \" + sourceSets.main.output.classesDir.absolutePath\n//        // define the custom EMMA ant tasks\n//        ant.taskdef(resource: \"emma_ant.properties\", classpath: configurations.emma.asPath)\n//\n//        ant.path(id: \"run.classpath\") {\n//            pathelement(location: sourceSets.main.output.classesDir.absolutePath)\n//        }\n//        def emmaInstDir = new File(sourceSets.main.output.classesDir.parentFile.parentFile, \"tmp/emma/instr\")\n//        emmaInstDir.mkdirs()\n//        println \"Creating $emmaInstDir to instrument from \" + sourceSets.main.output.classesDir.absolutePath\n//        // instruct our compiled classes and store them at $buildDir/tmp/emma/instr\n//        ant.emma(enabled: 'true', verbosity: 'trace1') {\n//            instr(filter: \"-com.porterhead.com.porterhead.rest.command.*\", merge: \"true\", destdir: emmaInstDir.absolutePath, instrpathref: \"run.classpath\",\n//                    metadatafile: new File(emmaInstDir, '/metadata.emma').absolutePath) {\n//                instrpath {\n//                    fileset(dir: sourceSets.main.output.classesDir.absolutePath, includes: \"**/*.class\")\n//                }\n//            }\n//        }\n//        setClasspath(files(\"$buildDir/tmp/emma/instr\") + configurations.emma + getClasspath())\n//    }\n\n//    doLast {\n//        def srcDir = sourceSets.main.java.srcDirs.toArray()[0]\n//        println \"Creating test coverage reports for classes \" + srcDir\n//        def emmaInstDir = new File(sourceSets.main.output.classesDir.parentFile.parentFile, \"tmp/emma\")\n//        ant.emma(enabled: \"true\", verbosity: 'trace1') {\n//            new File(\"$buildDir/reports/emma\").mkdirs()\n//            report(sourcepath: srcDir) {\n//                fileset(dir: emmaInstDir.absolutePath) {\n//                    include(name: \"**/*.emma\")\n//                }\n//                txt(outfile: \"$buildDir/reports/emma/coverage.txt\")\n//                html(outfile: \"$buildDir/reports/emma/coverage.html\")\n//                xml(outfile: \"$buildDir/reports/emma/coverage.xml\")\n//            }\n//        }\n//        println \"Test coverage reports available at $buildDir/reports/emma.\"\n//        println \"txt: $buildDir/reports/emma/coverage.txt\"\n//        println \"Test $buildDir/reports/emma/coverage.html\"\n//        println \"Test $buildDir/reports/emma/coverage.xml\"\n//    }\n}\n\ntask wrapper(type: Wrapper) {\n    gradleVersion = '2.0'\n}\n\n\n[jettyRun, jettyRunWar, jettyStop]*.stopPort = 8081\n[jettyRun, jettyRunWar, jettyStop]*.stopKey = 'stopKey'\n\ntask integrationTest(type: Test) {\n    include '**/*IntegrationTest*.*'\n    doFirst {\n        jettyRun.daemon = true\n        jettyRun.execute()\n    }\n    doLast {\n        jettyStop.execute()\n    }\n\n}\n\n\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Tue Jul 29 21:04:58 BST 2014\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=http\\://services.gradle.org/distributions/gradle-2.0-bin.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "systemProp.spring.profiles.active=dev\n\nplease accept pull request\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched.\nif $cygwin ; then\n    [ -n \"$JAVA_HOME\" ] && JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\nfi\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >&-\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >&-\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windowz variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\ngoto execute\r\n\r\n:4NT_args\r\n@rem Get arguments from the 4NT Shell from JP Software\r\nset CMD_LINE_ARGS=%$\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "src/main/config/ci/gradle.properties",
    "content": "\ntomcatContainerId=tomcat6x\ntomcatPort=8080\ntomcatHostname=localhost\ntomcatUsername=admin\ntomcatPassword=admin\ntomcatContext=rest-java\n\n\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/api/ErrorResponse.java",
    "content": "package com.porterhead.rest.api;\n\nimport javax.xml.bind.annotation.XmlRootElement;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 19/10/2012\n */\n@XmlRootElement\npublic class ErrorResponse {\n\n    private String errorCode;\n    private String consumerMessage;\n    private String applicationMessage;\n    private List<ValidationError> validationErrors = new ArrayList<ValidationError>();\n\n\n    public String getErrorCode() {\n        return errorCode;\n    }\n\n    public void setErrorCode(String errorCode) {\n        this.errorCode = errorCode;\n    }\n\n    public String getConsumerMessage() {\n        return consumerMessage;\n    }\n\n    public void setConsumerMessage(String consumerMessage) {\n        this.consumerMessage = consumerMessage;\n    }\n\n    public String getApplicationMessage() {\n        return applicationMessage;\n    }\n\n    public void setApplicationMessage(String applicationMessage) {\n        this.applicationMessage = applicationMessage;\n    }\n\n    public List<ValidationError> getValidationErrors() {\n        return validationErrors;\n    }\n\n    public void setValidationErrors(List<ValidationError> validationErrors) {\n        this.validationErrors = validationErrors;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/api/PagedQueryRequest.java",
    "content": "package com.porterhead.rest.api;\n\n/**\n * @version 1.0\n * @author: Iain Porter\n * @since 28/02/2013\n */\npublic class PagedQueryRequest {\n\n    public final static int DEFAULT_PAGE_SIZE = 50;\n    public final static int MAX_PAGE_SIZE = 100;\n    public final static String SORT_ORDER_ASCENDING = \"asc\";\n    public final static String SORT_ORDER_DESCENDING = \"desc\";\n\n    private int page;\n    private int pageSize;\n    private String sortProperty;\n    private String sortDirection;\n    private String searchToken;\n\n    public PagedQueryRequest(){}\n\n    public PagedQueryRequest(int page, int pageSize) {\n        this.page = page;\n        this.pageSize = pageSize;\n    }\n\n    public int getPage() {\n        return page;\n    }\n\n    public void setPage(int page) {\n        this.page = page;\n    }\n\n    public int getPageSize() {\n        return pageSize == 0 ? DEFAULT_PAGE_SIZE : pageSize > MAX_PAGE_SIZE ? MAX_PAGE_SIZE : pageSize;\n    }\n\n    public void setPageSize(int pageSize) {\n        this.pageSize = pageSize;\n    }\n\n    public String getSortProperty() {\n        return sortProperty;\n    }\n\n    public void setSortProperty(String sortProperty) {\n        this.sortProperty = sortProperty;\n    }\n\n    public String getSortDirection() {\n        return sortDirection;\n    }\n\n    public void setSortDirection(String sortDirection) {\n        this.sortDirection = sortDirection;\n    }\n\n    public String getSearchToken() {\n        return searchToken;\n    }\n\n    public void setSearchToken(String searchToken) {\n        this.searchToken = searchToken;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/api/PagedResponse.java",
    "content": "package com.porterhead.rest.api;\n\nimport javax.xml.bind.annotation.XmlRootElement;\nimport java.util.List;\n\n/**\n * @version 1.0\n * @author: Iain Porter\n * @since 28/02/2013\n */\n@XmlRootElement\npublic class PagedResponse<T> {\n\n    private int total;\n    private int page;\n    private long records;\n    private List<T> rows;\n\n    public PagedResponse() {}\n\n    public int getTotal() {\n        return total;\n    }\n\n    public void setTotal(int total) {\n        this.total = total;\n    }\n\n    public int getPage() {\n        return page;\n    }\n\n    public void setPage(int page) {\n        this.page = page;\n    }\n\n    public long getRecords() {\n        return records;\n    }\n\n    public void setRecords(long records) {\n        this.records = records;\n    }\n\n    public List<T> getRows() {\n        return rows;\n    }\n\n    public void setRows(List<T> rows) {\n        this.rows = rows;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/api/ValidationError.java",
    "content": "package com.porterhead.rest.api;\n\nimport javax.xml.bind.annotation.XmlRootElement;\n\n/**\n * @version 1.0\n * @author: Iain Porter\n * @since 08/05/2013\n */\n@XmlRootElement\npublic class ValidationError {\n\n    private String propertyName;\n    private String propertyValue;\n    private String message;\n\n    public String getPropertyName() {\n        return propertyName;\n    }\n\n    public void setPropertyName(String propertyName) {\n        this.propertyName = propertyName;\n    }\n\n    public String getPropertyValue() {\n        return propertyValue;\n    }\n\n    public void setPropertyValue(String propertyValue) {\n        this.propertyValue = propertyValue;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/authorization/AuthorizationRequestContext.java",
    "content": "package com.porterhead.rest.authorization;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter\n * @since 28/01/2013\n */\npublic class AuthorizationRequestContext {\n\n    /**\n     * The relative url of the request which starts at the root of the requested resource\n     */\n    private final String requestUrl;\n\n    /**\n     * The Http method (POST, GET, DELETE, PUT)\n     */\n    private final String httpMethod;\n\n    /**\n     * An Iso8061 formatted date timestamp\n     */\n    private final String requestDateString;\n\n    /**\n     * Client generated unique nonce value\n     */\n    private final String nonceToken;\n\n    /**\n     * The AuthorizationToken which should be in a format that the appropriate AuthorizationService can understand\n     */\n    private final String authorizationToken;\n\n    public AuthorizationRequestContext(String requestUrl, String httpMethod, String requestDateString, String nonceToken, String hashedToken) {\n        this.requestUrl = requestUrl;\n        this.httpMethod = httpMethod;\n        this.requestDateString = requestDateString;\n        this.nonceToken = nonceToken;\n        this.authorizationToken = hashedToken;\n    }\n\n    public String getRequestUrl() {\n        return requestUrl;\n    }\n\n    public String getHttpMethod() {\n        return httpMethod;\n    }\n\n    public String getRequestDateString() {\n        return requestDateString;\n    }\n\n    public String getNonceToken() {\n        return nonceToken;\n    }\n\n    public String getAuthorizationToken() {\n        return authorizationToken;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/authorization/AuthorizationService.java",
    "content": "package com.porterhead.rest.authorization;\n\nimport com.porterhead.rest.user.api.ExternalUser;\n\n/**\n *\n * @author: Iain Porter\n */\npublic interface AuthorizationService {\n\n    /**\n     * Given an AuthorizationRequestContext validate and authorize a User\n     *\n     * @param authorizationRequestContext the context required to authorize a user for a particular request\n     * @return ExternalUser\n     */\n    public ExternalUser authorize(AuthorizationRequestContext authorizationRequestContext);\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/authorization/exception/InvalidAuthorizationHeaderException.java",
    "content": "package com.porterhead.rest.authorization.exception;\n\nimport com.porterhead.rest.exception.BaseWebApplicationException;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 20/10/2012\n */\npublic class InvalidAuthorizationHeaderException extends BaseWebApplicationException {\n\n\n    public static final String DEVELOPER_MESSAGE = \"Authorization failed. This could be due to missing properties in the header or\" +\n            \" the Authorization header may have been incorrectly hashed\";\n\n    public InvalidAuthorizationHeaderException() {\n        super(401, \"40101\", \"Authorization failed\", DEVELOPER_MESSAGE);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/authorization/impl/RequestSigningAuthorizationService.java",
    "content": "package com.porterhead.rest.authorization.impl;\n\nimport com.google.common.cache.CacheBuilder;\nimport com.google.common.cache.CacheLoader;\nimport com.google.common.cache.LoadingCache;\nimport com.porterhead.rest.authorization.AuthorizationRequestContext;\nimport com.porterhead.rest.authorization.AuthorizationService;\nimport com.porterhead.rest.config.ApplicationConfig;\nimport com.porterhead.rest.user.UserRepository;\nimport com.porterhead.rest.user.UserService;\nimport com.porterhead.rest.user.api.ExternalUser;\nimport com.porterhead.rest.user.domain.AuthorizationToken;\nimport com.porterhead.rest.user.domain.User;\nimport com.porterhead.rest.user.exception.AuthorizationException;\nimport com.porterhead.rest.util.DateUtil;\nimport org.apache.commons.codec.binary.Base64;\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.joda.time.DateTime;\nimport org.joda.time.Duration;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.util.Assert;\n\nimport java.util.Date;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Any Resource that requires a role must have a header property of the following format:\n * <p/>\n * <code>\n * Authorization: <uuid of user>:<Signed Request>\n * </code>\n * <p/>\n * The signed request hash is comprised of the session token + : +  the relative url + , + the Http method + , + Date + , + nonce\n * This string is then Sha-256 encoded and then Base64 encoded\n * <p/>\n * An example:\n * <code>\n * Example:\n * 9fbc6f9a-af1b-4767-a492-c8462fd2a4d9:user/2e2ce9e8-798e-42b6-9326-fd2e56aef7aa/cards,POST,2012-06-30T12:00:00+01:00,34e321a7c4\n * <p/>\n * </code>\n * <p/>\n * This will be SHA-256 hashed and then Base64 encoded to produce:\n * <p/>\n * <code>\n * HR/3DJp8RCGo50Wu+/3cr7ibdoNXKg1eYMt3HO5QoP4=\n * </code>\n * <p/>\n * Authorization: 2e2ce9e8-798e-42b6-9326-fd2e56aef7aa:HR/3DJp8RCGo50Wu+/3cr7ibdoNXKg1eYMt3HO5QoP4=\n *\n * @author: Iain Porter\n */\npublic class RequestSigningAuthorizationService implements AuthorizationService {\n\n    Logger LOG = LoggerFactory.getLogger(RequestSigningAuthorizationService.class);\n\n    /**\n     * If the nonce already exists in the cache the difference between its timestamp and the current time will be\n     * greater than this value\n     */\n    private static final int NONCE_CHECK_TOLERANCE_IN_MILLIS = 20;\n\n    /**\n     * Maximum Number of Nonce values in the cache\n     * The capacity will never be reached as long as the number of requests is below this value within the time range specified by\n     * ApplicationConfig.getSessionDateOffsetInMinutes()\n     */\n    private static final int NONCE_CACHE_SIZE = 10000;\n\n    /**\n     * A an expiry cache that evicts nonce values after a configurable time period\n     */\n    private LoadingCache<String, Nonce> nonceCache;\n\n    /**\n     * The configuration for the application\n     */\n    private ApplicationConfig config;\n\n    /**\n     * User service required for persisting user objects\n     */\n    private UserService userService;\n\n    /**\n     * directly access user objetcs\n     */\n    private final UserRepository userRepository;\n\n    @Autowired\n    public RequestSigningAuthorizationService(UserRepository userRepository, UserService userService, ApplicationConfig applicationConfig) {\n        this.userService = userService;\n        this.userRepository = userRepository;\n        this.config = applicationConfig;\n        initNonceCache();\n    }\n\n    private void initNonceCache() {\n        nonceCache = CacheBuilder.newBuilder()\n                .maximumSize(NONCE_CACHE_SIZE)\n                .expireAfterWrite(config.getSessionDateOffsetInMinutes(), TimeUnit.MINUTES)\n                .build(\n                        new CacheLoader<String, Nonce>() {\n                            public Nonce load(String key) throws Exception {\n                                return new Nonce(new DateTime(), key);\n                            }\n                        });\n\n    }\n\n    /**\n     * If the request contains values in the AuthorizationRequestContext attempt to find and validate a user\n     *\n     * @param context\n     * @return The request signature was valid and a user is returned or null if the context did not contain the information necessary\n     * to load a user\n     */\n    public ExternalUser authorize(AuthorizationRequestContext context) {\n\n        ExternalUser externalUser = null;\n        if (context.getAuthorizationToken() != null && context.getRequestDateString() != null && context.getNonceToken() != null) {\n            String userId = null;\n            String hashedToken = null;\n            String[] token = context.getAuthorizationToken().split(\":\");\n            if (token.length == 2) {\n                userId = token[0];\n                hashedToken = token[1];\n                //make sure date and nonce is valid\n                validateRequestDate(context.getRequestDateString());\n                validateNonce(context.getNonceToken());\n\n                User user = userRepository.findByUuid(userId);\n                if (user != null) {\n                    externalUser = new ExternalUser(user);\n                    if (!isAuthorized(user, context, hashedToken)) {\n                        throw new AuthorizationException(\"Request rejected due to an authorization failure\");\n                    }\n                }\n            }\n        }\n        return externalUser;\n    }\n\n    /**\n     * Authorize a hashed token against a request string\n     * The hashed token will be comprised of:\n     * the User's session token + the relative request Url + the Http Verb + the Date as ISO 8061 String + a nonce token generated by the client\n     * <code>\n     * Example:\n     * 9fbc6f9a-af1b-4767-a492-c8462fd2a4d9:user/2e2ce9e8-798e-42b6-9326-fd2e56aef7aa,GET,2012-06-30T12:00:00+01:00,34e321a7c4\n     * <p/>\n     * </code>\n     * <p/>\n     * This will be SHA-256 hashed and then Base64 encoded to produce:\n     * <p/>\n     * <code>\n     * HR/3DJp8RCGo50Wu+/3cr7ibdoNXKg1eYMt3HO5QoP4=\n     * </code>\n     *\n     * @param user should have a session token that will validate the request signature\n     * @param authorizationRequest the request containing all the details needed to authorize the request\n     * @param hashedToken the token to match against\n     * @return true if the token is authorized\n     */\n    private boolean isAuthorized(User user, AuthorizationRequestContext authorizationRequest, String hashedToken) {\n        Assert.notNull(user);\n        Assert.notNull(authorizationRequest.getAuthorizationToken());\n        String unEncodedString = composeUnEncodedRequest(authorizationRequest);\n        AuthorizationToken authorizationToken = user.getAuthorizationToken();\n        String userTokenHash = encodeAuthToken(authorizationToken.getToken(), unEncodedString);\n            if (hashedToken.equals(userTokenHash)) {\n                return true;\n            }\n        LOG.error(\"Hash check failed for hashed token: {} for the following request: {} for user: {}\",\n                new Object[]{authorizationRequest.getAuthorizationToken(), unEncodedString, user.getId()});\n        return false;\n    }\n\n    /**\n     * Encode the token by prefixing it with the User's Session Token\n     *\n     * @param token\n     * @return encoded token\n     */\n    private String encodeAuthToken(String token, String unencodedRequest) {\n        byte[] digest = DigestUtils.sha256(token + \":\" + unencodedRequest);\n        return new String(Base64.encodeBase64(digest));\n\n    }\n\n    /**\n     * The recipe to compose a signed request\n     *\n     * @param authRequest\n     * @return the string value to hash\n     */\n    private String composeUnEncodedRequest(AuthorizationRequestContext authRequest) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(authRequest.getRequestUrl());\n        sb.append(',');\n        sb.append(authRequest.getHttpMethod().toUpperCase());\n        sb.append(',');\n        sb.append(authRequest.getRequestDateString());\n        sb.append(',').append(authRequest.getNonceToken());\n        return sb.toString();\n\n    }\n\n    /**\n     * Ensure that the date of the request falls within the configured range\n     * @param requestDateString\n     */\n    private void validateRequestDate(String requestDateString) {\n        Date date = DateUtil.getDateFromIso8061DateString(requestDateString);\n        DateTime now = new DateTime();\n        DateTime offset = new DateTime(date);\n        if (!(offset.isAfter(now.minusMinutes(config.getSessionDateOffsetInMinutes())) &&\n                offset.isBefore(now.plusMinutes(config.getSessionDateOffsetInMinutes())))) {\n            LOG.error(\"Date in header is out of range: {}\", requestDateString);\n            throw new AuthorizationException(\"Date in header is out of range: \" + requestDateString);\n        }\n    }\n\n    /**\n     * The nonce value sent by the client and used in the request signature should be unique across the system\n     * Nonce values will only be considered unique within the time limits of the cache.\n     * The value will be protected if the cache expiry time is within the limits of the request date range.\n     * If the date in the request is stale then the nonce value wil be irrelevant\n     *\n     * Note that the caching strategy will not work in a cluster. A distributed cache will be needed.\n     *\n     * @param nonceValue\n     */\n    private void validateNonce(String nonceValue) {\n        Nonce nonce = nonceCache.getUnchecked(nonceValue);\n        Duration tolerance = new Duration(nonce.timestamp, new DateTime());\n        if (tolerance.isLongerThan(Duration.millis(NONCE_CHECK_TOLERANCE_IN_MILLIS))) {\n            LOG.error(\"Nonce value was not unique: {}\", nonceValue);\n            throw new AuthorizationException(\"Nonce value is not unique\");\n        }\n    }\n\n    private static class Nonce {\n        private DateTime timestamp;\n        private String nonceValue;\n\n        Nonce(DateTime time, String nonce) {\n            this.timestamp = time;\n            this.nonceValue = nonce;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/authorization/impl/SecurityContextImpl.java",
    "content": "package com.porterhead.rest.authorization.impl;\n\nimport com.porterhead.rest.authorization.exception.InvalidAuthorizationHeaderException;\nimport com.porterhead.rest.user.api.ExternalUser;\nimport com.porterhead.rest.user.domain.Role;\n\nimport javax.ws.rs.core.SecurityContext;\nimport java.security.Principal;\n\n/**\n * Implementation of {@link javax.ws.rs.core.SecurityContext}\n *\n * User: porter\n * Date: 16/03/2012\n * Time: 16:13\n */\npublic class SecurityContextImpl implements SecurityContext {\n\n    private final ExternalUser user;\n\n    public SecurityContextImpl(ExternalUser user) {\n        this.user = user;\n    }\n\n    public Principal getUserPrincipal() {\n        return user;\n    }\n\n    public boolean isUserInRole(String role) {\n        if(role.equalsIgnoreCase(Role.anonymous.name())) {\n             return true;\n        }\n        if(user == null) {\n            throw new InvalidAuthorizationHeaderException();\n        }\n        return user.getRole().equalsIgnoreCase(role);\n    }\n\n    public boolean isSecure() {\n        return false;\n    }\n\n    public String getAuthenticationScheme() {\n        return SecurityContext.BASIC_AUTH;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/authorization/impl/SessionTokenAuthorizationService.java",
    "content": "package com.porterhead.rest.authorization.impl;\n\nimport com.porterhead.rest.authorization.AuthorizationRequestContext;\nimport com.porterhead.rest.authorization.AuthorizationService;\nimport com.porterhead.rest.user.UserRepository;\nimport com.porterhead.rest.user.api.ExternalUser;\nimport com.porterhead.rest.user.domain.AuthorizationToken;\nimport com.porterhead.rest.user.domain.User;\nimport com.porterhead.rest.user.exception.AuthorizationException;\n\nimport java.util.Date;\n\n/**\n *\n * Simple authorization service that requires a session token in the Authorization header\n * This is then matched to a user\n *\n * @version 1.0\n * @author: Iain Porter\n * @since 29/01/2013\n */\npublic class SessionTokenAuthorizationService implements AuthorizationService {\n\n    /**\n     * directly access user objects\n     */\n    private final UserRepository userRepository;\n\n    public SessionTokenAuthorizationService(UserRepository repository) {\n        this.userRepository = repository;\n    }\n\n    public ExternalUser authorize(AuthorizationRequestContext securityContext) {\n        String token = securityContext.getAuthorizationToken();\n        ExternalUser externalUser = null;\n        if(token == null) {\n            return externalUser;\n        }\n        User user =  userRepository.findBySession(token);\n        if(user == null) {\n            throw new AuthorizationException(\"Session token not valid\");\n        }\n        AuthorizationToken authorizationToken = user.getAuthorizationToken();\n            if (authorizationToken.getToken().equals(token)) {\n                externalUser = new ExternalUser(user);\n            }\n        return externalUser;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/config/ApplicationConfig.java",
    "content": "package com.porterhead.rest.config;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.core.env.Environment;\n\n/**\n * User: porter\n * Date: 17/05/2012\n * Time: 19:07\n */\n@Configuration\n@PropertySource({\"classpath:/properties/app.properties\"})\npublic class ApplicationConfig {\n\n    private final static String HOSTNAME_PROPERTY = \"hostNameUrl\";\n\n    private final static String SECURITY_AUTHORIZATION_REQUIRE_SIGNED_REQUESTS = \"security.authorization.requireSignedRequests\";\n    private final static String AUTHORIZATION_EXPIRY_DURATION = \"authorization.timeToLive.inSeconds\";\n    private final static String SESSION_DATE_OFFSET_IN_MINUTES = \"session.date.offset.inMinutes\";\n    private final static String TOKEN_EMAIL_REGISTRATION_DURATION = \"token.emailRegistration.timeToLive.inMinutes\";\n    private final static String TOKEN_EMAIL_VERIFICATION_DURATION = \"token.emailVerification.timeToLive.inMinutes\";\n    private final static String TOKEN_LOST_PASSWORD_DURATION = \"token.lostPassword.timeToLive.inMinutes\";\n    private final static String EMAIL_SERVICES_FROM_ADDRESS = \"email.services.fromAddress\";\n    private final static String EMAIL_SERVICES_REPLYTO_ADDRESS = \"email.services.replyTo\";\n    private final static String EMAIL_SERVICES_VERIFICATION_EMAIL_SUBJECT_TEXT = \"email.services.emailVerificationSubjectText\";\n    private final static String EMAIL_SERVICES_REGISTRATION_EMAIL_SUBJECT_TEXT = \"email.services.emailRegistrationSubjectText\";\n    private final static String EMAIL_SERVICES_LOST_PASSWORD_SUBJECT_TEXT = \"email.services.lostPasswordSubjectText\";\n\n\n    @Autowired\n    protected Environment environment;\n\n    public String getHostNameUrl() {\n        return environment.getProperty(HOSTNAME_PROPERTY);\n    }\n\n    public String getFacebookClientId() {\n        return environment.getProperty(\"facebook.clientId\");\n    }\n\n    public String getFacebookClientSecret() {\n        return environment.getProperty(\"facebook.clientSecret\");\n    }\n\n    public int getAuthorizationExpiryTimeInSeconds() {\n        return Integer.parseInt(environment.getProperty(AUTHORIZATION_EXPIRY_DURATION));\n    }\n\n    public int getSessionDateOffsetInMinutes() {\n        return Integer.parseInt(environment.getProperty(SESSION_DATE_OFFSET_IN_MINUTES));\n    }\n\n    public int getEmailRegistrationTokenExpiryTimeInMinutes() {\n        return Integer.parseInt(environment.getProperty(TOKEN_EMAIL_REGISTRATION_DURATION));\n    }\n\n    public int getEmailVerificationTokenExpiryTimeInMinutes() {\n        return Integer.parseInt(environment.getProperty(TOKEN_EMAIL_VERIFICATION_DURATION));\n    }\n\n    public int getLostPasswordTokenExpiryTimeInMinutes() {\n        return Integer.parseInt(environment.getProperty(TOKEN_LOST_PASSWORD_DURATION));\n    }\n\n    public String getEmailVerificationSubjectText() {\n        return environment.getProperty(EMAIL_SERVICES_VERIFICATION_EMAIL_SUBJECT_TEXT);\n    }\n\n    public String getEmailRegistrationSubjectText() {\n        return environment.getProperty(EMAIL_SERVICES_REGISTRATION_EMAIL_SUBJECT_TEXT);\n    }\n\n    public String getLostPasswordSubjectText() {\n        return environment.getProperty(EMAIL_SERVICES_LOST_PASSWORD_SUBJECT_TEXT);\n    }\n\n    public String getEmailFromAddress() {\n        return environment.getProperty(EMAIL_SERVICES_FROM_ADDRESS);\n    }\n\n    public String getEmailReplyToAddress() {\n        return environment.getProperty(EMAIL_SERVICES_REPLYTO_ADDRESS);\n    }\n\n    public Boolean requireSignedRequests() {\n        return environment.getProperty(SECURITY_AUTHORIZATION_REQUIRE_SIGNED_REQUESTS).equalsIgnoreCase(\"true\");\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/config/ApplicationDevConfig.java",
    "content": "package com.porterhead.rest.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.security.crypto.encrypt.Encryptors;\nimport org.springframework.security.crypto.encrypt.TextEncryptor;\n\n/**\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 21/09/2012\n */\n@Configuration\n@Profile(value={\"dev\", \"local\"})\n@PropertySource({\"classpath:/properties/dev-app.properties\"})\npublic class ApplicationDevConfig {\n\n    @Bean\n    public TextEncryptor textEncryptor() {\n        return Encryptors.noOpText();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/config/ApplicationProductionConfig.java",
    "content": "package com.porterhead.rest.config;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.security.crypto.encrypt.Encryptors;\nimport org.springframework.security.crypto.encrypt.TextEncryptor;\n\n/**\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 21/09/2012\n */\n@Configuration\n@Profile(value=\"production\")\n@PropertySource({\"classpath:/properties/production-app.properties\"})\npublic class ApplicationProductionConfig {\n\n    @Autowired\n    Environment environment;\n\n      @Bean\n        public TextEncryptor textEncryptor() {\n            return Encryptors.queryableText(environment.getProperty(\"security.encryptPassword\"),\n                    environment.getProperty(\"security.encryptSalt\"));\n        }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/config/ApplicationStagingConfig.java",
    "content": "package com.porterhead.rest.config;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.security.crypto.encrypt.Encryptors;\nimport org.springframework.security.crypto.encrypt.TextEncryptor;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 21/09/2012\n */\n@Configuration\n@Profile(value=\"staging\")\n@PropertySource({\"classpath:/properties/staging-app.properties\"})\npublic class ApplicationStagingConfig {\n\n        @Autowired\n        Environment environment;\n\n      @Bean\n        public TextEncryptor textEncryptor() {\n            return Encryptors.queryableText(environment.getProperty(\"security.encryptPassword\"),\n                    environment.getProperty(\"security.encryptSalt\"));\n        }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/exception/ApplicationRuntimeException.java",
    "content": "package com.porterhead.rest.exception;\n\n\npublic class ApplicationRuntimeException extends BaseWebApplicationException {\n\n    public ApplicationRuntimeException(String applicationMessage) {\n        super(500, \"50002\", \"Internal System error\", applicationMessage);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/exception/BaseWebApplicationException.java",
    "content": "package com.porterhead.rest.exception;\n\nimport com.porterhead.rest.api.ErrorResponse;\n\nimport javax.ws.rs.WebApplicationException;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.Response;\n\n/**\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 19/10/2012\n */\npublic abstract class BaseWebApplicationException extends WebApplicationException {\n\n    private final int status;\n    private final String errorMessage;\n    private final String errorCode;\n    private final String developerMessage;\n\n    public BaseWebApplicationException(int httpStatus, String errorCode, String errorMessage, String developerMessage) {\n        this.status = httpStatus;\n        this.errorMessage = errorMessage;\n        this.errorCode = errorCode;\n        this.developerMessage = developerMessage;\n    }\n\n\n    @Override\n    public Response getResponse() {\n        return Response.status(status).type(MediaType.APPLICATION_JSON_TYPE).entity(getErrorResponse()).build();\n    }\n\n    public ErrorResponse getErrorResponse() {\n        ErrorResponse response = new ErrorResponse();\n        response.setErrorCode(errorCode);\n        response.setApplicationMessage(developerMessage);\n        response.setConsumerMessage(errorMessage);\n        return response;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/exception/NotFoundException.java",
    "content": "package com.porterhead.rest.exception;\n\nimport javax.ws.rs.WebApplicationException;\n\n/**\n * User: porter\n * Date: 03/05/2012\n * Time: 12:27\n */\npublic class NotFoundException extends WebApplicationException {\n\n    public NotFoundException() {\n        super(404);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/exception/ValidationException.java",
    "content": "package com.porterhead.rest.exception;\n\nimport com.porterhead.rest.api.ErrorResponse;\nimport com.porterhead.rest.api.ValidationError;\n\nimport javax.validation.ConstraintViolation;\nimport javax.ws.rs.WebApplicationException;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.Response;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * User: porter\n * Date: 03/05/2012\n * Time: 21:43\n */\npublic class ValidationException extends WebApplicationException {\n\n    private final int status = 400;\n    private String errorMessage;\n    private String developerMessage;\n    private List<ValidationError> errors = new ArrayList<ValidationError>();\n\n    public ValidationException() {\n        errorMessage = \"Validation Error\";\n        developerMessage = \"The data passed in the request was invalid. Please check and resubmit\";\n    }\n\n    public ValidationException(String message) {\n        super();\n        errorMessage = message;\n    }\n\n    public ValidationException(Set<? extends ConstraintViolation<?>> violations) {\n        this();\n        for(ConstraintViolation<?> constraintViolation : violations) {\n            ValidationError error = new ValidationError();\n            error.setMessage(constraintViolation.getMessage());\n            error.setPropertyName(constraintViolation.getPropertyPath().toString());\n            error.setPropertyValue(constraintViolation.getInvalidValue() != null ? constraintViolation.getInvalidValue().toString() : null);\n            errors.add(error);\n        }\n    }\n\n    @Override\n    public Response getResponse() {\n        return Response.status(status).type(MediaType.APPLICATION_JSON_TYPE).entity(getErrorResponse()).build();\n    }\n\n    public ErrorResponse getErrorResponse() {\n        ErrorResponse response = new ErrorResponse();\n        response.setApplicationMessage(developerMessage);\n        response.setConsumerMessage(errorMessage);\n        response.setValidationErrors(errors);\n        return response;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/filter/ResourceFilterFactory.java",
    "content": "package com.porterhead.rest.filter;\n\nimport com.sun.jersey.api.container.filter.RolesAllowedResourceFilterFactory;\nimport com.sun.jersey.api.model.AbstractMethod;\nimport com.sun.jersey.spi.container.ResourceFilter;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport javax.ws.rs.ext.Provider;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Add the SecurityContextFilter to the list of Filters to apply to requests\n *\n * This factory is registered with the Web Context:\n *\n * <code>\n *     <init-param>\n            <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>\n            <param-value>com.porterhead.com.porterhead.rest.filter.ResourceFilterFactory</param-value>\n        </init-param>\n * </code>\n *\n *\n * @author: Iain Porter\n */\n@Component\n@Provider\npublic class ResourceFilterFactory extends RolesAllowedResourceFilterFactory {\n\n    @Autowired\n    private SecurityContextFilter securityContextFilter;\n\n    @Override\n    public List<ResourceFilter> create(AbstractMethod am) {\n        List<ResourceFilter> filters = super.create(am);\n        if (filters == null) {\n            filters = new ArrayList<ResourceFilter>();\n        }\n        List<ResourceFilter> securityFilters = new ArrayList<ResourceFilter>(filters);\n        //put the Security Filter first in line\n        securityFilters.add(0, securityContextFilter);\n        return securityFilters;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/filter/SecurityContextFilter.java",
    "content": "package com.porterhead.rest.filter;\n\nimport com.porterhead.rest.authorization.AuthorizationRequestContext;\nimport com.porterhead.rest.authorization.AuthorizationService;\nimport com.porterhead.rest.authorization.impl.RequestSigningAuthorizationService;\nimport com.porterhead.rest.authorization.impl.SecurityContextImpl;\nimport com.porterhead.rest.authorization.impl.SessionTokenAuthorizationService;\nimport com.porterhead.rest.config.ApplicationConfig;\nimport com.porterhead.rest.user.UserRepository;\nimport com.porterhead.rest.user.UserService;\nimport com.porterhead.rest.user.api.ExternalUser;\nimport com.sun.jersey.spi.container.ContainerRequest;\nimport com.sun.jersey.spi.container.ContainerRequestFilter;\nimport com.sun.jersey.spi.container.ContainerResponseFilter;\nimport com.sun.jersey.spi.container.ResourceFilter;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport javax.ws.rs.ext.Provider;\n\n/**\n * A Servlet filter class for authorizing requests.\n *\n *\n * The role of this filter class is to set a {@link javax.ws.rs.core.SecurityContext} in the {@link com.sun.jersey.spi.container.ContainerRequest}\n *\n * @see {@link com.porterhead.rest.authorization.impl.SecurityContextImpl}\n *\n * @author: Iain Porter\n */\n@Component\n@Provider\npublic class SecurityContextFilter implements ResourceFilter, ContainerRequestFilter {\n\n    private static final Logger LOG = LoggerFactory.getLogger(SecurityContextFilter.class);\n\n    protected static final String HEADER_AUTHORIZATION = \"Authorization\";\n\n    protected static final String HEADER_DATE = \"x-java-rest-date\";\n\n    protected static final String HEADER_NONCE = \"nonce\";\n\n    private AuthorizationService authorizationService;\n\n    ApplicationConfig config;\n\n    @Autowired\n    public SecurityContextFilter(UserRepository userRepository, UserService userService, ApplicationConfig config) {\n        delegateAuthorizationService(userRepository, userService, config);\n        this.config = config;\n\n    }\n\n    /**\n     * If there is an Authorisation header in the request extract the session token and retrieve the user\n     *\n     * Delegate to the AuthorizationService to validate the request\n     *\n     * If the request has a valid session token and the user is validated then a user object will be added to the security context\n     *\n     * Any Resource Controllers can assume the user has been validated and can merely authorize based on the role\n     *\n     * Resources with @PermitAll annotation do not require an Authorization header but will still be filtered\n     *\n     * @param request the ContainerRequest to filter\n     *\n     * @return the ContainerRequest with a SecurityContext added\n     */\n    public ContainerRequest filter(ContainerRequest request) {\n        String authToken = request.getHeaderValue(HEADER_AUTHORIZATION);\n        String requestDateString = request.getHeaderValue(HEADER_DATE);\n        String nonce = request.getHeaderValue(HEADER_NONCE);\n        AuthorizationRequestContext context = new AuthorizationRequestContext(request.getPath(), request.getMethod(),\n                            requestDateString, nonce, authToken);\n        ExternalUser externalUser = authorizationService.authorize(context);\n        request.setSecurityContext(new SecurityContextImpl(externalUser));\n        return request;\n    }\n\n    /**\n     * Specify the AuthorizationService that the application should use\n     *\n     * @param userRepository\n     * @param userService\n     * @param config\n     */\n    private void delegateAuthorizationService(UserRepository userRepository, UserService userService, ApplicationConfig config) {\n        if(config.requireSignedRequests()) {\n            this.authorizationService = new RequestSigningAuthorizationService(userRepository, userService, config);\n        } else {\n            this.authorizationService = new SessionTokenAuthorizationService(userRepository);\n        }\n    }\n\n\n    public ContainerRequestFilter getRequestFilter() {\n        return this;\n    }\n\n    public ContainerResponseFilter getResponseFilter() {\n        return null;\n    }\n\n    @Autowired\n    public void setConfig(ApplicationConfig config) {\n        this.config = config;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/gateway/EmailServicesGateway.java",
    "content": "package com.porterhead.rest.gateway;\n\nimport com.porterhead.rest.user.EmailServiceTokenModel;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 11/09/2012\n */\npublic interface EmailServicesGateway {\n\n    public void sendVerificationToken(EmailServiceTokenModel model);\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/model/BaseEntity.java",
    "content": "package com.porterhead.rest.model;\n\nimport org.springframework.data.jpa.domain.AbstractPersistable;\nimport org.springframework.util.Assert;\n\nimport javax.persistence.Column;\nimport javax.persistence.MappedSuperclass;\nimport javax.persistence.Version;\nimport java.util.Date;\nimport java.util.UUID;\n\n/**\n * Base class for all JPA Entities\n *\n * @author : Iain Porter\n */\n@MappedSuperclass\npublic abstract class BaseEntity extends AbstractPersistable<Long> {\n\n    @Version\n    private int version;\n\n    /**\n     *  All objects will have a unique UUID which allows for the decoupling from DB generated ids\n     *\n     */\n    @Column(length=36)\n    private String uuid;\n\n    private Date timeCreated;\n\n    public BaseEntity() {\n        this(UUID.randomUUID());\n    }\n\n    public BaseEntity(UUID guid) {\n        Assert.notNull(guid, \"UUID is required\");\n        setUuid(guid.toString());\n        this.timeCreated = new Date();\n    }\n\n    public UUID getUuid() {\n        return UUID.fromString(uuid);\n    }\n\n    public void setUuid(String uuid) {\n        this.uuid = uuid;\n    }\n\n    public int hashCode() {\n        return getUuid().hashCode();\n    }\n\n    /**\n     * In most instances we can rely on the UUID to identify the object.\n     * Subclasses may want a user friendly identifier for constructing easy to read urls\n     *\n     * <code>\n     *    /user/1883c578-76be-47fb-a5c1-7bbea3bf7fd0 using uuid as the identifier\n     *\n     *    /user/jsmith using the username as the identifier\n     *\n     * </code>\n     *\n     * @return Object unique identifier for the object\n     */\n    public Object getIdentifier() {\n        return getUuid().toString();\n    }\n\n    public int getVersion() {\n        return version;\n    }\n\n    public Date getTimeCreated() {\n        return timeCreated;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/resource/GenericExceptionMapper.java",
    "content": "package com.porterhead.rest.resource;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.ws.rs.WebApplicationException;\nimport javax.ws.rs.core.Response;\nimport javax.ws.rs.ext.ExceptionMapper;\nimport javax.ws.rs.ext.Provider;\n\n/**\n * User: porter\n * Date: 22/03/2012\n * Time: 15:56\n */\n@Provider\npublic class GenericExceptionMapper implements ExceptionMapper<Exception> {\n\n    private static Logger LOG = LoggerFactory.getLogger(GenericExceptionMapper.class);\n\n    public Response toResponse(Exception exception) {\n        if (exception instanceof WebApplicationException) {\n            LOG.info(\"Web Application Exception: \" + exception);\n            return ((WebApplicationException) exception).getResponse();\n        }\n        LOG.error(\"Internal Server Error: \" + exception);\n        LOG.error(\"Internal Server Error: \" + exception.getCause());\n        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/resource/HealthCheckResource.java",
    "content": "package com.porterhead.rest.resource;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.security.PermitAll;\nimport javax.ws.rs.GET;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.Produces;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.Response;\n\n/**\n * User: porter\n * Date: 11/04/2012\n * Time: 15:21\n */\n@Path(\"/healthcheck\")\n@Component\n@Produces({MediaType.TEXT_PLAIN})\n@PropertySource(\"classpath:properties/app.properties\")\npublic class HealthCheckResource {\n\n    @Autowired\n    Environment env;\n\n    @PermitAll\n    @GET\n    public Response ping() {\n        return Response.ok().entity(\"Running version \" + env.getProperty(\"application.version\")).build();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/service/BaseService.java",
    "content": "package com.porterhead.rest.service;\n\nimport com.porterhead.rest.exception.ValidationException;\n\nimport javax.validation.ConstraintViolation;\nimport javax.validation.Validator;\nimport java.util.Set;\n\n/**\n * @version 1.0\n * @author: Iain Porter\n * @since 08/05/2013\n */\npublic abstract class BaseService {\n\n    private Validator validator;\n\n    public BaseService(Validator validator) {\n        this.validator = validator;\n    }\n\n    protected void validate(Object request) {\n        Set<? extends ConstraintViolation<?>> constraintViolations = validator.validate(request);\n        if (constraintViolations.size() > 0) {\n            throw new ValidationException(constraintViolations);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/EmailServiceTokenModel.java",
    "content": "package com.porterhead.rest.user;\n\nimport com.porterhead.rest.user.domain.User;\nimport com.porterhead.rest.user.domain.VerificationToken;\nimport org.apache.commons.codec.binary.Base64;\n\nimport java.io.Serializable;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 13/09/2012\n */\npublic class EmailServiceTokenModel implements Serializable {\n\n    private final String emailAddress;\n    private final String token;\n    private final VerificationToken.VerificationTokenType tokenType;\n    private final String hostNameUrl;\n\n\n    public EmailServiceTokenModel(User user, VerificationToken token, String hostNameUrl)  {\n        this.emailAddress = user.getEmailAddress();\n        this.token = token.getToken();\n        this.tokenType = token.getTokenType();\n        this.hostNameUrl = hostNameUrl;\n    }\n\n    public String getEmailAddress() {\n        return emailAddress;\n    }\n\n    public String getEncodedToken() {\n        return new String(Base64.encodeBase64(token.getBytes()));\n    }\n\n    public String getToken() {\n        return token;\n    }\n\n    public VerificationToken.VerificationTokenType getTokenType() {\n        return tokenType;\n    }\n\n    public String getHostNameUrl() {\n        return hostNameUrl;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/SocialUserRepository.java",
    "content": "package com.porterhead.rest.user;\n\nimport com.porterhead.rest.user.domain.SocialUser;\nimport com.porterhead.rest.user.domain.User;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.util.MultiValueMap;\n\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * User: porter\n * Date: 15/05/2012\n * Time: 16:35\n */\npublic interface SocialUserRepository extends JpaRepository<SocialUser, Long> {\n\n    List<SocialUser> findAllByUser(User user);\n\n    List<SocialUser> findByUserAndProviderId(User user, String providerId);\n\n    List<SocialUser> findByProviderIdAndProviderUserId(String providerId, String providerUserId);\n\n    //TODO will need a JPA Query here\n    List<SocialUser> findByUserAndProviderUserId(User user, MultiValueMap<String, String> providerUserIds);\n\n    @Query(\"Select userId from SocialUser where providerId = ? AND providerUserId in (?)\")\n    Set<String> findByProviderIdAndProviderUserId(String providerId, Set<String> providerUserIds);\n\n    SocialUser findByUserAndProviderIdAndProviderUserId(User user, String providerId, String providerUserId);\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/UserRepository.java",
    "content": "package com.porterhead.rest.user;\n\nimport com.porterhead.rest.user.domain.User;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.Query;\n\nimport java.util.Date;\nimport java.util.List;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 12/04/2012\n */\npublic interface UserRepository  extends JpaRepository<User, Long> {\n\n    User findByEmailAddress(String emailAddress);\n\n    @Query(\"select u from User u where uuid = ?\")\n    User findByUuid(String uuid);\n\n    @Query(\"select u from User u where u in (select user from AuthorizationToken where lastUpdated < ?)\")\n    List<User> findByExpiredSession(Date lastUpdated);\n\n    @Query(\"select u from User u where u = (select user from AuthorizationToken where token = ?)\")\n    User findBySession(String token);\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/UserService.java",
    "content": "package com.porterhead.rest.user;\n\nimport com.porterhead.rest.user.api.*;\nimport com.porterhead.rest.user.domain.AuthorizationToken;\nimport com.porterhead.rest.user.domain.Role;\nimport com.porterhead.rest.user.domain.User;\nimport org.springframework.social.connect.Connection;\n\n/**\n * @author: Iain Porter\n *\n * Service to manage users\n */\npublic interface UserService {\n\n\n    /**\n     * Create a new User with the given role\n     *\n     * @param request\n     * @param role\n     * @return AuthenticatedUserToken\n     */\n    public AuthenticatedUserToken createUser(CreateUserRequest request, Role role);\n\n\n    /**\n     * Create a Default User with a given role\n     *\n     * @param role\n     * @return AuthenticatedUserToken\n     */\n    public AuthenticatedUserToken createUser(Role role);\n\n    /**\n     * Login a User\n     *\n     * @param request\n     * @return AuthenticatedUserToken\n     */\n    public AuthenticatedUserToken login(LoginRequest request);\n\n    /**\n     * Log in a User using Connection details from an authorized request from the User's supported Social provider\n     * encapsulated in the {@link org.springframework.social.connect.Connection} parameter\n     *\n     * @param connection containing the details of the authorized user account form the Social provider\n     * @return the User account linked to the {@link com.porterhead.rest.user.domain.SocialUser} account\n     */\n    public AuthenticatedUserToken socialLogin(Connection<?> connection);\n\n    /**\n     * Get a User based on a unique identifier\n     *\n     * Identifiers supported are uuid, emailAddress\n     *\n     * @param userIdentifier\n     * @return  User\n     */\n    public ExternalUser getUser(ExternalUser requestingUser, String userIdentifier);\n\n    /**\n     * Delete user, only authenticated user accounts can be deleted\n     *\n     * @param userMakingRequest the user authorized to delete the user\n     * @param userId the id of the user to delete\n     */\n    public void deleteUser(ExternalUser userMakingRequest, String userId);\n\n    /**\n     * Save User\n     *\n     * @param userId\n     * @param request\n     */\n    public ExternalUser saveUser(String userId, UpdateUserRequest request);\n\n    /**\n     * Create an AuthorizationToken for the User\n     *\n     * @return\n     */\n    public AuthorizationToken createAuthorizationToken(User user);\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/UserServiceImpl.java",
    "content": "package com.porterhead.rest.user;\n\n\nimport com.porterhead.rest.config.ApplicationConfig;\nimport com.porterhead.rest.service.BaseService;\nimport com.porterhead.rest.user.api.*;\nimport com.porterhead.rest.user.domain.AuthorizationToken;\nimport com.porterhead.rest.user.domain.Role;\nimport com.porterhead.rest.user.domain.User;\nimport com.porterhead.rest.user.exception.AuthenticationException;\nimport com.porterhead.rest.user.exception.AuthorizationException;\nimport com.porterhead.rest.user.exception.DuplicateUserException;\nimport com.porterhead.rest.user.exception.UserNotFoundException;\nimport com.porterhead.rest.user.social.JpaUsersConnectionRepository;\nimport com.porterhead.rest.util.StringUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.social.connect.Connection;\nimport org.springframework.social.connect.UserProfile;\nimport org.springframework.social.connect.UsersConnectionRepository;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\nimport javax.validation.Validator;\nimport java.util.List;\n\n/**\n * Service for managing User accounts\n *\n * @author: Iain Porter\n */\n@Service(\"userService\")\npublic class UserServiceImpl extends BaseService implements UserService {\n\n    /**\n     * For Social API handling\n     */\n    private UsersConnectionRepository jpaUsersConnectionRepository;\n\n    private UserRepository userRepository;\n\n    private ApplicationConfig applicationConfig;\n\n    public UserServiceImpl(Validator validator) {\n        super(validator);\n    }\n\n    @Autowired\n    public UserServiceImpl(UsersConnectionRepository usersConnectionRepository,\n                           Validator validator, ApplicationConfig applicationConfig) {\n        this(validator);\n        this.jpaUsersConnectionRepository = usersConnectionRepository;\n        ((JpaUsersConnectionRepository)this.jpaUsersConnectionRepository).setUserService(this);\n        this.applicationConfig = applicationConfig;\n    }\n\n    private static final Logger LOG = LoggerFactory.getLogger(UserServiceImpl.class);\n\n    /**\n     * {@inheritDoc}\n     *\n     * This method creates a User with the given Role. A check is made to see if the username already exists and a duplication\n     * check is made on the email address if it is present in the request.\n     * <P></P>\n     * The password is hashed and a AuthorizationToken generated for subsequent authorization of role-protected requests.\n     *\n     */\n    @Transactional\n    public AuthenticatedUserToken createUser(CreateUserRequest request, Role role) {\n        validate(request);\n        User searchedForUser = userRepository.findByEmailAddress(request.getUser().getEmailAddress());\n        if (searchedForUser != null) {\n            throw new DuplicateUserException();\n        }\n\n        User newUser = createNewUser(request, role);\n        AuthenticatedUserToken token = new AuthenticatedUserToken(newUser.getUuid().toString(), createAuthorizationToken(newUser).getToken());\n        userRepository.save(newUser);\n        return token;\n    }\n\n    @Transactional\n    public AuthenticatedUserToken createUser(Role role) {\n        User user = new User();\n        user.setRole(role);\n        AuthenticatedUserToken token = new AuthenticatedUserToken(user.getUuid().toString(),\n                createAuthorizationToken(user).getToken());\n        userRepository.save(user);\n        return token;\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     *  Login supports authentication against an email attribute.\n     *  If a User is retrieved that matches, the password in the request is hashed\n     *  and compared to the persisted password for the User account.\n     */\n    @Transactional\n    public AuthenticatedUserToken login(LoginRequest request) {\n        validate(request);\n        User user = null;\n        user = userRepository.findByEmailAddress(request.getUsername());\n        if (user == null) {\n            throw new AuthenticationException();\n        }\n        String hashedPassword = null;\n        try {\n            hashedPassword = user.hashPassword(request.getPassword());\n        } catch (Exception e) {\n            throw new AuthenticationException();\n        }\n        if (hashedPassword.equals(user.getHashedPassword())) {\n            return new AuthenticatedUserToken(user.getUuid().toString(), createAuthorizationToken(user).getToken());\n        } else {\n            throw new AuthenticationException();\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * Associate a Connection with a User account. If one does not exist a new User is created and linked to the\n     * {@link com.porterhead.rest.user.domain.SocialUser} represented in the Connection details.\n     *\n     * <P></P>\n     *\n     * A AuthorizationToken is generated and any Profile data that can be collected from the Social account is propagated to the User object.\n     *\n     */\n    @Transactional\n    public AuthenticatedUserToken socialLogin(Connection<?> connection) {\n\n        List<String> userUuids = jpaUsersConnectionRepository.findUserIdsWithConnection(connection);\n        if(userUuids.size() == 0) {\n            throw new AuthenticationException();\n        }\n        User user = userRepository.findByUuid(userUuids.get(0)); //take the first one if there are multiple userIds for this provider Connection\n        if (user == null) {\n            throw new AuthenticationException();\n        }\n        updateUserFromProfile(connection, user);\n        return new AuthenticatedUserToken(user.getUuid().toString(), createAuthorizationToken(user).getToken());\n    }\n\n    /**\n     * Allow user to get their own profile or a user with administrator role to get any profile\n     *\n     * @param requestingUser\n     * @param userIdentifier\n     * @return user\n     */\n    @Transactional\n    public ExternalUser getUser(ExternalUser requestingUser, String userIdentifier) {\n        Assert.notNull(requestingUser);\n        Assert.notNull(userIdentifier);\n        User user = ensureUserIsLoaded(userIdentifier);\n        if(!requestingUser.getId().equals(user.getUuid().toString()) && !requestingUser.getRole().equalsIgnoreCase(Role.administrator.toString()))  {\n           throw new AuthorizationException(\"User not authorized to load profile\");\n        }\n        return new ExternalUser(user);\n    }\n\n\n    @Transactional\n    public void deleteUser(ExternalUser userMakingRequest, String userId) {\n        Assert.notNull(userMakingRequest);\n        Assert.notNull(userId);\n        User userToDelete = ensureUserIsLoaded(userId);\n        if (userMakingRequest.getRole().equalsIgnoreCase(Role.administrator.toString()) && (userToDelete.hasRole(Role.anonymous) || userToDelete.hasRole(Role.authenticated))) {\n            userRepository.delete(userToDelete);\n        } else {\n            throw new AuthorizationException(\"User cannot be deleted. Only users with anonymous or authenticated role can be deleted.\");\n        }\n    }\n\n    @Transactional\n    public ExternalUser saveUser(String userId, UpdateUserRequest request) {\n        validate(request);\n        User user = ensureUserIsLoaded(userId);\n        if(request.getFirstName() != null) {\n            user.setFirstName(request.getFirstName());\n        }\n        if(request.getLastName() != null) {\n            user.setLastName(request.getLastName());\n        }\n        if(request.getEmailAddress() != null) {\n            if(!request.getEmailAddress().equals(user.getEmailAddress())) {\n                user.setEmailAddress(request.getEmailAddress());\n                user.setVerified(false);\n            }\n        }\n        userRepository.save(user);\n        return new ExternalUser(user);\n    }\n\n    @Override\n    public AuthorizationToken createAuthorizationToken(User user) {\n        if(user.getAuthorizationToken() == null || user.getAuthorizationToken().hasExpired()) {\n            user.setAuthorizationToken(new AuthorizationToken(user, applicationConfig.getAuthorizationExpiryTimeInSeconds()));\n            userRepository.save(user);\n        }\n        return user.getAuthorizationToken();\n    }\n\n    private User createNewUser(CreateUserRequest request, Role role) {\n        User userToSave = new User(request.getUser());\n        try {\n            userToSave.setHashedPassword(userToSave.hashPassword(request.getPassword().getPassword()));\n        }  catch (Exception e) {\n            throw new AuthenticationException();\n        }\n        userToSave.setRole(role);\n        return userToSave;\n    }\n\n    private void updateUserFromProfile(Connection<?> connection, User user) {\n        UserProfile profile = connection.fetchUserProfile();\n        user.setEmailAddress(profile.getEmail());\n        user.setFirstName(profile.getFirstName());\n        user.setLastName(profile.getLastName());\n        //users logging in from social network are already verified\n        user.setVerified(true);\n        if(user.hasRole(Role.anonymous)) {\n            user.setRole(Role.authenticated);\n        }\n        userRepository.save(user);\n    }\n\n    private User ensureUserIsLoaded(String userIdentifier) {\n        User user = null;\n        if (StringUtil.isValidUuid(userIdentifier)) {\n            user = userRepository.findByUuid(userIdentifier);\n        } else {\n            user = userRepository.findByEmailAddress(userIdentifier);\n        }\n        if (user == null) {\n            throw new UserNotFoundException();\n        }\n        return user;\n    }\n\n    @Autowired\n    public void setUserRepository(UserRepository userRepository) {\n        this.userRepository = userRepository;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/VerificationTokenRepository.java",
    "content": "package com.porterhead.rest.user;\n\nimport com.porterhead.rest.user.domain.VerificationToken;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.Query;\n\n/**\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 14/09/2012\n */\npublic interface VerificationTokenRepository extends JpaRepository<VerificationToken, Long> {\n\n    @Query(\"select t from VerificationToken t where uuid = ?\")\n    VerificationToken findByUuid(String uuid);\n\n    @Query(\"select t from VerificationToken t where token = ?\")\n    VerificationToken findByToken(String token);\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/VerificationTokenService.java",
    "content": "package com.porterhead.rest.user;\n\nimport com.porterhead.rest.user.api.LostPasswordRequest;\nimport com.porterhead.rest.user.api.PasswordRequest;\nimport com.porterhead.rest.user.domain.VerificationToken;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 10/09/2012\n */\npublic interface VerificationTokenService {\n\n    public VerificationToken sendEmailVerificationToken(String userId);\n\n    public VerificationToken sendEmailRegistrationToken(String userId);\n\n    public VerificationToken sendLostPasswordToken(LostPasswordRequest lostPasswordRequest);\n\n    public VerificationToken verify(String base64EncodedToken);\n\n    public VerificationToken generateEmailVerificationToken(String emailAddress);\n\n    public VerificationToken resetPassword(String base64EncodedToken, PasswordRequest passwordRequest);\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/VerificationTokenServiceImpl.java",
    "content": "package com.porterhead.rest.user;\n\nimport com.porterhead.rest.config.ApplicationConfig;\nimport com.porterhead.rest.gateway.EmailServicesGateway;\nimport com.porterhead.rest.service.BaseService;\nimport com.porterhead.rest.user.api.LostPasswordRequest;\nimport com.porterhead.rest.user.api.PasswordRequest;\nimport com.porterhead.rest.user.domain.Role;\nimport com.porterhead.rest.user.domain.User;\nimport com.porterhead.rest.user.domain.VerificationToken;\nimport com.porterhead.rest.user.exception.*;\nimport com.porterhead.rest.util.StringUtil;\nimport org.apache.commons.codec.binary.Base64;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\nimport javax.validation.Validator;\n\n/**\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 10/09/2012\n */\n@Service(\"verificationTokenService\")\npublic class VerificationTokenServiceImpl extends BaseService implements VerificationTokenService {\n\n    private VerificationTokenRepository tokenRepository;\n\n    private EmailServicesGateway emailServicesGateway;\n\n    private UserRepository userRepository;\n\n    ApplicationConfig config;\n\n    public VerificationTokenServiceImpl(Validator validator) {\n        super(validator);\n    }\n\n    @Autowired\n    public VerificationTokenServiceImpl(UserRepository userRepository, VerificationTokenRepository tokenRepository,\n                                        EmailServicesGateway emailServicesGateway, Validator validator) {\n        this(validator);\n        this.userRepository = userRepository;\n        this.tokenRepository = tokenRepository;\n        this.emailServicesGateway = emailServicesGateway;\n    }\n\n    @Transactional\n    public VerificationToken sendEmailVerificationToken(String userId) {\n        User user = ensureUserIsLoaded(userId);\n        return sendEmailVerificationToken(user);\n    }\n\n    private VerificationToken sendEmailVerificationToken(User user) {\n        VerificationToken token = new VerificationToken(user, VerificationToken.VerificationTokenType.emailVerification,\n                config.getEmailVerificationTokenExpiryTimeInMinutes());\n        user.addVerificationToken(token);\n        userRepository.save(user);\n        emailServicesGateway.sendVerificationToken(new EmailServiceTokenModel(user, token, getConfig().getHostNameUrl()));\n        return token;\n    }\n\n    @Transactional\n    public VerificationToken sendEmailRegistrationToken(String userId) {\n        User user = ensureUserIsLoaded(userId);\n        VerificationToken token = new VerificationToken(user,\n                VerificationToken.VerificationTokenType.emailRegistration,\n                config.getEmailRegistrationTokenExpiryTimeInMinutes());\n        user.addVerificationToken(token);\n        userRepository.save(user);\n        emailServicesGateway.sendVerificationToken(new EmailServiceTokenModel(user,\n                token, getConfig().getHostNameUrl()));\n        return token;\n    }\n\n    /**\n     * generate token if user found otherwise do nothing\n     *\n     * @param lostPasswordRequest\n     * @return  a token or null if user not found\n     */\n    @Transactional\n    public VerificationToken sendLostPasswordToken(LostPasswordRequest lostPasswordRequest) {\n        validate(lostPasswordRequest);\n        VerificationToken token = null;\n        User user = userRepository.findByEmailAddress(lostPasswordRequest.getEmailAddress());\n        if (user != null) {\n            token = user.getActiveLostPasswordToken();\n            if (token == null) {\n                token = new VerificationToken(user, VerificationToken.VerificationTokenType.lostPassword,\n                        config.getLostPasswordTokenExpiryTimeInMinutes());\n                user.addVerificationToken(token);\n                userRepository.save(user);\n            }\n            emailServicesGateway.sendVerificationToken(new EmailServiceTokenModel(user, token, getConfig().getHostNameUrl()));\n        }\n\n        return token;\n    }\n\n    @Transactional\n    public VerificationToken verify(String base64EncodedToken) {\n        VerificationToken token = loadToken(base64EncodedToken);\n        if (token.isVerified() || token.getUser().isVerified()) {\n            throw new AlreadyVerifiedException();\n        }\n        token.setVerified(true);\n        token.getUser().setVerified(true);\n        userRepository.save(token.getUser());\n        return token;\n    }\n\n    @Transactional\n    public VerificationToken generateEmailVerificationToken(String emailAddress) {\n        Assert.notNull(emailAddress);\n        User user = userRepository.findByEmailAddress(emailAddress);\n        if (user == null) {\n            throw new UserNotFoundException();\n        }\n        if (user.isVerified()) {\n            throw new AlreadyVerifiedException();\n        }\n        //if token still active resend that\n        VerificationToken token = user.getActiveEmailVerificationToken();\n        if (token == null) {\n            token = sendEmailVerificationToken(user);\n        } else {\n            emailServicesGateway.sendVerificationToken(new EmailServiceTokenModel(user, token, getConfig().getHostNameUrl()));\n        }\n        return token;\n    }\n\n    @Transactional\n    public VerificationToken resetPassword(String base64EncodedToken, PasswordRequest passwordRequest) {\n        Assert.notNull(base64EncodedToken);\n        validate(passwordRequest);\n        VerificationToken token = loadToken(base64EncodedToken);\n        if (token.isVerified()) {\n            throw new AlreadyVerifiedException();\n        }\n        token.setVerified(true);\n        User user = token.getUser();\n        try {\n            user.setHashedPassword(user.hashPassword(passwordRequest.getPassword()));\n        } catch (Exception e) {\n            throw new AuthenticationException();\n        }\n        //set user to verified if not already and authenticated role\n        user.setVerified(true);\n        if (user.hasRole(Role.anonymous)) {\n            user.setRole(Role.authenticated);\n        }\n        userRepository.save(user);\n        return token;\n    }\n\n    private VerificationToken loadToken(String base64EncodedToken) {\n        Assert.notNull(base64EncodedToken);\n        String rawToken = new String(Base64.decodeBase64(base64EncodedToken));\n        VerificationToken token = tokenRepository.findByToken(rawToken);\n        if (token == null) {\n            throw new TokenNotFoundException();\n        }\n        if (token.hasExpired()) {\n            throw new TokenHasExpiredException();\n        }\n        return token;\n    }\n\n    @Autowired\n    public void setConfig(ApplicationConfig config) {\n        this.config = config;\n    }\n\n    @Autowired\n    public void setUserRepository(UserRepository userRepository) {\n        this.userRepository = userRepository;\n    }\n\n    public ApplicationConfig getConfig() {\n        return this.config;\n    }\n\n    private User ensureUserIsLoaded(String userIdentifier) {\n        User user = null;\n        if (StringUtil.isValidUuid(userIdentifier)) {\n            user = userRepository.findByUuid(userIdentifier);\n        } else {\n            user = userRepository.findByEmailAddress(userIdentifier);\n        }\n        if (user == null) {\n            throw new UserNotFoundException();\n        }\n        return user;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/api/AuthenticatedUserToken.java",
    "content": "package com.porterhead.rest.user.api;\n\nimport javax.xml.bind.annotation.XmlRootElement;\n\n/**\n * @author: Iain Porter\n */\n@XmlRootElement\npublic class AuthenticatedUserToken {\n\n    private String userId;\n    private String token;\n\n    public AuthenticatedUserToken(){}\n\n    public AuthenticatedUserToken(String userId, String sessionToken) {\n        this.userId = userId;\n        this.token = sessionToken;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public String getToken() {\n        return token;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public void setToken(String token) {\n        this.token = token;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/api/CreateUserRequest.java",
    "content": "package com.porterhead.rest.user.api;\n\nimport javax.validation.Valid;\nimport javax.validation.constraints.NotNull;\nimport javax.xml.bind.annotation.XmlRootElement;\n\n/**\n * @author: Iain Porter\n */\n@XmlRootElement\npublic class CreateUserRequest {\n\n    @NotNull\n    @Valid\n    private ExternalUser user;\n\n    @NotNull\n    @Valid\n    private PasswordRequest password;\n\n\n    public CreateUserRequest() {\n    }\n\n    public CreateUserRequest(final ExternalUser user, final PasswordRequest password) {\n        this.user = user;\n        this.password = password;\n    }\n\n    public ExternalUser getUser() {\n        return user;\n    }\n\n    public void setUser(ExternalUser user) {\n        this.user = user;\n    }\n\n    public PasswordRequest getPassword() {\n        return password;\n    }\n\n    public void setPassword(PasswordRequest password) {\n        this.password = password;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/api/EmailVerificationRequest.java",
    "content": "package com.porterhead.rest.user.api;\n\nimport javax.validation.constraints.NotNull;\nimport javax.xml.bind.annotation.XmlRootElement;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 15/09/2012\n */\n@XmlRootElement\npublic class EmailVerificationRequest {\n\n    @NotNull\n    private String emailAddress;\n\n    public EmailVerificationRequest() {}\n\n    public EmailVerificationRequest(String emailAddress) {\n        this.emailAddress = emailAddress;\n    }\n\n    public String getEmailAddress() {\n        return emailAddress;\n    }\n\n    public void setEmailAddress(String emailAddress) {\n        this.emailAddress = emailAddress;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/api/ExternalUser.java",
    "content": "package com.porterhead.rest.user.api;\n\nimport com.porterhead.rest.user.domain.AuthorizationToken;\nimport com.porterhead.rest.user.domain.SocialUser;\nimport com.porterhead.rest.user.domain.User;\nimport org.codehaus.jackson.annotate.JsonIgnore;\nimport org.hibernate.validator.constraints.Email;\nimport org.hibernate.validator.constraints.Length;\n\nimport javax.validation.constraints.NotNull;\nimport javax.xml.bind.annotation.XmlRootElement;\nimport java.security.Principal;\nimport java.util.ArrayList;\nimport java.util.List;\n\n\n/**\n *\n * @author: Iain Porter\n */\n@XmlRootElement\npublic class ExternalUser implements Principal {\n\n    private String id;\n\n    @Length(max=50)\n    private String firstName;\n\n    @Length(max=50)\n    private String lastName;\n\n    @NotNull\n    @Email\n    private String emailAddress;\n\n    private boolean isVerified;\n\n    @JsonIgnore\n    private String role;\n\n    private List<SocialProfile> socialProfiles = new ArrayList<SocialProfile>();\n\n    public ExternalUser() {}\n\n    public ExternalUser(String userId) {\n        this.id = userId;\n    }\n\n    public ExternalUser(User user) {\n        this.id = user.getUuid().toString();\n        this.emailAddress = user.getEmailAddress();\n        this.firstName = user.getFirstName();\n        this.lastName = user.getLastName();\n        this.isVerified = user.isVerified();\n        for(SocialUser socialUser: user.getSocialUsers()) {\n            SocialProfile profile = new SocialProfile();\n            profile.setDisplayName(socialUser.getDisplayName());\n            profile.setImageUrl(socialUser.getImageUrl());\n            profile.setProfileUrl(socialUser.getProfileUrl());\n            profile.setProvider(socialUser.getProviderId());\n            profile.setProviderUserId(socialUser.getProviderUserId());\n            socialProfiles.add(profile);\n        }\n        role = user.getRole().toString();\n    }\n\n    public ExternalUser(User user, AuthorizationToken activeSession) {\n        this(user);\n    }\n\n    public String getFirstName() {\n        return firstName;\n    }\n\n    public void setFirstName(String firstName) {\n        this.firstName = firstName;\n    }\n\n    public String getLastName() {\n        return lastName;\n    }\n\n    public void setLastName(String lastName) {\n        this.lastName = lastName;\n    }\n\n    public String getEmailAddress() {\n        return emailAddress;\n    }\n\n    public void setEmailAddress(String emailAddress) {\n        this.emailAddress = emailAddress;\n    }\n\n    public List<SocialProfile> getSocialProfiles() {\n        return socialProfiles;\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public boolean isVerified() {\n        return isVerified;\n    }\n\n    public String getName() {\n        return emailAddress;\n    }\n\n    public String getRole() {\n        return role;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/api/LoginRequest.java",
    "content": "package com.porterhead.rest.user.api;\n\nimport org.hibernate.validator.constraints.Length;\n\nimport javax.validation.constraints.NotNull;\nimport javax.xml.bind.annotation.XmlRootElement;\n\n\n/**\n *\n * @author: Iain Porter\n */\n@XmlRootElement\npublic class LoginRequest {\n\n    @NotNull\n    private String username;\n\n    @Length(min=8, max=30)\n    @NotNull\n    private String password;\n\n    public LoginRequest(){}\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/api/LostPasswordRequest.java",
    "content": "package com.porterhead.rest.user.api;\n\nimport javax.validation.constraints.NotNull;\nimport javax.xml.bind.annotation.XmlRootElement;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 26/09/2012\n */\n@XmlRootElement\npublic class LostPasswordRequest {\n\n    @NotNull\n    private String emailAddress;\n\n    public LostPasswordRequest() {}\n\n    public LostPasswordRequest(final String emailAddress) {\n        this.emailAddress = emailAddress;\n    }\n\n    public String getEmailAddress() {\n        return emailAddress;\n    }\n\n    public void setEmailAddress(String emailAddress) {\n        this.emailAddress = emailAddress;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/api/OAuth2Request.java",
    "content": "package com.porterhead.rest.user.api;\n\nimport javax.validation.constraints.NotNull;\nimport javax.xml.bind.annotation.XmlRootElement;\n\n/**\n * User: porter\n * Date: 18/05/2012\n * Time: 09:59\n */\n@XmlRootElement\npublic class OAuth2Request {\n\n    private String accessToken;\n\n    @NotNull\n    public String getAccessToken() {\n        return accessToken;\n    }\n\n    public void setAccessToken(String accessToken) {\n        this.accessToken = accessToken;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/api/PasswordRequest.java",
    "content": "package com.porterhead.rest.user.api;\n\nimport org.hibernate.validator.constraints.Length;\n\nimport javax.validation.constraints.NotNull;\nimport javax.xml.bind.annotation.XmlRootElement;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 28/09/2012\n */\n@XmlRootElement\npublic class PasswordRequest {\n\n    @Length(min=8, max=30)\n    @NotNull\n    private String password;\n\n    public PasswordRequest() {}\n\n    public PasswordRequest(final String password) {\n        this.password = password;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/api/SocialProfile.java",
    "content": "package com.porterhead.rest.user.api;\n\nimport javax.xml.bind.annotation.XmlRootElement;\n\n/**\n * @author: Iain Porter\n */\n@XmlRootElement\npublic class SocialProfile {\n\n    String provider;\n    String providerUserId;\n    String profileUrl;\n    String imageUrl;\n    String displayName;\n\n    public SocialProfile() {}\n\n    public String getProvider() {\n        return provider;\n    }\n\n    public void setProvider(String provider) {\n        this.provider = provider;\n    }\n\n    public String getProviderUserId() {\n        return providerUserId;\n    }\n\n    public void setProviderUserId(String providerUserId) {\n        this.providerUserId = providerUserId;\n    }\n\n    public String getProfileUrl() {\n        return profileUrl;\n    }\n\n    public void setProfileUrl(String profileUrl) {\n        this.profileUrl = profileUrl;\n    }\n\n    public String getImageUrl() {\n        return imageUrl;\n    }\n\n    public void setImageUrl(String imageUrl) {\n        this.imageUrl = imageUrl;\n    }\n\n    public String getDisplayName() {\n        return displayName;\n    }\n\n    public void setDisplayName(String displayName) {\n        this.displayName = displayName;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/api/UpdateUserRequest.java",
    "content": "package com.porterhead.rest.user.api;\n\nimport org.hibernate.validator.constraints.Email;\n\nimport javax.validation.constraints.NotNull;\nimport javax.xml.bind.annotation.XmlRootElement;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 05/10/2012\n */\n@XmlRootElement\npublic class UpdateUserRequest {\n\n    private String firstName;\n    private String lastName;\n\n    @Email\n    @NotNull\n    private String emailAddress;\n\n    public UpdateUserRequest(){}\n\n    public String getFirstName() {\n        return firstName;\n    }\n\n    public void setFirstName(String firstName) {\n        this.firstName = firstName;\n    }\n\n    public String getLastName() {\n        return lastName;\n    }\n\n    public void setLastName(String lastName) {\n        this.lastName = lastName;\n    }\n\n    public String getEmailAddress() {\n        return emailAddress;\n    }\n\n    public void setEmailAddress(String emailAddress) {\n        this.emailAddress = emailAddress;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/domain/AuthorizationToken.java",
    "content": "package com.porterhead.rest.user.domain;\n\nimport org.springframework.data.jpa.domain.AbstractPersistable;\n\nimport javax.persistence.*;\nimport java.util.Date;\nimport java.util.UUID;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter\n * @since 28/12/2012\n */\n@Entity\n@Table(name=\"rest_authorization_token\")\npublic class AuthorizationToken extends AbstractPersistable<Long> {\n\n    private final static Integer DEFAULT_TIME_TO_LIVE_IN_SECONDS = (60 * 60 * 24 * 30); //30 Days\n\n    @Column(length=36)\n    private String token;\n\n    private Date timeCreated;\n\n    private Date expirationDate;\n\n    @JoinColumn(name = \"user_id\")\n    @OneToOne(fetch = FetchType.LAZY)\n    private User user;\n\n    public AuthorizationToken() {}\n\n    public AuthorizationToken(User user) {\n        this(user, DEFAULT_TIME_TO_LIVE_IN_SECONDS);\n    }\n\n    public AuthorizationToken(User user, Integer timeToLiveInSeconds) {\n        this.token = UUID.randomUUID().toString();\n        this.user = user;\n        this.timeCreated = new Date();\n        this.expirationDate = new Date(System.currentTimeMillis() + (timeToLiveInSeconds * 1000L));\n    }\n\n    public boolean hasExpired() {\n        return this.expirationDate != null && this.expirationDate.before(new Date());\n    }\n\n    public String getToken() {\n        return token;\n    }\n\n    public User getUser() {\n        return user;\n    }\n\n    public Date getTimeCreated() {\n        return timeCreated;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/domain/Role.java",
    "content": "package com.porterhead.rest.user.domain;\n\n/**\n * User: porter\n * Date: 03/04/2012\n * Time: 13:17\n */\npublic enum Role {\n\n        authenticated, administrator, anonymous\n    }\n\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/domain/SocialUser.java",
    "content": "package com.porterhead.rest.user.domain;\n\nimport com.porterhead.rest.model.BaseEntity;\n\nimport javax.persistence.*;\n\n/**\n * User: porter\n * Date: 15/05/2012\n * Time: 13:57\n */\n@Entity\n@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {\"userId\", \"providerId\", \"providerUserId\"}),\n        @UniqueConstraint(columnNames = {\"userId\", \"providerId\", \"rank\"})})\npublic class SocialUser extends BaseEntity {\n\n    @ManyToOne(cascade = CascadeType.MERGE, fetch = FetchType.EAGER, optional = false)\n\t@JoinColumn(name = \"userId\", nullable = false, updatable = false)\n    private User user;\n\n    private String providerId;\n\n    private String providerUserId;\n\n    private int rank;\n\n    private String displayName;\n\n    private String profileUrl;\n\n    private String imageUrl;\n\n    @Column(length = 500)\n    private String accessToken;\n\n    private String secret;\n\n    private String refreshToken;\n\n    private Long expireTime;\n\n    public String getProviderId() {\n        return providerId;\n    }\n\n    public void setProviderId(String providerId) {\n        this.providerId = providerId;\n    }\n\n    public String getProviderUserId() {\n        return providerUserId;\n    }\n\n    public void setProviderUserId(String providerUserId) {\n        this.providerUserId = providerUserId;\n    }\n\n    public int getRank() {\n        return rank;\n    }\n\n    public void setRank(int rank) {\n        this.rank = rank;\n    }\n\n    public String getDisplayName() {\n        return displayName;\n    }\n\n    public void setDisplayName(String displayName) {\n        this.displayName = displayName;\n    }\n\n    public String getProfileUrl() {\n        return profileUrl;\n    }\n\n    public void setProfileUrl(String profileUrl) {\n        this.profileUrl = profileUrl;\n    }\n\n    public String getImageUrl() {\n        return imageUrl;\n    }\n\n    public void setImageUrl(String imageUrl) {\n        this.imageUrl = imageUrl;\n    }\n\n    public String getAccessToken() {\n        return accessToken;\n    }\n\n    public void setAccessToken(String accessToken) {\n        this.accessToken = accessToken;\n    }\n\n    public String getSecret() {\n        return secret;\n    }\n\n    public void setSecret(String secret) {\n        this.secret = secret;\n    }\n\n    public String getRefreshToken() {\n        return refreshToken;\n    }\n\n    public void setRefreshToken(String refreshToken) {\n        this.refreshToken = refreshToken;\n    }\n\n    public Long getExpireTime() {\n        return expireTime;\n    }\n\n    public void setExpireTime(Long expireTime) {\n        this.expireTime = expireTime;\n    }\n\n\tpublic User getUser() {\n\t\treturn user;\n\t}\n\n\tpublic void setUser(User user) {\n\t\tthis.user = user;\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/domain/SocialUserBuilder.java",
    "content": "package com.porterhead.rest.user.domain;\n\n/**\n * User: porter\n * Date: 21/05/2012\n * Time: 08:12\n */\n    public class SocialUserBuilder {\n\n        SocialUser user;\n\n        public static SocialUserBuilder create() {\n            return new SocialUserBuilder();\n        }\n\n        public SocialUserBuilder() {\n            user = new SocialUser();\n        }\n\n        public SocialUser build() {\n            return user;\n        }\n\n        public SocialUserBuilder withUser(User user) {\n            this.user.setUser(user);\n            return this;\n        }\n\n        public SocialUserBuilder withProviderId(String id) {\n            this.user.setProviderId(id);\n            return this;\n        }\n\n        public SocialUserBuilder withProviderUserId(String id) {\n            this.user.setProviderUserId(id);\n            return this;\n        }\n\n        public SocialUserBuilder withRank(int rank) {\n            this.user.setRank(rank);\n            return this;\n        }\n\n        public SocialUserBuilder withDisplayName(String name) {\n            this.user.setDisplayName(name);\n            return this;\n        }\n\n        public SocialUserBuilder withProfileUrl(String url) {\n            this.user.setProfileUrl(url);\n            return this;\n        }\n\n        public SocialUserBuilder withImageUrl(String url) {\n            this.user.setImageUrl(url);\n            return this;\n        }\n\n        public SocialUserBuilder withAccessToken(String token) {\n            this.user.setAccessToken(token);\n            return this;\n        }\n\n        public SocialUserBuilder withSecret(String secret) {\n            this.user.setSecret(secret);\n            return this;\n        }\n\n        public SocialUserBuilder withRefreshToken(String token) {\n            this.user.setRefreshToken(token);\n            return this;\n        }\n\n        public SocialUserBuilder withExpireTime(Long time) {\n            this.user.setExpireTime(time);\n            return this;\n        }\n    }\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/domain/User.java",
    "content": "package com.porterhead.rest.user.domain;\n\nimport com.porterhead.rest.model.BaseEntity;\nimport com.porterhead.rest.user.api.ExternalUser;\nimport com.porterhead.rest.util.HashUtil;\nimport org.hibernate.annotations.LazyCollection;\nimport org.hibernate.annotations.LazyCollectionOption;\nimport org.springframework.util.StringUtils;\n\nimport javax.persistence.*;\nimport java.security.MessageDigest;\nimport java.util.*;\n\n\n/**\n* User: porter\n* Date: 09/03/2012\n* Time: 18:56\n*/\n@Entity\n@Table(name=\"rest_user\")\npublic class User extends BaseEntity {\n\n     /**\n     * Add additional salt to password hashing\n     */\n    private static final String HASH_SALT = \"d8a8e885-ecce-42bb-8332-894f20f0d8ed\";\n\n    private static final int HASH_ITERATIONS = 1000;\n\n    private String firstName;\n    private String lastName;\n    private String emailAddress;\n    private String hashedPassword;\n    private boolean isVerified;\n\n    @Enumerated(EnumType.STRING)\n    private Role role;\n\n    @OneToMany(cascade={CascadeType.ALL}, mappedBy=\"user\", fetch=FetchType.EAGER)\n    private Set<SocialUser> socialUsers = new HashSet<SocialUser>();\n\n    @OneToMany(mappedBy=\"user\",\n                 targetEntity=VerificationToken.class,\n                 cascade= CascadeType.ALL)\n    @LazyCollection(LazyCollectionOption.FALSE)\n    private List<VerificationToken> verificationTokens = new ArrayList<VerificationToken>();\n\n    @OneToOne(fetch = FetchType.LAZY,\n            mappedBy = \"user\",\n            cascade = CascadeType.ALL)\n    private AuthorizationToken authorizationToken;\n\n    public User() {\n        this(UUID.randomUUID());\n    }\n\n    public User(UUID uuid) {\n        super(uuid);\n        setRole(Role.anonymous); //all users are anonymous until credentials are proved\n    }\n\n    public User(ExternalUser externalUser) {\n        this();\n        this.firstName = externalUser.getFirstName();\n        this.lastName = externalUser.getLastName();\n        this.emailAddress = externalUser.getEmailAddress();\n    }\n\n    public void setHashedPassword(String hashedPassword) {\n        this.hashedPassword = hashedPassword;\n    }\n\n    public String getHashedPassword() {\n        return this.hashedPassword;\n    }\n\n    public String getFirstName() {\n        return firstName;\n    }\n\n    public void setFirstName(String firstName) {\n        this.firstName = firstName;\n    }\n\n    public String getLastName() {\n        return lastName;\n    }\n\n    public void setLastName(String lastName) {\n        this.lastName = lastName;\n    }\n\n    public String getEmailAddress() {\n        return emailAddress;\n    }\n\n    public void setEmailAddress(String emailAddress) {\n        this.emailAddress = emailAddress;\n    }\n\n    public Role getRole() {\n        return role;\n    }\n\n    public void setRole(Role role) {\n        this.role = role;\n    }\n\n    public boolean hasRole(Role role) {\n        return role.equals(this.role);\n    }\n\n\n    public boolean equals(Object otherUser) {\n        boolean response = false;\n\n        if(otherUser == null) {\n            response = false;\n        }\n        else if(! (otherUser instanceof User)) {\n            response = false;\n        }\n        else {\n            if(((User)otherUser).getUuid().equals(this.getUuid())) {\n                response = true;\n            }\n        }\n\n        return response;\n    }\n\n    public int hashCode() {\n        return getUuid().hashCode();\n    }\n\n    public String getName() {\n        if(StringUtils.hasText(getFirstName())) {\n           return getFirstName() + \" \" + getLastName();\n        }\n        return \"\";\n    }\n\n\tpublic Set<SocialUser> getSocialUsers() {\n\t\treturn socialUsers;\n\t}\n\n\n\tpublic void setSocialUsers(Set<SocialUser> socialUsers) {\n\t\tthis.socialUsers = socialUsers;\n\t}\n\n    public void addSocialUser(SocialUser socialUser) {\n        getSocialUsers().add(socialUser);\n    }\n\n    public synchronized void addVerificationToken(VerificationToken token) {\n        verificationTokens.add(token);\n    }\n\n    public synchronized List<VerificationToken> getVerificationTokens() {\n        return Collections.unmodifiableList(this.verificationTokens);\n    }\n\n    public synchronized void setAuthorizationToken(AuthorizationToken token) {\n\n\n        this.authorizationToken = token;\n    }\n\n    public synchronized AuthorizationToken getAuthorizationToken() {\n        return authorizationToken;\n    }\n\n    /**\n     * If the user has a VerificationToken of type VerificationTokenType.lostPassword\n     * that is active return it otherwise return null\n     *\n     * @return verificationToken\n     */\n    public VerificationToken getActiveLostPasswordToken() {\n        return getActiveToken(VerificationToken.VerificationTokenType.lostPassword);\n    }\n\n    /**\n     * If the user has a VerificationToken of type VerificationTokenType.emailVerification\n     * that is active return it otherwise return null\n     *\n     * @return verificationToken\n     */\n    public VerificationToken getActiveEmailVerificationToken() {\n        return getActiveToken(VerificationToken.VerificationTokenType.emailVerification);\n    }\n\n    /**\n     * If the user has a VerificationToken of type VerificationTokenType.emailRegistration\n     * that is active return it otherwise return null\n     *\n     * @return verificationToken\n     */\n    public VerificationToken getActiveEmailRegistrationToken() {\n        return getActiveToken(VerificationToken.VerificationTokenType.emailRegistration);\n    }\n\n    private VerificationToken getActiveToken(VerificationToken.VerificationTokenType tokenType) {\n         VerificationToken activeToken = null;\n        for (VerificationToken token : getVerificationTokens()) {\n            if (token.getTokenType().equals(tokenType)\n                    && !token.hasExpired() && !token.isVerified()) {\n                activeToken = token;\n                break;\n            }\n        }\n        return activeToken;\n    }\n\n    public boolean isVerified() {\n        return isVerified;\n    }\n\n    public void setVerified(boolean verified) {\n        isVerified = verified;\n    }\n\n    /**\n     * Hash the password using salt values\n     * See https://www.owasp.org/index.php/Hashing_Java\n     *\n     * @param passwordToHash\n     * @return hashed password\n     */\n    public String hashPassword(String passwordToHash) throws Exception {\n        return hashToken(passwordToHash, getUuid().toString() + HASH_SALT );\n    }\n\n\n    private String hashToken(String token, String salt) throws Exception {\n        return HashUtil.byteToBase64(getHash(HASH_ITERATIONS, token, salt.getBytes()));\n    }\n\n    public byte[] getHash(int numberOfIterations, String password, byte[] salt) throws Exception {\n       MessageDigest digest = MessageDigest.getInstance(\"SHA-256\");\n       digest.reset();\n       digest.update(salt);\n       byte[] input = digest.digest(password.getBytes(\"UTF-8\"));\n       for (int i = 0; i < numberOfIterations; i++) {\n           digest.reset();\n           input = digest.digest(input);\n       }\n       return input;\n   }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/domain/VerificationToken.java",
    "content": "package com.porterhead.rest.user.domain;\n\nimport com.porterhead.rest.model.BaseEntity;\nimport org.joda.time.DateTime;\n\nimport javax.persistence.*;\nimport java.util.Date;\nimport java.util.UUID;\n\n/**\n * A token that gives the user permission to carry out a specific task once within a determined time period.\n * An example would be a Lost Password token. The user receives the token embedded in a link.\n * They send the token back to the server by clicking the link and the action is processed\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 10/09/2012\n */\n@Entity\n@Table(name = \"rest_verification_token\")\npublic class VerificationToken extends BaseEntity {\n\n    private static final int DEFAULT_EXPIRY_TIME_IN_MINS = 60 * 24; //24 hours\n\n    @Column(length=36)\n    private final String token;\n\n    private Date expiryDate;\n\n    @Enumerated(EnumType.STRING)\n    private VerificationTokenType tokenType;\n\n    private boolean verified;\n\n    @ManyToOne\n    @JoinColumn(name = \"user_id\")\n    User user;\n\n    public VerificationToken() {\n        super();\n        this.token = UUID.randomUUID().toString();\n        this.expiryDate = calculateExpiryDate(DEFAULT_EXPIRY_TIME_IN_MINS);\n    }\n\n    public VerificationToken(User user, VerificationTokenType tokenType, int expirationTimeInMinutes) {\n        this();\n        this.user = user;\n        this.tokenType = tokenType;\n        this.expiryDate = calculateExpiryDate(expirationTimeInMinutes);\n    }\n\n    public VerificationTokenType getTokenType() {\n        return tokenType;\n    }\n\n    public boolean isVerified() {\n        return verified;\n    }\n\n    public void setVerified(boolean verified) {\n        this.verified = verified;\n    }\n\n    public User getUser() {\n        return user;\n    }\n\n    public void setUser(User user) {\n        this.user = user;\n    }\n\n    public Date getExpiryDate() {\n        return expiryDate;\n    }\n\n    public String getToken() {\n        return token;\n    }\n\n    private Date calculateExpiryDate(int expiryTimeInMinutes) {\n        DateTime now = new DateTime();\n        return now.plusMinutes(expiryTimeInMinutes).toDate();\n    }\n\n    public enum VerificationTokenType {\n\n        lostPassword, emailVerification, emailRegistration\n    }\n\n    public boolean hasExpired() {\n        DateTime tokenDate = new DateTime(getExpiryDate());\n        return tokenDate.isBeforeNow();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/exception/AlreadyVerifiedException.java",
    "content": "package com.porterhead.rest.user.exception;\n\nimport com.porterhead.rest.exception.BaseWebApplicationException;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 14/09/2012\n */\npublic class AlreadyVerifiedException extends BaseWebApplicationException {\n\n    public AlreadyVerifiedException() {\n        super(409, \"40905\", \"Already verified\", \"The token has already been verified\");\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/exception/AuthenticationException.java",
    "content": "package com.porterhead.rest.user.exception;\n\nimport com.porterhead.rest.exception.BaseWebApplicationException;\n\n/**\n * User: porter\n * Date: 13/03/2012\n * Time: 08:58\n */\npublic class AuthenticationException extends BaseWebApplicationException {\n\n    public AuthenticationException() {\n        super(401, \"40102\", \"Authentication Error\", \"Authentication Error. The username or password were incorrect\");\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/exception/AuthorizationException.java",
    "content": "package com.porterhead.rest.user.exception;\n\n\nimport com.porterhead.rest.exception.BaseWebApplicationException;\n\n/**\n * User: porter\n * Date: 04/04/2012\n * Time: 15:32\n */\npublic class AuthorizationException extends BaseWebApplicationException {\n\n    public AuthorizationException(String applicationMessage) {\n        super(403, \"40301\", \"Not authorized\", applicationMessage);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/exception/DuplicateUserException.java",
    "content": "package com.porterhead.rest.user.exception;\n\nimport com.porterhead.rest.exception.BaseWebApplicationException;\n\n/**\n * User: porter\n * Date: 12/03/2012\n * Time: 15:10\n */\npublic class DuplicateUserException extends BaseWebApplicationException {\n\n    public DuplicateUserException() {\n        super(409, \"40901\", \"User already exists\", \"An attempt was made to create a user that already exists\");\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/exception/TokenHasExpiredException.java",
    "content": "package com.porterhead.rest.user.exception;\n\nimport com.porterhead.rest.exception.BaseWebApplicationException;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 14/09/2012\n */\npublic class TokenHasExpiredException extends BaseWebApplicationException {\n\n    public TokenHasExpiredException() {\n        super(403, \"40304\", \"Token has expired\", \"An attempt was made to load a token that has expired\");\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/exception/TokenNotFoundException.java",
    "content": "package com.porterhead.rest.user.exception;\n\nimport com.porterhead.rest.exception.BaseWebApplicationException;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 14/09/2012\n */\npublic class TokenNotFoundException extends BaseWebApplicationException {\n\n    public TokenNotFoundException() {\n        super(404, \"40407\", \"Token Not Found\", \"No token could be found for that Id\");\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/exception/UserNotFoundException.java",
    "content": "package com.porterhead.rest.user.exception;\n\nimport com.porterhead.rest.exception.BaseWebApplicationException;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 12/09/2012\n */\npublic class UserNotFoundException extends BaseWebApplicationException {\n\n    public UserNotFoundException() {\n        super(404, \"40402\", \"User Not Found\", \"No User could be found for that Id\");\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/mail/MailSenderService.java",
    "content": "package com.porterhead.rest.user.mail;\n\nimport com.porterhead.rest.user.EmailServiceTokenModel;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 13/09/2012\n */\npublic interface MailSenderService {\n\n    public EmailServiceTokenModel sendVerificationEmail(EmailServiceTokenModel emailServiceTokenModel);\n\n    public EmailServiceTokenModel sendRegistrationEmail(EmailServiceTokenModel emailServiceTokenModel);\n\n    public EmailServiceTokenModel sendLostPasswordEmail(EmailServiceTokenModel emailServiceTokenModel);\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/mail/MockJavaMailSender.java",
    "content": "package com.porterhead.rest.user.mail;\n\nimport org.springframework.mail.MailException;\nimport org.springframework.mail.SimpleMailMessage;\nimport org.springframework.mail.javamail.JavaMailSender;\nimport org.springframework.mail.javamail.MimeMessagePreparator;\n\nimport javax.mail.Session;\nimport javax.mail.internet.MimeMessage;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\n\n/**\n * @author: Iain Porter\n */\npublic class MockJavaMailSender implements JavaMailSender {\n\n    List<MimeMessage> messages = new ArrayList<MimeMessage>();\n\n    public MimeMessage createMimeMessage() {\n        MimeMessage message = new MimeMessage(Session.getInstance(new Properties()));\n        return message;\n    }\n\n    public MimeMessage createMimeMessage(InputStream contentStream) throws MailException {\n        return null;  //To change body of implemented methods use File | Settings | File Templates.\n    }\n\n    public void send(MimeMessage mimeMessage) throws MailException {\n        //To change body of implemented methods use File | Settings | File Templates.\n    }\n\n    public void send(MimeMessage[] mimeMessages) throws MailException {\n        //To change body of implemented methods use File | Settings | File Templates.\n    }\n\n    public void send(MimeMessagePreparator mimeMessagePreparator) throws MailException {\n                try {\n                    MimeMessage mimeMessage = createMimeMessage();\n\t\t\t\t    mimeMessagePreparator.prepare(mimeMessage);\n                    messages.add(mimeMessage);\n                } catch(Exception e) {\n                    System.out.println(\"Exception while preparing Mail Message\" + e);\n                    throw new RuntimeException(e);\n                }\n\n\n    }\n\n    public void send(MimeMessagePreparator[] mimeMessagePreparators) throws MailException {\n        //To change body of implemented methods use File | Settings | File Templates.\n    }\n\n    public void send(SimpleMailMessage simpleMessage) throws MailException {\n        //To change body of implemented methods use File | Settings | File Templates.\n    }\n\n    public void send(SimpleMailMessage[] simpleMessages) throws MailException {\n        //To change body of implemented methods use File | Settings | File Templates.\n    }\n\n    public List<MimeMessage> getMessages() {\n        return messages;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/mail/impl/MailSenderServiceImpl.java",
    "content": "package com.porterhead.rest.user.mail.impl;\n\nimport com.porterhead.rest.config.ApplicationConfig;\nimport com.porterhead.rest.user.EmailServiceTokenModel;\nimport com.porterhead.rest.user.mail.*;\nimport org.apache.velocity.app.VelocityEngine;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.mail.javamail.JavaMailSender;\nimport org.springframework.mail.javamail.MimeMessageHelper;\nimport org.springframework.mail.javamail.MimeMessagePreparator;\nimport org.springframework.stereotype.Service;\nimport org.springframework.ui.velocity.VelocityEngineUtils;\n\nimport javax.mail.MessagingException;\nimport javax.mail.internet.MimeMessage;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 13/09/2012\n */\n@Service(\"mailSenderService\")\npublic class MailSenderServiceImpl implements MailSenderService {\n\n    private static Logger LOG = LoggerFactory.getLogger(MailSenderServiceImpl.class);\n\n    private final JavaMailSender mailSender;\n    private final VelocityEngine velocityEngine;\n    private ApplicationConfig config;\n\n    @Autowired\n    public MailSenderServiceImpl(JavaMailSender mailSender, VelocityEngine velocityEngine) {\n        this.mailSender = mailSender;\n        this.velocityEngine = velocityEngine;\n    }\n\n\n    public EmailServiceTokenModel sendVerificationEmail(final EmailServiceTokenModel emailVerificationModel) {\n        Map<String, String> resources = new HashMap<String, String>();\n          return sendVerificationEmail(emailVerificationModel, config.getEmailVerificationSubjectText(),\n                  \"META-INF/velocity/VerifyEmail.vm\", resources);\n    }\n\n    public EmailServiceTokenModel sendRegistrationEmail(final EmailServiceTokenModel emailVerificationModel) {\n        Map<String, String> resources = new HashMap<String, String>();\n          return sendVerificationEmail(emailVerificationModel, config.getEmailRegistrationSubjectText(),\n                  \"META-INF/velocity/RegistrationEmail.vm\", resources);\n    }\n\n    public EmailServiceTokenModel sendLostPasswordEmail(final EmailServiceTokenModel emailServiceTokenModel) {\n        Map<String, String> resources = new HashMap<String, String>();\n         return sendVerificationEmail(emailServiceTokenModel, config.getLostPasswordSubjectText(),\n                 \"META-INF/velocity/LostPasswordEmail.vm\", resources);\n    }\n\n\n    private void addInlineResource(MimeMessageHelper messageHelper, String resourcePath, String resourceIdentifier) throws MessagingException {\n        Resource resource = new ClassPathResource(resourcePath);\n        messageHelper.addInline(resourceIdentifier, resource);\n    }\n\n    private EmailServiceTokenModel sendVerificationEmail(final EmailServiceTokenModel emailVerificationModel, final String emailSubject,\n                                                         final String velocityModel, final Map<String, String> resources) {\n        MimeMessagePreparator preparator = new MimeMessagePreparator() {\n            public void prepare(MimeMessage mimeMessage) throws Exception {\n                MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, MimeMessageHelper.MULTIPART_MODE_RELATED, \"UTF-8\");\n                messageHelper.setTo(emailVerificationModel.getEmailAddress());\n                messageHelper.setFrom(config.getEmailFromAddress());\n                messageHelper.setReplyTo(config.getEmailReplyToAddress());\n                messageHelper.setSubject(emailSubject);\n                Map model = new HashMap();\n                model.put(\"model\", emailVerificationModel);\n                String text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, velocityModel, model);\n                messageHelper.setText(new String(text.getBytes(), \"UTF-8\"), true);\n                      for(String resourceIdentifier: resources.keySet()) {\n                   addInlineResource(messageHelper, resources.get(resourceIdentifier), resourceIdentifier);\n                }\n            }\n        };\n        LOG.debug(\"Sending {} token to : {}\",emailVerificationModel.getTokenType().toString(), emailVerificationModel.getEmailAddress());\n        this.mailSender.send(preparator);\n        return emailVerificationModel;\n    }\n\n    @Autowired\n    public void setConfig(ApplicationConfig config) {\n        this.config = config;\n    }\n\n    public ApplicationConfig getConfig() {\n        return this.config;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/resource/PasswordResource.java",
    "content": "package com.porterhead.rest.user.resource;\n\nimport com.porterhead.rest.user.VerificationTokenService;\nimport com.porterhead.rest.user.api.LostPasswordRequest;\nimport com.porterhead.rest.user.api.PasswordRequest;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.security.PermitAll;\nimport javax.ws.rs.*;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.Response;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 28/09/2012\n */\n@Path(\"password\")\n@Component\n@Produces({MediaType.APPLICATION_JSON})\n@Consumes({MediaType.APPLICATION_JSON})\npublic class PasswordResource {\n\n    @Autowired\n    protected VerificationTokenService verificationTokenService;\n\n    @PermitAll\n    @Path(\"tokens\")\n    @POST\n    public Response sendEmailToken(LostPasswordRequest request) {\n        verificationTokenService.sendLostPasswordToken(request);\n        return Response.ok().build();\n    }\n\n    @PermitAll\n    @Path(\"tokens/{token}\")\n    @POST\n    public Response resetPassword(@PathParam(\"token\") String base64EncodedToken, PasswordRequest request) {\n        verificationTokenService.resetPassword(base64EncodedToken, request);\n        return Response.ok().build();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/resource/UserResource.java",
    "content": "package com.porterhead.rest.user.resource;\n\nimport com.porterhead.rest.config.ApplicationConfig;\nimport com.porterhead.rest.gateway.EmailServicesGateway;\nimport com.porterhead.rest.user.UserService;\nimport com.porterhead.rest.user.VerificationTokenService;\nimport com.porterhead.rest.user.api.*;\nimport com.porterhead.rest.user.domain.Role;\nimport com.porterhead.rest.user.exception.AuthorizationException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.social.connect.Connection;\nimport org.springframework.social.connect.ConnectionFactoryLocator;\nimport org.springframework.social.connect.support.OAuth2ConnectionFactory;\nimport org.springframework.social.oauth2.AccessGrant;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.StringUtils;\n\nimport javax.annotation.security.PermitAll;\nimport javax.annotation.security.RolesAllowed;\nimport javax.ws.rs.*;\nimport javax.ws.rs.core.*;\nimport java.net.URI;\n\n/**\n * User: porter\n * Date: 12/03/2012\n * Time: 18:57\n */\n@Path(\"/user\")\n@Component\n@Produces({MediaType.APPLICATION_JSON})\n@Consumes({MediaType.APPLICATION_JSON})\npublic class UserResource {\n\n    private ConnectionFactoryLocator connectionFactoryLocator;\n\n    @Autowired\n    protected UserService userService;\n\n    @Autowired\n    protected VerificationTokenService verificationTokenService;\n\n    @Autowired\n    protected EmailServicesGateway emailServicesGateway;\n\n    @Context\n    protected UriInfo uriInfo;\n\n    @Autowired\n    ApplicationConfig config;\n\n    @Autowired\n    public UserResource(ConnectionFactoryLocator connectionFactoryLocator) {\n        this.connectionFactoryLocator = connectionFactoryLocator;\n    }\n\n\n    @PermitAll\n    @POST\n    public Response signupUser(CreateUserRequest request) {\n        AuthenticatedUserToken token = userService.createUser(request, Role.authenticated);\n        verificationTokenService.sendEmailRegistrationToken(token.getUserId());\n        URI location = uriInfo.getAbsolutePathBuilder().path(token.getUserId()).build();\n        return Response.created(location).entity(token).build();\n    }\n\n    @RolesAllowed(\"admin\")\n    @Path(\"{userId}\")\n    @DELETE\n    public Response deleteUser(@Context SecurityContext sc, @PathParam(\"userId\") String userId) {\n        ExternalUser userMakingRequest = (ExternalUser)sc.getUserPrincipal();\n        userService.deleteUser(userMakingRequest, userId);\n        return Response.ok().build();\n    }\n\n    @PermitAll\n    @Path(\"login\")\n    @POST\n    public Response login(LoginRequest request) {\n        AuthenticatedUserToken token = userService.login(request);\n        return getLoginResponse(token);\n    }\n\n    @PermitAll\n    @Path(\"login/{providerId}\")\n    @POST\n    public Response socialLogin(@PathParam(\"providerId\") String providerId, OAuth2Request request) {\n        OAuth2ConnectionFactory<?> connectionFactory = (OAuth2ConnectionFactory<?>) connectionFactoryLocator.getConnectionFactory(providerId);\n        Connection<?> connection = connectionFactory.createConnection(new AccessGrant(request.getAccessToken()));\n        AuthenticatedUserToken token = userService.socialLogin(connection);\n        return getLoginResponse(token);\n    }\n\n    @RolesAllowed({\"authenticated\"})\n    @Path(\"{userId}\")\n    @GET\n    public Response getUser(@Context SecurityContext sc, @PathParam(\"userId\") String userId) {\n        ExternalUser userMakingRequest = (ExternalUser)sc.getUserPrincipal();\n        ExternalUser user =  userService.getUser(userMakingRequest, userId);\n        return Response.ok().entity(user).build();\n    }\n\n    @RolesAllowed({\"authenticated\"})\n    @Path(\"{userId}\")\n    @PUT\n    public Response updateUser(@Context SecurityContext sc, @PathParam(\"userId\") String userId, UpdateUserRequest request) {\n        ExternalUser userMakingRequest = (ExternalUser)sc.getUserPrincipal();\n        if(!userMakingRequest.getId().equals(userId)) {\n            throw new AuthorizationException(\"User not authorized to modify this profile\");\n        }\n        boolean sendVerificationToken = StringUtils.hasLength(request.getEmailAddress()) &&\n                !request.getEmailAddress().equals(userMakingRequest.getEmailAddress());\n        ExternalUser savedUser = userService.saveUser(userId, request);\n        if(sendVerificationToken) {\n            verificationTokenService.sendEmailVerificationToken(savedUser.getId());\n        }\n        return Response.ok().build();\n    }\n\n    private Response getLoginResponse(AuthenticatedUserToken token) {\n        URI location = UriBuilder.fromPath(uriInfo.getBaseUri() + \"user/\" + token.getUserId()).build();\n        return Response.ok().entity(token).contentLocation(location).build();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/resource/VerificationResource.java",
    "content": "package com.porterhead.rest.user.resource;\n\nimport com.porterhead.rest.user.VerificationTokenService;\nimport com.porterhead.rest.user.api.EmailVerificationRequest;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.security.PermitAll;\nimport javax.ws.rs.*;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.Response;\n\n/**\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 14/09/2012\n */\n@Path(\"verify\")\n@Component\n@Produces({MediaType.APPLICATION_JSON})\n@Consumes({MediaType.APPLICATION_JSON})\npublic class VerificationResource  {\n\n    @Autowired\n    protected VerificationTokenService verificationTokenService;\n\n    @PermitAll\n    @Path(\"tokens/{token}\")\n    @POST\n    public Response verifyToken(@PathParam(\"token\") String token) {\n        verificationTokenService.verify(token);\n        return Response.ok().build();\n    }\n\n    @PermitAll\n    @Path(\"tokens\")\n    @POST\n    public Response sendEmailToken(EmailVerificationRequest request) {\n        verificationTokenService.generateEmailVerificationToken(request.getEmailAddress());\n        return Response.ok().build();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/social/JpaConnectionRepository.java",
    "content": "package com.porterhead.rest.user.social;\n\nimport com.porterhead.rest.user.SocialUserRepository;\nimport com.porterhead.rest.user.UserRepository;\nimport com.porterhead.rest.user.domain.SocialUser;\nimport com.porterhead.rest.user.domain.SocialUserBuilder;\nimport com.porterhead.rest.user.domain.User;\nimport org.springframework.dao.DuplicateKeyException;\nimport org.springframework.dao.EmptyResultDataAccessException;\nimport org.springframework.security.crypto.encrypt.TextEncryptor;\nimport org.springframework.social.connect.*;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport java.util.*;\n\n/**\n * User: porter\n * Date: 15/05/2012\n * Time: 16:13\n */\npublic class JpaConnectionRepository implements ConnectionRepository {\n\n    private final SocialUserRepository socialUserRepository;\n    private final UserRepository userRepository;\n    private final User user;\n    private final ConnectionFactoryLocator connectionFactoryLocator;\n\tprivate final TextEncryptor textEncryptor;\n\n    public JpaConnectionRepository(SocialUserRepository socialUserRepository, UserRepository userRepository, User user, ConnectionFactoryLocator locator, TextEncryptor encryptor) {\n        this.socialUserRepository = socialUserRepository;\n        this.userRepository = userRepository;\n        this.user = user;\n        this.connectionFactoryLocator = locator;\n        this.textEncryptor = encryptor;\n    }\n\n\tpublic MultiValueMap<String, Connection<?>> findAllConnections() {\n\t\tList<Connection<?>> resultList = connectionMapper.mapEntities(socialUserRepository.findAllByUser(user));\n\n\t\tMultiValueMap<String, Connection<?>> connections = new LinkedMultiValueMap<String, Connection<?>>();\n\t\tSet<String> registeredProviderIds = connectionFactoryLocator.registeredProviderIds();\n\t\tfor (String registeredProviderId : registeredProviderIds) {\n\t\t\tconnections.put(registeredProviderId, Collections.<Connection<?>>emptyList());\n\t\t}\n\t\tfor (Connection<?> connection : resultList) {\n\t\t\tString providerId = connection.getKey().getProviderId();\n\t\t\tif (connections.get(providerId).size() == 0) {\n\t\t\t\tconnections.put(providerId, new LinkedList<Connection<?>>());\n\t\t\t}\n\t\t\tconnections.add(providerId, connection);\n\t\t}\n\t\treturn connections;\n\t}\n\n\tpublic List<Connection<?>> findConnections(String providerId) {\n\t\treturn connectionMapper.mapEntities(socialUserRepository.findByUserAndProviderId(user, providerId));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <A> List<Connection<A>> findConnections(Class<A> apiType) {\n\t\tList<?> connections = findConnections(getProviderId(apiType));\n\t\treturn (List<Connection<A>>) connections;\n\t}\n\n\tpublic MultiValueMap<String, Connection<?>> findConnectionsToUsers(MultiValueMap<String, String> providerUsers) {\n\t\tif (providerUsers.isEmpty()) {\n\t\t\tthrow new IllegalArgumentException(\"Unable to execute find: no providerUsers provided\");\n\t\t}\n\n\t\tList<Connection<?>> resultList = connectionMapper.mapEntities(socialUserRepository.findByUserAndProviderUserId(user, providerUsers));\n\n\t\tMultiValueMap<String, Connection<?>> connectionsForUsers = new LinkedMultiValueMap<String, Connection<?>>();\n\t\tfor (Connection<?> connection : resultList) {\n\t\t\tString providerId = connection.getKey().getProviderId();\n\t\t\tList<String> userIds = providerUsers.get(providerId);\n\t\t\tList<Connection<?>> connections = connectionsForUsers.get(providerId);\n\t\t\tif (connections == null) {\n\t\t\t\tconnections = new ArrayList<Connection<?>>(userIds.size());\n\t\t\t\tfor (int i = 0; i < userIds.size(); i++) {\n\t\t\t\t\tconnections.add(null);\n\t\t\t\t}\n\t\t\t\tconnectionsForUsers.put(providerId, connections);\n\t\t\t}\n\t\t\tString providerUserId = connection.getKey().getProviderUserId();\n\t\t\tint connectionIndex = userIds.indexOf(providerUserId);\n\t\t\tconnections.set(connectionIndex, connection);\n\t\t}\n\t\treturn connectionsForUsers;\n\t}\n\n\tpublic Connection<?> getConnection(ConnectionKey connectionKey) {\n\t\ttry {\n\t\t\treturn connectionMapper.mapEntity(socialUserRepository.findByUserAndProviderIdAndProviderUserId(user, connectionKey.getProviderId(), connectionKey.getProviderUserId()));\n\t\t} catch (EmptyResultDataAccessException e) {\n\t\t\tthrow new NoSuchConnectionException(connectionKey);\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <A> Connection<A> getConnection(Class<A> apiType, String providerUserId) {\n\t\tString providerId = getProviderId(apiType);\n\t\treturn (Connection<A>) getConnection(new ConnectionKey(providerId, providerUserId));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <A> Connection<A> getPrimaryConnection(Class<A> apiType) {\n\t\tString providerId = getProviderId(apiType);\n\t\tConnection<A> connection = (Connection<A>) findPrimaryConnection(providerId);\n\t\tif (connection == null) {\n\t\t\tthrow new NotConnectedException(providerId);\n\t\t}\n\t\treturn connection;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <A> Connection<A> findPrimaryConnection(Class<A> apiType) {\n\t\tString providerId = getProviderId(apiType);\n\t\treturn (Connection<A>) findPrimaryConnection(providerId);\n\t}\n\n\t@Transactional\n\tpublic void addConnection(Connection<?> connection) {\n\t\ttry {\n\t\t\tConnectionData data = connection.createData();\n             //TODO: currently only support 1 connection per user per provider (rank = 1)\n            int rank = 1;\n            //create a SocialUser and call save\n            SocialUser socialUser = SocialUserBuilder.create().withUser(user).withProviderId(data.getProviderId())\n                    .withProviderUserId(data.getProviderUserId()).withRank(rank).withDisplayName(data.getDisplayName())\n                    .withProfileUrl(data.getProfileUrl()).withImageUrl(data.getImageUrl()).withAccessToken(encrypt(data.getAccessToken()))\n                            .withSecret(encrypt(data.getSecret())).withRefreshToken(encrypt(data.getRefreshToken()))\n                            .withExpireTime(data.getExpireTime()).build();\n\t\t\tsocialUserRepository.save(socialUser);\n\t\t} catch (DuplicateKeyException e) {\n\t\t\tthrow new DuplicateConnectionException(connection.getKey());\n\t\t}\n\t}\n\n\tpublic void updateConnection(Connection<?> connection) {\n\t\tConnectionData data = connection.createData();\n\n\t\tSocialUser socialUser = socialUserRepository.findByUserAndProviderIdAndProviderUserId(user, data.getProviderId(), data.getProviderUserId());\n\t\tif(socialUser != null){\n\t\t\tsocialUser.setDisplayName(data.getDisplayName());\n\t\t\tsocialUser.setProfileUrl(data.getProfileUrl());\n\t\t\tsocialUser.setImageUrl(data.getImageUrl());\n\t\t\tsocialUser.setAccessToken(encrypt(data.getAccessToken()));\n\t\t\tsocialUser.setSecret(encrypt(data.getSecret()));\n\t\t\tsocialUser.setRefreshToken(encrypt(data.getRefreshToken()));\n\t\t\tsocialUser.setExpireTime(data.getExpireTime());\n\n\t\t\tsocialUser = socialUserRepository.save(socialUser);\n\t\t}\n\t}\n\n\tpublic void removeConnections(String providerId) {\n        List<SocialUser> users = socialUserRepository.findByUserAndProviderId(user, providerId);\n\t\tsocialUserRepository.delete(users);\n\t}\n\n\tpublic void removeConnection(ConnectionKey connectionKey) {\n        SocialUser socialUser = socialUserRepository.findByUserAndProviderIdAndProviderUserId(user, connectionKey.getProviderId(), connectionKey.getProviderUserId());\n        socialUserRepository.delete(socialUser);\n\t}\n\n\tprivate Connection<?> findPrimaryConnection(String providerId) {\n\t\tList<Connection<?>> connections = connectionMapper.mapEntities(socialUserRepository.findByUserAndProviderId(user, providerId));\n\t\tif (connections.size() > 0) {\n\t\t\treturn connections.get(0);\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate final ServiceProviderConnectionMapper connectionMapper = new ServiceProviderConnectionMapper();\n\n\tprivate final class ServiceProviderConnectionMapper  {\n\n\t\tpublic List<Connection<?>> mapEntities(List<SocialUser> socialUsers){\n\t\t\tList<Connection<?>> result = new ArrayList<Connection<?>>();\n\t\t\tfor(SocialUser user : socialUsers){\n\t\t\t\tresult.add(mapEntity(user));\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tpublic Connection<?> mapEntity(SocialUser socialUser){\n\t\t\tConnectionData connectionData = mapConnectionData(socialUser);\n\t\t\tConnectionFactory<?> connectionFactory = connectionFactoryLocator.getConnectionFactory(connectionData.getProviderId());\n\t\t\treturn connectionFactory.createConnection(connectionData);\n\t\t}\n\n\t\tprivate ConnectionData mapConnectionData(SocialUser socialUser){\n\t\t\treturn new ConnectionData(socialUser.getProviderId(), socialUser.getProviderUserId(), socialUser.getDisplayName(), socialUser.getProfileUrl(), socialUser.getImageUrl(),\n\t\t\t\t\tdecrypt(socialUser.getAccessToken()), decrypt(socialUser.getSecret()), decrypt(socialUser.getRefreshToken()), expireTime(socialUser.getExpireTime()));\n\t\t}\n\n\t\tprivate String decrypt(String encryptedText) {\n\t\t\treturn encryptedText != null ? textEncryptor.decrypt(encryptedText) : encryptedText;\n\t\t}\n\n\t\tprivate Long expireTime(Long expireTime) {\n\t\t\treturn expireTime == null || expireTime == 0 ? null : expireTime;\n\t\t}\n\n\t}\n\n\tprivate <A> String getProviderId(Class<A> apiType) {\n\t\treturn connectionFactoryLocator.getConnectionFactory(apiType).getProviderId();\n\t}\n\n\tprivate String encrypt(String text) {\n\t\treturn text != null ? textEncryptor.encrypt(text) : text;\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/social/JpaUsersConnectionRepository.java",
    "content": "package com.porterhead.rest.user.social;\n\nimport com.porterhead.rest.user.domain.Role;\nimport com.porterhead.rest.user.domain.SocialUser;\nimport com.porterhead.rest.user.SocialUserRepository;\nimport com.porterhead.rest.user.UserRepository;\nimport com.porterhead.rest.user.UserService;\nimport com.porterhead.rest.user.domain.User;\nimport org.springframework.security.crypto.encrypt.TextEncryptor;\nimport org.springframework.social.connect.*;\nimport org.springframework.util.StringUtils;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * User: porter\n * Date: 15/05/2012\n * Time: 15:01\n */\npublic class JpaUsersConnectionRepository implements UsersConnectionRepository {\n\n\tprivate SocialUserRepository socialUserRepository;\n\n    private UserService userService;\n\n    private UserRepository userRepository;\n\n\tprivate final ConnectionFactoryLocator connectionFactoryLocator;\n\n\tprivate final TextEncryptor textEncryptor;\n\n\tpublic JpaUsersConnectionRepository(final SocialUserRepository repository, final UserRepository userRepository,\n                                        final ConnectionFactoryLocator connectionFactoryLocator,\n                                        final TextEncryptor textEncryptor) {\n\t\tthis.socialUserRepository = repository;\n        this.userRepository = userRepository;\n\t\tthis.connectionFactoryLocator = connectionFactoryLocator;\n\t\tthis.textEncryptor = textEncryptor;\n\t}\n\n    /**\n     * Find User with the Connection profile (providerId and providerUserId)\n     * If this is the first connection attempt there will be nor User so create one and\n     * persist the Connection information\n     * In reality there will only be one User associated with the Connection\n     *\n     * @param connection\n     * @return List of User Ids (see User.getUuid())\n     */\n\tpublic List<String> findUserIdsWithConnection(Connection<?> connection) {\n        List<String> userIds = new ArrayList<String>();\n        ConnectionKey key = connection.getKey();\n        List<SocialUser> users = socialUserRepository.findByProviderIdAndProviderUserId(key.getProviderId(), key.getProviderUserId());\n        if (!users.isEmpty()) {\n            for (SocialUser user : users) {\n                userIds.add(user.getUser().getUuid().toString());\n            }\n            return userIds;\n        }\n        //First time connected so create a User account or find one that is already created with the email address\n        User user = findUserFromSocialProfile(connection);\n        String userId;\n        if(user == null) {\n          userId = userService.createUser(Role.authenticated).getUserId();\n        } else {\n           userId = user.getUuid().toString();\n        }\n        //persist the Connection\n        createConnectionRepository(userId).addConnection(connection);\n        userIds.add(userId);\n\n        return userIds;\n\t}\n\n\tpublic Set<String> findUserIdsConnectedTo(String providerId, Set<String> providerUserIds) {\n\t\treturn socialUserRepository.findByProviderIdAndProviderUserId(providerId, providerUserIds);\n\t}\n\n\tpublic ConnectionRepository createConnectionRepository(String userId) {\n\t\tif (userId == null) {\n\t\t\tthrow new IllegalArgumentException(\"userId cannot be null\");\n\t\t}\n        User user = userRepository.findByUuid(userId);\n        if(user == null) {\n            throw new IllegalArgumentException(\"User not Found\");\n        }\n\t\treturn new JpaConnectionRepository(socialUserRepository, userRepository, user, connectionFactoryLocator, textEncryptor);\n\t}\n\n    private User findUserFromSocialProfile(Connection connection) {\n        User user = null;\n        UserProfile profile = connection.fetchUserProfile();\n        if(profile != null && StringUtils.hasText(profile.getEmail())) {\n           user = userRepository.findByEmailAddress(profile.getEmail());\n        }\n        return user;\n    }\n\n    public UserService getUserService() {\n        return userService;\n    }\n\n    public void setUserService(UserService userService) {\n        this.userService = userService;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/user/social/SocialConfig.java",
    "content": "package com.porterhead.rest.user.social;\n\nimport com.porterhead.rest.config.ApplicationConfig;\nimport com.porterhead.rest.user.SocialUserRepository;\nimport com.porterhead.rest.user.UserRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.crypto.encrypt.TextEncryptor;\nimport org.springframework.social.connect.ConnectionFactoryLocator;\nimport org.springframework.social.connect.UsersConnectionRepository;\nimport org.springframework.social.connect.support.ConnectionFactoryRegistry;\nimport org.springframework.social.facebook.connect.FacebookConnectionFactory;\n\n/**\n * User: porter\n * Date: 13/03/2012\n * Time: 17:39\n */\n@Configuration\npublic class SocialConfig {\n\n    @Autowired\n    ApplicationConfig config;\n\n    @Autowired\n    SocialUserRepository socialUserRepository;\n\n    @Autowired\n    UserRepository userRepository;\n\n    @Autowired\n    TextEncryptor textEncryptor;\n\n    @Bean\n    public ConnectionFactoryLocator connectionFactoryLocator() {\n        ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();\n        registry.addConnectionFactory(new FacebookConnectionFactory(\n            config.getFacebookClientId(),\n            config.getFacebookClientSecret()));\n        return registry;\n    }\n\n    @Bean\n    public UsersConnectionRepository usersConnectionRepository() {\n        JpaUsersConnectionRepository usersConnectionRepository = new JpaUsersConnectionRepository(socialUserRepository, userRepository,\n                connectionFactoryLocator(), textEncryptor);\n\n        return usersConnectionRepository;\n    }\n}"
  },
  {
    "path": "src/main/java/com/porterhead/rest/util/DateUtil.java",
    "content": "package com.porterhead.rest.util;\n\nimport org.joda.time.DateTime;\nimport org.joda.time.format.DateTimeFormatter;\nimport org.joda.time.format.ISODateTimeFormat;\n\nimport java.util.Date;\n\n/**\n * @author: Iain Porter\n */\npublic class DateUtil {\n\n    private static final DateTimeFormatter ISO8061_FORMATTER = ISODateTimeFormat.dateTimeNoMillis();\n\n    public static Date getDateFromIso8061DateString(String dateString) {\n        return ISO8061_FORMATTER.parseDateTime(dateString).toDate();\n    }\n\n    public static String getCurrentDateAsIso8061String() {\n        DateTime today = new DateTime();\n        return ISO8061_FORMATTER.print(today);\n    }\n\n     public static String getDateDateAsIso8061String(DateTime date) {\n        return ISO8061_FORMATTER.print(date);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/util/HashUtil.java",
    "content": "package com.porterhead.rest.util;\n\nimport org.apache.commons.codec.binary.Base64;\nimport org.apache.commons.codec.digest.DigestUtils;\n\nimport java.io.IOException;\n\n\npublic class HashUtil {\n\n    public static void main(String[] args) {\n        if (args.length < 1) {\n            System.out.println(\"Enter a String to sign\");\n            System.exit(-1);\n        }\n        System.out.println(\"Signed String: \" + signString(args[0]));\n    }\n\n    /**\n     * From a base 64 representation, returns the corresponding byte[]\n     *\n     * @param data String The base64 representation\n     * @return byte[]\n     * @throws java.io.IOException\n     */\n    public static byte[] base64ToByte(String data) throws IOException {\n        return Base64.decodeBase64(data);\n    }\n\n    /**\n     * From a byte[] returns a base 64 representation\n     *\n     * @param data byte[]\n     * @return String\n     * @throws IOException\n     */\n    public static String byteToBase64(byte[] data) {\n        return new String(Base64.encodeBase64(data));\n    }\n\n    private static String signString(String request) {\n        byte[] digest = DigestUtils.sha256(request);\n        return new String(Base64.encodeBase64(digest));\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/porterhead/rest/util/StringUtil.java",
    "content": "package com.porterhead.rest.util;\n\nimport org.springframework.util.StringUtils;\n\nimport java.util.regex.Pattern;\n\nimport static org.springframework.util.Assert.hasText;\n\n/**\n * Author: Iain porter\n */\npublic class StringUtil {\n\n    private static final Pattern UUID_PATTERN = Pattern.compile(\"^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$\");\n\n\tpublic static void minLength(String str, int len) throws IllegalArgumentException {\n\t\thasText(str);\n\t\tif (str.length() < len) {\n\t\t\tthrow new IllegalArgumentException();\n\t\t}\n\t}\n\n\tpublic static void maxLength(String str, int len) throws IllegalArgumentException {\n\t\thasText(str);\n\t\tif (str.length() > len) {\n\t\t\tthrow new IllegalArgumentException();\n\t\t}\n\t}\n\n\tpublic static void validEmail(String email) throws IllegalArgumentException {\n\t\tminLength(email, 4);\n        maxLength(email, 255);\n\t\tif (!email.contains(\"@\") || StringUtils.containsWhitespace(email)) {\n\t\t\tthrow new IllegalArgumentException();\n\t\t}\n\t}\n\n    public static boolean isValidUuid(String uuid) {\n        return UUID_PATTERN.matcher(uuid).matches();\n    }\n\n}\n"
  },
  {
    "path": "src/main/resources/META-INF/persistence.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n\n<persistence xmlns=\"http://java.sun.com/xml/ns/persistence\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"2.0\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd\">\n\n<persistence-unit name=\"samplePersistenceUnit\" transaction-type=\"RESOURCE_LOCAL\">\n       <provider>org.hibernate.ejb.HibernatePersistence</provider>\n        <class>com.porterhead.rest.user.domain.User</class>\n        <class>com.porterhead.rest.user.domain.SocialUser</class>\n        <class>com.porterhead.rest.user.domain.AuthorizationToken</class>\n        <class>com.porterhead.rest.user.domain.VerificationToken</class>\n       <properties>\n           <!-- value=\"create\" to build a new database on each run; value=\"update\" to modify an existing database; value=\"create-drop\" means the same as \"create\" but also drops tables when Hibernate closes; value=\"validate\" makes no changes to the database -->\n           <property name=\"hibernate.ejb.naming_strategy\" value=\"org.hibernate.cfg.ImprovedNamingStrategy\"/>\n           <property name=\"hibernate.connection.charSet\" value=\"UTF-8\"/>\n           <!--<property name=\"hbm2ddl.auto\" value=\"validate\"/>-->\n           <property name=\"show_sql\" value=\"true\"/>\n           <property name=\"hibernate.hbm2ddl.auto\" value=\"update\"/>\n           <property name=\"hibernate.dialect\" value=\"org.hibernate.dialect.MySQL5Dialect\"/>\n       </properties>\n\n   </persistence-unit>\n\n</persistence>"
  },
  {
    "path": "src/main/resources/META-INF/spring/component-scan-context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\">\n\n    <context:component-scan base-package=\"com.porterhead.rest.authorization\"/>\n    <context:component-scan base-package=\"com.porterhead.rest.filter\"/>\n    <context:component-scan base-package=\"com.porterhead.rest.config\"/>\n    <context:component-scan base-package=\"com.porterhead.rest.resource\"/>\n    <context:component-scan base-package=\"com.porterhead.rest.user\"/>\n\n</beans>"
  },
  {
    "path": "src/main/resources/META-INF/spring/data-context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:jpa=\"http://www.springframework.org/schema/data/jpa\"\n       xmlns:tx=\"http://www.springframework.org/schema/tx\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n        http://www.springframework.org/schema/beans/spring-beans.xsd\n        http://www.springframework.org/schema/data/jpa\n        http://www.springframework.org/schema/data/jpa/spring-jpa.xsd\n\t    http://www.springframework.org/schema/integration/jdbc\n\t    http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd\n        http://www.springframework.org/schema/tx\n\t    http://www.springframework.org/schema/tx/spring-tx.xsd\">\n\n    <bean id=\"entityManagerFactory\" class=\"org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean\">\n        <property name=\"persistenceUnitName\" value=\"samplePersistenceUnit\"/>\n        <property name=\"persistenceXmlLocation\" value=\"classpath:META-INF/persistence.xml\"/>\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n        <property name=\"jpaVendorAdapter\">\n            <bean class=\"org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter\"/>\n\n        </property>\n\n    </bean>\n\n    <jpa:repositories base-package=\"com.porterhead.rest.user\" />\n\n    <bean class=\"org.springframework.orm.jpa.JpaTransactionManager\"\n          id=\"transactionManager\">\n        <property name=\"entityManagerFactory\" ref=\"entityManagerFactory\"/>\n        <property name=\"jpaDialect\">\n            <bean class=\"org.springframework.orm.jpa.vendor.HibernateJpaDialect\"/>\n        </property>\n    </bean>\n\n    <tx:annotation-driven/>\n\n    <bean id=\"dataSource\" class=\"org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy\">\n        <constructor-arg ref=\"database\"/>\n    </bean>\n\n    <beans profile=\"dev\">\n\n        <bean id=\"database\" class=\"org.apache.commons.dbcp.BasicDataSource\" destroy-method=\"close\">\n            <property name=\"driverClassName\" value=\"org.h2.Driver\"/>\n            <property name=\"url\" value=\"jdbc:h2:mem:restDB\"/>\n            <property name=\"username\" value=\"sa\"/>\n            <property name=\"password\" value=\"\"/>\n        </bean>\n\n    </beans>\n\n    <beans profile=\"local\">\n\n        <bean id=\"database\" class=\"org.apache.commons.dbcp.BasicDataSource\" destroy-method=\"close\">\n            <property name=\"driverClassName\" value=\"com.mysql.jdbc.Driver\"/>\n            <property name=\"url\" value=\"jdbc:mysql://localhost:3306/javarest\"/>\n            <property name=\"username\" value=\"root\"/>\n            <property name=\"password\" value=\"\"/>\n            <property name=\"initialSize\" value=\"10\"/>\n            <property name=\"maxActive\" value=\"100\"/>\n            <property name=\"maxIdle\" value=\"50\"/>\n            <property name=\"minIdle\" value=\"10\"/>\n            <property name=\"timeBetweenEvictionRunsMillis\" value=\"30000\"/>\n            <property name=\"minEvictableIdleTimeMillis\" value=\"6000\"/>\n        </bean>\n\n\n    </beans>\n\n<beans profile=\"staging\">\n\n        <!-- staging database-->\n\n\n    </beans>\n\n    <beans profile=\"production\">\n\n        <!-- production database -->\n\n\n    </beans>\n\n\n</beans>"
  },
  {
    "path": "src/main/resources/META-INF/spring/email-services-context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:int=\"http://www.springframework.org/schema/integration\"\n       xmlns:int-jdbc=\"http://www.springframework.org/schema/integration/jdbc\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/integration\n\t    http://www.springframework.org/schema/integration/spring-integration.xsd\n\t    http://www.springframework.org/schema/integration/jdbc\n\t    http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd\n\t\thttp://www.springframework.org/schema/beans\n\t\thttp://www.springframework.org/schema/beans/spring-beans.xsd\">\n\n\n    <int:gateway id=\"emailServicesGateway\" service-interface=\"com.porterhead.rest.gateway.EmailServicesGateway\"\n                 default-reply-timeout=\"3000\">\n        <int:method name=\"sendVerificationToken\" request-channel=\"emailVerificationRouterChannel\"\n                    request-timeout=\"3000\"/>\n    </int:gateway>\n\n    <int:channel id=\"emailVerificationRouterChannel\">\n        <int:queue capacity=\"1000\" message-store=\"emailVerificationMessageStore\"/>\n    </int:channel>\n\n    <int:router id=\"emailVerificationRouter\" input-channel=\"emailVerificationRouterChannel\"\n                expression=\"payload.getTokenType()\">\n        <int:poller fixed-rate=\"2000\">\n            <int:transactional/>\n        </int:poller>\n        <int:mapping value=\"emailVerification\" channel=\"emailVerificationTokenSendChannel\"/>\n        <int:mapping value=\"emailRegistration\" channel=\"emailRegistrationTokenSendChannel\"/>\n        <int:mapping value=\"lostPassword\" channel=\"emailLostPasswordTokenSendChannel\"/>\n    </int:router>\n\n    <int:channel id=\"emailRegistrationTokenSendChannel\"/>\n    <int:service-activator id=\"emailVerficationMailSenderService\" input-channel=\"emailVerificationTokenSendChannel\"\n                           output-channel=\"nullChannel\" ref=\"mailSenderService\"\n                           method=\"sendVerificationEmail\">\n    </int:service-activator>\n\n    <int:channel id=\"emailVerificationTokenSendChannel\"/>\n    <int:service-activator id=\"emailRegistrationMailSenderService\" input-channel=\"emailRegistrationTokenSendChannel\"\n                           output-channel=\"nullChannel\" ref=\"mailSenderService\"\n                           method=\"sendRegistrationEmail\">\n    </int:service-activator>\n\n    <int:channel id=\"emailLostPasswordTokenSendChannel\"/>\n    <int:service-activator id=\"emailLostPasswordSenderService\" input-channel=\"emailLostPasswordTokenSendChannel\"\n                           output-channel=\"nullChannel\" ref=\"mailSenderService\"\n                           method=\"sendLostPasswordEmail\">\n    </int:service-activator>\n\n    <int:logging-channel-adapter id=\"emailVerificationLoggingChannel\" level=\"DEBUG\">\n\n    </int:logging-channel-adapter>\n\n\n    <beans profile=\"dev, local\">\n        <bean id=\"emailVerificationMessageStore\" class=\"org.springframework.integration.store.SimpleMessageStore\"/>\n\n    </beans>\n    <beans profile=\"production, staging\">\n\n        <int-jdbc:message-store id=\"emailVerificationMessageStore\" data-source=\"dataSource\" region=\"emailVerification\"/>\n    </beans>\n\n\n</beans>"
  },
  {
    "path": "src/main/resources/META-INF/spring/email-template-context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xsi:schemaLocation=\"\n\t\thttp://www.springframework.org/schema/beans\n\t\thttp://www.springframework.org/schema/beans/spring-beans.xsd\">\n\n     <bean id=\"velocityEngine\" class=\"org.springframework.ui.velocity.VelocityEngineFactoryBean\">\n        <property name=\"velocityProperties\">\n            <value>\n                resource.loader=class\n                class.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader\n            </value>\n        </property>\n    </bean>\n\n    <beans profile=\"production, staging\">\n    <bean id=\"mailSender\" class=\"org.springframework.mail.javamail.JavaMailSenderImpl\">\n      <!-- Email provider here-->\n      <property name=\"host\" value=\"\"/>\n      <property name=\"port\" value=\"\"/>\n      <property name=\"username\" value=\"\"/>\n      <property name=\"password\" value=\"\"/>\n\n        <property name=\"javaMailProperties\">\n          <props>\n           <prop key=\"mail.debug\">false</prop>\n           <prop key=\"mail.smtp.auth\">true</prop>\n           <prop key=\"mail.smtp.starttls.enable\">true</prop>\n          </props>\n        </property>\n   </bean>\n\n   </beans>\n\n\n    <beans profile=\"dev, local\">\n\n      <bean id=\"mailSender\" class=\"com.porterhead.rest.user.mail.MockJavaMailSender\">\n\n   </bean>\n   </beans>\n\n</beans>"
  },
  {
    "path": "src/main/resources/META-INF/spring/root-context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:task=\"http://www.springframework.org/schema/task\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\n       http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd\">\n\n    <import resource=\"component-scan-context.xml\"/>\n    <import resource=\"social-configuration-context.xml\"/>\n    <import resource=\"email-services-context.xml\"/>\n    <import resource=\"data-context.xml\"/>\n    <import resource=\"email-template-context.xml\"/>\n\n    <bean id=\"validatorFactory\" class=\"javax.validation.Validation\" factory-method=\"buildDefaultValidatorFactory\"/>\n    <bean id=\"validator\" factory-bean=\"validatorFactory\" factory-method=\"getValidator\"/>\n\n</beans>"
  },
  {
    "path": "src/main/resources/META-INF/spring/social-configuration-context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\">\n\n    <bean class=\"com.porterhead.rest.user.social.SocialConfig\"/>\n\n</beans>"
  },
  {
    "path": "src/main/resources/META-INF/velocity/LostPasswordEmail.vm",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Sample Rest Application</title>\n  </head>\n  <body style=\"margin: 0px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #333333; background-color: #481267;\">\n    <center>\n    <table style=\"width: 100%; height: 100%; background-color: #481267;\">\n      <tr><td style=\"width: 100%;\">\n\n        <table style=\"background-color: #ffffff; border-radius: 10px; width: 935px;\">\n          <tr>\n            <td style=\"padding-bottom: 20px; padding-top: 10px; padding-left: 10px;\"></td>\n\n            <!-- HEADER MESSAGE -->\n            <td style=\"padding-left: 30px; padding-bottom: 20px; padding-top: 10px;\"><h2>Reset Password</h2></td>\n\n\n            <td style=\"padding-bottom: 20px; padding-top: 10px; padding-left: 10px;\">\n\n            </td>\n          </tr>\n\n          <tr>\n            <td style=\"text-align: center; padding-top: 20px;\" valign=\"top\">\n\n\n            </td>\n            <td colspan=\"2\" style=\"padding-left: 30px; border-left: 2px solid #E7E7E8;\">\n\n              <!-- MESSAGE -->\n\n              <p>A request was submitted to reset the password for your account. Click through on the link below to reset your password within the next 24 hours.</p>\n\n              <p><a href=\"${model.getHostNameUrl()}/reset_password.html?${model.getEncodedToken()}\">Password Reset</a></p>\n\n              <!-- LEGALESE -->\n\n              <div style=\"font-size: 12px;\">\n                <p>Please don't reply to this automatically generated email.</p>\n\n                <p>What is this doing in my mailbox?</p>\n\n                <p>If you did not intend to reset your password, you do not need to click through on the link in this email. If you did not request a link to reset your password, and are concerned that your account is at risk, then please contact us through customer support at http://XXXXXXXXXX.</p>\n\n                <p>Thanks for using the Sample java REST Application!</p>\n              </div>\n            </td>\n          </tr>\n        </table>\n\n      </td></tr>\n    </table>\n    </center>\n  </body>\n</html>"
  },
  {
    "path": "src/main/resources/META-INF/velocity/RegistrationEmail.vm",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Sample Web</title>\n  </head>\n  <body style=\"margin: 0px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #333333; background-color: #F2F2F2;\">\n    <table style=\"width: 100%; background-color: #F2F2F2; height: 100%;\">\n      <tr><td style=\"width: 100%;\">\n\n        <table style=\"background-color: #ffffff; border-radius: 10px; width: 935px;\">\n          <tr>\n\n            <!-- HEADER MESSAGE -->\n            <td style=\"padding-left: 30px; padding-bottom: 20px; padding-top: 10px;\"><h2>Welcome to the java-rest project</h2></td>\n\n          </tr>\n\n          <tr>\n\n            <td style=\"padding-left: 30px; border-left: 2px solid #E7E7E8;\">\n\n              <!-- MESSAGE -->\n\n              <p>Thanks for coming on board to the sample java-rest project. <br/>\n                  Your registration is complete when you <a href=\"${model.getHostNameUrl()}/validate.html?${model.getEncodedToken()}\">click here</a> to validate your email address.</p>\n              <br>\n\n              <br>\n              <br>\n\n              <!-- LEGALESE -->\n\n              <div style=\"font-size: 12px;\">\n                <p>Please don't reply to this automatically generated email.</p>\n\n                <p>What is this doing in my mailbox?</p>\n\n                <p>If you do not wish to sign up for the java-rest project, you do not need to click through on the link above, and we will not contact you again unless you request it. As such, there is no need to unsubscribe.</p>\n\n                <p>Thanks for trying the java-rest project!</p>\n              </div>\n            </td>\n          </tr>\n        </table>\n\n      </td></tr>\n    </table>\n  </body>\n</html>\n"
  },
  {
    "path": "src/main/resources/META-INF/velocity/VerifyEmail.vm",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Verify Your Email</title>\n  </head>\n  <body style=\"margin: 0px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #333333; background-color: #F2F2F2;\">\n    <center>\n    <table style=\"width: 100%; background-color: #F2F2F2; height: 100%;\">\n      <tr><td style=\"width: 100%;\">\n\n        <table style=\"background-color: #ffffff; border-radius: 10px; width: 935px;\">\n          <tr>\n            <td style=\"padding-bottom: 20px; padding-top: 10px; padding-left: 10px;\"></td>\n\n            <!-- HEADER MESSAGE -->\n            <td style=\"padding-left: 30px; padding-bottom: 20px; padding-top: 10px;\"><h2>Email Verification</h2></td>\n\n\n            <td style=\"padding-bottom: 20px; padding-top: 10px; padding-left: 10px;\">\n\n            </td>\n          </tr>\n\n          <tr>\n            <td style=\"text-align: center; padding-top: 20px;\" valign=\"top\">\n\n\n            </td>\n            <td colspan=\"2\" style=\"padding-left: 30px; border-left: 2px solid #E7E7E8;\">\n\n              <!-- MESSAGE -->\n\n             <p>\n\t\t\t\tTo verify your email address for your XXXXXXXXXXX account click through on the link below within the next 48 hours.\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t<a href=\"${model.getHostNameUrl()}/validate.html?${model.getEncodedToken()}\">Verify my Email Address</a>\n\t\t\t</p>\n\t\t\t<p>\n\t\t\tThanks for using XXXXXXXXX!\n\t\t\t</p>\n\n              <!-- LEGALESE -->\n\n              <div style=\"font-size: 12px;\">\n                <p>Please don't reply to this automatically generated email.</p>\n\n                <p>What is this doing in my mailbox?</p>\n\n                <p>If you do not wish to sign up for XXXXXXXXX, you do not need to click through on the link above, and we will not contact you again unless you request it. As such, there is no need to unsubscribe.</p>\n\n                <p>Thanks for trying XXXXXXXXX!</p>\n              </div>\n            </td>\n          </tr>\n        </table>\n\n      </td></tr>\n    </table>\n    </center>\n  </body>\n</html>\n"
  },
  {
    "path": "src/main/resources/logback.xml",
    "content": "<configuration>\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <Pattern>\n                logbak: %d{HH:mm:ss.SSS} %logger{36} - %msg%n\n            </Pattern>\n        </layout>\n    </appender>\n    <logger name=\"com.porterhead.rest\" level=\"DEBUG\"/>\n\n    <root level=\"INFO\">\n        <appender-ref ref=\"STDOUT\"/>\n    </root>\n</configuration>"
  },
  {
    "path": "src/main/resources/properties/app.properties",
    "content": "#The Facebook app credentials for supporting Facebook login\nfacebook.clientId=133718006790561\nfacebook.clientSecret=2f489f0978614f958101b3d6b1776990\n\n#encryption keys to use for encrypt/decrypt functions\nsecurity.encryptPassword=yoursecurepassword!!!\nsecurity.encryptSalt=45ea2b40ef910eef32\n\n#if true all authorized requests will need to be signed and include the appropriate header fields.\n#See com.porterheadead.rest.authorization.impl.RequestSigningAuthorizationService\nsecurity.authorization.requireSignedRequests=true\n\n#How long in seconds before authorizationToken expires\nauthorization.timeToLive.inSeconds=2592000\n\n#How long in minutes to allow the request timestamp to differ from the server time\nsession.date.offset.inMinutes=15\n\n#How long in minutes that the email registration token should remain active\ntoken.emailRegistration.timeToLive.inMinutes=1440\n\n#How long in minutes that the email verification token should remain active\ntoken.emailVerification.timeToLive.inMinutes=1440\n\n#How long in minutes that the lost password token should remain active\ntoken.lostPassword.timeToLive.inMinutes=30\n\n#The address that mail sent to users will see as the from\nemail.services.fromAddress=foo@example.com\n\n#The address that mail sent to users will see as the replyTo\nemail.services.replyTo=foo@example.com\n\n#Email subject text for the various emails sent\nemail.services.emailVerificationSubjectText=[Java-REST sample application] Please verify your email Address\nemail.services.emailRegistrationSubjectText=Welcome to the Java-REST sample application\nemail.services.lostPasswordSubjectText=[Java-REST sample application] Reset Password\n\napplication.version=1.0.0\n"
  },
  {
    "path": "src/main/resources/properties/dev-app.properties",
    "content": "hostNameUrl=http://localhost:8080/java-rest\n"
  },
  {
    "path": "src/main/resources/properties/production-app.properties",
    "content": "hostNameUrl=http://localhost:8080/java-rest\n"
  },
  {
    "path": "src/main/resources/properties/staging-app.properties",
    "content": "hostNameUrl=http://localhost:8080/java-rest\n"
  },
  {
    "path": "src/main/resources/schema/indexes.sql",
    "content": "\nCREATE UNIQUE INDEX user_uuid_IDX ON rest_user ( uuid);\nCREATE INDEX user_email_address_IDX on rest_user (email_address);\nCREATE UNIQUE INDEX verification_token_uuid_IDX ON rest_verification_token (uuid);\nCREATE UNIQUE INDEX verification_token_token_IDX ON rest_verification_token (token);\nCREATE UNIQUE INDEX session_token_last_updated_IDX ON rest_session_token (last_updated);\nCREATE UNIQUE INDEX session_token_token_IDX ON rest_session_token (token);\n"
  },
  {
    "path": "src/main/resources/schema/message_store.sql",
    "content": "CREATE TABLE INT_MESSAGE  (\n\tMESSAGE_ID CHAR(36) NOT NULL PRIMARY KEY,\n\tREGION VARCHAR(100),\n\tCREATED_DATE DATETIME NOT NULL,\n\tMESSAGE_BYTES BLOB\n) ENGINE=InnoDB;\n\nCREATE INDEX INT_MESSAGE_IX1 ON INT_MESSAGE (CREATED_DATE);\n\nCREATE TABLE INT_GROUP_TO_MESSAGE  (\n\tGROUP_KEY CHAR(36) NOT NULL,\n\tMESSAGE_ID CHAR(36) NOT NULL,\n\tconstraint MESSAGE_GROUP_PK primary key (GROUP_KEY, MESSAGE_ID)\n) ENGINE=InnoDB;\n\nCREATE TABLE INT_MESSAGE_GROUP  (\n    GROUP_KEY CHAR(36) NOT NULL PRIMARY KEY,\n\tREGION VARCHAR(100),\n\tMARKED BIGINT,\n\tCOMPLETE BIGINT,\n\tLAST_RELEASED_SEQUENCE BIGINT,\n\tCREATED_DATE DATETIME NOT NULL,\n\tUPDATED_DATE DATETIME DEFAULT NULL\n) ENGINE=InnoDB;\n\nalter table INT_MESSAGE modify MESSAGE_BYTES MEDIUMBLOB;"
  },
  {
    "path": "src/main/resources/schema/truncate_data.sql",
    "content": "-- truncate all data\nTRUNCATE table social_user;\nTRUNCATE table rest_session_token;\nTRUNCATE table rest_verification_token;\nTRUNCATE table rest_user;\n"
  },
  {
    "path": "src/main/webapp/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\r\nClass-Path: \r\n\r\n"
  },
  {
    "path": "src/main/webapp/WEB-INF/spring/appservlet/servlet-context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans:beans\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns:beans=\"http://www.springframework.org/schema/beans\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\">\n\n\t<beans:import resource=\"classpath:META-INF/spring/root-context.xml\" />\n\t\n</beans:beans>\n"
  },
  {
    "path": "src/main/webapp/WEB-INF/web.xml",
    "content": "<web-app id=\"WebApp_ID\" version=\"2.4\"\n\txmlns=\"http://java.sun.com/xml/ns/j2ee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://java.sun.com/xml/ns/j2ee \n\thttp://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd\">\n\t<display-name>Example Java REST Application</display-name>\n\n    <context-param>\n        <param-name>contextConfigLocation</param-name>\n        <param-value>/WEB-INF/spring/appservlet/servlet-context.xml</param-value>\n    </context-param>\n\n    <context-param>\n        <param-name>spring.profiles.default</param-name>\n        <param-value>dev</param-value>\n    </context-param>\n\n\t<listener>\n\t\t<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>\n\t</listener>\n\n\t<filter-mapping>\n\t\t<filter-name>jersey-servlet</filter-name>\n\t\t<url-pattern>/*</url-pattern>\n\t</filter-mapping>\n\n    \t<filter>\n        <filter-name>jersey-servlet</filter-name>\n        <filter-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</filter-class>\n        <init-param>\n            <param-name>com.sun.jersey.config.property.packages</param-name>\n            <param-value>com.porterhead.rest.resource, com.porterhead.rest.user.resource</param-value>\n        </init-param>\n\n        <init-param>\n            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>\n            <param-value>true</param-value>\n        </init-param>\n        <init-param>\n            <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>\n            <param-value>com.porterhead.rest.filter.ResourceFilterFactory</param-value>\n        </init-param>\n        <init-param>\n            <param-name>com.sun.jersey.config.property.JSPTemplatesBasePath</param-name>\n            <param-value>/WEB-INF/jsp</param-value>\n        </init-param>\n        <init-param>\n            <param-name>com.sun.jersey.config.property.WebPageContentRegex</param-name>\n            <param-value>/(.*\\.jsp|.*\\.css|.*\\.png|.*\\.js|.*\\.gif|.*\\.jpg|.*\\.pdf|.*\\.html|(WEB-INF/jsp))</param-value>\n        </init-param>\n\n\t</filter>\n\n\t<filter>\n\t\t<filter-name>CharacterEncodingFilter</filter-name>\n\t\t<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>\n\t\t<init-param>\n\t\t\t<param-name>encoding</param-name>\n\t\t\t<param-value>UTF-8</param-value>\n\t\t</init-param>\n\t</filter>\n\n\t<filter-mapping>\n\t\t<filter-name>CharacterEncodingFilter</filter-name>\n\t\t<url-pattern>/*</url-pattern>\n\n\t</filter-mapping>\n\n    <welcome-file-list>\n       <welcome-file>index.html</welcome-file>\n    </welcome-file-list>\n\n\n</web-app>"
  },
  {
    "path": "src/main/webapp/css/styles.css",
    "content": "/*---------------Site styles------------*/\n\nbody {\n  background-color: #5087A3;\n  color: white;\n  font-family: helvetica;\n  margin: auto;\n  padding: 0;\n  -webkit-font-smoothing: antialiased;\n}\n\n/**** sections *****/\n\n#container {\n  margin: 0 auto;\n  margin-top: 20px;\n  width: 310px;\n  padding: 5px;\n}\n\n#logo{\n  text-align: center;\n  margin-bottom: 40px;\n}\n\n#footer {\n  margin-top: 20px;\n  text-align: center;\n  font-size: 12px;\n}\n\n.section {\n  background-color: #D8E0E0;\n  border-radius: 4px;\n  width: 290px;\n  padding: 10px;\n  color: #333333;\n  margin-bottom: 40px;\n}\n\n.section a {\n  color: #DAFFFF;\n}\n\n/****Components ****/\n\na{\n  color: #fff;\n  cursor: pointer;\n  text-decoration: none;\n}\n\na:hover{\n  color: #fff;\n  text-decoration: underline;\n}\n\na img {\n  border: 0;\n}\n\ninput[type=\"password\"], input[type=\"text\"], input[type=\"email\"] {\n  width: 100%;\n  border-radius: 0px;\n  -webkit-appearance: none;\n  height: 45px;\n  padding: 0px;\n  text-indent: 10px;\n  box-shadow: inset 0px 1px 3px rgba(0,0,0,.5);\n  border: none;\n  margin-bottom: 15px;\n  font-size: 14px;\n}\n\nbutton {\n  font-size: 16px;\n  background-color: #E0F0FF;\n  border: none;\n  box-shadow: 0px 1px 3px rgba(0,0,0,.5);\n  height: 45px;\n  width: 100%;\n  margin-bottom: 15px;\n  color: #fff;\n  font-weight: bold;\n  cursor: pointer;\n  border-radius: 3px;\n  background: -webkit-gradient(linear, left top, left bottom, from(#91c814), to(#74a020));\n  background: -moz-linear-gradient(top,  #91c814,  #74a020);\n}\n\nbutton:active{\n  box-shadow: inset 0px 1px 3px rgba(0,0,0,.5);\n}\n\nbutton:hover{\n  background: -webkit-gradient(linear, left top, left bottom, from(#96d319), to(#79a525));\n  background: -moz-linear-gradient(top,  #96d319,  #79a525);\n}\n\n.small_button {\n  width: 38%;\n}\n\n.medium_button {\n  width: 50%;\n}\n\n.success, .error {\n  font-size: 1.250em;\n  font-weight: bold;\n  text-align: center;\n}\n\n#error_message {\n  background-color: #f22931;\n  border-radius: 0px;\n  padding: 10px;\n  color: #ffffff;\n  display: none;\n  margin-bottom: 15px;\n  box-shadow: 0px 1px 3px rgba(0,0,0,.5);\n}\n\n#success_message {\n  background-color: #77b300;\n  border-radius: 0px;\n  padding: 10px;\n  color: #ffffff;\n  display: none;\n  margin-bottom: 15px;\n  box-shadow: 0px 1px 3px rgba(0,0,0,.5);\n}\ndd {\n  font-size: 12px;\n}\n\n.margin_below {\n  margin-bottom:15px;\n}\n\n/*---------------Nav-----------*/\n\n#nav {\n  margin-bottom: 40px;\n}\n\n.unselected_tab:hover{\n  background: -webkit-gradient(linear, left top, left bottom, from(#96d319), to(#79a525));\n  background: -moz-linear-gradient(top,  #96d319,  #79a525);\n\n}\n\n.selected_tab{\n  background-color: #271036;\n  color: #fff;\n  font-size: 16px;\n  box-shadow: inset 0px 1px 3px rgba(0,0,0,.5);\n}\n\n.unselected_tab:active{\n  box-shadow: inset 0px 1px 3px rgba(0,0,0,.5);\n}\n\n.unselected_tab{\n  color: #fff;\n  background-color: #77b300;\n  font-size: 16px;\n  background: -webkit-gradient(linear, left top, left bottom, from(#91c814), to(#74a020));\n  background: -moz-linear-gradient(top,  #91c814,  #74a020);\n  box-shadow: 0px 1px 3px rgba(0,0,0,.5);\n  cursor: pointer;\n}\n\n\n\n#account_tab{\n  width: 33.3%;\n  height: 45px;\n  line-height: 45px;\n  text-align: center;\n  border-radius: 0px 3px 3px 0px;\n  display:inline-block;\n  font-weight: bold;\n}\n\na#account_tab:hover{\n  text-decoration: none;\n}\n\n/*---------------Index Page------------*/\n\n.fb {\n  background-color: #336299;\n  height: 45px;\n  padding: 0px;\n  width: 100%;\n  margin-bottom: 40px;\n  box-shadow: 0px 1px 3px rgba(0,0,0,.5);\n  line-height: 45px;\n  font-weight: bold;\n  font-size: 1.000em;\n  text-align: center;\n  background-image: url(\"../img/fbline.png\");\n  background-repeat: no-repeat;\n  background-position: 4px center;\n  cursor: pointer;\n  border-radius: 3px;\n  z-index: 30;\n}\n\n.fb:active{\n  box-shadow: inset 0px 1px 3px rgba(0,0,0,.5);\n}\n\n.fb:hover{\n  background-color: #3969a3;\n}\n\n#or{\n  color: #77b300;\n  font-size: 36px;\n  text-align: center;\n  margin-bottom: 40px;\n  border-bottom: 1px solid #77b300;\n  line-height:0.1em;\n  width: 100%;\n}\n\n#or span{\n  padding:0 10px;\n  background-color: #5087A3;\n}\n\n.divider {\n  color: #77b300;\n  margin-top: 40px;\n  margin-bottom: 20px;\n  border-bottom: 1px solid #77b300;\n  width: 100%;\n}\n\n.right_link{\n  font-weight: bold;\n  line-height: 45px;\n  padding-left: 55px;\n}\n\n.padding{\n  padding: 0px 20px;\n}\n\n#forgot{\n  font-size: .750em\n  text-decoration: underline;\n}\n\n#terms_label, #preferences_label {\n  display: inline-block;\n  padding-left: 10px;\n}\n\n#name {\n  color: #333333;\n}\n\n.profilePhoto {\n  box-shadow: 0px 1px 4px rgba(50,50,50,.8);\n  vertical-align: middle;\n}\n\n\n"
  },
  {
    "path": "src/main/webapp/dashboard.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Java Rest sample application</title>\n    <link href=\"css/styles.css\" rel=\"stylesheet\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  </head>\n  <body>\n\n    <div id=\"container\">\n      <!--nav-->\n      <div id=\"main\">\n        Welcome to the Java Rest Sample Application\n\t    </div>\n\n      <!--content-->\n      <div class=\"section\">\n        <h4 id=\"name\"></h4>\n        <div id=\"verified\"></div>\n        <br>\n        <button class=\"small_button\" type=\"submit\" onclick=\"javaRest.user.logout();\">Logout</button>\n\t    </div>\n\n\t    <!--footer-->\n\t    <div id=\"footer\">\n      </div>\n\n    </div>\n\n    <script src=\"js/jquery-1.8.2.min.js\"></script>\n    <script src=\"js/store.js\"></script>\n    <script src=\"js/sha256.js\"></script>\n    <script src=\"js/enc-base64-min.js\"></script>\n    <script src=\"js/javarest.js\"></script>\n    <script src=\"js/cookie.js\"></script>\n    <script src=\"js/user.js\"></script>\n    <script type=\"text/javascript\">\n\n    // Require user to be logged in\n    if (!javaRest.user.is_logged_in())\n      window.location = 'index.html'\n\n    $(document).ready(function () {\n\n\n      javaRest.user.get(function (error) {\n        if (error)\n          return console.log(error)\n        var name = javaRest.user.user.firstName + ' ' + (javaRest.user.user.lastName || '')\n        $('#name').html((name != ' ' ? name : javaRest.user.user.emailAddress))\n\n        // facebook pic\n        if (javaRest.user.user.socialProfiles.length && javaRest.user.user.socialProfiles[0].imageUrl) {\n          var image_url = javaRest.user.user.socialProfiles[0].imageUrl\n          $('#name').prepend('<img class=\"profilePhoto\" src=\"' + image_url + '\">&nbsp;&nbsp;&nbsp;&nbsp;')\n        }\n\n\n        if (javaRest.user.user.verified)\n          $('#verified').html('Email verified')\n        else\n          $('#verified').html('Email unverified <a href=\"request_email.html\" style=\"color: blue;\">Resend verification email.</a>')\n      })\n    })\n    </script>\n  </body>\n</html>"
  },
  {
    "path": "src/main/webapp/forgot_password.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Java REST Sample Application</title>\n    <link href=\"css/styles.css\" rel=\"stylesheet\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  </head>\n  <body>\n\n    <div id=\"container\">\n\n      <!--content-->\n  \t  <input id=\"email\" type=\"email\" placeholder=\"Email\">\n  \t  <div id=\"error_message\"></div>\n\n  \t  <button type=\"submit\" id=\"login_button\" class=\"medium_button\">Reset Password</button>\n\n  \t  <a href=\"index.html\" class=\"right_link\">Login</a>\n\n\t    <!--footer-->\n\t    <div id=\"footer\">\n      </div>\n\n    </div>\n\n    <script src=\"js/jquery-1.8.2.min.js\"></script>\n    <script src=\"js/javarest.js\"></script>\n    <script src=\"js/cookie.js\"></script>\n    <script src=\"js/user.js\"></script>\n    <script type=\"text/javascript\">\n    $(document).ready(function () {\n\n      // Submit form on enter\n      $('input').live('keydown', function (event) {\n        if (event.keyCode === 13)\n          $('#login_button').click()\n      })\n\n      if (javaRest.user.is_logged_in())\n        window.location = 'dashboard.html'\n      $('#login_button').on('click', function () {\n        javaRest.user.send_reset_email($('#email').val(), function (error) {\n          if (!error)\n            window.location = 'index.html'\n          else {\n            console.log(error)\n            $('#error_message').html('Email address not found.').show()\n          }\n        })\n      })\n\n    })\n    </script>\n  </body>\n</html>"
  },
  {
    "path": "src/main/webapp/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Sample Java Rest Application</title>\n    <link href=\"css/styles.css\" rel=\"stylesheet\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  </head>\n  <body>\n\n    <div id=\"container\">\n\n\n      <div id=\"fb-root\"></div>\n\n      <div class=\"fb\" scope=\"email\" data-show-faces=\"false\" data-width=\"300\">Login with Facebook</div>\n\n      <div id=\"or\"><span>Or</span></div>\n\n\n      <input id=\"email\" type=\"email\" placeholder=\"Email\">\n\n\n\t    <input id=\"password\" type=\"password\" placeholder=\"Password\">\n\n\n\t    <div id=\"error_message\"></div>\n\n\n  \t  <button class=\"small_button\" type=\"submit\" id=\"login_button\">Login</button>\n\n\t    <a href=\"signup.html\" class=\"right_link\">Sign Up</a><br>\n\n      <a id=\"forgot\" href=\"forgot_password.html\">Forgot Password</a>\n\n    </div>\n\n\n    <script src=\"js/jquery-1.8.2.min.js\"></script>\n    <script src=\"js/javarest.js\"></script>\n    <script src=\"js/cookie.js\"></script>\n    <script src=\"js/user.js\"></script>\n    <script type=\"text/javascript\">\n\n    $(document).ready(function () {\n\n\n\n        window.fbAsyncInit = function() {\n          FB.init({\n            appId      : '133718006790561', // App ID\n            status     : true, // check login status\n            cookie     : true, // enable cookies to allow the server to access the session\n            xfbml      : true  // parse XFBML\n          });\n\n          $('.fb').on('click', function () {\n\n             FB.login(function(response) {\n               console.log(response)\n                 if (response.authResponse) {\n\n                   javaRest.user.loginSocial(response.authResponse.accessToken, function (error) {\n                     if (error)\n                       console.log(error)\n                      else\n                       window.location = 'dashboard.html'\n                   })\n                   console.log('Welcome!  Fetching your information.... ');\n                   FB.api('/me', function(response) {\n                     console.log('Good to see you, ' + response.name + '.');\n                   });\n                 } else {\n                   console.log('User cancelled login or did not fully authorize.');\n                 }\n               });\n\n          })\n\n        };\n        // Load the SDK Asynchronously\n        (function(d){\n           var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];\n           if (d.getElementById(id)) {return;}\n           js = d.createElement('script'); js.id = id; js.async = true;\n           js.src = \"//connect.facebook.net/en_US/all.js\";\n           ref.parentNode.insertBefore(js, ref);\n         }(document));\n\n\n      // Submit form on enter\n      $('input').live('keydown', function (event) {\n        if (event.keyCode === 13)\n          $('#login_button').click()\n      })\n\n      if (javaRest.user.is_logged_in())\n        window.location = 'dashboard.html'\n      $('#login_button').on('click', function () {\n        javaRest.user.login($('#email').val(), $('#password').val(), function (error) {\n          if (!error)\n            window.location = 'dashboard.html'\n          else {\n            console.log(error)\n            $('#error_message').html('Email and/or password did not match a user account.').show()\n          }\n        })\n      })\n\n    })\n    </script>\n  </body>\n</html>"
  },
  {
    "path": "src/main/webapp/js/bootstrap.js",
    "content": "/* ===================================================\n * bootstrap-transition.js v2.1.1\n * http://twitter.github.com/bootstrap/javascript.html#transitions\n * ===================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================== */\n\n\n!function ($) {\n\n  $(function () {\n\n    \"use strict\"; // jshint ;_;\n\n\n    /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)\n     * ======================================================= */\n\n    $.support.transition = (function () {\n\n      var transitionEnd = (function () {\n\n        var el = document.createElement('bootstrap')\n          , transEndEventNames = {\n               'WebkitTransition' : 'webkitTransitionEnd'\n            ,  'MozTransition'    : 'transitionend'\n            ,  'OTransition'      : 'oTransitionEnd otransitionend'\n            ,  'transition'       : 'transitionend'\n            }\n          , name\n\n        for (name in transEndEventNames){\n          if (el.style[name] !== undefined) {\n            return transEndEventNames[name]\n          }\n        }\n\n      }())\n\n      return transitionEnd && {\n        end: transitionEnd\n      }\n\n    })()\n\n  })\n\n}(window.jQuery);/* ==========================================================\n * bootstrap-alert.js v2.1.1\n * http://twitter.github.com/bootstrap/javascript.html#alerts\n * ==========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================== */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* ALERT CLASS DEFINITION\n  * ====================== */\n\n  var dismiss = '[data-dismiss=\"alert\"]'\n    , Alert = function (el) {\n        $(el).on('click', dismiss, this.close)\n      }\n\n  Alert.prototype.close = function (e) {\n    var $this = $(this)\n      , selector = $this.attr('data-target')\n      , $parent\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') //strip for ie7\n    }\n\n    $parent = $(selector)\n\n    e && e.preventDefault()\n\n    $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())\n\n    $parent.trigger(e = $.Event('close'))\n\n    if (e.isDefaultPrevented()) return\n\n    $parent.removeClass('in')\n\n    function removeElement() {\n      $parent\n        .trigger('closed')\n        .remove()\n    }\n\n    $.support.transition && $parent.hasClass('fade') ?\n      $parent.on($.support.transition.end, removeElement) :\n      removeElement()\n  }\n\n\n /* ALERT PLUGIN DEFINITION\n  * ======================= */\n\n  $.fn.alert = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('alert')\n      if (!data) $this.data('alert', (data = new Alert(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  $.fn.alert.Constructor = Alert\n\n\n /* ALERT DATA-API\n  * ============== */\n\n  $(function () {\n    $('body').on('click.alert.data-api', dismiss, Alert.prototype.close)\n  })\n\n}(window.jQuery);/* ============================================================\n * bootstrap-button.js v2.1.1\n * http://twitter.github.com/bootstrap/javascript.html#buttons\n * ============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================ */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* BUTTON PUBLIC CLASS DEFINITION\n  * ============================== */\n\n  var Button = function (element, options) {\n    this.$element = $(element)\n    this.options = $.extend({}, $.fn.button.defaults, options)\n  }\n\n  Button.prototype.setState = function (state) {\n    var d = 'disabled'\n      , $el = this.$element\n      , data = $el.data()\n      , val = $el.is('input') ? 'val' : 'html'\n\n    state = state + 'Text'\n    data.resetText || $el.data('resetText', $el[val]())\n\n    $el[val](data[state] || this.options[state])\n\n    // push to event loop to allow forms to submit\n    setTimeout(function () {\n      state == 'loadingText' ?\n        $el.addClass(d).attr(d, d) :\n        $el.removeClass(d).removeAttr(d)\n    }, 0)\n  }\n\n  Button.prototype.toggle = function () {\n    var $parent = this.$element.closest('[data-toggle=\"buttons-radio\"]')\n\n    $parent && $parent\n      .find('.active')\n      .removeClass('active')\n\n    this.$element.toggleClass('active')\n  }\n\n\n /* BUTTON PLUGIN DEFINITION\n  * ======================== */\n\n  $.fn.button = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('button')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('button', (data = new Button(this, options)))\n      if (option == 'toggle') data.toggle()\n      else if (option) data.setState(option)\n    })\n  }\n\n  $.fn.button.defaults = {\n    loadingText: 'loading...'\n  }\n\n  $.fn.button.Constructor = Button\n\n\n /* BUTTON DATA-API\n  * =============== */\n\n  $(function () {\n    $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) {\n      var $btn = $(e.target)\n      if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')\n      $btn.button('toggle')\n    })\n  })\n\n}(window.jQuery);/* ==========================================================\n * bootstrap-carousel.js v2.1.1\n * http://twitter.github.com/bootstrap/javascript.html#carousel\n * ==========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================== */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* CAROUSEL CLASS DEFINITION\n  * ========================= */\n\n  var Carousel = function (element, options) {\n    this.$element = $(element)\n    this.options = options\n    this.options.slide && this.slide(this.options.slide)\n    this.options.pause == 'hover' && this.$element\n      .on('mouseenter', $.proxy(this.pause, this))\n      .on('mouseleave', $.proxy(this.cycle, this))\n  }\n\n  Carousel.prototype = {\n\n    cycle: function (e) {\n      if (!e) this.paused = false\n      this.options.interval\n        && !this.paused\n        && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))\n      return this\n    }\n\n  , to: function (pos) {\n      var $active = this.$element.find('.item.active')\n        , children = $active.parent().children()\n        , activePos = children.index($active)\n        , that = this\n\n      if (pos > (children.length - 1) || pos < 0) return\n\n      if (this.sliding) {\n        return this.$element.one('slid', function () {\n          that.to(pos)\n        })\n      }\n\n      if (activePos == pos) {\n        return this.pause().cycle()\n      }\n\n      return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos]))\n    }\n\n  , pause: function (e) {\n      if (!e) this.paused = true\n      if (this.$element.find('.next, .prev').length && $.support.transition.end) {\n        this.$element.trigger($.support.transition.end)\n        this.cycle()\n      }\n      clearInterval(this.interval)\n      this.interval = null\n      return this\n    }\n\n  , next: function () {\n      if (this.sliding) return\n      return this.slide('next')\n    }\n\n  , prev: function () {\n      if (this.sliding) return\n      return this.slide('prev')\n    }\n\n  , slide: function (type, next) {\n      var $active = this.$element.find('.item.active')\n        , $next = next || $active[type]()\n        , isCycling = this.interval\n        , direction = type == 'next' ? 'left' : 'right'\n        , fallback  = type == 'next' ? 'first' : 'last'\n        , that = this\n        , e = $.Event('slide', {\n            relatedTarget: $next[0]\n          })\n\n      this.sliding = true\n\n      isCycling && this.pause()\n\n      $next = $next.length ? $next : this.$element.find('.item')[fallback]()\n\n      if ($next.hasClass('active')) return\n\n      if ($.support.transition && this.$element.hasClass('slide')) {\n        this.$element.trigger(e)\n        if (e.isDefaultPrevented()) return\n        $next.addClass(type)\n        $next[0].offsetWidth // force reflow\n        $active.addClass(direction)\n        $next.addClass(direction)\n        this.$element.one($.support.transition.end, function () {\n          $next.removeClass([type, direction].join(' ')).addClass('active')\n          $active.removeClass(['active', direction].join(' '))\n          that.sliding = false\n          setTimeout(function () { that.$element.trigger('slid') }, 0)\n        })\n      } else {\n        this.$element.trigger(e)\n        if (e.isDefaultPrevented()) return\n        $active.removeClass('active')\n        $next.addClass('active')\n        this.sliding = false\n        this.$element.trigger('slid')\n      }\n\n      isCycling && this.cycle()\n\n      return this\n    }\n\n  }\n\n\n /* CAROUSEL PLUGIN DEFINITION\n  * ========================== */\n\n  $.fn.carousel = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('carousel')\n        , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)\n        , action = typeof option == 'string' ? option : options.slide\n      if (!data) $this.data('carousel', (data = new Carousel(this, options)))\n      if (typeof option == 'number') data.to(option)\n      else if (action) data[action]()\n      else if (options.interval) data.cycle()\n    })\n  }\n\n  $.fn.carousel.defaults = {\n    interval: 5000\n  , pause: 'hover'\n  }\n\n  $.fn.carousel.Constructor = Carousel\n\n\n /* CAROUSEL DATA-API\n  * ================= */\n\n  $(function () {\n    $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) {\n      var $this = $(this), href\n        , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '')) //strip for ie7\n        , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data())\n      $target.carousel(options)\n      e.preventDefault()\n    })\n  })\n\n}(window.jQuery);/* =============================================================\n * bootstrap-collapse.js v2.1.1\n * http://twitter.github.com/bootstrap/javascript.html#collapse\n * =============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================ */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* COLLAPSE PUBLIC CLASS DEFINITION\n  * ================================ */\n\n  var Collapse = function (element, options) {\n    this.$element = $(element)\n    this.options = $.extend({}, $.fn.collapse.defaults, options)\n\n    if (this.options.parent) {\n      this.$parent = $(this.options.parent)\n    }\n\n    this.options.toggle && this.toggle()\n  }\n\n  Collapse.prototype = {\n\n    constructor: Collapse\n\n  , dimension: function () {\n      var hasWidth = this.$element.hasClass('width')\n      return hasWidth ? 'width' : 'height'\n    }\n\n  , show: function () {\n      var dimension\n        , scroll\n        , actives\n        , hasData\n\n      if (this.transitioning) return\n\n      dimension = this.dimension()\n      scroll = $.camelCase(['scroll', dimension].join('-'))\n      actives = this.$parent && this.$parent.find('> .accordion-group > .in')\n\n      if (actives && actives.length) {\n        hasData = actives.data('collapse')\n        if (hasData && hasData.transitioning) return\n        actives.collapse('hide')\n        hasData || actives.data('collapse', null)\n      }\n\n      this.$element[dimension](0)\n      this.transition('addClass', $.Event('show'), 'shown')\n      $.support.transition && this.$element[dimension](this.$element[0][scroll])\n    }\n\n  , hide: function () {\n      var dimension\n      if (this.transitioning) return\n      dimension = this.dimension()\n      this.reset(this.$element[dimension]())\n      this.transition('removeClass', $.Event('hide'), 'hidden')\n      this.$element[dimension](0)\n    }\n\n  , reset: function (size) {\n      var dimension = this.dimension()\n\n      this.$element\n        .removeClass('collapse')\n        [dimension](size || 'auto')\n        [0].offsetWidth\n\n      this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')\n\n      return this\n    }\n\n  , transition: function (method, startEvent, completeEvent) {\n      var that = this\n        , complete = function () {\n            if (startEvent.type == 'show') that.reset()\n            that.transitioning = 0\n            that.$element.trigger(completeEvent)\n          }\n\n      this.$element.trigger(startEvent)\n\n      if (startEvent.isDefaultPrevented()) return\n\n      this.transitioning = 1\n\n      this.$element[method]('in')\n\n      $.support.transition && this.$element.hasClass('collapse') ?\n        this.$element.one($.support.transition.end, complete) :\n        complete()\n    }\n\n  , toggle: function () {\n      this[this.$element.hasClass('in') ? 'hide' : 'show']()\n    }\n\n  }\n\n\n /* COLLAPSIBLE PLUGIN DEFINITION\n  * ============================== */\n\n  $.fn.collapse = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('collapse')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('collapse', (data = new Collapse(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.collapse.defaults = {\n    toggle: true\n  }\n\n  $.fn.collapse.Constructor = Collapse\n\n\n /* COLLAPSIBLE DATA-API\n  * ==================== */\n\n  $(function () {\n    $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function (e) {\n      var $this = $(this), href\n        , target = $this.attr('data-target')\n          || e.preventDefault()\n          || (href = $this.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '') //strip for ie7\n        , option = $(target).data('collapse') ? 'toggle' : $this.data()\n      $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed')\n      $(target).collapse(option)\n    })\n  })\n\n}(window.jQuery);/* ============================================================\n * bootstrap-dropdown.js v2.1.1\n * http://twitter.github.com/bootstrap/javascript.html#dropdowns\n * ============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================ */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* DROPDOWN CLASS DEFINITION\n  * ========================= */\n\n  var toggle = '[data-toggle=dropdown]'\n    , Dropdown = function (element) {\n        var $el = $(element).on('click.dropdown.data-api', this.toggle)\n        $('html').on('click.dropdown.data-api', function () {\n          $el.parent().removeClass('open')\n        })\n      }\n\n  Dropdown.prototype = {\n\n    constructor: Dropdown\n\n  , toggle: function (e) {\n      var $this = $(this)\n        , $parent\n        , isActive\n\n      if ($this.is('.disabled, :disabled')) return\n\n      $parent = getParent($this)\n\n      isActive = $parent.hasClass('open')\n\n      clearMenus()\n\n      if (!isActive) {\n        $parent.toggleClass('open')\n        $this.focus()\n      }\n\n      return false\n    }\n\n  , keydown: function (e) {\n      var $this\n        , $items\n        , $active\n        , $parent\n        , isActive\n        , index\n\n      if (!/(38|40|27)/.test(e.keyCode)) return\n\n      $this = $(this)\n\n      e.preventDefault()\n      e.stopPropagation()\n\n      if ($this.is('.disabled, :disabled')) return\n\n      $parent = getParent($this)\n\n      isActive = $parent.hasClass('open')\n\n      if (!isActive || (isActive && e.keyCode == 27)) return $this.click()\n\n      $items = $('[role=menu] li:not(.divider) a', $parent)\n\n      if (!$items.length) return\n\n      index = $items.index($items.filter(':focus'))\n\n      if (e.keyCode == 38 && index > 0) index--                                        // up\n      if (e.keyCode == 40 && index < $items.length - 1) index++                        // down\n      if (!~index) index = 0\n\n      $items\n        .eq(index)\n        .focus()\n    }\n\n  }\n\n  function clearMenus() {\n    getParent($(toggle))\n      .removeClass('open')\n  }\n\n  function getParent($this) {\n    var selector = $this.attr('data-target')\n      , $parent\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\\s]*$)/, '') //strip for ie7\n    }\n\n    $parent = $(selector)\n    $parent.length || ($parent = $this.parent())\n\n    return $parent\n  }\n\n\n  /* DROPDOWN PLUGIN DEFINITION\n   * ========================== */\n\n  $.fn.dropdown = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('dropdown')\n      if (!data) $this.data('dropdown', (data = new Dropdown(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  $.fn.dropdown.Constructor = Dropdown\n\n\n  /* APPLY TO STANDARD DROPDOWN ELEMENTS\n   * =================================== */\n\n  $(function () {\n    $('html')\n      .on('click.dropdown.data-api touchstart.dropdown.data-api', clearMenus)\n    $('body')\n      .on('click.dropdown touchstart.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })\n      .on('click.dropdown.data-api touchstart.dropdown.data-api'  , toggle, Dropdown.prototype.toggle)\n      .on('keydown.dropdown.data-api touchstart.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)\n  })\n\n}(window.jQuery);/* =========================================================\n * bootstrap-modal.js v2.1.1\n * http://twitter.github.com/bootstrap/javascript.html#modals\n * =========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================= */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* MODAL CLASS DEFINITION\n  * ====================== */\n\n  var Modal = function (element, options) {\n    this.options = options\n    this.$element = $(element)\n      .delegate('[data-dismiss=\"modal\"]', 'click.dismiss.modal', $.proxy(this.hide, this))\n    this.options.remote && this.$element.find('.modal-body').load(this.options.remote)\n  }\n\n  Modal.prototype = {\n\n      constructor: Modal\n\n    , toggle: function () {\n        return this[!this.isShown ? 'show' : 'hide']()\n      }\n\n    , show: function () {\n        var that = this\n          , e = $.Event('show')\n\n        this.$element.trigger(e)\n\n        if (this.isShown || e.isDefaultPrevented()) return\n\n        $('body').addClass('modal-open')\n\n        this.isShown = true\n\n        this.escape()\n\n        this.backdrop(function () {\n          var transition = $.support.transition && that.$element.hasClass('fade')\n\n          if (!that.$element.parent().length) {\n            that.$element.appendTo(document.body) //don't move modals dom position\n          }\n\n          that.$element\n            .show()\n\n          if (transition) {\n            that.$element[0].offsetWidth // force reflow\n          }\n\n          that.$element\n            .addClass('in')\n            .attr('aria-hidden', false)\n            .focus()\n\n          that.enforceFocus()\n\n          transition ?\n            that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :\n            that.$element.trigger('shown')\n\n        })\n      }\n\n    , hide: function (e) {\n        e && e.preventDefault()\n\n        var that = this\n\n        e = $.Event('hide')\n\n        this.$element.trigger(e)\n\n        if (!this.isShown || e.isDefaultPrevented()) return\n\n        this.isShown = false\n\n        $('body').removeClass('modal-open')\n\n        this.escape()\n\n        $(document).off('focusin.modal')\n\n        this.$element\n          .removeClass('in')\n          .attr('aria-hidden', true)\n\n        $.support.transition && this.$element.hasClass('fade') ?\n          this.hideWithTransition() :\n          this.hideModal()\n      }\n\n    , enforceFocus: function () {\n        var that = this\n        $(document).on('focusin.modal', function (e) {\n          if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {\n            that.$element.focus()\n          }\n        })\n      }\n\n    , escape: function () {\n        var that = this\n        if (this.isShown && this.options.keyboard) {\n          this.$element.on('keyup.dismiss.modal', function ( e ) {\n            e.which == 27 && that.hide()\n          })\n        } else if (!this.isShown) {\n          this.$element.off('keyup.dismiss.modal')\n        }\n      }\n\n    , hideWithTransition: function () {\n        var that = this\n          , timeout = setTimeout(function () {\n              that.$element.off($.support.transition.end)\n              that.hideModal()\n            }, 500)\n\n        this.$element.one($.support.transition.end, function () {\n          clearTimeout(timeout)\n          that.hideModal()\n        })\n      }\n\n    , hideModal: function (that) {\n        this.$element\n          .hide()\n          .trigger('hidden')\n\n        this.backdrop()\n      }\n\n    , removeBackdrop: function () {\n        this.$backdrop.remove()\n        this.$backdrop = null\n      }\n\n    , backdrop: function (callback) {\n        var that = this\n          , animate = this.$element.hasClass('fade') ? 'fade' : ''\n\n        if (this.isShown && this.options.backdrop) {\n          var doAnimate = $.support.transition && animate\n\n          this.$backdrop = $('<div class=\"modal-backdrop ' + animate + '\" />')\n            .appendTo(document.body)\n\n          if (this.options.backdrop != 'static') {\n            this.$backdrop.click($.proxy(this.hide, this))\n          }\n\n          if (doAnimate) this.$backdrop[0].offsetWidth // force reflow\n\n          this.$backdrop.addClass('in')\n\n          doAnimate ?\n            this.$backdrop.one($.support.transition.end, callback) :\n            callback()\n\n        } else if (!this.isShown && this.$backdrop) {\n          this.$backdrop.removeClass('in')\n\n          $.support.transition && this.$element.hasClass('fade')?\n            this.$backdrop.one($.support.transition.end, $.proxy(this.removeBackdrop, this)) :\n            this.removeBackdrop()\n\n        } else if (callback) {\n          callback()\n        }\n      }\n  }\n\n\n /* MODAL PLUGIN DEFINITION\n  * ======================= */\n\n  $.fn.modal = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('modal')\n        , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)\n      if (!data) $this.data('modal', (data = new Modal(this, options)))\n      if (typeof option == 'string') data[option]()\n      else if (options.show) data.show()\n    })\n  }\n\n  $.fn.modal.defaults = {\n      backdrop: true\n    , keyboard: true\n    , show: true\n  }\n\n  $.fn.modal.Constructor = Modal\n\n\n /* MODAL DATA-API\n  * ============== */\n\n  $(function () {\n    $('body').on('click.modal.data-api', '[data-toggle=\"modal\"]', function ( e ) {\n      var $this = $(this)\n        , href = $this.attr('href')\n        , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\\s]+$)/, ''))) //strip for ie7\n        , option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())\n\n      e.preventDefault()\n\n      $target\n        .modal(option)\n        .one('hide', function () {\n          $this.focus()\n        })\n    })\n  })\n\n}(window.jQuery);/* ===========================================================\n * bootstrap-tooltip.js v2.1.1\n * http://twitter.github.com/bootstrap/javascript.html#tooltips\n * Inspired by the original jQuery.tipsy by Jason Frame\n * ===========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================== */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* TOOLTIP PUBLIC CLASS DEFINITION\n  * =============================== */\n\n  var Tooltip = function (element, options) {\n    this.init('tooltip', element, options)\n  }\n\n  Tooltip.prototype = {\n\n    constructor: Tooltip\n\n  , init: function (type, element, options) {\n      var eventIn\n        , eventOut\n\n      this.type = type\n      this.$element = $(element)\n      this.options = this.getOptions(options)\n      this.enabled = true\n\n      if (this.options.trigger == 'click') {\n        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))\n      } else if (this.options.trigger != 'manual') {\n        eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'\n        eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'\n        this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))\n        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))\n      }\n\n      this.options.selector ?\n        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :\n        this.fixTitle()\n    }\n\n  , getOptions: function (options) {\n      options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())\n\n      if (options.delay && typeof options.delay == 'number') {\n        options.delay = {\n          show: options.delay\n        , hide: options.delay\n        }\n      }\n\n      return options\n    }\n\n  , enter: function (e) {\n      var self = $(e.currentTarget)[this.type](this._options).data(this.type)\n\n      if (!self.options.delay || !self.options.delay.show) return self.show()\n\n      clearTimeout(this.timeout)\n      self.hoverState = 'in'\n      this.timeout = setTimeout(function() {\n        if (self.hoverState == 'in') self.show()\n      }, self.options.delay.show)\n    }\n\n  , leave: function (e) {\n      var self = $(e.currentTarget)[this.type](this._options).data(this.type)\n\n      if (this.timeout) clearTimeout(this.timeout)\n      if (!self.options.delay || !self.options.delay.hide) return self.hide()\n\n      self.hoverState = 'out'\n      this.timeout = setTimeout(function() {\n        if (self.hoverState == 'out') self.hide()\n      }, self.options.delay.hide)\n    }\n\n  , show: function () {\n      var $tip\n        , inside\n        , pos\n        , actualWidth\n        , actualHeight\n        , placement\n        , tp\n\n      if (this.hasContent() && this.enabled) {\n        $tip = this.tip()\n        this.setContent()\n\n        if (this.options.animation) {\n          $tip.addClass('fade')\n        }\n\n        placement = typeof this.options.placement == 'function' ?\n          this.options.placement.call(this, $tip[0], this.$element[0]) :\n          this.options.placement\n\n        inside = /in/.test(placement)\n\n        $tip\n          .remove()\n          .css({ top: 0, left: 0, display: 'block' })\n          .appendTo(inside ? this.$element : document.body)\n\n        pos = this.getPosition(inside)\n\n        actualWidth = $tip[0].offsetWidth\n        actualHeight = $tip[0].offsetHeight\n\n        switch (inside ? placement.split(' ')[1] : placement) {\n          case 'bottom':\n            tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}\n            break\n          case 'top':\n            tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}\n            break\n          case 'left':\n            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}\n            break\n          case 'right':\n            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}\n            break\n        }\n\n        $tip\n          .css(tp)\n          .addClass(placement)\n          .addClass('in')\n      }\n    }\n\n  , setContent: function () {\n      var $tip = this.tip()\n        , title = this.getTitle()\n\n      $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)\n      $tip.removeClass('fade in top bottom left right')\n    }\n\n  , hide: function () {\n      var that = this\n        , $tip = this.tip()\n\n      $tip.removeClass('in')\n\n      function removeWithAnimation() {\n        var timeout = setTimeout(function () {\n          $tip.off($.support.transition.end).remove()\n        }, 500)\n\n        $tip.one($.support.transition.end, function () {\n          clearTimeout(timeout)\n          $tip.remove()\n        })\n      }\n\n      $.support.transition && this.$tip.hasClass('fade') ?\n        removeWithAnimation() :\n        $tip.remove()\n\n      return this\n    }\n\n  , fixTitle: function () {\n      var $e = this.$element\n      if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {\n        $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')\n      }\n    }\n\n  , hasContent: function () {\n      return this.getTitle()\n    }\n\n  , getPosition: function (inside) {\n      return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {\n        width: this.$element[0].offsetWidth\n      , height: this.$element[0].offsetHeight\n      })\n    }\n\n  , getTitle: function () {\n      var title\n        , $e = this.$element\n        , o = this.options\n\n      title = $e.attr('data-original-title')\n        || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)\n\n      return title\n    }\n\n  , tip: function () {\n      return this.$tip = this.$tip || $(this.options.template)\n    }\n\n  , validate: function () {\n      if (!this.$element[0].parentNode) {\n        this.hide()\n        this.$element = null\n        this.options = null\n      }\n    }\n\n  , enable: function () {\n      this.enabled = true\n    }\n\n  , disable: function () {\n      this.enabled = false\n    }\n\n  , toggleEnabled: function () {\n      this.enabled = !this.enabled\n    }\n\n  , toggle: function () {\n      this[this.tip().hasClass('in') ? 'hide' : 'show']()\n    }\n\n  , destroy: function () {\n      this.hide().$element.off('.' + this.type).removeData(this.type)\n    }\n\n  }\n\n\n /* TOOLTIP PLUGIN DEFINITION\n  * ========================= */\n\n  $.fn.tooltip = function ( option ) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('tooltip')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.tooltip.Constructor = Tooltip\n\n  $.fn.tooltip.defaults = {\n    animation: true\n  , placement: 'top'\n  , selector: false\n  , template: '<div class=\"tooltip\"><div class=\"tooltip-arrow\"></div><div class=\"tooltip-inner\"></div></div>'\n  , trigger: 'hover'\n  , title: ''\n  , delay: 0\n  , html: true\n  }\n\n}(window.jQuery);\n/* ===========================================================\n * bootstrap-popover.js v2.1.1\n * http://twitter.github.com/bootstrap/javascript.html#popovers\n * ===========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * =========================================================== */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* POPOVER PUBLIC CLASS DEFINITION\n  * =============================== */\n\n  var Popover = function (element, options) {\n    this.init('popover', element, options)\n  }\n\n\n  /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js\n     ========================================== */\n\n  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {\n\n    constructor: Popover\n\n  , setContent: function () {\n      var $tip = this.tip()\n        , title = this.getTitle()\n        , content = this.getContent()\n\n      $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)\n      $tip.find('.popover-content > *')[this.options.html ? 'html' : 'text'](content)\n\n      $tip.removeClass('fade top bottom left right in')\n    }\n\n  , hasContent: function () {\n      return this.getTitle() || this.getContent()\n    }\n\n  , getContent: function () {\n      var content\n        , $e = this.$element\n        , o = this.options\n\n      content = $e.attr('data-content')\n        || (typeof o.content == 'function' ? o.content.call($e[0]) :  o.content)\n\n      return content\n    }\n\n  , tip: function () {\n      if (!this.$tip) {\n        this.$tip = $(this.options.template)\n      }\n      return this.$tip\n    }\n\n  , destroy: function () {\n      this.hide().$element.off('.' + this.type).removeData(this.type)\n    }\n\n  })\n\n\n /* POPOVER PLUGIN DEFINITION\n  * ======================= */\n\n  $.fn.popover = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('popover')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('popover', (data = new Popover(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.popover.Constructor = Popover\n\n  $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {\n    placement: 'right'\n  , trigger: 'click'\n  , content: ''\n  , template: '<div class=\"popover\"><div class=\"arrow\"></div><div class=\"popover-inner\"><h3 class=\"popover-title\"></h3><div class=\"popover-content\"><p></p></div></div></div>'\n  })\n\n}(window.jQuery);/* =============================================================\n * bootstrap-scrollspy.js v2.1.1\n * http://twitter.github.com/bootstrap/javascript.html#scrollspy\n * =============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================== */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* SCROLLSPY CLASS DEFINITION\n  * ========================== */\n\n  function ScrollSpy(element, options) {\n    var process = $.proxy(this.process, this)\n      , $element = $(element).is('body') ? $(window) : $(element)\n      , href\n    this.options = $.extend({}, $.fn.scrollspy.defaults, options)\n    this.$scrollElement = $element.on('scroll.scroll-spy.data-api', process)\n    this.selector = (this.options.target\n      || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '')) //strip for ie7\n      || '') + ' .nav li > a'\n    this.$body = $('body')\n    this.refresh()\n    this.process()\n  }\n\n  ScrollSpy.prototype = {\n\n      constructor: ScrollSpy\n\n    , refresh: function () {\n        var self = this\n          , $targets\n\n        this.offsets = $([])\n        this.targets = $([])\n\n        $targets = this.$body\n          .find(this.selector)\n          .map(function () {\n            var $el = $(this)\n              , href = $el.data('target') || $el.attr('href')\n              , $href = /^#\\w/.test(href) && $(href)\n            return ( $href\n              && $href.length\n              && [[ $href.position().top, href ]] ) || null\n          })\n          .sort(function (a, b) { return a[0] - b[0] })\n          .each(function () {\n            self.offsets.push(this[0])\n            self.targets.push(this[1])\n          })\n      }\n\n    , process: function () {\n        var scrollTop = this.$scrollElement.scrollTop() + this.options.offset\n          , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight\n          , maxScroll = scrollHeight - this.$scrollElement.height()\n          , offsets = this.offsets\n          , targets = this.targets\n          , activeTarget = this.activeTarget\n          , i\n\n        if (scrollTop >= maxScroll) {\n          return activeTarget != (i = targets.last()[0])\n            && this.activate ( i )\n        }\n\n        for (i = offsets.length; i--;) {\n          activeTarget != targets[i]\n            && scrollTop >= offsets[i]\n            && (!offsets[i + 1] || scrollTop <= offsets[i + 1])\n            && this.activate( targets[i] )\n        }\n      }\n\n    , activate: function (target) {\n        var active\n          , selector\n\n        this.activeTarget = target\n\n        $(this.selector)\n          .parent('.active')\n          .removeClass('active')\n\n        selector = this.selector\n          + '[data-target=\"' + target + '\"],'\n          + this.selector + '[href=\"' + target + '\"]'\n\n        active = $(selector)\n          .parent('li')\n          .addClass('active')\n\n        if (active.parent('.dropdown-menu').length)  {\n          active = active.closest('li.dropdown').addClass('active')\n        }\n\n        active.trigger('activate')\n      }\n\n  }\n\n\n /* SCROLLSPY PLUGIN DEFINITION\n  * =========================== */\n\n  $.fn.scrollspy = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('scrollspy')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.scrollspy.Constructor = ScrollSpy\n\n  $.fn.scrollspy.defaults = {\n    offset: 10\n  }\n\n\n /* SCROLLSPY DATA-API\n  * ================== */\n\n  $(window).on('load', function () {\n    $('[data-spy=\"scroll\"]').each(function () {\n      var $spy = $(this)\n      $spy.scrollspy($spy.data())\n    })\n  })\n\n}(window.jQuery);/* ========================================================\n * bootstrap-tab.js v2.1.1\n * http://twitter.github.com/bootstrap/javascript.html#tabs\n * ========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ======================================================== */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* TAB CLASS DEFINITION\n  * ==================== */\n\n  var Tab = function (element) {\n    this.element = $(element)\n  }\n\n  Tab.prototype = {\n\n    constructor: Tab\n\n  , show: function () {\n      var $this = this.element\n        , $ul = $this.closest('ul:not(.dropdown-menu)')\n        , selector = $this.attr('data-target')\n        , previous\n        , $target\n        , e\n\n      if (!selector) {\n        selector = $this.attr('href')\n        selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') //strip for ie7\n      }\n\n      if ( $this.parent('li').hasClass('active') ) return\n\n      previous = $ul.find('.active a').last()[0]\n\n      e = $.Event('show', {\n        relatedTarget: previous\n      })\n\n      $this.trigger(e)\n\n      if (e.isDefaultPrevented()) return\n\n      $target = $(selector)\n\n      this.activate($this.parent('li'), $ul)\n      this.activate($target, $target.parent(), function () {\n        $this.trigger({\n          type: 'shown'\n        , relatedTarget: previous\n        })\n      })\n    }\n\n  , activate: function ( element, container, callback) {\n      var $active = container.find('> .active')\n        , transition = callback\n            && $.support.transition\n            && $active.hasClass('fade')\n\n      function next() {\n        $active\n          .removeClass('active')\n          .find('> .dropdown-menu > .active')\n          .removeClass('active')\n\n        element.addClass('active')\n\n        if (transition) {\n          element[0].offsetWidth // reflow for transition\n          element.addClass('in')\n        } else {\n          element.removeClass('fade')\n        }\n\n        if ( element.parent('.dropdown-menu') ) {\n          element.closest('li.dropdown').addClass('active')\n        }\n\n        callback && callback()\n      }\n\n      transition ?\n        $active.one($.support.transition.end, next) :\n        next()\n\n      $active.removeClass('in')\n    }\n  }\n\n\n /* TAB PLUGIN DEFINITION\n  * ===================== */\n\n  $.fn.tab = function ( option ) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('tab')\n      if (!data) $this.data('tab', (data = new Tab(this)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.tab.Constructor = Tab\n\n\n /* TAB DATA-API\n  * ============ */\n\n  $(function () {\n    $('body').on('click.tab.data-api', '[data-toggle=\"tab\"], [data-toggle=\"pill\"]', function (e) {\n      e.preventDefault()\n      $(this).tab('show')\n    })\n  })\n\n}(window.jQuery);/* =============================================================\n * bootstrap-typeahead.js v2.1.1\n * http://twitter.github.com/bootstrap/javascript.html#typeahead\n * =============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================ */\n\n\n!function($){\n\n  \"use strict\"; // jshint ;_;\n\n\n /* TYPEAHEAD PUBLIC CLASS DEFINITION\n  * ================================= */\n\n  var Typeahead = function (element, options) {\n    this.$element = $(element)\n    this.options = $.extend({}, $.fn.typeahead.defaults, options)\n    this.matcher = this.options.matcher || this.matcher\n    this.sorter = this.options.sorter || this.sorter\n    this.highlighter = this.options.highlighter || this.highlighter\n    this.updater = this.options.updater || this.updater\n    this.$menu = $(this.options.menu).appendTo('body')\n    this.source = this.options.source\n    this.shown = false\n    this.listen()\n  }\n\n  Typeahead.prototype = {\n\n    constructor: Typeahead\n\n  , select: function () {\n      var val = this.$menu.find('.active').attr('data-value')\n      this.$element\n        .val(this.updater(val))\n        .change()\n      return this.hide()\n    }\n\n  , updater: function (item) {\n      return item\n    }\n\n  , show: function () {\n      var pos = $.extend({}, this.$element.offset(), {\n        height: this.$element[0].offsetHeight\n      })\n\n      this.$menu.css({\n        top: pos.top + pos.height\n      , left: pos.left\n      })\n\n      this.$menu.show()\n      this.shown = true\n      return this\n    }\n\n  , hide: function () {\n      this.$menu.hide()\n      this.shown = false\n      return this\n    }\n\n  , lookup: function (event) {\n      var items\n\n      this.query = this.$element.val()\n\n      if (!this.query || this.query.length < this.options.minLength) {\n        return this.shown ? this.hide() : this\n      }\n\n      items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source\n\n      return items ? this.process(items) : this\n    }\n\n  , process: function (items) {\n      var that = this\n\n      items = $.grep(items, function (item) {\n        return that.matcher(item)\n      })\n\n      items = this.sorter(items)\n\n      if (!items.length) {\n        return this.shown ? this.hide() : this\n      }\n\n      return this.render(items.slice(0, this.options.items)).show()\n    }\n\n  , matcher: function (item) {\n      return ~item.toLowerCase().indexOf(this.query.toLowerCase())\n    }\n\n  , sorter: function (items) {\n      var beginswith = []\n        , caseSensitive = []\n        , caseInsensitive = []\n        , item\n\n      while (item = items.shift()) {\n        if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)\n        else if (~item.indexOf(this.query)) caseSensitive.push(item)\n        else caseInsensitive.push(item)\n      }\n\n      return beginswith.concat(caseSensitive, caseInsensitive)\n    }\n\n  , highlighter: function (item) {\n      var query = this.query.replace(/[\\-\\[\\]{}()*+?.,\\\\\\^$|#\\s]/g, '\\\\$&')\n      return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {\n        return '<strong>' + match + '</strong>'\n      })\n    }\n\n  , render: function (items) {\n      var that = this\n\n      items = $(items).map(function (i, item) {\n        i = $(that.options.item).attr('data-value', item)\n        i.find('a').html(that.highlighter(item))\n        return i[0]\n      })\n\n      items.first().addClass('active')\n      this.$menu.html(items)\n      return this\n    }\n\n  , next: function (event) {\n      var active = this.$menu.find('.active').removeClass('active')\n        , next = active.next()\n\n      if (!next.length) {\n        next = $(this.$menu.find('li')[0])\n      }\n\n      next.addClass('active')\n    }\n\n  , prev: function (event) {\n      var active = this.$menu.find('.active').removeClass('active')\n        , prev = active.prev()\n\n      if (!prev.length) {\n        prev = this.$menu.find('li').last()\n      }\n\n      prev.addClass('active')\n    }\n\n  , listen: function () {\n      this.$element\n        .on('blur',     $.proxy(this.blur, this))\n        .on('keypress', $.proxy(this.keypress, this))\n        .on('keyup',    $.proxy(this.keyup, this))\n\n      if ($.browser.chrome || $.browser.webkit || $.browser.msie) {\n        this.$element.on('keydown', $.proxy(this.keydown, this))\n      }\n\n      this.$menu\n        .on('click', $.proxy(this.click, this))\n        .on('mouseenter', 'li', $.proxy(this.mouseenter, this))\n    }\n\n  , move: function (e) {\n      if (!this.shown) return\n\n      switch(e.keyCode) {\n        case 9: // tab\n        case 13: // enter\n        case 27: // escape\n          e.preventDefault()\n          break\n\n        case 38: // up arrow\n          e.preventDefault()\n          this.prev()\n          break\n\n        case 40: // down arrow\n          e.preventDefault()\n          this.next()\n          break\n      }\n\n      e.stopPropagation()\n    }\n\n  , keydown: function (e) {\n      this.suppressKeyPressRepeat = !~$.inArray(e.keyCode, [40,38,9,13,27])\n      this.move(e)\n    }\n\n  , keypress: function (e) {\n      if (this.suppressKeyPressRepeat) return\n      this.move(e)\n    }\n\n  , keyup: function (e) {\n      switch(e.keyCode) {\n        case 40: // down arrow\n        case 38: // up arrow\n          break\n\n        case 9: // tab\n        case 13: // enter\n          if (!this.shown) return\n          this.select()\n          break\n\n        case 27: // escape\n          if (!this.shown) return\n          this.hide()\n          break\n\n        default:\n          this.lookup()\n      }\n\n      e.stopPropagation()\n      e.preventDefault()\n  }\n\n  , blur: function (e) {\n      var that = this\n      setTimeout(function () { that.hide() }, 150)\n    }\n\n  , click: function (e) {\n      e.stopPropagation()\n      e.preventDefault()\n      this.select()\n    }\n\n  , mouseenter: function (e) {\n      this.$menu.find('.active').removeClass('active')\n      $(e.currentTarget).addClass('active')\n    }\n\n  }\n\n\n  /* TYPEAHEAD PLUGIN DEFINITION\n   * =========================== */\n\n  $.fn.typeahead = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('typeahead')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.typeahead.defaults = {\n    source: []\n  , items: 8\n  , menu: '<ul class=\"typeahead dropdown-menu\"></ul>'\n  , item: '<li><a href=\"#\"></a></li>'\n  , minLength: 1\n  }\n\n  $.fn.typeahead.Constructor = Typeahead\n\n\n /*   TYPEAHEAD DATA-API\n  * ================== */\n\n  $(function () {\n    $('body').on('focus.typeahead.data-api', '[data-provide=\"typeahead\"]', function (e) {\n      var $this = $(this)\n      if ($this.data('typeahead')) return\n      e.preventDefault()\n      $this.typeahead($this.data())\n    })\n  })\n\n}(window.jQuery);\n/* ==========================================================\n * bootstrap-affix.js v2.1.1\n * http://twitter.github.com/bootstrap/javascript.html#affix\n * ==========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================== */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* AFFIX CLASS DEFINITION\n  * ====================== */\n\n  var Affix = function (element, options) {\n    this.options = $.extend({}, $.fn.affix.defaults, options)\n    this.$window = $(window).on('scroll.affix.data-api', $.proxy(this.checkPosition, this))\n    this.$element = $(element)\n    this.checkPosition()\n  }\n\n  Affix.prototype.checkPosition = function () {\n    if (!this.$element.is(':visible')) return\n\n    var scrollHeight = $(document).height()\n      , scrollTop = this.$window.scrollTop()\n      , position = this.$element.offset()\n      , offset = this.options.offset\n      , offsetBottom = offset.bottom\n      , offsetTop = offset.top\n      , reset = 'affix affix-top affix-bottom'\n      , affix\n\n    if (typeof offset != 'object') offsetBottom = offsetTop = offset\n    if (typeof offsetTop == 'function') offsetTop = offset.top()\n    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()\n\n    affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ?\n      false    : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ?\n      'bottom' : offsetTop != null && scrollTop <= offsetTop ?\n      'top'    : false\n\n    if (this.affixed === affix) return\n\n    this.affixed = affix\n    this.unpin = affix == 'bottom' ? position.top - scrollTop : null\n\n    this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : ''))\n  }\n\n\n /* AFFIX PLUGIN DEFINITION\n  * ======================= */\n\n  $.fn.affix = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('affix')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('affix', (data = new Affix(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.affix.Constructor = Affix\n\n  $.fn.affix.defaults = {\n    offset: 0\n  }\n\n\n /* AFFIX DATA-API\n  * ============== */\n\n  $(window).on('load', function () {\n    $('[data-spy=\"affix\"]').each(function () {\n      var $spy = $(this)\n        , data = $spy.data()\n\n      data.offset = data.offset || {}\n\n      data.offsetBottom && (data.offset.bottom = data.offsetBottom)\n      data.offsetTop && (data.offset.top = data.offsetTop)\n\n      $spy.affix(data)\n    })\n  })\n\n\n}(window.jQuery);"
  },
  {
    "path": "src/main/webapp/js/cookie.js",
    "content": "/**\n * Holds cookie methods\n */\njavaRest.cookie = {}\n\n/**\n * Get the value of a cookie.\n * @param {string}\n * @return {string}\n */\njavaRest.cookie.get = function (name) {\n  var pairs = document.cookie.split(/\\; /g)\n  var cookie = {}\n  for (var i in pairs) {\n    var parts = pairs[i].split(/\\=/)\n    cookie[parts[0]] = unescape(parts[1])\n  }\n  return cookie[name]\n}\n\n/**\n * Delete a cookie\n * @param {string}\n */\njavaRest.cookie.remove = function (name) {\n  document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'\n}\n\n/**\n * Set a cookie\n * @param {string}\n * @param {string}\n */\njavaRest.cookie.set = function (name, value) {\n  // document.cookie = \"name=value[; expires=UTCString][; domain=domainName][; path=pathName][; secure]\"; \n  document.cookie = name + '=' + value;\n}\n\n"
  },
  {
    "path": "src/main/webapp/js/enc-base64-min.js",
    "content": "/*\nCryptoJS v3.0.2\ncode.google.com/p/crypto-js\n(c) 2009-2012 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\n(function(){var h=CryptoJS,i=h.lib.WordArray;h.enc.Base64={stringify:function(b){var e=b.words,f=b.sigBytes,c=this._map;b.clamp();for(var b=[],a=0;a<f;a+=3)for(var d=(e[a>>>2]>>>24-8*(a%4)&255)<<16|(e[a+1>>>2]>>>24-8*((a+1)%4)&255)<<8|e[a+2>>>2]>>>24-8*((a+2)%4)&255,g=0;4>g&&a+0.75*g<f;g++)b.push(c.charAt(d>>>6*(3-g)&63));if(e=c.charAt(64))for(;b.length%4;)b.push(e);return b.join(\"\")},parse:function(b){var b=b.replace(/\\s/g,\"\"),e=b.length,f=this._map,c=f.charAt(64);c&&(c=b.indexOf(c),-1!=c&&(e=c));\nfor(var c=[],a=0,d=0;d<e;d++)if(d%4){var g=f.indexOf(b.charAt(d-1))<<2*(d%4),h=f.indexOf(b.charAt(d))>>>6-2*(d%4);c[a>>>2]|=(g|h)<<24-8*(a%4);a++}return i.create(c,a)},_map:\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\"}})();\n"
  },
  {
    "path": "src/main/webapp/js/grid.locale-en.js",
    "content": ";(function($){\r\n/**\r\n * jqGrid English Translation\r\n * Tony Tomov tony@trirand.com\r\n * http://trirand.com/blog/ \r\n * Dual licensed under the MIT and GPL licenses:\r\n * http://www.opensource.org/licenses/mit-license.php\r\n * http://www.gnu.org/licenses/gpl.html\r\n**/\r\n$.jgrid = $.jgrid || {};\r\n$.extend($.jgrid,{\r\n\tdefaults : {\r\n\t\trecordtext: \"View {0} - {1} of {2}\",\r\n\t\temptyrecords: \"No records to view\",\r\n\t\tloadtext: \"Loading...\",\r\n\t\tpgtext : \"Page {0} of {1}\"\r\n\t},\r\n\tsearch : {\r\n\t\tcaption: \"Search...\",\r\n\t\tFind: \"Find\",\r\n\t\tReset: \"Reset\",\r\n\t\todata : ['equal', 'not equal', 'less', 'less or equal','greater','greater or equal', 'begins with','does not begin with','is in','is not in','ends with','does not end with','contains','does not contain'],\r\n\t\tgroupOps: [\t{ op: \"AND\", text: \"all\" },\t{ op: \"OR\",  text: \"any\" }\t],\r\n\t\tmatchText: \" match\",\r\n\t\trulesText: \" rules\"\r\n\t},\r\n\tedit : {\r\n\t\taddCaption: \"Add Record\",\r\n\t\teditCaption: \"Edit Record\",\r\n\t\tbSubmit: \"Submit\",\r\n\t\tbCancel: \"Cancel\",\r\n\t\tbClose: \"Close\",\r\n\t\tsaveData: \"Data has been changed! Save changes?\",\r\n\t\tbYes : \"Yes\",\r\n\t\tbNo : \"No\",\r\n\t\tbExit : \"Cancel\",\r\n\t\tmsg: {\r\n\t\t\trequired:\"Field is required\",\r\n\t\t\tnumber:\"Please, enter valid number\",\r\n\t\t\tminValue:\"value must be greater than or equal to \",\r\n\t\t\tmaxValue:\"value must be less than or equal to\",\r\n\t\t\temail: \"is not a valid e-mail\",\r\n\t\t\tinteger: \"Please, enter valid integer value\",\r\n\t\t\tdate: \"Please, enter valid date value\",\r\n\t\t\turl: \"is not a valid URL. Prefix required ('http://' or 'https://')\",\r\n\t\t\tnodefined : \" is not defined!\",\r\n\t\t\tnovalue : \" return value is required!\",\r\n\t\t\tcustomarray : \"Custom function should return array!\",\r\n\t\t\tcustomfcheck : \"Custom function should be present in case of custom checking!\"\r\n\t\t\t\r\n\t\t}\r\n\t},\r\n\tview : {\r\n\t\tcaption: \"View Record\",\r\n\t\tbClose: \"Close\"\r\n\t},\r\n\tdel : {\r\n\t\tcaption: \"Delete\",\r\n\t\tmsg: \"Delete selected record(s)?\",\r\n\t\tbSubmit: \"Delete\",\r\n\t\tbCancel: \"Cancel\"\r\n\t},\r\n\tnav : {\r\n\t\tedittext: \"\",\r\n\t\tedittitle: \"Edit selected row\",\r\n\t\taddtext:\"\",\r\n\t\taddtitle: \"Add new row\",\r\n\t\tdeltext: \"\",\r\n\t\tdeltitle: \"Delete selected row\",\r\n\t\tsearchtext: \"\",\r\n\t\tsearchtitle: \"Find records\",\r\n\t\trefreshtext: \"\",\r\n\t\trefreshtitle: \"Reload Grid\",\r\n\t\talertcap: \"Warning\",\r\n\t\talerttext: \"Please, select row\",\r\n\t\tviewtext: \"\",\r\n\t\tviewtitle: \"View selected row\"\r\n\t},\r\n\tcol : {\r\n\t\tcaption: \"Select columns\",\r\n\t\tbSubmit: \"Ok\",\r\n\t\tbCancel: \"Cancel\"\r\n\t},\r\n\terrors : {\r\n\t\terrcap : \"Error\",\r\n\t\tnourl : \"No url is set\",\r\n\t\tnorecords: \"No records to process\",\r\n\t\tmodel : \"Length of colNames <> colModel!\"\r\n\t},\r\n\tformatter : {\r\n\t\tinteger : {thousandsSeparator: \" \", defaultValue: '0'},\r\n\t\tnumber : {decimalSeparator:\".\", thousandsSeparator: \" \", decimalPlaces: 2, defaultValue: '0.00'},\r\n\t\tcurrency : {decimalSeparator:\".\", thousandsSeparator: \" \", decimalPlaces: 2, prefix: \"\", suffix:\"\", defaultValue: '0.00'},\r\n\t\tdate : {\r\n\t\t\tdayNames:   [\r\n\t\t\t\t\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thr\", \"Fri\", \"Sat\",\r\n\t\t\t\t\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"\r\n\t\t\t],\r\n\t\t\tmonthNames: [\r\n\t\t\t\t\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\",\r\n\t\t\t\t\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"\r\n\t\t\t],\r\n\t\t\tAmPm : [\"am\",\"pm\",\"AM\",\"PM\"],\r\n\t\t\tS: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},\r\n\t\t\tsrcformat: 'Y-m-d',\r\n\t\t\tnewformat: 'd/m/Y',\r\n\t\t\tmasks : {\r\n\t\t\t\tISO8601Long:\"Y-m-d H:i:s\",\r\n\t\t\t\tISO8601Short:\"Y-m-d\",\r\n\t\t\t\tShortDate: \"n/j/Y\",\r\n\t\t\t\tLongDate: \"l, F d, Y\",\r\n\t\t\t\tFullDateTime: \"l, F d, Y g:i:s A\",\r\n\t\t\t\tMonthDay: \"F d\",\r\n\t\t\t\tShortTime: \"g:i A\",\r\n\t\t\t\tLongTime: \"g:i:s A\",\r\n\t\t\t\tSortableDateTime: \"Y-m-d\\\\TH:i:s\",\r\n\t\t\t\tUniversalSortableDateTime: \"Y-m-d H:i:sO\",\r\n\t\t\t\tYearMonth: \"F, Y\"\r\n\t\t\t},\r\n\t\t\treformatAfterEdit : false\r\n\t\t},\r\n\t\tbaseLinkUrl: '',\r\n\t\tshowAction: '',\r\n\t\ttarget: '',\r\n\t\tcheckbox : {disabled:true},\r\n\t\tidName : 'id'\r\n\t}\r\n});\r\n})(jQuery);\r\n"
  },
  {
    "path": "src/main/webapp/js/javarest.js",
    "content": "/**\n * Singleton used for Namespace\n */\nfunction javaRest() {\n  \n}\n\n/**\n * Wrap the API so we can proxy calls while testing.\n */\njavaRest.get = function (url, data, success, error) {\n  \n  var time = javaRest.get_iso_date()\n  var nonce = makeRandomString()\n  var string_to_hash = javaRest.cookie.get('token') + ':' + url + ',GET,' + time + \",\" + nonce\n  var authorization = javaRest.cookie.get('userId') + ':' + javaRest.hash(string_to_hash)\n  \n  var request = $.ajax({\n    url: url,\n    type: \"GET\",\n    data: data,\n    headers: {\n      'Authorization' : authorization,\n      'x-java-rest-date' : time,\n      'nonce' : nonce\n    },\n    dataType: \"json\"\n  })\n\n  request.done(success)\n\n  request.fail(error)\n  \n}\n\nfunction makeRandomString() {\n    return Math.random().toString(36).substring(2, 15) +\n        Math.random().toString(36).substring(2, 15);\n}\n\n/**\n * Return the current time as an ISO 8061 Date\n * @return {string} 2012-06-30T12:00:00+01:00\n */\njavaRest.get_iso_date = function () {\n  var d = new Date()\n  function pad(n) {return n<10 ? '0'+n : n}\n  return d.getUTCFullYear()+'-'\n    + pad(d.getUTCMonth()+1)+'-'\n    + pad(d.getUTCDate())+'T'\n    + pad(d.getUTCHours())+':'\n    + pad(d.getUTCMinutes())+':'\n    + pad(d.getUTCSeconds())+'Z'\n}\n\n/**\n * Get a query string var\n * @param {string}\n * @return {string}\n */\njavaRest.get_query = function (name) {\n  var query = window.location.search.substring(1)\n  var vars = query.split('&')\n  for (var i = 0; i < vars.length; i++) {\n      var pair = vars[i].split('=')\n      if (decodeURIComponent(pair[0]) == name) {\n          return decodeURIComponent(pair[1])\n      }\n  }\n}\n\n/**\n * SHA256, then base64 encode a string\n * @param {string}\n * @return {string}\n */\njavaRest.hash = function (string) {\n  var hash = CryptoJS.SHA256(string)\n  return hash.toString(CryptoJS.enc.Base64)\n}\n\n/**\n * Is the visitor on iPhone or Ipad?\n * @return {bool}\n */\njavaRest.isIos = function () {\n  return (navigator.userAgent.match(/iPad|iPhone|iPod/i) != null)\n}\n\n/**\n * Wrap the API so we can proxy calls while testing.\n */\njavaRest.post = function (url, data, success, error) {\n  \n  $.ajax({\n    url: url,\n    type: \"POST\",\n    contentType: \"application/json\", // send as JSON\n    data: JSON.stringify(data),\n    dataType: \"json\",\n    success : success,\n    error : error\n  })\n\n  \n}\n\n/**\n * Post with authentication\n */\njavaRest.postAuth = function (url, data, success, error) {\n  \n  var time = javaRest.get_iso_date()\n  var nonce = makeRandomString()\n  var string_to_hash = javaRest.cookie.get('token') + ':' + url + ',POST,' + time + \",\" + nonce\n  var authorization = javaRest.cookie.get('userId') + ':' + javaRest.hash(string_to_hash)\n  \n  $.ajax({\n    url: url,\n    type: \"POST\",\n    contentType: \"application/json\", // send as JSON\n    data: JSON.stringify(data),\n    headers: {\n      'Authorization' : authorization,\n      'x-java-rest-date' : time ,\n      'nonce' : nonce\n    },\n    dataType: \"json\",\n    success : success,\n    error : error\n  })\n\n  \n}\n\n/**\n * Wrap the API so we can proxy calls while testing.\n */\njavaRest.put = function (url, data, success, error) {\n  \n  var time = javaRest.get_iso_date()\n  var nonce = makeRandomString()\n  var string_to_hash = javaRest.cookie.get('token') + ':' + url + ',PUT,' + time + \",\" + nonce\n  var authorization = javaRest.cookie.get('userId') + ':' + javaRest.hash(string_to_hash)\n  \n  $.ajax({\n    url: url,\n    type: \"PUT\",\n    contentType: \"application/json\", // send as JSON\n    data: JSON.stringify(data),\n    headers: {\n      'Authorization' : authorization,\n      'x-java-rest-date' : time,\n      'nonce' : nonce\n    },\n    dataType: \"json\",\n    success : success,\n    error : error\n  })\n\n  \n}\n\n\n"
  },
  {
    "path": "src/main/webapp/js/jquery-full-house.js",
    "content": "/*\n    Based on this script by Marcus Ekwall\n    http://jsfiddle.net/mekwall/fNyHs/\n\n\tExamples, support and the newest version of this script is here:\n\thttps://github.com/kuchumovn/jquery-full-house\n\n    Author: Nikolay Kuchumov\n    github: kuchumovn\n    email: kuchumovn@gmail.com\n*/\n\n(function($)\n{\n\tvar Algorythm = \n\t{\n\t\t// you can write your own algorythm\n\t\tInterface: function(options)\n\t\t{\n\t\t\t// called if the 'x' font size is too big, and the text with this font size doesn't fit the container\n\t\t\tthis.too_big = function(x) {}\n\t\t\t\n\t\t\t// called if the text with font size 'x' fits the container (e.g. font_size=0 fits any container)\n\t\t\tthis.fits = function(x) {}\t\n\t\t\t\n\t\t\t// this.retry(x) function will be set automatically\n\t\t},\n\t\n\t\t// just for reference\n\t\tLinear: function(options)\n\t\t{\n\t\t\tvar largest_fit = 0\n\t\t\t\n\t\t\tthis.too_big = function(x) \n\t\t\t{\n\t\t\t\tif (x - 1 === largest_fit)\n\t\t\t\t\treturn largest_fit\n\t\t\t\t\t\n\t\t\t\treturn this.retry(x - 1)\n\t\t\t}\n\t\t\t\n\t\t\tthis.fits = function(x) \n\t\t\t{\n\t\t\t\tlargest_fit = x\n\t\t\t\treturn this.retry(x + 1)\n\t\t\t}\n\t\t},\n\t\t\n\t\t// the faster algorythm\n\t\tBinary: function(options)\n\t\t{\n\t\t\tvar largest_fit\n\t\t\tvar minimum_too_big\n\t\t\t\n\t\t\tvar step = options.Font_size_increment_step || 10\n\t\t\n\t\t\tthis.too_big = function(x)\n\t\t\t{\n\t\t\t\tminimum_too_big = x\n\t\t\t\t\n\t\t\t\tif (largest_fit)\n\t\t\t\t{\n\t\t\t\t\tif (largest_fit === x - 1)\n\t\t\t\t\t\treturn largest_fit\n\t\t\t\t\t\t\n\t\t\t\t\treturn this.retry(largest_fit + (x - largest_fit) / 2)\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (x === 1)\n\t\t\t\t\t\treturn 1\n\t\t\t\t\t\t\n\t\t\t\t\treturn this.retry(x - step)\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tthis.fits = function(x)\n\t\t\t{\n\t\t\t\tlargest_fit = x\n\t\t\t\t\n\t\t\t\tif (minimum_too_big)\n\t\t\t\t{\n\t\t\t\t\tif (minimum_too_big === x + 1)\n\t\t\t\t\t\treturn x\n\t\t\t\t\t\t\n\t\t\t\t\treturn this.retry(x + (minimum_too_big - x) / 2)\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn this.retry(x + step)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction get_initial_font_size(container)\n\t{\n\t\tif (container.css('fontSize'))\n\t\t{\n\t\t\tvar check = container.css('fontSize').match(/[\\d]+px/)\n\t\t\tif (check.length)\n\t\t\t\treturn parseInt(check[0])\n\t\t}\n\t\t\n\t\treturn 1\n\t}\n\t\n\tfunction find_max_font_size(container, options)\n\t{\n\t\tvar initial_font_size = get_initial_font_size(container)\n\t\tcontainer.css('fontSize', 0)\n\t\t\t\n\t\tvar html = container.html()\n\t\t\n\t\tcontainer.empty()\n\t\t\n\t\tvar overflow = container.css('overflow')\n\t\tcontainer.css('overflow', 'hidden')\n\t\t\n\t\tvar sandbox = $('<span/>').html(html).appendTo(container)\n\t\t\n\t\tvar available_height = container[0].scrollHeight\n\t\tvar available_width = container[0].scrollWidth\n\t\t\n\t\tfunction try_font_size(font_size)\n\t\t{\n\t\t\tcontainer.css({ fontSize: font_size + 'px' })\n\t\t}\n\t\t\n\t\tfunction recursive_search(algorythm, start_with)\n\t\t{\n\t\t\tvar find_max_font_size_starting_with = function(font_size)\n\t\t\t{\n\t\t\t\tfont_size = Math.ceil(font_size)\n\t\t\t\tif (font_size < 1)\n\t\t\t\t\tfont_size = 1\n\t\t\t\t\t\n\t\t\t\ttry_font_size(font_size)\n\t\t\t\t\n\t\t\t\tvar current_height = container[0].scrollHeight\n\t\t\t\tvar current_width = container[0].scrollWidth\n\t\t\t\t\n\t\t\t\tvar height_proportion = current_height / available_height\n\t\t\t\tvar width_proportion = current_width / available_width\n\t\t\t\t\n\t\t\t\tif (height_proportion > 1 || width_proportion > 1)\n\t\t\t\t\treturn algorythm.too_big(font_size)\n\t\t\t\telse\n\t\t\t\t\treturn algorythm.fits(font_size)\n\t\t\t}\n\t\t\t\n\t\t\talgorythm.retry = find_max_font_size_starting_with\n\t\t\treturn find_max_font_size_starting_with(start_with)\n\t\t}\n\t\t\n\t\toptions.algorythm = options.algorythm || 'Binary'\n\t\tvar algorythm = new Algorythm[options.algorythm](options)\n\t\t\n\t\tvar font_size = recursive_search(algorythm, initial_font_size)\n\n\t\tcontainer.css('overflow', overflow)\n\t\tcontainer.empty().html(html)\n\t\t\n\t\treturn font_size\n\t}\n\t\n\t$.fn.fill_with_text = function(options)\n\t{\n\t\toptions = options || {}\n\t\n\t\treturn $(this).each(function()\n\t\t{\n\t\t\tvar container = $(this)\n\t\t\tcontainer.css({ fontSize: find_max_font_size(container, options) + 'px' })\n\t\t\tif (options.collapse)\n\t\t\t\tcontainer.css('height', 'auto')\n\t\t})\n\t}\n})(jQuery)"
  },
  {
    "path": "src/main/webapp/js/sha256.js",
    "content": "/*\nCryptoJS v3.0.2\ncode.google.com/p/crypto-js\n(c) 2009-2012 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\nvar CryptoJS=CryptoJS||function(i,p){var f={},q=f.lib={},j=q.Base=function(){function a(){}return{extend:function(h){a.prototype=this;var d=new a;h&&d.mixIn(h);d.$super=this;return d},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var d in a)a.hasOwnProperty(d)&&(this[d]=a[d]);a.hasOwnProperty(\"toString\")&&(this.toString=a.toString)},clone:function(){return this.$super.extend(this)}}}(),k=q.WordArray=j.extend({init:function(a,h){a=\nthis.words=a||[];this.sigBytes=h!=p?h:4*a.length},toString:function(a){return(a||m).stringify(this)},concat:function(a){var h=this.words,d=a.words,c=this.sigBytes,a=a.sigBytes;this.clamp();if(c%4)for(var b=0;b<a;b++)h[c+b>>>2]|=(d[b>>>2]>>>24-8*(b%4)&255)<<24-8*((c+b)%4);else if(65535<d.length)for(b=0;b<a;b+=4)h[c+b>>>2]=d[b>>>2];else h.push.apply(h,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,b=this.sigBytes;a[b>>>2]&=4294967295<<32-8*(b%4);a.length=i.ceil(b/4)},clone:function(){var a=\nj.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var b=[],d=0;d<a;d+=4)b.push(4294967296*i.random()|0);return k.create(b,a)}}),r=f.enc={},m=r.Hex={stringify:function(a){for(var b=a.words,a=a.sigBytes,d=[],c=0;c<a;c++){var e=b[c>>>2]>>>24-8*(c%4)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join(\"\")},parse:function(a){for(var b=a.length,d=[],c=0;c<b;c+=2)d[c>>>3]|=parseInt(a.substr(c,2),16)<<24-4*(c%8);return k.create(d,b/2)}},s=r.Latin1={stringify:function(a){for(var b=\na.words,a=a.sigBytes,d=[],c=0;c<a;c++)d.push(String.fromCharCode(b[c>>>2]>>>24-8*(c%4)&255));return d.join(\"\")},parse:function(a){for(var b=a.length,d=[],c=0;c<b;c++)d[c>>>2]|=(a.charCodeAt(c)&255)<<24-8*(c%4);return k.create(d,b)}},g=r.Utf8={stringify:function(a){try{return decodeURIComponent(escape(s.stringify(a)))}catch(b){throw Error(\"Malformed UTF-8 data\");}},parse:function(a){return s.parse(unescape(encodeURIComponent(a)))}},b=q.BufferedBlockAlgorithm=j.extend({reset:function(){this._data=k.create();\nthis._nDataBytes=0},_append:function(a){\"string\"==typeof a&&(a=g.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var b=this._data,d=b.words,c=b.sigBytes,e=this.blockSize,f=c/(4*e),f=a?i.ceil(f):i.max((f|0)-this._minBufferSize,0),a=f*e,c=i.min(4*a,c);if(a){for(var g=0;g<a;g+=e)this._doProcessBlock(d,g);g=d.splice(0,a);b.sigBytes-=c}return k.create(g,c)},clone:function(){var a=j.clone.call(this);a._data=this._data.clone();return a},_minBufferSize:0});q.Hasher=b.extend({init:function(){this.reset()},\nreset:function(){b.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);this._doFinalize();return this._hash},clone:function(){var a=b.clone.call(this);a._hash=this._hash.clone();return a},blockSize:16,_createHelper:function(a){return function(b,d){return a.create(d).finalize(b)}},_createHmacHelper:function(a){return function(b,d){return e.HMAC.create(a,d).finalize(b)}}});var e=f.algo={};return f}(Math);\n(function(i){var p=CryptoJS,f=p.lib,q=f.WordArray,f=f.Hasher,j=p.algo,k=[],r=[];(function(){function f(a){for(var b=i.sqrt(a),d=2;d<=b;d++)if(!(a%d))return!1;return!0}function g(a){return 4294967296*(a-(a|0))|0}for(var b=2,e=0;64>e;)f(b)&&(8>e&&(k[e]=g(i.pow(b,0.5))),r[e]=g(i.pow(b,1/3)),e++),b++})();var m=[],j=j.SHA256=f.extend({_doReset:function(){this._hash=q.create(k.slice(0))},_doProcessBlock:function(f,g){for(var b=this._hash.words,e=b[0],a=b[1],h=b[2],d=b[3],c=b[4],i=b[5],j=b[6],k=b[7],l=0;64>\nl;l++){if(16>l)m[l]=f[g+l]|0;else{var n=m[l-15],o=m[l-2];m[l]=((n<<25|n>>>7)^(n<<14|n>>>18)^n>>>3)+m[l-7]+((o<<15|o>>>17)^(o<<13|o>>>19)^o>>>10)+m[l-16]}n=k+((c<<26|c>>>6)^(c<<21|c>>>11)^(c<<7|c>>>25))+(c&i^~c&j)+r[l]+m[l];o=((e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22))+(e&a^e&h^a&h);k=j;j=i;i=c;c=d+n|0;d=h;h=a;a=e;e=n+o|0}b[0]=b[0]+e|0;b[1]=b[1]+a|0;b[2]=b[2]+h|0;b[3]=b[3]+d|0;b[4]=b[4]+c|0;b[5]=b[5]+i|0;b[6]=b[6]+j|0;b[7]=b[7]+k|0},_doFinalize:function(){var f=this._data,g=f.words,b=8*this._nDataBytes,\ne=8*f.sigBytes;g[e>>>5]|=128<<24-e%32;g[(e+64>>>9<<4)+15]=b;f.sigBytes=4*g.length;this._process()}});p.SHA256=f._createHelper(j);p.HmacSHA256=f._createHmacHelper(j)})(Math);"
  },
  {
    "path": "src/main/webapp/js/store.js",
    "content": "/* Copyright (c) 2010-2012 Marcus Westin */\n(function(){function h(){try{return d in b&&b[d]}catch(a){return!1}}function i(){try{return e in b&&b[e]&&b[e][b.location.hostname]}catch(a){return!1}}var a={},b=window,c=b.document,d=\"localStorage\",e=\"globalStorage\",f=\"__storejs__\",g;a.disabled=!1,a.set=function(a,b){},a.get=function(a){},a.remove=function(a){},a.clear=function(){},a.transact=function(b,c,d){var e=a.get(b);d==null&&(d=c,c=null),typeof e==\"undefined\"&&(e=c||{}),d(e),a.set(b,e)},a.getAll=function(){},a.serialize=function(a){return JSON.stringify(a)},a.deserialize=function(a){if(typeof a!=\"string\")return undefined;try{return JSON.parse(a)}catch(b){return a||undefined}};if(h())g=b[d],a.set=function(b,c){return c===undefined?a.remove(b):(g.setItem(b,a.serialize(c)),c)},a.get=function(b){return a.deserialize(g.getItem(b))},a.remove=function(a){g.removeItem(a)},a.clear=function(){g.clear()},a.getAll=function(){var b={};for(var c=0;c<g.length;++c){var d=g.key(c);b[d]=a.get(d)}return b};else if(i())g=b[e][b.location.hostname],a.set=function(b,c){return c===undefined?a.remove(b):(g[b]=a.serialize(c),c)},a.get=function(b){return a.deserialize(g[b]&&g[b].value)},a.remove=function(a){delete g[a]},a.clear=function(){for(var a in g)delete g[a]},a.getAll=function(){var b={};for(var c=0;c<g.length;++c){var d=g.key(c);b[d]=a.get(d)}return b};else if(c.documentElement.addBehavior){var j,k;try{k=new ActiveXObject(\"htmlfile\"),k.open(),k.write('<script>document.w=window</script><iframe src=\"/favicon.ico\"></frame>'),k.close(),j=k.w.frames[0].document,g=j.createElement(\"div\")}catch(l){g=c.createElement(\"div\"),j=c.body}function m(b){return function(){var c=Array.prototype.slice.call(arguments,0);c.unshift(g),j.appendChild(g),g.addBehavior(\"#default#userData\"),g.load(d);var e=b.apply(a,c);return j.removeChild(g),e}}var n=new RegExp(\"[!\\\"#$%&'()*+,/\\\\\\\\:;<=>?@[\\\\]^`{|}~]\",\"g\");function o(a){return a.replace(n,\"___\")}a.set=m(function(b,c,e){return c=o(c),e===undefined?a.remove(c):(b.setAttribute(c,a.serialize(e)),b.save(d),e)}),a.get=m(function(b,c){return c=o(c),a.deserialize(b.getAttribute(c))}),a.remove=m(function(a,b){b=o(b),a.removeAttribute(b),a.save(d)}),a.clear=m(function(a){var b=a.XMLDocument.documentElement.attributes;a.load(d);for(var c=0,e;e=b[c];c++)a.removeAttribute(e.name);a.save(d)}),a.getAll=m(function(b){var c=b.XMLDocument.documentElement.attributes;b.load(d);var e={};for(var f=0,g;g=c[f];++f)e[g]=a.get(g);return e})}try{a.set(f,f),a.get(f)!=f&&(a.disabled=!0),a.remove(f)}catch(l){a.disabled=!0}a.enabled=!a.disabled,typeof module!=\"undefined\"&&typeof module!=\"function\"?module.exports=a:typeof define==\"function\"&&define.amd?define(a):this.store=a})()"
  },
  {
    "path": "src/main/webapp/js/user.js",
    "content": "javaRest.user = {}\n\n\n/**\n * Create a user\n *\n * @param {string}\n * @param {string}\n * @param {string}\n * @param {string}\n * @param {function}\n */\njavaRest.user.create = function (firstName, emailAddress, password, lastName, callback) {\n\n\n  javaRest.post(\n    'user',\n    {user :\n      {\n        \"firstName\" : firstName,\n        \"emailAddress\" : emailAddress\n      },\n    \"password\" : password\n    },\n    function (response) {\n      javaRest.cookie.set('token', response.token)\n      javaRest.cookie.set('userId', response.userId)\n      javaRest.cookie.set('email', emailAddress)\n      callback()\n    },\n    function(jqXHR, textStatus) {\n      console.log(jqXHR)\n      callback(jqXHR)\n    })\n\n}\n\n\n/**\n * Get user info\n * @param {function}\n */\njavaRest.user.download = function (callback) {\n\n  javaRest.get(\n    'user/' + javaRest.cookie.get('userId'),\n    {},\n    function (response) {\n      console.log(response)\n      // If the cached version is the same as the most recent\n      // version, just return. Else, we will run the callback.\n      if (store.get('userResponse') === JSON.stringify(response)) {\n        console.log('cached')\n        return false\n      }\n\n\n      store.set('userResponse', JSON.stringify(response))\n\n      javaRest.user.user = response\n\n      if (callback)\n        callback()\n    },\n    function(jqXHR, textStatus) {\n      if (callback)\n        callback(jqXHR)\n    })\n\n}\n\n/**\n * Get user info\n * @param {function}\n */\njavaRest.user.get = function (callback) {\n\n\n  var userResponse = store.get('userResponse')\n\n\n  if (userResponse) {\n    var response = JSON.parse(userResponse)\n    javaRest.user.user = response.user\n    // We still download the latest data in the background to make sure\n    // cache is current. But we return immediately.\n    javaRest.user.download(callback)\n    return callback()\n  }\n\n\n  javaRest.user.download(callback)\n\n}\n\n/**\n * @return {bool}\n */\njavaRest.user.is_logged_in = function () {\n  return !!javaRest.cookie.get('token')\n}\n\n/**\n * Log the user in\n * @param {string}\n * @param {string}\n * @param {function} Callback. First parameter is error, if any.\n */\njavaRest.user.login = function (email, password, callback) {\n\n  javaRest.post(\n    'user/login',\n      {\n      \"username\" : email,\n      \"password\" : password\n      },\n    function (response) {\n      javaRest.cookie.set('token', response.token)\n      javaRest.cookie.set('userId', response.userId)\n      javaRest.cookie.set('email', email)\n      callback()\n\n    },\n    function(jqXHR, textStatus) {\n      callback(jqXHR)\n    })\n\n}\n\n/**\n * Log the user in via facebook\n * @param {string}\n * @param {function} Callback. First parameter is error, if any.\n */\njavaRest.user.loginSocial = function (accessToken, callback) {\n\n  javaRest.post(\n    'user/login/facebook',\n      {\n      \"accessToken\" : accessToken\n      },\n    function (response) {\n      javaRest.cookie.set('token', response.token)\n      javaRest.cookie.set('userId', response.userId)\n      callback()\n\n    },\n    function(jqXHR, textStatus) {\n      callback(jqXHR)\n    })\n\n}\n\n\n/**\n * Delete the users cookies.\n */\njavaRest.user.logout = function () {\n  javaRest.cookie.remove('token')\n  javaRest.cookie.remove('userId')\n  javaRest.cookie.remove('email')\n  store.clear()\n  window.location = 'index.html'\n}\n\n/**\n * Delete the users cookies.\n */\njavaRest.user.reset_password = function (token, password, callback) {\n  javaRest.post(\n    'password/tokens/' + token,\n      {\n      \"password\" : password\n      },\n    function (response) {\n      callback()\n    },\n    function(jqXHR, textStatus) {\n      callback(jqXHR)\n    })\n}\n\n/**\n * Delete the users cookies.\n */\njavaRest.user.send_reset_email = function (email, callback) {\n  javaRest.post(\n    'password/tokens',\n      {\n      \"emailAddress\" : email\n      },\n    function (response) {\n      callback()\n\n    },\n    function(jqXHR, textStatus) {\n      callback(jqXHR)\n    })\n}\n\n\n\n/**\n * Update first name\n * @param {function}\n */\njavaRest.user.updateName = function (value, callback) {\n\n  javaRest.put(\n    'user/' + javaRest.cookie.get('userId'),\n      {\n      \"emailAddress\" : javaRest.cookie.get('email'),\n      \"firstName\" : value\n      },\n    function (response) {\n      console.log(response)\n      if (callback)\n        callback()\n      // Clear user cache\n      javaRest.user.download()\n    },\n    function(jqXHR, textStatus) {\n      if (callback)\n        callback(jqXHR)\n      // Clear user cache\n      javaRest.user.download()\n    })\n}\n\n"
  },
  {
    "path": "src/main/webapp/js/verify.js",
    "content": "javaRest.verify = {}\n\n/**\n * Sends an email to user for verification\n */\njavaRest.verify.request_email = function (email, callback) {\n  javaRest.post(\n    'verify/tokens',\n    {\n      'emailAddress' : email\n    },\n    function (response) {\n      console.log(response)\n      callback()\n    },\n    function(jqXHR, textStatus) {\n      callback(jqXHR)\n    })\n}\n\n/**\n * Validate an email address.\n */\njavaRest.verify.verify = function (token, callback) {\n  javaRest.post(\n    'verify/tokens/' + token,\n    {},\n    function (response) {\n      callback()\n    },\n    function(jqXHR, textStatus) {\n      callback(jqXHR)\n    })\n}\n\n"
  },
  {
    "path": "src/main/webapp/request_email.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Sample Java REST applicaiton</title>\n    <link href=\"css/styles.css\" rel=\"stylesheet\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\n  </head>\n  <body>\n\n    <div id=\"container\">\n\n      <!--nav-->\n      <div id=\"nav\">\n        <a href=\"dashboard.html\" class=\"unselected_tab\" id=\"dashboard_tab\">Dashboard</a>\n\t    </div>\n\n\n      <div class=\"success\" style=\"display: none;\">Success!<br><br>Check your inbox for an email from us. Click on the link in that email to verify your address.</div>\n      <div class=\"error\" style=\"display: none;\">Error sending verification email</div>\n\n\t    <!--footer-->\n\t    <div id=\"footer\">\n      </div>\n\n    </div>\n\n\n\n    <script src=\"js/jquery-1.8.2.min.js\"></script>\n    <script src=\"js/store.js\"></script>\n    <script src=\"js/sha256.js\"></script>\n    <script src=\"js/enc-base64-min.js\"></script>\n    <script src=\"js/javarest.js\"></script>\n    <script src=\"js/cookie.js\"></script>\n    <script src=\"js/user.js\"></script>\n    <script src=\"js/verify.js\"></script>\n    <script type=\"text/javascript\">\n\n    $(document).ready(function () {\n      javaRest.verify.request_email(javaRest.cookie.get('email'), function (error) {\n        if (error)\n          $('.error').show()\n        else\n          $('.success').show()\n      })\n    })\n    </script>\n  </body>\n</html>"
  },
  {
    "path": "src/main/webapp/reset_password.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Java REST Sample Application</title>\n    <link href=\"css/styles.css\" rel=\"stylesheet\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  </head>\n  <body>\n\n    <div id=\"container\">\n\n      <input id=\"password\" type=\"password\" placeholder=\"New Password\">\n      <div id=\"error_message\"></div>\n  \t  <button type=\"submit\" id=\"login_button\">Change Password</button>\n\n\n    </div>\n\n    <script src=\"js/jquery-1.8.2.min.js\"></script>\n    <script src=\"js/store.js\"></script>\n    <script src=\"js/javarest.js\"></script>\n    <script src=\"js/cookie.js\"></script>\n    <script src=\"js/user.js\"></script>\n    <script type=\"text/javascript\">\n    $(document).ready(function () {\n\n      // Submit form on enter\n      $('input').live('keydown', function (event) {\n        if (event.keyCode === 13)\n          $('#login_button').click()\n      })\n\n      if (javaRest.user.is_logged_in())\n        window.location = 'dashboard.html'\n      $('#login_button').on('click', function () {\n        javaRest.user.reset_password(window.location.search.substring(1), $('#password').val(), function (error) {\n          if (!error)\n            window.location = 'index.html'\n          else {\n            console.log(error)\n            if (error.status == '400')\n              $('#error_message').html('Password less than 8 characters or token expired.').show()\n            else if (error.status == '404')\n              $('#error_message').html('Token not found').show()\n            else if (error.status == '409')\n              $('#error_message').html('Token already used').show()\n            else\n              $('#error_message').html('Error').show()\n          }\n        })\n      })\n\n    })\n    </script>\n  </body>\n</html>"
  },
  {
    "path": "src/main/webapp/signup.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Sample Java REST Application</title>\n    <link href=\"css/styles.css\" rel=\"stylesheet\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  </head>\n  <body>\n\n    <div id=\"container\">\n\n\n      <div id=\"fb-root\"></div>\n      <div class=\"fb\" scope=\"email\" data-show-faces=\"false\" data-width=\"300\">Sign up with Facebook</div>\n      <div id=\"or\"><span>Or</span></div>\n\n        <input id=\"email\" type=\"email\" placeholder=\"Email\">\n        <input type=\"password\" id=\"password\" placeholder=\"Password\">\n  \t    <input type=\"password\" id=\"password2\" placeholder=\"Confirm Password\">\n  \t    <input type=\"text\" id=\"firstName\" placeholder=\"First Name\">\n  \t    <input type=\"checkbox\" value=\"true\" name=\"agree\" id=\"agree\"><label for=\"agree\" id=\"terms_label\">I agree to the <b><a href=\"terms.html\" target=\"_blank\">terms of service</a></b>.</label><br><br>\n\n  \t    <div id=\"error_message\"></div>\n\n  \t    <button type=\"submit\" id=\"login_button\" class=\"small_button\">Sign Up</button>\n\n  \t    <a href=\"index.html\" class=\"right_link\">Login</a>\n\n\t    <!--footer-->\n\t    <div id=\"footer\">\n      </div>\n\n    </div>\n\n    <script src=\"js/jquery-1.8.2.min.js\"></script>\n    <script src=\"js/store.js\"></script>\n    <script src=\"js/javarest.js\"></script>\n    <script src=\"js/cookie.js\"></script>\n    <script src=\"js/user.js\"></script>\n    <script type=\"text/javascript\">\n    $(document).ready(function () {\n\n\n        window.fbAsyncInit = function() {\n          FB.init({\n            appId      : '133718006790561', // App ID\n            status     : true, // check login status\n            cookie     : true, // enable cookies to allow the server to access the session\n            xfbml      : true  // parse XFBML\n          });\n\n          $('.fb').on('click', function () {\n\n             FB.login(function(response) {\n               console.log(response)\n                 if (response.authResponse) {\n\n                   javaRest.user.loginSocial(response.authResponse.accessToken, function (error) {\n                     if (error)\n                       console.log(error)\n                      else\n                       window.location = 'dashboard.html'\n                   })\n                   console.log('Welcome!  Fetching your information.... ');\n                   FB.api('/me', function(response) {\n                     console.log('Good to see you, ' + response.name + '.');\n                   });\n                 } else {\n                   console.log('User cancelled login or did not fully authorize.');\n                 }\n               });\n\n          })\n        };\n        // Load the SDK Asynchronously\n        (function(d){\n           var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];\n           if (d.getElementById(id)) {return;}\n           js = d.createElement('script'); js.id = id; js.async = true;\n           js.src = \"//connect.facebook.net/en_US/all.js\";\n           ref.parentNode.insertBefore(js, ref);\n         }(document));\n\n      // Submit form on enter\n      $('input').live('keydown', function (event) {\n        if (event.keyCode === 13)\n          $('#login_button').click()\n      })\n\n      if (javaRest.user.is_logged_in())\n        window.location = 'dashboard.html'\n      $('#login_button').on('click', function () {\n\n\n        if (!$('#agree').is(':checked'))\n          return $('#error_message').html('You must agree to the terms of service.').show()\n\n        javaRest.user.create($('#firstName').val(), $('#email').val(), $('#password').val(), '', function (error) {\n          if (!error)\n            window.location = 'dashboard.html'\n          else {\n            console.log(error)\n            if (error.status == '409')\n              $('#error_message').html('Email already registered.').show()\n            else\n              $('#error_message').html('Please fix your email address/password.').show()\n          }\n        })\n      })\n\n    })\n    </script>\n  </body>\n</html>"
  },
  {
    "path": "src/main/webapp/validate.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Email Validation</title>\n    <link href=\"css/styles.css\" rel=\"stylesheet\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\n  </head>\n  <body>\n\n    <div id=\"container\">\n\n      <!--content-->\n      <div class=\"success\" style=\"display: none;\">Your email address has been verified.<br><br><br></div>\n\n      <div class=\"error\" style=\"display: none;\">Error verifying your email address.\n      <br><br><br><button class=\"small_button\" onclick=\"window.location='/request_email.html'\">Resend verification token.</button></div>\n\n\n        <div class=\"expired\" style=\"display: none;\">Your verification link has expired.<br><br><br><button class=\"small_button\" onclick=\"window.location='/request_email.html'\">Resend verification token.</button></div>\n\n\n\n    </div>\n\n\n    <script src=\"js/jquery-1.8.2.min.js\"></script>\n    <script src=\"js/store.js\"></script>\n    <script src=\"js/javarest.js\"></script>\n    <script src=\"js/verify.js\"></script>\n    <script type=\"text/javascript\">\n\n    $(document).ready(function () {\n      javaRest.verify.verify(window.location.search.substring(1), function (error){\n        if (!error)\n          $('.success').show()\n        else if (error.status == '409') // already verified\n          $('.success').show()\n        else if (error.status == '404')\n          $('.error').show()\n        else if (error.status == '400')\n          $('.expired').show()\n        else\n          $('.error').show()\n      })\n    })\n    </script>\n  </body>\n</html>"
  },
  {
    "path": "src/test/groovy/BaseIntegrationTst.groovy",
    "content": "import groovyx.net.http.ContentType\nimport groovyx.net.http.RESTClient\nimport org.apache.commons.codec.binary.Base64\nimport org.apache.commons.codec.digest.DigestUtils\nimport org.apache.commons.lang.RandomStringUtils\n\n/**\n * User: porter\n * Date: 09/03/2012\n * Time: 17:40\n */\nabstract class BaseIntegrationTst extends GroovyTestCase {\n\n\n    protected static final String DATE_STRING = com.porterhead.rest.util.DateUtil.currentDateAsIso8061String;\n\n    private static final BASE_URL = \"http://localhost:\" + System.getProperty(\"tomcatPort\", \"8080\") + \"/java-rest/\";\n\n\n\n\n   RESTClient restClient;\n\n   RESTClient getRestClient() {\n       if (restClient == null) {\n           restClient = new RESTClient(BASE_URL);\n       }\n       return restClient;\n   }\n\n    public Object httpSignUpUser(String username, String password) {\n        return getRestClient().post(path: \"user\", contentType: ContentType.JSON, body: getCreateUserRequest(username, password))\n    }\n\n    protected Object httpGetUser(def sessionToken, def requestingUserId, def userToGet) {\n       def path = \"user/\" + userToGet\n       def nonce = generateNonce()\n       def authToken = calculateAuthToken(sessionToken, path + \",GET\", nonce)\n       def userResponse = getRestClient().get(path: path, contentType: ContentType.JSON,\n               headers: ['Authorization': requestingUserId + \":\" + authToken, \"x-java-rest-date\": DATE_STRING, \"nonce\": nonce])\n       return userResponse\n   }\n\n    public Object httpUpdateUser(userToken, userId, updateRequest) {\n        def path =  \"user/\"  + userId;\n        def nonce = generateNonce()\n       def authToken = calculateAuthToken(userToken, path +\",PUT\", nonce)\n        return getRestClient().put(path: path, contentType: ContentType.JSON, body: updateRequest,\n                headers: ['Authorization': userId + \":\" + authToken, \"x-java-rest-date\": DATE_STRING, \"nonce\": nonce])\n    }\n\n    protected Object httpDeleteUser(def userId, def sessionToken) {\n       def path = \"user/\" + userId\n        def nonce = generateNonce()\n       def authToken = calculateAuthToken(sessionToken, path + \",DELETE\", nonce)\n       def response = getRestClient().delete(path: path, contentType: ContentType.JSON,\n               headers: ['Authorization': userId + \":\" + authToken, \"x-java-rest-date\": DATE_STRING, \"nonce\": nonce])\n       return response\n   }\n\n    protected String getLastIdFromResponse(Object response) {\n       String location = response.headers.'Location'\n       return location.substring(location.lastIndexOf(\"/\") + 1 )\n    }\n\n\n    protected String getCreateUserRequest(String username, String password) {\n        return \"\"\"{\"user\":{\"emailAddress\":\"\"\" + '\\\"' + username + '\\\"' + \"\"\"},\"password\":\"\"\" + '\\\"' + password + '\\\"' + \"\"\"}\"\"\"\n    }\n\n    protected String getLoginRequest(String username, String password) {\n        return \"\"\"{\"username\":\"\"\" + '\\\"' + username + '\\\"' + \"\"\",\"password\":\"\"\" + '\\\"' + password + '\\\"' + \"\"\"}\"\"\"\n    }\n\n    protected String getNoRootUserRequest(String username, String password) {\n        return \"\"\"{\"username\":\"\"\" + '\\\"' + username + '\\\"' + \"\"\",\"password\":\"\"\" + '\\\"' + password + '\\\"' + \"\"\"}\"\"\"\n    }\n\n    protected String getEmailAddressRequest(String emailAddress) {\n        return \"{\" + getJsonNameValue(\"emailAddress\", emailAddress) + \"}\"\n    }\n\n    protected String getJsonNameValue(String name, Object value) {\n         return '\\\"' + name + '\\\":\\\"' +  value + '\\\"'\n    }\n\n\n    protected String createRandomUserName() {\n        return RandomStringUtils.randomAlphabetic(8) + \"@example.com\";\n    }\n\n    protected String calculateAuthToken(String sessionToken, String stringToHash, String nonce) {\n        byte[] digest = DigestUtils.sha256(sessionToken + \":\" + stringToHash + \",\" + DATE_STRING +\",\" + nonce);\n        return new String(Base64.encodeBase64(digest));\n    }\n\n    private String generateNonce() {\n        return RandomStringUtils.randomAlphanumeric(8);\n    }\n\n}\n"
  },
  {
    "path": "src/test/groovy/UserIntegrationTest.groovy",
    "content": "import groovyx.net.http.ContentType\nimport static org.hamcrest.Matchers.*\nimport static org.junit.Assert.assertThat\n\n/**\n * User: porter\n * Date: 09/03/2012\n * Time: 17:41\n */\nclass UserIntegrationTest extends BaseIntegrationTst {\n\n    def TEST_PASSWORD = \"password123\"\n\n\n    public void testSignUpUser() {\n\t\tdef signupResponse =  httpSignUpUser(createRandomUserName(), TEST_PASSWORD)\n\t\tassertEquals(201, signupResponse.status)\n        assertTrue(signupResponse.responseData[\"userId\"] != null)\n        assertTrue(signupResponse.responseData[\"token\"] != null)\n    }\n\n    public void testInvalidRequest() {\n\t\ttry {\n             def signupResponse =  getRestClient().post(path: \"user\", contentType: ContentType.JSON, body: getNoRootUserRequest(createRandomUserName(), TEST_PASSWORD))\n            fail(\"Expected 500 response\")\n        } catch (Exception e) {\n             assertEquals(500, e.response.status)\n        }\n    }\n\n    public void testPasswordTooShort() {\n\t\ttry {\n             def signupResponse =  getRestClient().post(path: \"user\", contentType: ContentType.JSON, body: getCreateUserRequest(createRandomUserName(), \"1234\"))\n            fail(\"Expected 400 response\")\n        } catch (Exception e) {\n             assertEquals(400, e.response.status)\n        }\n    }\n\n    public void testUsernameAlreadyExists() {\n        try {\n            String username = createRandomUserName();\n            getRestClient().post(path: \"user\", contentType: ContentType.JSON, body: getCreateUserRequest(username, TEST_PASSWORD))\n            getRestClient().post(path: \"user\", contentType: ContentType.JSON, body: getCreateUserRequest(username, TEST_PASSWORD))\n            fail(\"Expected 409 response\")\n        } catch (Exception e) {\n            assertEquals(409, e.response.status)\n        }\n    }\n\n    public void testLogin() {\n        def username = createRandomUserName()\n        getRestClient().post(path: \"user\", contentType: ContentType.JSON, body: getCreateUserRequest(username, TEST_PASSWORD))\n        def loginResponse = getRestClient().post(path: \"user/login\", contentType: ContentType.JSON, body: getLoginRequest(username, TEST_PASSWORD))\n        assertEquals(200, loginResponse.status)\n    }\n\n    public void testInvalidUsernameOnLogin() {\n        try {\n            def username = createRandomUserName()\n            getRestClient().post(path: \"user\", contentType: ContentType.JSON, body: getCreateUserRequest(username, TEST_PASSWORD))\n            getRestClient().post(path: \"user/login\", contentType: ContentType.JSON, body: getLoginRequest(createRandomUserName(), TEST_PASSWORD))\n            fail(\"Expected 401 response\")\n        } catch (Exception e) {\n            assertEquals(401, e.response.status)\n        }\n    }\n\n    public void testInvalidPasswordOnLogin() {\n        try {\n            def username = createRandomUserName()\n            getRestClient().post(path: \"user\", contentType: ContentType.JSON, body: getCreateUserRequest(username, TEST_PASSWORD))\n            getRestClient().post(path: \"user/login\", contentType: ContentType.JSON, body: getLoginRequest(username, \"12345678\"))\n            fail(\"Expected 401 response\")\n        } catch (Exception e) {\n            assertEquals(401, e.response.status)\n        }\n    }\n\n\n    public void testGetUser() {\n         //set up user data\n        def userResponse = httpSignUpUser(createRandomUserName(), \"password\")\n        def userId = userResponse.responseData[\"userId\"]\n        def userToken = userResponse.responseData[\"token\"]\n        def getUserResponse = httpGetUser(userToken, userId, userId)\n        assertEquals(200, getUserResponse.status)\n        def user = getUserResponse.responseData\n        assertThat(user.verified, is(false))\n    }\n\n    public void testUpdateUser() {\n          //set up user data\n        def userResponse = httpSignUpUser(createRandomUserName(), \"password\")\n        def userId = userResponse.responseData[\"userId\"]\n        def userToken = userResponse.responseData[\"token\"]\n        def updateRequest = \"{\" + getJsonNameValue(\"firstName\", \"FOO\") + \",\" + getJsonNameValue(\"lastName\", \"BAR\") + \",\" +\n                getJsonNameValue(\"emailAddress\", \"foobar@example.com\") +\"}\"\n        def updateUserResponse = httpUpdateUser(userToken, userId, updateRequest)\n        assertEquals(200, updateUserResponse.status)\n        def getUserResponse = httpGetUser(userToken, userId, userId)\n        assertEquals(200, getUserResponse.status)\n        def user = getUserResponse.responseData\n        assertThat(user.verified, is(false))\n        assertThat(user.firstName, is(\"FOO\"))\n        assertThat(user.lastName, is(\"BAR\"))\n        assertThat(user.emailAddress, is(\"foobar@example.com\"))\n    }\n\n    public void testUserAttemptsToUpdateAnotherUser() {\n        //set up user1 data\n        def userResponse = httpSignUpUser(createRandomUserName(), \"password\")\n        def userId = userResponse.responseData[\"userId\"]\n        def userToken = userResponse.responseData[\"token\"]\n        //set up user2 data\n        def userResponse2 = httpSignUpUser(createRandomUserName(), \"password\")\n        def userId2 = userResponse2.responseData[\"userId\"]\n        def updateRequest = \"{\" + getJsonNameValue(\"firstName\", \"FOO\") + \"}\"\n        try {\n            def updateUserResponse = httpUpdateUser(userToken, userId2, updateRequest)\n            fail(\"Expected 403 response\")\n        } catch (Exception e) {\n            assertEquals(403, e.response.status)\n        }\n\n    }\n\n\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/authorization/BaseAuthorizationTst.java",
    "content": "package com.porterhead.rest.authorization;\n\nimport com.porterhead.rest.authorization.impl.SessionTokenAuthorizationService;\nimport com.porterhead.rest.config.ApplicationConfig;\nimport com.porterhead.rest.user.UserRepository;\nimport com.porterhead.rest.user.domain.AuthorizationToken;\nimport com.porterhead.rest.user.domain.User;\nimport com.porterhead.rest.util.DateUtil;\nimport org.junit.Before;\n\nimport static org.mockito.Matchers.eq;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\n/**\n * @version 1.0\n * @author: Iain Porter\n * @since 29/01/2013\n */\npublic class BaseAuthorizationTst {\n\n    protected static String AUTH_TOKEN;\n    protected static final User USER = new User();\n    {\n        USER.setAuthorizationToken(new AuthorizationToken(USER));\n        AUTH_TOKEN = USER.getAuthorizationToken().getToken();\n    }\n\n    protected AuthorizationService authorizationService;\n    protected UserRepository userRepository;\n    protected ApplicationConfig applicationConfig;\n\n    @Before\n    public void setUp() {\n         userRepository = mock(UserRepository.class);\n         when(userRepository.findByUuid(eq(USER.getUuid().toString()))).thenReturn(USER);\n         when(userRepository.findBySession(eq(AUTH_TOKEN))).thenReturn(USER);\n         applicationConfig = mock(ApplicationConfig.class);\n         when(applicationConfig.getSessionDateOffsetInMinutes()).thenReturn(30);\n         authorizationService = new SessionTokenAuthorizationService(userRepository);\n    }\n\n    protected AuthorizationRequestContext getAuthorizationRequest(String hashedToken, String requestString, String nonce) {\n        return getAuthorizationRequest(hashedToken, requestString, DateUtil.getCurrentDateAsIso8061String(), nonce);\n    }\n\n    protected AuthorizationRequestContext getAuthorizationRequest(String hashedToken, String requestString, String dateString, String nonce) {\n        AuthorizationRequestContext authRequest = new AuthorizationRequestContext(requestString, \"POST\", dateString, nonce, hashedToken);\n        return authRequest;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/authorization/RequestSigningAuthorizationServiceTest.java",
    "content": "package com.porterhead.rest.authorization;\n\nimport com.porterhead.rest.authorization.impl.RequestSigningAuthorizationService;\nimport com.porterhead.rest.user.UserService;\nimport com.porterhead.rest.user.api.ExternalUser;\nimport com.porterhead.rest.user.exception.AuthorizationException;\nimport com.porterhead.rest.util.DateUtil;\nimport org.apache.commons.codec.binary.Base64;\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.hamcrest.Matchers;\nimport org.joda.time.DateTime;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.Assert.assertThat;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\n/**\n * User: porter\n * Date: 15/03/2012\n * Time: 11:41\n */\npublic class RequestSigningAuthorizationServiceTest extends BaseAuthorizationTst {\n\n    private AuthorizationService authorizationService;\n    private UserService userService;\n\n    @Before\n    public void setUp() {\n         super.setUp();\n         userService = mock(UserService.class);\n         authorizationService = new RequestSigningAuthorizationService(userRepository, userService, applicationConfig);\n    }\n\n    @Test\n    public void authorizeUser() throws Exception {\n        String dateString = DateUtil.getCurrentDateAsIso8061String();\n        String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(USER.getAuthorizationToken().getToken() + \":user/555,POST,\" + dateString + \",123\")));\n        ExternalUser user = authorizationService.authorize(getAuthorizationRequest(USER.getUuid().toString() + \":\" + hashedToken, \"user/555\", dateString, \"123\"));\n        assertThat(user.getId(), is(USER.getUuid().toString()));\n    }\n\n    @Test (expected = AuthorizationException.class)\n    public void invalidUnEncodedRequest() {\n        String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(AUTH_TOKEN + \":hash123,123\")));\n        authorizationService.authorize(getAuthorizationRequest(USER.getUuid().toString() + \":\" + hashedToken, \"hash123,1234\", \"123\"));\n    }\n\n    @Test (expected = AuthorizationException.class)\n    public void invalidSessionToken() {\n        String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(\"INVALID-SESSION-TOKEN:abcdef\")));\n        authorizationService.authorize(getAuthorizationRequest(USER.getUuid().toString() + \":\" + hashedToken, \"abcdef\", \"123\"));\n    }\n\n    @Test\n    public void missingNonce() {\n        String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(\"INVALID-SESSION-TOKEN:abcdef\")));\n        ExternalUser user = authorizationService.authorize(getAuthorizationRequest(USER.getUuid().toString() + \":\" + hashedToken, \"abcdef\", null));\n        assertThat(user, is(Matchers.<Object>nullValue()));\n    }\n\n    @Test (expected = AuthorizationException.class)\n    public void wrongNonce() {\n        String dateString = DateUtil.getCurrentDateAsIso8061String();\n        String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(USER.getAuthorizationToken().getToken() + \":hash123,123,POST,\" + dateString + \",123\")));\n        authorizationService.authorize(getAuthorizationRequest(USER.getUuid().toString() + \":\" + hashedToken, \"hash123,123\", dateString, \"567\"));\n    }\n\n    @Test (expected = AuthorizationException.class)\n    public void dateOutOfRange() {\n        when(applicationConfig.getSessionDateOffsetInMinutes()).thenReturn(5);\n        String dateString = DateUtil.getDateDateAsIso8061String(new DateTime().minusMinutes(20));\n        String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(USER.getAuthorizationToken().getToken() + \":hash123,123,POST,\" + dateString + \",123\")));\n        authorizationService.authorize(getAuthorizationRequest(USER.getUuid().toString() + \":\" + hashedToken, \"hash123,123\", dateString, \"567\"));\n    }\n\n    @Test\n    public void nullSessionToken() {\n        ExternalUser user = authorizationService.authorize(getAuthorizationRequest(null,  \"abcdef\", \"123\"));\n        assertThat(user, is(Matchers.<Object>nullValue()));\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/authorization/SecurityContextTest.java",
    "content": "package com.porterhead.rest.authorization;\n\nimport com.porterhead.rest.authorization.exception.InvalidAuthorizationHeaderException;\nimport com.porterhead.rest.user.api.ExternalUser;\nimport com.porterhead.rest.authorization.impl.SecurityContextImpl;\nimport com.porterhead.rest.user.domain.Role;\nimport com.porterhead.rest.user.domain.User;\nimport org.junit.Test;\n\nimport javax.ws.rs.core.SecurityContext;\n\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.Assert.assertThat;\n\n/**\n * User: porter\n * Date: 18/03/2012\n * Time: 11:46\n */\npublic class SecurityContextTest {\n\n    @Test\n    public void validRole() {\n        SecurityContext context = createSecurityContext(Role.authenticated);\n        assertThat(context.isUserInRole(Role.authenticated.name()), is(true));\n    }\n\n    @Test\n    public void invalidRole() {\n        SecurityContext context = createSecurityContext(Role.authenticated);\n        assertThat(context.isUserInRole(Role.administrator.name()), is(false));\n    }\n\n    @Test\n    public void allowAnonymousRole() {\n        SecurityContext context = createSecurityContext(Role.authenticated);\n        assertThat(context.isUserInRole(\"anonymous\"), is(true));\n    }\n\n    @Test\n    public void caseDoesNotMatter() {\n        SecurityContext context = createSecurityContext(Role.authenticated);\n        assertThat(context.isUserInRole(Role.authenticated.name().toUpperCase()), is(true));\n    }\n\n    @Test(expected = InvalidAuthorizationHeaderException.class)\n    public void authenticationFailure() {\n        User user = new User();\n        user.setRole(Role.authenticated);\n        ExternalUser externalUser = null;\n        SecurityContext context = new SecurityContextImpl(externalUser);\n        context.isUserInRole(Role.authenticated.name());\n    }\n\n    @Test(expected = InvalidAuthorizationHeaderException.class)\n    public void nullSession() {\n        SecurityContext context = new SecurityContextImpl(null);\n        context.isUserInRole(Role.authenticated.name());\n    }\n\n\n    private SecurityContext createSecurityContext(Role role) {\n        User user = new User();\n        user.setRole(role);\n        ExternalUser externalUser = new ExternalUser(user);\n        SecurityContext context = new SecurityContextImpl(externalUser);\n        return context;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/authorization/SessionTokenAuthorizationServiceTest.java",
    "content": "package com.porterhead.rest.authorization;\n\nimport com.porterhead.rest.authorization.impl.SessionTokenAuthorizationService;\nimport com.porterhead.rest.user.api.ExternalUser;\nimport com.porterhead.rest.user.exception.AuthorizationException;\nimport org.hamcrest.Matchers;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.Assert.assertThat;\n\n/**\n * @version 1.0\n * @author: Iain Porter\n * @since 29/01/2013\n */\npublic class SessionTokenAuthorizationServiceTest extends BaseAuthorizationTst {\n\n\n    @Before\n    public void setUp() {\n        super.setUp();\n        authorizationService = new SessionTokenAuthorizationService(userRepository);\n    }\n\n    @Test\n    public void authorizeUser() throws Exception {\n        ExternalUser user = authorizationService.authorize(getAuthorizationRequest(AUTH_TOKEN, \"user/123\", null));\n        assertThat(user.getId(), is(USER.getUuid().toString()));\n    }\n\n    @Test (expected = AuthorizationException.class)\n    public void invalidSessionToken() {\n        authorizationService.authorize(getAuthorizationRequest(\"abc\", \"abcdef\", \"123\"));\n    }\n\n    @Test\n    public void noSessionToken() {\n        ExternalUser user = authorizationService.authorize(getAuthorizationRequest(null, \"abcdef\", null));\n        assertThat(user, is(Matchers.<Object>nullValue()));\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/filter/SecurityContextFilterTest.java",
    "content": "package com.porterhead.rest.filter;\n\nimport com.porterhead.rest.config.ApplicationConfig;\nimport com.porterhead.rest.user.UserRepository;\nimport com.porterhead.rest.user.UserService;\nimport com.porterhead.rest.user.api.ExternalUser;\nimport com.porterhead.rest.user.domain.AuthorizationToken;\nimport com.porterhead.rest.user.domain.User;\nimport com.porterhead.rest.user.exception.AuthorizationException;\nimport com.sun.jersey.spi.container.ContainerRequest;\nimport org.apache.commons.codec.binary.Base64;\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.joda.time.DateTime;\nimport org.joda.time.format.ISODateTimeFormat;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.invocation.InvocationOnMock;\nimport org.mockito.stubbing.Answer;\n\nimport javax.ws.rs.core.SecurityContext;\n\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.nullValue;\nimport static org.junit.Assert.assertThat;\nimport static org.mockito.Matchers.any;\nimport static org.mockito.Mockito.*;\n\n\npublic class SecurityContextFilterTest {\n\n    private SecurityContextFilter filter;\n    private UserRepository userRepository;\n    private UserService userService;\n    private ContainerRequest containerRequest;\n    private ApplicationConfig applicationConfig;\n\n    @Before\n    public void setUp() {\n        userRepository = mock(UserRepository.class);\n        userService = mock(UserService.class);\n        containerRequest = mock(ContainerRequest.class);\n        applicationConfig = mock(ApplicationConfig.class);\n        when(applicationConfig.getSessionDateOffsetInMinutes()).thenReturn(30);\n        when(applicationConfig.requireSignedRequests()).thenReturn(true);\n        filter = new SecurityContextFilter(userRepository, userService, applicationConfig);\n\n    }\n\n    @Test\n    public void noHeadersInRequest() {\n        when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_AUTHORIZATION)).thenReturn(null);\n        when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_AUTHORIZATION)).thenReturn(null);\n        containerRequest = filter.filter(containerRequest);\n        assertThat(containerRequest.getUserPrincipal(), is(nullValue()));\n    }\n\n    @Test\n    public void validAuthHeaders() {\n        setUpValidRequest();\n        containerRequest = filter.filter(containerRequest);\n    }\n\n    private void setUpValidRequest() {\n        User user = new User();\n        user.setAuthorizationToken(new AuthorizationToken(user));\n        final ExternalUser externalUser = new ExternalUser(user);\n        String dateString = new DateTime().toString(ISODateTimeFormat.dateTimeNoMillis());\n        String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(user.getAuthorizationToken().getToken() + \":user/555,POST,\" + dateString + \",123\")));\n        when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_AUTHORIZATION)).thenReturn(externalUser.getId() + \":\" + hashedToken);\n        when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_DATE)).thenReturn(dateString);\n        when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_NONCE)).thenReturn(\"123\");\n        when(containerRequest.getPath()).thenReturn(\"user/555\");\n        when(containerRequest.getMethod()).thenReturn(\"POST\");\n        when(userRepository.findByUuid(user.getUuid().toString())).thenReturn(user);\n        doAnswer(new Answer() {\n\n            public Object answer(InvocationOnMock invocation) throws Throwable {\n                SecurityContext context = (SecurityContext) invocation.getArguments()[0];\n                ExternalUser user = (ExternalUser) context.getUserPrincipal();\n                assertThat(user.getId(), is(externalUser.getId()));\n                return null;\n            }\n        }).when(containerRequest).setSecurityContext(any(SecurityContext.class));\n    }\n\n    @Test (expected = AuthorizationException.class)\n    public void dateHeaderIsOutOfRange() {\n        User user = new User();\n        final ExternalUser externalUser = new ExternalUser(user);\n        when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_AUTHORIZATION)).thenReturn(externalUser.getId() + \":123\");\n        when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_DATE)).thenReturn(new DateTime().minusMinutes(10).toString(ISODateTimeFormat.dateTimeNoMillis()));\n        when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_NONCE)).thenReturn(\"123\");\n        when(applicationConfig.getSessionDateOffsetInMinutes()).thenReturn(5);\n        containerRequest = filter.filter(containerRequest);\n    }\n\n    @Test (expected = AuthorizationException.class)\n    public void duplicateNonce() throws Exception {\n        setUpValidRequest();\n        filter.filter(containerRequest);\n        Thread.sleep(20); //tolerance limit\n        //submit same request again with same nonce value\n        filter.filter(containerRequest);\n    }\n\n\n\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/mock/AppMockConfiguration.java",
    "content": "package com.porterhead.rest.mock;\n\nimport com.porterhead.rest.gateway.EmailServicesGateway;\nimport com.porterhead.rest.user.UserService;\nimport com.porterhead.rest.user.VerificationTokenService;\nimport com.porterhead.rest.user.mail.MailSenderService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.social.connect.ConnectionFactoryLocator;\n\nimport static org.mockito.Mockito.mock;\n\n/**\n * User: porter\n * Date: 07/05/2012\n * Time: 14:47\n */\n@Configuration\n@PropertySource(\"classpath:properties/app.properties\")\npublic class AppMockConfiguration {\n\n    @Autowired\n    private Environment environment;\n\n    public Environment environment() {\n        return environment;\n    }\n\n\n    @Bean\n    public UserService userService() {\n        UserService userService = mock(UserService.class);\n        return userService;\n    }\n\n    @Bean\n    public VerificationTokenService verificationTokenService() {\n        VerificationTokenService tokenService = mock(VerificationTokenService.class);\n        return tokenService;\n    }\n\n    @Bean\n    public MailSenderService mailSenderService() {\n        MailSenderService mailSenderService = mock(MailSenderService.class);\n        return mailSenderService;\n    }\n\n    @Bean\n    public EmailServicesGateway emailServicesGateway() {\n        EmailServicesGateway emailServicesGateway = mock(EmailServicesGateway.class);\n        return emailServicesGateway;\n    }\n\n    @Bean\n    public ConnectionFactoryLocator connectionFactoryLocator() {\n        ConnectionFactoryLocator connectionFactoryLocator =  mock(ConnectionFactoryLocator.class);\n        return connectionFactoryLocator;\n    }\n\n}\n\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/resource/BaseResourceTst.java",
    "content": "package com.porterhead.rest.resource;\n\nimport com.porterhead.rest.user.UserService;\nimport com.porterhead.rest.user.VerificationTokenService;\nimport com.porterhead.rest.user.api.LoginRequest;\nimport com.porterhead.rest.user.api.PasswordRequest;\nimport com.porterhead.rest.user.builder.ExternalUserBuilder;\nimport com.porterhead.rest.gateway.EmailServicesGateway;\nimport com.porterhead.rest.mock.AppMockConfiguration;\nimport com.porterhead.rest.user.domain.Role;\nimport com.porterhead.rest.user.domain.AuthorizationToken;\nimport com.porterhead.rest.user.api.CreateUserRequest;\nimport com.porterhead.rest.user.api.UpdateUserRequest;\nimport com.porterhead.rest.user.domain.User;\nimport com.sun.jersey.test.framework.JerseyTest;\nimport com.sun.jersey.test.framework.WebAppDescriptor;\nimport org.junit.Before;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.core.env.Environment;\nimport org.springframework.social.connect.ConnectionFactoryLocator;\nimport org.springframework.test.context.ActiveProfiles;\n\n/**\n * User: porter\n * Date: 04/05/2012\n * Time: 19:09\n */\n@ActiveProfiles(profiles = \"dev\")\npublic class BaseResourceTst extends JerseyTest {\n\n    public BaseResourceTst(WebAppDescriptor descriptor) {\n        super(descriptor);\n    }\n\n    protected static User TEST_USER;\n    protected static String FIRST_NAME = \"Test\";\n    protected static String LAST_NAME = \"User\";\n    protected static String EMAIL_ADDRESS = \"test@example.com\";\n    protected static String USERNAME = \"testuser\";\n    protected static String PASSWORD = \"password\";\n    protected static PasswordRequest PASSWORD_REQUEST;\n\n    {\n        TEST_USER = new User();\n        TEST_USER.setFirstName(FIRST_NAME);\n        TEST_USER.setLastName(LAST_NAME);\n        TEST_USER.setEmailAddress(EMAIL_ADDRESS);\n        TEST_USER.setRole(Role.authenticated);\n    }\n\n    {\n        PASSWORD_REQUEST = new PasswordRequest();\n        PASSWORD_REQUEST.setPassword(PASSWORD);\n    }\n\n    protected static AuthorizationToken AUTH_TOKEN;\n    {\n        TEST_USER.setAuthorizationToken(new AuthorizationToken(TEST_USER));\n        AUTH_TOKEN = TEST_USER.getAuthorizationToken();\n    }\n\n    protected static ApplicationContext appCtx;\n\n\n    public static class ApplicationContextAccess implements ApplicationContextAware {\n        public void setApplicationContext(ApplicationContext ctx) {\n            appCtx = ctx;\n        }\n    }\n\n    protected UserService userService;\n    protected VerificationTokenService verificationTokenService;\n    protected ConnectionFactoryLocator connectionFactoryLocator;\n    protected EmailServicesGateway emailServicesGateway;\n\n\n    protected Environment environment;\n\n    /**\n     * Relies on component scanning of mock services from {@link com.porterhead.rest.mock.AppMockConfiguration}\n     */\n    @Before\n    public void setUpMocks() {\n        AppMockConfiguration config = appCtx.getBean(AppMockConfiguration.class);\n        userService = config.userService();\n        verificationTokenService = config.verificationTokenService();\n        connectionFactoryLocator = (ConnectionFactoryLocator) appCtx.getBean(\"connectionFactoryLocator\");\n        environment = config.environment();\n        emailServicesGateway = config.emailServicesGateway();\n    }\n\n    protected CreateUserRequest createSignupRequest() {\n        return new CreateUserRequest(ExternalUserBuilder.create().withEmailAddress(TEST_USER.getEmailAddress())\n                .withFirstName(TEST_USER.getFirstName()).withLastName(TEST_USER.getLastName()).build(), PASSWORD_REQUEST);\n    }\n\n\n    protected LoginRequest createLoginRequest() {\n        LoginRequest request = new LoginRequest();\n        request.setUsername(TEST_USER.getEmailAddress());\n        request.setPassword(PASSWORD);\n        return request;\n    }\n\n    protected UpdateUserRequest createUpdateUserRequest(String emailAddress) {\n        UpdateUserRequest request = new UpdateUserRequest();\n        request.setEmailAddress(emailAddress);\n        return request;\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/resource/ConsumerSimpleSecurityFilter.java",
    "content": "package com.porterhead.rest.resource;\n\nimport com.porterhead.rest.user.domain.User;\n\n/**\n * User: porter\n * Date: 08/05/2012\n * Time: 09:18\n */\npublic class ConsumerSimpleSecurityFilter extends SimpleSecurityFilter {\n\n    @Override\n    User getUser() {\n        return BaseResourceTst.TEST_USER;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/resource/HealthCheckResourceTest.java",
    "content": "package com.porterhead.rest.resource;\n\nimport com.sun.jersey.api.client.ClientResponse;\nimport com.sun.jersey.spi.spring.container.servlet.SpringServlet;\nimport com.sun.jersey.test.framework.WebAppDescriptor;\nimport org.junit.Test;\nimport org.springframework.web.context.ContextLoaderListener;\n\nimport javax.ws.rs.core.MediaType;\n\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.Assert.assertThat;\n\n/**\n * User: porter\n * Date: 08/05/2012\n * Time: 09:29\n */\npublic class HealthCheckResourceTest extends BaseResourceTst {\n\n    public HealthCheckResourceTest() {\n        super(new WebAppDescriptor.Builder()\n                .contextPath(\"spring\")\n                .servletClass(SpringServlet.class)\n                .contextParam(\"contextConfigLocation\", \"classpath:integration-test-context.xml\")\n                .contextParam(\"spring.profiles.active\", \"dev\")\n                .contextListenerClass(ContextLoaderListener.class)\n                .build());\n    }\n\n    @Test\n    public void check() {\n        ClientResponse response = super.resource().path(\"/healthcheck\").accept(MediaType.TEXT_PLAIN).get(ClientResponse.class);\n        assertThat(response.getStatus(), is(200));\n        assertThat(response.getEntity(String.class), is(\"Running version \" + environment.getProperty(\"application.version\")));\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/resource/SimpleSecurityFilter.java",
    "content": "package com.porterhead.rest.resource;\n\nimport com.porterhead.rest.user.api.ExternalUser;\nimport com.porterhead.rest.authorization.impl.SecurityContextImpl;\nimport com.porterhead.rest.user.domain.User;\nimport com.sun.jersey.spi.container.ContainerRequest;\nimport com.sun.jersey.spi.container.ContainerRequestFilter;\n\n/**\n * User: porter\n * Date: 08/05/2012\n * Time: 09:01\n */\npublic abstract class SimpleSecurityFilter implements ContainerRequestFilter {\n\n    public ContainerRequest filter(ContainerRequest request) {\n        ExternalUser externalUser = new ExternalUser(getUser());\n        request.setSecurityContext(new SecurityContextImpl(externalUser));\n        return request;\n    }\n\n    abstract User getUser();\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/user/BaseServiceTest.java",
    "content": "package com.porterhead.rest.user;\n\n\nimport com.porterhead.rest.config.ApplicationConfig;\nimport com.porterhead.rest.user.api.AuthenticatedUserToken;\nimport com.porterhead.rest.user.api.CreateUserRequest;\nimport com.porterhead.rest.user.api.ExternalUser;\nimport com.porterhead.rest.user.api.PasswordRequest;\nimport com.porterhead.rest.user.builder.ExternalUserBuilder;\nimport com.porterhead.rest.user.domain.Role;\nimport org.apache.commons.lang.RandomStringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\n\n/**\n * User: porter\n * Date: 04/04/2012\n * Time: 14:21\n */\npublic class BaseServiceTest {\n\n    @Autowired\n    public UserService userService;\n\n    @Autowired\n    public UserRepository userRepository;\n\n    @Autowired\n    public ApplicationConfig applicationConfig;\n\n\n    protected AuthenticatedUserToken createUserWithRandomUserName(Role role) {\n        CreateUserRequest request = getDefaultCreateUserRequest();\n        return userService.createUser(request, role);\n    }\n\n    protected CreateUserRequest getDefaultCreateUserRequest() {\n        CreateUserRequest request = new CreateUserRequest();\n        request.setUser(getUser());\n        request.setPassword(new PasswordRequest(\"password\"));\n        return request;\n    }\n\n    protected ExternalUser getUser() {\n        ExternalUser user = ExternalUserBuilder.create().withFirstName(\"John\")\n                .withLastName(\"Smith\")\n                .withEmailAddress(createRandomEmailAddress())\n                .build();\n        return user;\n    }\n\n    protected String createRandomEmailAddress() {\n        return RandomStringUtils.randomAlphabetic(8) + \"@example.com\";\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/user/MailSenderServiceTest.java",
    "content": "package com.porterhead.rest.user;\n\n\nimport com.porterhead.rest.config.ApplicationConfig;\nimport com.porterhead.rest.user.api.AuthenticatedUserToken;\nimport com.porterhead.rest.user.domain.Role;\nimport com.porterhead.rest.user.domain.User;\nimport com.porterhead.rest.user.domain.VerificationToken;\nimport com.porterhead.rest.user.mail.MailSenderService;\nimport com.porterhead.rest.user.mail.MockJavaMailSender;\nimport com.porterhead.rest.user.mail.impl.MailSenderServiceImpl;\nimport org.apache.commons.codec.binary.Base64;\nimport org.apache.velocity.app.VelocityEngine;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.ActiveProfiles;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.internet.MimeMessage;\nimport java.io.IOException;\nimport java.util.List;\n\nimport static org.hamcrest.Matchers.containsString;\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.Assert.assertThat;\n\n/**\n * @author: Iain Porter\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(\"classpath:META-INF/spring/root-context.xml\")\n@ActiveProfiles(profiles = \"dev\")\n@Transactional\npublic class MailSenderServiceTest extends BaseServiceTest {\n\n    private MailSenderService mailService;\n\n    private MockJavaMailSender mailSender;\n\n    @Autowired\n    VelocityEngine velocityEngine;\n\n    @Autowired\n    ApplicationConfig config;\n\n    @Before\n    public void setUpServices() {\n        mailSender = new MockJavaMailSender();\n        mailService = new MailSenderServiceImpl(mailSender, velocityEngine);\n        ((MailSenderServiceImpl)mailService).setConfig(config);\n    }\n\n\n    @Test\n    public void sendVerificationEmail() throws Exception {\n        AuthenticatedUserToken userToken = createUserWithRandomUserName(Role.authenticated);\n        User user = userRepository.findByUuid(userToken.getUserId());\n        VerificationToken token = new VerificationToken(user,\n                VerificationToken.VerificationTokenType.emailVerification, 120);\n        mailService.sendVerificationEmail(new EmailServiceTokenModel(user, token, config.getHostNameUrl()));\n        assertOnMailResult(user, token);\n    }\n\n    @Test\n    public void sendRegistrationEmail() throws Exception {\n        AuthenticatedUserToken userToken = createUserWithRandomUserName(Role.authenticated);\n        User user = userRepository.findByUuid(userToken.getUserId());\n        VerificationToken token = new VerificationToken(user,\n                VerificationToken.VerificationTokenType.emailRegistration, 120);\n        mailService.sendRegistrationEmail(new EmailServiceTokenModel(user, token, config.getHostNameUrl()));\n        assertOnMailResult(user, token);\n    }\n\n    @Test\n    public void sendLostPasswordEmail() throws Exception {\n        AuthenticatedUserToken userToken = createUserWithRandomUserName(Role.authenticated);\n        User user = userRepository.findByUuid(userToken.getUserId());\n        VerificationToken token = new VerificationToken(user,\n                VerificationToken.VerificationTokenType.lostPassword, 120);\n        mailService.sendLostPasswordEmail(new EmailServiceTokenModel(user, token, config.getHostNameUrl()));\n        assertOnMailResult(user, token);\n    }\n\n    private void assertOnMailResult(User user, VerificationToken token) throws MessagingException, IOException {\n        List<MimeMessage> messages = mailSender.getMessages();\n        assertThat(messages.size(), is(1));\n        MimeMessage message = messages.get(0);\n        assertThat(message.getAllRecipients()[0].toString(), is((user.getEmailAddress())));\n        Multipart multipart = (Multipart)message.getContent();\n        String content = (String)multipart.getBodyPart(0).getContent();\n        assertThat(content, containsString(new String(Base64.encodeBase64(token.getToken().getBytes()))));\n    }\n\n\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/user/UserServiceTest.java",
    "content": "package com.porterhead.rest.user;\n\nimport com.porterhead.rest.exception.ValidationException;\nimport com.porterhead.rest.user.api.*;\nimport com.porterhead.rest.user.builder.ExternalUserBuilder;\nimport com.porterhead.rest.user.domain.AuthorizationToken;\nimport com.porterhead.rest.user.domain.Role;\nimport com.porterhead.rest.user.domain.User;\nimport com.porterhead.rest.user.exception.AuthenticationException;\nimport com.porterhead.rest.user.exception.AuthorizationException;\nimport com.porterhead.rest.user.exception.DuplicateUserException;\nimport com.porterhead.rest.user.exception.UserNotFoundException;\nimport org.apache.commons.lang.RandomStringUtils;\nimport org.hamcrest.Matchers;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.test.context.ActiveProfiles;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.Date;\n\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.not;\nimport static org.junit.Assert.assertThat;\n\n/**\n * @author Iain Porter\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(\"classpath:META-INF/spring/root-context.xml\")\n@ActiveProfiles(profiles = \"dev\")\n@Transactional\npublic class UserServiceTest  extends BaseServiceTest {\n\n\n    @Test\n    public void createValidUser() throws Exception {\n        AuthenticatedUserToken userToken = createUserWithRandomUserName(Role.authenticated);\n        assertThat(userToken.getUserId(), is(not(Matchers.<Object>nullValue())));\n        assertThat(userToken.getToken(), is(not(Matchers.<Object>nullValue())));\n    }\n\n    @Test\n    public void createDefaultUser() throws Exception {\n        AuthenticatedUserToken userToken = userService.createUser(Role.authenticated);\n        assertThat(userToken.getUserId(), is(not(Matchers.<Object>nullValue())));\n        assertThat(userToken.getToken(), is(not(Matchers.<Object>nullValue())));\n\n    }\n\n    @Test(expected = DuplicateUserException.class)\n    public void duplicateUser() throws Exception {\n        CreateUserRequest request = getDefaultCreateUserRequest();\n        userService.createUser(request, Role.authenticated);\n        //do again with same request\n        userService.createUser(request, Role.authenticated);\n\n    }\n\n    @Test(expected = ValidationException.class)\n    public void nullPasswordRequest() {\n        CreateUserRequest request = new CreateUserRequest();\n        request.setUser(getUser());\n        request.setPassword(new PasswordRequest());\n        userService.createUser(request, Role.authenticated);\n    }\n\n    @Test(expected = ValidationException.class)\n    public void badNameRequest() {\n        CreateUserRequest request = new CreateUserRequest();\n        ExternalUser user = getUser();\n        user.setFirstName(RandomStringUtils.randomAlphanumeric(101));\n        request.setUser(user);\n        request.setPassword(new PasswordRequest());\n        userService.createUser(request, Role.authenticated);\n    }\n\n    @Test(expected = ValidationException.class)\n    public void nullEmailAndUsernameRequest() {\n        CreateUserRequest request = new CreateUserRequest();\n        ExternalUser user = ExternalUserBuilder.create().withFirstName(\"John\")\n                .withLastName(\"Smith\")\n                .build();\n        request.setUser(user);\n        request.setPassword(new PasswordRequest(\"password\"));\n        userService.createUser(request, Role.authenticated);\n    }\n\n    @Test\n    public void validLoginWithEmailAddress() throws Exception {\n        CreateUserRequest request = getDefaultCreateUserRequest();\n        AuthenticatedUserToken createdUserToken = userService.createUser(request, Role.authenticated);\n        LoginRequest loginRequest = new LoginRequest();\n        loginRequest.setUsername(request.getUser().getEmailAddress());\n        loginRequest.setPassword(request.getPassword().getPassword());\n        AuthenticatedUserToken loginUserToken = userService.login(loginRequest);\n        assertThat(loginUserToken.getUserId(), is(createdUserToken.getUserId()));\n        User user = userRepository.findByUuid(loginUserToken.getUserId());\n        assertThat(user.getAuthorizationToken().getToken(), is(createdUserToken.getToken()));\n        //check that the same token is returned\n        assertThat(user.getAuthorizationToken().getToken(), is(loginUserToken.getToken()));\n        assertThat(user.isVerified(), is(false));\n\n    }\n\n    @Test\n    public void multipleLoginsGetSameAuthToken() {\n        CreateUserRequest request = getDefaultCreateUserRequest();\n        AuthenticatedUserToken createdUserToken = userService.createUser(request, Role.authenticated);\n        LoginRequest loginRequest = new LoginRequest();\n        loginRequest.setUsername(request.getUser().getEmailAddress());\n        loginRequest.setPassword(request.getPassword().getPassword());\n        String token1 = userService.login(loginRequest).getToken();\n        String token2 =  userService.login(loginRequest).getToken();\n\n        assertThat(token1, is(token2));\n    }\n\n    @Test(expected = ValidationException.class)\n    public void invalidLoginRequestNullPassword() {\n        LoginRequest request = new LoginRequest();\n        request.setUsername(createRandomEmailAddress());\n        userService.login(request);\n    }\n\n    @Test(expected = ValidationException.class)\n    public void invalidLoginRequestNullEmailAddress() {\n        LoginRequest request = new LoginRequest();\n        request.setPassword(\"password\");\n        userService.login(request);\n    }\n\n    @Test(expected = DuplicateUserException.class)\n    public void emailAddressAlreadyExists() {\n        CreateUserRequest request = getDefaultCreateUserRequest();\n        userService.createUser(request, Role.authenticated);\n        userService.createUser(request, Role.authenticated);\n    }\n\n    @Test(expected = AuthenticationException.class)\n    public void invalidPassword() {\n        CreateUserRequest request = getDefaultCreateUserRequest();\n        userService.createUser(request, Role.authenticated);\n        LoginRequest loginRequest = new LoginRequest();\n        loginRequest.setUsername(request.getUser().getEmailAddress());\n        loginRequest.setPassword(\"qwerty123\");\n        userService.login(loginRequest);\n\n    }\n\n    @Test(expected = AuthenticationException.class)\n    public void userNotFound() {\n        LoginRequest request = new LoginRequest();\n        request.setPassword(\"password\");\n        request.setUsername(createRandomEmailAddress());\n        userService.login(request);\n    }\n\n\n    @Test (expected = AuthorizationException.class)\n    public void userNotAuthorizedToDelete() {\n        AuthenticatedUserToken token1 = createUserWithRandomUserName(Role.authenticated);\n        AuthenticatedUserToken token2 = createUserWithRandomUserName(Role.authenticated);\n        ExternalUser user = userService.getUser(new ExternalUser(token1.getUserId()), token1.getUserId());\n        userService.deleteUser(user, token2.getUserId());\n    }\n\n\n    @Test\n    public void getValidUser() {\n        AuthenticatedUserToken token = createUserWithRandomUserName(Role.authenticated);\n        ExternalUser user = new ExternalUser(token.getUserId());\n        ExternalUser foundUser = userService.getUser(user, user.getId().toString());\n        assertThat(foundUser.getId(), is(user.getId()));\n    }\n\n    @Test (expected = UserNotFoundException.class)\n    public void getUserNotFound() {\n        userService.getUser(new ExternalUser(), \"123\");\n    }\n\n    @Test\n    public void getUserByEmailAddress() {\n        CreateUserRequest request = getDefaultCreateUserRequest();\n        AuthenticatedUserToken token = userService.createUser(request, Role.authenticated);\n        ExternalUser user = new ExternalUser(token.getUserId());\n        ExternalUser foundUser = userService.getUser(user, request.getUser().getEmailAddress());\n        assertThat(foundUser.getId(), is(user.getId()));\n    }\n\n    @Test\n    public void updateUser() {\n        AuthenticatedUserToken token = createUserWithRandomUserName(Role.authenticated);\n        UpdateUserRequest request = new UpdateUserRequest();\n        request.setFirstName(\"foo\");\n        request.setLastName(\"bar\");\n        request.setEmailAddress(\"foobar@example.com\");\n        userService.saveUser(token.getUserId(), request);\n        User loadedUser = userRepository.findByUuid(token.getUserId());\n        assertThat(loadedUser.getFirstName(), is(\"foo\"));\n        assertThat(loadedUser.getLastName(), is(\"bar\"));\n        assertThat(loadedUser.getEmailAddress(), is(\"foobar@example.com\"));\n    }\n\n    @Test (expected = ValidationException.class)\n    public void updateUserWithInvalidEmailAddress() {\n        AuthenticatedUserToken token = createUserWithRandomUserName(Role.authenticated);\n        UpdateUserRequest request = new UpdateUserRequest();\n        request.setEmailAddress(\"NotAValidEmailAddress\");\n        userService.saveUser(token.getUserId().toString(), request);\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/user/VerificationServiceTest.java",
    "content": "package com.porterhead.rest.user;\n\nimport com.porterhead.rest.config.ApplicationConfig;\nimport com.porterhead.rest.gateway.EmailServicesGateway;\nimport com.porterhead.rest.user.api.LostPasswordRequest;\nimport com.porterhead.rest.user.api.PasswordRequest;\nimport com.porterhead.rest.user.domain.User;\nimport com.porterhead.rest.user.domain.VerificationToken;\nimport com.porterhead.rest.user.exception.AlreadyVerifiedException;\nimport com.porterhead.rest.user.exception.TokenHasExpiredException;\nimport com.porterhead.rest.user.exception.TokenNotFoundException;\nimport com.porterhead.rest.user.exception.UserNotFoundException;\nimport org.apache.commons.codec.binary.Base64;\nimport org.hamcrest.Matchers;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport javax.validation.Validation;\nimport javax.validation.Validator;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.UUID;\n\nimport static org.hamcrest.Matchers.*;\nimport static org.junit.Assert.assertThat;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\n/**\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 12/09/2012\n */\npublic class VerificationServiceTest {\n\n    private EmailServicesGateway emailServicesGateway;\n    private UserRepository userRepository;\n    private VerificationTokenRepository tokenRepository;\n    private List<String> tokens;\n    private VerificationTokenService verificationTokenService;\n    private Validator validator;\n\n    @Before\n    public void setUp() {\n        tokens = new ArrayList<String>();\n\n        emailServicesGateway = new EmailServicesGateway() {\n            public void sendVerificationToken(EmailServiceTokenModel model) {\n                tokens.add(model.getToken());\n\n            }\n        };\n        validator = Validation.buildDefaultValidatorFactory().getValidator();\n\n        userRepository = mock(UserRepository.class);\n        tokenRepository = mock(VerificationTokenRepository.class);\n        ApplicationConfig config = mock(ApplicationConfig.class);\n        verificationTokenService = new VerificationTokenServiceImpl(userRepository, tokenRepository,\n                emailServicesGateway, validator);\n        ((VerificationTokenServiceImpl)verificationTokenService).setConfig(config);\n        when(config.getHostNameUrl()).thenReturn(new String(\"http://localhost:8080\"));\n        when(config.getLostPasswordTokenExpiryTimeInMinutes()).thenReturn(120);\n        when(config.getEmailVerificationTokenExpiryTimeInMinutes()).thenReturn(120);\n        when(config.getEmailRegistrationTokenExpiryTimeInMinutes()).thenReturn(120);\n    }\n\n\n    @Test\n    public void sendLostPasswordToken() {\n        User user = generateTestUser();\n        when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user);\n        VerificationToken token = verificationTokenService.sendLostPasswordToken(new LostPasswordRequest(user.getEmailAddress()));\n        assertThat(user.getVerificationTokens().size(), is(1));\n        assertThat(user.getActiveLostPasswordToken(), is(token));\n        assertThat(token, is(not(Matchers.<Object>nullValue())));\n        assertThat(tokens.size(), is(1));\n        String sentToken = tokens.get(0);\n        assertThat(sentToken, is(not(nullValue())));\n        assertThat(sentToken, is(token.getToken()));\n        assertThat(token.getTokenType(), is(VerificationToken.VerificationTokenType.lostPassword));\n\n    }\n\n    @Test\n    public void sendLostPasswordTokenAgain() {\n        User user = generateTestUser();\n        when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user);\n        VerificationToken token1 = verificationTokenService.sendLostPasswordToken(new LostPasswordRequest(user.getEmailAddress()));\n        VerificationToken token2 = verificationTokenService.sendLostPasswordToken(new LostPasswordRequest(user.getEmailAddress()));\n        assertThat(token1, is(token2));\n        assertThat(user.getVerificationTokens().size(), is(1));\n        assertThat(tokens.size(), is(2));  //gateway called twice\n\n    }\n\n    @Test\n    public void resetPassword() throws Exception {\n        User user = generateTestUser();\n        when(userRepository.save(user)).thenReturn(user);\n        when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user);\n        VerificationToken token = verificationTokenService.sendLostPasswordToken(new LostPasswordRequest(user.getEmailAddress()));\n        when(tokenRepository.findByToken(token.getToken())).thenReturn(token);\n        String encodedToken = new String(Base64.encodeBase64(token.getToken().getBytes()));\n        VerificationToken verifiedToken = verificationTokenService.resetPassword(encodedToken, new PasswordRequest(\"newpassword\"));\n        assertThat(verifiedToken.isVerified(), is(true));\n        assertThat(user.getHashedPassword(), is(user.hashPassword(\"newpassword\")));\n        assertThat(user.getVerificationTokens().get(0).isVerified(), is(true));\n        //user should also be verified\n        assertThat(user.isVerified(), is(true));\n    }\n\n    @Test\n    public void resetPasswordGetNewToken() {\n        User user = generateTestUser();\n        when(userRepository.save(user)).thenReturn(user);\n        when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user);\n        VerificationToken token = verificationTokenService.sendLostPasswordToken(new LostPasswordRequest(user.getEmailAddress()));\n        when(tokenRepository.findByToken(token.getToken())).thenReturn(token);\n        String encodedToken = new String(Base64.encodeBase64(token.getToken().getBytes()));\n        VerificationToken verifiedToken = verificationTokenService.resetPassword(encodedToken, new PasswordRequest(\"newpassword\"));\n        VerificationToken token2 = verificationTokenService.sendLostPasswordToken(new LostPasswordRequest(user.getEmailAddress()));\n        assertThat(token2.getToken(), is(not(token.getToken())));\n    }\n\n    @Test\n    public void sendEmailToken() {\n        User user = generateTestUser();\n        when(userRepository.findByUuid(user.getUuid().toString())).thenReturn(user);\n        VerificationToken token = verificationTokenService.sendEmailVerificationToken(user.getUuid().toString());\n        assertThat(user.getVerificationTokens().size(), is(1));\n        assertThat(token, is(not(Matchers.<Object>nullValue())));\n        assertThat(tokens.size(), is(1));\n        String sentToken = tokens.get(0);\n        assertThat(sentToken, is(not(nullValue())));\n        assertThat(sentToken, is(token.getToken()));\n        assertThat(token.getTokenType(), is(VerificationToken.VerificationTokenType.emailVerification));\n    }\n\n    @Test\n    public void sendRegistrationToken() {\n        User user = generateTestUser();\n        when(userRepository.findByUuid(user.getUuid().toString())).thenReturn(user);\n        VerificationToken token = verificationTokenService.sendEmailRegistrationToken(user.getUuid().toString());\n        assertThat(user.getVerificationTokens().size(), is(1));\n        assertThat(token, is(not(Matchers.<Object>nullValue())));\n        assertThat(tokens.size(), is(1));\n        String sentToken = tokens.get(0);\n        assertThat(sentToken, is(not(nullValue())));\n        assertThat(sentToken, is(token.getToken()));\n        assertThat(token.getTokenType(), is(VerificationToken.VerificationTokenType.emailRegistration));\n    }\n\n    @Test\n    public void verifyValidToken() {\n        User user = generateTestUser();\n        when(userRepository.save(user)).thenReturn(user);\n        when(userRepository.findByUuid(user.getUuid().toString())).thenReturn(user);\n        VerificationToken token = verificationTokenService.sendEmailVerificationToken(user.getUuid().toString());\n        when(tokenRepository.findByToken(token.getToken())).thenReturn(token);\n        String encodedToken = new String(Base64.encodeBase64(token.getToken().getBytes()));\n        VerificationToken verifiedToken = verificationTokenService.verify(encodedToken);\n        assertThat(verifiedToken.isVerified(), is(true));\n        assertThat(user.isVerified(), is(true));\n        assertThat(user.getVerificationTokens().get(0).isVerified(), is(true));\n    }\n\n    @Test (expected = TokenHasExpiredException.class)\n    public void tokenHasExpired() {\n        User user = generateTestUser();\n        VerificationToken token = mock(VerificationToken.class);\n        when(token.getUser()).thenReturn(user);\n        when(token.hasExpired()).thenReturn(true);\n        when(token.getToken()).thenReturn(UUID.randomUUID().toString());\n        when(userRepository.save(user)).thenReturn(user);\n        when(tokenRepository.findByToken(token.getToken())).thenReturn(token);\n        String encodedToken = new String(Base64.encodeBase64(token.getToken().getBytes()));\n        verificationTokenService.verify(encodedToken);\n    }\n\n    @Test (expected = AlreadyVerifiedException.class)\n    public void tokenAlreadyVerified() {\n        User user = generateTestUser();\n        VerificationToken token = mock(VerificationToken.class);\n        when(token.getUser()).thenReturn(user);\n        when(token.hasExpired()).thenReturn(false);\n        when(token.isVerified()).thenReturn(true);\n        when(token.getToken()).thenReturn(UUID.randomUUID().toString());\n        when(userRepository.save(user)).thenReturn(user);\n        when(tokenRepository.findByToken(token.getToken())).thenReturn(token);\n        String encodedToken = new String(Base64.encodeBase64(token.getToken().getBytes()));\n        verificationTokenService.verify(encodedToken);\n    }\n\n    @Test (expected = AlreadyVerifiedException.class)\n    public void userAlreadyVerified() {\n        User user = generateTestUser();\n        user.setVerified(true);\n        VerificationToken token = mock(VerificationToken.class);\n        when(token.getUser()).thenReturn(user);\n        when(token.hasExpired()).thenReturn(false);\n        when(token.isVerified()).thenReturn(false);\n        when(token.getToken()).thenReturn(UUID.randomUUID().toString());\n        when(userRepository.save(user)).thenReturn(user);\n        when(tokenRepository.findByToken(token.getToken())).thenReturn(token);\n        String encodedToken = new String(Base64.encodeBase64(token.getToken().getBytes()));\n        verificationTokenService.verify(encodedToken);\n    }\n\n    @Test (expected = TokenNotFoundException.class)\n    public void tokenNotFound() {\n        VerificationToken token = new VerificationToken(new User(), VerificationToken.VerificationTokenType.emailVerification, 120);\n        when(tokenRepository.findByToken(token.getToken())).thenReturn(null);\n        String encodedToken = new String(Base64.encodeBase64(token.getToken().getBytes()));\n        verificationTokenService.verify(encodedToken);\n    }\n\n    @Test\n    public void generateEmailToken() {\n        User user = generateTestUser();\n        when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user);\n        when(userRepository.save(user)).thenReturn(user);\n        VerificationToken token = verificationTokenService.generateEmailVerificationToken(user.getEmailAddress());\n        assertThat(user.getVerificationTokens().size(), is(1));\n        assertThat(token, is(not(Matchers.<Object>nullValue())));\n        assertThat(tokens.size(), is(1));\n        String sentToken = tokens.get(0);\n        assertThat(sentToken, is(not(nullValue())));\n        UUID.fromString(sentToken);\n        assertThat(sentToken, is(token.getToken()));\n    }\n\n    private User generateTestUser() {\n        User user = new User();\n        user.setEmailAddress(\"test@example.com\");\n        return user;\n    }\n\n    @Test\n    public void generateEmailTokenAlreadyActive() {\n        User user = generateTestUser();\n        when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user);\n        when(userRepository.save(user)).thenReturn(user);\n        VerificationToken token = verificationTokenService.generateEmailVerificationToken(user.getEmailAddress());\n        //request it again\n        verificationTokenService.generateEmailVerificationToken(user.getEmailAddress());\n        assertThat(user.getVerificationTokens().size(), is(1));\n        assertThat(tokens.size(), is(2)); //gateway invoked twice\n    }\n\n    @Test\n    public void generateEmailTokenAfterExpired() {\n        User user = generateTestUser();\n        VerificationToken token = mock(VerificationToken.class);\n        when(token.hasExpired()).thenReturn(true);\n        when(token.getTokenType()).thenReturn(VerificationToken.VerificationTokenType.emailVerification);\n        user.addVerificationToken(token);\n        when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user);\n        when(userRepository.save(user)).thenReturn(user);\n        VerificationToken generatedToken = verificationTokenService.generateEmailVerificationToken(user.getEmailAddress());\n        assertThat(user.getVerificationTokens().size(), is(2));\n        assertThat(tokens.size(), is(1)); //gateway invoked once, as first token was manually added\n    }\n\n    @Test (expected = UserNotFoundException.class)\n    public void emailAddressNotFound() {\n        verificationTokenService.generateEmailVerificationToken(\"test@example.com\");\n    }\n\n    @Test (expected = AlreadyVerifiedException.class)\n    public void generateEmailTokenAlreadyVerified() {\n        User user = new User();\n        user.setEmailAddress(\"test@example.com\");\n        user.setVerified(true);\n        VerificationToken token = mock(VerificationToken.class);\n        when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user);\n        verificationTokenService.generateEmailVerificationToken(user.getEmailAddress());\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/user/api/CreateUserRequestTest.java",
    "content": "package com.porterhead.rest.user.api;\n\nimport org.apache.commons.lang.RandomStringUtils;\nimport org.junit.Test;\n\nimport javax.validation.ConstraintViolation;\nimport java.util.Set;\n\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.Assert.assertThat;\n\n/**\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 08/11/2012\n */\npublic class CreateUserRequestTest extends ValidationTst {\n\n\n    @Test\n    public void validRequest() {\n        ExternalUser user = new ExternalUser();\n        user.setEmailAddress(RandomStringUtils.randomAlphanumeric(8) + \"@example.com\");\n        user.setFirstName(\"Bo\");\n        user.setLastName(\"Diddley\");\n        PasswordRequest passwordRequest = new PasswordRequest(RandomStringUtils.randomAlphanumeric(10));\n        CreateUserRequest createUserRequest = new CreateUserRequest(user, passwordRequest);\n        Set<ConstraintViolation<CreateUserRequest>> constraints = validator.validate(createUserRequest);\n        assertThat(constraints.size(), is(0));\n    }\n\n    @Test\n    public void nullUser() {\n        PasswordRequest passwordRequest = new PasswordRequest(RandomStringUtils.randomAlphanumeric(10));\n        CreateUserRequest createUserRequest = new CreateUserRequest(null, passwordRequest);\n        Set<ConstraintViolation<CreateUserRequest>> constraints = validator.validate(createUserRequest);\n        assertThat(constraints.size(), is(1));\n    }\n\n    @Test\n    public void firstNameTooLong() {\n        ExternalUser user = new ExternalUser();\n        user.setEmailAddress(RandomStringUtils.randomAlphabetic(8) + \"@example.com\");\n        user.setFirstName(RandomStringUtils.randomAlphabetic(101));\n        PasswordRequest passwordRequest = new PasswordRequest(RandomStringUtils.randomAlphanumeric(10));\n        CreateUserRequest createUserRequest = new CreateUserRequest(user, passwordRequest);\n        Set<ConstraintViolation<CreateUserRequest>> constraints = validator.validate(createUserRequest);\n        assertThat(constraints.size(), is(1));\n    }\n\n    @Test\n    public void lastNameTooLong() {\n        ExternalUser user = new ExternalUser();\n        user.setEmailAddress(RandomStringUtils.randomAlphabetic(8) + \"@example.com\");\n        user.setLastName(RandomStringUtils.randomAlphabetic(101));\n        PasswordRequest passwordRequest = new PasswordRequest(RandomStringUtils.randomAlphanumeric(10));\n        CreateUserRequest createUserRequest = new CreateUserRequest(user, passwordRequest);\n        Set<ConstraintViolation<CreateUserRequest>> constraints = validator.validate(createUserRequest);\n        assertThat(constraints.size(), is(1));\n    }\n\n\n}\n\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/user/api/LoginRequestTest.java",
    "content": "package com.porterhead.rest.user.api;\n\nimport org.apache.commons.lang.RandomStringUtils;\nimport org.junit.Test;\n\nimport javax.validation.ConstraintViolation;\nimport java.util.Set;\n\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.Assert.assertThat;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 09/11/2012\n */\npublic class LoginRequestTest extends ValidationTst {\n\n    @Test\n    public void validRequest() {\n        LoginRequest request = new LoginRequest();\n        request.setUsername(RandomStringUtils.randomAlphabetic(8) + \"@example.com\");\n        request.setPassword(RandomStringUtils.randomAlphanumeric(8));\n        Set<ConstraintViolation<LoginRequest>> constraints = validator.validate(request);\n        assertThat(constraints.size(), is(0));\n    }\n\n    @Test\n    public void invalidPassword() {\n        LoginRequest request = new LoginRequest();\n        request.setUsername(RandomStringUtils.randomAlphanumeric(8) + \"@example.com\");\n        request.setPassword(RandomStringUtils.randomAlphanumeric(7));\n        Set<ConstraintViolation<LoginRequest>> constraints = validator.validate(request);\n        assertThat(constraints.size(), is(1));\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/user/api/PasswordRequestTest.java",
    "content": "package com.porterhead.rest.user.api;\n\nimport org.apache.commons.lang.RandomStringUtils;\nimport org.junit.Test;\n\nimport javax.validation.ConstraintViolation;\nimport java.util.Set;\n\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.Assert.assertThat;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 30/09/2012\n */\npublic class PasswordRequestTest extends ValidationTst {\n\n    @Test\n    public void validPassword() {\n        PasswordRequest request = new PasswordRequest(\"password\");\n        Set<ConstraintViolation<PasswordRequest>> constraints = validator.validate(request);\n        assertThat(constraints.size(), is(0));\n    }\n\n    public void passwordTooShort() {\n        PasswordRequest request = new PasswordRequest(RandomStringUtils.randomAlphanumeric(7));\n        Set<ConstraintViolation<PasswordRequest>> constraints = validator.validate(request);\n        assertThat(constraints.size(), is(1));\n    }\n\n    public void passwordTooLong() {\n        PasswordRequest request = new PasswordRequest(RandomStringUtils.randomAlphanumeric(36));\n        Set<ConstraintViolation<PasswordRequest>> constraints = validator.validate(request);\n        assertThat(constraints.size(), is(1));\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/user/api/ValidationTst.java",
    "content": "package com.porterhead.rest.user.api;\n\nimport org.junit.Before;\n\nimport javax.validation.Validation;\nimport javax.validation.Validator;\n\n/**\n * @version 1.0\n * @author: Iain Porter\n * @since 08/05/2013\n */\npublic class ValidationTst {\n\n    protected Validator validator;\n\n    @Before\n    public void setUp() {\n        validator = Validation.buildDefaultValidatorFactory().getValidator();\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/user/builder/ExternalUserBuilder.java",
    "content": "package com.porterhead.rest.user.builder;\n\nimport com.porterhead.rest.user.api.ExternalUser;\n\n/**\n * User: porter\n * Date: 12/03/2012\n * Time: 14:32\n */\npublic class ExternalUserBuilder {\n\n    public static ExternalUserBuilder create() {\n          return new ExternalUserBuilder();\n      }\n\n\n    private final ExternalUser user;\n\n    public ExternalUserBuilder() {\n        user = new ExternalUser();\n    }\n\n    public ExternalUser build() {\n        return user;\n    }\n\n    public ExternalUserBuilder withFirstName(String name) {\n        user.setFirstName(name);\n        return this;\n    }\n\n    public ExternalUserBuilder withLastName(String name) {\n        user.setLastName(name);\n        return this;\n    }\n\n    public ExternalUserBuilder withEmailAddress(String email) {\n        user.setEmailAddress(email);\n        return this;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/user/resource/PasswordResourceTest.java",
    "content": "package com.porterhead.rest.user.resource;\n\nimport com.porterhead.rest.resource.BaseResourceTst;\nimport com.porterhead.rest.resource.ConsumerSimpleSecurityFilter;\nimport com.porterhead.rest.user.api.LostPasswordRequest;\nimport com.porterhead.rest.user.api.PasswordRequest;\nimport com.sun.jersey.api.client.ClientResponse;\nimport com.sun.jersey.api.core.ResourceConfig;\nimport com.sun.jersey.spi.spring.container.servlet.SpringServlet;\nimport com.sun.jersey.test.framework.WebAppDescriptor;\nimport org.junit.Test;\nimport org.springframework.web.context.ContextLoaderListener;\n\nimport java.util.UUID;\n\nimport static javax.ws.rs.core.MediaType.APPLICATION_JSON;\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.Assert.assertThat;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 24/10/2012\n */\npublic class PasswordResourceTest extends BaseResourceTst {\n\n    public PasswordResourceTest() {\n            super(new WebAppDescriptor.Builder()\n                    .contextPath(\"spring\")\n                    .contextParam(\"contextConfigLocation\", \"classpath:integration-test-context.xml\")\n                    .contextParam(\"spring.profiles.active\", \"dev\")\n                    .servletClass(SpringServlet.class)\n                    .contextListenerClass(ContextLoaderListener.class)\n                    .initParam(ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS, ConsumerSimpleSecurityFilter.class.getName())\n                    .build());\n        }\n\n    @Test\n    public void sendEmailToken() {\n        ClientResponse response = super.resource().path(\"password/tokens\").entity(createLostPasswordRequest(TEST_USER.getEmailAddress()), APPLICATION_JSON).accept(APPLICATION_JSON).post(ClientResponse.class);\n        assertThat(response.getStatus(), is(200));\n    }\n\n    @Test\n    public void resetPassword() {\n       ClientResponse response = super.resource().path(\"password/tokens/\" + UUID.randomUUID().toString()).entity(createPasswordRequest(\"abcd1234\"), APPLICATION_JSON).accept(APPLICATION_JSON).post(ClientResponse.class);\n       assertThat(response.getStatus(), is(200));\n    }\n\n    private LostPasswordRequest createLostPasswordRequest(String emailAddress) {\n        LostPasswordRequest request = new LostPasswordRequest();\n        request.setEmailAddress(emailAddress);\n        return request;\n    }\n\n    private PasswordRequest createPasswordRequest(String password) {\n        PasswordRequest request = new PasswordRequest();\n        request.setPassword(password);\n        return request;\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/user/resource/UserResourceTest.java",
    "content": "package com.porterhead.rest.user.resource;\n\nimport com.porterhead.rest.resource.BaseResourceTst;\nimport com.porterhead.rest.resource.ConsumerSimpleSecurityFilter;\nimport com.porterhead.rest.user.domain.Role;\nimport com.porterhead.rest.user.domain.User;\nimport com.porterhead.rest.user.exception.AuthenticationException;\nimport com.porterhead.rest.user.exception.DuplicateUserException;\nimport com.porterhead.rest.exception.ValidationException;\nimport com.porterhead.rest.user.api.*;\nimport com.sun.jersey.api.client.ClientResponse;\nimport com.sun.jersey.api.client.WebResource;\nimport com.sun.jersey.api.core.ResourceConfig;\nimport com.sun.jersey.spi.spring.container.servlet.SpringServlet;\nimport com.sun.jersey.test.framework.WebAppDescriptor;\nimport org.junit.Test;\nimport org.springframework.social.connect.Connection;\nimport org.springframework.social.connect.support.OAuth2ConnectionFactory;\nimport org.springframework.social.facebook.api.Facebook;\nimport org.springframework.social.oauth2.AccessGrant;\nimport org.springframework.web.context.ContextLoaderListener;\n\nimport static javax.ws.rs.core.MediaType.APPLICATION_JSON;\nimport static org.hamcrest.Matchers.*;\nimport static org.junit.Assert.assertThat;\nimport static org.mockito.Matchers.any;\nimport static org.mockito.Mockito.*;\n\n/**\n * User: porter\n * Date: 05/05/2012\n * Time: 09:45\n */\npublic class UserResourceTest extends BaseResourceTst {\n\n    public UserResourceTest() {\n            super(new WebAppDescriptor.Builder()\n                    .contextPath(\"spring\")\n                    .contextParam(\"contextConfigLocation\", \"classpath:integration-test-context.xml\")\n                    .contextParam(\"spring.profiles.active\", \"dev\")\n                    .servletClass(SpringServlet.class)\n                    .contextListenerClass(ContextLoaderListener.class)\n                    .initParam(ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS, ConsumerSimpleSecurityFilter.class.getName())\n                    .build());\n        }\n\n    @Test\n    public void signUp() {\n        when(userService.createUser(any(CreateUserRequest.class), any(Role.class))).thenReturn(\n                new AuthenticatedUserToken(TEST_USER.getUuid().toString(), AUTH_TOKEN.getToken()));\n        WebResource webResource = resource();\n        CreateUserRequest request = createSignupRequest();\n        ClientResponse response = webResource.path(\"user\").entity(request, APPLICATION_JSON).accept(APPLICATION_JSON).post(ClientResponse.class);\n        assertThat(response.getStatus(), is(201));\n        AuthenticatedUserToken token = response.getEntity(AuthenticatedUserToken.class);\n        assertThat(token.getToken(), is(not(nullValue())));\n        assertThat(token.getUserId(), is(not(nullValue())));\n    }\n\n    @Test\n    public void validationErrorOnCreateUser() {\n        when(userService.createUser(any(CreateUserRequest.class), any(Role.class))).thenThrow(new ValidationException());\n        CreateUserRequest request = createSignupRequest();\n        ClientResponse response = super.resource().path(\"user\").entity(request, APPLICATION_JSON).accept(APPLICATION_JSON).post(ClientResponse.class);\n        assertThat(response.getStatus(), is(400));\n    }\n\n    @Test\n    public void duplicateUserOnCreateUser() {\n        when(userService.createUser(any(CreateUserRequest.class), any(Role.class))).thenThrow(new DuplicateUserException());\n        CreateUserRequest request = createSignupRequest();\n        ClientResponse response = super.resource().path(\"user\").entity(request, APPLICATION_JSON).accept(APPLICATION_JSON).post(ClientResponse.class);\n        assertThat(response.getStatus(), is(409));\n    }\n\n    @Test\n    public void login() {\n        when(userService.login(any(LoginRequest.class))).thenReturn(\n                new AuthenticatedUserToken(TEST_USER.getUuid().toString(), AUTH_TOKEN.getToken()));\n        ClientResponse response = super.resource().path(\"user/login\").entity(createLoginRequest(), APPLICATION_JSON).accept(APPLICATION_JSON).post(ClientResponse.class);\n        assertThat(response.getStatus(), is(200));\n        AuthenticatedUserToken token = response.getEntity(AuthenticatedUserToken.class);\n        assertThat(token.getToken(), is(not(nullValue())));\n        assertThat(token.getUserId(), is(not(nullValue())));\n    }\n\n    @Test\n    public void socialLogin() {\n        OAuth2ConnectionFactory connectionFactory = mock(OAuth2ConnectionFactory.class);\n        Connection<Facebook> connection = mock(Connection.class);\n        when(connectionFactoryLocator.getConnectionFactory(any(String.class))).thenReturn(connectionFactory);\n        when(connectionFactory.createConnection(any(AccessGrant.class))).thenReturn(connection);\n        when(userService.socialLogin(connection)).thenReturn(\n                new AuthenticatedUserToken(TEST_USER.getUuid().toString(), AUTH_TOKEN.getToken()));\n        OAuth2Request request = new OAuth2Request();\n        request.setAccessToken(\"123\");\n        ClientResponse response = super.resource().path(\"user/login/facebook\").entity(request, APPLICATION_JSON).accept(APPLICATION_JSON).post(ClientResponse.class);\n        assertThat(response.getStatus(), is(200));\n        AuthenticatedUserToken token = response.getEntity(AuthenticatedUserToken.class);\n        assertThat(token.getToken(), is(not(nullValue())));\n        assertThat(token.getUserId(), is(not(nullValue())));\n    }\n\n    @Test\n    public void validationErrorOnLogin() {\n        when(userService.login(any(LoginRequest.class))).thenThrow(new ValidationException());\n        ClientResponse response = super.resource().path(\"user/login\").entity(createLoginRequest(), APPLICATION_JSON).accept(APPLICATION_JSON).post(ClientResponse.class);\n        assertThat(response.getStatus(), is(400));\n    }\n\n    @Test\n    public void authenticationErrorOnLogin() {\n        when(userService.login(any(LoginRequest.class))).thenThrow(new AuthenticationException());\n        ClientResponse response = super.resource().path(\"user/login\").entity(createLoginRequest(), APPLICATION_JSON).accept(APPLICATION_JSON).post(ClientResponse.class);\n        assertThat(response.getStatus(), is(401));\n    }\n\n    @Test\n    public void getUser() {\n        when(userService.getUser(any(ExternalUser.class), any(String.class))).thenReturn(new ExternalUser(TEST_USER, AUTH_TOKEN));\n        ClientResponse response = super.resource().path(\"user/\" + TEST_USER.getUuid().toString()).accept(APPLICATION_JSON).get(ClientResponse.class);\n        assertThat(response.getStatus(), is(200));\n        ExternalUser userResponse = response.getEntity(ExternalUser.class);\n        assertThat(userResponse.getEmailAddress(), is(TEST_USER.getEmailAddress()));\n        assertThat(userResponse.getFirstName(), is(TEST_USER.getFirstName()));\n        assertThat(userResponse.getLastName(), is(TEST_USER.getLastName()));\n    }\n\n\n    @Test\n    public void deleteUser() {\n        ClientResponse response = super.resource().path(\"user/\" + TEST_USER.getUuid().toString()).accept(APPLICATION_JSON).delete(ClientResponse.class);\n        assertThat(response.getStatus(), is(200));\n    }\n\n    @Test\n    public void updateUserWithNewEmailAddress() {\n        when(userService.saveUser(any(String.class), any(UpdateUserRequest.class))).thenReturn(new ExternalUser(TEST_USER, AUTH_TOKEN));\n        ClientResponse response = super.resource().path(\"user/\" + TEST_USER.getUuid().toString()).entity(createUpdateUserRequest(\"foobar@example.com\"),\n                APPLICATION_JSON).accept(APPLICATION_JSON).put(ClientResponse.class);\n        assertThat(response.getStatus(), is(200));\n        verify(verificationTokenService, times(1)).sendEmailVerificationToken(any(String.class));\n    }\n\n    @Test\n    public void updateUserButNotEmailAddress() {\n        ClientResponse response = super.resource().path(\"user/\" + TEST_USER.getUuid().toString()).entity(createUpdateUserRequest(TEST_USER.getEmailAddress()),\n                APPLICATION_JSON).accept(APPLICATION_JSON).put(ClientResponse.class);\n        assertThat(response.getStatus(), is(200));\n        verify(verificationTokenService, times(0)).sendEmailVerificationToken(any(String.class));\n    }\n\n    @Test\n    public void userTriesToModifyAnotherUserProfile() {\n        User user = new User();\n        ClientResponse response = super.resource().path(\"user/\" + user.getUuid().toString()).entity(createUpdateUserRequest(\"foobar@example.com\"),\n                APPLICATION_JSON).accept(APPLICATION_JSON).put(ClientResponse.class);\n        assertThat(response.getStatus(), is(403));\n    }\n\n\n    @Test\n    public void runtimeError() {\n        when(userService.createUser(any(CreateUserRequest.class), any(Role.class))).thenThrow(new RuntimeException());\n        ClientResponse response = super.resource().path(\"user\").entity(createSignupRequest(), APPLICATION_JSON).accept(APPLICATION_JSON).post(ClientResponse.class);\n        assertThat(response.getStatus(), is(500));\n\n    }\n\n\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/user/resource/VerificationResourceTest.java",
    "content": "package com.porterhead.rest.user.resource;\n\nimport com.porterhead.rest.resource.BaseResourceTst;\nimport com.porterhead.rest.resource.ConsumerSimpleSecurityFilter;\nimport com.porterhead.rest.user.api.EmailVerificationRequest;\nimport com.porterhead.rest.user.domain.User;\nimport com.porterhead.rest.user.domain.VerificationToken;\nimport com.sun.jersey.api.client.ClientResponse;\nimport com.sun.jersey.api.core.ResourceConfig;\nimport com.sun.jersey.spi.spring.container.servlet.SpringServlet;\nimport com.sun.jersey.test.framework.WebAppDescriptor;\nimport org.junit.Test;\nimport org.springframework.web.context.ContextLoaderListener;\n\nimport java.util.UUID;\n\nimport static javax.ws.rs.core.MediaType.APPLICATION_JSON;\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.Assert.assertThat;\nimport static org.mockito.Mockito.when;\n\n/**\n *\n * @version 1.0\n * @author: Iain Porter iain.porter@porterhead.com\n * @since 14/09/2012\n */\npublic class VerificationResourceTest extends BaseResourceTst {\n\n    public VerificationResourceTest() {\n        super(new WebAppDescriptor.Builder()\n                .contextPath(\"spring\")\n                .contextParam(\"contextConfigLocation\", \"classpath:integration-test-context.xml\")\n                .initParam(\"com.sun.jersey.api.json.POJOMappingFeature\", \"true\")\n                .contextParam(\"spring.profiles.active\", \"dev\")\n                .servletClass(SpringServlet.class)\n                .contextListenerClass(ContextLoaderListener.class)\n                .initParam(ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS, ConsumerSimpleSecurityFilter.class.getName())\n                .build());\n    }\n\n    @Test\n    public void verify() {\n        VerificationToken token = new VerificationToken(new User(), VerificationToken.VerificationTokenType.emailVerification, 120);\n        when(verificationTokenService.verify(\"123\")).thenReturn(token);\n        ClientResponse response = super.resource().path(\"verify/tokens/\" + UUID.randomUUID())\n                .accept(APPLICATION_JSON).post(ClientResponse.class);\n        assertThat(response.getStatus(), is(200));\n    }\n\n    @Test\n    public void generateEmailToken() {\n        VerificationToken token = new VerificationToken(new User(), VerificationToken.VerificationTokenType.emailVerification, 120);\n        when(verificationTokenService.generateEmailVerificationToken(\"test@example.com\")).thenReturn(token);\n        ClientResponse response = super.resource().path(\"verify/tokens\").entity(new EmailVerificationRequest(\"test@example.com\"), APPLICATION_JSON)\n                .accept(APPLICATION_JSON).post(ClientResponse.class);\n        assertThat(response.getStatus(), is(200));\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/user/social/AbstractSocialTst.java",
    "content": "package com.porterhead.rest.user.social;\n\nimport com.porterhead.rest.user.SocialUserRepository;\nimport com.porterhead.rest.user.UserRepository;\nimport com.porterhead.rest.user.domain.SocialUser;\nimport com.porterhead.rest.user.domain.User;\nimport org.junit.Before;\nimport org.springframework.security.crypto.encrypt.Encryptors;\nimport org.springframework.security.crypto.encrypt.TextEncryptor;\nimport org.springframework.social.connect.*;\nimport org.springframework.social.facebook.api.Facebook;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport static org.mockito.Matchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\n/**\n * User: porter\n * Date: 22/05/2012\n * Time: 13:28\n */\npublic abstract class AbstractSocialTst {\n\n    protected static final String PROVIDER_ID = \"facebook\";\n    protected static final String PROVIDER_USER_ID = \"123456\";\n    protected static final String ACCESS_TOKEN = \"1234567890\";\n\n    protected Connection<Facebook> connection;\n    protected SocialUserRepository socialUserRepository;\n    protected UserRepository userRepository;\n    protected User user;\n    protected ConnectionFactoryLocator connectionFactoryLocator;\n    protected ConnectionFactory connectionFactory;\n    protected TextEncryptor textEncryptor = Encryptors.noOpText();\n    protected SocialUser socialUser;\n    protected List<SocialUser> socialUsers;\n    protected Set<String> providerIds = new HashSet<String>();\n\n    @Before\n    public final void setMocks() {\n        mockUserRepository();\n        mockSocialUsers();\n        mockConnectionData();\n        setUpRepository();\n\n    }\n\n    public abstract void setUpRepository();\n\n    private void mockUserRepository() {\n        user = new User();\n        userRepository = mock(UserRepository.class);\n        when(userRepository.findByUuid(any(String.class))).thenReturn(user);\n    }\n\n    private void mockSocialUsers() {\n        socialUser = new SocialUser();\n        socialUser.setUser(user);\n        socialUser.setAccessToken(ACCESS_TOKEN);\n        socialUser.setProviderId(PROVIDER_ID);\n        socialUser.setProviderUserId(PROVIDER_USER_ID);\n        socialUser.setDisplayName(\"Test User\");\n        socialUser.setRank(1);\n        socialUsers = new ArrayList<SocialUser>();\n        socialUsers.add(socialUser);\n        socialUserRepository = mock(SocialUserRepository.class);\n\n    }\n\n    private void mockConnectionData() {\n        providerIds.add(PROVIDER_ID);\n        connectionFactoryLocator = mock(ConnectionFactoryLocator.class);\n        connection = mock(Connection.class);\n        connectionFactory = mock(ConnectionFactory.class);\n        when(connection.getKey()).thenReturn(new ConnectionKey(PROVIDER_ID, PROVIDER_USER_ID));\n        when(connectionFactoryLocator.registeredProviderIds()).thenReturn(providerIds);\n        ConnectionData data = new ConnectionData(PROVIDER_ID, PROVIDER_USER_ID, \"Test User\", null, null, ACCESS_TOKEN, null, null, null);\n        when(connection.createData()).thenReturn(data);\n        when(connectionFactoryLocator.getConnectionFactory(any(String.class))).thenReturn(connectionFactory);\n        when(connectionFactory.createConnection(any(ConnectionData.class))).thenReturn(connection);\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/user/social/JpaConnectionRepositoryTest.java",
    "content": "package com.porterhead.rest.user.social;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.springframework.social.connect.Connection;\nimport org.springframework.util.MultiValueMap;\n\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.Assert.assertThat;\nimport static org.mockito.Mockito.when;\n\n/**\n * User: porter\n * Date: 22/05/2012\n * Time: 13:12\n */\npublic class JpaConnectionRepositoryTest extends AbstractSocialTst {\n\n    private JpaConnectionRepository connectionRepository;\n\n    @Before\n    public void setUpRepository() {\n        connectionRepository = new JpaConnectionRepository(socialUserRepository, userRepository, user, connectionFactoryLocator, textEncryptor);\n    }\n\n    @Test\n    public void findAllConnections() {\n       when(socialUserRepository.findAllByUser(user)).thenReturn(socialUsers);\n       MultiValueMap<String, Connection<?>> allConnections = connectionRepository.findAllConnections();\n       assertThat(allConnections.size(), is(1));\n    }\n\n\n}\n"
  },
  {
    "path": "src/test/java/com/porterhead/rest/user/social/JpaUsersConnectionRepositoryTest.java",
    "content": "package com.porterhead.rest.user.social;\n\nimport com.porterhead.rest.config.ApplicationConfig;\nimport com.porterhead.rest.user.UserService;\nimport com.porterhead.rest.user.UserServiceImpl;\nimport com.porterhead.rest.user.api.AuthenticatedUserToken;\nimport com.porterhead.rest.user.api.CreateUserRequest;\nimport com.porterhead.rest.user.api.ExternalUser;\nimport com.porterhead.rest.user.api.PasswordRequest;\nimport com.porterhead.rest.user.builder.ExternalUserBuilder;\nimport com.porterhead.rest.user.domain.Role;\nimport com.porterhead.rest.user.domain.SocialUser;\nimport com.porterhead.rest.user.domain.User;\nimport org.apache.commons.lang.RandomStringUtils;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.invocation.InvocationOnMock;\nimport org.mockito.stubbing.Answer;\nimport org.springframework.social.connect.UserProfile;\nimport org.springframework.social.connect.UserProfileBuilder;\n\nimport javax.validation.Validation;\nimport javax.validation.Validator;\nimport java.util.List;\nimport java.util.UUID;\n\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.notNullValue;\nimport static org.junit.Assert.assertThat;\nimport static org.mockito.Matchers.any;\nimport static org.mockito.Mockito.*;\n\n/**\n * User: porter\n * Date: 21/05/2012\n * Time: 18:35\n */\npublic class JpaUsersConnectionRepositoryTest extends AbstractSocialTst {\n\n    private JpaUsersConnectionRepository usersConnectionRepository;\n    private Validator validator;\n    private ApplicationConfig applicationConfig;\n\n\n    public void setUpRepository() {\n       usersConnectionRepository = new JpaUsersConnectionRepository(\n                socialUserRepository, userRepository, connectionFactoryLocator, textEncryptor);\n         when(userRepository.save(any(User.class))).thenAnswer(new Answer<User>() {\n            public User answer(InvocationOnMock invocation) throws Throwable {\n                Object[] args = invocation.getArguments();\n                user.setUuid(((User) args[0]).getUuid().toString());\n                return (User) args[0];\n            }\n        });\n        validator = Validation.buildDefaultValidatorFactory().getValidator();\n        applicationConfig = mock(ApplicationConfig.class);\n        when(applicationConfig.getAuthorizationExpiryTimeInSeconds()).thenReturn(60 * 60);\n    }\n\n    @Test\n    public void firstTimeConnected() {\n        UserService userService = new UserServiceImpl(usersConnectionRepository, validator, applicationConfig);\n        ((UserServiceImpl)userService).setUserRepository(userRepository);\n        List<String> userIds = usersConnectionRepository.findUserIdsWithConnection(connection);\n        assertThat(userIds.size(), is(1));\n        assertThat(userIds.get(0), is(user.getUuid().toString()));\n        verify(userRepository, times(2)).save(any(User.class));\n        verify(socialUserRepository).save(any(SocialUser.class));\n    }\n\n    @Test\n    public void alreadyRegistered() {\n        when(socialUserRepository.findByProviderIdAndProviderUserId(PROVIDER_ID, PROVIDER_USER_ID)).thenReturn(socialUsers);\n        List<String> userIds = usersConnectionRepository.findUserIdsWithConnection(connection);\n        assertThat(userIds.size(), is(1));\n        assertThat(userIds.get(0), is(user.getUuid().toString()));\n        verify(userRepository, never()).save(any(User.class));\n        verify(socialUserRepository, never()).save(any(SocialUser.class));\n\n    }\n\n    @Test\n    public void validSocialLogin() {\n        UserService userService = new UserServiceImpl(usersConnectionRepository, validator, applicationConfig);\n        ((UserServiceImpl)userService).setUserRepository(userRepository);\n        UserProfileBuilder builder = new UserProfileBuilder();\n        UserProfile profile = builder.setFirstName(\"Tom\").setLastName(\"Tucker\").setEmail(\"tt@example.com\").setUsername(\"ttucker\").build();\n        when(connection.fetchUserProfile()).thenReturn(profile);\n        AuthenticatedUserToken token = userService.socialLogin(connection);\n        ExternalUser user = userService.getUser(new ExternalUser(token.getUserId()), token.getUserId());\n        assertThat(user, is(notNullValue()));\n        assertThat(user.getEmailAddress(), is(\"tt@example.com\"));\n        assertThat(user.getFirstName(), is(\"Tom\"));\n        assertThat(user.getLastName(), is(\"Tucker\"));\n        assertThat(user.isVerified(), is(true));\n        assertThat(user.getRole().equalsIgnoreCase(Role.authenticated.toString()), is(true));\n    }\n\n     @Test\n    public void updateFromSocialLogin() {\n        UserService userService = new UserServiceImpl(usersConnectionRepository, validator, applicationConfig);\n        ((UserServiceImpl)userService).setUserRepository(userRepository);\n        UserProfileBuilder builder = new UserProfileBuilder();\n        UserProfile profile = builder.setFirstName(\"Tom\").setLastName(\"Tucker\").setEmail(\"tt@example.com\").setUsername(\"ttucker\").build();\n        when(connection.fetchUserProfile()).thenReturn(profile);\n        userService.socialLogin(connection);\n        //login again and update\n        profile = builder.setFirstName(\"Foo\").setLastName(\"Bar\").setEmail(\"foobar@example.com\").setUsername(\"foobar\").build();\n        when(connection.fetchUserProfile()).thenReturn(profile);\n        AuthenticatedUserToken token = userService.socialLogin(connection);\n        ExternalUser user = userService.getUser(new ExternalUser(token.getUserId()), token.getUserId());\n        assertThat(user, is(notNullValue()));\n        assertThat(user.getEmailAddress(), is(\"foobar@example.com\"));\n        assertThat(user.getFirstName(), is(\"Foo\"));\n        assertThat(user.getLastName(), is(\"Bar\"));\n        assertThat(user.isVerified(), is(true));\n        assertThat(user.getRole().equalsIgnoreCase(Role.authenticated.toString()), is(true));\n    }\n\n     /**\n     * Test to ensure that the social login is linked to the previously enrolled email address\n     *\n     */\n    @Test\n    public void loginWithEmailAddressThenSocialLogin() {\n        //set up services\n        UserService userService = new UserServiceImpl(usersConnectionRepository, validator, applicationConfig);\n        ((UserServiceImpl) userService).setUserRepository(userRepository);\n        //create email account\n        CreateUserRequest request = getCreateUserRequest(RandomStringUtils.randomAlphabetic(8) + \"@example.com\");\n        AuthenticatedUserToken token = userService.createUser(request, Role.authenticated);\n\n        UserProfileBuilder builder = new UserProfileBuilder();\n        UserProfile profile = builder.setFirstName(user.getFirstName()).setLastName(user.getLastName()).setEmail(user.getEmailAddress()).setUsername(\"jsmith.12\").build();\n        when(connection.fetchUserProfile()).thenReturn(profile);\n        when(userRepository.findByEmailAddress(any(String.class))).thenReturn(new User(UUID.fromString(token.getUserId())));\n        when(userRepository.findByUuid(any(String.class))).thenReturn(new User(UUID.fromString(token.getUserId())));\n        AuthenticatedUserToken loginToken = userService.socialLogin(connection);\n        ExternalUser user = userService.getUser(new ExternalUser(token.getUserId()), token.getUserId());\n        assertThat(token.getUserId(), is(loginToken.getUserId()));\n    }\n\n    private CreateUserRequest getCreateUserRequest(String emailAddress) {\n        CreateUserRequest request = new CreateUserRequest();\n        ExternalUser user = ExternalUserBuilder.create().withFirstName(\"John\")\n                .withLastName(\"Smith\")\n                .withEmailAddress(emailAddress)\n                .build();\n        request.setUser(user);\n        request.setPassword(new PasswordRequest(\"password\"));\n        return request;\n    }\n}\n"
  },
  {
    "path": "src/test/resources/integration-test-context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n\t\thttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\">\n\n\n\n\t<bean class=\"com.porterhead.rest.resource.BaseResourceTst$ApplicationContextAccess\"/>\n    <context:component-scan base-package=\"com.porterhead.rest.resource\" />\n    <context:component-scan base-package=\"com.porterhead.rest.mock\" />\n    <context:component-scan base-package=\"com.porterhead.rest.config\" />\n    <context:component-scan base-package=\"com.porterhead.rest.user.resource\" />\n\n</beans>\n"
  },
  {
    "path": "src/test/resources/social-test-context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\">\n\n\n    <bean class=\"com.porterhead.rest.user.social.SocialConfig\"/>\n\n</beans>"
  }
]