├── server
├── public
├── app
│ ├── service
│ │ ├── __init__.py
│ │ ├── task.py
│ │ └── github.py
│ ├── __init__.py
│ ├── views
│ │ ├── tasks.py
│ │ ├── auth.py
│ │ └── __init__.py
│ ├── config.py
│ └── models.py
├── requirements
│ ├── docker.txt
│ ├── general.txt
│ ├── dev.txt
│ └── constraints.txt
├── .gitignore
├── gunicorn_entrypoint.py
├── templates
│ ├── index.html
│ ├── login.html
│ └── base.html
├── tests
│ └── __init__.py
├── Dockerfile
└── manage.py
├── anim.gif
├── front
├── img
│ ├── kobin.png
│ └── favicon.ico
├── ts
│ ├── task.model.ts
│ ├── main.ts
│ ├── task.component.ts
│ ├── task.service.ts
│ ├── task-detail.component.ts
│ └── task-list.component.ts
├── .gitignore
├── README.md
├── tsconfig.json
├── Dockerfile
├── package.json
├── stylus
│ └── style.styl
└── yarn.lock
├── .gitignore
├── envrc
├── LICENSE
├── docker-compose.yml
└── README.md
/server/public:
--------------------------------------------------------------------------------
1 | ../front/public
--------------------------------------------------------------------------------
/server/app/service/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/anim.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kobinpy/kobin-todo/HEAD/anim.gif
--------------------------------------------------------------------------------
/front/img/kobin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kobinpy/kobin-todo/HEAD/front/img/kobin.png
--------------------------------------------------------------------------------
/front/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kobinpy/kobin-todo/HEAD/front/img/favicon.ico
--------------------------------------------------------------------------------
/server/requirements/docker.txt:
--------------------------------------------------------------------------------
1 | -r ./general.txt
2 | click
3 | gunicorn
4 | wsgi-static-middleware
5 |
--------------------------------------------------------------------------------
/server/requirements/general.txt:
--------------------------------------------------------------------------------
1 | kobin
2 | jinja2
3 | requests
4 | redis
5 | SQLAlchemy
6 | psycopg2
7 |
--------------------------------------------------------------------------------
/server/requirements/dev.txt:
--------------------------------------------------------------------------------
1 | flake8
2 | coverage
3 | click
4 | wsgicli
5 | wsgi_static_middleware
6 | ipython
7 |
--------------------------------------------------------------------------------
/front/ts/task.model.ts:
--------------------------------------------------------------------------------
1 | export class Task {
2 | id: number;
3 | title: string;
4 | detail: string;
5 | done: boolean;
6 | }
7 |
--------------------------------------------------------------------------------
/front/.gitignore:
--------------------------------------------------------------------------------
1 | ### node
2 | node_modules/
3 | public/
4 | ts/*.js
5 | *.js.map
6 | npm-debug.log
7 |
8 | ### Scss
9 | .sass-cache
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### IntelliJ IDEA
2 | .idea/
3 |
4 | ### DB
5 | db.sqlite3
6 | db.sqlite3.*
7 |
8 | ### sandbox
9 | sandbox/
10 |
11 | ### direnv
12 | .envrc
13 |
--------------------------------------------------------------------------------
/server/app/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 | from kobin import Kobin, load_config_from_pyfile
3 | from . import views
4 |
5 | config = load_config_from_pyfile(os.environ.get('KOBIN_SETTINGS_FILE', 'app/config.py'))
6 | app = Kobin(config=config)
7 | views.setup_routing(app)
8 |
--------------------------------------------------------------------------------
/front/ts/main.ts:
--------------------------------------------------------------------------------
1 | import "es6-shim";
2 | import "reflect-metadata";
3 | import "rxjs/Rx";
4 | import "zone.js/dist/zone";
5 |
6 | import {bootstrap} from "angular2/platform/browser";
7 | import {TaskComponent} from './task.component'
8 |
9 | bootstrap(TaskComponent);
10 |
--------------------------------------------------------------------------------
/envrc:
--------------------------------------------------------------------------------
1 | export KOBIN_TODO_ENV=develop
2 | export REDIS_PASSWORD=password
3 | export POSTGRES_PASSWORD=password
4 | export SECRET_KEY=secret
5 |
6 | export KOBIN_TODO_GITHUB_CLIENT_ID=xxxxxxxxxxxxxxxxxxxx
7 | export KOBIN_TODO_GITHUB_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
8 |
--------------------------------------------------------------------------------
/server/.gitignore:
--------------------------------------------------------------------------------
1 | ### Python template
2 |
3 | __pycache__/
4 | venv/
5 |
6 | # Installer logs
7 | pip-log.txt
8 | pip-delete-this-directory.txt
9 |
10 | # Unit test / coverage reports
11 | htmlcov/
12 | .tox/
13 | .coverage
14 | .coverage.*
15 | .cache
16 | nosetests.xml
17 | coverage.xml
18 | *,cover
19 |
--------------------------------------------------------------------------------
/server/gunicorn_entrypoint.py:
--------------------------------------------------------------------------------
1 | from app import app
2 | from os import path
3 | from wsgi_static_middleware import StaticMiddleware
4 |
5 | # Enable wsgi static middleware
6 | BASE_DIR = path.dirname(path.abspath(__name__))
7 | PUBLIC_DIR = path.join(BASE_DIR, 'public')
8 |
9 | app = StaticMiddleware(app, static_root='/static', static_dirs=[PUBLIC_DIR])
10 |
--------------------------------------------------------------------------------
/front/README.md:
--------------------------------------------------------------------------------
1 | # kobin todo front
2 |
3 | Frontend for Kobin TODO.
4 |
5 | ## Requirements
6 |
7 | - node 7.3
8 | - yarn
9 |
10 | ## How to build without Docker
11 |
12 | ```console
13 | $ npm install
14 | $ npm run build
15 | ```
16 |
17 | ## Update yarn.lock and package.json
18 |
19 | ```console
20 | $ npm install -g npm-check-updates
21 | $ ncu
22 | $ npm update
23 | ```
24 |
--------------------------------------------------------------------------------
/front/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es6",
5 | "noImplicitAny": false,
6 | "sourceMap": true,
7 | "moduleResolution": "node",
8 | "experimentalDecorators": true,
9 | "emitDecoratorMetadata": true
10 | },
11 | "exclude": [
12 | "node_modules"
13 | ],
14 | "files": [
15 | "./ts/main.ts"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/front/ts/task.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from 'angular2/core'
2 | import {HTTP_PROVIDERS} from 'angular2/http'
3 |
4 | import {TaskListComponent} from './task-list.component'
5 |
6 | @Component({
7 | selector: 'app-task',
8 | template: `
9 | Now loading...
10 | `,
11 | providers: [HTTP_PROVIDERS],
12 | directives: [TaskListComponent]
13 | })
14 | export class TaskComponent {
15 | }
16 |
--------------------------------------------------------------------------------
/server/templates/index.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block title %}Kobin TODO{% endblock %}
4 |
5 | {% block head %}
6 | {{ super() }}
7 |
8 |
9 | {% endblock %}
10 |
11 | {% block body %}
12 | Loading...
13 | {% endblock %}
14 |
15 | {% block extrafooter %}
16 | {{ super() }}
17 |
18 | {% endblock %}
19 |
--------------------------------------------------------------------------------
/front/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:7.3
2 |
3 | RUN mkdir -p /usr/src/public
4 | WORKDIR /usr/src
5 |
6 | ADD ./package.json /usr/src/package.json
7 | ADD ./yarn.lock /usr/src/yarn.lock
8 |
9 | RUN npm install -g yarn && \
10 | npm install
11 |
12 | ADD ./img /usr/src/img
13 | ADD ./stylus /usr/src/stylus
14 | ADD ./ts /usr/src/ts
15 | ADD ./tsconfig.json /usr/src/tsconfig.json
16 |
17 | RUN npm run build
18 |
19 | # Shared folder should enable after npm build.
20 | VOLUME /usr/src/public
21 |
--------------------------------------------------------------------------------
/server/templates/login.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block title %}Kobin TODO{% endblock %}
4 |
5 | {% block head %}
6 | {{ super() }}
7 |
8 |
9 | {% endblock %}
10 |
11 | {% block body %}
12 |
16 | {% endblock %}
17 |
--------------------------------------------------------------------------------
/server/tests/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import unittest
4 | import coverage
5 |
6 |
7 | def run():
8 | os.environ['KOBIN_SETTINGS_FILE'] = 'config/tests.py'
9 |
10 | # start coverage engine
11 | cov = coverage.Coverage(branch=True)
12 | cov.start()
13 |
14 | # run tests
15 | tests = unittest.TestLoader().discover('.')
16 | ok = unittest.TextTestRunner(verbosity=2).run(tests).wasSuccessful()
17 |
18 | # print coverage report
19 | cov.stop()
20 | print('')
21 | cov.report(omit=['manage.py', 'tests/*', 'venv/*', 'config/*'])
22 |
23 | sys.exit(0 if ok else 1)
24 |
--------------------------------------------------------------------------------
/server/requirements/constraints.txt:
--------------------------------------------------------------------------------
1 | appnope==0.1.0
2 | click==6.6
3 | coverage==4.2
4 | decorator==4.0.10
5 | flake8==3.2.1
6 | ipython==5.1.0
7 | ipython-genutils==0.1.0
8 | Jinja2==2.8
9 | kobin==0.1.3
10 | MarkupSafe==0.23
11 | mccabe==0.5.3
12 | pexpect==4.2.1
13 | pickleshare==0.7.4
14 | prompt-toolkit==1.0.9
15 | psycopg2==2.6.2
16 | ptyprocess==0.5.1
17 | pycodestyle==2.2.0
18 | pyflakes==1.3.0
19 | Pygments==2.1.3
20 | redis==2.10.5
21 | requests==2.12.4
22 | simplegeneric==0.8.1
23 | six==1.10.0
24 | SQLAlchemy==1.1.4
25 | traitlets==4.3.1
26 | wcwidth==0.1.7
27 | wsgi-lineprof==0.2.0
28 | wsgi-static-middleware==0.1.1
29 | wsgicli==0.4.0
30 |
--------------------------------------------------------------------------------
/server/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.6-slim
2 | MAINTAINER Masashi Shibata
3 |
4 | RUN apt-get update && apt-get install -y --no-install-recommends git gcc libpq-dev && \
5 | rm -rf /var/lib/apt/lists/*
6 |
7 | RUN pip install --upgrade pip
8 | ADD requirements /usr/src/requirements
9 | RUN pip install \
10 | -c /usr/src/requirements/constraints.txt \
11 | -r /usr/src/requirements/docker.txt
12 |
13 | ADD ./app /usr/src/app
14 | ADD ./templates /usr/src/templates
15 | ADD ./manage.py /usr/src/manage.py
16 | ADD ./gunicorn_entrypoint.py /usr/src/gunicorn_entrypoint.py
17 |
18 | WORKDIR /usr/src
19 | EXPOSE 80
20 | CMD ["gunicorn", "-w", "1", "-b", ":80", "gunicorn_entrypoint:app"]
21 |
--------------------------------------------------------------------------------
/server/templates/base.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {% block head %}
6 | {% block title %}{% endblock %} - Kobin
7 |
8 |
9 | {% endblock %}
10 |
11 |
12 | {% block body %}
13 | {% endblock %}
14 | {% block extrafooter %}
15 |
16 | {% endblock %}
17 |
18 |
19 |
--------------------------------------------------------------------------------
/server/app/views/tasks.py:
--------------------------------------------------------------------------------
1 | from kobin import request, Response, JSONResponse, HTTPError
2 |
3 | from ..service import task as task_service
4 |
5 |
6 | def task_list():
7 | tasks = [t.serialize for t in task_service.retrieve_tasks()]
8 | return JSONResponse({'tasks': tasks})
9 |
10 |
11 | def create_task():
12 | new_task = task_service.create_task(title=request.json['title'])
13 | return JSONResponse(new_task.serialize)
14 |
15 |
16 | def get_task(task_id: int):
17 | task = task_service.retrieve_task(task_id)
18 | if task is None:
19 | raise HTTPError(f"Not found: {request.path}", 404)
20 | return JSONResponse(task.serialize)
21 |
22 |
23 | def update_task(task_id: int):
24 | updated_task = task_service.update_task(task_id, request.json['task'])
25 | return JSONResponse(updated_task.serialize)
26 |
27 |
28 | def delete_task(task_id: int):
29 | if not task_service.delete_task(task_id):
30 | raise HTTPError("Task is not found.", 404)
31 | return Response('', status=204)
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 MASASHI Shibata
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 |
--------------------------------------------------------------------------------
/front/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "kobin-todo",
3 | "version": "0.0.1",
4 | "description": "Todo application in Kobin python web-framework.",
5 | "scripts": {
6 | "dir": "mkdir -p ./public/img ./public/js ./public/css",
7 | "tsc": "tsc -p .",
8 | "browserify": "browserify ./ts/main.js -o ./public/js/bundle.js",
9 | "stylus": "stylus ./stylus/style.styl -o ./public/css/style.css",
10 | "img": "cp -r ./img/ ./public/img",
11 | "build": "npm run dir && npm run tsc && npm run browserify && npm run stylus && npm run img"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/c-bata/kobin-todo.git"
16 | },
17 | "keywords": [],
18 | "author": "c-bata",
19 | "license": "MIT",
20 | "bugs": {
21 | "url": "https://github.com/c-bata/kobin-example/issues"
22 | },
23 | "homepage": "https://github.com/c-bata/kobin-example#readme",
24 | "dependencies": {
25 | "angular2": "^2.0.0-beta.15",
26 | "es6-shim": "^0.35.0",
27 | "reflect-metadata": "^0.1.2",
28 | "rxjs": "^5.0.0-beta.2",
29 | "typescript": "^2.1.4",
30 | "zone.js": "^0.7.4"
31 | },
32 | "devDependencies": {
33 | "browserify": "^13.0.0",
34 | "stylus": "^0.54.5"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/server/app/service/task.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, Any, List
2 | from kobin import HTTPError
3 | from .. import app, models
4 | from ..service import github as github_service
5 |
6 |
7 | def retrieve_tasks() -> List[models.Task]:
8 | session = app.config["SESSION"]
9 | return session.query(models.Task).all()
10 |
11 |
12 | def create_task(title: str=None) -> models.Task:
13 | user = github_service.current_user()
14 | if user is None:
15 | raise HTTPError(body='You are not logged in.', status=401)
16 |
17 | new_task = models.Task(title=title, user_id=user.id)
18 | session = app.config["SESSION"]
19 | session.add(new_task)
20 | session.commit()
21 | return new_task
22 |
23 |
24 | def retrieve_task(task_id) -> models.Task:
25 | session = app.config["SESSION"]
26 | return session.query(models.Task).get(task_id)
27 |
28 |
29 | def update_task(task_id: int, new_task: Dict[str, Any]) -> models.Task:
30 | task = retrieve_task(task_id)
31 | task.update(**new_task)
32 | session = app.config["SESSION"]
33 | session.add(task)
34 | session.commit()
35 | return task
36 |
37 |
38 | def delete_task(task_id: int) -> bool:
39 | task = retrieve_task(task_id)
40 | if task is None:
41 | return False
42 | session = app.config["SESSION"]
43 | session.delete(task)
44 | session.commit()
45 | return True
46 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | server:
4 | container_name: kobin_server
5 | build:
6 | context: ./server
7 | environment:
8 | - REDIS_HOST=redis
9 | - REDIS_PORT=6379
10 | - REDIS_DB=0
11 | - POSTGRES_HOST=postgres
12 | - POSTGRES_USER=kobin
13 | - POSTGRES_NAME=kobintodo
14 |
15 | - SECRET_KEY
16 | - REDIS_PASSWORD
17 | - POSTGRES_PASSWORD
18 | - KOBIN_TODO_GITHUB_CLIENT_ID
19 | - KOBIN_TODO_GITHUB_CLIENT_SECRET
20 | links:
21 | - postgres
22 | - redis
23 | ports:
24 | - "8080:80"
25 | volumes_from:
26 | - front
27 | command: gunicorn -w 1 -b :80 --reload --log-level debug gunicorn_entrypoint:app
28 |
29 | front:
30 | container_name: kobin_front
31 | build:
32 | context: ./front
33 | volumes:
34 | - ./front/public:/usr/src/public
35 | - /usr/src/public
36 |
37 | postgres:
38 | image: postgres:latest
39 | container_name: kobin_postgres
40 | environment:
41 | - POSTGRES_USER=kobin
42 | - POSTGRES_DB=kobintodo
43 | - POSTGRES_PASSWORD
44 | ports:
45 | - "5432:5432"
46 |
47 | redis:
48 | image: redis:latest
49 | container_name: kobin_redis
50 | environment:
51 | - REDIS_PASSWORD
52 | ports:
53 | - "6379:6379"
54 | command: redis-server --requirepass ${REDIS_PASSWORD}
55 |
--------------------------------------------------------------------------------
/server/manage.py:
--------------------------------------------------------------------------------
1 | import click
2 | import subprocess
3 | import sys
4 |
5 | from app import app
6 |
7 |
8 | @click.group()
9 | def cli():
10 | """This is a management script for the kobin-todo application."""
11 | pass
12 |
13 |
14 | @cli.command()
15 | def migrate():
16 | """Runs database migrations."""
17 | from app.models import Base
18 | metadata = Base.metadata
19 | engine = app.config.get("SQLALCHEMY_ENGINE")
20 | metadata.create_all(engine)
21 |
22 |
23 | @cli.command()
24 | def run():
25 | """Runs server."""
26 | subprocess.call(['wsgicli', 'run', 'app/__init__.py', 'app',
27 | '-p', '8080', '--reload',
28 | '--static', '--static-root', '/static/',
29 | '--static-dirs', './public/'])
30 |
31 |
32 | @cli.command()
33 | def shell():
34 | """Run shell"""
35 | subprocess.call(['wsgicli', 'shell', 'manage.py', 'app', '-i', '--models', 'ipython'])
36 |
37 |
38 | @cli.command()
39 | def lint():
40 | """Runs code linter."""
41 | lint = subprocess.call(['flake8', '--ignore=E501', 'app/', 'manage.py'])
42 | if lint:
43 | print("OK")
44 | sys.exit(lint)
45 |
46 |
47 | @cli.command()
48 | def test():
49 | """Runs unit tests."""
50 | tests = subprocess.call(['python', '-c', 'import tests; tests.run()'])
51 | sys.exit(tests)
52 |
53 | if __name__ == '__main__':
54 | cli()
55 |
--------------------------------------------------------------------------------
/server/app/views/auth.py:
--------------------------------------------------------------------------------
1 | from kobin import request, RedirectResponse
2 | from datetime import timedelta
3 |
4 | from .. import app
5 | from ..service import github as github_service
6 |
7 |
8 | def github_oauth_callback():
9 | code = request.query['code']
10 | payload = {
11 | "client_id": app.config.get('GITHUB_CLIENT_ID'),
12 | "client_secret": app.config.get('GITHUB_CLIENT_SECRET'),
13 | "code": code,
14 | }
15 | access_token = github_service.get_access_token(payload)
16 | user_info = github_service.get_github_user_info(access_token)
17 | user = github_service.get_or_create_user(
18 | nickname=user_info['login'],
19 | name=user_info['name'],
20 | avatar_url=user_info['avatar_url'],
21 | auth_service='github',
22 | auth_service_id=user_info['id'],
23 | email=user_info['email'],
24 | )
25 |
26 | r = app.config.get('REDIS')
27 | r.set('access_token_{id}'.format(id=user.id), access_token)
28 | response = RedirectResponse(app.router.reverse('top'))
29 | response.set_cookie("user_id", f"access_token_{user.id}",
30 | max_age=timedelta(days=1), path='/',
31 | secret=app.config['SECRET_KEY'])
32 | return response
33 |
34 |
35 | def logout():
36 | response = RedirectResponse(app.router.reverse('top'))
37 | response.delete_cookie('user_id')
38 | return response
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # kobin-todo
2 |
3 | Todo application using Kobin.
4 |
5 | 
6 |
7 | ## Running Kobin TODO by Docker
8 |
9 | Set Environment Variables.
10 |
11 | ```sh
12 | export KOBIN_TODO_GITHUB_CLIENT_ID=xxxxxxxxxxxxxxxxxxxx
13 | export KOBIN_TODO_GITHUB_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
14 | ```
15 |
16 | Run with Docker.
17 |
18 | ```console
19 | $ docker-compose build
20 | $ docker-compose up -d
21 | $ docker-compose run server python manage.py migrate
22 | ```
23 |
24 | Other:
25 |
26 | - bash: `docker-compose exec server /bin/bash`
27 | - logs: `docker-compose logs -f server`
28 | - psql: `psql -h localhost --user kobin kobintodo`
29 |
30 |
31 | ## How to build
32 |
33 | Set Environment Variables
34 |
35 | ```sh
36 | export KOBIN_TODO_ENV=develop
37 | export KOBIN_TODO_GITHUB_CLIENT_ID=xxxxxxxxxxxxxxxxxxxx
38 | export KOBIN_TODO_GITHUB_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
39 | ```
40 |
41 | Compile TypeScript and Stylus
42 |
43 | ```console
44 | $ cd front
45 | $ npm install
46 | $ npm run build
47 | ```
48 |
49 | Run redis and postgresql
50 |
51 | ```console
52 | $ docker-compose up -d redis postgres
53 | ```
54 |
55 | Setup python interpreter
56 |
57 | ```console
58 | $ python3.6 -m venv venv
59 | $ source venv/bin/activate
60 | $ pip install -c requirements/constraints.txt -r requirements/general.txt -r requirements.dev.txt
61 | $ python manage.py migrate
62 | ```
63 |
64 | Run
65 |
66 | ```console
67 | $ python manage.py run
68 | ```
69 |
--------------------------------------------------------------------------------
/server/app/views/__init__.py:
--------------------------------------------------------------------------------
1 | def setup_routing(app):
2 | from kobin import TemplateResponse, request, HTTPError
3 | from . import tasks
4 | from . import auth
5 |
6 | # tasks
7 | app.route('/api/tasks', 'GET', 'task-list', tasks.task_list)
8 | app.route('/api/tasks', 'POST', 'task-create', tasks.create_task)
9 | app.route('/api/tasks/{task_id}', 'GET', 'task-detail', tasks.get_task)
10 | app.route('/api/tasks/{task_id}', 'PATCH', 'task-task-update', tasks.update_task)
11 | app.route('/api/tasks/{task_id}', 'DELETE', 'task-delete', tasks.delete_task)
12 |
13 | # auth
14 | app.route('/auth/github/callback', 'GET', 'github-callback', auth.github_oauth_callback)
15 | app.route('/logout', 'GET', '/', auth.logout)
16 |
17 | @app.route('/', method='GET', name='top')
18 | def index():
19 | if request.environ.get('kobin.user'):
20 | return TemplateResponse('index.html')
21 | return TemplateResponse('login.html', client_id=app.config['GITHUB_CLIENT_ID'])
22 |
23 | @app.before_request
24 | def before():
25 | redis_access_token_key = request.get_cookie("user_id", default=None,
26 | secret=app.config['SECRET_KEY'])
27 | request.environ['kobin.user'] = redis_access_token_key
28 |
29 | @app.after_request
30 | def after(response):
31 | if isinstance(response, HTTPError):
32 | s = app.config['DB']['SESSION']
33 | s.rollback()
34 | return response
35 |
--------------------------------------------------------------------------------
/front/stylus/style.styl:
--------------------------------------------------------------------------------
1 | .sidebar
2 | position: fixed;
3 | width: 300px;
4 | top: 0;
5 | left: 0;
6 | height: 100%;
7 |
8 | color: #eee;
9 | background-color: #389adc;
10 |
11 | .task-titles
12 | height: calc(100% - 170px - 100px);
13 | overflow-y: auto;
14 | margin-top: 170px;
15 | padding: 10px;
16 |
17 | .sidebar-top
18 | position: absolute;
19 | left: 0;
20 | top: 0;
21 | width: 100%;
22 |
23 | .logo
24 | width: 100%;
25 | padding: 30px;
26 |
27 | footer
28 | position: absolute;
29 | left: 0;
30 | bottom: 0;
31 | width: 100%;
32 | height: 100px;
33 |
34 | display: flex;
35 | display: -webkit-flex;
36 | flex-direction: column;
37 | -webkit-flex-direction: column;
38 | align-items: center;
39 | -webkit-align-items: center;
40 |
41 | a
42 | color: #ddd;
43 |
44 | html, body
45 | height: 100%;
46 |
47 | .top-container
48 | width: 100%;
49 | height: 100%;
50 | background: #4990E2;
51 |
52 | display: flex;
53 | display: -webkit-flex;
54 |
55 | flex-direction: column;
56 | -webkit-flex-direction: column;
57 | justify-content: center;
58 | -webkit-justify-content: center;
59 | align-items: center;
60 | -webkit-align-items: center;
61 |
62 | .top-logo
63 | width: 300px;
64 | margin: 50px auto;
65 |
66 | .top-oauth-link
67 | font-size: 20px;
68 | color: #EFEFEF;
69 | font-weight: lighter;
70 |
71 | main
72 | padding: 20px;
73 | margin-left: 300px;
74 |
--------------------------------------------------------------------------------
/server/app/service/github.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import json
3 | from typing import Dict
4 | from kobin import request, HTTPError
5 |
6 | from .. import app, models
7 |
8 |
9 | def get_or_create_user(nickname: str, name: str, auth_service: str, avatar_url: str,
10 | auth_service_id: int, email: str) -> models.User:
11 | session = app.config["SESSION"]
12 | user = session.query(models.User).filter_by(
13 | auth_service=auth_service, auth_service_id=auth_service_id
14 | ).first()
15 |
16 | if user is None:
17 | user = models.User(
18 | nickname=nickname,
19 | name=name,
20 | avatar_url=avatar_url,
21 | auth_service=auth_service,
22 | auth_service_id=auth_service_id,
23 | email=email,
24 | )
25 | session.add(user)
26 | session.commit()
27 | return user
28 |
29 |
30 | def current_user() -> models.User:
31 | user_id = int(request.environ['kobin.user'].split('_')[-1])
32 | session = app.config["SESSION"]
33 | return session.query(models.User).get(user_id)
34 |
35 |
36 | def get_github_user_info(access_token: str) -> Dict:
37 | url = "https://api.github.com/user?access_token={token}".format(token=access_token)
38 | res = requests.get(url)
39 | return res.json()
40 |
41 |
42 | def get_access_token(payload: Dict[str, str]):
43 | headers = {'Content-Type': 'application/json'}
44 | res = requests.post('https://github.com/login/oauth/access_token',
45 | data=json.dumps(payload), headers=headers)
46 | if res.status_code != 200:
47 | raise HTTPError("Github authentication error", 500)
48 | res_params = {k: v for k, v in
49 | [p.split('=') for p in res.text.split('&')]}
50 | return res_params['access_token']
51 |
--------------------------------------------------------------------------------
/server/app/config.py:
--------------------------------------------------------------------------------
1 | import os
2 | import redis
3 | from sqlalchemy.orm import sessionmaker
4 | from sqlalchemy import create_engine
5 |
6 | ENV = os.getenv('KOBIN_TODO_ENV')
7 |
8 | BASE_DIR = os.path.dirname(os.path.abspath(__name__))
9 | TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates')]
10 |
11 | # Github
12 | # ======
13 | GITHUB_CLIENT_ID = os.environ.get('KOBIN_TODO_GITHUB_CLIENT_ID')
14 | GITHUB_CLIENT_SECRET = os.environ.get('KOBIN_TODO_GITHUB_CLIENT_SECRET')
15 |
16 |
17 | # Database
18 | # ========
19 | if ENV == 'develop':
20 | REDIS_HOST = 'localhost'
21 | REDIS_PORT = 6379
22 | REDIS_DB = 0
23 | REDIS_PASSWORD = 'password'
24 | SQLALCHEMY_DATABASE_URI = 'postgresql+psycopg2://kobin:password@localhost/kobintodo'
25 | DEBUG = True
26 | SECRET_KEY = b'secretkey'
27 | elif ENV == 'test':
28 | REDIS_HOST = 'localhost'
29 | REDIS_PORT = 6379
30 | REDIS_DB = 0
31 | REDIS_PASSWORD = 'password'
32 | REDIS_PASSWORD = None
33 | SQLALCHEMY_DATABASE_URI = 'sqlite://'
34 | DEBUG = True
35 | SECRET_KEY = b'secretkey'
36 | else:
37 | DEBUG = False
38 | SECRET_KEY = os.environ.get('SECRET_KEY').encode('utf-8')
39 |
40 | REDIS_HOST = os.environ.get('REDIS_HOST')
41 | REDIS_PORT = os.environ.get('REDIS_PORT')
42 | REDIS_PASSWORD = os.environ.get('REDIS_PASSWORD')
43 | REDIS_DB = os.environ.get('REDIS_DB')
44 |
45 | host = os.environ.get('POSTGRES_HOST')
46 | user = os.environ.get('POSTGRES_USER')
47 | password = os.environ.get('POSTGRES_PASSWORD')
48 | db = os.environ.get('POSTGRES_NAME')
49 | SQLALCHEMY_DATABASE_URI = f'postgresql+psycopg2://{user}:{password}@{host}/{db}'
50 |
51 | # SQLAlchemy
52 | Session = sessionmaker()
53 | SQLALCHEMY_ENGINE = create_engine(SQLALCHEMY_DATABASE_URI, echo=True)
54 | Session.configure(bind=SQLALCHEMY_ENGINE)
55 | SQLALCHEMY_SESSION = Session()
56 |
57 | # for Redis
58 | REDIS = redis.StrictRedis(
59 | host=REDIS_HOST,
60 | port=REDIS_PORT,
61 | db=REDIS_DB,
62 | password=REDIS_PASSWORD,
63 | )
64 |
--------------------------------------------------------------------------------
/front/ts/task.service.ts:
--------------------------------------------------------------------------------
1 | import {Task} from './task.model'
2 | import {Injectable} from 'angular2/core'
3 | import {Http, Response, Headers, RequestOptions} from 'angular2/http';
4 | import {Observable} from "rxjs/Observable";
5 |
6 | @Injectable()
7 | export class TaskService {
8 | constructor(
9 | private http: Http
10 | ) { }
11 |
12 | private _tasksUrl = 'api/tasks';
13 | private defaultRequestOptions: RequestOptions = new RequestOptions({
14 | headers: new Headers({ 'Content-Type': 'application/json' }),
15 | });
16 |
17 | getTasks(): Observable {
18 | return this.http.get(this._tasksUrl)
19 | .map(this.extractTasks)
20 | .catch(this.handleError);
21 | }
22 |
23 | addTask(title: string): Observable {
24 | let body = JSON.stringify({ title });
25 | return this.http.post(this._tasksUrl, body, this.defaultRequestOptions)
26 | .map(this.extractTask)
27 | .catch(this.handleError);
28 | }
29 |
30 | updateTask(task: Task): Observable {
31 | let body = JSON.stringify({ task });
32 | return this.http.patch(`api/tasks/${task.id}`, body, this.defaultRequestOptions)
33 | .map(this.extractTask)
34 | .catch(this.handleError)
35 | }
36 |
37 | deleteTask(task: Task): Observable {
38 | return this.http.delete(`api/tasks/${task.id}`, this.defaultRequestOptions)
39 | .map(res => res)
40 | .catch(this.handleError)
41 | }
42 |
43 | private extractTasks(res: Response) {
44 | if (res.status < 200 || res.status >= 300) {
45 | throw new Error('Bad response status: ' + res.status);
46 | }
47 | let body = res.json();
48 | return body.tasks || {};
49 | }
50 |
51 | private extractTask(res: Response) {
52 | if (res.status < 200 || res.status >= 300) {
53 | throw new Error('Bad response status: ' + res.status);
54 | }
55 | let body = res.json();
56 | return body || {};
57 | }
58 |
59 | private handleError(error: any) {
60 | let errMsg = error.message || 'Server error';
61 | console.error(errMsg);
62 | return Observable.throw(errMsg);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/front/ts/task-detail.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, Input} from 'angular2/core'
2 | import {Task} from './task.model'
3 | import {TaskService} from './task.service'
4 |
5 | @Component({
6 | selector: 'app-task-detail',
7 | template: `
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | This task is done.
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | Error:
29 | {{errorMessage}}
30 |
31 |
32 | `,
33 | })
34 | export class TaskDetailComponent {
35 | @Input() task: Task;
36 | @Input() tasks: Task[];
37 | errorMessage: string;
38 |
39 | constructor(
40 | private _taskService: TaskService
41 | ) {}
42 |
43 | updateTask(task: Task) {
44 | this._taskService.updateTask(task)
45 | .subscribe(
46 | task => this.task = task,
47 | error => this.errorMessage = error
48 | );
49 | }
50 |
51 | deleteTask(task: Task) {
52 | let index = this.tasks.indexOf(task);
53 | this._taskService.deleteTask(task)
54 | .subscribe(
55 | res => {
56 | this.tasks.splice(index, 1);
57 | this.task = null;
58 | },
59 | error => this.errorMessage = error
60 | );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/server/app/models.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy.ext import declarative
2 | from datetime import datetime
3 | from sqlalchemy import (
4 | Column, Integer, Unicode, UnicodeText, Boolean, DateTime, ForeignKey
5 | )
6 |
7 | Base = declarative.declarative_base()
8 |
9 |
10 | class User(Base):
11 | __tablename__ = 'users'
12 | id = Column(Integer, primary_key=True)
13 | name = Column(Unicode(255), nullable=False)
14 | nickname = Column(Unicode(255), nullable=False)
15 | email = Column(Unicode(255), nullable=False)
16 | avatar_url = Column(Unicode(512), nullable=False)
17 | auth_service = Column(Unicode(16)) # Now, Support only github.
18 | auth_service_id = Column(Integer, nullable=False)
19 | updated_at = Column(DateTime, default=datetime.now(), nullable=False)
20 | created_at = Column(DateTime, default=datetime.now(), nullable=False)
21 |
22 | def __repr__(self):
23 | return f""
24 |
25 | @property
26 | def serialize(self):
27 | return {
28 | 'id': self.id,
29 | 'name': self.name,
30 | 'nickname': self.name,
31 | 'email': self.email,
32 | 'avatar_url': self.avatar_url,
33 | 'updated_at': self.updated_at.strftime('%Y-%m-%d'),
34 | 'created_at': self.created_at.strftime('%Y-%m-%d'),
35 | }
36 |
37 |
38 | class Task(Base):
39 | __tablename__ = 'tasks'
40 | id = Column(Integer, primary_key=True)
41 | title = Column(Unicode(255), nullable=False)
42 | detail = Column(UnicodeText)
43 | done = Column(Boolean, nullable=False, default=False)
44 | user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
45 | updated_at = Column(DateTime, default=datetime.now(), nullable=False)
46 | created_at = Column(DateTime, default=datetime.now(), nullable=False)
47 |
48 | def __repr__(self):
49 | return f""
50 |
51 | def update(self, title=None, detail=None, done=None, **kwargs):
52 | if title is not None:
53 | self.title = title
54 | if detail is not None:
55 | self.detail = detail
56 | if done is not None:
57 | self.done = done
58 | self.updated_at = datetime.now()
59 |
60 | @property
61 | def serialize(self):
62 | return {
63 | 'id': self.id,
64 | 'title': self.title,
65 | 'detail': self.detail,
66 | 'done': self.done,
67 | 'user_id': self.user_id,
68 | 'updated_at': self.updated_at.strftime('%Y-%m-%d'),
69 | 'created_at': self.created_at.strftime('%Y-%m-%d'),
70 | }
--------------------------------------------------------------------------------
/front/ts/task-list.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, OnInit} from 'angular2/core';
2 |
3 | import {Task} from './task.model'
4 | import {TaskService} from "./task.service";
5 | import {TaskDetailComponent} from './task-detail.component'
6 |
7 | @Component({
8 | selector: 'app-task-list',
9 | template: `
10 |
40 |
41 |
42 |
43 |
44 | `,
45 | providers: [TaskService],
46 | directives: [TaskDetailComponent],
47 | styles: [`
48 | li { list-style: none; padding: 10px 0 10px 20px; }
49 | ul { padding-left: 0px; }
50 | .selected { background-color: #2980b9; }
51 | .task-add { padding: 10px 20px 10px 20px; }
52 | .task-add {
53 | display: flex;
54 | display: -webkit-flex;
55 | flex-flow: row nowrap;
56 | }
57 | .task-add-input {
58 | background: rgba(0, 0, 0, 0.2);
59 | border-color: #ddd;
60 | border-width: 2px;
61 | color: #fff;
62 | border-radius: 0px;
63 | flex-grow: 3;
64 | margin-right: 4px;
65 | }
66 | .task-add-btn {
67 | background: #eee;
68 | color: rgba(0, 0, 0, 0.7);
69 | border-radius: 0px;
70 | }
71 | `],
72 | })
73 | export class TaskListComponent implements OnInit {
74 | tasks: Task[] = [];
75 | selectedTask: Task;
76 | errorMessage: string;
77 |
78 | constructor(
79 | private _taskService: TaskService
80 | ) {}
81 |
82 | getTasks() {
83 | this._taskService.getTasks()
84 | .subscribe(
85 | tasks => this.tasks = tasks,
86 | error => this.errorMessage = error
87 | );
88 | }
89 |
90 | addTask(title: string) {
91 | if (!title) {
92 | return;
93 | }
94 | this._taskService.addTask(title)
95 | .subscribe(
96 | task => {
97 | this.tasks.push(task);
98 | this.selectedTask = task;
99 | },
100 | error => this.errorMessage = error
101 | );
102 | }
103 |
104 | doneTaskLength() {
105 | return this.tasks
106 | .filter(task => task.done)
107 | .length
108 | }
109 |
110 | toggleDone(task: Task) {
111 | task.done = !task.done;
112 | this._taskService.updateTask(task)
113 | .subscribe(
114 | task => {
115 | this.tasks.filter(t => t.id === task.id)
116 | .map(t => t.done = task.done)
117 | },
118 | error => this.errorMessage = error
119 | );
120 | }
121 |
122 | ngOnInit() {
123 | this.getTasks();
124 | }
125 |
126 | onSelect(task: Task) {
127 | this.selectedTask = task;
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/front/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | JSONStream@^1.0.3:
6 | version "1.3.0"
7 | resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.0.tgz#680ab9ac6572a8a1a207e0b38721db1c77b215e5"
8 | dependencies:
9 | jsonparse "^1.2.0"
10 | through ">=2.2.7 <3"
11 |
12 | acorn@^1.0.3:
13 | version "1.2.2"
14 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-1.2.2.tgz#c8ce27de0acc76d896d2b1fad3df588d9e82f014"
15 |
16 | acorn@^2.7.0:
17 | version "2.7.0"
18 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-2.7.0.tgz#ab6e7d9d886aaca8b085bc3312b79a198433f0e7"
19 |
20 | acorn@^3.1.0:
21 | version "3.3.0"
22 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
23 |
24 | amdefine@>=0.0.4:
25 | version "1.0.1"
26 | resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
27 |
28 | angular2@^2.0.0-beta.15:
29 | version "2.0.0-beta.21"
30 | resolved "https://registry.yarnpkg.com/angular2/-/angular2-2.0.0-beta.21.tgz#78643e590641526a2596dcd1d5cca3a5509ed76d"
31 |
32 | array-filter@~0.0.0:
33 | version "0.0.1"
34 | resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec"
35 |
36 | array-map@~0.0.0:
37 | version "0.0.0"
38 | resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662"
39 |
40 | array-reduce@~0.0.0:
41 | version "0.0.0"
42 | resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b"
43 |
44 | asn1.js@^4.0.0:
45 | version "4.9.0"
46 | resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.0.tgz#f71a1243f3e79d46d7b07d7fbf4824ee73af054a"
47 | dependencies:
48 | bn.js "^4.0.0"
49 | inherits "^2.0.1"
50 | minimalistic-assert "^1.0.0"
51 |
52 | assert@~1.3.0:
53 | version "1.3.0"
54 | resolved "https://registry.yarnpkg.com/assert/-/assert-1.3.0.tgz#03939a622582a812cc202320a0b9a56c9b815849"
55 | dependencies:
56 | util "0.10.3"
57 |
58 | astw@^2.0.0:
59 | version "2.0.0"
60 | resolved "https://registry.yarnpkg.com/astw/-/astw-2.0.0.tgz#08121ac8288d35611c0ceec663f6cd545604897d"
61 | dependencies:
62 | acorn "^1.0.3"
63 |
64 | balanced-match@^0.4.1:
65 | version "0.4.2"
66 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
67 |
68 | base64-js@^1.0.2:
69 | version "1.2.0"
70 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
71 |
72 | bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
73 | version "4.11.6"
74 | resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215"
75 |
76 | brace-expansion@^1.0.0:
77 | version "1.1.6"
78 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
79 | dependencies:
80 | balanced-match "^0.4.1"
81 | concat-map "0.0.1"
82 |
83 | brorand@^1.0.1:
84 | version "1.0.6"
85 | resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.0.6.tgz#4028706b915f91f7b349a2e0bf3c376039d216e5"
86 |
87 | browser-pack@^6.0.1:
88 | version "6.0.2"
89 | resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.0.2.tgz#f86cd6cef4f5300c8e63e07a4d512f65fbff4531"
90 | dependencies:
91 | JSONStream "^1.0.3"
92 | combine-source-map "~0.7.1"
93 | defined "^1.0.0"
94 | through2 "^2.0.0"
95 | umd "^3.0.0"
96 |
97 | browser-resolve@^1.11.0, browser-resolve@^1.7.0:
98 | version "1.11.2"
99 | resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce"
100 | dependencies:
101 | resolve "1.1.7"
102 |
103 | browserify-aes@^1.0.0, browserify-aes@^1.0.4:
104 | version "1.0.6"
105 | resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a"
106 | dependencies:
107 | buffer-xor "^1.0.2"
108 | cipher-base "^1.0.0"
109 | create-hash "^1.1.0"
110 | evp_bytestokey "^1.0.0"
111 | inherits "^2.0.1"
112 |
113 | browserify-cipher@^1.0.0:
114 | version "1.0.0"
115 | resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a"
116 | dependencies:
117 | browserify-aes "^1.0.4"
118 | browserify-des "^1.0.0"
119 | evp_bytestokey "^1.0.0"
120 |
121 | browserify-des@^1.0.0:
122 | version "1.0.0"
123 | resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd"
124 | dependencies:
125 | cipher-base "^1.0.1"
126 | des.js "^1.0.0"
127 | inherits "^2.0.1"
128 |
129 | browserify-rsa@^4.0.0:
130 | version "4.0.1"
131 | resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
132 | dependencies:
133 | bn.js "^4.1.0"
134 | randombytes "^2.0.1"
135 |
136 | browserify-sign@^4.0.0:
137 | version "4.0.0"
138 | resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.0.tgz#10773910c3c206d5420a46aad8694f820b85968f"
139 | dependencies:
140 | bn.js "^4.1.1"
141 | browserify-rsa "^4.0.0"
142 | create-hash "^1.1.0"
143 | create-hmac "^1.1.2"
144 | elliptic "^6.0.0"
145 | inherits "^2.0.1"
146 | parse-asn1 "^5.0.0"
147 |
148 | browserify-zlib@~0.1.2:
149 | version "0.1.4"
150 | resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
151 | dependencies:
152 | pako "~0.2.0"
153 |
154 | browserify@^13.0.0:
155 | version "13.1.1"
156 | resolved "https://registry.yarnpkg.com/browserify/-/browserify-13.1.1.tgz#72a2310e2f706ed87db929cf0ee73a5e195d9bb0"
157 | dependencies:
158 | JSONStream "^1.0.3"
159 | assert "~1.3.0"
160 | browser-pack "^6.0.1"
161 | browser-resolve "^1.11.0"
162 | browserify-zlib "~0.1.2"
163 | buffer "^4.1.0"
164 | cached-path-relative "^1.0.0"
165 | concat-stream "~1.5.1"
166 | console-browserify "^1.1.0"
167 | constants-browserify "~1.0.0"
168 | crypto-browserify "^3.0.0"
169 | defined "^1.0.0"
170 | deps-sort "^2.0.0"
171 | domain-browser "~1.1.0"
172 | duplexer2 "~0.1.2"
173 | events "~1.1.0"
174 | glob "^5.0.15"
175 | has "^1.0.0"
176 | htmlescape "^1.1.0"
177 | https-browserify "~0.0.0"
178 | inherits "~2.0.1"
179 | insert-module-globals "^7.0.0"
180 | labeled-stream-splicer "^2.0.0"
181 | module-deps "^4.0.8"
182 | os-browserify "~0.1.1"
183 | parents "^1.0.1"
184 | path-browserify "~0.0.0"
185 | process "~0.11.0"
186 | punycode "^1.3.2"
187 | querystring-es3 "~0.2.0"
188 | read-only-stream "^2.0.0"
189 | readable-stream "^2.0.2"
190 | resolve "^1.1.4"
191 | shasum "^1.0.0"
192 | shell-quote "^1.4.3"
193 | stream-browserify "^2.0.0"
194 | stream-http "^2.0.0"
195 | string_decoder "~0.10.0"
196 | subarg "^1.0.0"
197 | syntax-error "^1.1.1"
198 | through2 "^2.0.0"
199 | timers-browserify "^1.0.1"
200 | tty-browserify "~0.0.0"
201 | url "~0.11.0"
202 | util "~0.10.1"
203 | vm-browserify "~0.0.1"
204 | xtend "^4.0.0"
205 |
206 | buffer-shims@^1.0.0:
207 | version "1.0.0"
208 | resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51"
209 |
210 | buffer-xor@^1.0.2:
211 | version "1.0.3"
212 | resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
213 |
214 | buffer@^4.1.0:
215 | version "4.9.1"
216 | resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
217 | dependencies:
218 | base64-js "^1.0.2"
219 | ieee754 "^1.1.4"
220 | isarray "^1.0.0"
221 |
222 | builtin-status-codes@^2.0.0:
223 | version "2.0.0"
224 | resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-2.0.0.tgz#6f22003baacf003ccd287afe6872151fddc58579"
225 |
226 | cached-path-relative@^1.0.0:
227 | version "1.0.0"
228 | resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.0.tgz#d1094c577fbd9a8b8bd43c96af6188aa205d05f4"
229 |
230 | cipher-base@^1.0.0, cipher-base@^1.0.1:
231 | version "1.0.3"
232 | resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07"
233 | dependencies:
234 | inherits "^2.0.1"
235 |
236 | combine-source-map@~0.7.1:
237 | version "0.7.2"
238 | resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.7.2.tgz#0870312856b307a87cc4ac486f3a9a62aeccc09e"
239 | dependencies:
240 | convert-source-map "~1.1.0"
241 | inline-source-map "~0.6.0"
242 | lodash.memoize "~3.0.3"
243 | source-map "~0.5.3"
244 |
245 | concat-map@0.0.1:
246 | version "0.0.1"
247 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
248 |
249 | concat-stream@~1.5.0, concat-stream@~1.5.1:
250 | version "1.5.2"
251 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266"
252 | dependencies:
253 | inherits "~2.0.1"
254 | readable-stream "~2.0.0"
255 | typedarray "~0.0.5"
256 |
257 | console-browserify@^1.1.0:
258 | version "1.1.0"
259 | resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
260 | dependencies:
261 | date-now "^0.1.4"
262 |
263 | constants-browserify@~1.0.0:
264 | version "1.0.0"
265 | resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
266 |
267 | convert-source-map@~1.1.0:
268 | version "1.1.3"
269 | resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860"
270 |
271 | core-util-is@~1.0.0:
272 | version "1.0.2"
273 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
274 |
275 | create-ecdh@^4.0.0:
276 | version "4.0.0"
277 | resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d"
278 | dependencies:
279 | bn.js "^4.1.0"
280 | elliptic "^6.0.0"
281 |
282 | create-hash@^1.1.0, create-hash@^1.1.1:
283 | version "1.1.2"
284 | resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.2.tgz#51210062d7bb7479f6c65bb41a92208b1d61abad"
285 | dependencies:
286 | cipher-base "^1.0.1"
287 | inherits "^2.0.1"
288 | ripemd160 "^1.0.0"
289 | sha.js "^2.3.6"
290 |
291 | create-hmac@^1.1.0, create-hmac@^1.1.2:
292 | version "1.1.4"
293 | resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.4.tgz#d3fb4ba253eb8b3f56e39ea2fbcb8af747bd3170"
294 | dependencies:
295 | create-hash "^1.1.0"
296 | inherits "^2.0.1"
297 |
298 | crypto-browserify@^3.0.0:
299 | version "3.11.0"
300 | resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522"
301 | dependencies:
302 | browserify-cipher "^1.0.0"
303 | browserify-sign "^4.0.0"
304 | create-ecdh "^4.0.0"
305 | create-hash "^1.1.0"
306 | create-hmac "^1.1.0"
307 | diffie-hellman "^5.0.0"
308 | inherits "^2.0.1"
309 | pbkdf2 "^3.0.3"
310 | public-encrypt "^4.0.0"
311 | randombytes "^2.0.0"
312 |
313 | css-parse@1.7.x:
314 | version "1.7.0"
315 | resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-1.7.0.tgz#321f6cf73782a6ff751111390fc05e2c657d8c9b"
316 |
317 | date-now@^0.1.4:
318 | version "0.1.4"
319 | resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
320 |
321 | debug@*:
322 | version "2.5.2"
323 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.5.2.tgz#50c295a53dbf1657146e0c1b21307275e90d49cb"
324 | dependencies:
325 | ms "0.7.2"
326 |
327 | defined@^1.0.0:
328 | version "1.0.0"
329 | resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
330 |
331 | deps-sort@^2.0.0:
332 | version "2.0.0"
333 | resolved "https://registry.yarnpkg.com/deps-sort/-/deps-sort-2.0.0.tgz#091724902e84658260eb910748cccd1af6e21fb5"
334 | dependencies:
335 | JSONStream "^1.0.3"
336 | shasum "^1.0.0"
337 | subarg "^1.0.0"
338 | through2 "^2.0.0"
339 |
340 | des.js@^1.0.0:
341 | version "1.0.0"
342 | resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
343 | dependencies:
344 | inherits "^2.0.1"
345 | minimalistic-assert "^1.0.0"
346 |
347 | detective@^4.0.0:
348 | version "4.3.2"
349 | resolved "https://registry.yarnpkg.com/detective/-/detective-4.3.2.tgz#77697e2e7947ac3fe7c8e26a6d6f115235afa91c"
350 | dependencies:
351 | acorn "^3.1.0"
352 | defined "^1.0.0"
353 |
354 | diffie-hellman@^5.0.0:
355 | version "5.0.2"
356 | resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e"
357 | dependencies:
358 | bn.js "^4.1.0"
359 | miller-rabin "^4.0.0"
360 | randombytes "^2.0.0"
361 |
362 | domain-browser@~1.1.0:
363 | version "1.1.7"
364 | resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
365 |
366 | duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2:
367 | version "0.1.4"
368 | resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
369 | dependencies:
370 | readable-stream "^2.0.2"
371 |
372 | elliptic@^6.0.0:
373 | version "6.3.2"
374 | resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.2.tgz#e4c81e0829cf0a65ab70e998b8232723b5c1bc48"
375 | dependencies:
376 | bn.js "^4.4.0"
377 | brorand "^1.0.1"
378 | hash.js "^1.0.0"
379 | inherits "^2.0.1"
380 |
381 | es6-shim@^0.35.0:
382 | version "0.35.2"
383 | resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.2.tgz#45c5b3eb2f792ed28f130d826239be50affb897f"
384 |
385 | events@~1.1.0:
386 | version "1.1.1"
387 | resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
388 |
389 | evp_bytestokey@^1.0.0:
390 | version "1.0.0"
391 | resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53"
392 | dependencies:
393 | create-hash "^1.1.1"
394 |
395 | fs.realpath@^1.0.0:
396 | version "1.0.0"
397 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
398 |
399 | function-bind@^1.0.2:
400 | version "1.1.0"
401 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
402 |
403 | glob@7.0.x:
404 | version "7.0.6"
405 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a"
406 | dependencies:
407 | fs.realpath "^1.0.0"
408 | inflight "^1.0.4"
409 | inherits "2"
410 | minimatch "^3.0.2"
411 | once "^1.3.0"
412 | path-is-absolute "^1.0.0"
413 |
414 | glob@^5.0.15:
415 | version "5.0.15"
416 | resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
417 | dependencies:
418 | inflight "^1.0.4"
419 | inherits "2"
420 | minimatch "2 || 3"
421 | once "^1.3.0"
422 | path-is-absolute "^1.0.0"
423 |
424 | has@^1.0.0:
425 | version "1.0.1"
426 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28"
427 | dependencies:
428 | function-bind "^1.0.2"
429 |
430 | hash.js@^1.0.0:
431 | version "1.0.3"
432 | resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573"
433 | dependencies:
434 | inherits "^2.0.1"
435 |
436 | htmlescape@^1.1.0:
437 | version "1.1.1"
438 | resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351"
439 |
440 | https-browserify@~0.0.0:
441 | version "0.0.1"
442 | resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
443 |
444 | ieee754@^1.1.4:
445 | version "1.1.8"
446 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
447 |
448 | indexof@0.0.1:
449 | version "0.0.1"
450 | resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
451 |
452 | inflight@^1.0.4:
453 | version "1.0.6"
454 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
455 | dependencies:
456 | once "^1.3.0"
457 | wrappy "1"
458 |
459 | inherits@2, inherits@^2.0.1, inherits@~2.0.1:
460 | version "2.0.3"
461 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
462 |
463 | inherits@2.0.1:
464 | version "2.0.1"
465 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
466 |
467 | inline-source-map@~0.6.0:
468 | version "0.6.2"
469 | resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5"
470 | dependencies:
471 | source-map "~0.5.3"
472 |
473 | insert-module-globals@^7.0.0:
474 | version "7.0.1"
475 | resolved "https://registry.yarnpkg.com/insert-module-globals/-/insert-module-globals-7.0.1.tgz#c03bf4e01cb086d5b5e5ace8ad0afe7889d638c3"
476 | dependencies:
477 | JSONStream "^1.0.3"
478 | combine-source-map "~0.7.1"
479 | concat-stream "~1.5.1"
480 | is-buffer "^1.1.0"
481 | lexical-scope "^1.2.0"
482 | process "~0.11.0"
483 | through2 "^2.0.0"
484 | xtend "^4.0.0"
485 |
486 | is-buffer@^1.1.0:
487 | version "1.1.4"
488 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b"
489 |
490 | isarray@^1.0.0, isarray@~1.0.0:
491 | version "1.0.0"
492 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
493 |
494 | isarray@~0.0.1:
495 | version "0.0.1"
496 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
497 |
498 | json-stable-stringify@~0.0.0:
499 | version "0.0.1"
500 | resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz#611c23e814db375527df851193db59dd2af27f45"
501 | dependencies:
502 | jsonify "~0.0.0"
503 |
504 | jsonify@~0.0.0:
505 | version "0.0.0"
506 | resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
507 |
508 | jsonparse@^1.2.0:
509 | version "1.2.0"
510 | resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.2.0.tgz#5c0c5685107160e72fe7489bddea0b44c2bc67bd"
511 |
512 | labeled-stream-splicer@^2.0.0:
513 | version "2.0.0"
514 | resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz#a52e1d138024c00b86b1c0c91f677918b8ae0a59"
515 | dependencies:
516 | inherits "^2.0.1"
517 | isarray "~0.0.1"
518 | stream-splicer "^2.0.0"
519 |
520 | lexical-scope@^1.2.0:
521 | version "1.2.0"
522 | resolved "https://registry.yarnpkg.com/lexical-scope/-/lexical-scope-1.2.0.tgz#fcea5edc704a4b3a8796cdca419c3a0afaf22df4"
523 | dependencies:
524 | astw "^2.0.0"
525 |
526 | lodash.memoize@~3.0.3:
527 | version "3.0.4"
528 | resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f"
529 |
530 | miller-rabin@^4.0.0:
531 | version "4.0.0"
532 | resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d"
533 | dependencies:
534 | bn.js "^4.0.0"
535 | brorand "^1.0.1"
536 |
537 | minimalistic-assert@^1.0.0:
538 | version "1.0.0"
539 | resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3"
540 |
541 | "minimatch@2 || 3", minimatch@^3.0.2:
542 | version "3.0.3"
543 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
544 | dependencies:
545 | brace-expansion "^1.0.0"
546 |
547 | minimist@0.0.8:
548 | version "0.0.8"
549 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
550 |
551 | minimist@^1.1.0:
552 | version "1.2.0"
553 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
554 |
555 | mkdirp@0.5.x:
556 | version "0.5.1"
557 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
558 | dependencies:
559 | minimist "0.0.8"
560 |
561 | module-deps@^4.0.8:
562 | version "4.0.8"
563 | resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-4.0.8.tgz#55fd70623399706c3288bef7a609ff1e8c0ed2bb"
564 | dependencies:
565 | JSONStream "^1.0.3"
566 | browser-resolve "^1.7.0"
567 | cached-path-relative "^1.0.0"
568 | concat-stream "~1.5.0"
569 | defined "^1.0.0"
570 | detective "^4.0.0"
571 | duplexer2 "^0.1.2"
572 | inherits "^2.0.1"
573 | parents "^1.0.0"
574 | readable-stream "^2.0.2"
575 | resolve "^1.1.3"
576 | stream-combiner2 "^1.1.1"
577 | subarg "^1.0.0"
578 | through2 "^2.0.0"
579 | xtend "^4.0.0"
580 |
581 | ms@0.7.2:
582 | version "0.7.2"
583 | resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
584 |
585 | once@^1.3.0:
586 | version "1.4.0"
587 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
588 | dependencies:
589 | wrappy "1"
590 |
591 | os-browserify@~0.1.1:
592 | version "0.1.2"
593 | resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.1.2.tgz#49ca0293e0b19590a5f5de10c7f265a617d8fe54"
594 |
595 | pako@~0.2.0:
596 | version "0.2.9"
597 | resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
598 |
599 | parents@^1.0.0, parents@^1.0.1:
600 | version "1.0.1"
601 | resolved "https://registry.yarnpkg.com/parents/-/parents-1.0.1.tgz#fedd4d2bf193a77745fe71e371d73c3307d9c751"
602 | dependencies:
603 | path-platform "~0.11.15"
604 |
605 | parse-asn1@^5.0.0:
606 | version "5.0.0"
607 | resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.0.0.tgz#35060f6d5015d37628c770f4e091a0b5a278bc23"
608 | dependencies:
609 | asn1.js "^4.0.0"
610 | browserify-aes "^1.0.0"
611 | create-hash "^1.1.0"
612 | evp_bytestokey "^1.0.0"
613 | pbkdf2 "^3.0.3"
614 |
615 | path-browserify@~0.0.0:
616 | version "0.0.0"
617 | resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
618 |
619 | path-is-absolute@^1.0.0:
620 | version "1.0.1"
621 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
622 |
623 | path-platform@~0.11.15:
624 | version "0.11.15"
625 | resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2"
626 |
627 | pbkdf2@^3.0.3:
628 | version "3.0.9"
629 | resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.9.tgz#f2c4b25a600058b3c3773c086c37dbbee1ffe693"
630 | dependencies:
631 | create-hmac "^1.1.2"
632 |
633 | process-nextick-args@~1.0.6:
634 | version "1.0.7"
635 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
636 |
637 | process@~0.11.0:
638 | version "0.11.9"
639 | resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1"
640 |
641 | public-encrypt@^4.0.0:
642 | version "4.0.0"
643 | resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6"
644 | dependencies:
645 | bn.js "^4.1.0"
646 | browserify-rsa "^4.0.0"
647 | create-hash "^1.1.0"
648 | parse-asn1 "^5.0.0"
649 | randombytes "^2.0.1"
650 |
651 | punycode@1.3.2:
652 | version "1.3.2"
653 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
654 |
655 | punycode@^1.3.2:
656 | version "1.4.1"
657 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
658 |
659 | querystring-es3@~0.2.0:
660 | version "0.2.1"
661 | resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
662 |
663 | querystring@0.2.0:
664 | version "0.2.0"
665 | resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
666 |
667 | randombytes@^2.0.0, randombytes@^2.0.1:
668 | version "2.0.3"
669 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.3.tgz#674c99760901c3c4112771a31e521dc349cc09ec"
670 |
671 | read-only-stream@^2.0.0:
672 | version "2.0.0"
673 | resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0"
674 | dependencies:
675 | readable-stream "^2.0.2"
676 |
677 | readable-stream@^2.0.2, readable-stream@^2.1.0, readable-stream@^2.1.5:
678 | version "2.2.2"
679 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e"
680 | dependencies:
681 | buffer-shims "^1.0.0"
682 | core-util-is "~1.0.0"
683 | inherits "~2.0.1"
684 | isarray "~1.0.0"
685 | process-nextick-args "~1.0.6"
686 | string_decoder "~0.10.x"
687 | util-deprecate "~1.0.1"
688 |
689 | readable-stream@~2.0.0:
690 | version "2.0.6"
691 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
692 | dependencies:
693 | core-util-is "~1.0.0"
694 | inherits "~2.0.1"
695 | isarray "~1.0.0"
696 | process-nextick-args "~1.0.6"
697 | string_decoder "~0.10.x"
698 | util-deprecate "~1.0.1"
699 |
700 | reflect-metadata@^0.1.2:
701 | version "0.1.9"
702 | resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.9.tgz#987238dc87a516895fe457f130435ffbd763a4d4"
703 |
704 | resolve@1.1.7:
705 | version "1.1.7"
706 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
707 |
708 | resolve@^1.1.3, resolve@^1.1.4:
709 | version "1.2.0"
710 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.2.0.tgz#9589c3f2f6149d1417a40becc1663db6ec6bc26c"
711 |
712 | ripemd160@^1.0.0:
713 | version "1.0.1"
714 | resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-1.0.1.tgz#93a4bbd4942bc574b69a8fa57c71de10ecca7d6e"
715 |
716 | rxjs@^5.0.0-beta.2:
717 | version "5.0.2"
718 | resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.0.2.tgz#cc6513756daa93cab4085c1b5a19a3e28fb6c6bf"
719 | dependencies:
720 | symbol-observable "^1.0.1"
721 |
722 | sax@0.5.x:
723 | version "0.5.8"
724 | resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1"
725 |
726 | sha.js@^2.3.6, sha.js@~2.4.4:
727 | version "2.4.8"
728 | resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f"
729 | dependencies:
730 | inherits "^2.0.1"
731 |
732 | shasum@^1.0.0:
733 | version "1.0.2"
734 | resolved "https://registry.yarnpkg.com/shasum/-/shasum-1.0.2.tgz#e7012310d8f417f4deb5712150e5678b87ae565f"
735 | dependencies:
736 | json-stable-stringify "~0.0.0"
737 | sha.js "~2.4.4"
738 |
739 | shell-quote@^1.4.3:
740 | version "1.6.1"
741 | resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767"
742 | dependencies:
743 | array-filter "~0.0.0"
744 | array-map "~0.0.0"
745 | array-reduce "~0.0.0"
746 | jsonify "~0.0.0"
747 |
748 | source-map@0.1.x:
749 | version "0.1.43"
750 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346"
751 | dependencies:
752 | amdefine ">=0.0.4"
753 |
754 | source-map@~0.5.3:
755 | version "0.5.6"
756 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
757 |
758 | stream-browserify@^2.0.0:
759 | version "2.0.1"
760 | resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
761 | dependencies:
762 | inherits "~2.0.1"
763 | readable-stream "^2.0.2"
764 |
765 | stream-combiner2@^1.1.1:
766 | version "1.1.1"
767 | resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe"
768 | dependencies:
769 | duplexer2 "~0.1.0"
770 | readable-stream "^2.0.2"
771 |
772 | stream-http@^2.0.0:
773 | version "2.5.0"
774 | resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.5.0.tgz#585eee513217ed98fe199817e7313b6f772a6802"
775 | dependencies:
776 | builtin-status-codes "^2.0.0"
777 | inherits "^2.0.1"
778 | readable-stream "^2.1.0"
779 | to-arraybuffer "^1.0.0"
780 | xtend "^4.0.0"
781 |
782 | stream-splicer@^2.0.0:
783 | version "2.0.0"
784 | resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-2.0.0.tgz#1b63be438a133e4b671cc1935197600175910d83"
785 | dependencies:
786 | inherits "^2.0.1"
787 | readable-stream "^2.0.2"
788 |
789 | string_decoder@~0.10.0, string_decoder@~0.10.x:
790 | version "0.10.31"
791 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
792 |
793 | stylus@^0.54.5:
794 | version "0.54.5"
795 | resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.5.tgz#42b9560931ca7090ce8515a798ba9e6aa3d6dc79"
796 | dependencies:
797 | css-parse "1.7.x"
798 | debug "*"
799 | glob "7.0.x"
800 | mkdirp "0.5.x"
801 | sax "0.5.x"
802 | source-map "0.1.x"
803 |
804 | subarg@^1.0.0:
805 | version "1.0.0"
806 | resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2"
807 | dependencies:
808 | minimist "^1.1.0"
809 |
810 | symbol-observable@^1.0.1:
811 | version "1.0.4"
812 | resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d"
813 |
814 | syntax-error@^1.1.1:
815 | version "1.1.6"
816 | resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.1.6.tgz#b4549706d386cc1c1dc7c2423f18579b6cade710"
817 | dependencies:
818 | acorn "^2.7.0"
819 |
820 | through2@^2.0.0:
821 | version "2.0.3"
822 | resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
823 | dependencies:
824 | readable-stream "^2.1.5"
825 | xtend "~4.0.1"
826 |
827 | "through@>=2.2.7 <3":
828 | version "2.3.8"
829 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
830 |
831 | timers-browserify@^1.0.1:
832 | version "1.4.2"
833 | resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d"
834 | dependencies:
835 | process "~0.11.0"
836 |
837 | to-arraybuffer@^1.0.0:
838 | version "1.0.1"
839 | resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
840 |
841 | tty-browserify@~0.0.0:
842 | version "0.0.0"
843 | resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
844 |
845 | typedarray@~0.0.5:
846 | version "0.0.6"
847 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
848 |
849 | typescript@^2.1.4:
850 | version "2.1.4"
851 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.1.4.tgz#b53b69fb841126acb1dd4b397d21daba87572251"
852 |
853 | umd@^3.0.0:
854 | version "3.0.1"
855 | resolved "http://registry.npmjs.org/umd/-/umd-3.0.1.tgz#8ae556e11011f63c2596708a8837259f01b3d60e"
856 |
857 | url@~0.11.0:
858 | version "0.11.0"
859 | resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
860 | dependencies:
861 | punycode "1.3.2"
862 | querystring "0.2.0"
863 |
864 | util-deprecate@~1.0.1:
865 | version "1.0.2"
866 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
867 |
868 | util@0.10.3, util@~0.10.1:
869 | version "0.10.3"
870 | resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
871 | dependencies:
872 | inherits "2.0.1"
873 |
874 | vm-browserify@~0.0.1:
875 | version "0.0.4"
876 | resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
877 | dependencies:
878 | indexof "0.0.1"
879 |
880 | wrappy@1:
881 | version "1.0.2"
882 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
883 |
884 | xtend@^4.0.0, xtend@~4.0.1:
885 | version "4.0.1"
886 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
887 |
888 | zone.js@^0.7.4:
889 | version "0.7.4"
890 | resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.4.tgz#0e624fe5b724450ee433495deff15c02b3908ee0"
891 |
--------------------------------------------------------------------------------