├── .gitignore ├── Dockerfile ├── README.md ├── app.cmd ├── app.js ├── config.batinc ├── model ├── airport.js ├── auth.js ├── flight.js ├── flightPath.js └── user.js ├── package.json ├── public ├── css │ ├── bootstrap-switch.min.css │ ├── bootstrap.css │ ├── bootstrap.css.map │ ├── datepicker.css │ └── style.css ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── images │ ├── CBTravel.LOGO.png │ └── poweredBy.01.png ├── index.html ├── js │ ├── angular-cookies.min.js │ ├── angular-cookies.min.js.map │ ├── angular-jwt.min.js │ ├── angular-md5.min.js │ ├── angular-md5.min.js.map │ ├── angular-ui-router.min.js │ ├── angular.min.js │ ├── angular.min.js.map │ ├── app.js │ ├── bootstrap-datepicker.js │ ├── bootstrap-switch.min.js │ ├── bootstrap.min.js │ ├── faye-browser-min.js │ ├── faye-browser-min.js.map │ ├── jquery-ui.js │ ├── jquery-ui.min.js │ ├── jquery.min.js │ ├── jquery.min.map │ ├── locales │ │ ├── bootstrap-datepicker.bg.js │ │ ├── bootstrap-datepicker.ca.js │ │ ├── bootstrap-datepicker.cs.js │ │ ├── bootstrap-datepicker.da.js │ │ ├── bootstrap-datepicker.de.js │ │ ├── bootstrap-datepicker.el.js │ │ ├── bootstrap-datepicker.es.js │ │ ├── bootstrap-datepicker.fi.js │ │ ├── bootstrap-datepicker.fr.js │ │ ├── bootstrap-datepicker.he.js │ │ ├── bootstrap-datepicker.hr.js │ │ ├── bootstrap-datepicker.id.js │ │ ├── bootstrap-datepicker.is.js │ │ ├── bootstrap-datepicker.it.js │ │ ├── bootstrap-datepicker.ja.js │ │ ├── bootstrap-datepicker.kr.js │ │ ├── bootstrap-datepicker.lt.js │ │ ├── bootstrap-datepicker.lv.js │ │ ├── bootstrap-datepicker.ms.js │ │ ├── bootstrap-datepicker.nb.js │ │ ├── bootstrap-datepicker.nl.js │ │ ├── bootstrap-datepicker.pl.js │ │ ├── bootstrap-datepicker.pt-BR.js │ │ ├── bootstrap-datepicker.pt.js │ │ ├── bootstrap-datepicker.ro.js │ │ ├── bootstrap-datepicker.rs-latin.js │ │ ├── bootstrap-datepicker.rs.js │ │ ├── bootstrap-datepicker.ru.js │ │ ├── bootstrap-datepicker.sk.js │ │ ├── bootstrap-datepicker.sl.js │ │ ├── bootstrap-datepicker.sv.js │ │ ├── bootstrap-datepicker.sw.js │ │ ├── bootstrap-datepicker.th.js │ │ ├── bootstrap-datepicker.tr.js │ │ ├── bootstrap-datepicker.uk.js │ │ ├── bootstrap-datepicker.zh-CN.js │ │ └── bootstrap-datepicker.zh-TW.js │ ├── moment.min.js │ ├── ngCart.js │ ├── ui-bootstrap-tpls.min.js │ └── ui-bootstrap.min.js └── templates │ ├── cart.html │ ├── home.html │ ├── login.html │ ├── ngCart │ ├── cart.html │ └── summary.html │ └── user.html ├── routes └── routes.js └── utils ├── config.json ├── db.js └── provision.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store* 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # This Dockerfile and related *.batinc files are for building a 2 | # "batteries included" docker image, where database, application and 3 | # sample data are all included and pre-installed in a single docker 4 | # image for ease of use. 5 | # 6 | # To build the try-cb-nodejs docker image... 7 | # 8 | # docker build -t try-cb-nodejs . 9 | # 10 | # To launch the try-cb-nodejs docker image in a container instance... 11 | # 12 | # docker run -it --rm -p 3000:3000 -p 8091:8091 try-cb-nodejs 13 | # 14 | FROM couchbase/server:enterprise-4.0.0-rc0 15 | 16 | RUN yum -y install gcc-c++ 17 | 18 | # Originally from https://github.com/joyent/docker-node Dockerfile... 19 | # 20 | # verify gpg and sha256: http://nodejs.org/dist/v0.10.30/SHASUMS256.txt.asc 21 | # gpg: aka "Timothy J Fontaine (Work) " 22 | # gpg: aka "Julien Gilli " 23 | RUN gpg --keyserver pool.sks-keyservers.net --recv-keys 7937DFD2AB06298B2293C3187D33FF9D0246406D 114F43EE0176B71C7BC219DD50A3051F888C628D 24 | 25 | ENV NODE_VERSION 0.12.2 26 | ENV NPM_VERSION 2.9.1 27 | 28 | RUN curl -SLO "http://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz" \ 29 | && curl -SLO "http://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \ 30 | && gpg --verify SHASUMS256.txt.asc \ 31 | && grep " node-v$NODE_VERSION-linux-x64.tar.gz\$" SHASUMS256.txt.asc | sha256sum -c - \ 32 | && tar -xzf "node-v$NODE_VERSION-linux-x64.tar.gz" -C /usr/local --strip-components=1 \ 33 | && rm "node-v$NODE_VERSION-linux-x64.tar.gz" SHASUMS256.txt.asc \ 34 | && npm install -g npm@"$NPM_VERSION" \ 35 | && npm cache clear 36 | 37 | # Originally from https://github.com/joyent/docker-node/blob/0.12/onbuild/Dockerfile... 38 | # 39 | RUN mkdir -p /usr/src/app 40 | 41 | WORKDIR /usr/src/app 42 | 43 | COPY . /usr/src/app 44 | 45 | RUN npm install 46 | 47 | # Finish couchbase and try-cb-nodejs setup... 48 | # 49 | RUN /usr/src/app/config.batinc 50 | 51 | EXPOSE 3000 8091 8092 8093 11210 11211 52 | 53 | ENTRYPOINT ["/bin/bash", "-c"] 54 | 55 | CMD ["/usr/src/app/app.cmd"] 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | try-cb-nodejs 2 | =============== 3 | 4 | A sample application and dataset for getting started with Couchbase 4.0 or later. The application runs a single page UI for demonstrating query capabilities. The application uses Couchbase Server + Node.js + Express + Angular and boostrap. The application is a flight planner that allows the user to search for and select a flight route (including return flight) based on airports and dates. Airport selection is done dynamically using an angular typeahead bound to cb server query. Date selection uses date time pickers and then searches for applicable air flight routes from a previously populated database. 5 | 6 | ## Installation and Configuration 7 | The steps below assume you are running a standalone couchbase instance running kv, indexing, fts (in Couchbase 4.5 or later) and query services on the same server where the node application will also be running. The config.json file in the root of this application can be edited to handle more complex topologies such as running couchbase server inside a vm, or pointing to a docker instance. 8 | 9 | - [1] Install a Couchbase Server, and start it. There is no need to manually configure the server through the admin UI, step 3 (below) will **automatically** provision couchbase and the application. If you've already configured a local instance of Couchbase Server 4.0 or newer, the application can use this instance as long as you specify the credentials to connect to Couchbase within the application configuration file. 10 | 11 | - [2] Install Node.js 12 | 13 | - [3] Make a directory, clone this repo, install dependencies, start the application. From a terminal: 14 | 15 | **mkidr ~/try-cb 16 | git clone https://github.com/couchbaselabs/try-cb-nodejs.git ~/try-cb 17 | cd ~/try-cb** 18 | 19 | **NOTE**:_The remainder of this step uses npm to "build" a cluster. If you already have a configured instance of Couchbase Server, edit the "config.json file in the root of the cloned repository and change the username and password fields to match the credentials you entered when you setup couchbase. You can also skip the remainder of this step. You can also configure the application to use a remote instance of couchbase or MDS by editing the endPoint, n1qlService and hostname fields. For further information on MDS, refer to the Couchbase Documentation_ 20 | 21 | **npm run build** _This step may be omitted if you already have a configured instance of couchbase_ 22 | 23 | - [4] After the cluster has been built, to start the application run from a terminal: 24 | 25 | **npm run start** 26 | 27 | - [5] Open a browser and load the url http://localhost:3000 28 | 29 | **NOTE**: Once the application has provisioned the cluster, if 'npm run build' is executed again the application will first check the cluster is not already provisioned. It will not modify an already provisioned cluster. Use 'npm start' to start the application at any point in the future. 30 | 31 | ## REST API DOCUMENTATION 32 | #### GET /api/airport/findAll?search=<_search string_> [**RETURNS: {"airportname":"<_airport name_>"} for typeahead airports passed in the query string in the parameter "search"**] 33 | --Used for Typeahead 34 | --Queries for Airport by Name, FAA code or ICAO code. 35 | 36 | #### GET /api/flightPath/findAll?from=<_from airport_>&to=<_to airport_>&leave=<_leave date_>&ret=<_return date_> [**RETURNS: {"sourceairport":"<_faa code_>","destinationairport":"<_faa code_>","name":"<_airline name_>","equipment":"<_list of planes airline uses for this route_>"} of available flight routes**] 37 | --Populates the available flights panel on successful query. 38 | --Queries for available flight route by FAA codes, and joins against airline information to provide airline name. 39 | 40 | #### POST /api/user/login _request body_ {"user":<_user_>,"password":<_encrypted password_>} [**RETURNS:{encrypted JSON Web Token}**] 41 | --Creates a new user. 42 | --Returns an Encrypted JSON Web Token used by the Application 43 | 44 | #### GET /api/user/login?user=<_user_>&password=<_encrypted password_>[**RETURNS:{<_success or failure_>:<_error or encrypted JSON Web Token_>}**] 45 | --Logs in a user 46 | --Returns success and JSON Web Token OR failure and error message 47 | 48 | #### POST /api/user/flights _request body_ {"token":<_JSON Web Token_>,"flights":<_group of flights to book_>} [**RETURNS:{"added":<_number of flights booked in this request_>}**] 49 | --Checks if user is logged in from the JSON Web Token and then if token is correct it will book the list of flights passed in. 50 | --Returns number of flights added if successful, or error. 51 | 52 | #### POST /api/user/flights?token=<_JSON Web Token_> [**RETURNS:{list of flights previously booked specific to user}**] 53 | --Checks if the user is logged in from the JSON Web Token and then if token is correct it will return a list of previously booked flights. 54 | --Returns JSON Array of Documents of previously booked flights, or error. 55 | -------------------------------------------------------------------------------- /app.cmd: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | /usr/local/bin/couchbase-start & 4 | 5 | sleep 10 6 | 7 | echo "Starting Travel App -- Web UI available at: http://:3000" 8 | echo "Note: to find your , you can use: boot2docker ip" 9 | 10 | node app.js 11 | 12 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var app = express(); 3 | var config = require('./utils/config'); 4 | var path = require('path'); 5 | 6 | app.use(express.static(path.join(__dirname, 'public'))); 7 | require('./routes/routes')(app); 8 | 9 | app.listen(config.application.httpPort); 10 | 11 | var http = require('http'), 12 | faye = require('faye'); 13 | 14 | var server = http.createServer(), 15 | bayeux = new faye.NodeAdapter({mount: '/faye', timeout: 45}); 16 | 17 | bayeux.attach(server); 18 | server.listen(8000); 19 | 20 | //// ▶▶ uncaught exception - DEBUG only ◀◀ //// 21 | 22 | /* 23 | process.on('uncaughtException', function (err) { 24 | console.log('Caught exception: ' + err); 25 | console.log('Please confirm the couchbase instance: ',config.couchbase.endPoint, 26 | 'is running and accessible. '); 27 | process.exit(); 28 | }); 29 | */ 30 | -------------------------------------------------------------------------------- /config.batinc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | npm install couchbase 4 | 5 | /usr/local/bin/couchbase-start & 6 | 7 | sleep 10 8 | 9 | /opt/couchbase/bin/couchbase-cli cluster-init \ 10 | --cluster=127.0.0.1:8091 \ 11 | -u Administrator -p password \ 12 | --cluster-ramsize=500 \ 13 | --services="data;index;query" 14 | 15 | sleep 10 16 | 17 | /opt/couchbase/bin/cbdocloader \ 18 | -n 127.0.0.1:8091 -u Administrator -p password \ 19 | -b travel-sample -s 400 /opt/couchbase/samples/travel-sample.zip 20 | 21 | sleep 10 22 | 23 | node app.js & 24 | 25 | sleep 10 26 | 27 | curl -v -X POST http://127.0.0.1:3000/api/status/provisionCB 28 | 29 | sleep 10 30 | 31 | ps | grep node | cut -f 2 -d ' ' | xargs kill 32 | 33 | /etc/init.d/couchbase-server stop 34 | 35 | sleep 10 36 | -------------------------------------------------------------------------------- /model/airport.js: -------------------------------------------------------------------------------- 1 | var db = require('./../utils/db'); 2 | var config = require('./../utils/config'); 3 | 4 | 5 | /** 6 | * 7 | * @param queryStr 8 | * @param done 9 | */ 10 | module.exports.findAll = function (queryStr,user,done) { 11 | var queryPrep; 12 | if (queryStr.length == 3) { 13 | queryPrep = "SELECT airportname FROM `" + config.couchbase.bucket + "` WHERE faa ='" + queryStr.toUpperCase() + "'"; 14 | } else if (queryStr.length == 4 && (queryStr==queryStr.toUpperCase()||queryStr==queryStr.toLowerCase())) { 15 | queryPrep = "SELECT airportname FROM `" + config.couchbase.bucket + "` WHERE icao ='" + queryStr.toUpperCase() + "'"; 16 | } else { 17 | queryPrep = "SELECT airportname FROM `" + config.couchbase.bucket + "` WHERE airportname LIKE '" + queryStr + "%'"; 18 | } 19 | 20 | db.query(queryPrep,user,function (err, res) { 21 | if (err) { 22 | done(err, null); 23 | return; 24 | } 25 | if (res) { 26 | done(null, res); 27 | return; 28 | } 29 | }); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /model/auth.js: -------------------------------------------------------------------------------- 1 | var db = require('./../utils/db'); 2 | var jwt = require('jsonwebtoken'); 3 | var config = require('./../utils/config'); 4 | var User = require('./user.js'); 5 | var jwt = require('jsonwebtoken'); 6 | var sec=config.application.hashToken; 7 | 8 | module.exports.createLogin = function (newUser,newPass,done) { 9 | // Check if user Exists 10 | newUser=newUser.toLowerCase(); 11 | filterScan(newUser, function (filtcb) { 12 | if (filtcb) { 13 | User.findByName(newUser, function (err, user) { 14 | if(err){ 15 | // Error 16 | done(err,null); 17 | return; 18 | } 19 | if(user.length==0){ 20 | // Create user 21 | var userNew = new User({ 22 | name:newUser, 23 | password:newPass, 24 | token:jwt.sign({user:newUser},sec), 25 | flights:[] 26 | }); 27 | // Save User 28 | userNew.save(function(err) { 29 | if(err){ 30 | done(err,null); 31 | return; 32 | } 33 | db.refreshExpiry("$User$name|" + userNew.name, 14400, function(error, result) { 34 | db.refreshExpiry("User|" + userNew._id, 14400, function(error, result) {}); 35 | if(error) { 36 | return done(error, null); 37 | } 38 | return done(null, {"success": userNew.token}); 39 | }); 40 | }); 41 | } 42 | if(user.length>0){ 43 | // User Exists 44 | done(null,{"failure":"User exists, please choose a different username"}); 45 | return; 46 | } 47 | }); 48 | } else { 49 | // Word Violation 50 | done(null,{"failure":"Prohibited term, please choose a different username"}); 51 | return; 52 | } 53 | }); 54 | } 55 | 56 | module.exports.login=function(user,pass,done){ 57 | User.findByName(user,function(err,found){ 58 | if(err){ 59 | // Error 60 | done(err,null); 61 | return; 62 | } 63 | if(found.length===0){ 64 | // User not found 65 | done(null,{"failure":"Bad Username or Password"}); 66 | return; 67 | } 68 | if(found.length===1){ 69 | // User Found 70 | if(pass!=found[0].password){ 71 | // Bad Password 72 | done(null,{"failure":"Bad Username or Password"}); 73 | return; 74 | }else{ 75 | done(null,{"success":found[0].token}); 76 | return; 77 | } 78 | } 79 | }) 80 | } 81 | 82 | module.exports.book=function(token,flights,done){ 83 | User.findByName(jwt.decode(token).user,function(err,found){ 84 | if(err){ 85 | done(err,null) 86 | } 87 | if(found) { 88 | found[0].addflights(flights, function (err, count) { 89 | if (err) { 90 | done("error adding flights", null); 91 | return; 92 | } 93 | if (count) { 94 | found[0].save(function (err) { 95 | if (err) { 96 | done(err, null); 97 | return; 98 | } 99 | done(null, count); 100 | return; 101 | }); 102 | } 103 | }); 104 | } 105 | }); 106 | 107 | } 108 | 109 | module.exports.booked =function(token,done){ 110 | User.findByName(jwt.decode(token).user,function(err,found){ 111 | if(err){ 112 | done(err,null); 113 | return; 114 | } 115 | if(found) { 116 | done(null,found[0].flights); 117 | return; 118 | }else{ 119 | done(null,"{}") 120 | return; 121 | } 122 | }); 123 | } 124 | 125 | var filter = []; 126 | 127 | function filterScan(term,done){ 128 | for(var i=0; i div { 78 | display: none; 79 | } 80 | .datepicker.days div.datepicker-days { 81 | display: block; 82 | } 83 | .datepicker.months div.datepicker-months { 84 | display: block; 85 | } 86 | .datepicker.years div.datepicker-years { 87 | display: block; 88 | } 89 | .datepicker table { 90 | margin: 0; 91 | -webkit-touch-callout: none; 92 | -webkit-user-select: none; 93 | -khtml-user-select: none; 94 | -moz-user-select: none; 95 | -ms-user-select: none; 96 | user-select: none; 97 | } 98 | .datepicker td, 99 | .datepicker th { 100 | text-align: center; 101 | width: 20px; 102 | height: 20px; 103 | -webkit-border-radius: 4px; 104 | -moz-border-radius: 4px; 105 | border-radius: 4px; 106 | border: none; 107 | } 108 | .table-striped .datepicker table tr td, 109 | .table-striped .datepicker table tr th { 110 | background-color: transparent; 111 | } 112 | .datepicker table tr td.day:hover, 113 | .datepicker table tr td.day.focused { 114 | background: #eeeeee; 115 | cursor: pointer; 116 | } 117 | .datepicker table tr td.old, 118 | .datepicker table tr td.new { 119 | color: #999999; 120 | } 121 | .datepicker table tr td.disabled, 122 | .datepicker table tr td.disabled:hover { 123 | background: none; 124 | color: #999999; 125 | cursor: default; 126 | } 127 | .datepicker table tr td.today, 128 | .datepicker table tr td.today:hover, 129 | .datepicker table tr td.today.disabled, 130 | .datepicker table tr td.today.disabled:hover { 131 | background-color: #fde19a; 132 | background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a); 133 | background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a); 134 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); 135 | background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a); 136 | background-image: -o-linear-gradient(top, #fdd49a, #fdf59a); 137 | background-image: linear-gradient(top, #fdd49a, #fdf59a); 138 | background-repeat: repeat-x; 139 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); 140 | border-color: #fdf59a #fdf59a #fbed50; 141 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 142 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 143 | color: #000; 144 | } 145 | .datepicker table tr td.today:hover, 146 | .datepicker table tr td.today:hover:hover, 147 | .datepicker table tr td.today.disabled:hover, 148 | .datepicker table tr td.today.disabled:hover:hover, 149 | .datepicker table tr td.today:active, 150 | .datepicker table tr td.today:hover:active, 151 | .datepicker table tr td.today.disabled:active, 152 | .datepicker table tr td.today.disabled:hover:active, 153 | .datepicker table tr td.today.active, 154 | .datepicker table tr td.today:hover.active, 155 | .datepicker table tr td.today.disabled.active, 156 | .datepicker table tr td.today.disabled:hover.active, 157 | .datepicker table tr td.today.disabled, 158 | .datepicker table tr td.today:hover.disabled, 159 | .datepicker table tr td.today.disabled.disabled, 160 | .datepicker table tr td.today.disabled:hover.disabled, 161 | .datepicker table tr td.today[disabled], 162 | .datepicker table tr td.today:hover[disabled], 163 | .datepicker table tr td.today.disabled[disabled], 164 | .datepicker table tr td.today.disabled:hover[disabled] { 165 | background-color: #fdf59a; 166 | } 167 | .datepicker table tr td.today:active, 168 | .datepicker table tr td.today:hover:active, 169 | .datepicker table tr td.today.disabled:active, 170 | .datepicker table tr td.today.disabled:hover:active, 171 | .datepicker table tr td.today.active, 172 | .datepicker table tr td.today:hover.active, 173 | .datepicker table tr td.today.disabled.active, 174 | .datepicker table tr td.today.disabled:hover.active { 175 | background-color: #fbf069 \9; 176 | } 177 | .datepicker table tr td.today:hover:hover { 178 | color: #000; 179 | } 180 | .datepicker table tr td.today.active:hover { 181 | color: #fff; 182 | } 183 | .datepicker table tr td.range, 184 | .datepicker table tr td.range:hover, 185 | .datepicker table tr td.range.disabled, 186 | .datepicker table tr td.range.disabled:hover { 187 | background: #eeeeee; 188 | -webkit-border-radius: 0; 189 | -moz-border-radius: 0; 190 | border-radius: 0; 191 | } 192 | .datepicker table tr td.range.today, 193 | .datepicker table tr td.range.today:hover, 194 | .datepicker table tr td.range.today.disabled, 195 | .datepicker table tr td.range.today.disabled:hover { 196 | background-color: #f3d17a; 197 | background-image: -moz-linear-gradient(top, #f3c17a, #f3e97a); 198 | background-image: -ms-linear-gradient(top, #f3c17a, #f3e97a); 199 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a)); 200 | background-image: -webkit-linear-gradient(top, #f3c17a, #f3e97a); 201 | background-image: -o-linear-gradient(top, #f3c17a, #f3e97a); 202 | background-image: linear-gradient(top, #f3c17a, #f3e97a); 203 | background-repeat: repeat-x; 204 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0); 205 | border-color: #f3e97a #f3e97a #edde34; 206 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 207 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 208 | -webkit-border-radius: 0; 209 | -moz-border-radius: 0; 210 | border-radius: 0; 211 | } 212 | .datepicker table tr td.range.today:hover, 213 | .datepicker table tr td.range.today:hover:hover, 214 | .datepicker table tr td.range.today.disabled:hover, 215 | .datepicker table tr td.range.today.disabled:hover:hover, 216 | .datepicker table tr td.range.today:active, 217 | .datepicker table tr td.range.today:hover:active, 218 | .datepicker table tr td.range.today.disabled:active, 219 | .datepicker table tr td.range.today.disabled:hover:active, 220 | .datepicker table tr td.range.today.active, 221 | .datepicker table tr td.range.today:hover.active, 222 | .datepicker table tr td.range.today.disabled.active, 223 | .datepicker table tr td.range.today.disabled:hover.active, 224 | .datepicker table tr td.range.today.disabled, 225 | .datepicker table tr td.range.today:hover.disabled, 226 | .datepicker table tr td.range.today.disabled.disabled, 227 | .datepicker table tr td.range.today.disabled:hover.disabled, 228 | .datepicker table tr td.range.today[disabled], 229 | .datepicker table tr td.range.today:hover[disabled], 230 | .datepicker table tr td.range.today.disabled[disabled], 231 | .datepicker table tr td.range.today.disabled:hover[disabled] { 232 | background-color: #f3e97a; 233 | } 234 | .datepicker table tr td.range.today:active, 235 | .datepicker table tr td.range.today:hover:active, 236 | .datepicker table tr td.range.today.disabled:active, 237 | .datepicker table tr td.range.today.disabled:hover:active, 238 | .datepicker table tr td.range.today.active, 239 | .datepicker table tr td.range.today:hover.active, 240 | .datepicker table tr td.range.today.disabled.active, 241 | .datepicker table tr td.range.today.disabled:hover.active { 242 | background-color: #efe24b \9; 243 | } 244 | .datepicker table tr td.selected, 245 | .datepicker table tr td.selected:hover, 246 | .datepicker table tr td.selected.disabled, 247 | .datepicker table tr td.selected.disabled:hover { 248 | background-color: #9e9e9e; 249 | background-image: -moz-linear-gradient(top, #b3b3b3, #808080); 250 | background-image: -ms-linear-gradient(top, #b3b3b3, #808080); 251 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080)); 252 | background-image: -webkit-linear-gradient(top, #b3b3b3, #808080); 253 | background-image: -o-linear-gradient(top, #b3b3b3, #808080); 254 | background-image: linear-gradient(top, #b3b3b3, #808080); 255 | background-repeat: repeat-x; 256 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0); 257 | border-color: #808080 #808080 #595959; 258 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 259 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 260 | color: #fff; 261 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 262 | } 263 | .datepicker table tr td.selected:hover, 264 | .datepicker table tr td.selected:hover:hover, 265 | .datepicker table tr td.selected.disabled:hover, 266 | .datepicker table tr td.selected.disabled:hover:hover, 267 | .datepicker table tr td.selected:active, 268 | .datepicker table tr td.selected:hover:active, 269 | .datepicker table tr td.selected.disabled:active, 270 | .datepicker table tr td.selected.disabled:hover:active, 271 | .datepicker table tr td.selected.active, 272 | .datepicker table tr td.selected:hover.active, 273 | .datepicker table tr td.selected.disabled.active, 274 | .datepicker table tr td.selected.disabled:hover.active, 275 | .datepicker table tr td.selected.disabled, 276 | .datepicker table tr td.selected:hover.disabled, 277 | .datepicker table tr td.selected.disabled.disabled, 278 | .datepicker table tr td.selected.disabled:hover.disabled, 279 | .datepicker table tr td.selected[disabled], 280 | .datepicker table tr td.selected:hover[disabled], 281 | .datepicker table tr td.selected.disabled[disabled], 282 | .datepicker table tr td.selected.disabled:hover[disabled] { 283 | background-color: #808080; 284 | } 285 | .datepicker table tr td.selected:active, 286 | .datepicker table tr td.selected:hover:active, 287 | .datepicker table tr td.selected.disabled:active, 288 | .datepicker table tr td.selected.disabled:hover:active, 289 | .datepicker table tr td.selected.active, 290 | .datepicker table tr td.selected:hover.active, 291 | .datepicker table tr td.selected.disabled.active, 292 | .datepicker table tr td.selected.disabled:hover.active { 293 | background-color: #666666 \9; 294 | } 295 | .datepicker table tr td.active, 296 | .datepicker table tr td.active:hover, 297 | .datepicker table tr td.active.disabled, 298 | .datepicker table tr td.active.disabled:hover { 299 | background-color: #006dcc; 300 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc); 301 | background-image: -ms-linear-gradient(top, #0088cc, #0044cc); 302 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); 303 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); 304 | background-image: -o-linear-gradient(top, #0088cc, #0044cc); 305 | background-image: linear-gradient(top, #0088cc, #0044cc); 306 | background-repeat: repeat-x; 307 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); 308 | border-color: #0044cc #0044cc #002a80; 309 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 310 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 311 | color: #fff; 312 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 313 | } 314 | .datepicker table tr td.active:hover, 315 | .datepicker table tr td.active:hover:hover, 316 | .datepicker table tr td.active.disabled:hover, 317 | .datepicker table tr td.active.disabled:hover:hover, 318 | .datepicker table tr td.active:active, 319 | .datepicker table tr td.active:hover:active, 320 | .datepicker table tr td.active.disabled:active, 321 | .datepicker table tr td.active.disabled:hover:active, 322 | .datepicker table tr td.active.active, 323 | .datepicker table tr td.active:hover.active, 324 | .datepicker table tr td.active.disabled.active, 325 | .datepicker table tr td.active.disabled:hover.active, 326 | .datepicker table tr td.active.disabled, 327 | .datepicker table tr td.active:hover.disabled, 328 | .datepicker table tr td.active.disabled.disabled, 329 | .datepicker table tr td.active.disabled:hover.disabled, 330 | .datepicker table tr td.active[disabled], 331 | .datepicker table tr td.active:hover[disabled], 332 | .datepicker table tr td.active.disabled[disabled], 333 | .datepicker table tr td.active.disabled:hover[disabled] { 334 | background-color: #0044cc; 335 | } 336 | .datepicker table tr td.active:active, 337 | .datepicker table tr td.active:hover:active, 338 | .datepicker table tr td.active.disabled:active, 339 | .datepicker table tr td.active.disabled:hover:active, 340 | .datepicker table tr td.active.active, 341 | .datepicker table tr td.active:hover.active, 342 | .datepicker table tr td.active.disabled.active, 343 | .datepicker table tr td.active.disabled:hover.active { 344 | background-color: #003399 \9; 345 | } 346 | .datepicker table tr td span { 347 | display: block; 348 | width: 23%; 349 | height: 54px; 350 | line-height: 54px; 351 | float: left; 352 | margin: 1%; 353 | cursor: pointer; 354 | -webkit-border-radius: 4px; 355 | -moz-border-radius: 4px; 356 | border-radius: 4px; 357 | } 358 | .datepicker table tr td span:hover { 359 | background: #eeeeee; 360 | } 361 | .datepicker table tr td span.disabled, 362 | .datepicker table tr td span.disabled:hover { 363 | background: none; 364 | color: #999999; 365 | cursor: default; 366 | } 367 | .datepicker table tr td span.active, 368 | .datepicker table tr td span.active:hover, 369 | .datepicker table tr td span.active.disabled, 370 | .datepicker table tr td span.active.disabled:hover { 371 | background-color: #006dcc; 372 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc); 373 | background-image: -ms-linear-gradient(top, #0088cc, #0044cc); 374 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); 375 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); 376 | background-image: -o-linear-gradient(top, #0088cc, #0044cc); 377 | background-image: linear-gradient(top, #0088cc, #0044cc); 378 | background-repeat: repeat-x; 379 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); 380 | border-color: #0044cc #0044cc #002a80; 381 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 382 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 383 | color: #fff; 384 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 385 | } 386 | .datepicker table tr td span.active:hover, 387 | .datepicker table tr td span.active:hover:hover, 388 | .datepicker table tr td span.active.disabled:hover, 389 | .datepicker table tr td span.active.disabled:hover:hover, 390 | .datepicker table tr td span.active:active, 391 | .datepicker table tr td span.active:hover:active, 392 | .datepicker table tr td span.active.disabled:active, 393 | .datepicker table tr td span.active.disabled:hover:active, 394 | .datepicker table tr td span.active.active, 395 | .datepicker table tr td span.active:hover.active, 396 | .datepicker table tr td span.active.disabled.active, 397 | .datepicker table tr td span.active.disabled:hover.active, 398 | .datepicker table tr td span.active.disabled, 399 | .datepicker table tr td span.active:hover.disabled, 400 | .datepicker table tr td span.active.disabled.disabled, 401 | .datepicker table tr td span.active.disabled:hover.disabled, 402 | .datepicker table tr td span.active[disabled], 403 | .datepicker table tr td span.active:hover[disabled], 404 | .datepicker table tr td span.active.disabled[disabled], 405 | .datepicker table tr td span.active.disabled:hover[disabled] { 406 | background-color: #0044cc; 407 | } 408 | .datepicker table tr td span.active:active, 409 | .datepicker table tr td span.active:hover:active, 410 | .datepicker table tr td span.active.disabled:active, 411 | .datepicker table tr td span.active.disabled:hover:active, 412 | .datepicker table tr td span.active.active, 413 | .datepicker table tr td span.active:hover.active, 414 | .datepicker table tr td span.active.disabled.active, 415 | .datepicker table tr td span.active.disabled:hover.active { 416 | background-color: #003399 \9; 417 | } 418 | .datepicker table tr td span.old, 419 | .datepicker table tr td span.new { 420 | color: #999999; 421 | } 422 | .datepicker th.datepicker-switch { 423 | width: 145px; 424 | } 425 | .datepicker thead tr:first-child th, 426 | .datepicker tfoot tr th { 427 | cursor: pointer; 428 | } 429 | .datepicker thead tr:first-child th:hover, 430 | .datepicker tfoot tr th:hover { 431 | background: #eeeeee; 432 | } 433 | .datepicker .cw { 434 | font-size: 10px; 435 | width: 12px; 436 | padding: 0 2px 0 5px; 437 | vertical-align: middle; 438 | } 439 | .datepicker thead tr:first-child th.cw { 440 | cursor: default; 441 | background-color: transparent; 442 | } 443 | .input-append.date .add-on i, 444 | .input-prepend.date .add-on i { 445 | cursor: pointer; 446 | width: 16px; 447 | height: 16px; 448 | } 449 | .input-daterange input { 450 | text-align: left; 451 | } 452 | .input-daterange input:first-child { 453 | -webkit-border-radius: 3px 0 0 3px; 454 | -moz-border-radius: 3px 0 0 3px; 455 | border-radius: 3px 0 0 3px; 456 | } 457 | .input-daterange input:last-child { 458 | -webkit-border-radius: 0 3px 3px 0; 459 | -moz-border-radius: 0 3px 3px 0; 460 | border-radius: 0 3px 3px 0; 461 | } 462 | .input-daterange .add-on { 463 | display: inline-block; 464 | width: auto; 465 | min-width: 16px; 466 | height: 20px; 467 | padding: 4px 5px; 468 | font-weight: normal; 469 | line-height: 20px; 470 | text-align: center; 471 | text-shadow: 0 1px 0 #ffffff; 472 | vertical-align: middle; 473 | background-color: #eeeeee; 474 | border: 1px solid #ccc; 475 | margin-left: -5px; 476 | margin-right: -5px; 477 | } 478 | .datepicker.dropdown-menu { 479 | position: absolute; 480 | top: 100%; 481 | left: 0; 482 | z-index: 1000; 483 | float: left; 484 | display: none; 485 | min-width: 160px; 486 | list-style: none; 487 | background-color: #ffffff; 488 | border: 1px solid #ccc; 489 | border: 1px solid rgba(0, 0, 0, 0.2); 490 | -webkit-border-radius: 5px; 491 | -moz-border-radius: 5px; 492 | border-radius: 5px; 493 | -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 494 | -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 495 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 496 | -webkit-background-clip: padding-box; 497 | -moz-background-clip: padding; 498 | background-clip: padding-box; 499 | *border-right-width: 2px; 500 | *border-bottom-width: 2px; 501 | color: #333333; 502 | font-size: 13px; 503 | line-height: 20px; 504 | } 505 | .datepicker.dropdown-menu th, 506 | .datepicker.datepicker-inline th, 507 | .datepicker.dropdown-menu td, 508 | .datepicker.datepicker-inline td { 509 | padding: 4px 5px; 510 | } -------------------------------------------------------------------------------- /public/css/style.css: -------------------------------------------------------------------------------- 1 | .sel-width { 2 | height: 20px; 3 | width: 54px; 4 | } 5 | .abc{ 6 | height:35px; 7 | } 8 | .showMe{ 9 | font-size:10px; 10 | font-weight: bold; 11 | background-color:#000000; 12 | color: #ffff00; 13 | width:99%; 14 | margin-top: 5px; 15 | margin-left: auto; 16 | margin-right: auto; 17 | border: 1px solid black; 18 | } 19 | .insFooter { 20 | font-size:12px; 21 | color:black; 22 | position:fixed; 23 | opacity: 0.7; 24 | left:0px; 25 | bottom:0px; 26 | height:100px; 27 | width:100%; 28 | background:#ffff00; 29 | border:none; 30 | } -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToddGreenstein/try-cb-nodejs/e95beb1d709ce499a55080a409b43c232c072129/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToddGreenstein/try-cb-nodejs/e95beb1d709ce499a55080a409b43c232c072129/public/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToddGreenstein/try-cb-nodejs/e95beb1d709ce499a55080a409b43c232c072129/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToddGreenstein/try-cb-nodejs/e95beb1d709ce499a55080a409b43c232c072129/public/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /public/images/CBTravel.LOGO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToddGreenstein/try-cb-nodejs/e95beb1d709ce499a55080a409b43c232c072129/public/images/CBTravel.LOGO.png -------------------------------------------------------------------------------- /public/images/poweredBy.01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToddGreenstein/try-cb-nodejs/e95beb1d709ce499a55080a409b43c232c072129/public/images/poweredBy.01.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Couchbase Travel || 2015 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 |
28 | 30 | NARRATION : {{fact}} 31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /public/js/angular-cookies.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.4.3 3 | (c) 2010-2015 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(p,g,l){'use strict';function m(b,a,f){var c=f.baseHref(),k=b[0];return function(b,d,e){var f,h;e=e||{};h=e.expires;f=g.isDefined(e.path)?e.path:c;d===l&&(h="Thu, 01 Jan 1970 00:00:00 GMT",d="");g.isString(h)&&(h=new Date(h));d=encodeURIComponent(b)+"="+encodeURIComponent(d);d=d+(f?";path="+f:"")+(e.domain?";domain="+e.domain:"");d+=h?";expires="+h.toUTCString():"";d+=e.secure?";secure":"";e=d.length+1;4096 4096 bytes)!");k.cookie=d}}g.module("ngCookies",["ng"]).provider("$cookies",[function(){var b=this.defaults={};this.$get=["$$cookieReader","$$cookieWriter",function(a,f){return{get:function(c){return a()[c]},getObject:function(c){return(c=this.get(c))?g.fromJson(c):c},getAll:function(){return a()},put:function(c,a,n){f(c,a,n?g.extend({},b,n):b)},putObject:function(c,b,a){this.put(c,g.toJson(b),a)},remove:function(a,k){f(a,l,k?g.extend({},b,k):b)}}}]}]);g.module("ngCookies").factory("$cookieStore", 8 | ["$cookies",function(b){return{get:function(a){return b.getObject(a)},put:function(a,f){b.putObject(a,f)},remove:function(a){b.remove(a)}}}]);m.$inject=["$document","$log","$browser"];g.module("ngCookies").provider("$$cookieWriter",function(){this.$get=m})})(window,window.angular); 9 | //# sourceMappingURL=angular-cookies.min.js.map 10 | -------------------------------------------------------------------------------- /public/js/angular-cookies.min.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version":3, 3 | "file":"angular-cookies.min.js", 4 | "lineCount":7, 5 | "mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkBC,CAAlB,CAA6B,CAmBtCD,CAAAE,OAAA,CAAe,WAAf,CAA4B,CAAC,IAAD,CAA5B,CAAAC,QAAA,CA0BW,UA1BX,CA0BuB,CAAC,YAAD,CAAe,UAAf,CAA2B,QAAQ,CAACC,CAAD,CAAaC,CAAb,CAAuB,CAAA,IACvEC,EAAU,EAD6D,CAEvEC,EAAc,EAFyD,CAGvEC,CAHuE,CAIvEC,EAAU,CAAA,CAJ6D,CAKvEC,EAAOV,CAAAU,KALgE,CAMvEC,EAAcX,CAAAW,YAGlBN,EAAAO,UAAA,CAAmB,QAAQ,EAAG,CAC5B,IAAIC,EAAiBR,CAAAC,QAAA,EACjBE,EAAJ,EAA0BK,CAA1B,GACEL,CAGA,CAHqBK,CAGrB,CAFAH,CAAA,CAAKG,CAAL,CAAqBN,CAArB,CAEA,CADAG,CAAA,CAAKG,CAAL,CAAqBP,CAArB,CACA,CAAIG,CAAJ,EAAaL,CAAAU,OAAA,EAJf,CAF4B,CAA9B,CAAA,EAUAL,EAAA,CAAU,CAAA,CAKVL,EAAAW,OAAA,CASAC,QAAa,EAAG,CAAA,IACVC,CADU,CAEVC,CAFU,CAIVC,CAGJ,KAAKF,CAAL,GAAaV,EAAb,CACMI,CAAA,CAAYL,CAAA,CAAQW,CAAR,CAAZ,CAAJ,EACEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBhB,CAAvB,CAKJ,KAAKgB,CAAL,GAAaX,EAAb,CACEY,CAKA,CALQZ,CAAA,CAAQW,CAAR,CAKR,CAJKjB,CAAAoB,SAAA,CAAiBF,CAAjB,CAIL,GAHEA,CACA,CADQ,EACR,CADaA,CACb,CAAAZ,CAAA,CAAQW,CAAR,CAAA,CAAgBC,CAElB,EAAIA,CAAJ,GAAcX,CAAA,CAAYU,CAAZ,CAAd,GACEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBC,CAAvB,CACA,CAAAC,CAAA,CAAU,CAAA,CAFZ,CAOF,IAAIA,CAAJ,CAIE,IAAKF,CAAL,GAFAI,EAEaf,CAFID,CAAAC,QAAA,EAEJA,CAAAA,CAAb,CACMA,CAAA,CAAQW,CAAR,CAAJ,GAAsBI,CAAA,CAAeJ,CAAf,CAAtB,GAEMN,CAAA,CAAYU,CAAA,CAAeJ,CAAf,CAAZ,CAAJ,CACE,OAAOX,CAAA,CAAQW,CAAR,CADT,CAGEX,CAAA,CAAQW,CAAR,CAHF,CAGkBI,CAAA,CAAeJ,CAAf,CALpB,CAhCU,CAThB,CAEA,OAAOX,EA1BoE,CAA1D,CA1BvB,CAAAH,QAAA,CAoIW,cApIX;AAoI2B,CAAC,UAAD,CAAa,QAAQ,CAACmB,CAAD,CAAW,CAErD,MAAO,CAWLC,IAAKA,QAAQ,CAACC,CAAD,CAAM,CAEjB,MAAO,CADHN,CACG,CADKI,CAAA,CAASE,CAAT,CACL,EAAQxB,CAAAyB,SAAA,CAAiBP,CAAjB,CAAR,CAAkCA,CAFxB,CAXd,CA0BLQ,IAAKA,QAAQ,CAACF,CAAD,CAAMN,CAAN,CAAa,CACxBI,CAAA,CAASE,CAAT,CAAA,CAAgBxB,CAAA2B,OAAA,CAAeT,CAAf,CADQ,CA1BrB,CAuCLU,OAAQA,QAAQ,CAACJ,CAAD,CAAM,CACpB,OAAOF,CAAA,CAASE,CAAT,CADa,CAvCjB,CAF8C,CAAhC,CApI3B,CAnBsC,CAArC,CAAD,CAwMGzB,MAxMH,CAwMWA,MAAAC,QAxMX;", 6 | "sources":["angular-cookies.js"], 7 | "names":["window","angular","undefined","module","factory","$rootScope","$browser","cookies","lastCookies","lastBrowserCookies","runEval","copy","isUndefined","addPollFn","currentCookies","$apply","$watch","push","name","value","updated","isString","browserCookies","$cookies","get","key","fromJson","put","toJson","remove"] 8 | } 9 | -------------------------------------------------------------------------------- /public/js/angular-jwt.min.js: -------------------------------------------------------------------------------- 1 | !function(){angular.module("angular-jwt",["angular-jwt.interceptor","angular-jwt.jwt"]),angular.module("angular-jwt.interceptor",[]).provider("jwtInterceptor",function(){this.authHeader="Authorization",this.authPrefix="Bearer ",this.tokenGetter=function(){return null};var e=this;this.$get=["$q","$injector","$rootScope",function(t,r,n){return{request:function(n){if(n.skipAuthorization)return n;if(n.headers=n.headers||{},n.headers[e.authHeader])return n;var a=t.when(r.invoke(e.tokenGetter,this,{config:n}));return a.then(function(t){return t&&(n.headers[e.authHeader]=e.authPrefix+t),n})},responseError:function(e){return 401===e.status&&n.$broadcast("unauthenticated",e),t.reject(e)}}}]}),angular.module("angular-jwt.jwt",[]).service("jwtHelper",function(){this.urlBase64Decode=function(e){var t=e.replace("-","+").replace("_","/");switch(t.length%4){case 0:break;case 2:t+="==";break;case 3:t+="=";break;default:throw"Illegal base64url string!"}return decodeURIComponent(escape(window.atob(t)))},this.decodeToken=function(e){var t=e.split(".");if(3!==t.length)throw new Error("JWT must have 3 parts");var r=this.urlBase64Decode(t[1]);if(!r)throw new Error("Cannot decode the token");return JSON.parse(r)},this.getTokenExpirationDate=function(e){var t;if(t=this.decodeToken(e),!t.exp)return null;var r=new Date(0);return r.setUTCSeconds(t.exp),r},this.isTokenExpired=function(e){var t=this.getTokenExpirationDate(e);return t?!(t.valueOf()>(new Date).valueOf()):!1}})}(); -------------------------------------------------------------------------------- /public/js/angular-md5.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | angular-md5 - v0.1.7 3 | 2014-01-20 4 | */ 5 | 6 | !function(a,b){b.module("angular-md5",["gdi2290.md5"]),b.module("ngMd5",["gdi2290.md5"]),b.module("gdi2290.md5",["gdi2290.gravatar-filter","gdi2290.md5-service","gdi2290.md5-filter"]),b.module("gdi2290.gravatar-filter",[]).filter("gravatar",["md5",function(a){var b={};return function(c,d){return b[c]||(d=d?a.createHash(d.toString().toLowerCase()):"",b[c]=c?a.createHash(c.toString().toLowerCase()):d),b[c]}}]),b.module("gdi2290.md5-filter",[]).filter("md5",["md5",function(a){return function(b){return b?a.createHash(b.toString().toLowerCase()):b}}]),b.module("gdi2290.md5-service",[]).factory("md5",[function(){var a={createHash:function(a){var b,c,d,e,f,g,h,i,j,k,l=function(a,b){return a<>>32-b},m=function(a,b){var c,d,e,f,g;return e=2147483648&a,f=2147483648&b,c=1073741824&a,d=1073741824&b,g=(1073741823&a)+(1073741823&b),c&d?2147483648^g^e^f:c|d?1073741824&g?3221225472^g^e^f:1073741824^g^e^f:g^e^f},n=function(a,b,c){return a&b|~a&c},o=function(a,b,c){return a&c|b&~c},p=function(a,b,c){return a^b^c},q=function(a,b,c){return b^(a|~c)},r=function(a,b,c,d,e,f,g){return a=m(a,m(m(n(b,c,d),e),g)),m(l(a,f),b)},s=function(a,b,c,d,e,f,g){return a=m(a,m(m(o(b,c,d),e),g)),m(l(a,f),b)},t=function(a,b,c,d,e,f,g){return a=m(a,m(m(p(b,c,d),e),g)),m(l(a,f),b)},u=function(a,b,c,d,e,f,g){return a=m(a,m(m(q(b,c,d),e),g)),m(l(a,f),b)},v=function(a){for(var b,c=a.length,d=c+8,e=(d-d%64)/64,f=16*(e+1),g=new Array(f-1),h=0,i=0;c>i;)b=(i-i%4)/4,h=i%4*8,g[b]=g[b]|a.charCodeAt(i)<>>29,g},w=function(a){var b,c,d="",e="";for(c=0;3>=c;c++)b=a>>>8*c&255,e="0"+b.toString(16),d+=e.substr(e.length-2,2);return d},x=[],y=7,z=12,A=17,B=22,C=5,D=9,E=14,F=20,G=4,H=11,I=16,J=23,K=6,L=10,M=15,N=21;for(x=v(a),h=1732584193,i=4023233417,j=2562383102,k=271733878,b=x.length,c=0;b>c;c+=16)d=h,e=i,f=j,g=k,h=r(h,i,j,k,x[c+0],y,3614090360),k=r(k,h,i,j,x[c+1],z,3905402710),j=r(j,k,h,i,x[c+2],A,606105819),i=r(i,j,k,h,x[c+3],B,3250441966),h=r(h,i,j,k,x[c+4],y,4118548399),k=r(k,h,i,j,x[c+5],z,1200080426),j=r(j,k,h,i,x[c+6],A,2821735955),i=r(i,j,k,h,x[c+7],B,4249261313),h=r(h,i,j,k,x[c+8],y,1770035416),k=r(k,h,i,j,x[c+9],z,2336552879),j=r(j,k,h,i,x[c+10],A,4294925233),i=r(i,j,k,h,x[c+11],B,2304563134),h=r(h,i,j,k,x[c+12],y,1804603682),k=r(k,h,i,j,x[c+13],z,4254626195),j=r(j,k,h,i,x[c+14],A,2792965006),i=r(i,j,k,h,x[c+15],B,1236535329),h=s(h,i,j,k,x[c+1],C,4129170786),k=s(k,h,i,j,x[c+6],D,3225465664),j=s(j,k,h,i,x[c+11],E,643717713),i=s(i,j,k,h,x[c+0],F,3921069994),h=s(h,i,j,k,x[c+5],C,3593408605),k=s(k,h,i,j,x[c+10],D,38016083),j=s(j,k,h,i,x[c+15],E,3634488961),i=s(i,j,k,h,x[c+4],F,3889429448),h=s(h,i,j,k,x[c+9],C,568446438),k=s(k,h,i,j,x[c+14],D,3275163606),j=s(j,k,h,i,x[c+3],E,4107603335),i=s(i,j,k,h,x[c+8],F,1163531501),h=s(h,i,j,k,x[c+13],C,2850285829),k=s(k,h,i,j,x[c+2],D,4243563512),j=s(j,k,h,i,x[c+7],E,1735328473),i=s(i,j,k,h,x[c+12],F,2368359562),h=t(h,i,j,k,x[c+5],G,4294588738),k=t(k,h,i,j,x[c+8],H,2272392833),j=t(j,k,h,i,x[c+11],I,1839030562),i=t(i,j,k,h,x[c+14],J,4259657740),h=t(h,i,j,k,x[c+1],G,2763975236),k=t(k,h,i,j,x[c+4],H,1272893353),j=t(j,k,h,i,x[c+7],I,4139469664),i=t(i,j,k,h,x[c+10],J,3200236656),h=t(h,i,j,k,x[c+13],G,681279174),k=t(k,h,i,j,x[c+0],H,3936430074),j=t(j,k,h,i,x[c+3],I,3572445317),i=t(i,j,k,h,x[c+6],J,76029189),h=t(h,i,j,k,x[c+9],G,3654602809),k=t(k,h,i,j,x[c+12],H,3873151461),j=t(j,k,h,i,x[c+15],I,530742520),i=t(i,j,k,h,x[c+2],J,3299628645),h=u(h,i,j,k,x[c+0],K,4096336452),k=u(k,h,i,j,x[c+7],L,1126891415),j=u(j,k,h,i,x[c+14],M,2878612391),i=u(i,j,k,h,x[c+5],N,4237533241),h=u(h,i,j,k,x[c+12],K,1700485571),k=u(k,h,i,j,x[c+3],L,2399980690),j=u(j,k,h,i,x[c+10],M,4293915773),i=u(i,j,k,h,x[c+1],N,2240044497),h=u(h,i,j,k,x[c+8],K,1873313359),k=u(k,h,i,j,x[c+15],L,4264355552),j=u(j,k,h,i,x[c+6],M,2734768916),i=u(i,j,k,h,x[c+13],N,1309151649),h=u(h,i,j,k,x[c+4],K,4149444226),k=u(k,h,i,j,x[c+11],L,3174756917),j=u(j,k,h,i,x[c+2],M,718787259),i=u(i,j,k,h,x[c+9],N,3951481745),h=m(h,d),i=m(i,e),j=m(j,f),k=m(k,g);var O=w(h)+w(i)+w(j)+w(k);return O.toLowerCase()}};return a}])}(this,this.angular,void 0); 7 | //# sourceMappingURL=angular-md5.min.js.map -------------------------------------------------------------------------------- /public/js/angular-md5.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"angular-md5.min.js","sources":["?",".tmp/angular-md5.js"],"names":["window","angular","module","filter","md5","cache","text","defaultText","createHash","toString","toLowerCase","factory","str","xl","k","AA","BB","CC","DD","a","b","c","d","rotateLeft","lValue","iShiftBits","addUnsigned","lX","lY","lX4","lY4","lX8","lY8","lResult","_F","x","y","z","_G","_H","_I","_FF","s","ac","_GG","_HH","_II","convertToWordArray","lWordCount","lMessageLength","length","lNumberOfWords_temp1","lNumberOfWords_temp2","lNumberOfWords","lWordArray","Array","lBytePosition","lByteCount","charCodeAt","wordToHex","lByte","lCount","wordToHexValue","wordToHexValue_temp","substr","S11","S12","S13","S14","S21","S22","S23","S24","S31","S32","S33","S34","S41","S42","S43","S44","temp","this"],"mappings":";;;;;CAAA,SAAUA,EAAOC,GCAjBA,EAAQC,OAAO,eAAgB,gBAC/BD,EAAQC,OAAO,SAAU,gBACzBD,EAAQC,OAAO,eACb,0BACA,sBACA,uBAEFD,EAAQC,OAAO,8BAA+BC,OAAO,YACnD,MACA,SAAUC,GACR,GAAIC,KACJ,OAAO,UAAUC,EAAMC,GAKrB,MAJKF,GAAMC,KACTC,EAAcA,EAAcH,EAAII,WAAWD,EAAYE,WAAWC,eAAiB,GACnFL,EAAMC,GAAQA,EAAOF,EAAII,WAAWF,EAAKG,WAAWC,eAAiBH,GAEhEF,EAAMC,OAInBL,EAAQC,OAAO,yBAA0BC,OAAO,OAC9C,MACA,SAAUC,GACR,MAAO,UAAUE,GACf,MAAOA,GAAOF,EAAII,WAAWF,EAAKG,WAAWC,eAAiBJ,MAIpEL,EAAQC,OAAO,0BAA2BS,QAAQ,OAAQ,WACtD,GAAIP,IACAI,WAAY,SAAUI,GACpB,GAAIC,GAmFQC,EAAGC,EAAIC,EAAIC,EAAIC,EAAIC,EAAGC,EAAGC,EAAGC,EAlFpCC,EAAa,SAAUC,EAAQC,GACjC,MAAOD,IAAUC,EAAaD,IAAW,GAAKC,GAE5CC,EAAc,SAAUC,EAAIC,GAC9B,GAAIC,GAAKC,EAAKC,EAAKC,EAAKC,CAMxB,OALAF,GAAW,WAALJ,EACNK,EAAW,WAALJ,EACNC,EAAW,WAALF,EACNG,EAAW,WAALF,EACNK,GAAgB,WAALN,IAAyB,WAALC,GAC3BC,EAAMC,EACS,WAAVG,EAAuBF,EAAMC,EAElCH,EAAMC,EACM,WAAVG,EACe,WAAVA,EAAuBF,EAAMC,EAEnB,WAAVC,EAAuBF,EAAMC,EAG/BC,EAAUF,EAAMC,GAGvBE,EAAK,SAAUC,EAAGC,EAAGC,GACvB,MAAOF,GAAIC,GAAKD,EAAIE,GAElBC,EAAK,SAAUH,EAAGC,EAAGC,GACvB,MAAOF,GAAIE,EAAID,GAAKC,GAElBE,EAAK,SAAUJ,EAAGC,EAAGC,GACvB,MAAOF,GAAIC,EAAIC,GAEbG,EAAK,SAAUL,EAAGC,EAAGC,GACvB,MAAOD,IAAKD,GAAKE,IAEfI,EAAM,SAAUtB,EAAGC,EAAGC,EAAGC,EAAGa,EAAGO,EAAGC,GAEpC,MADAxB,GAAIO,EAAYP,EAAGO,EAAYA,EAAYQ,EAAGd,EAAGC,EAAGC,GAAIa,GAAIQ,IACrDjB,EAAYH,EAAWJ,EAAGuB,GAAItB,IAEnCwB,EAAM,SAAUzB,EAAGC,EAAGC,EAAGC,EAAGa,EAAGO,EAAGC,GAEpC,MADAxB,GAAIO,EAAYP,EAAGO,EAAYA,EAAYY,EAAGlB,EAAGC,EAAGC,GAAIa,GAAIQ,IACrDjB,EAAYH,EAAWJ,EAAGuB,GAAItB,IAEnCyB,EAAM,SAAU1B,EAAGC,EAAGC,EAAGC,EAAGa,EAAGO,EAAGC,GAEpC,MADAxB,GAAIO,EAAYP,EAAGO,EAAYA,EAAYa,EAAGnB,EAAGC,EAAGC,GAAIa,GAAIQ,IACrDjB,EAAYH,EAAWJ,EAAGuB,GAAItB,IAEnC0B,EAAM,SAAU3B,EAAGC,EAAGC,EAAGC,EAAGa,EAAGO,EAAGC,GAEpC,MADAxB,GAAIO,EAAYP,EAAGO,EAAYA,EAAYc,EAAGpB,EAAGC,EAAGC,GAAIa,GAAIQ,IACrDjB,EAAYH,EAAWJ,EAAGuB,GAAItB,IAEnC2B,EAAqB,SAAUnC,GASjC,IARA,GAAIoC,GACAC,EAAiBrC,EAAIsC,OACrBC,EAAuBF,EAAiB,EACxCG,GAAwBD,EAAuBA,EAAuB,IAAM,GAC5EE,EAA8C,IAA5BD,EAAuB,GACzCE,EAAa,GAAIC,OAAMF,EAAiB,GACxCG,EAAgB,EAChBC,EAAa,EACGR,EAAbQ,GACLT,GAAcS,EAAaA,EAAa,GAAK,EAC7CD,EAAgBC,EAAa,EAAI,EACjCH,EAAWN,GAAcM,EAAWN,GAAcpC,EAAI8C,WAAWD,IAAeD,EAChFC,GAOF,OALAT,IAAcS,EAAaA,EAAa,GAAK,EAC7CD,EAAgBC,EAAa,EAAI,EACjCH,EAAWN,GAAcM,EAAWN,GAAc,KAAOQ,EACzDF,EAAWD,EAAiB,GAAKJ,GAAkB,EACnDK,EAAWD,EAAiB,GAAKJ,IAAmB,GAC7CK,GAELK,EAAY,SAAUnC,GACxB,GAAmDoC,GAAOC,EAAtDC,EAAiB,GAAIC,EAAsB,EAC/C,KAAKF,EAAS,EAAa,GAAVA,EAAaA,IAC5BD,EAAQpC,IAAoB,EAATqC,EAAa,IAChCE,EAAsB,IAAMH,EAAMnD,SAAS,IAC3CqD,GAAkCC,EAAoBC,OAAOD,EAAoBb,OAAS,EAAG,EAE/F,OAAOY,IAEL3B,KAAuC8B,EAAM,EAAGC,EAAM,GAAIC,EAAM,GAAIC,EAAM,GAAIC,EAAM,EAAGC,EAAM,EAAGC,EAAM,GAAIC,EAAM,GAAIC,EAAM,EAAGC,EAAM,GAAIC,EAAM,GAAIC,EAAM,GAAIC,EAAM,EAAGC,EAAM,GAAIC,EAAM,GAAIC,EAAM,EAOlM,KANA7C,EAAIY,EAAmBnC,GACvBO,EAAI,WACJC,EAAI,WACJC,EAAI,WACJC,EAAI,UACJT,EAAKsB,EAAEe,OACFpC,EAAI,EAAOD,EAAJC,EAAQA,GAAK,GACvBC,EAAKI,EACLH,EAAKI,EACLH,EAAKI,EACLH,EAAKI,EACLH,EAAIsB,EAAItB,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,GAAImD,EAAK,YACnC3C,EAAImB,EAAInB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,GAAIoD,EAAK,YACnC7C,EAAIoB,EAAIpB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,GAAIqD,EAAK,WACnC/C,EAAIqB,EAAIrB,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,GAAIsD,EAAK,YACnCjD,EAAIsB,EAAItB,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,GAAImD,EAAK,YACnC3C,EAAImB,EAAInB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,GAAIoD,EAAK,YACnC7C,EAAIoB,EAAIpB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,GAAIqD,EAAK,YACnC/C,EAAIqB,EAAIrB,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,GAAIsD,EAAK,YACnCjD,EAAIsB,EAAItB,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,GAAImD,EAAK,YACnC3C,EAAImB,EAAInB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,GAAIoD,EAAK,YACnC7C,EAAIoB,EAAIpB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,IAAKqD,EAAK,YACpC/C,EAAIqB,EAAIrB,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,IAAKsD,EAAK,YACpCjD,EAAIsB,EAAItB,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,IAAKmD,EAAK,YACpC3C,EAAImB,EAAInB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,IAAKoD,EAAK,YACpC7C,EAAIoB,EAAIpB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,IAAKqD,EAAK,YACpC/C,EAAIqB,EAAIrB,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,IAAKsD,EAAK,YACpCjD,EAAIyB,EAAIzB,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,GAAIuD,EAAK,YACnC/C,EAAIsB,EAAItB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,GAAIwD,EAAK,YACnCjD,EAAIuB,EAAIvB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,IAAKyD,EAAK,WACpCnD,EAAIwB,EAAIxB,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,GAAI0D,EAAK,YACnCrD,EAAIyB,EAAIzB,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,GAAIuD,EAAK,YACnC/C,EAAIsB,EAAItB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,IAAKwD,EAAK,UACpCjD,EAAIuB,EAAIvB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,IAAKyD,EAAK,YACpCnD,EAAIwB,EAAIxB,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,GAAI0D,EAAK,YACnCrD,EAAIyB,EAAIzB,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,GAAIuD,EAAK,WACnC/C,EAAIsB,EAAItB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,IAAKwD,EAAK,YACpCjD,EAAIuB,EAAIvB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,GAAIyD,EAAK,YACnCnD,EAAIwB,EAAIxB,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,GAAI0D,EAAK,YACnCrD,EAAIyB,EAAIzB,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,IAAKuD,EAAK,YACpC/C,EAAIsB,EAAItB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,GAAIwD,EAAK,YACnCjD,EAAIuB,EAAIvB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,GAAIyD,EAAK,YACnCnD,EAAIwB,EAAIxB,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,IAAK0D,EAAK,YACpCrD,EAAI0B,EAAI1B,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,GAAI2D,EAAK,YACnCnD,EAAIuB,EAAIvB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,GAAI4D,EAAK,YACnCrD,EAAIwB,EAAIxB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,IAAK6D,EAAK,YACpCvD,EAAIyB,EAAIzB,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,IAAK8D,EAAK,YACpCzD,EAAI0B,EAAI1B,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,GAAI2D,EAAK,YACnCnD,EAAIuB,EAAIvB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,GAAI4D,EAAK,YACnCrD,EAAIwB,EAAIxB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,GAAI6D,EAAK,YACnCvD,EAAIyB,EAAIzB,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,IAAK8D,EAAK,YACpCzD,EAAI0B,EAAI1B,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,IAAK2D,EAAK,WACpCnD,EAAIuB,EAAIvB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,GAAI4D,EAAK,YACnCrD,EAAIwB,EAAIxB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,GAAI6D,EAAK,YACnCvD,EAAIyB,EAAIzB,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,GAAI8D,EAAK,UACnCzD,EAAI0B,EAAI1B,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,GAAI2D,EAAK,YACnCnD,EAAIuB,EAAIvB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,IAAK4D,EAAK,YACpCrD,EAAIwB,EAAIxB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,IAAK6D,EAAK,WACpCvD,EAAIyB,EAAIzB,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,GAAI8D,EAAK,YACnCzD,EAAI2B,EAAI3B,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,GAAI+D,EAAK,YACnCvD,EAAIwB,EAAIxB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,GAAIgE,EAAK,YACnCzD,EAAIyB,EAAIzB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,IAAKiE,EAAK,YACpC3D,EAAI0B,EAAI1B,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,GAAIkE,EAAK,YACnC7D,EAAI2B,EAAI3B,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,IAAK+D,EAAK,YACpCvD,EAAIwB,EAAIxB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,GAAIgE,EAAK,YACnCzD,EAAIyB,EAAIzB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,IAAKiE,EAAK,YACpC3D,EAAI0B,EAAI1B,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,GAAIkE,EAAK,YACnC7D,EAAI2B,EAAI3B,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,GAAI+D,EAAK,YACnCvD,EAAIwB,EAAIxB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,IAAKgE,EAAK,YACpCzD,EAAIyB,EAAIzB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,GAAIiE,EAAK,YACnC3D,EAAI0B,EAAI1B,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,IAAKkE,EAAK,YACpC7D,EAAI2B,EAAI3B,EAAGC,EAAGC,EAAGC,EAAGa,EAAErB,EAAI,GAAI+D,EAAK,YACnCvD,EAAIwB,EAAIxB,EAAGH,EAAGC,EAAGC,EAAGc,EAAErB,EAAI,IAAKgE,EAAK,YACpCzD,EAAIyB,EAAIzB,EAAGC,EAAGH,EAAGC,EAAGe,EAAErB,EAAI,GAAIiE,EAAK,WACnC3D,EAAI0B,EAAI1B,EAAGC,EAAGC,EAAGH,EAAGgB,EAAErB,EAAI,GAAIkE,EAAK,YACnC7D,EAAIO,EAAYP,EAAGJ,GACnBK,EAAIM,EAAYN,EAAGJ,GACnBK,EAAIK,EAAYL,EAAGJ,GACnBK,EAAII,EAAYJ,EAAGJ,EAErB,IAAI+D,GAAOtB,EAAUxC,GAAKwC,EAAUvC,GAAKuC,EAAUtC,GAAKsC,EAAUrC,EAClE,OAAO2D,GAAKvE,eAGlB,OAAON,ODvMsC8E,KAAKA,KAAKjF,QAAQ"} -------------------------------------------------------------------------------- /public/js/app.js: -------------------------------------------------------------------------------- 1 | var travelApp = angular.module("travelapp", ["ui.router", 'ui.bootstrap','ngCart','angular-md5','ngCookies','angular-jwt']); 2 | var fayeClient = null; 3 | 4 | /* 5 | * AngularJS Config Method 6 | * 7 | * All configuration happens here. Usually routes and or language (i18n, l10n) goes here 8 | */ 9 | travelApp.config(function($stateProvider, $urlRouterProvider) { 10 | $stateProvider 11 | .state("home", { 12 | url: "/home", 13 | templateUrl: "templates/home.html", 14 | controller: "HomeController" 15 | }) 16 | .state("login", { 17 | url: "/login", 18 | templateUrl: "templates/login.html", 19 | controller: "LoginController" 20 | }) 21 | .state("cart", { 22 | url: "/cart", 23 | templateUrl: "templates/cart.html" 24 | }) 25 | .state("user", { 26 | url: "/user", 27 | templateUrl: "templates/user.html", 28 | controller: "UserController" 29 | }); 30 | }); 31 | 32 | /* 33 | * AngularJS Run Method 34 | * 35 | * All global initialization happens in this method. It is run only once when the application is first 36 | * loaded 37 | */ 38 | travelApp.run(function($rootScope, $state, $cookies) { 39 | $rootScope.showCode = true; 40 | $rootScope.publishMessage = function(message) { 41 | $rootScope.textAreaShowMe = message + "\n" + ($rootScope.textAreaShowMe ? $rootScope.textAreaShowMe : ""); 42 | }; 43 | fayeClient = new Faye.Client("http://" + window.location.hostname + ":8000" + "/faye",{timeout:30}); 44 | if($cookies.get("user")) { 45 | var subscription = fayeClient.subscribe("/" + ($cookies.get("user")).replace(".","_"), function(message) { 46 | $rootScope.publishMessage(message.text); 47 | }); 48 | $state.go("home"); 49 | } else { 50 | $state.go("login"); 51 | $rootScope.fact="User authorization through couchbase and ottoman user objects"; 52 | } 53 | }); 54 | 55 | travelApp.controller("LoginController", function($scope, $rootScope, $state, $http, md5, $cookies, jwtHelper) { 56 | $scope.login = function(username, password, isNew) { 57 | $cookies.remove("token"); 58 | $cookies.remove("user"); 59 | var cookieExpiration = new Date(); 60 | cookieExpiration.setHours(cookieExpiration.getHours() + 4); 61 | if(isNew === true) { 62 | $rootScope.publishMessage("REST POST=/api/user/login"); 63 | $http.post("/api/user/login", 64 | { 65 | user: username, 66 | password:md5.createHash(password) 67 | } 68 | ) 69 | .then(function(response) { 70 | if(response.data.success) { 71 | $scope.formData.error = null; 72 | $cookies.put('token',response.data.success, {"expires": cookieExpiration}); 73 | $cookies.put('user',jwtHelper.decodeToken(response.data.success).user, {"expires": cookieExpiration}); 74 | var subscription = fayeClient.subscribe("/" + ($cookies.get("user")).replace(".","_"), function(message) { 75 | $rootScope.publishMessage(message.text); 76 | }); 77 | $state.go("home"); 78 | } 79 | if(response.data.failure) { 80 | $scope.formData.error = response.data.failure; 81 | } 82 | }, function(error) { 83 | console.log(JSON.stringify(error)); 84 | }); 85 | } else { 86 | $rootScope.publishMessage("REST REQ=/api/user/login"); 87 | $http.get("/api/user/login", 88 | { 89 | params: { 90 | user:username, 91 | password:md5.createHash(password) 92 | } 93 | } 94 | ) 95 | .then(function(response) { 96 | if(response.data.success){ 97 | $scope.formData.error=null; 98 | $cookies.put('token',response.data.success, {"expires": cookieExpiration}); 99 | $cookies.put('user',jwtHelper.decodeToken(response.data.success).user, {"expires": cookieExpiration}); 100 | var subscription = fayeClient.subscribe("/" + ($cookies.get("user")).replace(".","_"), function(message) { 101 | $rootScope.publishMessage(message.text); 102 | }); 103 | $state.go("home"); 104 | } 105 | if(response.data.failure) { 106 | $scope.formData.error = response.data.failure; 107 | } 108 | }, function(error) { 109 | console.log(JSON.stringify(error)); 110 | }); 111 | } 112 | } 113 | $scope.toggleDebug = function() { 114 | $rootScope.showCode = !$rootScope.showCode; 115 | } 116 | }); 117 | 118 | travelApp.controller("HomeController", function($scope, $rootScope, $state, $http, $cookies, $window, ngCart) { 119 | 120 | $scope.empty = true; 121 | 122 | $scope.findAirports = function(val) { 123 | $rootScope.fact="Typeahead bound to REST call: /api/airport/findAll"; 124 | $rootScope.publishMessage("REST REQ=/api/airport/findAll"); 125 | return $http.get("/api/airport/findAll", 126 | { 127 | params: { 128 | search: val, 129 | token: $cookies.get('token') 130 | } 131 | } 132 | ) 133 | .then(function(response) { 134 | return response.data; 135 | }); 136 | }; 137 | $scope.findFlights = function(fromName, toName, departDate) { 138 | $rootScope.fact = "Searching for flights using REST call: /api/flightPath/findAll"; 139 | $scope.rowCollectionLeave = []; 140 | $scope.rowCollectionRet = []; 141 | $scope.departDate = $("#leaveDate").val(); 142 | $scope.returnDate = $("#retDate").val(); 143 | $rootScope.publishMessage("REST REQ=/api/flightPath/findAll"); 144 | $http.get("/api/flightPath/findAll", 145 | { 146 | params: { 147 | from: fromName, 148 | to: toName, 149 | leave: $scope.departDate, 150 | token:$cookies.get('token') 151 | } 152 | } 153 | ) 154 | .then(function(response) { 155 | if (response.data.length > 0) { 156 | $scope.empty = false; 157 | } 158 | for (var j = 0; j < response.data.length; j++) { 159 | var d= new Date(Date.parse($scope.departDate + " " + response.data[j].utc)); 160 | d.setHours(d.getHours()+response.data[j].flighttime); 161 | response.data[j].utcland = d.getHours() + ":" + d.getMinutes() + ":00"; 162 | $scope.rowCollectionLeave.push(response.data[j]); 163 | } 164 | }, function(error) { 165 | console.log(JSON.stringify(error)); 166 | }); 167 | if($scope.returnDate) { 168 | $rootScope.publishMessage("REST REQ=/api/flightPath/findAll"); 169 | $http.get("/api/flightPath/findAll", 170 | { 171 | params: { 172 | from: toName, 173 | to: fromName, 174 | leave: $scope.returnDate, 175 | token:$cookies.get('token') 176 | } 177 | } 178 | ) 179 | .then(function(responseRet) { 180 | if (responseRet.data.length > 0) { 181 | $scope.retEmpty = false; 182 | } 183 | for (var j = 0; j < responseRet.data.length; j++) { 184 | var d= new Date(Date.parse($scope.returnDate + " " + responseRet.data[j].utc)); 185 | d.setHours(d.getHours()+responseRet.data[j].flighttime); 186 | responseRet.data[j].utcland = d.getHours() + ":" + d.getMinutes() + ":00"; 187 | $scope.rowCollectionRet.push(responseRet.data[j]); 188 | } 189 | }, function(error) { 190 | console.log(JSON.stringify(error)); 191 | }); 192 | } 193 | }; 194 | $scope.removeRow = function(row) { 195 | var index = $scope.rowCollectionLeave.indexOf(row); 196 | if (index !== -1) { 197 | $scope.rowCollectionLeave.splice(index, 1); 198 | } 199 | }; 200 | $scope.selectRow = function(row) { 201 | $rootScope.fact="Native Angular Validation, choose OUTBOUND row "; 202 | $scope.rowCollectionLeave=[]; 203 | $scope.rowCollectionLeave.push(row); 204 | row.date=$scope.departDate; 205 | ngCart.addItem(row.flight,row.name +"-"+row.flight,row.price,1,row); 206 | var tempRet=[]; 207 | for (var k=0;k<$scope.rowCollectionRet.length;k++){ 208 | if($scope.rowCollectionRet[k].name == row.name){ 209 | tempRet.push($scope.rowCollectionRet[k]); 210 | } 211 | } 212 | $scope.rowCollectionRet=tempRet; 213 | }; 214 | $scope.removeRowRet = function(row) { 215 | var index = $scope.rowCollectionRet.indexOf(row); 216 | if (index !== -1) { 217 | $scope.rowCollectionRet.splice(index, 1); 218 | } 219 | }; 220 | $scope.selectRowRet = function(row) { 221 | $rootScope.fact="Native Angular Validation, choose INBOUND row "; 222 | $scope.rowCollectionRet=[]; 223 | $scope.rowCollectionRet.push(row); 224 | row.date=$scope.returnDate; 225 | ngCart.addItem(row.flight,row.name +"-"+row.flight,row.price,1,row); 226 | var tempLeave=[]; 227 | for (var j=0;j<$scope.rowCollectionLeave.length;j++){ 228 | if($scope.rowCollectionLeave[j].name == row.name){ 229 | tempLeave.push($scope.rowCollectionLeave[j]); 230 | } 231 | } 232 | $scope.rowCollectionLeave=tempLeave; 233 | }; 234 | 235 | $('.input-daterange').datepicker( 236 | { 237 | "todayHighlight": true, 238 | "autoclose":true, 239 | "startDate":"+0d" 240 | } 241 | ).on("changeDate", function(ev) { 242 | var date = new Date(ev.date); 243 | //$scope.departDate = ev.date; 244 | //$rootScope.publishMessage("DATE SELECTED≔" + (date.getMonth() + 1) + "-" + date.getDate() + "-" + date.getFullYear()); 245 | $("#textAreaShowMe").val("DATE SELECTED≔" + (date.getMonth() + 1) + "-" + date.getDate() + "-" + date.getFullYear() + "\n" + $("#textAreaShowMe").val()); 246 | }).on("show",function(sh){ 247 | $rootScope.fact="Selecting DATE from DatePicker"; 248 | }); 249 | 250 | $("input.switch").bootstrapSwitch({ 251 | onText: '⇄', 252 | offText: '→', 253 | size: 'small', 254 | state: true 255 | }); 256 | $("input.switch").on('switchChange.bootstrapSwitch', function (event, state) { 257 | if(!state){ 258 | $scope.fact="Changing to ONE WAY"; 259 | $("#retDate").hide(); 260 | $("#retSpan").hide(); 261 | $("#retLabel").html("ONE WAY"); 262 | $scope.retEmpty=true; 263 | $scope.$apply(); 264 | }else{ 265 | $scope.fact="Changing to ROUND TRIP"; 266 | $("#retDate").show(); 267 | $("#retSpan").show(); 268 | $("#retLabel").html("ROUND TRIP"); 269 | $scope.retEmpty=false; 270 | $scope.$apply(); 271 | } 272 | }); 273 | $("input.switchShowMe").bootstrapSwitch({ 274 | onText: 'on', 275 | offText: 'off', 276 | size: 'small', 277 | state: $rootScope.showCode 278 | }); 279 | 280 | $("input.switchShowMe").on('switchChange.bootstrapSwitch', function(event, state) { 281 | $rootScope.showCode = state; 282 | $rootScope.$apply(); 283 | }); 284 | }); 285 | 286 | 287 | 288 | 289 | 290 | travelApp.controller("UserController", function($rootScope, $scope, $http, $cookies) { 291 | 292 | $scope.rowCollectionFlight=[]; 293 | 294 | $scope.findBookedFlights = function() { 295 | $rootScope.fact="Searching for previously booked flights"; 296 | $rootScope.publishMessage("REST REQ=/api/user/flights"); 297 | $http.get("/api/user/flights", 298 | { 299 | params: { 300 | token: $cookies.get('token') 301 | } 302 | } 303 | ) 304 | .then(function(responseFlights){ 305 | if (responseFlights.data.length > 0) { 306 | $scope.fliEmpty = false; 307 | } 308 | for (var j = 0; j < responseFlights.data.length; j++) { 309 | $scope.rowCollectionFlight.push(responseFlights.data[j]); 310 | } 311 | }); 312 | }; 313 | 314 | }); 315 | -------------------------------------------------------------------------------- /public/js/bootstrap-switch.min.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * bootstrap-switch - v3.3.2 3 | * http://www.bootstrap-switch.org 4 | * ======================================================================== 5 | * Copyright 2012-2013 Mattia Larentis 6 | * 7 | * ======================================================================== 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * ======================================================================== 20 | */ 21 | 22 | (function(){var t=[].slice;!function(e,i){"use strict";var n;return n=function(){function t(t,i){null==i&&(i={}),this.$element=e(t),this.options=e.extend({},e.fn.bootstrapSwitch.defaults,{state:this.$element.is(":checked"),size:this.$element.data("size"),animate:this.$element.data("animate"),disabled:this.$element.is(":disabled"),readonly:this.$element.is("[readonly]"),indeterminate:this.$element.data("indeterminate"),inverse:this.$element.data("inverse"),radioAllOff:this.$element.data("radio-all-off"),onColor:this.$element.data("on-color"),offColor:this.$element.data("off-color"),onText:this.$element.data("on-text"),offText:this.$element.data("off-text"),labelText:this.$element.data("label-text"),handleWidth:this.$element.data("handle-width"),labelWidth:this.$element.data("label-width"),baseClass:this.$element.data("base-class"),wrapperClass:this.$element.data("wrapper-class")},i),this.$wrapper=e("
",{"class":function(t){return function(){var e;return e=[""+t.options.baseClass].concat(t._getClasses(t.options.wrapperClass)),e.push(t.options.state?""+t.options.baseClass+"-on":""+t.options.baseClass+"-off"),null!=t.options.size&&e.push(""+t.options.baseClass+"-"+t.options.size),t.options.disabled&&e.push(""+t.options.baseClass+"-disabled"),t.options.readonly&&e.push(""+t.options.baseClass+"-readonly"),t.options.indeterminate&&e.push(""+t.options.baseClass+"-indeterminate"),t.options.inverse&&e.push(""+t.options.baseClass+"-inverse"),t.$element.attr("id")&&e.push(""+t.options.baseClass+"-id-"+t.$element.attr("id")),e.join(" ")}}(this)()}),this.$container=e("
",{"class":""+this.options.baseClass+"-container"}),this.$on=e("",{html:this.options.onText,"class":""+this.options.baseClass+"-handle-on "+this.options.baseClass+"-"+this.options.onColor}),this.$off=e("",{html:this.options.offText,"class":""+this.options.baseClass+"-handle-off "+this.options.baseClass+"-"+this.options.offColor}),this.$label=e("",{html:this.options.labelText,"class":""+this.options.baseClass+"-label"}),this.$element.on("init.bootstrapSwitch",function(e){return function(){return e.options.onInit.apply(t,arguments)}}(this)),this.$element.on("switchChange.bootstrapSwitch",function(e){return function(){return e.options.onSwitchChange.apply(t,arguments)}}(this)),this.$container=this.$element.wrap(this.$container).parent(),this.$wrapper=this.$container.wrap(this.$wrapper).parent(),this.$element.before(this.options.inverse?this.$off:this.$on).before(this.$label).before(this.options.inverse?this.$on:this.$off),this.options.indeterminate&&this.$element.prop("indeterminate",!0),this._init(),this._elementHandlers(),this._handleHandlers(),this._labelHandlers(),this._formHandler(),this._externalLabelHandler(),this.$element.trigger("init.bootstrapSwitch")}return t.prototype._constructor=t,t.prototype.state=function(t,e){return"undefined"==typeof t?this.options.state:this.options.disabled||this.options.readonly?this.$element:this.options.state&&!this.options.radioAllOff&&this.$element.is(":radio")?this.$element:(this.options.indeterminate&&this.indeterminate(!1),t=!!t,this.$element.prop("checked",t).trigger("change.bootstrapSwitch",e),this.$element)},t.prototype.toggleState=function(t){return this.options.disabled||this.options.readonly?this.$element:this.options.indeterminate?(this.indeterminate(!1),this.state(!0)):this.$element.prop("checked",!this.options.state).trigger("change.bootstrapSwitch",t)},t.prototype.size=function(t){return"undefined"==typeof t?this.options.size:(null!=this.options.size&&this.$wrapper.removeClass(""+this.options.baseClass+"-"+this.options.size),t&&this.$wrapper.addClass(""+this.options.baseClass+"-"+t),this._width(),this._containerPosition(),this.options.size=t,this.$element)},t.prototype.animate=function(t){return"undefined"==typeof t?this.options.animate:(t=!!t,t===this.options.animate?this.$element:this.toggleAnimate())},t.prototype.toggleAnimate=function(){return this.options.animate=!this.options.animate,this.$wrapper.toggleClass(""+this.options.baseClass+"-animate"),this.$element},t.prototype.disabled=function(t){return"undefined"==typeof t?this.options.disabled:(t=!!t,t===this.options.disabled?this.$element:this.toggleDisabled())},t.prototype.toggleDisabled=function(){return this.options.disabled=!this.options.disabled,this.$element.prop("disabled",this.options.disabled),this.$wrapper.toggleClass(""+this.options.baseClass+"-disabled"),this.$element},t.prototype.readonly=function(t){return"undefined"==typeof t?this.options.readonly:(t=!!t,t===this.options.readonly?this.$element:this.toggleReadonly())},t.prototype.toggleReadonly=function(){return this.options.readonly=!this.options.readonly,this.$element.prop("readonly",this.options.readonly),this.$wrapper.toggleClass(""+this.options.baseClass+"-readonly"),this.$element},t.prototype.indeterminate=function(t){return"undefined"==typeof t?this.options.indeterminate:(t=!!t,t===this.options.indeterminate?this.$element:this.toggleIndeterminate())},t.prototype.toggleIndeterminate=function(){return this.options.indeterminate=!this.options.indeterminate,this.$element.prop("indeterminate",this.options.indeterminate),this.$wrapper.toggleClass(""+this.options.baseClass+"-indeterminate"),this._containerPosition(),this.$element},t.prototype.inverse=function(t){return"undefined"==typeof t?this.options.inverse:(t=!!t,t===this.options.inverse?this.$element:this.toggleInverse())},t.prototype.toggleInverse=function(){var t,e;return this.$wrapper.toggleClass(""+this.options.baseClass+"-inverse"),e=this.$on.clone(!0),t=this.$off.clone(!0),this.$on.replaceWith(t),this.$off.replaceWith(e),this.$on=t,this.$off=e,this.options.inverse=!this.options.inverse,this.$element},t.prototype.onColor=function(t){var e;return e=this.options.onColor,"undefined"==typeof t?e:(null!=e&&this.$on.removeClass(""+this.options.baseClass+"-"+e),this.$on.addClass(""+this.options.baseClass+"-"+t),this.options.onColor=t,this.$element)},t.prototype.offColor=function(t){var e;return e=this.options.offColor,"undefined"==typeof t?e:(null!=e&&this.$off.removeClass(""+this.options.baseClass+"-"+e),this.$off.addClass(""+this.options.baseClass+"-"+t),this.options.offColor=t,this.$element)},t.prototype.onText=function(t){return"undefined"==typeof t?this.options.onText:(this.$on.html(t),this._width(),this._containerPosition(),this.options.onText=t,this.$element)},t.prototype.offText=function(t){return"undefined"==typeof t?this.options.offText:(this.$off.html(t),this._width(),this._containerPosition(),this.options.offText=t,this.$element)},t.prototype.labelText=function(t){return"undefined"==typeof t?this.options.labelText:(this.$label.html(t),this._width(),this.options.labelText=t,this.$element)},t.prototype.handleWidth=function(t){return"undefined"==typeof t?this.options.handleWidth:(this.options.handleWidth=t,this._width(),this._containerPosition(),this.$element)},t.prototype.labelWidth=function(t){return"undefined"==typeof t?this.options.labelWidth:(this.options.labelWidth=t,this._width(),this._containerPosition(),this.$element)},t.prototype.baseClass=function(){return this.options.baseClass},t.prototype.wrapperClass=function(t){return"undefined"==typeof t?this.options.wrapperClass:(t||(t=e.fn.bootstrapSwitch.defaults.wrapperClass),this.$wrapper.removeClass(this._getClasses(this.options.wrapperClass).join(" ")),this.$wrapper.addClass(this._getClasses(t).join(" ")),this.options.wrapperClass=t,this.$element)},t.prototype.radioAllOff=function(t){return"undefined"==typeof t?this.options.radioAllOff:(t=!!t,t===this.options.radioAllOff?this.$element:(this.options.radioAllOff=t,this.$element))},t.prototype.onInit=function(t){return"undefined"==typeof t?this.options.onInit:(t||(t=e.fn.bootstrapSwitch.defaults.onInit),this.options.onInit=t,this.$element)},t.prototype.onSwitchChange=function(t){return"undefined"==typeof t?this.options.onSwitchChange:(t||(t=e.fn.bootstrapSwitch.defaults.onSwitchChange),this.options.onSwitchChange=t,this.$element)},t.prototype.destroy=function(){var t;return t=this.$element.closest("form"),t.length&&t.off("reset.bootstrapSwitch").removeData("bootstrap-switch"),this.$container.children().not(this.$element).remove(),this.$element.unwrap().unwrap().off(".bootstrapSwitch").removeData("bootstrap-switch"),this.$element},t.prototype._width=function(){var t,e;return t=this.$on.add(this.$off),t.add(this.$label).css("width",""),e="auto"===this.options.handleWidth?Math.max(this.$on.width(),this.$off.width()):this.options.handleWidth,t.width(e),this.$label.width(function(t){return function(i,n){return"auto"!==t.options.labelWidth?t.options.labelWidth:e>n?e:n}}(this)),this._handleWidth=this.$on.outerWidth(),this._labelWidth=this.$label.outerWidth(),this.$container.width(2*this._handleWidth+this._labelWidth),this.$wrapper.width(this._handleWidth+this._labelWidth)},t.prototype._containerPosition=function(t,e){return null==t&&(t=this.options.state),this.$container.css("margin-left",function(e){return function(){var i;return i=[0,"-"+e._handleWidth+"px"],e.options.indeterminate?"-"+e._handleWidth/2+"px":t?e.options.inverse?i[1]:i[0]:e.options.inverse?i[0]:i[1]}}(this)),e?setTimeout(function(){return e()},50):void 0},t.prototype._init=function(){var t,e;return t=function(t){return function(){return t._width(),t._containerPosition(null,function(){return t.options.animate?t.$wrapper.addClass(""+t.options.baseClass+"-animate"):void 0})}}(this),this.$wrapper.is(":visible")?t():e=i.setInterval(function(n){return function(){return n.$wrapper.is(":visible")?(t(),i.clearInterval(e)):void 0}}(this),50)},t.prototype._elementHandlers=function(){return this.$element.on({"change.bootstrapSwitch":function(t){return function(i,n){var o;return i.preventDefault(),i.stopImmediatePropagation(),o=t.$element.is(":checked"),t._containerPosition(o),o!==t.options.state?(t.options.state=o,t.$wrapper.toggleClass(""+t.options.baseClass+"-off").toggleClass(""+t.options.baseClass+"-on"),n?void 0:(t.$element.is(":radio")&&e("[name='"+t.$element.attr("name")+"']").not(t.$element).prop("checked",!1).trigger("change.bootstrapSwitch",!0),t.$element.trigger("switchChange.bootstrapSwitch",[o]))):void 0}}(this),"focus.bootstrapSwitch":function(t){return function(e){return e.preventDefault(),t.$wrapper.addClass(""+t.options.baseClass+"-focused")}}(this),"blur.bootstrapSwitch":function(t){return function(e){return e.preventDefault(),t.$wrapper.removeClass(""+t.options.baseClass+"-focused")}}(this),"keydown.bootstrapSwitch":function(t){return function(e){if(e.which&&!t.options.disabled&&!t.options.readonly)switch(e.which){case 37:return e.preventDefault(),e.stopImmediatePropagation(),t.state(!1);case 39:return e.preventDefault(),e.stopImmediatePropagation(),t.state(!0)}}}(this)})},t.prototype._handleHandlers=function(){return this.$on.on("click.bootstrapSwitch",function(t){return function(e){return e.preventDefault(),e.stopPropagation(),t.state(!1),t.$element.trigger("focus.bootstrapSwitch")}}(this)),this.$off.on("click.bootstrapSwitch",function(t){return function(e){return e.preventDefault(),e.stopPropagation(),t.state(!0),t.$element.trigger("focus.bootstrapSwitch")}}(this))},t.prototype._labelHandlers=function(){return this.$label.on({"mousedown.bootstrapSwitch touchstart.bootstrapSwitch":function(t){return function(e){return t._dragStart||t.options.disabled||t.options.readonly?void 0:(e.preventDefault(),e.stopPropagation(),t._dragStart=(e.pageX||e.originalEvent.touches[0].pageX)-parseInt(t.$container.css("margin-left"),10),t.options.animate&&t.$wrapper.removeClass(""+t.options.baseClass+"-animate"),t.$element.trigger("focus.bootstrapSwitch"))}}(this),"mousemove.bootstrapSwitch touchmove.bootstrapSwitch":function(t){return function(e){var i;if(null!=t._dragStart&&(e.preventDefault(),i=(e.pageX||e.originalEvent.touches[0].pageX)-t._dragStart,!(i<-t._handleWidth||i>0)))return t._dragEnd=i,t.$container.css("margin-left",""+t._dragEnd+"px")}}(this),"mouseup.bootstrapSwitch touchend.bootstrapSwitch":function(t){return function(e){var i;if(t._dragStart)return e.preventDefault(),t.options.animate&&t.$wrapper.addClass(""+t.options.baseClass+"-animate"),t._dragEnd?(i=t._dragEnd>-(t._handleWidth/2),t._dragEnd=!1,t.state(t.options.inverse?!i:i)):t.state(!t.options.state),t._dragStart=!1}}(this),"mouseleave.bootstrapSwitch":function(t){return function(){return t.$label.trigger("mouseup.bootstrapSwitch")}}(this)})},t.prototype._externalLabelHandler=function(){var t;return t=this.$element.closest("label"),t.on("click",function(e){return function(i){return i.preventDefault(),i.stopImmediatePropagation(),i.target===t[0]?e.toggleState():void 0}}(this))},t.prototype._formHandler=function(){var t;return t=this.$element.closest("form"),t.data("bootstrap-switch")?void 0:t.on("reset.bootstrapSwitch",function(){return i.setTimeout(function(){return t.find("input").filter(function(){return e(this).data("bootstrap-switch")}).each(function(){return e(this).bootstrapSwitch("state",this.checked)})},1)}).data("bootstrap-switch",!0)},t.prototype._getClasses=function(t){var i,n,o,s;if(!e.isArray(t))return[""+this.options.baseClass+"-"+t];for(n=[],o=0,s=t.length;s>o;o++)i=t[o],n.push(""+this.options.baseClass+"-"+i);return n},t}(),e.fn.bootstrapSwitch=function(){var i,o,s;return o=arguments[0],i=2<=arguments.length?t.call(arguments,1):[],s=this,this.each(function(){var t,a;return t=e(this),a=t.data("bootstrap-switch"),a||t.data("bootstrap-switch",a=new n(this,o)),"string"==typeof o?s=a[o].apply(a,i):void 0}),s},e.fn.bootstrapSwitch.Constructor=n,e.fn.bootstrapSwitch.defaults={state:!0,size:null,animate:!0,disabled:!1,readonly:!1,indeterminate:!1,inverse:!1,radioAllOff:!1,onColor:"primary",offColor:"default",onText:"ON",offText:"OFF",labelText:" ",handleWidth:"auto",labelWidth:"auto",baseClass:"bootstrap-switch",wrapperClass:"wrapper",onInit:function(){},onSwitchChange:function(){}}}(window.jQuery,window)}).call(this); -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.bg.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bulgarian translation for bootstrap-datepicker 3 | * Apostol Apostolov 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['bg'] = { 7 | days: ["Неделя", "Понеделник", "Вторник", "Сряда", "Четвъртък", "Петък", "Събота", "Неделя"], 8 | daysShort: ["Нед", "Пон", "Вто", "Сря", "Чет", "Пет", "Съб", "Нед"], 9 | daysMin: ["Н", "П", "В", "С", "Ч", "П", "С", "Н"], 10 | months: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"], 11 | monthsShort: ["Ян", "Фев", "Мар", "Апр", "Май", "Юни", "Юли", "Авг", "Сеп", "Окт", "Ное", "Дек"], 12 | today: "днес" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.ca.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Catalan translation for bootstrap-datepicker 3 | * J. Garcia 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['ca'] = { 7 | days: ["Diumenge", "Dilluns", "Dimarts", "Dimecres", "Dijous", "Divendres", "Dissabte", "Diumenge"], 8 | daysShort: ["Diu", "Dil", "Dmt", "Dmc", "Dij", "Div", "Dis", "Diu"], 9 | daysMin: ["dg", "dl", "dt", "dc", "dj", "dv", "ds", "dg"], 10 | months: ["Gener", "Febrer", "Març", "Abril", "Maig", "Juny", "Juliol", "Agost", "Setembre", "Octubre", "Novembre", "Desembre"], 11 | monthsShort: ["Gen", "Feb", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Oct", "Nov", "Des"], 12 | today: "Avui" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.cs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Czech translation for bootstrap-datepicker 3 | * Matěj Koubík 4 | * Fixes by Michal Remiš 5 | */ 6 | ;(function($){ 7 | $.fn.datepicker.dates['cs'] = { 8 | days: ["Neděle", "Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota", "Neděle"], 9 | daysShort: ["Ned", "Pon", "Úte", "Stř", "Čtv", "Pát", "Sob", "Ned"], 10 | daysMin: ["Ne", "Po", "Út", "St", "Čt", "Pá", "So", "Ne"], 11 | months: ["Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec"], 12 | monthsShort: ["Led", "Úno", "Bře", "Dub", "Kvě", "Čer", "Čnc", "Srp", "Zář", "Říj", "Lis", "Pro"], 13 | today: "Dnes" 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.da.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Danish translation for bootstrap-datepicker 3 | * Christian Pedersen 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['da'] = { 7 | days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"], 8 | daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"], 9 | daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø", "Sø"], 10 | months: ["Januar", "Februar", "Marts", "April", "Maj", "Juni", "Juli", "August", "September", "Oktober", "November", "December"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], 12 | today: "I Dag" 13 | }; 14 | }(jQuery)); -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.de.js: -------------------------------------------------------------------------------- 1 | /** 2 | * German translation for bootstrap-datepicker 3 | * Sam Zurcher 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['de'] = { 7 | days: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"], 8 | daysShort: ["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam", "Son"], 9 | daysMin: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"], 10 | months: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"], 11 | monthsShort: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"], 12 | today: "Heute", 13 | weekStart: 1 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.el.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Greek translation for bootstrap-datepicker 3 | */ 4 | ;(function($){ 5 | $.fn.datepicker.dates['el'] = { 6 | days: ["Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο", "Κυριακή"], 7 | daysShort: ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ", "Κυρ"], 8 | daysMin: ["Κυ", "Δε", "Τρ", "Τε", "Πε", "Πα", "Σα", "Κυ"], 9 | months: ["Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος"], 10 | monthsShort: ["Ιαν", "Φεβ", "Μαρ", "Απρ", "Μάι", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ"], 11 | today: "Σήμερα" 12 | }; 13 | }(jQuery)); -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.es.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Spanish translation for bootstrap-datepicker 3 | * Bruno Bonamin 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['es'] = { 7 | days: ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo"], 8 | daysShort: ["Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb", "Dom"], 9 | daysMin: ["Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa", "Do"], 10 | months: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"], 11 | monthsShort: ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"], 12 | today: "Hoy" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.fi.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Finnish translation for bootstrap-datepicker 3 | * Jaakko Salonen 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['fi'] = { 7 | days: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai", "sunnuntai"], 8 | daysShort: ["sun", "maa", "tii", "kes", "tor", "per", "lau", "sun"], 9 | daysMin: ["su", "ma", "ti", "ke", "to", "pe", "la", "su"], 10 | months: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"], 11 | monthsShort: ["tam", "hel", "maa", "huh", "tou", "kes", "hei", "elo", "syy", "lok", "mar", "jou"], 12 | today: "tänään" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.fr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * French translation for bootstrap-datepicker 3 | * Nico Mollet 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['fr'] = { 7 | days: ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"], 8 | daysShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"], 9 | daysMin: ["D", "L", "Ma", "Me", "J", "V", "S", "D"], 10 | months: ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"], 11 | monthsShort: ["Jan", "Fev", "Mar", "Avr", "Mai", "Jui", "Jul", "Aou", "Sep", "Oct", "Nov", "Dec"], 12 | today: "Aujourd'hui", 13 | weekStart: 1 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.he.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hebrew translation for bootstrap-datepicker 3 | * Sagie Maoz 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['he'] = { 7 | days: ["ראשון", "שני", "שלישי", "רביעי", "חמישי", "שישי", "שבת", "ראשון"], 8 | daysShort: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], 9 | daysMin: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], 10 | months: ["ינואר", "פברואר", "מרץ", "אפריל", "מאי", "יוני", "יולי", "אוגוסט", "ספטמבר", "אוקטובר", "נובמבר", "דצמבר"], 11 | monthsShort: ["ינו", "פבר", "מרץ", "אפר", "מאי", "יונ", "יול", "אוג", "ספט", "אוק", "נוב", "דצמ"], 12 | today: "היום", 13 | rtl: true 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.hr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Croatian localisation 3 | */ 4 | ;(function($){ 5 | $.fn.datepicker.dates['hr'] = { 6 | days: ["Nedjelja", "Ponedjelja", "Utorak", "Srijeda", "Četrtak", "Petak", "Subota", "Nedjelja"], 7 | daysShort: ["Ned", "Pon", "Uto", "Srr", "Čet", "Pet", "Sub", "Ned"], 8 | daysMin: ["Ne", "Po", "Ut", "Sr", "Če", "Pe", "Su", "Ne"], 9 | months: ["Siječanj", "Veljača", "Ožujak", "Travanj", "Svibanj", "Lipanj", "Srpanj", "Kolovoz", "Rujan", "Listopad", "Studeni", "Prosinac"], 10 | monthsShort: ["Sije", "Velj", "Ožu", "Tra", "Svi", "Lip", "Jul", "Kol", "Ruj", "Lis", "Stu", "Pro"], 11 | today: "Danas" 12 | }; 13 | }(jQuery)); 14 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.id.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bahasa translation for bootstrap-datepicker 3 | * Azwar Akbar 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['id'] = { 7 | days: ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu", "Minggu"], 8 | daysShort: ["Mgu", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab", "Mgu"], 9 | daysMin: ["Mg", "Sn", "Sl", "Ra", "Ka", "Ju", "Sa", "Mg"], 10 | months: ["Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ags", "Sep", "Okt", "Nov", "Des"] 12 | }; 13 | }(jQuery)); 14 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.is.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Icelandic translation for bootstrap-datepicker 3 | * Hinrik Örn Sigurðsson 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['is'] = { 7 | days: ["Sunnudagur", "Mánudagur", "Þriðjudagur", "Miðvikudagur", "Fimmtudagur", "Föstudagur", "Laugardagur", "Sunnudagur"], 8 | daysShort: ["Sun", "Mán", "Þri", "Mið", "Fim", "Fös", "Lau", "Sun"], 9 | daysMin: ["Su", "Má", "Þr", "Mi", "Fi", "Fö", "La", "Su"], 10 | months: ["Janúar", "Febrúar", "Mars", "Apríl", "Maí", "Júní", "Júlí", "Ágúst", "September", "Október", "Nóvember", "Desember"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maí", "Jún", "Júl", "Ágú", "Sep", "Okt", "Nóv", "Des"], 12 | today: "Í Dag" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.it.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Italian translation for bootstrap-datepicker 3 | * Enrico Rubboli 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['it'] = { 7 | days: ["Domenica", "Lunedi", "Martedi", "Mercoledi", "Giovedi", "Venerdi", "Sabato", "Domenica"], 8 | daysShort: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab", "Dom"], 9 | daysMin: ["Do", "Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"], 10 | months: ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"], 11 | monthsShort: ["Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"], 12 | today: "Oggi" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.ja.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Japanese translation for bootstrap-datepicker 3 | * Norio Suzuki 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['ja'] = { 7 | days: ["日曜", "月曜", "火曜", "水曜", "木曜", "金曜", "土曜", "日曜"], 8 | daysShort: ["日", "月", "火", "水", "木", "金", "土", "日"], 9 | daysMin: ["日", "月", "火", "水", "木", "金", "土", "日"], 10 | months: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], 11 | monthsShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"] 12 | }; 13 | }(jQuery)); 14 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.kr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Korean translation for bootstrap-datepicker 3 | * Gu Youn 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['kr'] = { 7 | days: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일", "일요일"], 8 | daysShort: ["일", "월", "화", "수", "목", "금", "토", "일"], 9 | daysMin: ["일", "월", "화", "수", "목", "금", "토", "일"], 10 | months: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"], 11 | monthsShort: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"] 12 | }; 13 | }(jQuery)); 14 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.lt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Lithuanian translation for bootstrap-datepicker 3 | * Šarūnas Gliebus 4 | */ 5 | 6 | ;(function($){ 7 | $.fn.datepicker.dates['lt'] = { 8 | days: ["Sekmadienis", "Pirmadienis", "Antradienis", "Trečiadienis", "Ketvirtadienis", "Penktadienis", "Šeštadienis", "Sekmadienis"], 9 | daysShort: ["S", "Pr", "A", "T", "K", "Pn", "Š", "S"], 10 | daysMin: ["Sk", "Pr", "An", "Tr", "Ke", "Pn", "Št", "Sk"], 11 | months: ["Sausis", "Vasaris", "Kovas", "Balandis", "Gegužė", "Birželis", "Liepa", "Rugpjūtis", "Rugsėjis", "Spalis", "Lapkritis", "Gruodis"], 12 | monthsShort: ["Sau", "Vas", "Kov", "Bal", "Geg", "Bir", "Lie", "Rugp", "Rugs", "Spa", "Lap", "Gru"], 13 | today: "Šiandien", 14 | weekStart: 1 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.lv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Latvian translation for bootstrap-datepicker 3 | * Artis Avotins 4 | */ 5 | 6 | ;(function($){ 7 | $.fn.datepicker.dates['lv'] = { 8 | days: ["Svētdiena", "Pirmdiena", "Otrdiena", "Trešdiena", "Ceturtdiena", "Piektdiena", "Sestdiena", "Svētdiena"], 9 | daysShort: ["Sv", "P", "O", "T", "C", "Pk", "S", "Sv"], 10 | daysMin: ["Sv", "Pr", "Ot", "Tr", "Ce", "Pk", "St", "Sv"], 11 | months: ["Janvāris", "Februāris", "Marts", "Aprīlis", "Maijs", "Jūnijs", "Jūlijs", "Augusts", "Septembris", "Oktobris", "Novembris", "Decembris"], 12 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jūn", "Jūl", "Aug", "Sep", "Okt", "Nov", "Dec."], 13 | today: "Šodien", 14 | weekStart: 1 15 | }; 16 | }(jQuery)); -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.ms.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Malay translation for bootstrap-datepicker 3 | * Ateman Faiz 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['ms'] = { 7 | days: ["Ahad", "Isnin", "Selasa", "Rabu", "Khamis", "Jumaat", "Sabtu", "Ahad"], 8 | daysShort: ["Aha", "Isn", "Sel", "Rab", "Kha", "Jum", "Sab", "Aha"], 9 | daysMin: ["Ah", "Is", "Se", "Ra", "Kh", "Ju", "Sa", "Ah"], 10 | months: ["Januari", "Februari", "Mac", "April", "Mei", "Jun", "Julai", "Ogos", "September", "Oktober", "November", "Disember"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ogo", "Sep", "Okt", "Nov", "Dis"], 12 | today: "Hari Ini" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.nb.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Norwegian (bokmål) translation for bootstrap-datepicker 3 | * Fredrik Sundmyhr 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['nb'] = { 7 | days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"], 8 | daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"], 9 | daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø", "Sø"], 10 | months: ["Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Des"], 12 | today: "I Dag" 13 | }; 14 | }(jQuery)); -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.nl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dutch translation for bootstrap-datepicker 3 | * Reinier Goltstein 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['nl'] = { 7 | days: ["Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"], 8 | daysShort: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], 9 | daysMin: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], 10 | months: ["Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"], 11 | monthsShort: ["Jan", "Feb", "Mrt", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], 12 | today: "Vandaag" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.pl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Polish translation for bootstrap-datepicker 3 | * Robert 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['pl'] = { 7 | days: ["Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota", "Niedziela"], 8 | daysShort: ["Nie", "Pn", "Wt", "Śr", "Czw", "Pt", "So", "Nie"], 9 | daysMin: ["N", "Pn", "Wt", "Śr", "Cz", "Pt", "So", "N"], 10 | months: ["Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"], 11 | monthsShort: ["Sty", "Lu", "Mar", "Kw", "Maj", "Cze", "Lip", "Sie", "Wrz", "Pa", "Lis", "Gru"], 12 | today: "Dzisiaj", 13 | weekStart: 1 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.pt-BR.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Brazilian translation for bootstrap-datepicker 3 | * Cauan Cabral 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['pt-BR'] = { 7 | days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"], 8 | daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"], 9 | daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa", "Do"], 10 | months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], 11 | monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], 12 | today: "Hoje" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.pt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Portuguese translation for bootstrap-datepicker 3 | * Original code: Cauan Cabral 4 | * Tiago Melo 5 | */ 6 | ;(function($){ 7 | $.fn.datepicker.dates['pt'] = { 8 | days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"], 9 | daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"], 10 | daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa", "Do"], 11 | months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], 12 | monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"] 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.ro.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Romanian translation for bootstrap-datepicker 3 | * Cristian Vasile 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['ro'] = { 7 | days: ["Duminică", "Luni", "Marţi", "Miercuri", "Joi", "Vineri", "Sâmbătă", "Duminică"], 8 | daysShort: ["Dum", "Lun", "Mar", "Mie", "Joi", "Vin", "Sâm", "Dum"], 9 | daysMin: ["Du", "Lu", "Ma", "Mi", "Jo", "Vi", "Sâ", "Du"], 10 | months: ["Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie", "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"], 11 | monthsShort: ["Ian", "Feb", "Mar", "Apr", "Mai", "Iun", "Iul", "Aug", "Sep", "Oct", "Nov", "Dec"], 12 | today: "Astăzi", 13 | weekStart: 1 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.rs-latin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Serbian latin translation for bootstrap-datepicker 3 | * Bojan Milosavlević 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['rs'] = { 7 | days: ["Nedelja","Ponedeljak", "Utorak", "Sreda", "Četvrtak", "Petak", "Subota", "Nedelja"], 8 | daysShort: ["Ned", "Pon", "Uto", "Sre", "Čet", "Pet", "Sub", "Ned"], 9 | daysMin: ["N", "Po", "U", "Sr", "Č", "Pe", "Su", "N"], 10 | months: ["Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", "Avgust", "Septembar", "Oktobar", "Novembar", "Decembar"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], 12 | today: "Danas" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.rs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Serbian cyrillic translation for bootstrap-datepicker 3 | * Bojan Milosavlević 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['rs'] = { 7 | days: ["Недеља","Понедељак", "Уторак", "Среда", "Четвртак", "Петак", "Субота", "Недеља"], 8 | daysShort: ["Нед", "Пон", "Уто", "Сре", "Чет", "Пет", "Суб", "Нед"], 9 | daysMin: ["Н", "По", "У", "Ср", "Ч", "Пе", "Су", "Н"], 10 | months: ["Јануар", "Фебруар", "Март", "Април", "Мај", "Јун", "Јул", "Август", "Септембар", "Октобар", "Новембар", "Децембар"], 11 | monthsShort: ["Јан", "Феб", "Мар", "Апр", "Мај", "Јун", "Јул", "Авг", "Сеп", "Окт", "Нов", "Дец"], 12 | today: "Данас" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.ru.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Russian translation for bootstrap-datepicker 3 | * Victor Taranenko 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['ru'] = { 7 | days: ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"], 8 | daysShort: ["Вск", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб", "Вск"], 9 | daysMin: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"], 10 | months: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"], 11 | monthsShort: ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"], 12 | today: "Сегодня" 13 | }; 14 | }(jQuery)); -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.sk.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Slovak translation for bootstrap-datepicker 3 | * Marek Lichtner 4 | * Fixes by Michal Remiš 5 | */ 6 | ;(function($){ 7 | $.fn.datepicker.dates["sk"] = { 8 | days: ["Nedeľa", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota", "Nedeľa"], 9 | daysShort: ["Ned", "Pon", "Uto", "Str", "Štv", "Pia", "Sob", "Ned"], 10 | daysMin: ["Ne", "Po", "Ut", "St", "Št", "Pia", "So", "Ne"], 11 | months: ["Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Október", "November", "December"], 12 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Máj", "Jún", "Júl", "Aug", "Sep", "Okt", "Nov", "Dec"], 13 | today: "Dnes" 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.sl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Slovene translation for bootstrap-datepicker 3 | * Gregor Rudolf 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['sl'] = { 7 | days: ["Nedelja", "Ponedeljek", "Torek", "Sreda", "Četrtek", "Petek", "Sobota", "Nedelja"], 8 | daysShort: ["Ned", "Pon", "Tor", "Sre", "Čet", "Pet", "Sob", "Ned"], 9 | daysMin: ["Ne", "Po", "To", "Sr", "Če", "Pe", "So", "Ne"], 10 | months: ["Januar", "Februar", "Marec", "April", "Maj", "Junij", "Julij", "Avgust", "September", "Oktober", "November", "December"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], 12 | today: "Danes" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.sv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Swedish translation for bootstrap-datepicker 3 | * Patrik Ragnarsson 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['sv'] = { 7 | days: ["Söndag", "Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag", "Söndag"], 8 | daysShort: ["Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör", "Sön"], 9 | daysMin: ["Sö", "Må", "Ti", "On", "To", "Fr", "Lö", "Sö"], 10 | months: ["Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], 12 | today: "I Dag" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.sw.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Swahili translation for bootstrap-datepicker 3 | * Edwin Mugendi 4 | * Source: http://scriptsource.org/cms/scripts/page.php?item_id=entry_detail&uid=xnfaqyzcku 5 | */ 6 | ;(function($){ 7 | $.fn.datepicker.dates['sw'] = { 8 | days: ["Jumapili", "Jumatatu", "Jumanne", "Jumatano", "Alhamisi", "Ijumaa", "Jumamosi", "Jumapili"], 9 | daysShort: ["J2", "J3", "J4", "J5", "Alh", "Ij", "J1", "J2"], 10 | daysMin: ["2", "3", "4", "5", "A", "I", "1", "2"], 11 | months: ["Januari", "Februari", "Machi", "Aprili", "Mei", "Juni", "Julai", "Agosti", "Septemba", "Oktoba", "Novemba", "Desemba"], 12 | monthsShort: ["Jan", "Feb", "Mac", "Apr", "Mei", "Jun", "Jul", "Ago", "Sep", "Okt", "Nov", "Des"], 13 | today: "Leo" 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.th.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Thai translation for bootstrap-datepicker 3 | * Suchau Jiraprapot 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['th'] = { 7 | days: ["อาทิตย์", "จันทร์", "อังคาร", "พุธ", "พฤหัส", "ศุกร์", "เสาร์", "อาทิตย์"], 8 | daysShort: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], 9 | daysMin: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], 10 | months: ["มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม"], 11 | monthsShort: ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."], 12 | today: "วันนี้" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.tr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Turkish translation for bootstrap-datepicker 3 | * Serkan Algur 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['tr'] = { 7 | days: ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi", "Pazar"], 8 | daysShort: ["Pz", "Pzt", "Sal", "Çrş", "Prş", "Cu", "Cts", "Pz"], 9 | daysMin: ["Pz", "Pzt", "Sa", "Çr", "Pr", "Cu", "Ct", "Pz"], 10 | months: ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"], 11 | monthsShort: ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara"], 12 | today: "Bugün" 13 | }; 14 | }(jQuery)); 15 | 16 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.uk.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ukrainian translation for bootstrap-datepicker 3 | * Andrey Vityuk 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['uk'] = { 7 | days: ["Неділя", "Понеділок", "Вівторок", "Середа", "Четвер", "П'ятниця", "Субота", "Неділя"], 8 | daysShort: ["Нед", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб", "Нед"], 9 | daysMin: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Нд"], 10 | months: ["Січень", "Лютий", "Березень", "Квітень", "Травень", "Червень", "Липень", "Серпень", "Вересень", "Жовтень", "Листопад", "Грудень"], 11 | monthsShort: ["Січ", "Лют", "Бер", "Кві", "Тра", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Гру"], 12 | today: "Сьогодні" 13 | }; 14 | }(jQuery)); -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.zh-CN.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Simplified Chinese translation for bootstrap-datepicker 3 | * Yuan Cheung 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['zh-CN'] = { 7 | days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"], 8 | daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"], 9 | daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"], 10 | months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], 11 | monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], 12 | today: "今日" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /public/js/locales/bootstrap-datepicker.zh-TW.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Traditional Chinese translation for bootstrap-datepicker 3 | * Rung-Sheng Jang 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['zh-TW'] = { 7 | days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"], 8 | daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"], 9 | daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"], 10 | months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], 11 | monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"] 12 | }; 13 | }(jQuery)); 14 | -------------------------------------------------------------------------------- /public/js/ngCart.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | angular.module('ngCart', ['ngCart.directives']) 5 | 6 | .config([function () { 7 | 8 | }]) 9 | 10 | .provider('$ngCart', function () { 11 | this.$get = function () { 12 | }; 13 | }) 14 | 15 | .run(['$rootScope', 'ngCart','ngCartItem', 'store', function ($rootScope, ngCart, ngCartItem, store) { 16 | 17 | $rootScope.$on('ngCart:change', function(){ 18 | ngCart.$save(); 19 | }); 20 | 21 | if (angular.isObject(store.get('cart'))) { 22 | ngCart.$restore(store.get('cart')); 23 | 24 | } else { 25 | ngCart.init(); 26 | } 27 | 28 | }]) 29 | 30 | .service('ngCart', ['$rootScope', 'ngCartItem', 'store', function ($rootScope, ngCartItem, store) { 31 | 32 | this.init = function(){ 33 | this.$cart = { 34 | shipping : null, 35 | taxRate : null, 36 | tax : null, 37 | complete : false, 38 | items : [] 39 | }; 40 | }; 41 | 42 | this.addItem = function (id, name, price, quantity, data) { 43 | 44 | var inCart = this.getItemById(id); 45 | 46 | if (typeof inCart === 'object'){ 47 | //Update quantity of an item if it's already in the cart 48 | inCart.setQuantity(quantity, false); 49 | } else { 50 | var newItem = new ngCartItem(id, name, price, quantity, data); 51 | this.$cart.items.push(newItem); 52 | $rootScope.$broadcast('ngCart:itemAdded', newItem); 53 | } 54 | 55 | $rootScope.$broadcast('ngCart:change', {}); 56 | }; 57 | 58 | this.getItemById = function (itemId) { 59 | var items = this.getCart().items; 60 | var build = false; 61 | 62 | angular.forEach(items, function (item) { 63 | if (item.getId() === itemId) { 64 | build = item; 65 | } 66 | }); 67 | return build; 68 | }; 69 | 70 | this.setShipping = function(shipping){ 71 | this.$cart.shipping = shipping; 72 | return this.getShipping(); 73 | }; 74 | 75 | this.getShipping = function(){ 76 | if (this.getCart().items.length == 0) return 0; 77 | return this.getCart().shipping; 78 | }; 79 | 80 | this.setTaxRate = function(taxRate){ 81 | this.$cart.taxRate = +parseFloat(taxRate).toFixed(2); 82 | return this.getTaxRate(); 83 | }; 84 | 85 | this.getTaxRate = function(){ 86 | return this.$cart.taxRate 87 | }; 88 | 89 | this.getTax = function(){ 90 | return +parseFloat(((this.getSubTotal()/100) * this.getCart().taxRate )).toFixed(2); 91 | }; 92 | 93 | this.setCart = function (cart) { 94 | this.$cart = cart; 95 | return this.getCart(); 96 | }; 97 | 98 | this.getCart = function(){ 99 | return this.$cart; 100 | }; 101 | 102 | this.getItems = function(){ 103 | return this.getCart().items; 104 | }; 105 | 106 | this.getTotalItems = function () { 107 | var count = 0; 108 | var items = this.getItems(); 109 | angular.forEach(items, function (item) { 110 | count += item.getQuantity(); 111 | }); 112 | return count; 113 | }; 114 | 115 | this.getTotalUniqueItems = function () { 116 | return this.getCart().items.length; 117 | }; 118 | 119 | this.getSubTotal = function(){ 120 | var total = 0; 121 | angular.forEach(this.getCart().items, function (item) { 122 | total += item.getTotal(); 123 | }); 124 | return +parseFloat(total).toFixed(2); 125 | }; 126 | 127 | this.totalCost = function () { 128 | return +parseFloat(this.getSubTotal() + this.getShipping() + this.getTax()).toFixed(2); 129 | }; 130 | 131 | this.removeItem = function (index) { 132 | this.$cart.items.splice(index, 1); 133 | $rootScope.$broadcast('ngCart:itemRemoved', {}); 134 | $rootScope.$broadcast('ngCart:change', {}); 135 | 136 | }; 137 | 138 | this.removeItemById = function (id) { 139 | var cart = this.getCart(); 140 | angular.forEach(cart.items, function (item, index) { 141 | if (item.getId() === id) { 142 | cart.items.splice(index, 1); 143 | } 144 | }); 145 | this.setCart(cart); 146 | $rootScope.$broadcast('ngCart:itemRemoved', {}); 147 | $rootScope.$broadcast('ngCart:change', {}); 148 | }; 149 | 150 | this.empty = function () { 151 | 152 | $rootScope.$broadcast('ngCart:change', {}); 153 | this.$cart.items = []; 154 | localStorage.removeItem('cart'); 155 | }; 156 | 157 | 158 | this.toObject = function() { 159 | 160 | if (this.getItems().length === 0) return false; 161 | 162 | var items = []; 163 | angular.forEach(this.getItems(), function(item){ 164 | items.push (item.toObject()); 165 | }); 166 | 167 | return { 168 | shipping: this.getShipping(), 169 | tax: this.getTax(), 170 | taxRate: this.getTaxRate(), 171 | subTotal: this.getSubTotal(), 172 | totalCost: this.totalCost(), 173 | items:items 174 | } 175 | }; 176 | 177 | 178 | this.$restore = function(storedCart){ 179 | var _self = this; 180 | _self.init(); 181 | _self.$cart.shipping = storedCart.shipping; 182 | _self.$cart.tax = storedCart.tax; 183 | 184 | angular.forEach(storedCart.items, function (item) { 185 | _self.$cart.items.push(new ngCartItem(item._id, item._name, item._price, item._quantity, item._data)); 186 | }); 187 | this.$save(); 188 | }; 189 | 190 | this.$save = function () { 191 | return store.set('cart', JSON.stringify(this.getCart())); 192 | } 193 | 194 | }]) 195 | 196 | .factory('ngCartItem', ['$rootScope', '$log', function ($rootScope, $log) { 197 | 198 | var item = function (id, name, price, quantity, data) { 199 | this.setId(id); 200 | this.setName(name); 201 | this.setPrice(price); 202 | this.setQuantity(quantity); 203 | this.setData(data); 204 | }; 205 | 206 | 207 | item.prototype.setId = function(id){ 208 | if (id) this._id = id; 209 | else { 210 | $log.error('An ID must be provided'); 211 | } 212 | }; 213 | 214 | item.prototype.getId = function(){ 215 | return this._id; 216 | }; 217 | 218 | 219 | item.prototype.setName = function(name){ 220 | if (name) this._name = name; 221 | else { 222 | $log.error('A name must be provided'); 223 | } 224 | }; 225 | item.prototype.getName = function(){ 226 | return this._name; 227 | }; 228 | 229 | item.prototype.setPrice = function(price){ 230 | var priceFloat = parseFloat(price); 231 | if (priceFloat) { 232 | if (priceFloat <= 0) { 233 | $log.error('A price must be over 0'); 234 | } else { 235 | this._price = (priceFloat); 236 | } 237 | } else { 238 | $log.error('A price must be provided'); 239 | } 240 | }; 241 | item.prototype.getPrice = function(){ 242 | return this._price; 243 | }; 244 | 245 | 246 | item.prototype.setQuantity = function(quantity, relative){ 247 | 248 | 249 | var quantityInt = parseInt(quantity); 250 | if (quantityInt % 1 === 0){ 251 | if (relative === true){ 252 | this._quantity += quantityInt; 253 | } else { 254 | this._quantity = quantityInt; 255 | } 256 | if (this._quantity < 1) this._quantity = 1; 257 | 258 | } else { 259 | this._quantity = 1; 260 | $log.info('Quantity must be an integer and was defaulted to 1'); 261 | } 262 | $rootScope.$broadcast('ngCart:change', {}); 263 | 264 | }; 265 | 266 | item.prototype.getQuantity = function(){ 267 | return this._quantity; 268 | }; 269 | 270 | item.prototype.setData = function(data){ 271 | if (data) this._data = data; 272 | }; 273 | 274 | item.prototype.getData = function(){ 275 | if (this._data) return this._data; 276 | else $log.info('This item has no data'); 277 | }; 278 | 279 | 280 | item.prototype.getTotal = function(){ 281 | return +parseFloat(this.getQuantity() * this.getPrice()).toFixed(2); 282 | }; 283 | 284 | item.prototype.toObject = function() { 285 | return { 286 | id: this.getId(), 287 | name: this.getName(), 288 | price: this.getPrice(), 289 | quantity: this.getQuantity(), 290 | data: this.getData(), 291 | total: this.getTotal() 292 | } 293 | }; 294 | 295 | return item; 296 | 297 | }]) 298 | 299 | .service('store', ['$window', function ($window) { 300 | 301 | return { 302 | 303 | get: function (key) { 304 | if ($window.localStorage [key]) { 305 | var cart = angular.fromJson($window.localStorage [key]); 306 | return JSON.parse(cart); 307 | } 308 | return false; 309 | 310 | }, 311 | 312 | 313 | set: function (key, val) { 314 | 315 | if (val === undefined) { 316 | $window.localStorage .removeItem(key); 317 | } else { 318 | $window.localStorage [key] = angular.toJson(val); 319 | } 320 | return $window.localStorage [key]; 321 | } 322 | } 323 | }]) 324 | 325 | .controller('CartController',['$scope', 'ngCart', function($scope, ngCart) { 326 | $scope.ngCart = ngCart; 327 | 328 | }]) 329 | 330 | .value('version', '0.0.3-rc.1'); 331 | ;'use strict'; 332 | 333 | 334 | angular.module('ngCart.directives', ['ngCart.fulfilment']) 335 | 336 | .controller('CartController',['$scope', 'ngCart', function($scope, ngCart) { 337 | $scope.ngCart = ngCart; 338 | }]) 339 | 340 | .directive('ngcartAddtocart', ['ngCart', function(ngCart){ 341 | return { 342 | restrict : 'E', 343 | controller : 'CartController', 344 | scope: { 345 | id:'@', 346 | name:'@', 347 | quantity:'@', 348 | quantityMax:'@', 349 | price:'@', 350 | data:'=' 351 | }, 352 | transclude: true, 353 | templateUrl: 'templates/ngCart/addtocart.html', 354 | link:function(scope, element, attrs){ 355 | scope.attrs = attrs; 356 | scope.inCart = function(){ 357 | return ngCart.getItemById(attrs.id); 358 | }; 359 | 360 | if (scope.inCart()){ 361 | scope.q = ngCart.getItemById(attrs.id).getQuantity(); 362 | } else { 363 | scope.q = parseInt(scope.quantity); 364 | } 365 | 366 | scope.qtyOpt = []; 367 | for (var i = 1; i <= scope.quantityMax; i++) { 368 | scope.qtyOpt.push(i); 369 | } 370 | 371 | } 372 | 373 | }; 374 | }]) 375 | 376 | .directive('ngcartCart', ['$http','$cookies','$rootScope', function($http,$cookies,$rootScope){ 377 | return { 378 | restrict: 'E', 379 | controller: 'CartController', 380 | scope: { 381 | }, 382 | templateUrl: 'templates/ngCart/cart.html', 383 | link: function (scope, element, attrs) { 384 | scope.book = function () { 385 | $rootScope.fact="Book Flights, using angular ngCart Directive"; 386 | $rootScope.publishMessage("REST POST=/api/user/flights"); 387 | $http.post('/api/user/flights', { 388 | token: $cookies.get('token'), 389 | flights: this.ngCart.getItems() 390 | }) 391 | .then(function (response) { 392 | if(response.data.added>0){ 393 | scope.ngCart.empty(); 394 | scope.ngCart.$cart.complete=true; 395 | } 396 | }); 397 | } 398 | } 399 | }; 400 | }]) 401 | 402 | .directive('ngcartSummary', ['$location','$window','$cookies','$rootScope',function(location,window,$cookies,$rootScope){ 403 | return { 404 | restrict : 'AEC', 405 | controller : 'CartController', 406 | scope: { 407 | }, 408 | transclude: true, 409 | templateUrl: 'templates/ngCart/summary.html', 410 | link:function(scope,element, attrs){ 411 | scope.isActive = function(viewLocation) { 412 | var absUrl = location.absUrl(); 413 | if (absUrl[absUrl.length-1] === '/') { 414 | absUrl += 'index.html'; 415 | } 416 | if (absUrl.indexOf(viewLocation) !== -1) { 417 | return true; 418 | } 419 | return false; 420 | }, 421 | scope.logout=function(){ 422 | $cookies.remove("user"); 423 | $rootScope.fact="User authorization through couchbase and ottoman user objects"; 424 | $rootScope.textAreaShowMe="CONSOLE RESET!! User logged out."; 425 | }, 426 | scope.getUser=function(){ 427 | if($cookies.get('user')===undefined){ 428 | scope.ngCart.empty(); 429 | window.location.href="http://" + window.location.host + "/#/login"; 430 | return; 431 | } 432 | return $cookies.get('user'); 433 | } 434 | } 435 | }; 436 | }]) 437 | 438 | .directive('ngcartCheckout', [function(){ 439 | return { 440 | restrict : 'E', 441 | controller : ('CartController', ['$scope', 'ngCart', 'fulfilmentProvider', function($scope, ngCart, fulfilmentProvider) { 442 | $scope.ngCart = ngCart; 443 | $scope.checkout = function () { 444 | fulfilmentProvider.setService($scope.service); 445 | fulfilmentProvider.setSettings($scope.settings); 446 | var promise = fulfilmentProvider.checkout(); 447 | console.log(promise); 448 | } 449 | }]), 450 | scope: { 451 | service:'@', 452 | settings:'=' 453 | }, 454 | transclude: true, 455 | templateUrl: 'templates/ngCart/checkout.html' 456 | }; 457 | }]);; 458 | angular.module('ngCart.fulfilment', []) 459 | .service('fulfilmentProvider', ['$injector', function($injector){ 460 | 461 | this._obj = { 462 | service : undefined, 463 | settings : undefined 464 | }; 465 | 466 | this.setService = function(service){ 467 | this._obj.service = service; 468 | }; 469 | 470 | this.setSettings = function(settings){ 471 | this._obj.settings = settings; 472 | }; 473 | 474 | this.checkout = function(){ 475 | var provider = $injector.get('ngCart.fulfilment.' + this._obj.service); 476 | return provider.checkout(this._obj.settings); 477 | 478 | } 479 | 480 | }]) 481 | 482 | 483 | .service('ngCart.fulfilment.log', ['$q', '$log', 'ngCart', function($q, $log, ngCart){ 484 | 485 | this.checkout = function(){ 486 | 487 | var deferred = $q.defer(); 488 | 489 | $log.info(ngCart.toObject()); 490 | deferred.resolve({ 491 | cart:ngCart.toObject() 492 | }); 493 | 494 | return deferred.promise; 495 | 496 | } 497 | 498 | }]) 499 | 500 | .service('ngCart.fulfilment.http', ['$http', 'ngCart', function($http, ngCart){ 501 | 502 | this.checkout = function(settings){ 503 | return $http.post(settings.url, 504 | {data:ngCart.toObject()}) 505 | } 506 | }]) 507 | 508 | 509 | .service('ngCart.fulfilment.paypal', ['$http', 'ngCart', function($http, ngCart){ 510 | 511 | 512 | }]); 513 | -------------------------------------------------------------------------------- /public/templates/cart.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 11 |
12 |
13 |
14 |
15 | CART DETAILS 16 |
17 |
18 |
19 | 20 |
21 |
22 |
23 |
ITINERARY
24 | 25 |
26 | 29 |
30 |
31 |
32 |
33 | -------------------------------------------------------------------------------- /public/templates/home.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 11 |
12 |
13 |
14 |
15 | Find a Flight 16 |
17 |
18 |
19 | 20 |
21 |
22 |
23 |
24 |
25 |
26 | 27 |
28 |
29 | From 30 | 38 | To 39 | 48 |
49 |
50 |
51 |

52 | Please enter at least 3 letters for the source airport. 53 |

54 |

55 | Please enter at least 3 letters for the destination airport. 56 |

57 |
58 | 59 |
60 |
61 |
62 | Leave 63 | 65 | Return 66 | 68 |
69 |
70 |
71 |
72 |
73 | 74 |
75 |
76 | 77 |
78 |
79 | 80 |
81 |
82 | 83 |
84 |
85 |
86 | 91 |
92 |
93 |
94 |
95 |
96 | 99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |

Available Flights

108 |
109 |
110 |

Outbound Leg {{this.leave}}

111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 140 | 145 | 146 | 147 |
AirlineFlightDepartureFromArrivalToAircraftPriceReservation
{{row.name}}{{row.flight}}{{row.utc}}{{row.sourceairport | uppercase}}{{row.utcland}}{{row.destinationairport | uppercase}}{{row.equipment}}${{row.price}} 136 | 139 | 141 | 144 |
148 |
149 |

Return Leg {{this.ret}}

150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 179 | 184 | 185 | 186 |
AirlineFlightDepartureFromArrivalToAircraftPriceReservation
{{rowRet.name}}{{rowRet.flight}}{{rowRet.utc}}{{rowRet.sourceairport | uppercase}}{{rowRet.utcland}}{{rowRet.destinationairport | uppercase}}{{rowRet.equipment}}${{rowRet.price}} 175 | 178 | 180 | 183 |
187 |
188 |
189 | 191 |
192 |
193 |
194 |
195 | -------------------------------------------------------------------------------- /public/templates/login.html: -------------------------------------------------------------------------------- 1 | 13 |
14 | 33 |
34 | -------------------------------------------------------------------------------- /public/templates/ngCart/cart.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 73 | 74 | 75 | 76 | 77 |
AirlineFlightDateFromToSeatsAmountTotal
Tax ({{ ngCart.getTaxRate() }}%):{{ ngCart.getTax() | currency }}
Shipping:{{ ngCart.getShipping() | currency }}
Total:{{ ngCart.totalCost() | currency }}
{{item.getData().name}}{{item.getData().flight}}{{item.getData().date + " " +item.getData().utc}}{{item.getData().sourceairport | uppercase}}{{item.getData().destinationairport | uppercase}}   71 | {{ item.getQuantity() | number }}   72 | {{ item.getPrice() | currency}}{{ item.getTotal() | currency }}
78 |
79 |
80 | 83 |
84 | -------------------------------------------------------------------------------- /public/templates/ngCart/summary.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | LOGGED IN AS: 5 | {{getUser()}} 6 | | LOGOUT
7 |
8 |
9 |
SHOPPING CART:{{ ngCart.getTotalItems() }} 10 | 11 | ({{ ngCart.totalCost() | currency }}) 12 |
13 |
14 | 31 |
32 | -------------------------------------------------------------------------------- /public/templates/user.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 11 |
12 |
13 |
14 |
15 | USER PROFILE 16 |
17 |
18 |
19 | 20 |
21 |
22 |
23 |
TOTAL BOOKED FLIGHTS: {{rowCollectionFlight.length}}
24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 45 | 46 | 47 |
AirlineFlightDepartureFromToReservation
{{row.name}}{{row.flight}}{{row.date}}{{row.sourceairport | uppercase}}{{row.destinationairport | uppercase}} 43 | Confirmed 44 |
48 |
49 | 52 |
53 |
54 |
55 |
56 | -------------------------------------------------------------------------------- /routes/routes.js: -------------------------------------------------------------------------------- 1 | //// ▶▶ require objects ◀◀ //// 2 | 3 | var bodyParser = require('body-parser'); 4 | var http = require('http'); 5 | var db = require('../utils/db'); 6 | var airport=require('../model/airport'); 7 | var flightPath=require('../model/flightPath'); 8 | var auth=require('../model/auth.js'); 9 | var user=require('../model/user.js'); 10 | var jwt = require('jsonwebtoken'); 11 | var config = require('./../utils/config'); 12 | var sec=config.application.hashToken; 13 | 14 | //// ▶▶ application/json parser ◀◀ //// 15 | var jsonParser = bodyParser.json(); 16 | 17 | //// ▶▶ application/x-www-form-urlencoded parser ◀◀ //// 18 | var urlencodedParser = bodyParser.urlencoded({ extended: false }); 19 | 20 | module.exports = function (app) { 21 | 22 | //// ▶▶ enable cors ◀◀ //// 23 | app.use(function(req, res, next) { 24 | res.header("Access-Control-Allow-Origin", "*"); 25 | res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 26 | next(); 27 | }); 28 | 29 | //// ▶▶ airports ◀◀ //// 30 | app.get('/api/airport/findAll',function(req,res) { 31 | if (req.query.search) { 32 | airport.findAll(req.query.search, jwt.decode(req.query.token).user,function (err, done) { 33 | if (err) { 34 | res.status = 400; 35 | res.send(err); 36 | return; 37 | } 38 | res.status = 202; 39 | res.send(done); 40 | }); 41 | }else{ 42 | res.status = 400; 43 | res.send({"airport":"bad request"}); 44 | return; 45 | } 46 | }); 47 | 48 | //// ▶▶ flightPath ◀◀ //// 49 | app.get('/api/flightPath/findAll',function(req,res){ 50 | if(req.query.from && req.query.to && req.query.leave){ 51 | flightPath.findAll(req.query.from, req.query.to,req.query.leave,jwt.decode(req.query.token).user, function (err, done) { 52 | if (err) { 53 | res.status = 400; 54 | res.send(err); 55 | return; 56 | } 57 | res.status = 202; 58 | res.send(done); 59 | }); 60 | }else{ 61 | res.status = 400; 62 | res.send({"flightPath":"bad request"}); 63 | return; 64 | } 65 | }); 66 | 67 | //// ▶▶ create login ◀◀ //// 68 | app.post('/api/user/login',jsonParser,function(req,res){ 69 | auth.createLogin(req.body.user,req.body.password,function(err,done){ 70 | if(err){ 71 | res.status=400; 72 | res.send(err); 73 | return; 74 | } 75 | res.status=202; 76 | res.send(done); 77 | return; 78 | }); 79 | }); 80 | 81 | //// ▶▶ login ◀◀ //// 82 | app.get('/api/user/login',urlencodedParser,function(req,res){ 83 | auth.login(req.query.user,req.query.password,function(err,check){ 84 | if(err){ 85 | res.status=400; 86 | res.send(err); 87 | return; 88 | } 89 | if(check){ 90 | res.status=202; 91 | res.send(check); 92 | return; 93 | } 94 | }); 95 | }); 96 | 97 | //// ▶▶ book flights ◀◀ //// 98 | app.post('/api/user/flights',jsonParser,function(req,res){ 99 | auth.book(req.body.token,req.body.flights,function(err,done){ 100 | if(err){ 101 | res.status=400; 102 | res.send(err); 103 | return; 104 | } 105 | res.status=202; 106 | res.send({added:done}); 107 | return; 108 | }); 109 | }); 110 | 111 | //// ▶▶ booked flights ◀◀ //// 112 | app.get('/api/user/flights',urlencodedParser,function(req,res){ 113 | auth.booked(req.query.token,function(err,done){ 114 | if(err){ 115 | res.status=400; 116 | res.send(err); 117 | return; 118 | } 119 | res.status=202; 120 | res.send(done); 121 | return; 122 | }); 123 | }); 124 | 125 | //// ▶▶ verify environment and publish URL to console ◀◀ //// 126 | db.query('SELECT NAME FROM system:keyspaces',function(err,result){ 127 | if(err){ 128 | console.log('Please confirm the couchbase instance:\n ',config.couchbase.endPoint, 129 | 'Is running and accessible. '); 130 | process.exit(); 131 | } 132 | else{ 133 | console.log("ENVIRONMENT: READY--LOGIN AT:","http://" + config.application.hostName + 134 | ":" + config.application.httpPort); 135 | } 136 | }); 137 | 138 | } 139 | -------------------------------------------------------------------------------- /utils/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "couchbase": { 3 | "endPoint": "localhost:8091", 4 | "n1qlService": "localhost:8093", 5 | "ftsService": "localhost:8094", 6 | "hostName": "127.0.0.1", 7 | "bucket": "travel-sample", 8 | "user": "Administrator", 9 | "password": "password", 10 | "dataPath": "", 11 | "indexPath": "", 12 | "indexType": "gsi", 13 | "indexerStorageMode":"forestdb", 14 | "showQuery": false, 15 | "indexMemQuota": 2048, 16 | "dataMemQuota": 1024, 17 | "ftsMemoryQuota":1024, 18 | "thresholdItemCount": 31565, 19 | "ftsIndex": { 20 | "type": "fulltext-index", 21 | "name": "hotels", 22 | "sourceType": "couchbase", 23 | "sourceName": "travel-sample", 24 | "planParams": { 25 | "maxPartitionsPerPIndex": 32, 26 | "numReplicas": 0, 27 | "hierarchyRules": null, 28 | "nodePlanParams": null, 29 | "pindexWeights": null, 30 | "planFrozen": false 31 | }, 32 | "params": { 33 | "mapping": { 34 | "byte_array_converter": "json", 35 | "default_analyzer": "standard", 36 | "default_datetime_parser": "dateTimeOptional", 37 | "default_field": "_all", 38 | "default_mapping": { 39 | "display_order": "1", 40 | "dynamic": true, 41 | "enabled": false 42 | }, 43 | "default_type": "_default", 44 | "index_dynamic": true, 45 | "store_dynamic": false, 46 | "type_field": "type", 47 | "types": { 48 | "hotel": { 49 | "display_order": "0", 50 | "dynamic": true, 51 | "enabled": true, 52 | "properties": { 53 | "city": { 54 | "dynamic": false, 55 | "enabled": true, 56 | "fields": [ 57 | { 58 | "analyzer": "", 59 | "display_order": "2", 60 | "include_in_all": true, 61 | "include_term_vectors": true, 62 | "index": true, 63 | "name": "city", 64 | "store": true, 65 | "type": "text" 66 | } 67 | ] 68 | }, 69 | "content": { 70 | "dynamic": false, 71 | "enabled": true, 72 | "fields": [ 73 | { 74 | "analyzer": "", 75 | "display_order": "4", 76 | "include_in_all": true, 77 | "include_term_vectors": true, 78 | "index": true, 79 | "name": "content", 80 | "store": true, 81 | "type": "text" 82 | } 83 | ] 84 | }, 85 | "name": { 86 | "dynamic": false, 87 | "enabled": true, 88 | "fields": [ 89 | { 90 | "analyzer": "", 91 | "display_order": "0", 92 | "include_in_all": true, 93 | "include_term_vectors": true, 94 | "index": true, 95 | "name": "name", 96 | "store": true, 97 | "type": "text" 98 | } 99 | ] 100 | }, 101 | "price": { 102 | "dynamic": false, 103 | "enabled": true, 104 | "fields": [ 105 | { 106 | "analyzer": "", 107 | "display_order": "1", 108 | "include_in_all": true, 109 | "include_term_vectors": true, 110 | "index": true, 111 | "name": "price", 112 | "store": true, 113 | "type": "text" 114 | } 115 | ] 116 | }, 117 | "reviews": { 118 | "dynamic": false, 119 | "enabled": true, 120 | "fields": [ 121 | { 122 | "analyzer": "", 123 | "display_order": "3", 124 | "include_in_all": true, 125 | "include_term_vectors": true, 126 | "index": true, 127 | "name": "reviews", 128 | "store": false, 129 | "type": "text" 130 | } 131 | ] 132 | } 133 | } 134 | } 135 | } 136 | }, 137 | "store": { 138 | "kvStoreName": "forestdb" 139 | } 140 | }, 141 | "sourceParams": { 142 | "clusterManagerBackoffFactor": 0, 143 | "clusterManagerSleepInitMS": 0, 144 | "clusterManagerSleepMaxMS": 2000, 145 | "dataManagerBackoffFactor": 0, 146 | "dataManagerSleepInitMS": 0, 147 | "dataManagerSleepMaxMS": 2000, 148 | "feedBufferAckThreshold": 0, 149 | "feedBufferSizeBytes": 0 150 | } 151 | } 152 | }, 153 | "application": { 154 | "autoprovision": true, 155 | "hostName": "localhost", 156 | "httpPort": 3000, 157 | "dataSource": "embedded", 158 | "wait": 3000, 159 | "checkInterval": 1000, 160 | "verbose": false, 161 | "distanceCostMultiplier": 0.1, 162 | "avgKmHr": 800, 163 | "hashToken": "UNSECURE_SECRET_TOKEN" 164 | } 165 | } -------------------------------------------------------------------------------- /utils/db.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @type {exports} 4 | */ 5 | var config = require('./config'); 6 | var couchbase = require('couchbase'); 7 | var endPoint = config.couchbase.endPoint; 8 | var bucket = config.couchbase.bucket; 9 | var myCluster = new couchbase.Cluster(endPoint); 10 | var myBucket=myCluster.openBucket(bucket); 11 | var ODMBucket = myCluster.openBucket(bucket); 12 | var db = myBucket; 13 | var ottoman = require('ottoman'); 14 | var faye = require('faye'); 15 | var client = new faye.Client('http://localhost:8000/faye'); 16 | 17 | /** 18 | * 19 | * @param key 20 | * @param val 21 | * @param done 22 | */ 23 | function upsert(key, val, done) { 24 | db.upsert(key, val, function (err, res) { 25 | if (err) { 26 | console.log("DB.UPSERT:",key,":", err); 27 | done(err, null); 28 | return; 29 | } 30 | done(null, res); 31 | }); 32 | } 33 | 34 | /** 35 | * 36 | * @param key 37 | * @param done 38 | */ 39 | function read(key, done) { 40 | db.get(key, function (err, result) { 41 | if (err) { 42 | console.log("DB.READ:", err); 43 | done(err, null); 44 | return; 45 | } 46 | done(null, result); 47 | }); 48 | } 49 | 50 | /** 51 | * 52 | * @param key 53 | * @param done 54 | */ 55 | function docDelete(key, done) { 56 | db.delete(key, function (err, result) { 57 | if (err) { 58 | console.log("DB.DELETE:", err); 59 | done(err, null); 60 | return; 61 | } 62 | done(null, true); 63 | }); 64 | } 65 | 66 | function refreshExpiry(key, time, done) { 67 | db.touch(key, time, function(err, result) { 68 | if(err) { 69 | return done(err, null); 70 | } 71 | done(null, true); 72 | }); 73 | } 74 | 75 | function sendMessage(channel, message) { 76 | if(config.couchbase.showQuery){ 77 | if(channel){ 78 | var publication = client.publish('/'+channel, {text: message},function(err,pubres){ 79 | if(err){ 80 | console.log("ERR:",err); 81 | } 82 | if(pubres){ 83 | console.log("SUCCESS:",pubres); 84 | } 85 | }); 86 | } 87 | } 88 | } 89 | 90 | /** 91 | * 92 | * @param sql 93 | * @param user 94 | * @param done 95 | */ 96 | function query(sql,user,done){ 97 | 98 | // Init a channel 99 | var channel; 100 | 101 | // Check for only 2 parameters and if only 2 assign the callback correctly 102 | // Otherwise, assign channel to the username passed in for publishing using Faye 103 | if(typeof done === "undefined"){ 104 | done=user; 105 | } 106 | else{ 107 | channel=user; 108 | } 109 | 110 | // Setup Query 111 | var N1qlQuery = couchbase.N1qlQuery; 112 | 113 | // Check if configured to show queries in console 114 | if(config.couchbase.showQuery){ 115 | console.log("QUERY:",sql); 116 | } 117 | 118 | // publish to channel subscriber using faye 119 | if(channel){ 120 | var publication = client.publish('/'+channel, {text: 'N1QL='+sql},function(err,pubres){ 121 | if(err){ 122 | console.log("ERR:",err); 123 | } 124 | if(pubres){ 125 | console.log("SUCCESS:",pubres); 126 | } 127 | }); 128 | } 129 | 130 | // Make a N1QL specific Query 131 | var query = N1qlQuery.fromString(sql); 132 | 133 | // Issue Query 134 | db.query(query,function(err,result){ 135 | if (err) { 136 | console.log("ERR:",err); 137 | done(err,null); 138 | return; 139 | } 140 | done(null,result); 141 | }); 142 | } 143 | 144 | 145 | /** 146 | * 147 | * @param done 148 | */ 149 | 150 | module.exports.ODMBucket=ODMBucket; 151 | module.exports.endPoint=endPoint; 152 | module.exports.bucket=bucket; 153 | module.exports.query=query; 154 | module.exports.delete=docDelete; 155 | module.exports.read=read; 156 | module.exports.upsert=upsert; 157 | module.exports.refreshExpiry=refreshExpiry; 158 | module.exports.sendMessage=sendMessage; 159 | -------------------------------------------------------------------------------- /utils/provision.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var config = require('./config'); 3 | var request = require('request'); 4 | var fs = require('fs'); 5 | 6 | var checkInterval = config.application.checkInterval; 7 | 8 | class cluster { 9 | constructor() { 10 | // local json object for Class properties. ES6 does not 11 | // include suport for class properties beyond setter/getters. 12 | // The constructor instantiates a "config" and passes this 13 | // through the provisioning process. 14 | 15 | //implementationVersion 16 | 17 | var locals = {}; 18 | locals.endPoint = config.couchbase.endPoint; 19 | locals.endPointQuery = config.couchbase.n1qlService; 20 | locals.endPointFts = config.couchbase.ftsService; 21 | locals.hostName = config.couchbase.hostName; 22 | locals.sampleBucket = config.couchbase.bucket; 23 | locals.sampleBucketCount = config.couchbase.thresholdItemCount; 24 | locals.user = config.couchbase.user; 25 | locals.password = config.couchbase.password; 26 | locals.indexType = config.couchbase.indexType; 27 | locals.indexerStorageMode = config.couchbase.indexerStorageMode; 28 | locals.indexMemQuota = config.couchbase.indexMemQuota; 29 | locals.dataMemQuota = config.couchbase.dataMemQuota; 30 | locals.ftsMemQuota = config.couchbase.ftsMemoryQuota; 31 | locals.dataPath = config.couchbase.dataPath; 32 | locals.indexPath = config.couchbase.indexPath; 33 | locals.checkInterval = config.application.checkInterval; 34 | locals.ftsIndex=config.couchbase.ftsIndex; 35 | locals.finsihed = false; 36 | locals.currentCount = 0; 37 | locals.timerWait = ""; 38 | locals.instanceVersion=0; 39 | 40 | this._locals = locals; 41 | } 42 | 43 | provision() { 44 | // Load locals to pass through provisioning sequence 45 | var locals = this.locals; 46 | 47 | // resolve path issues 48 | this._resolvePaths(locals); 49 | 50 | // Provision promise chain sequence. Without binding "this", 51 | // scope is not preserved from the caller each time a new 52 | // promise is instantiated. 53 | 54 | this._verifyNodejsVersion(locals) 55 | .then(this._instanceExsists) 56 | .then(this._verifyCouchbaseVersion.bind(this)) 57 | .then(this._init) 58 | .then(this._rename) 59 | .then(this._storageMode) 60 | .then(this._services.bind(this)) 61 | .then(this._memory) 62 | .then(this._admin) 63 | .then(this._bucket) 64 | .then(this._loaded.bind(this)) 65 | .then(this._buildFtsIndex.bind(this)) 66 | .then(this._finish.bind(this)) 67 | .catch((err) => { 68 | console.log("ERR:", err) 69 | }); 70 | } 71 | 72 | get locals() { 73 | return this._locals; 74 | } 75 | 76 | set _currentCount(count){ 77 | this.locals.currentCount=count; 78 | } 79 | 80 | set _instanceVersion(version){ 81 | this.locals.instanceVersion=version; 82 | } 83 | 84 | set finished(currentState) { 85 | this._locals.finished = currrentState; 86 | } 87 | 88 | _resolvePaths(locals) { 89 | // Check for custom datapath, otherwise assign to platform default 90 | if (locals.dataPath == "") { 91 | if (process.platform == 'darwin') { 92 | locals.dataPath = "/Users/" + process.env.USER + 93 | "/Library/Application Support/Couchbase/var/lib/couchbase/data"; 94 | } else { 95 | locals.dataPath = "/opt/couchbase/var/lib/couchbase/data"; 96 | } 97 | } 98 | // Check for custom indexpath, otherwise assign to platform default 99 | if (locals.indexPath == "") { 100 | if (process.platform == 'darwin') { 101 | locals.indexPath = "/Users/" + process.env.USER + 102 | "/Library/Application Support/Couchbase/var/lib/couchbase/data"; 103 | } else { 104 | locals.indexPath = "/opt/couchbase/var/lib/couchbase/data"; 105 | } 106 | } 107 | } 108 | 109 | _init(locals) { 110 | return new Promise( 111 | (resolve, reject) => { 112 | request.post({ 113 | url: 'http://' + locals.endPoint + '/nodes/self/controller/settings', 114 | form: { 115 | path: locals.dataPath, 116 | index_path: locals.indexPath 117 | } 118 | }, (err, httpResponse, body) => { 119 | if (err) { 120 | reject(err); 121 | return; 122 | } 123 | console.log(" PROVISION INITIALIZE SERVICES:", httpResponse.statusCode); 124 | if(httpResponse.statusCode!=200) console.log(" WARNING:",body); 125 | resolve(locals); 126 | }); 127 | }); 128 | } 129 | 130 | _rename(locals) { 131 | return new Promise( 132 | (resolve, reject) => { 133 | request.post({ 134 | url: 'http://' + locals.endPoint + '/node/controller/rename', 135 | form: { 136 | hostname: locals.hostName 137 | } 138 | }, (err, httpResponse, body) => { 139 | if (err) { 140 | reject(err); 141 | return; 142 | } 143 | console.log(" PROVISION RENAMING:", httpResponse.statusCode); 144 | if(httpResponse.statusCode!=200) console.log(" WARNING:",body); 145 | resolve(locals); 146 | }); 147 | }); 148 | } 149 | 150 | _storageMode(locals) { 151 | return new Promise( 152 | (resolve, reject) => { 153 | request.post({ 154 | url: 'http://' + locals.endPoint + '/settings/indexes', 155 | form: { 156 | storageMode: locals.indexerStorageMode 157 | } 158 | }, (err, httpResponse, body) => { 159 | if (err) { 160 | reject(err); 161 | return; 162 | } 163 | console.log(" PROVISION INDEX STORAGE MODE:", httpResponse.statusCode); 164 | if(httpResponse.statusCode!=200) console.log(" WARNING:",body); 165 | resolve(locals); 166 | }); 167 | }); 168 | } 169 | 170 | _services(locals) { 171 | return new Promise( 172 | (resolve, reject) => { 173 | var data = { 174 | services:'kv,n1ql,index' 175 | }; 176 | 177 | if (locals.ftsMemQuota != "0" && locals.instanceVersion>=4.5) data["services"] += ",fts"; 178 | 179 | request.post({ 180 | url: 'http://' + locals.endPoint + '/node/controller/setupServices', 181 | form: data 182 | }, (err, httpResponse, body) => { 183 | if (err) { 184 | reject(err); 185 | return; 186 | } 187 | console.log(" PROVISION SERVICES:", httpResponse.statusCode); 188 | if(httpResponse.statusCode!=200) console.log(" WARNING:",body); 189 | resolve(locals); 190 | }); 191 | }); 192 | } 193 | 194 | _memory(locals) { 195 | return new Promise( 196 | (resolve, reject) => { 197 | var data = { 198 | indexMemoryQuota: locals.indexMemQuota, 199 | memoryQuota: locals.dataMemQuota 200 | }; 201 | 202 | if (locals.ftsMemQuota != "0" && locals.instanceVersion>=4.5) 203 | data["ftsMemoryQuota"] = locals.ftsMemQuota; 204 | 205 | request.post({ 206 | url: 'http://' + locals.endPoint + '/pools/default', 207 | form: data 208 | }, (err, httpResponse, body) => { 209 | if (err) { 210 | reject(err); 211 | return; 212 | } 213 | console.log(" PROVISION MEMORY:", httpResponse.statusCode); 214 | if(httpResponse.statusCode!=200) console.log(" WARNING:",body); 215 | resolve(locals); 216 | }); 217 | }); 218 | } 219 | 220 | _admin(locals) { 221 | return new Promise( 222 | (resolve, reject) => { 223 | request.post({ 224 | url: 'http://' + locals.endPoint + '/settings/web', 225 | form: { 226 | password: locals.password, 227 | username: locals.user, 228 | port: 'SAME' 229 | } 230 | }, (err, httpResponse, body) => { 231 | if (err) { 232 | reject(err); 233 | return; 234 | } 235 | console.log(" PROVISION ADMIN USER:", httpResponse.statusCode); 236 | if(httpResponse.statusCode!=200) console.log(" WARNING:",body); 237 | resolve(locals); 238 | }); 239 | }); 240 | } 241 | 242 | _bucket(locals) { 243 | return new Promise( 244 | (resolve, reject) => { 245 | request.post({ 246 | url: 'http://' + locals.endPoint + '/sampleBuckets/install', 247 | headers: { 248 | 'Content-Type': 'application/x-www-form-urlencoded' 249 | }, 250 | form: JSON.stringify([locals.sampleBucket]), 251 | auth: { 252 | 'user': locals.user, 253 | 'pass': locals.password, 254 | 'sendImmediately': true 255 | } 256 | }, (err, httpResponse, body) => { 257 | if (err) { 258 | reject(err); 259 | return; 260 | } 261 | console.log(" PROVISION BUCKET:", httpResponse.statusCode); 262 | if (httpResponse.statusCode == 202) { 263 | resolve(locals); 264 | } 265 | reject(httpResponse.statusCode); 266 | }); 267 | }); 268 | } 269 | 270 | _instanceExsists(locals) { 271 | return new Promise( 272 | (resolve, reject) => { 273 | request.get({ 274 | url: "http://" + locals.endPoint + "/pools/default/buckets/", 275 | auth: { 276 | 'user': locals.user, 277 | 'pass': locals.password, 278 | 'sendImmediately': true 279 | } 280 | }, (err, httpResponse, body) => { 281 | if (err) { 282 | reject("COUCHBASE INSTANCE AT " + locals.endPoint + " NOT FOUND."); 283 | return; 284 | } 285 | body = JSON.parse(body); 286 | for (var i = 0; i < body.length; i++) { 287 | if (body[i].name == locals.sampleBucket) { 288 | reject("\n This application cannot provision an already built cluster.\n" + 289 | " BUCKET:" + locals.sampleBucket + " on CLUSTER " + 290 | locals.endPoint + " EXISTS\n The cluster has not been modified.\n" + 291 | " To run the travel-sample application run 'npm start'"); 292 | } 293 | } 294 | resolve(locals); 295 | }); 296 | }); 297 | } 298 | 299 | _queryOnline() { 300 | return new Promise( 301 | (resolve, reject) => { 302 | request.get({ 303 | url: "http://" + this.endPointQuery + "/query?statement=SELECT+name+FROM+system%3Akeyspaces", 304 | auth: { 305 | 'user': config.couchbase.user, 306 | 'pass': config.couchbase.password, 307 | 'sendImmediately': true 308 | }, 309 | headers: { 310 | Accept: 'application/json' 311 | } 312 | }, (err, httpResponse, body) => { 313 | if (err) { 314 | reject(err); 315 | return; 316 | } 317 | if (response.statusCode == 200) 318 | resolve(httpResponse.statusCode); 319 | }); 320 | }); 321 | } 322 | 323 | _itemCount() { 324 | return new Promise( 325 | (resolve, reject)=> { 326 | request.get({ 327 | url: "http://" + this.locals.endPoint + "/pools/default/buckets/" + this.locals.sampleBucket, 328 | auth: { 329 | 'user': this.locals.user, 330 | 'pass': this.locals.password, 331 | 'sendImmediately': true 332 | } 333 | }, (err, httpResponse, body) => { 334 | if (err) { 335 | resolve(false); 336 | return; 337 | } 338 | if (parseInt(JSON.parse(body).basicStats.itemCount) > this.locals.sampleBucketCount) { 339 | resolve(true); 340 | } 341 | else{ 342 | this._currentCount=parseInt(JSON.parse(body).basicStats.itemCount); 343 | resolve(false); 344 | } 345 | }); 346 | }); 347 | } 348 | 349 | _loaded() { 350 | return new Promise( 351 | (resolve, reject)=> { 352 | this.locals.timerLoop = setInterval(()=> { 353 | this._itemCount().then((loaded)=> { 354 | if (loaded) { 355 | clearInterval(this.locals.timerLoop); 356 | process.stdout.write(" LOADING ITEMS:100% of " +this.locals.sampleBucketCount + " Items"); 357 | console.log("\n BUCKET:", this.locals.sampleBucket, "LOADED."); 358 | resolve("DONE"); 359 | return; 360 | } 361 | process.stdout.write(" LOADING ITEMS:" + 362 | Math.round(100*(this.locals.currentCount/this.locals.sampleBucketCount))+ "% of " + 363 | this.locals.sampleBucketCount + " Items\r"); 364 | }); 365 | }, this.locals.checkInterval); 366 | } 367 | ); 368 | } 369 | 370 | _buildFtsIndex(){ 371 | return new Promise( 372 | (resolve, reject) => { 373 | if(this.locals.instanceVersion>=4.5 && this.locals.ftsMemQuota!="0"){ 374 | request({ 375 | url: 'http://' + this.locals.endPointFts + '/api/index/' + this.locals.ftsIndex.name, 376 | method:'PUT', 377 | json: true, 378 | body: this.locals.ftsIndex, 379 | auth: { 380 | 'user': this.locals.user, 381 | 'pass': this.locals.password, 382 | 'sendImmediately': true 383 | } 384 | }, (err, httpResponse, body) => { 385 | if (err) { 386 | reject(err); 387 | return; 388 | } 389 | console.log(" PROVISION FTS INDEX:", httpResponse.statusCode); 390 | if(httpResponse.statusCode!=200) console.log(" WARNING:",body); 391 | resolve("ok"); 392 | }); 393 | } 394 | else { 395 | console.log(" PROVISION FTS INDEX: Skipping, CB version < 4.5 or ftsMemoryQuota = 0"); 396 | resolve("ok"); 397 | } 398 | 399 | }); 400 | } 401 | 402 | _verifyCouchbaseVersion(locals){ 403 | return new Promise( 404 | (resolve, reject)=> { 405 | request.get({ 406 | url: "http://" + this.locals.endPoint + "/pools", 407 | auth: { 408 | 'user': this.locals.user, 409 | 'pass': this.locals.password, 410 | 'sendImmediately': true 411 | } 412 | }, (err, httpResponse, body) => { 413 | if (err) { 414 | resolve(false); 415 | return; 416 | } 417 | var ver = (JSON.parse(body).implementationVersion).split(".",2); 418 | this._instanceVersion=parseFloat(ver[0]+"."+ver[1]); 419 | resolve(locals); 420 | }); 421 | }); 422 | } 423 | 424 | _verifyNodejsVersion(locals) { 425 | return new Promise( 426 | (resolve, reject)=> { 427 | if (parseInt(((process.version).split("v"))[1].substr(0, 1)) < 4) { 428 | reject("\n The nodejs version is too low. This application requires\n" + 429 | " ES6 features in order to provision a cluster, specifically: \n" + 430 | " --promises \n --arrow functions \n --classes \n" + 431 | " Please upgrade the nodejs version from:\n --Current " + 432 | process.version + "\n --Minimum:4.0.0"); 433 | } else resolve(locals); 434 | }); 435 | } 436 | 437 | _finish() { 438 | return new Promise( 439 | (resolve, reject)=> { 440 | console.log("Cluster " + this.locals.endPoint + " provisioning complete. \n" + 441 | " To login to couchbase: open a browser " + this.locals.endPoint + "\n" + 442 | " To run the travel-sample application, run 'npm start'"); 443 | resolve("ok"); 444 | }); 445 | } 446 | } 447 | var c = new cluster(config); 448 | c.provision(); 449 | --------------------------------------------------------------------------------