├── README.md ├── angular-d3-chart ├── .editorconfig ├── .gitignore ├── README.md ├── angular.json ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.e2e.json ├── package-lock.json ├── package.json ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── market-chart │ │ │ ├── market-chart.component.css │ │ │ ├── market-chart.component.html │ │ │ ├── market-chart.component.spec.ts │ │ │ └── market-chart.component.ts │ │ ├── market-price.ts │ │ ├── market-status.service.spec.ts │ │ └── market-status.service.ts │ ├── assets │ │ └── .gitkeep │ ├── browserslist │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── karma.conf.js │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── tslint.json ├── tsconfig.json └── tslint.json └── server ├── .gitignore ├── index.js ├── market.js ├── package-lock.json └── package.json /README.md: -------------------------------------------------------------------------------- 1 | # Real-Time Charts using Angular, D3, and Socket.IO 2 | 3 | Please, [refer to this article to get detailed instructions on how to build real-time charts with Angular, D3, and Socket.IO](https://auth0.com/blog/real-time-charts-using-angular-d3-and-socket-io/). 4 | -------------------------------------------------------------------------------- /angular-d3-chart/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /angular-d3-chart/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | -------------------------------------------------------------------------------- /angular-d3-chart/README.md: -------------------------------------------------------------------------------- 1 | # AngularD3Chart 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 6.0.8. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /angular-d3-chart/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "angular-d3-chart": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "prefix": "app", 11 | "schematics": {}, 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/angular-d3-chart", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": "src/polyfills.ts", 20 | "tsConfig": "src/tsconfig.app.json", 21 | "assets": [ 22 | "src/favicon.ico", 23 | "src/assets" 24 | ], 25 | "styles": [ 26 | "src/styles.css" 27 | ], 28 | "scripts": [] 29 | }, 30 | "configurations": { 31 | "production": { 32 | "fileReplacements": [ 33 | { 34 | "replace": "src/environments/environment.ts", 35 | "with": "src/environments/environment.prod.ts" 36 | } 37 | ], 38 | "optimization": true, 39 | "outputHashing": "all", 40 | "sourceMap": false, 41 | "extractCss": true, 42 | "namedChunks": false, 43 | "aot": true, 44 | "extractLicenses": true, 45 | "vendorChunk": false, 46 | "buildOptimizer": true 47 | } 48 | } 49 | }, 50 | "serve": { 51 | "builder": "@angular-devkit/build-angular:dev-server", 52 | "options": { 53 | "browserTarget": "angular-d3-chart:build" 54 | }, 55 | "configurations": { 56 | "production": { 57 | "browserTarget": "angular-d3-chart:build:production" 58 | } 59 | } 60 | }, 61 | "extract-i18n": { 62 | "builder": "@angular-devkit/build-angular:extract-i18n", 63 | "options": { 64 | "browserTarget": "angular-d3-chart:build" 65 | } 66 | }, 67 | "test": { 68 | "builder": "@angular-devkit/build-angular:karma", 69 | "options": { 70 | "main": "src/test.ts", 71 | "polyfills": "src/polyfills.ts", 72 | "tsConfig": "src/tsconfig.spec.json", 73 | "karmaConfig": "src/karma.conf.js", 74 | "styles": [ 75 | "src/styles.css" 76 | ], 77 | "scripts": [], 78 | "assets": [ 79 | "src/favicon.ico", 80 | "src/assets" 81 | ] 82 | } 83 | }, 84 | "lint": { 85 | "builder": "@angular-devkit/build-angular:tslint", 86 | "options": { 87 | "tsConfig": [ 88 | "src/tsconfig.app.json", 89 | "src/tsconfig.spec.json" 90 | ], 91 | "exclude": [ 92 | "**/node_modules/**" 93 | ] 94 | } 95 | } 96 | } 97 | }, 98 | "angular-d3-chart-e2e": { 99 | "root": "e2e/", 100 | "projectType": "application", 101 | "architect": { 102 | "e2e": { 103 | "builder": "@angular-devkit/build-angular:protractor", 104 | "options": { 105 | "protractorConfig": "e2e/protractor.conf.js", 106 | "devServerTarget": "angular-d3-chart:serve" 107 | }, 108 | "configurations": { 109 | "production": { 110 | "devServerTarget": "angular-d3-chart:serve:production" 111 | } 112 | } 113 | }, 114 | "lint": { 115 | "builder": "@angular-devkit/build-angular:tslint", 116 | "options": { 117 | "tsConfig": "e2e/tsconfig.e2e.json", 118 | "exclude": [ 119 | "**/node_modules/**" 120 | ] 121 | } 122 | } 123 | } 124 | } 125 | }, 126 | "defaultProject": "angular-d3-chart" 127 | } -------------------------------------------------------------------------------- /angular-d3-chart/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.e2e.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; -------------------------------------------------------------------------------- /angular-d3-chart/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('workspace-project App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('Welcome to angular-d3-chart!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /angular-d3-chart/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /angular-d3-chart/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /angular-d3-chart/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-d3-chart", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "^6.0.3", 15 | "@angular/common": "^6.0.3", 16 | "@angular/compiler": "^6.0.3", 17 | "@angular/core": "^6.0.3", 18 | "@angular/forms": "^6.0.3", 19 | "@angular/http": "^6.0.3", 20 | "@angular/platform-browser": "^6.0.3", 21 | "@angular/platform-browser-dynamic": "^6.0.3", 22 | "@angular/router": "^6.0.3", 23 | "core-js": "^2.5.4", 24 | "d3": "^5.4.0", 25 | "rxjs": "^6.0.0", 26 | "socket.io-client": "^2.1.1", 27 | "zone.js": "^0.8.26" 28 | }, 29 | "devDependencies": { 30 | "@angular-devkit/build-angular": "~0.6.8", 31 | "@angular/cli": "~6.0.8", 32 | "@angular/compiler-cli": "^6.0.3", 33 | "@angular/language-service": "^6.0.3", 34 | "@types/d3": "^5.0.0", 35 | "@types/jasmine": "~2.8.6", 36 | "@types/jasminewd2": "~2.0.3", 37 | "@types/node": "~8.9.4", 38 | "@types/socket.io-client": "^1.4.32", 39 | "codelyzer": "~4.2.1", 40 | "jasmine-core": "~2.99.1", 41 | "jasmine-spec-reporter": "~4.2.1", 42 | "karma": "~1.7.1", 43 | "karma-chrome-launcher": "~2.2.0", 44 | "karma-coverage-istanbul-reporter": "~2.0.0", 45 | "karma-jasmine": "~1.1.1", 46 | "karma-jasmine-html-reporter": "^0.2.2", 47 | "protractor": "~5.3.0", 48 | "ts-node": "~5.0.1", 49 | "tslint": "~5.9.1", 50 | "typescript": "~2.7.2" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /angular-d3-chart/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auth0-blog/angular-d3-socketio/c40da02eac2a1ba49a9786373ab69e296cf33fdb/angular-d3-chart/src/app/app.component.css -------------------------------------------------------------------------------- /angular-d3-chart/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /angular-d3-chart/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | describe('AppComponent', () => { 4 | beforeEach(async(() => { 5 | TestBed.configureTestingModule({ 6 | declarations: [ 7 | AppComponent 8 | ], 9 | }).compileComponents(); 10 | })); 11 | it('should create the app', async(() => { 12 | const fixture = TestBed.createComponent(AppComponent); 13 | const app = fixture.debugElement.componentInstance; 14 | expect(app).toBeTruthy(); 15 | })); 16 | it(`should have as title 'app'`, async(() => { 17 | const fixture = TestBed.createComponent(AppComponent); 18 | const app = fixture.debugElement.componentInstance; 19 | expect(app.title).toEqual('app'); 20 | })); 21 | it('should render title in a h1 tag', async(() => { 22 | const fixture = TestBed.createComponent(AppComponent); 23 | fixture.detectChanges(); 24 | const compiled = fixture.debugElement.nativeElement; 25 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to angular-d3-chart!'); 26 | })); 27 | }); 28 | -------------------------------------------------------------------------------- /angular-d3-chart/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | import {MarketStatusService} from './market-status.service'; 3 | import {Observable} from 'rxjs'; 4 | import {MarketPrice} from './market-price'; 5 | 6 | @Component({ 7 | selector: 'app-root', 8 | templateUrl: './app.component.html', 9 | styleUrls: ['./app.component.css'] 10 | }) 11 | export class AppComponent { 12 | title = 'app'; 13 | marketStatus: MarketPrice[]; 14 | marketStatusToPlot: MarketPrice[]; 15 | 16 | set MarketStatus(status: MarketPrice[]) { 17 | this.marketStatus = status; 18 | this.marketStatusToPlot = this.marketStatus.slice(0, 20); 19 | } 20 | 21 | constructor(private marketStatusSvc: MarketStatusService) { 22 | this.marketStatusSvc.getInitialMarketStatus() 23 | .subscribe(prices => { 24 | this.MarketStatus = prices; 25 | 26 | let marketUpdateObservable = this.marketStatusSvc.getUpdates(); // 1 27 | marketUpdateObservable.subscribe((latestStatus: MarketPrice) => { // 2 28 | this.MarketStatus = [latestStatus].concat(this.marketStatus); // 3 29 | }); // 4 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /angular-d3-chart/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import {BrowserModule} from '@angular/platform-browser'; 2 | import {NgModule} from '@angular/core'; 3 | import {HttpClientModule} from '@angular/common/http'; 4 | 5 | import {AppComponent} from './app.component'; 6 | import { MarketChartComponent } from './market-chart/market-chart.component'; 7 | 8 | @NgModule({ 9 | declarations: [ 10 | AppComponent, 11 | MarketChartComponent 12 | ], 13 | imports: [ 14 | BrowserModule, 15 | HttpClientModule 16 | ], 17 | providers: [], 18 | bootstrap: [AppComponent] 19 | }) 20 | export class AppModule {} 21 | -------------------------------------------------------------------------------- /angular-d3-chart/src/app/market-chart/market-chart.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auth0-blog/angular-d3-socketio/c40da02eac2a1ba49a9786373ab69e296cf33fdb/angular-d3-chart/src/app/market-chart/market-chart.component.css -------------------------------------------------------------------------------- /angular-d3-chart/src/app/market-chart/market-chart.component.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /angular-d3-chart/src/app/market-chart/market-chart.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MarketChartComponent } from './market-chart.component'; 4 | 5 | describe('MarketChartComponent', () => { 6 | let component: MarketChartComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ MarketChartComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(MarketChartComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /angular-d3-chart/src/app/market-chart/market-chart.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component, ElementRef, Input, OnChanges, ViewChild} from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | 4 | import {MarketPrice} from '../market-price'; 5 | 6 | @Component({ 7 | selector: 'app-market-chart', 8 | templateUrl: './market-chart.component.html', 9 | styleUrls: ['./market-chart.component.css'], 10 | changeDetection: ChangeDetectionStrategy.OnPush 11 | }) 12 | export class MarketChartComponent implements OnChanges { 13 | @ViewChild('chart') 14 | chartElement: ElementRef; 15 | 16 | parseDate = d3.timeParse('%d-%m-%Y'); 17 | 18 | @Input() 19 | marketStatus: MarketPrice[]; 20 | 21 | private svgElement: HTMLElement; 22 | private chartProps: any; 23 | 24 | constructor() { } 25 | 26 | ngOnChanges() { 27 | if (this.marketStatus && this.chartProps) { 28 | this.updateChart(); 29 | } else if (this.marketStatus) { 30 | this.buildChart(); 31 | } 32 | } 33 | 34 | formatDate() { 35 | this.marketStatus.forEach(ms => { 36 | if (typeof ms.date === 'string') { 37 | ms.date = this.parseDate(ms.date); 38 | } 39 | }); 40 | } 41 | 42 | updateChart() { 43 | let _this = this; 44 | this.formatDate(); 45 | 46 | // Scale the range of the data again 47 | this.chartProps.x.domain(d3.extent(this.marketStatus, function (d) { 48 | if (d.date instanceof Date) { 49 | return d.date.getTime(); 50 | } 51 | })); 52 | 53 | this.chartProps.y.domain([0, d3.max(this.marketStatus, function (d) { return Math.max(d.close, d.open); })]); 54 | 55 | // Select the section we want to apply our changes to 56 | this.chartProps.svg.transition(); 57 | 58 | // Make the changes to the line chart 59 | this.chartProps.svg.select('.line.line1') // update the line 60 | .attr('d', this.chartProps.valueline(this.marketStatus)); 61 | 62 | this.chartProps.svg.select('.line.line2') // update the line 63 | .attr('d', this.chartProps.valueline2(this.marketStatus)); 64 | 65 | this.chartProps.svg.select('.x.axis') // update x axis 66 | .call(this.chartProps.xAxis); 67 | 68 | this.chartProps.svg.select('.y.axis') // update y axis 69 | .call(this.chartProps.yAxis); 70 | } 71 | 72 | buildChart() { 73 | this.chartProps = {}; 74 | this.formatDate(); 75 | 76 | // Set the dimensions of the canvas / graph 77 | var margin = { top: 30, right: 20, bottom: 30, left: 50 }, 78 | width = 600 - margin.left - margin.right, 79 | height = 270 - margin.top - margin.bottom; 80 | 81 | // Set the ranges 82 | this.chartProps.x = d3.scaleTime().range([0, width]); 83 | this.chartProps.y = d3.scaleLinear().range([height, 0]); 84 | 85 | // Define the axes 86 | var xAxis = d3.axisBottom(this.chartProps.x); 87 | var yAxis = d3.axisLeft(this.chartProps.y).ticks(5); 88 | 89 | let _this = this; 90 | 91 | // Define the line 92 | var valueline = d3.line() 93 | .x(function (d) { 94 | if (d.date instanceof Date) { 95 | return _this.chartProps.x(d.date.getTime()); 96 | } 97 | }) 98 | .y(function (d) { console.log('Close market'); return _this.chartProps.y(d.close); }); 99 | 100 | // Define the line 101 | var valueline2 = d3.line() 102 | .x(function (d) { 103 | if (d.date instanceof Date) { 104 | return _this.chartProps.x(d.date.getTime()); 105 | } 106 | }) 107 | .y(function (d) { console.log('Open market'); return _this.chartProps.y(d.open); }); 108 | 109 | var svg = d3.select(this.chartElement.nativeElement) 110 | .append('svg') 111 | .attr('width', width + margin.left + margin.right) 112 | .attr('height', height + margin.top + margin.bottom) 113 | .append('g') 114 | .attr('transform', `translate(${margin.left},${margin.top})`); 115 | 116 | // Scale the range of the data 117 | this.chartProps.x.domain( 118 | d3.extent(_this.marketStatus, function (d) { 119 | if (d.date instanceof Date) 120 | return (d.date as Date).getTime(); 121 | })); 122 | this.chartProps.y.domain([0, d3.max(this.marketStatus, function (d) { 123 | return Math.max(d.close, d.open); 124 | })]); 125 | 126 | // Add the valueline2 path. 127 | svg.append('path') 128 | .attr('class', 'line line2') 129 | .style('stroke', 'green') 130 | .style('fill', 'none') 131 | .attr('d', valueline2(_this.marketStatus)); 132 | 133 | // Add the valueline path. 134 | svg.append('path') 135 | .attr('class', 'line line1') 136 | .style('stroke', 'black') 137 | .style('fill', 'none') 138 | .attr('d', valueline(_this.marketStatus)); 139 | 140 | 141 | // Add the X Axis 142 | svg.append('g') 143 | .attr('class', 'x axis') 144 | .attr('transform', `translate(0,${height})`) 145 | .call(xAxis); 146 | 147 | // Add the Y Axis 148 | svg.append('g') 149 | .attr('class', 'y axis') 150 | .call(yAxis); 151 | 152 | // Setting the required objects in chartProps so they could be used to update the chart 153 | this.chartProps.svg = svg; 154 | this.chartProps.valueline = valueline; 155 | this.chartProps.valueline2 = valueline2; 156 | this.chartProps.xAxis = xAxis; 157 | this.chartProps.yAxis = yAxis; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /angular-d3-chart/src/app/market-price.ts: -------------------------------------------------------------------------------- 1 | export class MarketPrice { 2 | open: number; 3 | close: number; 4 | date: string | Date; 5 | } 6 | -------------------------------------------------------------------------------- /angular-d3-chart/src/app/market-status.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { MarketStatusService } from './market-status.service'; 4 | 5 | describe('MarketStatusService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [MarketStatusService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([MarketStatusService], (service: MarketStatusService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /angular-d3-chart/src/app/market-status.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {HttpClient} from '@angular/common/http'; 3 | 4 | import {MarketPrice} from './market-price'; 5 | import { Subject, from } from 'rxjs'; 6 | import * as socketio from 'socket.io-client'; 7 | 8 | @Injectable({ 9 | providedIn: 'root' 10 | }) 11 | export class MarketStatusService { 12 | 13 | private baseUrl = 'http://localhost:3000'; 14 | constructor(private httpClient: HttpClient) { } 15 | 16 | getInitialMarketStatus() { 17 | return this.httpClient.get(`${this.baseUrl}/api/market`); 18 | } 19 | 20 | getUpdates() { 21 | let socket = socketio(this.baseUrl); 22 | let marketSub = new Subject(); 23 | let marketSubObservable = from(marketSub); 24 | 25 | socket.on('market', (marketStatus: MarketPrice) => { 26 | marketSub.next(marketStatus); 27 | }); 28 | 29 | return marketSubObservable; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /angular-d3-chart/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auth0-blog/angular-d3-socketio/c40da02eac2a1ba49a9786373ab69e296cf33fdb/angular-d3-chart/src/assets/.gitkeep -------------------------------------------------------------------------------- /angular-d3-chart/src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # For IE 9-11 support, please uncomment the last line of the file and adjust as needed 5 | > 0.5% 6 | last 2 versions 7 | Firefox ESR 8 | not dead 9 | # IE 9-11 -------------------------------------------------------------------------------- /angular-d3-chart/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /angular-d3-chart/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * In development mode, to ignore zone related error stack frames such as 11 | * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can 12 | * import the following file, but please comment it out in production mode 13 | * because it will have performance impact when throw error 14 | */ 15 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 16 | -------------------------------------------------------------------------------- /angular-d3-chart/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auth0-blog/angular-d3-socketio/c40da02eac2a1ba49a9786373ab69e296cf33fdb/angular-d3-chart/src/favicon.ico -------------------------------------------------------------------------------- /angular-d3-chart/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AngularD3Chart 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /angular-d3-chart/src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage'), 20 | reports: ['html', 'lcovonly'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false 30 | }); 31 | }; -------------------------------------------------------------------------------- /angular-d3-chart/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.log(err)); 13 | -------------------------------------------------------------------------------- /angular-d3-chart/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** IE10 and IE11 requires the following for the Reflect API. */ 41 | // import 'core-js/es6/reflect'; 42 | 43 | 44 | /** Evergreen browsers require these. **/ 45 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 46 | import 'core-js/es7/reflect'; 47 | 48 | 49 | /** 50 | * Web Animations `@angular/platform-browser/animations` 51 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 52 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 53 | **/ 54 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 55 | 56 | /** 57 | * By default, zone.js will patch all possible macroTask and DomEvents 58 | * user can disable parts of macroTask/DomEvents patch by setting following flags 59 | */ 60 | 61 | // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 62 | // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 63 | // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 64 | 65 | /* 66 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 67 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 68 | */ 69 | // (window as any).__Zone_enable_cross_context_check = true; 70 | 71 | /*************************************************************************************************** 72 | * Zone JS is required by default for Angular itself. 73 | */ 74 | import 'zone.js/dist/zone'; // Included with Angular CLI. 75 | 76 | 77 | 78 | /*************************************************************************************************** 79 | * APPLICATION IMPORTS 80 | */ 81 | (window as any).global = window; 82 | -------------------------------------------------------------------------------- /angular-d3-chart/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /angular-d3-chart/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /angular-d3-chart/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "types": [] 7 | }, 8 | "exclude": [ 9 | "src/test.ts", 10 | "**/*.spec.ts" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /angular-d3-chart/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "types": [ 7 | "jasmine", 8 | "node" 9 | ] 10 | }, 11 | "files": [ 12 | "test.ts", 13 | "polyfills.ts" 14 | ], 15 | "include": [ 16 | "**/*.spec.ts", 17 | "**/*.d.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /angular-d3-chart/src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "app", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "app", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /angular-d3-chart/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2017", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /angular-d3-chart/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "deprecation": { 15 | "severity": "warn" 16 | }, 17 | "eofline": true, 18 | "forin": true, 19 | "import-blacklist": [ 20 | true, 21 | "rxjs/Rx" 22 | ], 23 | "import-spacing": true, 24 | "indent": [ 25 | true, 26 | "spaces" 27 | ], 28 | "interface-over-type-literal": true, 29 | "label-position": true, 30 | "max-line-length": [ 31 | true, 32 | 140 33 | ], 34 | "member-access": false, 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-arg": true, 47 | "no-bitwise": true, 48 | "no-console": [ 49 | true, 50 | "debug", 51 | "info", 52 | "time", 53 | "timeEnd", 54 | "trace" 55 | ], 56 | "no-construct": true, 57 | "no-debugger": true, 58 | "no-duplicate-super": true, 59 | "no-empty": false, 60 | "no-empty-interface": true, 61 | "no-eval": true, 62 | "no-inferrable-types": [ 63 | true, 64 | "ignore-params" 65 | ], 66 | "no-misused-new": true, 67 | "no-non-null-assertion": true, 68 | "no-shadowed-variable": true, 69 | "no-string-literal": false, 70 | "no-string-throw": true, 71 | "no-switch-case-fall-through": true, 72 | "no-trailing-whitespace": true, 73 | "no-unnecessary-initializer": true, 74 | "no-unused-expression": true, 75 | "no-use-before-declare": true, 76 | "no-var-keyword": true, 77 | "object-literal-sort-keys": false, 78 | "one-line": [ 79 | true, 80 | "check-open-brace", 81 | "check-catch", 82 | "check-else", 83 | "check-whitespace" 84 | ], 85 | "prefer-const": true, 86 | "quotemark": [ 87 | true, 88 | "single" 89 | ], 90 | "radix": true, 91 | "semicolon": [ 92 | true, 93 | "always" 94 | ], 95 | "triple-equals": [ 96 | true, 97 | "allow-null-check" 98 | ], 99 | "typedef-whitespace": [ 100 | true, 101 | { 102 | "call-signature": "nospace", 103 | "index-signature": "nospace", 104 | "parameter": "nospace", 105 | "property-declaration": "nospace", 106 | "variable-declaration": "nospace" 107 | } 108 | ], 109 | "unified-signatures": true, 110 | "variable-name": false, 111 | "whitespace": [ 112 | true, 113 | "check-branch", 114 | "check-decl", 115 | "check-operator", 116 | "check-separator", 117 | "check-type" 118 | ], 119 | "no-output-on-prefix": true, 120 | "use-input-property-decorator": true, 121 | "use-output-property-decorator": true, 122 | "use-host-property-decorator": true, 123 | "no-input-rename": true, 124 | "no-output-rename": true, 125 | "use-life-cycle-interface": true, 126 | "use-pipe-transform-interface": true, 127 | "component-class-suffix": true, 128 | "directive-class-suffix": true 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | -------------------------------------------------------------------------------- /server/index.js: -------------------------------------------------------------------------------- 1 | const app = require('express')(); 2 | const http = require('http').Server(app); 3 | const market = require('./market'); 4 | const io = require('socket.io')(http); 5 | 6 | const port = 3000; 7 | 8 | app.use((req, res, next) => { 9 | res.header('Access-Control-Allow-Origin', '*'); 10 | res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); 11 | next(); 12 | }); 13 | 14 | app.get('/api/market', (req, res) => { 15 | res.send(market.marketPositions); 16 | }); 17 | 18 | setInterval(function () { 19 | market.updateMarket(); 20 | io.sockets.emit('market', market.marketPositions[0]); 21 | }, 5000); 22 | 23 | io.on('connection', function (socket) { 24 | console.log('a user connected'); 25 | }); 26 | 27 | http.listen(port, () => { 28 | console.log(`Listening on *:${port}`); 29 | }); 30 | -------------------------------------------------------------------------------- /server/market.js: -------------------------------------------------------------------------------- 1 | const moment = require('moment'); 2 | 3 | const marketPositions = [ 4 | {"date": "10-05-2012", "close": 68.55, "open": 74.55}, 5 | {"date": "09-05-2012", "close": 74.55, "open": 69.55}, 6 | {"date": "08-05-2012", "close": 69.55, "open": 62.55}, 7 | {"date": "07-05-2012", "close": 62.55, "open": 56.55}, 8 | {"date": "06-05-2012", "close": 56.55, "open": 59.55}, 9 | {"date": "05-05-2012", "close": 59.86, "open": 65.86}, 10 | {"date": "04-05-2012", "close": 62.62, "open": 65.62}, 11 | {"date": "03-05-2012", "close": 64.48, "open": 60.48}, 12 | {"date": "02-05-2012", "close": 60.98, "open": 55.98}, 13 | {"date": "01-05-2012", "close": 58.13, "open": 53.13}, 14 | {"date": "30-04-2012", "close": 68.55, "open": 74.55}, 15 | {"date": "29-04-2012", "close": 74.55, "open": 69.55}, 16 | {"date": "28-04-2012", "close": 69.55, "open": 62.55}, 17 | {"date": "27-04-2012", "close": 62.55, "open": 56.55}, 18 | {"date": "26-04-2012", "close": 56.55, "open": 59.55}, 19 | {"date": "25-04-2012", "close": 59.86, "open": 65.86}, 20 | {"date": "24-04-2012", "close": 62.62, "open": 65.62}, 21 | {"date": "23-04-2012", "close": 64.48, "open": 60.48}, 22 | {"date": "22-04-2012", "close": 60.98, "open": 55.98}, 23 | {"date": "21-04-2012", "close": 58.13, "open": 53.13} 24 | ]; 25 | 26 | let counter = 0; 27 | 28 | function updateMarket() { 29 | const diff = Math.floor(Math.random() * 1000) / 100; 30 | const lastDay = moment(marketPositions[0].date, 'DD-MM-YYYY').add(1, 'days'); 31 | let open; 32 | let close; 33 | 34 | if (counter % 2 === 0) { 35 | open = marketPositions[0].open + diff; 36 | close = marketPositions[0].close + diff; 37 | } else { 38 | open = Math.abs(marketPositions[0].open - diff); 39 | close = Math.abs(marketPositions[0].close - diff); 40 | } 41 | 42 | marketPositions.unshift({ 43 | date: lastDay.format('DD-MM-YYYY'), 44 | open, 45 | close 46 | }); 47 | counter++; 48 | } 49 | 50 | module.exports = { 51 | marketPositions, 52 | updateMarket, 53 | }; 54 | -------------------------------------------------------------------------------- /server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.5", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", 10 | "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", 11 | "requires": { 12 | "mime-types": "2.1.18", 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 | "array-flatten": { 22 | "version": "1.1.1", 23 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 24 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 25 | }, 26 | "arraybuffer.slice": { 27 | "version": "0.0.7", 28 | "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", 29 | "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" 30 | }, 31 | "async-limiter": { 32 | "version": "1.0.0", 33 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", 34 | "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" 35 | }, 36 | "backo2": { 37 | "version": "1.0.2", 38 | "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", 39 | "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" 40 | }, 41 | "base64-arraybuffer": { 42 | "version": "0.1.5", 43 | "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", 44 | "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" 45 | }, 46 | "base64id": { 47 | "version": "1.0.0", 48 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", 49 | "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" 50 | }, 51 | "better-assert": { 52 | "version": "1.0.2", 53 | "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", 54 | "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", 55 | "requires": { 56 | "callsite": "1.0.0" 57 | } 58 | }, 59 | "blob": { 60 | "version": "0.0.4", 61 | "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", 62 | "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" 63 | }, 64 | "body-parser": { 65 | "version": "1.18.2", 66 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", 67 | "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", 68 | "requires": { 69 | "bytes": "3.0.0", 70 | "content-type": "1.0.4", 71 | "debug": "2.6.9", 72 | "depd": "1.1.2", 73 | "http-errors": "1.6.3", 74 | "iconv-lite": "0.4.19", 75 | "on-finished": "2.3.0", 76 | "qs": "6.5.1", 77 | "raw-body": "2.3.2", 78 | "type-is": "1.6.16" 79 | } 80 | }, 81 | "bytes": { 82 | "version": "3.0.0", 83 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 84 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 85 | }, 86 | "callsite": { 87 | "version": "1.0.0", 88 | "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", 89 | "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" 90 | }, 91 | "component-bind": { 92 | "version": "1.0.0", 93 | "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", 94 | "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" 95 | }, 96 | "component-emitter": { 97 | "version": "1.2.1", 98 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 99 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" 100 | }, 101 | "component-inherit": { 102 | "version": "0.0.3", 103 | "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", 104 | "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" 105 | }, 106 | "content-disposition": { 107 | "version": "0.5.2", 108 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 109 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 110 | }, 111 | "content-type": { 112 | "version": "1.0.4", 113 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 114 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 115 | }, 116 | "cookie": { 117 | "version": "0.3.1", 118 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 119 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 120 | }, 121 | "cookie-signature": { 122 | "version": "1.0.6", 123 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 124 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 125 | }, 126 | "debug": { 127 | "version": "2.6.9", 128 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 129 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 130 | "requires": { 131 | "ms": "2.0.0" 132 | } 133 | }, 134 | "depd": { 135 | "version": "1.1.2", 136 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 137 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 138 | }, 139 | "destroy": { 140 | "version": "1.0.4", 141 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 142 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 143 | }, 144 | "ee-first": { 145 | "version": "1.1.1", 146 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 147 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 148 | }, 149 | "encodeurl": { 150 | "version": "1.0.2", 151 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 152 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 153 | }, 154 | "engine.io": { 155 | "version": "3.2.0", 156 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz", 157 | "integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==", 158 | "requires": { 159 | "accepts": "1.3.5", 160 | "base64id": "1.0.0", 161 | "cookie": "0.3.1", 162 | "debug": "3.1.0", 163 | "engine.io-parser": "2.1.2", 164 | "ws": "3.3.3" 165 | }, 166 | "dependencies": { 167 | "debug": { 168 | "version": "3.1.0", 169 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 170 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 171 | "requires": { 172 | "ms": "2.0.0" 173 | } 174 | } 175 | } 176 | }, 177 | "engine.io-client": { 178 | "version": "3.2.1", 179 | "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", 180 | "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", 181 | "requires": { 182 | "component-emitter": "1.2.1", 183 | "component-inherit": "0.0.3", 184 | "debug": "3.1.0", 185 | "engine.io-parser": "2.1.2", 186 | "has-cors": "1.1.0", 187 | "indexof": "0.0.1", 188 | "parseqs": "0.0.5", 189 | "parseuri": "0.0.5", 190 | "ws": "3.3.3", 191 | "xmlhttprequest-ssl": "1.5.5", 192 | "yeast": "0.1.2" 193 | }, 194 | "dependencies": { 195 | "debug": { 196 | "version": "3.1.0", 197 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 198 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 199 | "requires": { 200 | "ms": "2.0.0" 201 | } 202 | } 203 | } 204 | }, 205 | "engine.io-parser": { 206 | "version": "2.1.2", 207 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", 208 | "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", 209 | "requires": { 210 | "after": "0.8.2", 211 | "arraybuffer.slice": "0.0.7", 212 | "base64-arraybuffer": "0.1.5", 213 | "blob": "0.0.4", 214 | "has-binary2": "1.0.3" 215 | } 216 | }, 217 | "escape-html": { 218 | "version": "1.0.3", 219 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 220 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 221 | }, 222 | "etag": { 223 | "version": "1.8.1", 224 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 225 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 226 | }, 227 | "express": { 228 | "version": "4.16.3", 229 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", 230 | "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", 231 | "requires": { 232 | "accepts": "1.3.5", 233 | "array-flatten": "1.1.1", 234 | "body-parser": "1.18.2", 235 | "content-disposition": "0.5.2", 236 | "content-type": "1.0.4", 237 | "cookie": "0.3.1", 238 | "cookie-signature": "1.0.6", 239 | "debug": "2.6.9", 240 | "depd": "1.1.2", 241 | "encodeurl": "1.0.2", 242 | "escape-html": "1.0.3", 243 | "etag": "1.8.1", 244 | "finalhandler": "1.1.1", 245 | "fresh": "0.5.2", 246 | "merge-descriptors": "1.0.1", 247 | "methods": "1.1.2", 248 | "on-finished": "2.3.0", 249 | "parseurl": "1.3.2", 250 | "path-to-regexp": "0.1.7", 251 | "proxy-addr": "2.0.3", 252 | "qs": "6.5.1", 253 | "range-parser": "1.2.0", 254 | "safe-buffer": "5.1.1", 255 | "send": "0.16.2", 256 | "serve-static": "1.13.2", 257 | "setprototypeof": "1.1.0", 258 | "statuses": "1.4.0", 259 | "type-is": "1.6.16", 260 | "utils-merge": "1.0.1", 261 | "vary": "1.1.2" 262 | } 263 | }, 264 | "finalhandler": { 265 | "version": "1.1.1", 266 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", 267 | "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", 268 | "requires": { 269 | "debug": "2.6.9", 270 | "encodeurl": "1.0.2", 271 | "escape-html": "1.0.3", 272 | "on-finished": "2.3.0", 273 | "parseurl": "1.3.2", 274 | "statuses": "1.4.0", 275 | "unpipe": "1.0.0" 276 | } 277 | }, 278 | "forwarded": { 279 | "version": "0.1.2", 280 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 281 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 282 | }, 283 | "fresh": { 284 | "version": "0.5.2", 285 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 286 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 287 | }, 288 | "has-binary2": { 289 | "version": "1.0.3", 290 | "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", 291 | "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", 292 | "requires": { 293 | "isarray": "2.0.1" 294 | } 295 | }, 296 | "has-cors": { 297 | "version": "1.1.0", 298 | "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", 299 | "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" 300 | }, 301 | "http-errors": { 302 | "version": "1.6.3", 303 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 304 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 305 | "requires": { 306 | "depd": "1.1.2", 307 | "inherits": "2.0.3", 308 | "setprototypeof": "1.1.0", 309 | "statuses": "1.4.0" 310 | } 311 | }, 312 | "iconv-lite": { 313 | "version": "0.4.19", 314 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 315 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" 316 | }, 317 | "indexof": { 318 | "version": "0.0.1", 319 | "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", 320 | "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" 321 | }, 322 | "inherits": { 323 | "version": "2.0.3", 324 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 325 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 326 | }, 327 | "ipaddr.js": { 328 | "version": "1.6.0", 329 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", 330 | "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=" 331 | }, 332 | "isarray": { 333 | "version": "2.0.1", 334 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", 335 | "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" 336 | }, 337 | "media-typer": { 338 | "version": "0.3.0", 339 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 340 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 341 | }, 342 | "merge-descriptors": { 343 | "version": "1.0.1", 344 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 345 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 346 | }, 347 | "methods": { 348 | "version": "1.1.2", 349 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 350 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 351 | }, 352 | "mime": { 353 | "version": "1.4.1", 354 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 355 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 356 | }, 357 | "mime-db": { 358 | "version": "1.33.0", 359 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", 360 | "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" 361 | }, 362 | "mime-types": { 363 | "version": "2.1.18", 364 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", 365 | "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", 366 | "requires": { 367 | "mime-db": "1.33.0" 368 | } 369 | }, 370 | "moment": { 371 | "version": "2.22.2", 372 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", 373 | "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" 374 | }, 375 | "ms": { 376 | "version": "2.0.0", 377 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 378 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 379 | }, 380 | "negotiator": { 381 | "version": "0.6.1", 382 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 383 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 384 | }, 385 | "object-component": { 386 | "version": "0.0.3", 387 | "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", 388 | "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" 389 | }, 390 | "on-finished": { 391 | "version": "2.3.0", 392 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 393 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 394 | "requires": { 395 | "ee-first": "1.1.1" 396 | } 397 | }, 398 | "parseqs": { 399 | "version": "0.0.5", 400 | "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", 401 | "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", 402 | "requires": { 403 | "better-assert": "1.0.2" 404 | } 405 | }, 406 | "parseuri": { 407 | "version": "0.0.5", 408 | "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", 409 | "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", 410 | "requires": { 411 | "better-assert": "1.0.2" 412 | } 413 | }, 414 | "parseurl": { 415 | "version": "1.3.2", 416 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 417 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 418 | }, 419 | "path-to-regexp": { 420 | "version": "0.1.7", 421 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 422 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 423 | }, 424 | "proxy-addr": { 425 | "version": "2.0.3", 426 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", 427 | "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", 428 | "requires": { 429 | "forwarded": "0.1.2", 430 | "ipaddr.js": "1.6.0" 431 | } 432 | }, 433 | "qs": { 434 | "version": "6.5.1", 435 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 436 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" 437 | }, 438 | "range-parser": { 439 | "version": "1.2.0", 440 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 441 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 442 | }, 443 | "raw-body": { 444 | "version": "2.3.2", 445 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", 446 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", 447 | "requires": { 448 | "bytes": "3.0.0", 449 | "http-errors": "1.6.2", 450 | "iconv-lite": "0.4.19", 451 | "unpipe": "1.0.0" 452 | }, 453 | "dependencies": { 454 | "depd": { 455 | "version": "1.1.1", 456 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 457 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" 458 | }, 459 | "http-errors": { 460 | "version": "1.6.2", 461 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", 462 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", 463 | "requires": { 464 | "depd": "1.1.1", 465 | "inherits": "2.0.3", 466 | "setprototypeof": "1.0.3", 467 | "statuses": "1.4.0" 468 | } 469 | }, 470 | "setprototypeof": { 471 | "version": "1.0.3", 472 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", 473 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" 474 | } 475 | } 476 | }, 477 | "safe-buffer": { 478 | "version": "5.1.1", 479 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 480 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 481 | }, 482 | "send": { 483 | "version": "0.16.2", 484 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", 485 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", 486 | "requires": { 487 | "debug": "2.6.9", 488 | "depd": "1.1.2", 489 | "destroy": "1.0.4", 490 | "encodeurl": "1.0.2", 491 | "escape-html": "1.0.3", 492 | "etag": "1.8.1", 493 | "fresh": "0.5.2", 494 | "http-errors": "1.6.3", 495 | "mime": "1.4.1", 496 | "ms": "2.0.0", 497 | "on-finished": "2.3.0", 498 | "range-parser": "1.2.0", 499 | "statuses": "1.4.0" 500 | } 501 | }, 502 | "serve-static": { 503 | "version": "1.13.2", 504 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", 505 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", 506 | "requires": { 507 | "encodeurl": "1.0.2", 508 | "escape-html": "1.0.3", 509 | "parseurl": "1.3.2", 510 | "send": "0.16.2" 511 | } 512 | }, 513 | "setprototypeof": { 514 | "version": "1.1.0", 515 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 516 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 517 | }, 518 | "socket.io": { 519 | "version": "2.1.1", 520 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", 521 | "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", 522 | "requires": { 523 | "debug": "3.1.0", 524 | "engine.io": "3.2.0", 525 | "has-binary2": "1.0.3", 526 | "socket.io-adapter": "1.1.1", 527 | "socket.io-client": "2.1.1", 528 | "socket.io-parser": "3.2.0" 529 | }, 530 | "dependencies": { 531 | "debug": { 532 | "version": "3.1.0", 533 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 534 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 535 | "requires": { 536 | "ms": "2.0.0" 537 | } 538 | } 539 | } 540 | }, 541 | "socket.io-adapter": { 542 | "version": "1.1.1", 543 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", 544 | "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" 545 | }, 546 | "socket.io-client": { 547 | "version": "2.1.1", 548 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", 549 | "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", 550 | "requires": { 551 | "backo2": "1.0.2", 552 | "base64-arraybuffer": "0.1.5", 553 | "component-bind": "1.0.0", 554 | "component-emitter": "1.2.1", 555 | "debug": "3.1.0", 556 | "engine.io-client": "3.2.1", 557 | "has-binary2": "1.0.3", 558 | "has-cors": "1.1.0", 559 | "indexof": "0.0.1", 560 | "object-component": "0.0.3", 561 | "parseqs": "0.0.5", 562 | "parseuri": "0.0.5", 563 | "socket.io-parser": "3.2.0", 564 | "to-array": "0.1.4" 565 | }, 566 | "dependencies": { 567 | "debug": { 568 | "version": "3.1.0", 569 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 570 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 571 | "requires": { 572 | "ms": "2.0.0" 573 | } 574 | } 575 | } 576 | }, 577 | "socket.io-parser": { 578 | "version": "3.2.0", 579 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", 580 | "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", 581 | "requires": { 582 | "component-emitter": "1.2.1", 583 | "debug": "3.1.0", 584 | "isarray": "2.0.1" 585 | }, 586 | "dependencies": { 587 | "debug": { 588 | "version": "3.1.0", 589 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 590 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 591 | "requires": { 592 | "ms": "2.0.0" 593 | } 594 | } 595 | } 596 | }, 597 | "statuses": { 598 | "version": "1.4.0", 599 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 600 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 601 | }, 602 | "to-array": { 603 | "version": "0.1.4", 604 | "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", 605 | "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" 606 | }, 607 | "type-is": { 608 | "version": "1.6.16", 609 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", 610 | "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", 611 | "requires": { 612 | "media-typer": "0.3.0", 613 | "mime-types": "2.1.18" 614 | } 615 | }, 616 | "ultron": { 617 | "version": "1.1.1", 618 | "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", 619 | "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" 620 | }, 621 | "unpipe": { 622 | "version": "1.0.0", 623 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 624 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 625 | }, 626 | "utils-merge": { 627 | "version": "1.0.1", 628 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 629 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 630 | }, 631 | "vary": { 632 | "version": "1.1.2", 633 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 634 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 635 | }, 636 | "ws": { 637 | "version": "3.3.3", 638 | "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", 639 | "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", 640 | "requires": { 641 | "async-limiter": "1.0.0", 642 | "safe-buffer": "5.1.1", 643 | "ultron": "1.1.1" 644 | } 645 | }, 646 | "xmlhttprequest-ssl": { 647 | "version": "1.5.5", 648 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", 649 | "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" 650 | }, 651 | "yeast": { 652 | "version": "0.1.2", 653 | "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", 654 | "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" 655 | } 656 | } 657 | } 658 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "express": "^4.16.3", 14 | "moment": "^2.22.2", 15 | "socket.io": "^2.1.1" 16 | } 17 | } 18 | --------------------------------------------------------------------------------