├── .gitattributes ├── .gitignore ├── README.md ├── angularjs-material-seed ├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src │ ├── app.routes.ts │ ├── app.ts │ ├── app │ │ ├── directives │ │ │ └── directives │ │ │ │ ├── directives.component.ts │ │ │ │ ├── directives.html │ │ │ │ ├── directives.module.ts │ │ │ │ ├── directives.routes.ts │ │ │ │ └── directives.service.ts │ │ ├── expressions │ │ │ ├── array │ │ │ │ ├── array.component.ts │ │ │ │ ├── array.html │ │ │ │ ├── array.module.ts │ │ │ │ ├── array.routes.ts │ │ │ │ └── array.service.ts │ │ │ ├── number │ │ │ │ ├── number.component.ts │ │ │ │ ├── number.html │ │ │ │ ├── number.module.ts │ │ │ │ ├── number.routes.ts │ │ │ │ └── number.service.ts │ │ │ ├── object │ │ │ │ ├── object.component.ts │ │ │ │ ├── object.html │ │ │ │ ├── object.module.ts │ │ │ │ ├── object.routes.ts │ │ │ │ └── object.service.ts │ │ │ └── string │ │ │ │ ├── string.component.ts │ │ │ │ ├── string.html │ │ │ │ ├── string.module.ts │ │ │ │ ├── string.routes.ts │ │ │ │ └── string.service.ts │ │ ├── home │ │ │ ├── home.component.ts │ │ │ ├── home.html │ │ │ ├── home.module.ts │ │ │ ├── home.routes.ts │ │ │ └── home.service.ts │ │ ├── main │ │ │ ├── main.component.ts │ │ │ ├── main.html │ │ │ └── main.module.ts │ │ └── settings │ │ │ ├── settings.component.ts │ │ │ ├── settings.html │ │ │ ├── settings.module.ts │ │ │ └── settings.routes.ts │ ├── assets │ │ ├── angularjs-material.png │ │ ├── favicon.ico │ │ └── material-icons.woff2 │ ├── index.html │ └── style.scss ├── tsconfig.json └── webpack.config.js ├── assets └── star.png ├── package-lock.json └── shopping-cart ├── .gitignore ├── README.md ├── client ├── assets │ ├── Database-Architecture.txt │ ├── customers.json │ ├── desserts.json │ └── shopping-cart.png ├── css │ ├── favicon.ico │ ├── material-icons.woff2 │ └── style.css ├── js │ ├── app.js │ ├── app.service.js │ ├── home.controller.js │ ├── menu.controller.js │ ├── products.controller.js │ └── ui-bootstrap-2.5.0.min.js ├── uploads │ ├── img-2852020-1590684956674.jpg │ └── iphone-11-pro-27-5-2020-1590551435418.jpg └── views │ ├── index.html │ └── pages │ ├── home.html │ └── products.html ├── package-lock.json ├── package.json ├── server.js └── utils ├── config.js ├── db.js ├── helper.js ├── product.js ├── routes.js └── socket.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | coverage -------------------------------------------------------------------------------- /angularjs-material-seed/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = tab 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | spaces_around_brackets = inside 11 | max_line_length = 1000 12 | 13 | spaces_around_brackets = inside 14 | max_line_length = 1000 15 | 16 | [*.md] 17 | max_line_length = off 18 | trim_trailing_whitespace = false 19 | -------------------------------------------------------------------------------- /angularjs-material-seed/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /angularjs-material-seed/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Pradeep Kumar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /angularjs-material-seed/README.md: -------------------------------------------------------------------------------- 1 | # AngularJs-Material Seed App 2 | 3 | Ready to go template to get started with AngularJs, Material, Typescript, SCSS and Webpack. 4 | 5 | Includes: 6 | * Predefined sidenav with hammerjs-support 7 | * Offline Material Icons 8 | * Home and Settings page as AngularJs 1.6 components with their own modules 9 | * Multiple theme configuration 10 | 11 | ## Demo 12 | [link](#) 13 | 14 | ## Usage 15 | Start Live Dev Server 16 | ```js 17 | npm start 18 | ``` 19 | 20 | Build Project and deploy to "dist": 21 | ```js 22 | npm run build:prod 23 | ``` 24 | 25 | ## Project Output 26 | 27 | ![Project Output](https://github.com/learning-zone/angularjs-interview-questions/blob/master/angular-material-seed/src/assets/angularjs-material.png) 28 | 29 | 30 | ## References 31 | 32 | * [AngularJS V1.7x](https://code.angularjs.org/snapshot-stable/docs/tutorial/step_00) 33 | * [AngularJS Material](https://material.angularjs.org/latest/) 34 | * [HammerJS](https://hammerjs.github.io/) 35 | * [Sass](https://sass-lang.com/) 36 | * [Webpack](https://webpack.js.org/) 37 | * [Typescript](https://www.typescriptlang.org/) 38 | -------------------------------------------------------------------------------- /angularjs-material-seed/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angularjs-webpack-typescript", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --port 4200 --mode development --open", 8 | "build": "webpack --mode development", 9 | "build:prod": "webpack --mode production", 10 | "test": "karma start karma.conf.js", 11 | "test-single-run": "npm test -- --single-run", 12 | "preupdate-webdriver": "npm install", 13 | "update-webdriver": "webdriver-manager update --gecko false", 14 | "preprotractor": "npm run update-webdriver", 15 | "protractor": "protractor e2e-tests/protractor.conf.js" 16 | }, 17 | "author": "", 18 | "license": "ISC", 19 | "dependencies": { 20 | "@types/angular": "1.6.54", 21 | "@types/angular-material": "1.1.68", 22 | "@types/node": "12.0.10", 23 | "@uirouter/angularjs": "1.0.20", 24 | "angular": "^1.8.0", 25 | "angular-animate": "^1.8.0", 26 | "angular-aria": "^1.8.0", 27 | "angular-hammer": "2.2.0", 28 | "angular-material": "1.1.19", 29 | "hammerjs": "2.0.8" 30 | }, 31 | "devDependencies": { 32 | "angular-mocks": "^1.8.0", 33 | "clean-webpack-plugin": "^3.0.0", 34 | "copy-webpack-plugin": "^5.0.3", 35 | "css-loader": "1.0.0", 36 | "file-loader": "3.0.1", 37 | "html-loader": "0.5.5", 38 | "html-webpack-plugin": "^3.2.0", 39 | "jasmine-core": "^3.5.0", 40 | "karma": "^5.1.0", 41 | "karma-chrome-launcher": "^3.1.0", 42 | "karma-firefox-launcher": "^1.3.0", 43 | "karma-jasmine": "^3.3.1", 44 | "live-server": "^1.2.1", 45 | "mini-css-extract-plugin": "^0.7.0", 46 | "ngtemplate-loader": "2.0.1", 47 | "node-sass": "4.12.0", 48 | "protractor": "^5.4.4", 49 | "sass-loader": "7.1.0", 50 | "style-loader": "0.23.1", 51 | "ts-loader": "5.3.2", 52 | "typescript": "3.5.2", 53 | "uglifyjs-webpack-plugin": "^2.1.3", 54 | "url-loader": "1.1.2", 55 | "webpack": "4.35.0", 56 | "webpack-bundle-analyzer": "3.3.2", 57 | "webpack-cli": "3.3.5", 58 | "webpack-dev-server": "3.7.2" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /angularjs-material-seed/src/app.routes.ts: -------------------------------------------------------------------------------- 1 | export function routes($urlRouterProvider) { 2 | $urlRouterProvider.otherwise('/'); 3 | } 4 | routes.$inject = ['$urlRouterProvider']; -------------------------------------------------------------------------------- /angularjs-material-seed/src/app.ts: -------------------------------------------------------------------------------- 1 | import * as angular from 'angular'; 2 | import * as ngAnimate from 'angular-animate'; 3 | import * as ngAria from 'angular-aria'; 4 | import * as ngMaterial from 'angular-material'; 5 | import * as uiRouter from '@uirouter/angularjs'; 6 | import { routes } from './app.routes'; 7 | import 'angular-material/angular-material.scss'; 8 | import 'hammerjs'; 9 | import * as hmTouchEvents from 'angular-hammer'; 10 | 11 | import './style.scss'; 12 | 13 | import mainModule from './app/main/main.module'; 14 | import settingsModule from './app/settings/settings.module'; 15 | import homeModule from './app/home/home.module'; 16 | import numberModule from './app/expressions/number/number.module'; 17 | import objectModule from './app/expressions/object/object.module'; 18 | import stringModule from './app/expressions/string/string.module'; 19 | import arrayModule from './app/expressions/array/array.module'; 20 | import directivesModule from './app/directives/directives/directives.module'; 21 | 22 | 23 | angular.module("app", [ 24 | uiRouter.default, 25 | ngAnimate, ngAria, 26 | ngMaterial, 27 | hmTouchEvents, 28 | mainModule, 29 | settingsModule, 30 | homeModule, 31 | numberModule, 32 | stringModule, 33 | objectModule, 34 | arrayModule, 35 | directivesModule 36 | ]); 37 | angular.module("app").config(routes); 38 | 39 | angular.module("app").config(["$mdThemingProvider", function ($mdThemingProvider) { 40 | $mdThemingProvider.theme("blue") 41 | .primaryPalette("blue") 42 | .accentPalette("red"); 43 | 44 | $mdThemingProvider.theme("green") 45 | .primaryPalette("teal") 46 | .accentPalette("red"); 47 | 48 | $mdThemingProvider.alwaysWatchTheme(true); 49 | }]); 50 | 51 | //https://docs.angularjs.org/guide/production 52 | angular.module("app").config(['$compileProvider', function ($compileProvider) { 53 | $compileProvider.debugInfoEnabled(true); 54 | $compileProvider.commentDirectivesEnabled(false); 55 | $compileProvider.cssClassDirectivesEnabled(false); 56 | }]); 57 | 58 | angular.bootstrap(document, ["app"]); 59 | 60 | //https://github.com/vsternbach/angularjs-typescript-webpack 61 | //http://ryanmullins.github.io/angular-hammer/ -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/directives/directives/directives.component.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as angular from 'angular'; 3 | 4 | class DirectivesCtrl { 5 | 6 | constructor(private $scope: any) { } 7 | } 8 | 9 | export default { 10 | bindings: { title: "=" }, 11 | templateUrl: require("./directives.html"), 12 | controller: DirectivesCtrl 13 | } -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/directives/directives/directives.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NgAPP Directives 6 | 7 | 8 | 9 | 10 | some button 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/directives/directives/directives.module.ts: -------------------------------------------------------------------------------- 1 | import * as angular from 'angular'; 2 | 3 | import { routes } from './directives.routes'; 4 | import directivesComponent from './directives.component'; 5 | import { DirectivesService } from './directives.service'; 6 | 7 | export default angular.module('ng-app', []) 8 | .config(routes) 9 | .component("directives", directivesComponent) 10 | .service('directivesService', DirectivesService) 11 | .name; -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/directives/directives/directives.routes.ts: -------------------------------------------------------------------------------- 1 | export function routes($urlRouterProvider, $stateProvider) { 2 | $stateProvider.state({ name: 'directives', url: '/directives', component: 'directives' }); 3 | } 4 | routes.$inject = ['$urlRouterProvider', '$stateProvider']; -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/directives/directives/directives.service.ts: -------------------------------------------------------------------------------- 1 | export class DirectivesService { 2 | constructor() { 3 | } 4 | } -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/array/array.component.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as angular from 'angular'; 3 | 4 | class ArrayCtrl { 5 | 6 | constructor(private $scope: any) { 7 | 8 | } 9 | 10 | } 11 | 12 | export default { 13 | bindings: { text: "@" }, /** Reading an attribute as text **/ 14 | templateUrl: require("./array.html"), 15 | controller: ArrayCtrl 16 | } -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/array/array.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Array Expressions 6 | 7 | 8 | 9 | 10 |
11 | 12 |
13 |
Student Marks
14 |

15 | Physics: {{marks[0] }}
16 | Chemistry: {{marks[1] }}
17 | Mathematics: {{marks[2] }}
18 |

19 |
20 |
21 |
22 |
23 |
24 |
-------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/array/array.module.ts: -------------------------------------------------------------------------------- 1 | import * as angular from 'angular'; 2 | 3 | import { routes } from './array.routes'; 4 | import arrayComponent from './array.component'; 5 | import { ArrayService } from './array.service'; 6 | 7 | export default angular.module('array', []) 8 | .config(routes) 9 | .component("array", arrayComponent) 10 | .service('arrayService', ArrayService) 11 | .name; -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/array/array.routes.ts: -------------------------------------------------------------------------------- 1 | export function routes($urlRouterProvider, $stateProvider) { 2 | $stateProvider.state({ name: 'array', url: '/array', component: 'array' }); 3 | } 4 | routes.$inject = ['$urlRouterProvider', '$stateProvider']; -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/array/array.service.ts: -------------------------------------------------------------------------------- 1 | export class ArrayService { 2 | constructor() { 3 | } 4 | } -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/number/number.component.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as angular from 'angular'; 3 | 4 | class NumberCtrl { 5 | sum = 0; 6 | constructor(private $scope: any) { 7 | 8 | } 9 | 10 | getResult() { 11 | this.sum = this.$scope.user.number1 + this.$scope.user.number2; 12 | this.$scope.result = "Total is: "+ this.sum; 13 | } 14 | } 15 | 16 | export default { 17 | bindings: { title: "=" }, 18 | templateUrl: require("./number.html"), 19 | controller: NumberCtrl 20 | } -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/number/number.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Number Expressions 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Add 23 | 24 | 25 |
26 | {{result}} 27 |
28 |
29 |
30 |
31 |
-------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/number/number.module.ts: -------------------------------------------------------------------------------- 1 | import * as angular from 'angular'; 2 | 3 | import { routes } from './number.routes'; 4 | import numberComponent from './number.component'; 5 | import { NumberService } from './number.service'; 6 | 7 | export default angular.module('number', []) 8 | .config(routes) 9 | .component("number", numberComponent) 10 | .service('numberService', NumberService) 11 | .name; -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/number/number.routes.ts: -------------------------------------------------------------------------------- 1 | export function routes($urlRouterProvider, $stateProvider) { 2 | $stateProvider.state({ name: 'number', url: '/number', component: 'number' }); 3 | } 4 | routes.$inject = ['$urlRouterProvider', '$stateProvider']; -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/number/number.service.ts: -------------------------------------------------------------------------------- 1 | export class NumberService { 2 | constructor() { 3 | } 4 | } -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/object/object.component.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as angular from 'angular'; 3 | 4 | class ObjectCtrl { 5 | 6 | constructor(private $scope: any) { 7 | 8 | } 9 | 10 | initHeaders() { 11 | return [ 12 | { 13 | contentField : 'date', 14 | contentFilter: { 15 | filter : 'date', 16 | pattern: 'dd/MM/yyyy' 17 | }, 18 | contentType : 'text', 19 | label : 'Date', 20 | sortableField: true 21 | }, { 22 | contentField : 'label', 23 | contentFilter: { 24 | filter: 'uppercase' 25 | }, 26 | contentType : 'text', 27 | label : 'Label', 28 | sortableField: true 29 | }, { 30 | contentField : 'amount', 31 | contentType : 'input', 32 | label : 'Amount', 33 | sortableField: true 34 | } 35 | ]; 36 | } 37 | 38 | initContent() { 39 | return [ 40 | { 41 | amount: 10.0, 42 | date : new Date().getMilliseconds(), 43 | label : 'Task 1' 44 | }, { 45 | amount: 20.0, 46 | date : new Date().getMilliseconds(), 47 | label : 'Task 2' 48 | }, { 49 | amount: 90.0, 50 | date : new Date().getMilliseconds(), 51 | label : 'Task 3' 52 | }, { 53 | amount: 60.0, 54 | date : new Date().getMilliseconds(), 55 | label : 'Task 4' 56 | }, { 57 | amount: 70.0, 58 | date : new Date().getMilliseconds(), 59 | label : 'Task 5' 60 | }, { 61 | amount: 30.0, 62 | date : new Date().getMilliseconds(), 63 | label : 'Task 6' 64 | }, { 65 | amount: 50.0, 66 | date : new Date().getMilliseconds(), 67 | label : 'Task 7' 68 | }, { 69 | amount: 80.0, 70 | date : new Date().getMilliseconds(), 71 | label : 'Task 8' 72 | }, { 73 | amount: 5.0, 74 | date : new Date().getMilliseconds(), 75 | label : 'Task 9' 76 | } 77 | ]; 78 | } 79 | } 80 | 81 | export default { 82 | bindings: { text: "@" }, /** Reading an attribute as text **/ 83 | templateUrl: require("./object.html"), 84 | controller: ObjectCtrl 85 | } -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/object/object.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Object Expressions 6 | 7 | 8 | 9 | 10 |
11 | 12 |
13 |

Student Name: {{ student.name }}

14 |

Percentage: {{ student.percent }}

15 |
16 |
17 |
18 |
19 |
20 |
-------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/object/object.module.ts: -------------------------------------------------------------------------------- 1 | import * as angular from 'angular'; 2 | 3 | import { routes } from './object.routes'; 4 | import objectComponent from './object.component'; 5 | import { ObjectService } from './object.service'; 6 | 7 | export default angular.module('object', []) 8 | .config(routes) 9 | .component("object", objectComponent) 10 | .service('objectService', ObjectService) 11 | .name; -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/object/object.routes.ts: -------------------------------------------------------------------------------- 1 | export function routes($urlRouterProvider, $stateProvider) { 2 | $stateProvider.state({ name: 'object', url: '/object', component: 'object' }); 3 | } 4 | routes.$inject = ['$urlRouterProvider', '$stateProvider']; -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/object/object.service.ts: -------------------------------------------------------------------------------- 1 | export class ObjectService { 2 | constructor() { 3 | } 4 | } -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/string/string.component.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as angular from 'angular'; 3 | 4 | class StringCtrl { 5 | 6 | constructor(private $scope: any) { 7 | 8 | } 9 | 10 | getResult() { 11 | this.$scope.result = 'You full name is: ' +this.$scope.user.firstName + ' ' +this.$scope.user.lastName; 12 | } 13 | } 14 | 15 | export default { 16 | bindings: { text: "@" }, /** Reading an attribute as text **/ 17 | templateUrl: require("./string.html"), 18 | controller: StringCtrl 19 | } -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/string/string.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | String Expressions 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Result 23 | 24 | 25 |
26 | {{result}} 27 |
28 |
29 |
30 |
31 |
-------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/string/string.module.ts: -------------------------------------------------------------------------------- 1 | import * as angular from 'angular'; 2 | 3 | import { routes } from './string.routes'; 4 | import stringComponent from './string.component'; 5 | import { StringService } from './string.service'; 6 | 7 | export default angular.module('string', []) 8 | .config(routes) 9 | .component("string", stringComponent) 10 | .service('stringService', StringService) 11 | .name; -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/string/string.routes.ts: -------------------------------------------------------------------------------- 1 | export function routes($urlRouterProvider, $stateProvider) { 2 | $stateProvider.state({ name: 'string', url: '/string', component: 'string' }); 3 | } 4 | routes.$inject = ['$urlRouterProvider', '$stateProvider']; -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/expressions/string/string.service.ts: -------------------------------------------------------------------------------- 1 | export class StringService { 2 | constructor() { 3 | } 4 | } -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | 2 | class HomeCtrl { 3 | static $inject = []; 4 | constructor() { 5 | this.test = "some binding"; 6 | } 7 | 8 | test: string; 9 | 10 | testClick() { 11 | alert("you clicked the button") 12 | } 13 | 14 | folders = [ 15 | { title: "list item 1", icon: "folder", updated: new Date('1/1/16') }, 16 | { title: "list item 2", icon: "folder", updated: new Date('1/1/16') }, 17 | { title: "list item 3", icon: "folder", updated: new Date('1/1/16') }, 18 | ]; 19 | } 20 | 21 | export default { 22 | bindings: {}, 23 | templateUrl: require("./home.html"), 24 | controller: HomeCtrl 25 | } -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/home/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Home Page 6 | 7 | 8 | 9 | 10 | some button 11 | 12 | 13 | 14 | 15 | 16 | Folders 17 | 18 | {{folder.icon}} 19 |
20 |

{{folder.title}}

21 |

{{folder.updated | date}}

22 |
23 |
24 |
25 |
-------------------------------------------------------------------------------- /angularjs-material-seed/src/app/home/home.module.ts: -------------------------------------------------------------------------------- 1 | import * as angular from 'angular'; 2 | 3 | import { routes } from './home.routes'; 4 | 5 | import homeComponent from './home.component'; 6 | import { HomeService } from './home.service'; 7 | 8 | export default angular.module('home', []) 9 | .config(routes) 10 | .component("home", homeComponent) 11 | .service('homeService', HomeService) 12 | .name; -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/home/home.routes.ts: -------------------------------------------------------------------------------- 1 | export function routes($urlRouterProvider, $stateProvider) { 2 | $urlRouterProvider.otherwise('/'); 3 | 4 | $stateProvider.state({ name: 'home', url: '/', component: 'home' }); 5 | } 6 | routes.$inject = ['$urlRouterProvider', '$stateProvider']; -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/home/home.service.ts: -------------------------------------------------------------------------------- 1 | export class HomeService { 2 | constructor() { 3 | } 4 | } -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/main/main.component.ts: -------------------------------------------------------------------------------- 1 | import * as angular from 'angular'; 2 | 3 | class MainCtrl { 4 | 5 | constructor( 6 | private $scope: ng.IScope, 7 | private $mdSidenav: ng.material.ISidenavService, 8 | private $location: ng.ILocationService 9 | ) { 10 | this.$scope.$on('update-theme', (event, args) => { 11 | this.currentTheme = args; 12 | }); 13 | 14 | this.$scope.$on('$viewContentLoaded', () => { 15 | document.getElementById('pages').classList.add('pages-sidenav'); 16 | this.openNav(); 17 | }); 18 | } 19 | $onInit() { 20 | } 21 | 22 | currentTheme = "green"; 23 | menus = [ 24 | { 25 | title: 'Expressions', 26 | icon: 'list', 27 | active: false, 28 | type: 'dropdown', 29 | submenus: [ 30 | { 31 | title: 'Number Expressions', 32 | icon: 'settings_ethernet', 33 | path: 'number' 34 | }, 35 | { 36 | title: 'String Expressions', 37 | icon: 'settings_ethernet', 38 | path: 'string' 39 | }, 40 | { 41 | title: 'Object Expressions', 42 | icon: 'settings_ethernet', 43 | path: 'object' 44 | }, 45 | { 46 | title: 'Array Expressions', 47 | icon: 'settings_ethernet', 48 | path: 'array' 49 | } 50 | ] 51 | }, 52 | { 53 | title: 'Directives', 54 | icon: 'list', 55 | active: false, 56 | type: 'dropdown', 57 | submenus: [ 58 | { 59 | title: 'Directives', 60 | icon: 'settings_ethernet', 61 | path: 'directives' 62 | } 63 | ] 64 | } 65 | ]; 66 | 67 | sideNav() { 68 | document.getElementById('pages').classList.toggle('pages-sidenav'); 69 | } 70 | 71 | toggleNav() { 72 | this.$mdSidenav("left").toggle(); 73 | } 74 | 75 | openNav() { 76 | this.$mdSidenav("left").open(); 77 | } 78 | 79 | closeNav() { 80 | this.$mdSidenav("left").close(); 81 | } 82 | 83 | goTo(link: string) { 84 | this.$mdSidenav("left").open(); 85 | this.$location.path(link); 86 | } 87 | } 88 | 89 | MainCtrl.$inject = ["$scope", "$mdSidenav", "$location", "$mdComponentRegistry", "$log", "$mdMedia", "$timeout"]; 90 | 91 | export default { 92 | bindings: { title: "=" }, 93 | templateUrl: require("./main.html"), 94 | controller: MainCtrl 95 | } -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/main/main.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | 7 |
8 |
9 | 10 | 11 | 12 | 13 | 14 | {{item.icon}} 15 | {{item.title}} 16 | 17 | 18 | 19 | {{subitem.icon}}  20 | {{subitem.title}} 21 | 22 | 23 | 24 | 25 |
26 | 27 |
28 | 29 | 30 |
31 |

{{$ctrl.title}}

32 | 33 | menu 34 | 35 |
36 |
37 | 38 | 39 | 40 | 41 | 42 |
43 |
-------------------------------------------------------------------------------- /angularjs-material-seed/src/app/main/main.module.ts: -------------------------------------------------------------------------------- 1 | import * as angular from 'angular'; 2 | import mainComponent from './main.component'; 3 | 4 | export default angular.module('main', []) 5 | .component("main", mainComponent) 6 | .name; -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/settings/settings.component.ts: -------------------------------------------------------------------------------- 1 | class SettingsCtrl { 2 | static $inject = ['$rootScope']; 3 | constructor(private $rootScope: ng.IRootScopeService) { 4 | } 5 | 6 | theme: string = "green"; 7 | themes: Array = ["blue", "green"]; 8 | 9 | updateTheme() { 10 | this.$rootScope.$broadcast("update-theme", this.theme); 11 | } 12 | } 13 | 14 | export default { 15 | bindings: {}, 16 | templateUrl: require("./settings.html"), 17 | controller: SettingsCtrl 18 | } -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/settings/settings.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Settings Page 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {{theme}} 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/settings/settings.module.ts: -------------------------------------------------------------------------------- 1 | import * as angular from 'angular'; 2 | import settingsComponent from './settings.component'; 3 | import { routes } from './settings.routes'; 4 | 5 | export default angular.module('settings', []) 6 | .config(routes) 7 | .component("settings", settingsComponent) 8 | .name; -------------------------------------------------------------------------------- /angularjs-material-seed/src/app/settings/settings.routes.ts: -------------------------------------------------------------------------------- 1 | export function routes($urlRouterProvider, $stateProvider) { 2 | $stateProvider.state({ name: 'settings', url: '/settings', component: 'settings' }); 3 | } 4 | routes.$inject = ['$urlRouterProvider', '$stateProvider']; -------------------------------------------------------------------------------- /angularjs-material-seed/src/assets/angularjs-material.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/angularjs-material-seed/src/assets/angularjs-material.png -------------------------------------------------------------------------------- /angularjs-material-seed/src/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/angularjs-material-seed/src/assets/favicon.ico -------------------------------------------------------------------------------- /angularjs-material-seed/src/assets/material-icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/angularjs-material-seed/src/assets/material-icons.woff2 -------------------------------------------------------------------------------- /angularjs-material-seed/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AngularJs Webpack Typescript 6 | 7 | 8 | 9 | 10 | 11 |
Loading...
12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /angularjs-material-seed/src/style.scss: -------------------------------------------------------------------------------- 1 | [ng-cloak] { 2 | display: none !important; 3 | } 4 | 5 | @font-face { 6 | font-family: 'Material Icons'; 7 | font-style: normal; 8 | font-weight: 400; 9 | src: url(./assets/material-icons.woff2) format('woff2'); 10 | } 11 | 12 | .material-icons { 13 | font-family: 'Material Icons'; 14 | font-weight: normal; 15 | font-style: normal; 16 | font-size: 24px; 17 | line-height: 1; 18 | letter-spacing: normal; 19 | text-transform: none; 20 | display: inline-block; 21 | white-space: nowrap; 22 | word-wrap: normal; 23 | direction: ltr; 24 | font-feature-settings: 'liga'; 25 | -webkit-font-feature-settings: 'liga'; 26 | -webkit-font-smoothing: antialiased; 27 | } 28 | 29 | [ng-cloak] { 30 | display: none !important; 31 | } 32 | 33 | .splash { 34 | display: none; 35 | } 36 | 37 | [ng-cloak].splash { 38 | display: block !important; 39 | } 40 | 41 | .md-sidenav-left, md-sidenav { 42 | top: 71px; 43 | border-radius: 4px; 44 | } 45 | 46 | md-sidenav { 47 | max-width: 240px; 48 | } 49 | 50 | md-toolbar:not(.md-menu-toolbar) { 51 | box-shadow: 0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12); 52 | } 53 | 54 | md-backdrop.md-opaque { 55 | opacity: 0; 56 | } 57 | 58 | md-toolbar.md-tall { 59 | height: 0px; 60 | min-height: 0px; 61 | max-height: 0px; 62 | } 63 | 64 | .pages-sidenav { 65 | padding-left: 16%; 66 | transition-duration: 0.6s; 67 | -webkit-transition-duration: 0.6s; 68 | } 69 | 70 | .submenus-text { 71 | padding-left: 2px; 72 | font-size: 14px; 73 | } 74 | 75 | md-list-item .md-list-item-inner { 76 | border-bottom: 0.1px solid; 77 | } -------------------------------------------------------------------------------- /angularjs-material-seed/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "sourceMap": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "removeComments": false, 9 | "noImplicitAny": false, 10 | "lib": [ 11 | "es2015", 12 | "dom" 13 | ] 14 | }, 15 | "exclude": [ 16 | "node_modules" 17 | ] 18 | } -------------------------------------------------------------------------------- /angularjs-material-seed/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 4 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 5 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 6 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); 7 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 8 | 9 | var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 10 | 11 | module.exports = (env, argv) => { 12 | 13 | return { 14 | context: path.resolve(__dirname, './src'), 15 | 16 | entry: { 17 | app: './app.ts' 18 | }, 19 | 20 | output: { 21 | filename: '[name].[contenthash].bundle.js', 22 | chunkFilename: '[name].[contenthash].bundle.js', 23 | path: path.resolve(__dirname, 'dist'), 24 | }, 25 | 26 | devtool: 'source-map', 27 | 28 | resolve: { extensions: ['.ts', '.js'] }, 29 | 30 | module: { 31 | rules: [ 32 | { 33 | test: /\.ts?$/, 34 | loader: 'ts-loader', 35 | options: { transpileOnly: true } 36 | }, 37 | { 38 | test: /\.html$/, 39 | exclude: `${path.join(__dirname, "/src/index.html")}`, 40 | use: [ 41 | { loader: 'ngtemplate-loader?relativeTo=' + (path.resolve(__dirname, './src')) }, 42 | { loader: 'html-loader' } 43 | ] 44 | }, 45 | { 46 | test: /\.scss$/, 47 | use: [ 48 | MiniCssExtractPlugin.loader, 49 | "css-loader", 50 | "sass-loader" 51 | ] 52 | }, 53 | { test: /\.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/, loader: 'file-loader?name=assets/[name].[ext]' }, 54 | ] 55 | }, 56 | 57 | plugins: [ 58 | new webpack.ProgressPlugin(), 59 | new CleanWebpackPlugin(), 60 | new HtmlWebpackPlugin({ 61 | template: "./index.html", 62 | filename: "index.html", 63 | chunksSortMode: "manual", 64 | chunks: ['vendors', 'app'], 65 | }), 66 | new MiniCssExtractPlugin({ 67 | filename: "style.[contenthash].css", 68 | chunkFilename: "style.[contenthash].css" 69 | }), 70 | new CopyWebpackPlugin([ 71 | { from: 'assets', to: 'assets' } 72 | ]) 73 | //new BundleAnalyzerPlugin() 74 | ], 75 | 76 | optimization: { 77 | splitChunks: { 78 | cacheGroups: { 79 | commons: { test: /[\\/]node_modules[\\/]/, name: "vendors", chunks: "all" } 80 | } 81 | }, 82 | minimizer: [ 83 | new UglifyJsPlugin({ 84 | uglifyOptions: { 85 | output: { 86 | comments: false 87 | } 88 | } 89 | }) 90 | ] 91 | } 92 | } 93 | }; -------------------------------------------------------------------------------- /assets/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/assets/star.png -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "@angular/upgrade": { 6 | "version": "9.1.3", 7 | "resolved": "https://registry.npmjs.org/@angular/upgrade/-/upgrade-9.1.3.tgz", 8 | "integrity": "sha512-VtnURviY4qZPALI6vz5tJdSuJY5Ltj3P7ZVTZ2XE2wk2oC9piGlNrkF912HFG4uN2uxoxwX2TFSD5wkMIcLTWQ==" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /shopping-cart/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # IDEs and editors 7 | /.idea 8 | .project 9 | .classpath 10 | .c9/ 11 | *.launch 12 | .settings/ 13 | *.sublime-workspace 14 | 15 | # IDE - VSCode 16 | .vscode/* 17 | !.vscode/settings.json 18 | !.vscode/tasks.json 19 | !.vscode/launch.json 20 | !.vscode/extensions.json 21 | -------------------------------------------------------------------------------- /shopping-cart/README.md: -------------------------------------------------------------------------------- 1 | ## Shopping Cart 2 | 3 | 4 | Shopping Cart 5 | 6 | 7 | #### Project Description 8 | 9 | > Shopping application developed on AngularJS, AngularJS Material, NodeJS and MySQL. 10 | 11 | 12 | 13 | #### Installation & Setup 14 | 15 | 1. `Run install` 16 | 2. `node server.js` 17 | 18 | 19 | #### Tools and Technologies 20 | 21 | - Technology: AngularJS, HTML, SCSS, NodeJS 22 | - Middleware: ExpressJS 23 | - Database : MySQL 24 | 25 | 26 | 27 | 28 | #### Resources 29 | 30 | * [AngularJS v1.7x](https://code.angularjs.org/snapshot-stable/docs/tutorial/step_00) 31 | * [AngularJS Material](https://material.angularjs.org/latest/) 32 | * [HammerJS](https://hammerjs.github.io/) 33 | * [Sass](https://sass-lang.com/) 34 | * [Webpack](https://webpack.js.org/) 35 | * [Typescript](https://www.typescriptlang.org/) 36 | 37 | 38 | #### Project Output 39 | 40 | 41 | -------------------------------------------------------------------------------- /shopping-cart/client/assets/Database-Architecture.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * Table Structure 3 | * 4 | **/ 5 | 6 | 7 | ------------------- 8 | Product Table 9 | ------------------- 10 | a. Product Name 11 | b. Product Description 12 | c. Product SKU 13 | d. Product Serial Number 14 | e. Product Purchase Price 15 | f. Product Selling Price 16 | g. Product Quantity 17 | h. Reordered Stock Amount 18 | i. Expiration Date 19 | j. Product Image 20 | 21 | ------------------ 22 | Barcode Table 23 | ------------------ 24 | a. Barcode Type 25 | b. Barcode 26 | 27 | ---------------- 28 | Warehouse 29 | ---------------- 30 | 31 | 32 | 33 | 34 | ---------------- 35 | Category 36 | ---------------- 37 | 38 | 39 | -------------------------------------------------------------------------------- /shopping-cart/client/assets/customers.json: -------------------------------------------------------------------------------- 1 | {"customers":[{"id":"ALFKI","companyName":"Alfreds Futterkiste","contactName":"Maria Anders","contactTitle":"Sales Representative","address":"Obere Str. 57","city":"Berlin","postalCode":"12209","country":"Germany","phone":"030-0074321","fax":"030-0076545"},{"id":"ANATR","companyName":"Ana Trujillo Emparedados y helados","contactName":"Ana Trujillo","contactTitle":"Owner","address":"Avda. de la Constitución 2222","city":"México D.F.","postalCode":"05021","country":"Mexico","phone":"(5) 555-4729","fax":"(5) 555-3745"},{"id":"ANTON","companyName":"Antonio Moreno Taquería","contactName":"Antonio Moreno","contactTitle":"Owner","address":"Mataderos 2312","city":"México D.F.","postalCode":"05023","country":"Mexico","phone":"(5) 555-3932"},{"id":"AROUT","companyName":"Around the Horn","contactName":"Thomas Hardy","contactTitle":"Sales Representative","address":"120 Hanover Sq.","city":"London","postalCode":"WA1 1DP","country":"UK","phone":"(171) 555-7788","fax":"(171) 555-6750"},{"id":"BERGS","companyName":"Berglunds snabbköp","contactName":"Christina Berglund","contactTitle":"Order Administrator","address":"Berguvsvägen 8","city":"Luleå","postalCode":"S-958 22","country":"Sweden","phone":"0921-12 34 65","fax":"0921-12 34 67"},{"id":"BLAUS","companyName":"Blauer See Delikatessen","contactName":"Hanna Moos","contactTitle":"Sales Representative","address":"Forsterstr. 57","city":"Mannheim","postalCode":"68306","country":"Germany","phone":"0621-08460","fax":"0621-08924"},{"id":"BLONP","companyName":"Blondesddsl père et fils","contactName":"Frédérique Citeaux","contactTitle":"Marketing Manager","address":"24, place Kléber","city":"Strasbourg","postalCode":"67000","country":"France","phone":"88.60.15.31","fax":"88.60.15.32"},{"id":"BOLID","companyName":"Bólido Comidas preparadas","contactName":"Martín Sommer","contactTitle":"Owner","address":"C/ Araquil, 67","city":"Madrid","postalCode":"28023","country":"Spain","phone":"(91) 555 22 82","fax":"(91) 555 91 99"},{"id":"BONAP","companyName":"Bon app","contactName":"Laurence Lebihan","contactTitle":"Owner","address":"12, rue des Bouchers","city":"Marseille","postalCode":"13008","country":"France","phone":"91.24.45.40","fax":"91.24.45.41"},{"id":"BOTTM","companyName":"Bottom-Dollar Markets","contactName":"Elizabeth Lincoln","contactTitle":"Accounting Manager","address":"23 Tsawassen Blvd.","city":"Tsawassen","region":"BC","postalCode":"T2F 8M4","country":"Canada","phone":"(604) 555-4729","fax":"(604) 555-3745"},{"id":"BSBEV","companyName":"B's Beverages","contactName":"Victoria Ashworth","contactTitle":"Sales Representative","address":"Fauntleroy Circus","city":"London","postalCode":"EC2 5NT","country":"UK","phone":"(171) 555-1212"},{"id":"CACTU","companyName":"Cactus Comidas para llevar","contactName":"Patricio Simpson","contactTitle":"Sales Agent","address":"Cerrito 333","city":"Buenos Aires","postalCode":"1010","country":"Argentina","phone":"(1) 135-5555","fax":"(1) 135-4892"},{"id":"CENTC","companyName":"Centro comercial Moctezuma","contactName":"Francisco Chang","contactTitle":"Marketing Manager","address":"Sierras de Granada 9993","city":"México D.F.","postalCode":"05022","country":"Mexico","phone":"(5) 555-3392","fax":"(5) 555-7293"},{"id":"CHOPS","companyName":"Chop-suey Chinese","contactName":"Yang Wang","contactTitle":"Owner","address":"Hauptstr. 29","city":"Bern","postalCode":"3012","country":"Switzerland","phone":"0452-076545"},{"id":"COMMI","companyName":"Comércio Mineiro","contactName":"Pedro Afonso","contactTitle":"Sales Associate","address":"Av. dos Lusíadas, 23","city":"Sao Paulo","region":"SP","postalCode":"05432-043","country":"Brazil","phone":"(11) 555-7647"},{"id":"CONSH","companyName":"Consolidated Holdings","contactName":"Elizabeth Brown","contactTitle":"Sales Representative","address":"Berkeley Gardens 12 Brewery","city":"London","postalCode":"WX1 6LT","country":"UK","phone":"(171) 555-2282","fax":"(171) 555-9199"},{"id":"DRACD","companyName":"Drachenblut Delikatessen","contactName":"Sven Ottlieb","contactTitle":"Order Administrator","address":"Walserweg 21","city":"Aachen","postalCode":"52066","country":"Germany","phone":"0241-039123","fax":"0241-059428"},{"id":"DUMON","companyName":"Du monde entier","contactName":"Janine Labrune","contactTitle":"Owner","address":"67, rue des Cinquante Otages","city":"Nantes","postalCode":"44000","country":"France","phone":"40.67.88.88","fax":"40.67.89.89"},{"id":"EASTC","companyName":"Eastern Connection","contactName":"Ann Devon","contactTitle":"Sales Agent","address":"35 King George","city":"London","postalCode":"WX3 6FW","country":"UK","phone":"(171) 555-0297","fax":"(171) 555-3373"},{"id":"ERNSH","companyName":"Ernst Handel","contactName":"Roland Mendel","contactTitle":"Sales Manager","address":"Kirchgasse 6","city":"Graz","postalCode":"8010","country":"Austria","phone":"7675-3425","fax":"7675-3426"},{"id":"FAMIA","companyName":"Familia Arquibaldo","contactName":"Aria Cruz","contactTitle":"Marketing Assistant","address":"Rua Orós, 92","city":"Sao Paulo","region":"SP","postalCode":"05442-030","country":"Brazil","phone":"(11) 555-9857"},{"id":"FISSA","companyName":"FISSA Fabrica Inter. Salchichas S.A.","contactName":"Diego Roel","contactTitle":"Accounting Manager","address":"C/ Moralzarzal, 86","city":"Madrid","postalCode":"28034","country":"Spain","phone":"(91) 555 94 44","fax":"(91) 555 55 93"},{"id":"FOLIG","companyName":"Folies gourmandes","contactName":"Martine Rancé","contactTitle":"Assistant Sales Agent","address":"184, chaussée de Tournai","city":"Lille","postalCode":"59000","country":"France","phone":"20.16.10.16","fax":"20.16.10.17"},{"id":"FOLKO","companyName":"Folk och fä HB","contactName":"Maria Larsson","contactTitle":"Owner","address":"Åkergatan 24","city":"Bräcke","postalCode":"S-844 67","country":"Sweden","phone":"0695-34 67 21"},{"id":"FRANK","companyName":"Frankenversand","contactName":"Peter Franken","contactTitle":"Marketing Manager","address":"Berliner Platz 43","city":"München","postalCode":"80805","country":"Germany","phone":"089-0877310","fax":"089-0877451"},{"id":"FRANR","companyName":"France restauration","contactName":"Carine Schmitt","contactTitle":"Marketing Manager","address":"54, rue Royale","city":"Nantes","postalCode":"44000","country":"France","phone":"40.32.21.21","fax":"40.32.21.20"},{"id":"FRANS","companyName":"Franchi S.p.A.","contactName":"Paolo Accorti","contactTitle":"Sales Representative","address":"Via Monte Bianco 34","city":"Torino","postalCode":"10100","country":"Italy","phone":"011-4988260","fax":"011-4988261"},{"id":"FURIB","companyName":"Furia Bacalhau e Frutos do Mar","contactName":"Lino Rodriguez","contactTitle":"Sales Manager","address":"Jardim das rosas n. 32","city":"Lisboa","postalCode":"1675","country":"Portugal","phone":"(1) 354-2534","fax":"(1) 354-2535"},{"id":"GALED","companyName":"Galería del gastrónomo","contactName":"Eduardo Saavedra","contactTitle":"Marketing Manager","address":"Rambla de Cataluña, 23","city":"Barcelona","postalCode":"08022","country":"Spain","phone":"(93) 203 4560","fax":"(93) 203 4561"},{"id":"GODOS","companyName":"Godos Cocina Típica","contactName":"José Pedro Freyre","contactTitle":"Sales Manager","address":"C/ Romero, 33","city":"Sevilla","postalCode":"41101","country":"Spain","phone":"(95) 555 82 82"},{"id":"GOURL","companyName":"Gourmet Lanchonetes","contactName":"André Fonseca","contactTitle":"Sales Associate","address":"Av. Brasil, 442","city":"Campinas","region":"SP","postalCode":"04876-786","country":"Brazil","phone":"(11) 555-9482"},{"id":"GREAL","companyName":"Great Lakes Food Market","contactName":"Howard Snyder","contactTitle":"Marketing Manager","address":"2732 Baker Blvd.","city":"Eugene","region":"OR","postalCode":"97403","country":"USA","phone":"(503) 555-7555"},{"id":"GROSR","companyName":"GROSELLA-Restaurante","contactName":"Manuel Pereira","contactTitle":"Owner","address":"5ª Ave. Los Palos Grandes","city":"Caracas","region":"DF","postalCode":"1081","country":"Venezuela","phone":"(2) 283-2951","fax":"(2) 283-3397"},{"id":"HANAR","companyName":"Hanari Carnes","contactName":"Mario Pontes","contactTitle":"Accounting Manager","address":"Rua do Paço, 67","city":"Rio de Janeiro","region":"RJ","postalCode":"05454-876","country":"Brazil","phone":"(21) 555-0091","fax":"(21) 555-8765"},{"id":"HILAA","companyName":"HILARION-Abastos","contactName":"Carlos Hernández","contactTitle":"Sales Representative","address":"Carrera 22 con Ave. Carlos Soublette #8-35","city":"San Cristóbal","region":"Táchira","postalCode":"5022","country":"Venezuela","phone":"(5) 555-1340","fax":"(5) 555-1948"},{"id":"HUNGC","companyName":"Hungry Coyote Import Store","contactName":"Yoshi Latimer","contactTitle":"Sales Representative","address":"City Center Plaza 516 Main St.","city":"Elgin","region":"OR","postalCode":"97827","country":"USA","phone":"(503) 555-6874","fax":"(503) 555-2376"},{"id":"HUNGO","companyName":"Hungry Owl All-Night Grocers","contactName":"Patricia McKenna","contactTitle":"Sales Associate","address":"8 Johnstown Road","city":"Cork","region":"Co. Cork","country":"Ireland","phone":"2967 542","fax":"2967 3333"},{"id":"ISLAT","companyName":"Island Trading","contactName":"Helen Bennett","contactTitle":"Marketing Manager","address":"Garden House Crowther Way","city":"Cowes","region":"Isle of Wight","postalCode":"PO31 7PJ","country":"UK","phone":"(198) 555-8888"},{"id":"KOENE","companyName":"Königlich Essen","contactName":"Philip Cramer","contactTitle":"Sales Associate","address":"Maubelstr. 90","city":"Brandenburg","postalCode":"14776","country":"Germany","phone":"0555-09876"},{"id":"LACOR","companyName":"La corne d'abondance","contactName":"Daniel Tonini","contactTitle":"Sales Representative","address":"67, avenue de l'Europe","city":"Versailles","postalCode":"78000","country":"France","phone":"30.59.84.10","fax":"30.59.85.11"},{"id":"LAMAI","companyName":"La maison d'Asie","contactName":"Annette Roulet","contactTitle":"Sales Manager","address":"1 rue Alsace-Lorraine","city":"Toulouse","postalCode":"31000","country":"France","phone":"61.77.61.10","fax":"61.77.61.11"},{"id":"LAUGB","companyName":"Laughing Bacchus Wine Cellars","contactName":"Yoshi Tannamuri","contactTitle":"Marketing Assistant","address":"1900 Oak St.","city":"Vancouver","region":"BC","postalCode":"V3F 2K1","country":"Canada","phone":"(604) 555-3392","fax":"(604) 555-7293"},{"id":"LAZYK","companyName":"Lazy K Kountry Store","contactName":"John Steel","contactTitle":"Marketing Manager","address":"12 Orchestra Terrace","city":"Walla Walla","region":"WA","postalCode":"99362","country":"USA","phone":"(509) 555-7969","fax":"(509) 555-6221"},{"id":"LEHMS","companyName":"Lehmanns Marktstand","contactName":"Renate Messner","contactTitle":"Sales Representative","address":"Magazinweg 7","city":"Frankfurt a.M.","postalCode":"60528","country":"Germany","phone":"069-0245984","fax":"069-0245874"},{"id":"LETSS","companyName":"Let's Stop N Shop","contactName":"Jaime Yorres","contactTitle":"Owner","address":"87 Polk St. Suite 5","city":"San Francisco","region":"CA","postalCode":"94117","country":"USA","phone":"(415) 555-5938"},{"id":"LILAS","companyName":"LILA-Supermercado","contactName":"Carlos González","contactTitle":"Accounting Manager","address":"Carrera 52 con Ave. Bolívar #65-98 Llano Largo","city":"Barquisimeto","region":"Lara","postalCode":"3508","country":"Venezuela","phone":"(9) 331-6954","fax":"(9) 331-7256"},{"id":"LINOD","companyName":"LINO-Delicateses","contactName":"Felipe Izquierdo","contactTitle":"Owner","address":"Ave. 5 de Mayo Porlamar","city":"I. de Margarita","region":"Nueva Esparta","postalCode":"4980","country":"Venezuela","phone":"(8) 34-56-12","fax":"(8) 34-93-93"},{"id":"LONEP","companyName":"Lonesome Pine Restaurant","contactName":"Fran Wilson","contactTitle":"Sales Manager","address":"89 Chiaroscuro Rd.","city":"Portland","region":"OR","postalCode":"97219","country":"USA","phone":"(503) 555-9573","fax":"(503) 555-9646"},{"id":"MAGAA","companyName":"Magazzini Alimentari Riuniti","contactName":"Giovanni Rovelli","contactTitle":"Marketing Manager","address":"Via Ludovico il Moro 22","city":"Bergamo","postalCode":"24100","country":"Italy","phone":"035-640230","fax":"035-640231"},{"id":"MAISD","companyName":"Maison Dewey","contactName":"Catherine Dewey","contactTitle":"Sales Agent","address":"Rue Joseph-Bens 532","city":"Bruxelles","postalCode":"B-1180","country":"Belgium","phone":"(02) 201 24 67","fax":"(02) 201 24 68"},{"id":"MEREP","companyName":"Mère Paillarde","contactName":"Jean Fresnière","contactTitle":"Marketing Assistant","address":"43 rue St. Laurent","city":"Montréal","region":"Québec","postalCode":"H1J 1C3","country":"Canada","phone":"(514) 555-8054","fax":"(514) 555-8055"},{"id":"MORGK","companyName":"Morgenstern Gesundkost","contactName":"Alexander Feuer","contactTitle":"Marketing Assistant","address":"Heerstr. 22","city":"Leipzig","postalCode":"04179","country":"Germany","phone":"0342-023176"},{"id":"NORTS","companyName":"North/South","contactName":"Simon Crowther","contactTitle":"Sales Associate","address":"South House 300 Queensbridge","city":"London","postalCode":"SW7 1RZ","country":"UK","phone":"(171) 555-7733","fax":"(171) 555-2530"},{"id":"OCEAN","companyName":"Océano Atlántico Ltda.","contactName":"Yvonne Moncada","contactTitle":"Sales Agent","address":"Ing. Gustavo Moncada 8585 Piso 20-A","city":"Buenos Aires","postalCode":"1010","country":"Argentina","phone":"(1) 135-5333","fax":"(1) 135-5535"},{"id":"OLDWO","companyName":"Old World Delicatessen","contactName":"Rene Phillips","contactTitle":"Sales Representative","address":"2743 Bering St.","city":"Anchorage","region":"AK","postalCode":"99508","country":"USA","phone":"(907) 555-7584","fax":"(907) 555-2880"},{"id":"OTTIK","companyName":"Ottilies Käseladen","contactName":"Henriette Pfalzheim","contactTitle":"Owner","address":"Mehrheimerstr. 369","city":"Köln","postalCode":"50739","country":"Germany","phone":"0221-0644327","fax":"0221-0765721"},{"id":"PARIS","companyName":"Paris spécialités","contactName":"Marie Bertrand","contactTitle":"Owner","address":"265, boulevard Charonne","city":"Paris","postalCode":"75012","country":"France","phone":"(1) 42.34.22.66","fax":"(1) 42.34.22.77"},{"id":"PERIC","companyName":"Pericles Comidas clásicas","contactName":"Guillermo Fernández","contactTitle":"Sales Representative","address":"Calle Dr. Jorge Cash 321","city":"México D.F.","postalCode":"05033","country":"Mexico","phone":"(5) 552-3745","fax":"(5) 545-3745"},{"id":"PICCO","companyName":"Piccolo und mehr","contactName":"Georg Pipps","contactTitle":"Sales Manager","address":"Geislweg 14","city":"Salzburg","postalCode":"5020","country":"Austria","phone":"6562-9722","fax":"6562-9723"},{"id":"PRINI","companyName":"Princesa Isabel Vinhos","contactName":"Isabel de Castro","contactTitle":"Sales Representative","address":"Estrada da saúde n. 58","city":"Lisboa","postalCode":"1756","country":"Portugal","phone":"(1) 356-5634"},{"id":"QUEDE","companyName":"Que Delícia","contactName":"Bernardo Batista","contactTitle":"Accounting Manager","address":"Rua da Panificadora, 12","city":"Rio de Janeiro","region":"RJ","postalCode":"02389-673","country":"Brazil","phone":"(21) 555-4252","fax":"(21) 555-4545"},{"id":"QUEEN","companyName":"Queen Cozinha","contactName":"Lúcia Carvalho","contactTitle":"Marketing Assistant","address":"Alameda dos Canàrios, 891","city":"Sao Paulo","region":"SP","postalCode":"05487-020","country":"Brazil","phone":"(11) 555-1189"},{"id":"QUICK","companyName":"QUICK-Stop","contactName":"Horst Kloss","contactTitle":"Accounting Manager","address":"Taucherstraße 10","city":"Cunewalde","postalCode":"01307","country":"Germany","phone":"0372-035188"},{"id":"RANCH","companyName":"Rancho grande","contactName":"Sergio Gutiérrez","contactTitle":"Sales Representative","address":"Av. del Libertador 900","city":"Buenos Aires","postalCode":"1010","country":"Argentina","phone":"(1) 123-5555","fax":"(1) 123-5556"},{"id":"RATTC","companyName":"Rattlesnake Canyon Grocery","contactName":"Paula Wilson","contactTitle":"Assistant Sales Representative","address":"2817 Milton Dr.","city":"Albuquerque","region":"NM","postalCode":"87110","country":"USA","phone":"(505) 555-5939","fax":"(505) 555-3620"},{"id":"REGGC","companyName":"Reggiani Caseifici","contactName":"Maurizio Moroni","contactTitle":"Sales Associate","address":"Strada Provinciale 124","city":"Reggio Emilia","postalCode":"42100","country":"Italy","phone":"0522-556721","fax":"0522-556722"},{"id":"RICAR","companyName":"Ricardo Adocicados","contactName":"Janete Limeira","contactTitle":"Assistant Sales Agent","address":"Av. Copacabana, 267","city":"Rio de Janeiro","region":"RJ","postalCode":"02389-890","country":"Brazil","phone":"(21) 555-3412"},{"id":"RICSU","companyName":"Richter Supermarkt","contactName":"Michael Holz","contactTitle":"Sales Manager","address":"Grenzacherweg 237","city":"Genève","postalCode":"1203","country":"Switzerland","phone":"0897-034214"},{"id":"ROMEY","companyName":"Romero y tomillo","contactName":"Alejandra Camino","contactTitle":"Accounting Manager","address":"Gran Vía, 1","city":"Madrid","postalCode":"28001","country":"Spain","phone":"(91) 745 6200","fax":"(91) 745 6210"},{"id":"SANTG","companyName":"Santé Gourmet","contactName":"Jonas Bergulfsen","contactTitle":"Owner","address":"Erling Skakkes gate 78","city":"Stavern","postalCode":"4110","country":"Norway","phone":"07-98 92 35","fax":"07-98 92 47"},{"id":"SAVEA","companyName":"Save-a-lot Markets","contactName":"Jose Pavarotti","contactTitle":"Sales Representative","address":"187 Suffolk Ln.","city":"Boise","region":"ID","postalCode":"83720","country":"USA","phone":"(208) 555-8097"},{"id":"SEVES","companyName":"Seven Seas Imports","contactName":"Hari Kumar","contactTitle":"Sales Manager","address":"90 Wadhurst Rd.","city":"London","postalCode":"OX15 4NB","country":"UK","phone":"(171) 555-1717","fax":"(171) 555-5646"},{"id":"SIMOB","companyName":"Simons bistro","contactName":"Jytte Petersen","contactTitle":"Owner","address":"Vinbæltet 34","city":"Kobenhavn","postalCode":"1734","country":"Denmark","phone":"31 12 34 56","fax":"31 13 35 57"},{"id":"SPECD","companyName":"Spécialités du monde","contactName":"Dominique Perrier","contactTitle":"Marketing Manager","address":"25, rue Lauriston","city":"Paris","postalCode":"75016","country":"France","phone":"(1) 47.55.60.10","fax":"(1) 47.55.60.20"},{"id":"SPLIR","companyName":"Split Rail Beer & Ale","contactName":"Art Braunschweiger","contactTitle":"Sales Manager","address":"P.O. Box 555","city":"Lander","region":"WY","postalCode":"82520","country":"USA","phone":"(307) 555-4680","fax":"(307) 555-6525"},{"id":"SUPRD","companyName":"Suprêmes délices","contactName":"Pascale Cartrain","contactTitle":"Accounting Manager","address":"Boulevard Tirou, 255","city":"Charleroi","postalCode":"B-6000","country":"Belgium","phone":"(071) 23 67 22 20","fax":"(071) 23 67 22 21"},{"id":"THEBI","companyName":"The Big Cheese","contactName":"Liz Nixon","contactTitle":"Marketing Manager","address":"89 Jefferson Way Suite 2","city":"Portland","region":"OR","postalCode":"97201","country":"USA","phone":"(503) 555-3612"},{"id":"THECR","companyName":"The Cracker Box","contactName":"Liu Wong","contactTitle":"Marketing Assistant","address":"55 Grizzly Peak Rd.","city":"Butte","region":"MT","postalCode":"59801","country":"USA","phone":"(406) 555-5834","fax":"(406) 555-8083"},{"id":"TOMSP","companyName":"Toms Spezialitäten","contactName":"Karin Josephs","contactTitle":"Marketing Manager","address":"Luisenstr. 48","city":"Münster","postalCode":"44087","country":"Germany","phone":"0251-031259","fax":"0251-035695"},{"id":"TORTU","companyName":"Tortuga Restaurante","contactName":"Miguel Angel Paolino","contactTitle":"Owner","address":"Avda. Azteca 123","city":"México D.F.","postalCode":"05033","country":"Mexico","phone":"(5) 555-2933"},{"id":"TRADH","companyName":"Tradição Hipermercados","contactName":"Anabela Domingues","contactTitle":"Sales Representative","address":"Av. Inês de Castro, 414","city":"Sao Paulo","region":"SP","postalCode":"05634-030","country":"Brazil","phone":"(11) 555-2167","fax":"(11) 555-2168"},{"id":"TRAIH","companyName":"Trail's Head Gourmet Provisioners","contactName":"Helvetius Nagy","contactTitle":"Sales Associate","address":"722 DaVinci Blvd.","city":"Kirkland","region":"WA","postalCode":"98034","country":"USA","phone":"(206) 555-8257","fax":"(206) 555-2174"},{"id":"VAFFE","companyName":"Vaffeljernet","contactName":"Palle Ibsen","contactTitle":"Sales Manager","address":"Smagsloget 45","city":"Århus","postalCode":"8200","country":"Denmark","phone":"86 21 32 43","fax":"86 22 33 44"},{"id":"VICTE","companyName":"Victuailles en stock","contactName":"Mary Saveley","contactTitle":"Sales Agent","address":"2, rue du Commerce","city":"Lyon","postalCode":"69004","country":"France","phone":"78.32.54.86","fax":"78.32.54.87"},{"id":"VINET","companyName":"Vins et alcools Chevalier","contactName":"Paul Henriot","contactTitle":"Accounting Manager","address":"59 rue de l'Abbaye","city":"Reims","postalCode":"51100","country":"France","phone":"26.47.15.10","fax":"26.47.15.11"},{"id":"WANDK","companyName":"Die Wandernde Kuh","contactName":"Rita Müller","contactTitle":"Sales Representative","address":"Adenauerallee 900","city":"Stuttgart","postalCode":"70563","country":"Germany","phone":"0711-020361","fax":"0711-035428"},{"id":"WARTH","companyName":"Wartian Herkku","contactName":"Pirkko Koskitalo","contactTitle":"Accounting Manager","address":"Torikatu 38","city":"Oulu","postalCode":"90110","country":"Finland","phone":"981-443655","fax":"981-443655"},{"id":"WELLI","companyName":"Wellington Importadora","contactName":"Paula Parente","contactTitle":"Sales Manager","address":"Rua do Mercado, 12","city":"Resende","region":"SP","postalCode":"08737-363","country":"Brazil","phone":"(14) 555-8122"},{"id":"WHITC","companyName":"White Clover Markets","contactName":"Karl Jablonski","contactTitle":"Owner","address":"305 - 14th Ave. S. Suite 3B","city":"Seattle","region":"WA","postalCode":"98128","country":"USA","phone":"(206) 555-4112","fax":"(206) 555-4115"},{"id":"WILMK","companyName":"Wilman Kala","contactName":"Matti Karttunen","contactTitle":"Owner/Marketing Assistant","address":"Keskuskatu 45","city":"Helsinki","postalCode":"21240","country":"Finland","phone":"90-224 8858","fax":"90-224 8858"},{"id":"WOLZA","companyName":"Wolski Zajazd","contactName":"Zbyszek Piestrzeniewicz","contactTitle":"Owner","address":"ul. Filtrowa 68","city":"Warszawa","postalCode":"01-012","country":"Poland","phone":"(26) 642-7012","fax":"(26) 642-7012"}],"responseStatus":{}} -------------------------------------------------------------------------------- /shopping-cart/client/assets/desserts.json: -------------------------------------------------------------------------------- 1 | { 2 | "count": 9, 3 | "data": [ 4 | { 5 | "name": "Frozen yogurt", 6 | "type": "Ice cream", 7 | "calories": { "value": 159.0 }, 8 | "fat": { "value": 6.0 }, 9 | "carbs": { "value": 24.0 }, 10 | "protein": { "value": 4.0 }, 11 | "sodium": { "value": 87.0 }, 12 | "calcium": { "value": 14.0 }, 13 | "iron": { "value": 1.0 }, 14 | "comment": "Not as good as the real thing." 15 | }, { 16 | "name": "Ice cream sandwich", 17 | "type": "Ice cream", 18 | "calories": { "value": 237.0 }, 19 | "fat": { "value": 9.0 }, 20 | "carbs": { "value": 37.0 }, 21 | "protein": { "value": 4.3 }, 22 | "sodium": { "value": 129.0 }, 23 | "calcium": { "value": 8.0 }, 24 | "iron": { "value": 1.0 } 25 | }, { 26 | "name": "Eclair", 27 | "type": "Pastry", 28 | "calories": { "value": 262.0 }, 29 | "fat": { "value": 16.0 }, 30 | "carbs": { "value": 24.0 }, 31 | "protein": { "value": 6.0 }, 32 | "sodium": { "value": 337.0 }, 33 | "calcium": { "value": 6.0 }, 34 | "iron": { "value": 7.0 } 35 | }, { 36 | "name": "Cupcake", 37 | "type": "Pastry", 38 | "calories": { "value": 305.0 }, 39 | "fat": { "value": 3.7 }, 40 | "carbs": { "value": 67.0 }, 41 | "protein": { "value": 4.3 }, 42 | "sodium": { "value": 413.0 }, 43 | "calcium": { "value": 3.0 }, 44 | "iron": { "value": 8.0 } 45 | }, { 46 | "name": "Jelly bean", 47 | "type": "Candy", 48 | "calories": { "value": 375.0 }, 49 | "fat": { "value": 0.0 }, 50 | "carbs": { "value": 94.0 }, 51 | "protein": { "value": 0.0 }, 52 | "sodium": { "value": 50.0 }, 53 | "calcium": { "value": 0.0 }, 54 | "iron": { "value": 0.0 } 55 | }, { 56 | "name": "Lollipop", 57 | "type": "Candy", 58 | "calories": { "value": 392.0 }, 59 | "fat": { "value": 0.2 }, 60 | "carbs": { "value": 98.0 }, 61 | "protein": { "value": 0.0 }, 62 | "sodium": { "value": 38.0 }, 63 | "calcium": { "value": 0.0 }, 64 | "iron": { "value": 2.0 } 65 | }, { 66 | "name": "Honeycomb", 67 | "type": "Other", 68 | "calories": { "value": 408.0 }, 69 | "fat": { "value": 3.2 }, 70 | "carbs": { "value": 87.0 }, 71 | "protein": { "value": 6.5 }, 72 | "sodium": { "value": 562.0 }, 73 | "calcium": { "value": 0.0 }, 74 | "iron": { "value": 45.0 } 75 | }, { 76 | "name": "Donut", 77 | "type": "Pastry", 78 | "calories": { "value": 452.0 }, 79 | "fat": { "value": 25.0 }, 80 | "carbs": { "value": 51.0 }, 81 | "protein": { "value": 4.9 }, 82 | "sodium": { "value": 326.0 }, 83 | "calcium": { "value": 2.0 }, 84 | "iron": { "value": 22.0 } 85 | }, { 86 | "name": "KitKat", 87 | "type": "Candy", 88 | "calories": { "value": 518.0 }, 89 | "fat": { "value": 26.0 }, 90 | "carbs": { "value": 65.0 }, 91 | "protein": { "value": 7.0 }, 92 | "sodium": { "value": 54.0 }, 93 | "calcium": { "value": 12.0 }, 94 | "iron": { "value": 6.0 } 95 | } 96 | ] 97 | } -------------------------------------------------------------------------------- /shopping-cart/client/assets/shopping-cart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/shopping-cart/client/assets/shopping-cart.png -------------------------------------------------------------------------------- /shopping-cart/client/css/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/shopping-cart/client/css/favicon.ico -------------------------------------------------------------------------------- /shopping-cart/client/css/material-icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/shopping-cart/client/css/material-icons.woff2 -------------------------------------------------------------------------------- /shopping-cart/client/css/style.css: -------------------------------------------------------------------------------- 1 | [ng-cloak] { 2 | display: none !important; 3 | } 4 | 5 | @font-face { 6 | font-family: 'Material Icons'; 7 | font-style: normal; 8 | font-weight: 400; 9 | src: url(./material-icons.woff2) format('woff2'); 10 | } 11 | 12 | .material-icons { 13 | font-family: 'Material Icons'; 14 | font-weight: normal; 15 | font-style: normal; 16 | font-size: 24px; 17 | line-height: 1; 18 | letter-spacing: normal; 19 | text-transform: none; 20 | display: inline-block; 21 | white-space: nowrap; 22 | word-wrap: normal; 23 | direction: ltr; 24 | font-feature-settings: 'liga'; 25 | -webkit-font-feature-settings: 'liga'; 26 | -webkit-font-smoothing: antialiased; 27 | } 28 | 29 | [ng-cloak] { 30 | display: none !important; 31 | } 32 | 33 | .splash { 34 | display: none; 35 | } 36 | 37 | [ng-cloak].splash { 38 | display: block !important; 39 | } 40 | 41 | .md-sidenav-left, md-sidenav { 42 | top: 71px; 43 | border-radius: 4px; 44 | } 45 | 46 | md-sidenav { 47 | max-width: 240px; 48 | } 49 | 50 | md-toolbar:not(.md-menu-toolbar) { 51 | box-shadow: 0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12); 52 | } 53 | 54 | md-backdrop.md-opaque { 55 | opacity: 0; 56 | } 57 | 58 | md-toolbar.md-tall { 59 | height: 0px; 60 | min-height: 0px; 61 | max-height: 0px; 62 | } 63 | 64 | .pages-sidenav { 65 | height: 100%; 66 | padding-left: 16%; 67 | transition-duration: 0.6s; 68 | -webkit-transition-duration: 0.6s; 69 | } 70 | 71 | .submenus-text { 72 | padding-left: 2px; 73 | font-size: 14px; 74 | } 75 | 76 | md-list-item .md-list-item-inner { 77 | border-bottom: 0.2px solid; 78 | } 79 | 80 | #main { 81 | box-shadow: 0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12); 82 | } 83 | 84 | .home-title { 85 | padding-left: 30px; 86 | } 87 | /**** Accordion Style ***********/ 88 | 89 | .md-subheader .md-subheader-inner { 90 | padding: 10px !important; 91 | cursor: pointer; 92 | } 93 | .md-accordion { 94 | padding: 2px; 95 | } 96 | md-list-item { 97 | color: rgba(0,0,0,0.54); 98 | } 99 | .md-accordion .expandCollapse { 100 | width:30px; 101 | height:30px; 102 | position:relative; 103 | font-size:16px; 104 | font-weight:bold; 105 | cursor:pointer; 106 | color:#9999; 107 | display:block; 108 | margin-top: -2px; 109 | margin-left: -2px; 110 | overflow: hidden; 111 | float: right; 112 | } 113 | .md-accordion .expandCollapse:active { 114 | border:0px; 115 | } 116 | .md-accordion .expandCollapse:before, .md-accordion .expandCollapse:after { 117 | width:30px; 118 | height:30px; 119 | display:block; 120 | position:absolute; 121 | top:0; left:0; 122 | line-height:32px; 123 | text-align:center; 124 | -webkit-transition: .3s all ease-out; 125 | transition: .3s all ease-out; 126 | } 127 | .md-accordion .expandCollapse:before { 128 | opacity:1; 129 | -webkit-transform: rotate(0deg); 130 | transform: rotate(0deg); 131 | content: "|"; 132 | margin-top:-3px; 133 | } 134 | .md-accordion .expandCollapse:after { 135 | opacity:1; 136 | -webkit-transform: rotate(-90deg); 137 | transform: rotate(-90deg); 138 | content: "|"; 139 | margin-left:-3px; 140 | } 141 | .md-accordion .active:before { 142 | opacity:1; 143 | -webkit-transform: rotate(90deg); 144 | transform: rotate(90deg); 145 | margin-left:3px; 146 | margin-top:0px; 147 | } 148 | 149 | .md-accordion .dataContent { 150 | background: #F2F2F2; 151 | height: 0px; 152 | overflow: hidden; 153 | transition: .3s all ease-out; 154 | -webkit-transition: .3s all ease-out; 155 | } 156 | 157 | .md-accordion .activeContent { 158 | height: auto; 159 | padding-top: 0px; 160 | display: block; 161 | transition: .3s all ease-out; 162 | } 163 | 164 | .md-accordion md-toolbar{ 165 | cursor:pointer; 166 | border-bottom: 1px solid rgb(63,107,181) 167 | } 168 | md-list-item._md-button-wrap>div.md-button:first-child { 169 | padding: 0 10px; 170 | } 171 | 172 | .product-continer { 173 | padding: 6px 2px 0 0; 174 | border-radius: 4px; 175 | margin-bottom: 100px; 176 | } 177 | .product-add { 178 | height: auto; 179 | border: 1px solid rgba(0,0,0,0.07); 180 | transition: .3s all ease-out; 181 | } 182 | .ng-hide { 183 | height: 0; 184 | } 185 | /** Add Product **/ 186 | .inputdemoErrors .inputErrorsApp { 187 | min-height: 48px; } 188 | 189 | .inputdemoErrors md-input-container > p { 190 | font-size: 0.8em; 191 | text-align: left; 192 | width: 100%; 193 | } 194 | #input-file-id { 195 | opacity: 1; 196 | width: 200px; 197 | height: 200px; 198 | border: 1px solid rgba(0,0,0,.14); 199 | background-color: rgba(0,0,0,.02); 200 | 201 | } 202 | 203 | #input-file-id:before { 204 | content: ''; 205 | } 206 | 207 | .custom-file-input::-webkit-file-upload-button { 208 | visibility: hidden; 209 | } 210 | .custom-file-input::before { 211 | content: 'Browse'; 212 | background: linear-gradient(top, #f9f9f9, #e3e3e3); 213 | border: 1px solid #999; 214 | border-radius: 3px; 215 | padding: 8px 26px 5px 26px; 216 | outline: none; 217 | white-space: nowrap; 218 | -webkit-user-select: none; 219 | cursor: pointer; 220 | text-shadow: 1px 1px #fff; 221 | font-size: 14px; 222 | color: #999; 223 | } 224 | .custom-file-input:hover::before { 225 | border-color: #999; 226 | } 227 | .custom-file-input:active::before { 228 | background: -webkit-linear-gradient(top, #e3e3e3, #f9f9f9); 229 | } 230 | 231 | .md-block { 232 | margin: 12px; 233 | } 234 | -------------------------------------------------------------------------------- /shopping-cart/client/js/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const app = angular.module('app', ['ngRoute', 'ngAnimate', 'ngAria', 'md.data.table', 'ngMaterial']); 4 | 5 | /* 6 | * Theme Settings 7 | */ 8 | app.config(['$mdThemingProvider', function ($mdThemingProvider) { 9 | $mdThemingProvider.theme("blue") 10 | .primaryPalette("blue") 11 | .accentPalette("red"); 12 | 13 | $mdThemingProvider.theme("green") 14 | .primaryPalette("teal") 15 | .accentPalette("red"); 16 | 17 | $mdThemingProvider.theme("altTheme") 18 | .primaryPalette("purple") 19 | .accentPalette("green"); 20 | 21 | $mdThemingProvider.alwaysWatchTheme(true); 22 | }]); 23 | 24 | /* 25 | * configuring our routes for the app 26 | */ 27 | app.config(function ($routeProvider, $locationProvider) { 28 | $routeProvider 29 | // route for the home page 30 | 31 | .when('/home', { 32 | templateUrl: '/views/pages/home.html', 33 | controller: 'homeController' 34 | }) 35 | .when('/products', { 36 | templateUrl: '/views/pages/products.html', 37 | controller: 'productsController' 38 | }) 39 | .otherwise({ 40 | redirectTo: '/home' 41 | }); 42 | 43 | // use the HTML5 History API 44 | $locationProvider.html5Mode(true); 45 | }); 46 | 47 | app.config( 48 | function($mdIconProvider, $$mdSvgRegistry) { 49 | // Add default icons from angular material 50 | $mdIconProvider 51 | .icon('md-close', $$mdSvgRegistry.mdClose) 52 | .icon('md-menu', $$mdSvgRegistry.mdMenu) 53 | .icon('md-toggle-arrow', $$mdSvgRegistry.mdToggleArrow) ; 54 | } 55 | ); 56 | 57 | app.factory('appService', ($http) => { 58 | return new AppService($http) 59 | }); 60 | -------------------------------------------------------------------------------- /shopping-cart/client/js/app.service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | class AppService{ 4 | constructor($http){ 5 | this.$http = $http; 6 | this.socket = null; 7 | } 8 | httpCall(httpData){ 9 | if (httpData.url === undefined || httpData.url === null || httpData.url === ''){ 10 | alert(`Invalid HTTP call`); 11 | } 12 | const HTTP = this.$http; 13 | const params = httpData.params; 14 | return new Promise( (resolve, reject) => { 15 | HTTP.post(httpData.url, params).then( (response) => { 16 | resolve(response.data); 17 | }).catch( (response, status, header, config) => { 18 | reject(response.data); 19 | }); 20 | }); 21 | } 22 | connectSocketServer(userId){ 23 | const socket = io.connect( { query: `userId=${userId}` }); 24 | this.socket = socket; 25 | } 26 | 27 | socketEmit(eventName, params){ 28 | this.socket.emit(eventName, params); 29 | } 30 | 31 | socketOn(eventName, callback) { 32 | this.socket.on(eventName, (response) => { 33 | if (callback) { 34 | callback(response); 35 | } 36 | }); 37 | } 38 | 39 | getMessages(userId, friendId) { 40 | return new Promise((resolve, reject) => { 41 | this.httpCall({ 42 | url: '/getMessages', 43 | params: { 44 | 'userId': userId, 45 | 'toUserId': friendId 46 | } 47 | }).then((response) => { 48 | resolve(response); 49 | }).catch((error) => { 50 | reject(error); 51 | }); 52 | }); 53 | } 54 | 55 | scrollToBottom(){ 56 | const messageThread = document.querySelector('.message-thread'); 57 | setTimeout(() => { 58 | messageThread.scrollTop = messageThread.scrollHeight + 500; 59 | }, 10); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /shopping-cart/client/js/home.controller.js: -------------------------------------------------------------------------------- 1 | 'user strict'; 2 | 3 | app.controller('homeController', function ($scope, $routeParams, $location, appService, $mdSidenav){ 4 | 5 | console.log('HomeController'); 6 | }); -------------------------------------------------------------------------------- /shopping-cart/client/js/menu.controller.js: -------------------------------------------------------------------------------- 1 | 'user strict'; 2 | 3 | app.controller('menuController', function ($scope, $routeParams, $location, $mdSidenav){ 4 | 5 | console.log('menuController'); 6 | $scope.project_name = 'Shopping Cart'; 7 | $scope.currentTheme = "green"; 8 | 9 | $scope.$on('$viewContentLoaded', () => { 10 | document.getElementById('pages').classList.add('pages-sidenav'); 11 | $scope.openNav(); 12 | }); 13 | 14 | /** Sidebar Menu **/ 15 | $scope.menus = [ 16 | { 17 | title: 'Dashboard', 18 | icon: 'dashboard', 19 | active: false, 20 | path: 'dashboard' 21 | }, 22 | { 23 | title: 'Products', 24 | icon: 'pages', 25 | active: false, 26 | type: 'dropdown', 27 | submenus: [ 28 | { 29 | title: 'Products', 30 | icon: 'radio_button_checked', 31 | path: 'products' 32 | }, 33 | { 34 | title: 'Out Of Stock', 35 | icon: 'radio_button_checked', 36 | path: 'out-of-stock' 37 | }, 38 | { 39 | title: 'Expired Products', 40 | icon: 'radio_button_checked', 41 | path: 'expired-products' 42 | }, 43 | { 44 | title: 'Products Tax', 45 | icon: 'radio_button_checked', 46 | path: 'products-tax' 47 | }, 48 | { 49 | title: 'Products Categories', 50 | icon: 'radio_button_checked', 51 | path: 'products-categories' 52 | } 53 | ] 54 | }, 55 | { 56 | title: 'Warehouses', 57 | icon: 'store', 58 | active: false, 59 | path: 'warehouses' 60 | }, 61 | { 62 | title: 'Suppliers', 63 | icon: 'people_outline', 64 | active: false, 65 | path: 'suppliers' 66 | }, 67 | { 68 | title: 'Purchases', 69 | icon: 'shopping_cart', 70 | active: false, 71 | type: 'dropdown', 72 | submenus: [ 73 | { 74 | title: 'New Purchases', 75 | icon: 'radio_button_checked', 76 | path: 'new-purchases' 77 | }, 78 | { 79 | title: 'Purchase List', 80 | icon: 'radio_button_checked', 81 | path: 'purchase-list' 82 | } 83 | ] 84 | }, 85 | { 86 | title: 'Customers', 87 | icon: 'people', 88 | active: false, 89 | path: 'customers' 90 | }, 91 | { 92 | title: 'Companies', 93 | icon: 'shop', 94 | active: false, 95 | path: 'companies' 96 | }, 97 | { 98 | title: 'Sales Order', 99 | icon: 'add_shopping_cart', 100 | active: false, 101 | type: 'dropdown', 102 | submenus: [ 103 | { 104 | title: 'Manage Orders', 105 | icon: 'radio_button_checked', 106 | path: 'manage-orders' 107 | }, 108 | { 109 | title: 'Add New Order', 110 | icon: 'radio_button_checked', 111 | path: 'add-new-order' 112 | }, 113 | { 114 | title: 'Order Quotes', 115 | icon: 'radio_button_checked', 116 | path: 'order-quotes' 117 | }, 118 | { 119 | title: 'Add Order Quote', 120 | icon: 'radio_button_checked', 121 | path: 'add-order-quote' 122 | } 123 | ] 124 | }, 125 | { 126 | title: 'Calendar', 127 | icon: 'calendar_today', 128 | active: false, 129 | path: 'calendar' 130 | }, 131 | { 132 | title: 'Expenditure', 133 | icon: 'attach_money', 134 | active: false, 135 | path: 'expenditure' 136 | }, 137 | { 138 | title: 'Reports', 139 | icon: 'bar_chart', 140 | active: false, 141 | type: 'dropdown', 142 | submenus: [ 143 | { 144 | title: 'Today Reports', 145 | icon: 'radio_button_checked', 146 | path: 'today-reports' 147 | }, 148 | { 149 | title: 'Purchase Report', 150 | icon: 'radio_button_checked', 151 | path: 'purchase-report' 152 | }, 153 | { 154 | title: 'Sales Report', 155 | icon: 'radio_button_checked', 156 | path: 'sales-report' 157 | } 158 | ] 159 | }, 160 | { 161 | title: 'System', 162 | icon: 'settings', 163 | active: false, 164 | type: 'dropdown', 165 | submenus: [ 166 | { 167 | title: 'Multi Language', 168 | icon: 'radio_button_checked', 169 | path: 'multi-language' 170 | }, 171 | { 172 | title: 'Settings', 173 | icon: 'radio_button_checked', 174 | path: 'Settings' 175 | }, 176 | { 177 | title: 'Payment Gateway', 178 | icon: 'radio_button_checked', 179 | path: 'payment-gateway' 180 | }, 181 | { 182 | title: 'Theme Settings', 183 | icon: 'radio_button_checked', 184 | path: 'theme-settings' 185 | }, 186 | { 187 | title: 'Constants', 188 | icon: 'radio_button_checked', 189 | path: 'constants' 190 | }, 191 | { 192 | title: 'Database Backup', 193 | icon: 'radio_button_checked', 194 | path: 'database-backup' 195 | }, 196 | { 197 | title: 'Email Templates', 198 | icon: 'radio_button_checked', 199 | path: 'email-templates' 200 | }, 201 | { 202 | title: 'Staff', 203 | icon: 'radio_button_checked', 204 | path: 'staff' 205 | }, 206 | { 207 | title: 'Staff Roles & Privileges', 208 | icon: 'radio_button_checked', 209 | path: 'staff-roles-privileges' 210 | }, 211 | { 212 | title: 'Transactions Log', 213 | icon: 'radio_button_checked', 214 | path: 'transactions-log' 215 | } 216 | ] 217 | }, 218 | { 219 | title: 'Logout', 220 | icon: 'power_settings_new', 221 | active: false, 222 | path: 'Logout' 223 | } 224 | ]; 225 | 226 | $scope.sideNav = () => { 227 | document.getElementById('pages').classList.toggle('pages-sidenav'); 228 | } 229 | 230 | $scope.toggleNav = () => { 231 | $mdSidenav("left").toggle(); 232 | } 233 | 234 | $scope.openNav = () => { 235 | $mdSidenav("left").open(); 236 | } 237 | 238 | $scope.closeNav = () => { 239 | $mdSidenav("left").close(); 240 | } 241 | 242 | $scope.goTo = (link) => { 243 | $mdSidenav("left").open(); 244 | $location.path(link); 245 | } 246 | 247 | // Menu Toggle 248 | $scope.collapseAll = function(data) { 249 | for(var i in $scope.menus) { 250 | if($scope.menus[i] != data) { 251 | $scope.menus[i].expanded = false; 252 | } 253 | } 254 | data.expanded = !data.expanded; 255 | }; 256 | }); 257 | -------------------------------------------------------------------------------- /shopping-cart/client/js/products.controller.js: -------------------------------------------------------------------------------- 1 | 'user strict'; 2 | 3 | // File Upload Directive 4 | app.directive('fileModel', ['$parse', function ($parse) { 5 | return { 6 | restrict: 'A', 7 | link: function(scope, element, attrs) { 8 | var model = $parse(attrs.fileModel); 9 | var modelSetter = model.assign; 10 | 11 | element.bind('change', function(){ 12 | scope.$apply(function(){ 13 | modelSetter(scope, element[0].files[0]); 14 | }); 15 | }); 16 | } 17 | }; 18 | }]); 19 | 20 | // File Upload Service 21 | app.service('multipartForm', ['$http', function ($http) { 22 | this.post = function(uploadUrl, data) { 23 | var fd = new FormData(); 24 | for(var key in data) { 25 | fd.append(key, data[key]); 26 | } 27 | 28 | $http.post(uploadUrl, fd, { 29 | transformRequest: angular.identity, 30 | headers: {'Content-Type': undefined} 31 | }).then(function (httpResponse) { 32 | console.log('multipartForm Response:', httpResponse); 33 | }); 34 | } 35 | }]); 36 | 37 | app.controller('productsController', function ($http, $mdEditDialog, $q, $timeout, $scope, multipartForm){ 38 | 39 | $scope.options = { 40 | rowSelection: true, 41 | multiSelect: true, 42 | autoSelect: true, 43 | decapitate: false, 44 | largeEditDialog: false, 45 | boundaryLinks: false, 46 | limitSelect: true, 47 | pageSelect: true 48 | }; 49 | 50 | $scope.IsVisible = false; 51 | $scope.selected = []; 52 | $scope.product = {}; 53 | $scope.limitOptions = [5, 10, 15, { 54 | label: 'All', 55 | value: function () { 56 | return $scope.products ? $scope.products.count : 0; 57 | } 58 | }]; 59 | 60 | $scope.query = { 61 | order: 'product_name', 62 | limit: 10, 63 | page: 1 64 | }; 65 | 66 | $http.post('/getProducts').then(function (products) { 67 | $scope.products = products.data; 68 | console.log($scope.products); 69 | }); 70 | 71 | $scope.toggleLimitOptions = function () { 72 | $scope.limitOptions = $scope.limitOptions ? undefined : [5, 10, 15]; 73 | }; 74 | 75 | $scope.onPaginate = function(page, limit) { 76 | console.log('Scope Page: ' + $scope.query.page + ' Scope Limit: ' + $scope.query.limit); 77 | console.log('Page: ' + page + ' Limit: ' + limit); 78 | 79 | $scope.promise = $timeout(function () { 80 | 81 | }, 2000); 82 | }; 83 | 84 | $scope.deselect = function (item) { 85 | console.log(item.name, 'was deselected'); 86 | }; 87 | 88 | $scope.log = function (item) { 89 | console.log(item.name, 'was selected'); 90 | }; 91 | 92 | $scope.loadStuff = function () { 93 | $scope.promise = $timeout(function () { 94 | 95 | }, 2000); 96 | }; 97 | 98 | $scope.onReorder = function(order) { 99 | 100 | console.log('Scope Order: ' + $scope.query.order); 101 | console.log('Order: ' + order); 102 | 103 | $scope.promise = $timeout(function () { 104 | 105 | }, 2000); 106 | }; 107 | 108 | $scope.addProduct = function() { 109 | $scope.IsVisible = $scope.IsVisible ? false : true; 110 | } 111 | 112 | // Image Preview 113 | $scope.SelectFile = function (e) { 114 | var reader = new FileReader(); 115 | reader.onload = function (e) { 116 | $scope.PreviewImage = e.target.result; 117 | $scope.$apply(); 118 | }; 119 | 120 | reader.readAsDataURL(e.target.files[0]); 121 | }; 122 | 123 | // Add Product 124 | $scope.submit= function(){ 125 | 126 | // File Upload Service 127 | const uploadUrl = "/addProducts"; 128 | multipartForm.post(uploadUrl, $scope.product); 129 | } 130 | 131 | }); -------------------------------------------------------------------------------- /shopping-cart/client/uploads/img-2852020-1590684956674.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/shopping-cart/client/uploads/img-2852020-1590684956674.jpg -------------------------------------------------------------------------------- /shopping-cart/client/uploads/iphone-11-pro-27-5-2020-1590551435418.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/shopping-cart/client/uploads/iphone-11-pro-27-5-2020-1590551435418.jpg -------------------------------------------------------------------------------- /shopping-cart/client/views/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Shopping Cart 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 | {{data.icon}} 38 | {{data.title}} 39 | 40 |
41 |
42 | 49 |
50 |
51 |
52 | 53 |
54 | 55 |
56 | 57 | menu 58 | 59 |

{{project_name}}

60 |
61 |
62 | 63 | 64 | 65 |
Loading...
66 |
67 |
68 |
69 |
70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /shopping-cart/client/views/pages/home.html: -------------------------------------------------------------------------------- 1 |

Home Page

2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /shopping-cart/client/views/pages/products.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 | Product Details 6 | 7 | 8 | playlist_add 9 | 10 | 11 | refresh 12 | 13 | 14 | filter_list 15 | 16 | 17 | more_vert 18 | 19 |
20 |
21 | 22 | 23 |
24 | 25 |
26 | 27 | 28 | 29 | 30 |
31 |
This is required.
32 | 33 |
34 |
35 | 36 | 37 | 38 | 39 |
40 |
The product escription must be less than 500 characters long.
41 |
42 |
43 | 44 |
45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | None 54 | East 55 | West 56 | North 57 | South 58 | 59 | 60 | 61 | 62 | 63 | 64 | Electronics 65 | Mobile 66 | Cloths 67 | 68 | 69 |
70 | 71 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 |
87 | 88 |
89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 |
104 | 105 |
106 | 107 | 108 |
109 | 110 |
111 |
112 | 113 |
114 | Submit 115 |
116 | 117 |
118 |
119 |
120 | 121 | 122 | 123 |
124 | {{selected.length}} {{selected.length > 1 ? 'items' : 'item'}} selected 125 | 126 | 127 | delete 128 | 129 |
130 |
131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 |
ActionImageNameWarehouseQuantityBarcodePurchase PriceSelling PriceCategory
edit{{product.product_name}}{{product.wharehouse_id}}{{product.quantity}}{{product.barcode}}{{product.purchase_price}}{{product.selling_price}}{{product.category_id}}
162 |
163 | 164 | 165 | 166 |
-------------------------------------------------------------------------------- /shopping-cart/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shopping-cart", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.4", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", 10 | "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", 11 | "requires": { 12 | "mime-types": "~2.1.16", 13 | "negotiator": "0.6.1" 14 | } 15 | }, 16 | "after": { 17 | "version": "0.8.2", 18 | "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", 19 | "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" 20 | }, 21 | "append-field": { 22 | "version": "1.0.0", 23 | "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", 24 | "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" 25 | }, 26 | "array-flatten": { 27 | "version": "1.1.1", 28 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 29 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 30 | }, 31 | "arraybuffer.slice": { 32 | "version": "0.0.7", 33 | "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", 34 | "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" 35 | }, 36 | "async-limiter": { 37 | "version": "1.0.0", 38 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", 39 | "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" 40 | }, 41 | "backo2": { 42 | "version": "1.0.2", 43 | "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", 44 | "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" 45 | }, 46 | "base64-arraybuffer": { 47 | "version": "0.1.5", 48 | "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", 49 | "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" 50 | }, 51 | "base64id": { 52 | "version": "1.0.0", 53 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", 54 | "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" 55 | }, 56 | "better-assert": { 57 | "version": "1.0.2", 58 | "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", 59 | "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", 60 | "requires": { 61 | "callsite": "1.0.0" 62 | } 63 | }, 64 | "bignumber.js": { 65 | "version": "4.0.4", 66 | "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.0.4.tgz", 67 | "integrity": "sha512-LDXpJKVzEx2/OqNbG9mXBNvHuiRL4PzHCGfnANHMJ+fv68Ads3exDVJeGDJws+AoNEuca93bU3q+S0woeUaCdg==" 68 | }, 69 | "blob": { 70 | "version": "0.0.4", 71 | "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", 72 | "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" 73 | }, 74 | "body-parser": { 75 | "version": "1.18.2", 76 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", 77 | "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", 78 | "requires": { 79 | "bytes": "3.0.0", 80 | "content-type": "~1.0.4", 81 | "debug": "2.6.9", 82 | "depd": "~1.1.1", 83 | "http-errors": "~1.6.2", 84 | "iconv-lite": "0.4.19", 85 | "on-finished": "~2.3.0", 86 | "qs": "6.5.1", 87 | "raw-body": "2.3.2", 88 | "type-is": "~1.6.15" 89 | } 90 | }, 91 | "buffer-from": { 92 | "version": "1.1.1", 93 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 94 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" 95 | }, 96 | "busboy": { 97 | "version": "0.2.14", 98 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", 99 | "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", 100 | "requires": { 101 | "dicer": "0.2.5", 102 | "readable-stream": "1.1.x" 103 | }, 104 | "dependencies": { 105 | "isarray": { 106 | "version": "0.0.1", 107 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 108 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 109 | }, 110 | "readable-stream": { 111 | "version": "1.1.14", 112 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 113 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 114 | "requires": { 115 | "core-util-is": "~1.0.0", 116 | "inherits": "~2.0.1", 117 | "isarray": "0.0.1", 118 | "string_decoder": "~0.10.x" 119 | } 120 | }, 121 | "string_decoder": { 122 | "version": "0.10.31", 123 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 124 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" 125 | } 126 | } 127 | }, 128 | "bytes": { 129 | "version": "3.0.0", 130 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 131 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 132 | }, 133 | "callsite": { 134 | "version": "1.0.0", 135 | "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", 136 | "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" 137 | }, 138 | "component-bind": { 139 | "version": "1.0.0", 140 | "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", 141 | "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" 142 | }, 143 | "component-emitter": { 144 | "version": "1.2.1", 145 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 146 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" 147 | }, 148 | "component-inherit": { 149 | "version": "0.0.3", 150 | "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", 151 | "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" 152 | }, 153 | "concat-stream": { 154 | "version": "1.6.2", 155 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", 156 | "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", 157 | "requires": { 158 | "buffer-from": "^1.0.0", 159 | "inherits": "^2.0.3", 160 | "readable-stream": "^2.2.2", 161 | "typedarray": "^0.0.6" 162 | } 163 | }, 164 | "content-disposition": { 165 | "version": "0.5.2", 166 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 167 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 168 | }, 169 | "content-type": { 170 | "version": "1.0.4", 171 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 172 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 173 | }, 174 | "cookie": { 175 | "version": "0.3.1", 176 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 177 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 178 | }, 179 | "cookie-signature": { 180 | "version": "1.0.6", 181 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 182 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 183 | }, 184 | "core-util-is": { 185 | "version": "1.0.2", 186 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 187 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 188 | }, 189 | "debug": { 190 | "version": "2.6.9", 191 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 192 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 193 | "requires": { 194 | "ms": "2.0.0" 195 | } 196 | }, 197 | "depd": { 198 | "version": "1.1.2", 199 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 200 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 201 | }, 202 | "destroy": { 203 | "version": "1.0.4", 204 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 205 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 206 | }, 207 | "dicer": { 208 | "version": "0.2.5", 209 | "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", 210 | "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", 211 | "requires": { 212 | "readable-stream": "1.1.x", 213 | "streamsearch": "0.1.2" 214 | }, 215 | "dependencies": { 216 | "isarray": { 217 | "version": "0.0.1", 218 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 219 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 220 | }, 221 | "readable-stream": { 222 | "version": "1.1.14", 223 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 224 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 225 | "requires": { 226 | "core-util-is": "~1.0.0", 227 | "inherits": "~2.0.1", 228 | "isarray": "0.0.1", 229 | "string_decoder": "~0.10.x" 230 | } 231 | }, 232 | "string_decoder": { 233 | "version": "0.10.31", 234 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 235 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" 236 | } 237 | } 238 | }, 239 | "ee-first": { 240 | "version": "1.1.1", 241 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 242 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 243 | }, 244 | "encodeurl": { 245 | "version": "1.0.1", 246 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", 247 | "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=" 248 | }, 249 | "engine.io": { 250 | "version": "3.1.4", 251 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.4.tgz", 252 | "integrity": "sha1-PQIRtwpVLOhB/8fahiezAamkFi4=", 253 | "requires": { 254 | "accepts": "1.3.3", 255 | "base64id": "1.0.0", 256 | "cookie": "0.3.1", 257 | "debug": "~2.6.9", 258 | "engine.io-parser": "~2.1.0", 259 | "uws": "~0.14.4", 260 | "ws": "~3.3.1" 261 | }, 262 | "dependencies": { 263 | "accepts": { 264 | "version": "1.3.3", 265 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", 266 | "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", 267 | "requires": { 268 | "mime-types": "~2.1.11", 269 | "negotiator": "0.6.1" 270 | } 271 | } 272 | } 273 | }, 274 | "engine.io-client": { 275 | "version": "3.1.4", 276 | "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.4.tgz", 277 | "integrity": "sha1-T88TcLRxY70s6b4nM5ckMDUNTqE=", 278 | "requires": { 279 | "component-emitter": "1.2.1", 280 | "component-inherit": "0.0.3", 281 | "debug": "~2.6.9", 282 | "engine.io-parser": "~2.1.1", 283 | "has-cors": "1.1.0", 284 | "indexof": "0.0.1", 285 | "parseqs": "0.0.5", 286 | "parseuri": "0.0.5", 287 | "ws": "~3.3.1", 288 | "xmlhttprequest-ssl": "~1.5.4", 289 | "yeast": "0.1.2" 290 | } 291 | }, 292 | "engine.io-parser": { 293 | "version": "2.1.2", 294 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", 295 | "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", 296 | "requires": { 297 | "after": "0.8.2", 298 | "arraybuffer.slice": "~0.0.7", 299 | "base64-arraybuffer": "0.1.5", 300 | "blob": "0.0.4", 301 | "has-binary2": "~1.0.2" 302 | } 303 | }, 304 | "escape-html": { 305 | "version": "1.0.3", 306 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 307 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 308 | }, 309 | "etag": { 310 | "version": "1.8.1", 311 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 312 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 313 | }, 314 | "express": { 315 | "version": "4.16.2", 316 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", 317 | "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=", 318 | "requires": { 319 | "accepts": "~1.3.4", 320 | "array-flatten": "1.1.1", 321 | "body-parser": "1.18.2", 322 | "content-disposition": "0.5.2", 323 | "content-type": "~1.0.4", 324 | "cookie": "0.3.1", 325 | "cookie-signature": "1.0.6", 326 | "debug": "2.6.9", 327 | "depd": "~1.1.1", 328 | "encodeurl": "~1.0.1", 329 | "escape-html": "~1.0.3", 330 | "etag": "~1.8.1", 331 | "finalhandler": "1.1.0", 332 | "fresh": "0.5.2", 333 | "merge-descriptors": "1.0.1", 334 | "methods": "~1.1.2", 335 | "on-finished": "~2.3.0", 336 | "parseurl": "~1.3.2", 337 | "path-to-regexp": "0.1.7", 338 | "proxy-addr": "~2.0.2", 339 | "qs": "6.5.1", 340 | "range-parser": "~1.2.0", 341 | "safe-buffer": "5.1.1", 342 | "send": "0.16.1", 343 | "serve-static": "1.13.1", 344 | "setprototypeof": "1.1.0", 345 | "statuses": "~1.3.1", 346 | "type-is": "~1.6.15", 347 | "utils-merge": "1.0.1", 348 | "vary": "~1.1.2" 349 | }, 350 | "dependencies": { 351 | "setprototypeof": { 352 | "version": "1.1.0", 353 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 354 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 355 | }, 356 | "statuses": { 357 | "version": "1.3.1", 358 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", 359 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" 360 | } 361 | } 362 | }, 363 | "finalhandler": { 364 | "version": "1.1.0", 365 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", 366 | "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", 367 | "requires": { 368 | "debug": "2.6.9", 369 | "encodeurl": "~1.0.1", 370 | "escape-html": "~1.0.3", 371 | "on-finished": "~2.3.0", 372 | "parseurl": "~1.3.2", 373 | "statuses": "~1.3.1", 374 | "unpipe": "~1.0.0" 375 | }, 376 | "dependencies": { 377 | "statuses": { 378 | "version": "1.3.1", 379 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", 380 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" 381 | } 382 | } 383 | }, 384 | "forwarded": { 385 | "version": "0.1.2", 386 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 387 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 388 | }, 389 | "fresh": { 390 | "version": "0.5.2", 391 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 392 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 393 | }, 394 | "fs": { 395 | "version": "0.0.1-security", 396 | "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", 397 | "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ=" 398 | }, 399 | "has-binary2": { 400 | "version": "1.0.2", 401 | "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.2.tgz", 402 | "integrity": "sha1-6D26SfC5vk0CbSc2U1DZ8D9Uvpg=", 403 | "requires": { 404 | "isarray": "2.0.1" 405 | }, 406 | "dependencies": { 407 | "isarray": { 408 | "version": "2.0.1", 409 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", 410 | "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" 411 | } 412 | } 413 | }, 414 | "has-cors": { 415 | "version": "1.1.0", 416 | "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", 417 | "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" 418 | }, 419 | "http": { 420 | "version": "0.0.1-security", 421 | "resolved": "https://registry.npmjs.org/http/-/http-0.0.1-security.tgz", 422 | "integrity": "sha512-RnDvP10Ty9FxqOtPZuxtebw1j4L/WiqNMDtuc1YMH1XQm5TgDRaR1G9u8upL6KD1bXHSp9eSXo/ED+8Q7FAr+g==" 423 | }, 424 | "http-errors": { 425 | "version": "1.6.2", 426 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", 427 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", 428 | "requires": { 429 | "depd": "1.1.1", 430 | "inherits": "2.0.3", 431 | "setprototypeof": "1.0.3", 432 | "statuses": ">= 1.3.1 < 2" 433 | }, 434 | "dependencies": { 435 | "depd": { 436 | "version": "1.1.1", 437 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 438 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" 439 | } 440 | } 441 | }, 442 | "iconv-lite": { 443 | "version": "0.4.19", 444 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 445 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" 446 | }, 447 | "indexof": { 448 | "version": "0.0.1", 449 | "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", 450 | "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" 451 | }, 452 | "inherits": { 453 | "version": "2.0.3", 454 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 455 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 456 | }, 457 | "ipaddr.js": { 458 | "version": "1.5.2", 459 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", 460 | "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=" 461 | }, 462 | "isarray": { 463 | "version": "1.0.0", 464 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 465 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 466 | }, 467 | "media-typer": { 468 | "version": "0.3.0", 469 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 470 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 471 | }, 472 | "merge-descriptors": { 473 | "version": "1.0.1", 474 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 475 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 476 | }, 477 | "methods": { 478 | "version": "1.1.2", 479 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 480 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 481 | }, 482 | "mime": { 483 | "version": "1.4.1", 484 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 485 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 486 | }, 487 | "mime-db": { 488 | "version": "1.30.0", 489 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", 490 | "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" 491 | }, 492 | "mime-types": { 493 | "version": "2.1.17", 494 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", 495 | "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", 496 | "requires": { 497 | "mime-db": "~1.30.0" 498 | } 499 | }, 500 | "minimist": { 501 | "version": "1.2.5", 502 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 503 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" 504 | }, 505 | "mkdirp": { 506 | "version": "0.5.5", 507 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 508 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 509 | "requires": { 510 | "minimist": "^1.2.5" 511 | } 512 | }, 513 | "ms": { 514 | "version": "2.0.0", 515 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 516 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 517 | }, 518 | "multer": { 519 | "version": "1.4.2", 520 | "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.2.tgz", 521 | "integrity": "sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==", 522 | "requires": { 523 | "append-field": "^1.0.0", 524 | "busboy": "^0.2.11", 525 | "concat-stream": "^1.5.2", 526 | "mkdirp": "^0.5.1", 527 | "object-assign": "^4.1.1", 528 | "on-finished": "^2.3.0", 529 | "type-is": "^1.6.4", 530 | "xtend": "^4.0.0" 531 | } 532 | }, 533 | "mysql": { 534 | "version": "2.15.0", 535 | "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.15.0.tgz", 536 | "integrity": "sha512-C7tjzWtbN5nzkLIV+E8Crnl9bFyc7d3XJcBAvHKEVkjrYjogz3llo22q6s/hw+UcsE4/844pDob9ac+3dVjQSA==", 537 | "requires": { 538 | "bignumber.js": "4.0.4", 539 | "readable-stream": "2.3.3", 540 | "safe-buffer": "5.1.1", 541 | "sqlstring": "2.3.0" 542 | } 543 | }, 544 | "negotiator": { 545 | "version": "0.6.1", 546 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 547 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 548 | }, 549 | "object-assign": { 550 | "version": "4.1.1", 551 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 552 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 553 | }, 554 | "object-component": { 555 | "version": "0.0.3", 556 | "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", 557 | "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" 558 | }, 559 | "on-finished": { 560 | "version": "2.3.0", 561 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 562 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 563 | "requires": { 564 | "ee-first": "1.1.1" 565 | } 566 | }, 567 | "parseqs": { 568 | "version": "0.0.5", 569 | "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", 570 | "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", 571 | "requires": { 572 | "better-assert": "~1.0.0" 573 | } 574 | }, 575 | "parseuri": { 576 | "version": "0.0.5", 577 | "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", 578 | "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", 579 | "requires": { 580 | "better-assert": "~1.0.0" 581 | } 582 | }, 583 | "parseurl": { 584 | "version": "1.3.2", 585 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 586 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 587 | }, 588 | "path": { 589 | "version": "0.12.7", 590 | "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", 591 | "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", 592 | "requires": { 593 | "process": "^0.11.1", 594 | "util": "^0.10.3" 595 | } 596 | }, 597 | "path-to-regexp": { 598 | "version": "0.1.7", 599 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 600 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 601 | }, 602 | "process": { 603 | "version": "0.11.10", 604 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", 605 | "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" 606 | }, 607 | "process-nextick-args": { 608 | "version": "1.0.7", 609 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", 610 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" 611 | }, 612 | "proxy-addr": { 613 | "version": "2.0.2", 614 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", 615 | "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", 616 | "requires": { 617 | "forwarded": "~0.1.2", 618 | "ipaddr.js": "1.5.2" 619 | } 620 | }, 621 | "qs": { 622 | "version": "6.5.1", 623 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 624 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" 625 | }, 626 | "range-parser": { 627 | "version": "1.2.0", 628 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 629 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 630 | }, 631 | "raw-body": { 632 | "version": "2.3.2", 633 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", 634 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", 635 | "requires": { 636 | "bytes": "3.0.0", 637 | "http-errors": "1.6.2", 638 | "iconv-lite": "0.4.19", 639 | "unpipe": "1.0.0" 640 | } 641 | }, 642 | "readable-stream": { 643 | "version": "2.3.3", 644 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", 645 | "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", 646 | "requires": { 647 | "core-util-is": "~1.0.0", 648 | "inherits": "~2.0.3", 649 | "isarray": "~1.0.0", 650 | "process-nextick-args": "~1.0.6", 651 | "safe-buffer": "~5.1.1", 652 | "string_decoder": "~1.0.3", 653 | "util-deprecate": "~1.0.1" 654 | } 655 | }, 656 | "safe-buffer": { 657 | "version": "5.1.1", 658 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 659 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 660 | }, 661 | "send": { 662 | "version": "0.16.1", 663 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", 664 | "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", 665 | "requires": { 666 | "debug": "2.6.9", 667 | "depd": "~1.1.1", 668 | "destroy": "~1.0.4", 669 | "encodeurl": "~1.0.1", 670 | "escape-html": "~1.0.3", 671 | "etag": "~1.8.1", 672 | "fresh": "0.5.2", 673 | "http-errors": "~1.6.2", 674 | "mime": "1.4.1", 675 | "ms": "2.0.0", 676 | "on-finished": "~2.3.0", 677 | "range-parser": "~1.2.0", 678 | "statuses": "~1.3.1" 679 | }, 680 | "dependencies": { 681 | "statuses": { 682 | "version": "1.3.1", 683 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", 684 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" 685 | } 686 | } 687 | }, 688 | "serve-static": { 689 | "version": "1.13.1", 690 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", 691 | "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", 692 | "requires": { 693 | "encodeurl": "~1.0.1", 694 | "escape-html": "~1.0.3", 695 | "parseurl": "~1.3.2", 696 | "send": "0.16.1" 697 | } 698 | }, 699 | "setprototypeof": { 700 | "version": "1.0.3", 701 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", 702 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" 703 | }, 704 | "socket.io": { 705 | "version": "2.0.4", 706 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.0.4.tgz", 707 | "integrity": "sha1-waRZDO/4fs8TxyZS8Eb3FrKeYBQ=", 708 | "requires": { 709 | "debug": "~2.6.6", 710 | "engine.io": "~3.1.0", 711 | "socket.io-adapter": "~1.1.0", 712 | "socket.io-client": "2.0.4", 713 | "socket.io-parser": "~3.1.1" 714 | } 715 | }, 716 | "socket.io-adapter": { 717 | "version": "1.1.1", 718 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", 719 | "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" 720 | }, 721 | "socket.io-client": { 722 | "version": "2.0.4", 723 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.0.4.tgz", 724 | "integrity": "sha1-CRilUkBtxeVAs4Dc2Xr8SmQzL44=", 725 | "requires": { 726 | "backo2": "1.0.2", 727 | "base64-arraybuffer": "0.1.5", 728 | "component-bind": "1.0.0", 729 | "component-emitter": "1.2.1", 730 | "debug": "~2.6.4", 731 | "engine.io-client": "~3.1.0", 732 | "has-cors": "1.1.0", 733 | "indexof": "0.0.1", 734 | "object-component": "0.0.3", 735 | "parseqs": "0.0.5", 736 | "parseuri": "0.0.5", 737 | "socket.io-parser": "~3.1.1", 738 | "to-array": "0.1.4" 739 | } 740 | }, 741 | "socket.io-parser": { 742 | "version": "3.1.2", 743 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.1.2.tgz", 744 | "integrity": "sha1-28IoIVH8T6675Aru3Ady66YZ9/I=", 745 | "requires": { 746 | "component-emitter": "1.2.1", 747 | "debug": "~2.6.4", 748 | "has-binary2": "~1.0.2", 749 | "isarray": "2.0.1" 750 | }, 751 | "dependencies": { 752 | "isarray": { 753 | "version": "2.0.1", 754 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", 755 | "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" 756 | } 757 | } 758 | }, 759 | "sqlstring": { 760 | "version": "2.3.0", 761 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.0.tgz", 762 | "integrity": "sha1-UluKT9Jtb3GqYegipsr5dtMa0qg=" 763 | }, 764 | "statuses": { 765 | "version": "1.4.0", 766 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 767 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 768 | }, 769 | "streamsearch": { 770 | "version": "0.1.2", 771 | "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", 772 | "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" 773 | }, 774 | "string_decoder": { 775 | "version": "1.0.3", 776 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", 777 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", 778 | "requires": { 779 | "safe-buffer": "~5.1.0" 780 | } 781 | }, 782 | "to-array": { 783 | "version": "0.1.4", 784 | "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", 785 | "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" 786 | }, 787 | "type-is": { 788 | "version": "1.6.15", 789 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", 790 | "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", 791 | "requires": { 792 | "media-typer": "0.3.0", 793 | "mime-types": "~2.1.15" 794 | } 795 | }, 796 | "typedarray": { 797 | "version": "0.0.6", 798 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 799 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" 800 | }, 801 | "ultron": { 802 | "version": "1.1.1", 803 | "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", 804 | "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" 805 | }, 806 | "unpipe": { 807 | "version": "1.0.0", 808 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 809 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 810 | }, 811 | "util": { 812 | "version": "0.10.4", 813 | "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", 814 | "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", 815 | "requires": { 816 | "inherits": "2.0.3" 817 | } 818 | }, 819 | "util-deprecate": { 820 | "version": "1.0.2", 821 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 822 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 823 | }, 824 | "utils-merge": { 825 | "version": "1.0.1", 826 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 827 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 828 | }, 829 | "uws": { 830 | "version": "0.14.5", 831 | "resolved": "https://registry.npmjs.org/uws/-/uws-0.14.5.tgz", 832 | "integrity": "sha1-Z6rzPEaypYel9mZtAPdpEyjxSdw=", 833 | "optional": true 834 | }, 835 | "vary": { 836 | "version": "1.1.2", 837 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 838 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 839 | }, 840 | "ws": { 841 | "version": "3.3.3", 842 | "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", 843 | "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", 844 | "requires": { 845 | "async-limiter": "~1.0.0", 846 | "safe-buffer": "~5.1.0", 847 | "ultron": "~1.1.0" 848 | } 849 | }, 850 | "xmlhttprequest-ssl": { 851 | "version": "1.5.5", 852 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", 853 | "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" 854 | }, 855 | "xtend": { 856 | "version": "4.0.2", 857 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 858 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" 859 | }, 860 | "yeast": { 861 | "version": "0.1.2", 862 | "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", 863 | "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" 864 | } 865 | } 866 | } 867 | -------------------------------------------------------------------------------- /shopping-cart/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shopping-cart", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "body-parser": "^1.18.2", 14 | "express": "^4.16.2", 15 | "fs": "0.0.1-security", 16 | "http": "0.0.1-security", 17 | "multer": "^1.4.2", 18 | "mysql": "^2.15.0", 19 | "path": "^0.12.7", 20 | "socket.io": "^2.0.4" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /shopping-cart/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require("express"); 4 | const http = require('http'); 5 | const socketio = require('socket.io'); 6 | const bodyParser = require('body-parser'); 7 | 8 | const socketEvents = require('./utils/socket'); 9 | const routes = require('./utils/routes'); 10 | const config = require('./utils/config'); 11 | 12 | 13 | class Server{ 14 | 15 | constructor(){ 16 | this.port = process.env.PORT || 3000; 17 | this.host = `localhost`; 18 | 19 | this.app = express(); 20 | this.http = http.Server(this.app); 21 | this.socket = socketio(this.http); 22 | } 23 | 24 | appConfig(){ 25 | this.app.use( 26 | bodyParser.json() 27 | ); 28 | new config(this.app); 29 | } 30 | 31 | /* Including app Routes starts*/ 32 | includeRoutes(){ 33 | new routes(this.app).routesConfig(); 34 | new socketEvents(this.socket).socketConfig(); 35 | } 36 | /* Including app Routes ends*/ 37 | 38 | appExecute(){ 39 | 40 | this.appConfig(); 41 | this.includeRoutes(); 42 | 43 | this.http.listen(this.port, this.host, () => { 44 | console.log(`Listening on http://${this.host}:${this.port}`); 45 | }); 46 | } 47 | 48 | } 49 | 50 | const app = new Server(); 51 | app.appExecute(); -------------------------------------------------------------------------------- /shopping-cart/utils/config.js: -------------------------------------------------------------------------------- 1 | class Config{ 2 | 3 | constructor(app){ 4 | // Setting .html as the default template extension 5 | app.set('view engine', 'html'); 6 | 7 | // Telling express where it can find the templates 8 | app.set('views', (__dirname + '/../views')); 9 | 10 | //Files 11 | app.use(require('express').static(require('path').join('client'))); 12 | 13 | } 14 | } 15 | module.exports = Config; -------------------------------------------------------------------------------- /shopping-cart/utils/db.js: -------------------------------------------------------------------------------- 1 | const mysql = require('mysql'); 2 | 3 | class Db { 4 | constructor(config) { 5 | this.connection = mysql.createPool({ 6 | connectionLimit: 100, 7 | host: '127.0.0.1', 8 | user: 'root', 9 | password: 'root', 10 | database: 'learning_zone', 11 | debug: false 12 | }); 13 | } 14 | query(sql, args) { 15 | return new Promise((resolve, reject) => { 16 | this.connection.query(sql, args, (err, rows) => { 17 | if (err) 18 | return reject(err); 19 | resolve(rows); 20 | }); 21 | }); 22 | } 23 | close() { 24 | return new Promise((resolve, reject) => { 25 | this.connection.end(err => { 26 | if (err) 27 | return reject(err); 28 | resolve(); 29 | }); 30 | }); 31 | } 32 | } 33 | module.exports = new Db(); -------------------------------------------------------------------------------- /shopping-cart/utils/helper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const DB = require('./db'); 3 | 4 | class Helper{ 5 | 6 | constructor(app){ 7 | this.db = DB; 8 | } 9 | 10 | async userNameCheck (username){ 11 | return await this.db.query(`SELECT count(username) as count FROM users WHERE LOWER(username) = ?`, `${username}`); 12 | } 13 | 14 | async registerUser(params){ 15 | try { 16 | return await this.db.query("INSERT INTO users (`username`,`password`,`online`) VALUES (?,?,?)", [params['username'],params['password'],'Y']); 17 | } catch (error) { 18 | console.error(error); 19 | return null; 20 | } 21 | } 22 | 23 | async loginUser(params){ 24 | try { 25 | return await this.db.query(`SELECT id FROM users WHERE LOWER(username) = ? AND password = ?`, [params.username,params.password]); 26 | } catch (error) { 27 | return null; 28 | } 29 | } 30 | 31 | async userSessionCheck(userId){ 32 | try { 33 | const result = await this.db.query(`SELECT online,username FROM user WHERE id = ? AND online = ?`, [userId,'Y']); 34 | if(result !== null){ 35 | return result[0]['username']; 36 | }else{ 37 | return null; 38 | } 39 | } catch (error) { 40 | return null; 41 | } 42 | } 43 | 44 | async addSocketId(userId, userSocketId){ 45 | try { 46 | return await this.db.query(`UPDATE users SET socketid = ?, online= ? WHERE id = ?`, [userSocketId,'Y',userId]); 47 | } catch (error) { 48 | console.log(error); 49 | return null; 50 | } 51 | } 52 | 53 | async isUserLoggedOut(userSocketId){ 54 | try { 55 | return await this.db.query(`SELECT online FROM users WHERE socketid = ?`, [userSocketId]); 56 | } catch (error) { 57 | return null; 58 | } 59 | } 60 | 61 | async logoutUser(userSocketId){ 62 | return await this.db.query(`UPDATE users SET socketid = ?, online= ? WHERE socketid = ?`, ['','N',userSocketId]); 63 | } 64 | 65 | getChatList(userId, userSocketId){ 66 | try { 67 | return Promise.all([ 68 | this.db.query(`SELECT id,username,online,socketid FROM users WHERE id = ?`, [userId]), 69 | this.db.query(`SELECT id,username,online,socketid FROM users WHERE online = ? and socketid != ?`, ['Y',userSocketId]) 70 | ]).then( (response) => { 71 | return { 72 | userinfo : response[0].length > 0 ? response[0][0] : response[0], 73 | chatlist : response[1] 74 | }; 75 | }).catch( (error) => { 76 | console.warn(error); 77 | return (null); 78 | }); 79 | } catch (error) { 80 | console.warn(error); 81 | return null; 82 | } 83 | } 84 | 85 | async insertMessages(params){ 86 | try { 87 | return await this.db.query( 88 | "INSERT INTO message (`from_user_id`,`to_user_id`,`message`) values (?,?,?)", 89 | [params.fromUserId, params.toUserId, params.message] 90 | ); 91 | } catch (error) { 92 | console.warn(error); 93 | return null; 94 | } 95 | } 96 | 97 | async getMessages(userId, toUserId){ 98 | try { 99 | return await this.db.query( 100 | `SELECT id,from_user_id as fromUserId,to_user_id as toUserId,message FROM message WHERE 101 | (from_user_id = ? AND to_user_id = ? ) 102 | OR 103 | (from_user_id = ? AND to_user_id = ? ) ORDER BY id ASC 104 | `, 105 | [userId, toUserId, toUserId, userId] 106 | ); 107 | } catch (error) { 108 | console.warn(error); 109 | return null; 110 | } 111 | } 112 | } 113 | module.exports = new Helper(); -------------------------------------------------------------------------------- /shopping-cart/utils/product.js: -------------------------------------------------------------------------------- 1 | 'user strict'; 2 | const DB = require('./db'); 3 | 4 | class Product{ 5 | 6 | constructor(app){ 7 | this.db = DB; 8 | } 9 | 10 | // Get All Products 11 | async getProducts(userId, toUserId){ 12 | try { 13 | return await this.db.query( 14 | `SELECT * FROM product ORDER BY id ASC` 15 | ); 16 | } catch (error) { 17 | console.warn(error); 18 | return null; 19 | } 20 | } 21 | 22 | // Add Product 23 | async addProducts(params){ 24 | 25 | let insert_statement = "INSERT INTO `product` (`product_name`, `product_description`, `sku`, `serial_number`, `purchase_price`, `selling_price`, `quantity`, `barcode`, `reordered_stock_amount`, `product_image`, `category_id`, `wharehouse_id`) VALUES ( ? )"; 26 | let values = [ 27 | params['product_name'], params['product_description'], params['sku'], params['serial_number'], params['purchase_price'], 28 | params['selling_price'], params['quantity'], params['barcode'], params['reordered_stock_amount'], params['product_image'], 29 | params['category'], params['warehouse'] 30 | ]; 31 | 32 | console.log("insert_statement: "+insert_statement); 33 | console.log("values: "+values); 34 | try { 35 | return await this.db.query(insert_statement, [values]); 36 | } catch (error) { 37 | console.error(error); 38 | return null; 39 | } 40 | } 41 | } 42 | module.exports = new Product(); -------------------------------------------------------------------------------- /shopping-cart/utils/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const helper = require('./helper'); 4 | const product = require('./product'); 5 | const path = require('path'); 6 | const multer = require('multer'); 7 | 8 | class Routes{ 9 | 10 | constructor(app){ 11 | 12 | this.app = app; 13 | } 14 | 15 | appRoutes(){ 16 | this.app.post('/usernameCheck',async (request,response) =>{ 17 | const username = request.body.username; 18 | if (username === "" || username === undefined || username === null) { 19 | response.status(412).json({ 20 | error : true, 21 | message : `username cant be empty.` 22 | }); 23 | } else { 24 | const data = await helper.userNameCheck(username.toLowerCase()); 25 | if (data[0]['count'] > 0) { 26 | response.status(401).json({ 27 | error:true, 28 | message: 'This username is alreday taken.' 29 | }); 30 | } else { 31 | response.status(200).json({ 32 | error:false, 33 | message: 'This username is available.' 34 | }); 35 | } 36 | } 37 | }); 38 | 39 | this.app.post('/registerUser', async (request,response) => { 40 | const registrationResponse = {} 41 | const data = { 42 | username : (request.body.username).toLowerCase(), 43 | password : request.body.password 44 | }; 45 | if(data.username === '') { 46 | registrationResponse.error = true; 47 | registrationResponse.message = `username cant be empty.`; 48 | response.status(412).json(registrationResponse); 49 | }else if(data.password === ''){ 50 | registrationResponse.error = true; 51 | registrationResponse.message = `password cant be empty.`; 52 | response.status(412).json(registrationResponse); 53 | }else{ 54 | const result = await helper.registerUser( data ); 55 | if (result === null) { 56 | registrationResponse.error = true; 57 | registrationResponse.message = `User registration unsuccessful,try after some time.`; 58 | response.status(417).json(registrationResponse); 59 | } else { 60 | registrationResponse.error = false; 61 | registrationResponse.userId = result.insertId; 62 | registrationResponse.message = `User registration successful.`; 63 | response.status(200).json(registrationResponse); 64 | } 65 | } 66 | }); 67 | 68 | this.app.post('/login',async (request,response) =>{ 69 | const loginResponse = {} 70 | const data = { 71 | username : (request.body.username).toLowerCase(), 72 | password : request.body.password 73 | }; 74 | if(data.username === '' || data.username === null) { 75 | loginResponse.error = true; 76 | loginResponse.message = `username cant be empty.`; 77 | response.status(412).json(loginResponse); 78 | }else if(data.password === '' || data.password === null){ 79 | loginResponse.error = true; 80 | loginResponse.message = `password cant be empty.`; 81 | response.status(412).json(loginResponse); 82 | }else{ 83 | const result = await helper.loginUser(data); 84 | if (result === null || result.length === 0) { 85 | loginResponse.error = true; 86 | loginResponse.message = `Invalid username and password combination.`; 87 | response.status(401).json(loginResponse); 88 | } else { 89 | loginResponse.error = false; 90 | loginResponse.userId = result[0].id; 91 | loginResponse.message = `User logged in.`; 92 | response.status(200).json(loginResponse); 93 | } 94 | } 95 | }); 96 | 97 | this.app.post('/userSessionCheck', async (request,response) =>{ 98 | const userId = request.body.userId; 99 | const sessionCheckResponse = {} 100 | if (userId == '') { 101 | sessionCheckResponse.error = true; 102 | sessionCheckResponse.message = `User Id cant be empty.`; 103 | response.status(412).json(sessionCheckResponse); 104 | }else{ 105 | const username = await helper.userSessionCheck(userId); 106 | if (username === null || username === '') { 107 | sessionCheckResponse.error = true; 108 | sessionCheckResponse.message = `User is not logged in.`; 109 | response.status(401).json(sessionCheckResponse); 110 | }else{ 111 | sessionCheckResponse.error = false; 112 | sessionCheckResponse.username = username; 113 | sessionCheckResponse.message = `User logged in.`; 114 | response.status(200).json(sessionCheckResponse); 115 | } 116 | } 117 | }); 118 | 119 | this.app.post('/getMessages',async (request,response) => { 120 | const userId = request.body.userId; 121 | const toUserId = request.body.toUserId; 122 | const messages = {} 123 | if (userId === '') { 124 | messages.error = true; 125 | messages.message = `userId cant be empty.`; 126 | response.status(200).json(messages); 127 | }else{ 128 | const result = await helper.getMessages( userId, toUserId); 129 | if (result === null) { 130 | messages.error = true; 131 | messages.message = `Internal Server error.`; 132 | response.status(500).json(messages); 133 | }else{ 134 | messages.error = false; 135 | messages.messages = result; 136 | response.status(200).json(messages); 137 | } 138 | } 139 | }); 140 | 141 | /** Get Product Details */ 142 | this.app.post('/getProducts',async (request,response) => { 143 | const userId = request.body.userId; 144 | const toUserId = request.body.toUserId; 145 | const products = {} 146 | if (userId === '') { 147 | products.error = true; 148 | products.message = `userId cant be empty.`; 149 | response.status(200).json(products); 150 | }else{ 151 | const result = await product.getProducts( userId, toUserId); 152 | if (result === null) { 153 | products.error = true; 154 | products.message = `Internal Server error.`; 155 | response.status(500).json(products); 156 | }else{ 157 | products.error = false; 158 | products.products = result; 159 | response.status(200).json(products); 160 | } 161 | } 162 | }); 163 | 164 | // File Upload 165 | var storage = multer.diskStorage({ 166 | destination: './client/uploads/', 167 | filename: function (request, file, cb) { 168 | var d = new Date(); 169 | cb(null, 'img' + '-' + d.getDate() + (d.getMonth()+1) + d.getFullYear() + '-' + Date.now() + path.extname(file.originalname)) 170 | } 171 | }) 172 | 173 | var upload = multer({ storage: storage }); 174 | 175 | // Add Product 176 | this.app.post('/addProducts', upload.single('file'), async (request, response, next) => { 177 | 178 | const userId = request.body.userId; 179 | const toUserId = request.body.toUserId; 180 | const params = request.body; 181 | // File Location 182 | params.product_image = './uploads/' + request.file.filename; 183 | 184 | console.log("Routes request: "+JSON.stringify(params)); 185 | console.log("Routes Params: "+JSON.stringify(request.file)); 186 | 187 | const products = {} 188 | if (userId === '') { 189 | products.error = true; 190 | products.message = `userId cant be empty.`; 191 | response.status(200).json(products); 192 | }else{ 193 | const result = await product.addProducts( params ); 194 | if (result === null) { 195 | products.error = true; 196 | products.message = `Internal Server error.`; 197 | response.status(500).json(products); 198 | }else{ 199 | products.error = false; 200 | products.products = result; 201 | response.status(200).json(products); 202 | } 203 | } 204 | }); 205 | 206 | this.app.get('*',(request,response) =>{ 207 | response.sendFile(path.join(__dirname + '../../client/views/index.html')); 208 | /* 209 | * OR one can define the template engine and use response.render(); 210 | */ 211 | }); 212 | } 213 | 214 | routesConfig(){ 215 | this.appRoutes(); 216 | } 217 | } 218 | module.exports = Routes; -------------------------------------------------------------------------------- /shopping-cart/utils/socket.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const helper = require('./helper'); 5 | 6 | class Socket{ 7 | 8 | constructor(socket){ 9 | this.io = socket; 10 | } 11 | 12 | socketEvents(){ 13 | 14 | this.io.on('connection', (socket) => { 15 | 16 | /** 17 | * get the user's Chat list 18 | */ 19 | socket.on('chat-list', async (userId) => { 20 | 21 | let chatListResponse = {}; 22 | 23 | if (userId === '' && (typeof userId !== 'string' || typeof userId !== 'number')) { 24 | 25 | chatListResponse.error = true; 26 | chatListResponse.message = `User does not exits.`; 27 | 28 | this.io.emit('chat-list-response',chatListResponse); 29 | }else{ 30 | const result = await helper.getChatList(userId, socket.id); 31 | this.io.to(socket.id).emit('chat-list-response', { 32 | error: result !== null ? false : true, 33 | singleUser: false, 34 | chatList: result.chatlist 35 | }); 36 | 37 | socket.broadcast.emit('chat-list-response', { 38 | error: result !== null ? false : true, 39 | singleUser: true, 40 | chatList: result.userinfo 41 | }); 42 | } 43 | }); 44 | /** 45 | * send the messages to the user 46 | */ 47 | socket.on('add-message', async (data) => { 48 | 49 | if (data.message === '') { 50 | 51 | this.io.to(socket.id).emit(`add-message-response`,`Message cant be empty`); 52 | 53 | }else if(data.fromUserId === ''){ 54 | 55 | this.io.to(socket.id).emit(`add-message-response`,`Unexpected error, Login again.`); 56 | 57 | }else if(data.toUserId === ''){ 58 | 59 | this.io.to(socket.id).emit(`add-message-response`,`Select a user to chat.`); 60 | 61 | }else{ 62 | let toSocketId = data.toSocketId; 63 | const sqlResult = await helper.insertMessages({ 64 | fromUserId: data.fromUserId, 65 | toUserId: data.toUserId, 66 | message: data.message 67 | }); 68 | this.io.to(toSocketId).emit(`add-message-response`, data); 69 | } 70 | }); 71 | 72 | 73 | /** 74 | * Logout the user 75 | */ 76 | socket.on('logout', async () => { 77 | const isLoggedOut = await helper.logoutUser(socket.id); 78 | this.io.to(socket.id).emit('logout-response',{ 79 | error : false 80 | }); 81 | socket.disconnect(); 82 | }); 83 | 84 | 85 | /** 86 | * sending the disconnected user to all socket users. 87 | */ 88 | socket.on('disconnect',async ()=>{ 89 | const isLoggedOut = await helper.logoutUser(socket.id); 90 | setTimeout(async ()=>{ 91 | const isLoggedOut = await helper.isUserLoggedOut(socket.id); 92 | if (isLoggedOut && isLoggedOut !== null) { 93 | socket.broadcast.emit('chat-list-response', { 94 | error: false, 95 | userDisconnected: true, 96 | socketId: socket.id 97 | }); 98 | } 99 | },1000); 100 | }); 101 | 102 | }); 103 | 104 | } 105 | 106 | socketConfig(){ 107 | 108 | this.io.use( async (socket, next) => { 109 | let userId = socket.request._query['userId']; 110 | let userSocketId = socket.id; 111 | const response = await helper.addSocketId( userId, userSocketId); 112 | if(response && response !== null){ 113 | next(); 114 | }else{ 115 | console.error(`Socket connection failed, for user Id ${userId}.`); 116 | } 117 | }); 118 | 119 | this.socketEvents(); 120 | } 121 | } 122 | module.exports = Socket; --------------------------------------------------------------------------------