├── app
├── node_modules
│ ├── objectid
│ │ ├── .npmignore
│ │ ├── LICENSE.md
│ │ ├── index.js
│ │ ├── README.md
│ │ ├── package.json
│ │ └── test.js
│ └── nconf
│ │ ├── test
│ │ ├── fixtures
│ │ │ ├── malformed.json
│ │ │ ├── hierarchy
│ │ │ │ ├── hierarchical.json
│ │ │ │ ├── user.json
│ │ │ │ └── global.json
│ │ │ ├── merge
│ │ │ │ ├── file2.json
│ │ │ │ └── file1.json
│ │ │ ├── scripts
│ │ │ │ ├── nconf-env.js
│ │ │ │ ├── nconf-argv.js
│ │ │ │ ├── nconf-nested-env.js
│ │ │ │ ├── provider-argv.js
│ │ │ │ ├── provider-env.js
│ │ │ │ ├── nconf-change-argv.js
│ │ │ │ ├── nconf-hierarchical-file-argv.js
│ │ │ │ ├── nconf-hierarchical-load-merge.js
│ │ │ │ └── nconf-hierarchical-load-save.js
│ │ │ ├── bom.json
│ │ │ ├── complete.json
│ │ │ ├── no-bom.json
│ │ │ ├── data.js
│ │ │ └── secure.json
│ │ ├── stores
│ │ │ ├── argv-test.js
│ │ │ ├── env-test.js
│ │ │ ├── literal-test.js
│ │ │ ├── memory-store-test.js
│ │ │ └── file-store-test.js
│ │ ├── common-test.js
│ │ ├── mocks
│ │ │ └── mock-store.js
│ │ ├── provider-save-test.js
│ │ ├── helpers.js
│ │ ├── hierarchy-test.js
│ │ ├── nconf-test.js
│ │ ├── complete-test.js
│ │ └── provider-test.js
│ │ ├── .npmignore
│ │ ├── .travis.yml
│ │ ├── lib
│ │ ├── nconf
│ │ │ ├── formats.js
│ │ │ ├── stores
│ │ │ │ ├── literal.js
│ │ │ │ ├── argv.js
│ │ │ │ ├── env.js
│ │ │ │ ├── memory.js
│ │ │ │ └── file.js
│ │ │ ├── common.js
│ │ │ └── provider.js
│ │ └── nconf.js
│ │ ├── LICENSE
│ │ ├── usage.js
│ │ ├── package.json
│ │ └── README.md
├── icons
│ ├── icon.ico
│ ├── icon.png
│ ├── icon.icns
│ ├── icon@2x.png
│ └── installer.png
├── sign
│ ├── dist
│ │ ├── sign-icons.png
│ │ ├── sign-icons@2.png
│ │ └── sign.min.css
│ ├── src
│ │ ├── images
│ │ │ ├── dida
│ │ │ │ ├── sign-icons
│ │ │ │ │ ├── qq.png
│ │ │ │ │ ├── weibo.png
│ │ │ │ │ └── wechat.png
│ │ │ │ └── sign-icons@2
│ │ │ │ │ ├── qq.png
│ │ │ │ │ ├── wechat.png
│ │ │ │ │ └── weibo.png
│ │ │ ├── common
│ │ │ │ ├── sign-icons
│ │ │ │ │ ├── logo.png
│ │ │ │ │ ├── email-blue.png
│ │ │ │ │ ├── email-gray.png
│ │ │ │ │ ├── lock-blue.png
│ │ │ │ │ ├── lock-gray.png
│ │ │ │ │ ├── name-blue.png
│ │ │ │ │ └── name-gray.png
│ │ │ │ └── sign-icons@2
│ │ │ │ │ ├── logo.png
│ │ │ │ │ ├── lock-blue.png
│ │ │ │ │ ├── lock-gray.png
│ │ │ │ │ ├── name-blue.png
│ │ │ │ │ ├── name-gray.png
│ │ │ │ │ ├── email-blue.png
│ │ │ │ │ └── email-gray.png
│ │ │ └── tick
│ │ │ │ ├── sign-icons
│ │ │ │ ├── facebook.png
│ │ │ │ ├── google.png
│ │ │ │ └── twitter.png
│ │ │ │ └── sign-icons@2
│ │ │ │ ├── google.png
│ │ │ │ ├── facebook.png
│ │ │ │ └── twitter.png
│ │ ├── styles
│ │ │ ├── main.scss
│ │ │ ├── _btns.scss
│ │ │ ├── _reset.scss
│ │ │ ├── _color.scss
│ │ │ ├── _functions.scss
│ │ │ ├── _mixins.scss
│ │ │ ├── sign-icons.scss
│ │ │ ├── sign-icons@2.scss
│ │ │ ├── _global.scss
│ │ │ ├── _sign.scss
│ │ │ ├── _variables.scss
│ │ │ └── _button.scss
│ │ └── scripts
│ │ │ └── sign.js
│ ├── package.json
│ ├── npm-debug.log
│ ├── icon.mustache
│ └── gulpfile.js
├── appest.js
├── appest-dida.js
├── main.css
├── appest-tick.js
├── package.json
├── index.html
├── user-config.js
├── index.js
├── main.js
├── menu.js
└── signin.html
├── screenshot.png
├── .gitignore
├── .eslintrc.json
├── README.md
├── package.json
└── gulpfile.js
/app/node_modules/objectid/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/screenshot.png
--------------------------------------------------------------------------------
/app/icons/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/icons/icon.ico
--------------------------------------------------------------------------------
/app/icons/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/icons/icon.png
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/malformed.json:
--------------------------------------------------------------------------------
1 | {
2 | "literal": "bazz",
3 | }
--------------------------------------------------------------------------------
/app/icons/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/icons/icon.icns
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | !/app/node_modules
4 | npm-debug.log
5 | pkg
6 |
--------------------------------------------------------------------------------
/app/icons/icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/icons/icon@2x.png
--------------------------------------------------------------------------------
/app/icons/installer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/icons/installer.png
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/hierarchy/hierarchical.json:
--------------------------------------------------------------------------------
1 | {
2 | "test": "empty"
3 | }
--------------------------------------------------------------------------------
/app/sign/dist/sign-icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/dist/sign-icons.png
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "standard",
3 | "plugins": [
4 | "standard"
5 | ]
6 | }
--------------------------------------------------------------------------------
/app/sign/dist/sign-icons@2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/dist/sign-icons@2.png
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/hierarchy/user.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "My specific title",
3 | "color": "green"
4 | }
--------------------------------------------------------------------------------
/app/sign/src/images/dida/sign-icons/qq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/dida/sign-icons/qq.png
--------------------------------------------------------------------------------
/app/sign/src/images/dida/sign-icons/weibo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/dida/sign-icons/weibo.png
--------------------------------------------------------------------------------
/app/sign/src/images/dida/sign-icons@2/qq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/dida/sign-icons@2/qq.png
--------------------------------------------------------------------------------
/app/sign/src/images/common/sign-icons/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/common/sign-icons/logo.png
--------------------------------------------------------------------------------
/app/sign/src/images/common/sign-icons@2/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/common/sign-icons@2/logo.png
--------------------------------------------------------------------------------
/app/sign/src/images/dida/sign-icons/wechat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/dida/sign-icons/wechat.png
--------------------------------------------------------------------------------
/app/sign/src/images/dida/sign-icons@2/wechat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/dida/sign-icons@2/wechat.png
--------------------------------------------------------------------------------
/app/sign/src/images/dida/sign-icons@2/weibo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/dida/sign-icons@2/weibo.png
--------------------------------------------------------------------------------
/app/sign/src/images/tick/sign-icons/facebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/tick/sign-icons/facebook.png
--------------------------------------------------------------------------------
/app/sign/src/images/tick/sign-icons/google.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/tick/sign-icons/google.png
--------------------------------------------------------------------------------
/app/sign/src/images/tick/sign-icons/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/tick/sign-icons/twitter.png
--------------------------------------------------------------------------------
/app/sign/src/images/tick/sign-icons@2/google.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/tick/sign-icons@2/google.png
--------------------------------------------------------------------------------
/app/sign/src/images/tick/sign-icons@2/facebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/tick/sign-icons@2/facebook.png
--------------------------------------------------------------------------------
/app/sign/src/images/tick/sign-icons@2/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/tick/sign-icons@2/twitter.png
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/hierarchy/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "My generic title",
3 | "color": "red",
4 | "movie": "Kill Bill"
5 | }
--------------------------------------------------------------------------------
/app/sign/src/images/common/sign-icons/email-blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/common/sign-icons/email-blue.png
--------------------------------------------------------------------------------
/app/sign/src/images/common/sign-icons/email-gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/common/sign-icons/email-gray.png
--------------------------------------------------------------------------------
/app/sign/src/images/common/sign-icons/lock-blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/common/sign-icons/lock-blue.png
--------------------------------------------------------------------------------
/app/sign/src/images/common/sign-icons/lock-gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/common/sign-icons/lock-gray.png
--------------------------------------------------------------------------------
/app/sign/src/images/common/sign-icons/name-blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/common/sign-icons/name-blue.png
--------------------------------------------------------------------------------
/app/sign/src/images/common/sign-icons/name-gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/common/sign-icons/name-gray.png
--------------------------------------------------------------------------------
/app/sign/src/images/common/sign-icons@2/lock-blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/common/sign-icons@2/lock-blue.png
--------------------------------------------------------------------------------
/app/sign/src/images/common/sign-icons@2/lock-gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/common/sign-icons@2/lock-gray.png
--------------------------------------------------------------------------------
/app/sign/src/images/common/sign-icons@2/name-blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/common/sign-icons@2/name-blue.png
--------------------------------------------------------------------------------
/app/sign/src/images/common/sign-icons@2/name-gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/common/sign-icons@2/name-gray.png
--------------------------------------------------------------------------------
/app/sign/src/images/common/sign-icons@2/email-blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/common/sign-icons@2/email-blue.png
--------------------------------------------------------------------------------
/app/sign/src/images/common/sign-icons@2/email-gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwartz/dida/HEAD/app/sign/src/images/common/sign-icons@2/email-gray.png
--------------------------------------------------------------------------------
/app/appest.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | user: {
3 | inboxId: '',
4 | username: ''
5 | },
6 | domain: 'dida365.com',
7 | api_domain: 'dida365.com',
8 | protocol: 'https://',
9 | productName: '滴答清单'
10 | }
11 |
--------------------------------------------------------------------------------
/app/appest-dida.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | user: {
3 | inboxId: '',
4 | username: ''
5 | },
6 | domain: 'dida365.com',
7 | api_domain: 'dida365.com',
8 | protocol: 'https://',
9 | productName: '滴答清单'
10 | }
11 |
--------------------------------------------------------------------------------
/app/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | overflow: hidden;
3 | }
4 |
5 | input {
6 | width: 600px;
7 | height: 40px;
8 | padding: 10px;
9 | font-size: 16px;
10 | box-sizing: border-box;
11 | }
12 |
13 | input:focus {
14 | outline: none;
15 | }
16 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/merge/file2.json:
--------------------------------------------------------------------------------
1 | {
2 | "candy": {
3 | "something": "file2",
4 | "something3": true,
5 | "something4": true
6 | },
7 | "dates": true,
8 | "elderberries": true,
9 | "unicorn": null
10 | }
11 |
--------------------------------------------------------------------------------
/app/appest-tick.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | user: {
3 | inboxId: '',
4 | username: ''
5 | },
6 | domain: 'ticktick.com',
7 | api_domain: 'ticktick.com',
8 | protocol: 'https://',
9 | productName: 'TickTick'
10 | }
11 |
--------------------------------------------------------------------------------
/app/sign/src/styles/main.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | // variables
4 | @import
5 | 'variables';
6 |
7 | @import
8 | 'global';
9 |
10 | @import
11 | 'button',
12 | 'btns';
13 |
14 | @import
15 | 'sign-icons',
16 | 'reset',
17 | 'sign';
18 |
--------------------------------------------------------------------------------
/app/sign/src/styles/_btns.scss:
--------------------------------------------------------------------------------
1 | // buttons
2 | .btns {
3 |
4 | .btn-loading {
5 | display: none;
6 | }
7 |
8 | &.ing {
9 | .btn-initial {
10 | display: none;
11 | }
12 |
13 | .btn-loading {
14 | display: inline-block;
15 | }
16 | }
17 |
18 | }
--------------------------------------------------------------------------------
/app/node_modules/nconf/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | config.json
3 | test/fixtures/*.json
4 | !test/fixtures/complete.json
5 | !test/fixtures/malformed.json
6 | !test/fixtures/bom.json
7 | !test/fixtures/no-bom.json
8 | !test/fixtures/secure.json
9 | node_modules/
10 | node_modules/*
11 | npm-debug.log
12 | coverage
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/scripts/nconf-env.js:
--------------------------------------------------------------------------------
1 | /*
2 | * nconf-env.js: Test fixture for using process.env defaults with nconf.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var nconf = require('../../../lib/nconf').env();
9 |
10 | process.stdout.write(nconf.get('SOMETHING'));
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/scripts/nconf-argv.js:
--------------------------------------------------------------------------------
1 | /*
2 | * default-argv.js: Test fixture for using yargs defaults with nconf.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var nconf = require('../../../lib/nconf').argv().env();
9 |
10 | process.stdout.write(nconf.get('something'));
11 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/scripts/nconf-nested-env.js:
--------------------------------------------------------------------------------
1 | /*
2 | * nconf-nested-env.js: Test fixture for env with nested keys.
3 | *
4 | * (C) 2012, Charlie Robbins and the Contributors.
5 | * (C) 2012, Michael Hart
6 | *
7 | */
8 |
9 | var nconf = require('../../../lib/nconf').env('_');
10 |
11 | process.stdout.write(nconf.get('SOME:THING'));
12 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/scripts/provider-argv.js:
--------------------------------------------------------------------------------
1 | /*
2 | * provider-argv.js: Test fixture for using yargs defaults with nconf.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var nconf = require('../../../lib/nconf');
9 |
10 | var provider = new (nconf.Provider)().argv();
11 |
12 | process.stdout.write(provider.get('something'));
13 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/scripts/provider-env.js:
--------------------------------------------------------------------------------
1 | /*
2 | * provider-argv.js: Test fixture for using process.env defaults with nconf.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var nconf = require('../../../lib/nconf');
9 |
10 | var provider = new (nconf.Provider)().env();
11 |
12 | process.stdout.write(provider.get('SOMETHING'));
--------------------------------------------------------------------------------
/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "1.0.0",
4 | "description": "Desktop App of 滴答清单(TickTick)",
5 | "main": "main.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "xwartz",
10 | "license": "MIT",
11 | "dependencies": {
12 | "nconf": "^0.8.4",
13 | "objectid": "^3.2.1"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/merge/file1.json:
--------------------------------------------------------------------------------
1 | {
2 | "apples": true,
3 | "bananas": true,
4 | "foo": {
5 | "bar": "boo"
6 | },
7 | "candy": {
8 | "something": "file1",
9 | "something1": true,
10 | "something2": true,
11 | "something5": {
12 | "first": 1,
13 | "second": 2
14 | }
15 | },
16 | "unicorn": {
17 | "exists": true
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/bom.json:
--------------------------------------------------------------------------------
1 | {
2 | "I've seen things": {
3 | "like": [
4 | "carrots",
5 | "handbags",
6 | "cheese",
7 | "toilets",
8 | "russians",
9 | "planets",
10 | "hampsters",
11 | "weddings",
12 | "poets",
13 | "stalin",
14 | "kuala lumpur"
15 | ]
16 | },
17 | "host": "weebls-stuff.com",
18 | "port": 78304
19 | }
20 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/complete.json:
--------------------------------------------------------------------------------
1 | {
2 | "I've seen things": {
3 | "like": [
4 | "carrots",
5 | "handbags",
6 | "cheese",
7 | "toilets",
8 | "russians",
9 | "planets",
10 | "hampsters",
11 | "weddings",
12 | "poets",
13 | "stalin",
14 | "kuala lumpur"
15 | ]
16 | },
17 | "host": "weebls-stuff.com",
18 | "port": 78304
19 | }
20 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/no-bom.json:
--------------------------------------------------------------------------------
1 | {
2 | "I've seen things": {
3 | "like": [
4 | "carrots",
5 | "handbags",
6 | "cheese",
7 | "toilets",
8 | "russians",
9 | "planets",
10 | "hampsters",
11 | "weddings",
12 | "poets",
13 | "stalin",
14 | "kuala lumpur"
15 | ]
16 | },
17 | "host": "weebls-stuff.com",
18 | "port": 78304
19 | }
20 |
--------------------------------------------------------------------------------
/app/sign/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ticktick-sign",
3 | "version": "0.0.1",
4 | "devDependencies": {
5 | "gulp": "^3.9.1",
6 | "gulp-compass": "^2.1.0",
7 | "gulp-minify-css": "^1.2.4",
8 | "gulp-notify": "^2.2.0",
9 | "gulp-plumber": "^1.1.0",
10 | "gulp-rename": "^1.2.2",
11 | "gulp-shell": "^0.5.2",
12 | "gulp-uncss": "^1.0.4",
13 | "gulp.spritesmith": "~1.1.1",
14 | "shelljs": "^0.6.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/scripts/nconf-change-argv.js:
--------------------------------------------------------------------------------
1 | /*
2 | * nconf-change-argv.js: Test fixture for changing argv on the fly
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var nconf = require('../../../lib/nconf').argv();
9 |
10 | //
11 | // Remove 'badValue', 'evenWorse' and 'OHNOEZ'
12 | //
13 | process.argv.splice(3, 3);
14 | nconf.stores['argv'].loadArgv();
15 | process.stdout.write(nconf.get('something'));
16 |
17 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/scripts/nconf-hierarchical-file-argv.js:
--------------------------------------------------------------------------------
1 | /*
2 | * nconf-hierarchical-file-argv.js: Test fixture for using yargs defaults and a file store with nconf.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | * (C) 2011, Sander Tolsma
6 | *
7 | */
8 |
9 | var path = require('path'),
10 | nconf = require('../../../lib/nconf');
11 |
12 | nconf.argv();
13 | nconf.add('file', {
14 | file: path.join(__dirname, '../hierarchy/hierarchical.json')
15 | });
16 |
17 | process.stdout.write(nconf.get('something') || 'undefined');
18 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/scripts/nconf-hierarchical-load-merge.js:
--------------------------------------------------------------------------------
1 | /*
2 | * nconf-hierarchical-load-merge.js: Test fixture for loading and merging nested objects across stores.
3 | *
4 | * (C) 2012, Charlie Robbins and the Contributors.
5 | * (C) 2012, Michael Hart
6 | *
7 | */
8 |
9 | var path = require('path'),
10 | nconf = require('../../../lib/nconf');
11 |
12 | nconf.argv()
13 | .file(path.join(__dirname, '..', 'merge', 'file1.json'));
14 |
15 | process.stdout.write(JSON.stringify({
16 | apples: nconf.get('apples'),
17 | candy: nconf.get('candy')
18 | }));
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 滴答清单(TickTick)
2 |
3 | > Task Manager: [滴答清单](https://dida365.com/) && [TickTick](https://ticktick.com/)
4 |
5 | dida: Easily add task to 滴答清单(TickTick) by shortcut.
6 |
7 |
8 |
9 | ## Dev
10 |
11 | ```
12 | $ npm i && cd app && npm i
13 | ```
14 |
15 | ### Run
16 |
17 | ```
18 | $ npm start
19 | ```
20 |
21 | ## Build
22 |
23 | ```
24 | $ npm run build:dida
25 | ```
26 | or
27 | ```
28 | $ npm run build:tick
29 | ```
30 |
31 | ## Note
32 |
33 | ### Mirrors
34 |
35 | [China](https://npm.taobao.org/)
36 |
37 | ## License
38 |
39 | ©MIT
40 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js:
4 | - "0.10"
5 | - "0.12"
6 | - "4.1"
7 | - "5"
8 |
9 | before_install:
10 | - travis_retry npm install npm -g
11 |
12 | before_install:
13 | - travis_retry npm install -g npm@2.5.1
14 | - travis_retry npm install
15 |
16 | script:
17 | - npm test
18 |
19 | after_script:
20 | - npm run cover
21 | - npm run coveralls
22 |
23 | matrix:
24 | allow_failures:
25 | - node_js: "0.10"
26 |
27 | notifications:
28 | email:
29 | - travis@nodejitsu.com
30 | irc: "irc.freenode.org#nodejitsu"
31 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/data.js:
--------------------------------------------------------------------------------
1 | /*
2 | * data.js: Simple data fixture for configuration test.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | exports.data = {
9 | isNull: null,
10 | literal: 'bazz',
11 | arr: ['one', 2, true, { value: 'foo' }],
12 | obj: {
13 | host: 'localhost',
14 | port: 5984,
15 | array: ['one', 2, true, { foo: 'bar' }],
16 | auth: {
17 | username: 'admin',
18 | password: 'password'
19 | }
20 | }
21 | };
22 |
23 | exports.merge = {
24 | prop1: 1,
25 | prop2: [1, 2, 3],
26 | prop3: {
27 | foo: 'bar',
28 | bar: 'foo'
29 | }
30 | };
--------------------------------------------------------------------------------
/app/node_modules/nconf/lib/nconf/formats.js:
--------------------------------------------------------------------------------
1 | /*
2 | * formats.js: Default formats supported by nconf
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var ini = require('ini');
9 |
10 | var formats = exports;
11 |
12 | //
13 | // ### @json
14 | // Standard JSON format which pretty prints `.stringify()`.
15 | //
16 | formats.json = {
17 | stringify: function (obj, replacer, spacing) {
18 | return JSON.stringify(obj, replacer || null, spacing || 2)
19 | },
20 | parse: JSON.parse
21 | };
22 |
23 | //
24 | // ### @ini
25 | // Standard INI format supplied from the `ini` module
26 | // http://en.wikipedia.org/wiki/INI_file
27 | //
28 | formats.ini = ini;
29 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/stores/argv-test.js:
--------------------------------------------------------------------------------
1 | /*
2 | * argv-test.js: Tests for the nconf argv store.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var vows = require('vows'),
9 | assert = require('assert'),
10 | helpers = require('../helpers'),
11 | nconf = require('../../lib/nconf');
12 |
13 | vows.describe('nconf/stores/argv').addBatch({
14 | "An instance of nconf.Argv": {
15 | topic: new nconf.Argv(),
16 | "should have the correct methods defined": function (argv) {
17 | assert.isFunction(argv.loadSync);
18 | assert.isFunction(argv.loadArgv);
19 | assert.isFalse(argv.options);
20 | }
21 | }
22 | }).export(module);
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/stores/env-test.js:
--------------------------------------------------------------------------------
1 | /*
2 | * env-test.js: Tests for the nconf env store.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var vows = require('vows'),
9 | assert = require('assert'),
10 | helpers = require('../helpers'),
11 | nconf = require('../../lib/nconf');
12 |
13 | vows.describe('nconf/stores/env').addBatch({
14 | "An instance of nconf.Env": {
15 | topic: new nconf.Env(),
16 | "should have the correct methods defined": function (env) {
17 | assert.isFunction(env.loadSync);
18 | assert.isFunction(env.loadEnv);
19 | assert.isArray(env.whitelist);
20 | assert.lengthOf(env.whitelist, 0);
21 | assert.equal(env.separator, '');
22 | }
23 | }
24 | }).export(module);
25 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/lib/nconf/stores/literal.js:
--------------------------------------------------------------------------------
1 | /*
2 | * literal.js: Simple literal Object store for nconf.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var util = require('util'),
9 | Memory = require('./memory').Memory
10 |
11 | var Literal = exports.Literal = function Literal (options) {
12 | Memory.call(this, options);
13 |
14 | options = options || {}
15 | this.type = 'literal';
16 | this.readOnly = true;
17 | this.store = options.store || options;
18 | };
19 |
20 | // Inherit from Memory store.
21 | util.inherits(Literal, Memory);
22 |
23 | //
24 | // ### function loadSync (callback)
25 | // Returns the data stored in `this.store` synchronously.
26 | //
27 | Literal.prototype.loadSync = function () {
28 | return this.store;
29 | };
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/secure.json:
--------------------------------------------------------------------------------
1 | {
2 | "isNull": {
3 | "alg": "aes-256-ctr",
4 | "value": "af07fbcf"
5 | },
6 | "literal": {
7 | "alg": "aes-256-ctr",
8 | "value": "e310f6d94f13"
9 | },
10 | "arr": {
11 | "alg": "aes-256-ctr",
12 | "value": "9a78b783175e69bb8f3458042b1c098d8ed9613410fac185b3735099224f8fe4ece0f0da8decfddbbf0eab3b7c391c47772b5441"
13 | },
14 | "obj": {
15 | "alg": "aes-256-ctr",
16 | "value": "ba78b783175968add93a680429424ae4cf957d2916ebcfa399730bb17200ddb0ecacb183c1b1ebcd950ced76726964062e74643c995c47372bfb1311bee8f65bbeb5a1d9426537a6d83635220ec7934e1d7cc187f7218cd4afadfa2f107fb42c232d80d95c160ee704fa8e922998b0b3e47ec579dd0baef7cae6d7dbaa203d732adb5cff22b80d810d7191237999cd8dc528d8f2201ae128a9f9e2df96d1a816aa73e3e6b8e6246cd98b454e453b36f43f9117cb4af8fa85429a92"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/fixtures/scripts/nconf-hierarchical-load-save.js:
--------------------------------------------------------------------------------
1 | /*
2 | * nconf-hierarchical-load-save.js: Test fixture for using yargs, envvars and a file store with nconf.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var fs = require('fs'),
9 | path = require('path'),
10 | nconf = require('../../../lib/nconf');
11 |
12 | //
13 | // Setup nconf to use (in-order):
14 | // 1. Command-line arguments
15 | // 2. Environment variables
16 | // 3. A file located at 'path/to/config.json'
17 | //
18 | nconf.argv()
19 | .env()
20 | .file({ file: path.join(__dirname, '..', 'load-save.json') });
21 |
22 | //
23 | // Set a few variables on `nconf`.
24 | //
25 | nconf.set('database:host', '127.0.0.1');
26 | nconf.set('database:port', 5984);
27 |
28 | process.stdout.write(nconf.get('foo'));
29 | //
30 | // Save the configuration object to disk
31 | //
32 | nconf.save();
33 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/stores/literal-test.js:
--------------------------------------------------------------------------------
1 | /*
2 | * literal-test.js: Tests for the nconf literal store.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var vows = require('vows'),
9 | assert = require('assert'),
10 | helpers = require('../helpers'),
11 | nconf = require('../../lib/nconf');
12 |
13 | vows.describe('nconf/stores/literal').addBatch({
14 | "An instance of nconf.Literal": {
15 | topic: new nconf.Literal({
16 | foo: 'bar',
17 | one: 2
18 | }),
19 | "should have the correct methods defined": function (literal) {
20 | assert.equal(literal.type, 'literal');
21 | assert.isFunction(literal.get);
22 | assert.isFunction(literal.set);
23 | assert.isFunction(literal.merge);
24 | assert.isFunction(literal.loadSync);
25 | },
26 | "should have the correct values in the store": function (literal) {
27 | assert.equal(literal.store.foo, 'bar');
28 | assert.equal(literal.store.one, 2);
29 | }
30 | }
31 | }).export(module);
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/common-test.js:
--------------------------------------------------------------------------------
1 | /*
2 | * common.js: Tests for common utility function in nconf.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var fs = require('fs'),
9 | path = require('path'),
10 | vows = require('vows'),
11 | assert = require('assert'),
12 | helpers = require('./helpers'),
13 | nconf = require('../lib/nconf');
14 |
15 | var mergeDir = path.join(__dirname, 'fixtures', 'merge'),
16 | files = fs.readdirSync(mergeDir).map(function (f) { return path.join(mergeDir, f) });
17 |
18 | vows.describe('nconf/common').addBatch({
19 | "Using nconf.common module": {
20 | "the loadFiles() method": {
21 | topic: function () {
22 | nconf.loadFiles(files, this.callback);
23 | },
24 | "should merge the files correctly": helpers.assertMerged
25 | },
26 | "the loadFilesSync() method": {
27 | "should merge the files correctly": function () {
28 | helpers.assertMerged(null, nconf.loadFilesSync(files));
29 | }
30 | }
31 | }
32 | }).export(module);
--------------------------------------------------------------------------------
/app/node_modules/objectid/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright © 2013 Agile Diagnosis, Inc.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/mocks/mock-store.js:
--------------------------------------------------------------------------------
1 | /*
2 | * mock-store.js: Mock store for ensuring certain operations are actually called.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var util = require('util'),
9 | events = require('events'),
10 | nconf = require('../../lib/nconf');
11 |
12 | var Mock = nconf.Mock = function () {
13 | events.EventEmitter.call(this);
14 | this.type = 'mock';
15 | };
16 |
17 | // Inherit from Memory store.
18 | util.inherits(Mock, events.EventEmitter);
19 |
20 | //
21 | // ### function save (value, callback)
22 | // #### @value {Object} _Ignored_ Left here for consistency
23 | // #### @callback {function} Continuation to respond to when complete.
24 | // Waits `1000ms` and then calls the callback and emits the `save` event.
25 | //
26 | Mock.prototype.save = function (value, callback) {
27 | if (!callback && typeof value === 'function') {
28 | callback = value;
29 | value = null;
30 | }
31 |
32 | var self = this;
33 |
34 | setTimeout(function () {
35 | self.emit('save');
36 | callback();
37 | }, 1000);
38 | };
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/provider-save-test.js:
--------------------------------------------------------------------------------
1 | /*
2 | * provider-save-test.js: Ensures consistency for Provider `save` operations.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var assert = require('assert'),
9 | vows = require('vows'),
10 | nconf = require('../lib/nconf');
11 |
12 | //
13 | // Expose `nconf.Mock`
14 | //
15 | require('./mocks/mock-store');
16 |
17 | vows.describe('nconf/provider/save').addBatch({
18 | "When using nconf": {
19 | "an instance of 'nconf.Provider'": {
20 | "with a Mock store": {
21 | topic: function () {
22 | return nconf.use('mock');
23 | },
24 | "the save() method": {
25 | topic: function () {
26 | var mock = nconf.stores.mock,
27 | that = this;
28 |
29 | mock.on('save', function () { that.saved = true });
30 | nconf.save(this.callback);
31 | },
32 | "should actually save before responding": function () {
33 | assert.isTrue(this.saved);
34 | }
35 | }
36 | }
37 | }
38 | }
39 | }).export(module);
--------------------------------------------------------------------------------
/app/node_modules/nconf/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2011 Charlie Robbins and the Contributors.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dida",
3 | "version": "1.0.0",
4 | "description": "Desktop App of 滴答清单(TickTick)",
5 | "main": "app/main.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "electron app/main.js",
9 | "build:dida": "gulp pkg:dida",
10 | "build:tick": "gulp pkg:tick"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/xwartz/dida.git"
15 | },
16 | "keywords": [
17 | "dida",
18 | "ticktick",
19 | "electron",
20 | "js",
21 | "es6",
22 | "desktop app"
23 | ],
24 | "author": "xwartz (https://github.com/xwartz/)",
25 | "license": "MIT",
26 | "bugs": {
27 | "url": "https://github.com/xwartz/dida/issues"
28 | },
29 | "homepage": "https://github.com/xwartz/dida#readme",
30 | "devDependencies": {
31 | "del": "^2.2.0",
32 | "electron-prebuilt": "0.36.0",
33 | "electron-builder": "^2.8.3",
34 | "electron-packager": "^5.2.1",
35 | "eslint-config-standard": "^4.4.0",
36 | "eslint-plugin-standard": "^1.3.1",
37 | "gulp": "^3.9.1",
38 | "gulp-rename": "^1.2.2",
39 | "gulp-shell": "^0.5.2",
40 | "yargs": "^4.2.0"
41 | },
42 | "dependencies": {}
43 | }
44 |
--------------------------------------------------------------------------------
/app/user-config.js:
--------------------------------------------------------------------------------
1 | // 存储用户信息
2 |
3 | 'use strict'
4 |
5 | var nconf = require('nconf')
6 | var electron = require('electron')
7 | var app = electron.app
8 |
9 | var appest = require('./appest')
10 |
11 | // 不是主进程的话, 渲染进程只能用 remote
12 | if(!app) {
13 | var remote = electron.remote
14 | app = remote.app
15 | }
16 |
17 | nconf.file({
18 | file: getUserHome() + '/' + appest.domain + '.json'
19 | })
20 |
21 | function getUserHome() {
22 | return app.getPath('appData') + '/ticktick'
23 | }
24 |
25 | function _save (key, value) {
26 | nconf.set(key, value)
27 | nconf.save()
28 | }
29 |
30 | function readConfig(key) {
31 | nconf.load()
32 | return nconf.get(key)
33 | }
34 |
35 | function saveConfig(data) {
36 | var Appest = {}
37 | if(data.user) {
38 | Appest = Object.assign({}, data)
39 | } else {
40 | Appest = {
41 | user: {
42 | isGFS: data.pro,
43 | inboxId: data.inboxId,
44 | username: data.username
45 | },
46 | end_date: data.proEndDate,
47 | }
48 | }
49 | _save('Appest', Appest)
50 | }
51 |
52 | function clearConfig () {
53 | saveConfig({ inboxId: '' })
54 | }
55 |
56 | module.exports = {
57 | saveConfig: saveConfig,
58 | readConfig: readConfig,
59 | clearConfig: clearConfig
60 | }
61 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/lib/nconf.js:
--------------------------------------------------------------------------------
1 | /*
2 | * nconf.js: Top-level include for the nconf module
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var fs = require('fs'),
9 | async = require('async'),
10 | common = require('./nconf/common'),
11 | Provider = require('./nconf/provider').Provider;
12 |
13 | //
14 | // `nconf` is by default an instance of `nconf.Provider`.
15 | //
16 | var nconf = module.exports = new Provider();
17 |
18 | //
19 | // Expose the version from the package.json
20 | //
21 | nconf.version = require('../package.json').version;
22 |
23 | //
24 | // Setup all stores as lazy-loaded getters.
25 | //
26 | fs.readdirSync(__dirname + '/nconf/stores').forEach(function (file) {
27 | var store = file.replace('.js', ''),
28 | name = common.capitalize(store);
29 |
30 | nconf.__defineGetter__(name, function () {
31 | return require('./nconf/stores/' + store)[name];
32 | });
33 | });
34 |
35 | //
36 | // Expose the various components included with nconf
37 | //
38 | nconf.key = common.key;
39 | nconf.path = common.path;
40 | nconf.loadFiles = common.loadFiles;
41 | nconf.loadFilesSync = common.loadFilesSync;
42 | nconf.formats = require('./nconf/formats');
43 | nconf.Provider = Provider;
44 |
45 |
--------------------------------------------------------------------------------
/app/sign/src/styles/_reset.scss:
--------------------------------------------------------------------------------
1 | $s-base-divider: 36px;
2 |
3 | $s-input-placeholder-color: $base-font-color-holder;
4 |
5 | @mixin input-placeholder($color) {
6 | // style placeholder text cross browser
7 | ::-webkit-input-placeholder {
8 | color: $color;
9 | }
10 |
11 | :-moz-placeholder { /* Firefox 18- */
12 | color: $color;
13 | }
14 |
15 | ::-moz-placeholder { /* Firefox 19+ */
16 | color: $color;
17 | }
18 |
19 | :-ms-input-placeholder {
20 | color: $color !important;
21 | }
22 | }
23 |
24 | @include input-placeholder($s-input-placeholder-color);
25 |
26 | /*reset style*/
27 | html, body, div, span, i, p, a, ul, li {
28 | margin: 0;
29 | padding: 0;
30 | border: 0;
31 | outline: 0;
32 | font-size: 100%;
33 | font: inherit;
34 | }
35 |
36 | ol, ul {
37 | list-style: none;
38 | }
39 |
40 | a {
41 | color: $base-font-color-link;
42 | text-decoration: none;
43 |
44 | &:hover {
45 | color: $base-font-color-link;
46 | text-decoration: underline;
47 | }
48 |
49 | &:hover, &:active {
50 | outline: 0;
51 | }
52 |
53 | &:visited {
54 | color: $base-font-color-link;
55 | text-decoration: none;
56 | }
57 |
58 | }
59 |
60 | input,
61 | input:focus {
62 | outline: 0;
63 | box-shadow: none;
64 | }
65 |
66 | img {
67 | border-radius: 50%;
68 | }
69 |
70 | .button {
71 | cursor: pointer;
72 | -webkit-appearance: none;
73 | }
--------------------------------------------------------------------------------
/app/node_modules/objectid/index.js:
--------------------------------------------------------------------------------
1 | var ObjectId = require('bson').ObjectId
2 |
3 | ObjectId.prototype.equals = function (oidB) {
4 | return equals(this, oidB)
5 | }
6 |
7 | var objIdPattern = /^[0-9a-fA-F]{24}$/;
8 | var isValid = function (alleged) {
9 | return (Boolean(alleged) && !Array.isArray(alleged) && objIdPattern.test(String(alleged)))
10 | }
11 |
12 | var equals = function (oidA, oidB) {
13 | // curried
14 | if (arguments.length === 1) {
15 | return function (oidB) {
16 | return equals(oidA, oidB)
17 | }
18 | }
19 |
20 | if (oidA === oidB) { return true; }
21 | if (!isValid(oidA) || !isValid(oidB)) { return false }
22 | return (String(oidA) === String(oidB))
23 | return false;
24 | }
25 |
26 | var tryParse = function (oid, out, as) {
27 | if (!isValid(oid)) { return false }
28 | try {
29 | out[as] = Id(oid)
30 | return true
31 | } catch (e) {
32 | return false
33 | }
34 | }
35 |
36 | function Id(id) {
37 | if (id instanceof ObjectId) { return id }
38 |
39 | if (arguments.length === 0) {
40 | return new ObjectId()
41 | }
42 |
43 | id = String(id)
44 |
45 | if (isValid(id)) {
46 | return new ObjectId(id)
47 |
48 | } else {
49 | throw new Error('Invalid ObjectId: ' + id)
50 | }
51 |
52 | }
53 |
54 | module.exports = Id;
55 | module.exports.constructor = ObjectId;
56 | module.exports.tryParse = tryParse;
57 | module.exports.equals = equals;
58 | module.exports.isValid = isValid;
59 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/usage.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs'),
2 | path = require('path'),
3 | nconf = require('./lib/nconf');
4 |
5 | //
6 | // Configure the provider with a single store and
7 | // support for command-line arguments and environment
8 | // variables.
9 | //
10 | var single = new nconf.Provider({
11 | env: true,
12 | argv: true,
13 | store: {
14 | type: 'file',
15 | file: path.join(__dirname, 'config.json')
16 | }
17 | });
18 |
19 | //
20 | // Configure the provider with multiple hierarchical stores
21 | // representing `user` and `global` configuration values.
22 | //
23 | var multiple = new nconf.Provider({
24 | stores: [
25 | { name: 'user', type: 'file', file: path.join(__dirname, 'user-config.json') },
26 | { name: 'global', type: 'global', file: path.join(__dirname, 'global-config.json') }
27 | ]
28 | });
29 |
30 | //
31 | // Setup nconf to use the 'file' store and set a couple of values;
32 | //
33 | nconf.use('file', { file: path.join(__dirname, 'config.json') });
34 | nconf.set('database:host', '127.0.0.1');
35 | nconf.set('database:port', 5984);
36 |
37 | //
38 | // Get the entire database object from nconf
39 | //
40 | var database = nconf.get('database');
41 | console.dir(database);
42 |
43 | //
44 | // Save the configuration object to disk
45 | //
46 | nconf.save(function (err) {
47 | fs.readFile(path.join(__dirname, 'config.json'), function (err, data) {
48 | console.dir(JSON.parse(data.toString()))
49 | });
50 | });
--------------------------------------------------------------------------------
/app/sign/npm-debug.log:
--------------------------------------------------------------------------------
1 | 0 info it worked if it ends with ok
2 | 1 verbose cli [ '/usr/local/bin/node', '/usr/local/bin/npm', 'start' ]
3 | 2 info using npm@3.5.2
4 | 3 info using node@v5.5.0
5 | 4 verbose stack Error: missing script: start
6 | 4 verbose stack at run (/usr/local/lib/node_modules/npm/lib/run-script.js:147:19)
7 | 4 verbose stack at /usr/local/lib/node_modules/npm/lib/run-script.js:57:5
8 | 4 verbose stack at /usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:345:5
9 | 4 verbose stack at checkBinReferences_ (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:309:45)
10 | 4 verbose stack at final (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:343:3)
11 | 4 verbose stack at then (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:113:5)
12 | 4 verbose stack at ReadFileContext. (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:284:20)
13 | 4 verbose stack at ReadFileContext.callback (/usr/local/lib/node_modules/npm/node_modules/graceful-fs/graceful-fs.js:76:16)
14 | 4 verbose stack at FSReqWrap.readFileAfterOpen [as oncomplete] (fs.js:324:13)
15 | 5 verbose cwd /Users/xwartz/github/pupa/sign
16 | 6 error Darwin 15.3.0
17 | 7 error argv "/usr/local/bin/node" "/usr/local/bin/npm" "start"
18 | 8 error node v5.5.0
19 | 9 error npm v3.5.2
20 | 10 error missing script: start
21 | 11 error If you need help, you may report this error at:
22 | 11 error
23 | 12 verbose exit [ 1, true ]
24 |
--------------------------------------------------------------------------------
/app/node_modules/objectid/README.md:
--------------------------------------------------------------------------------
1 | # objectid
2 | mongodb objectid utilities
3 |
4 | ## about
5 |
6 | 1.x is probably the version you want to use in a browser. 3.x focuses on compatibility with the npm `mongodb` driver.
7 |
8 | ## installation
9 |
10 | $ npm install objectid
11 |
12 | ## usage
13 |
14 | var objectid = require('objectid')
15 |
16 | var id = objectid()
17 |
18 | objectid.isValid(id)
19 | // => true
20 |
21 | objectid.isValid('4frsdef43wzx')
22 | // => false
23 |
24 | `objectid.isValid` returns true for `mongodb` native driver `ObjectID` objects, or any other representations with a `.toString` method which returns the hex string encoding of a valid objectid.
25 |
26 | Calling `objectid` with an existing objectid - whether a string, an object created by this module, an objectid created by another driver (such as the result of a query) - will cast the value to an instanceof this module. It will throw if the argument is not a valid ObjectId.
27 |
28 | ## Static Methods
29 |
30 | ### ObjectId.equals(oidA, oidB) => Boolean
31 | Curried to support creating equality predicates.
32 |
33 | ### ObjectId.tryParse(oid, out, as) => Boolean
34 |
35 | ### ObjectId.isValid(oid) => Boolean
36 |
37 | ## Instance Methods
38 |
39 | ### ObjectId#equals(oidB) => Boolean
40 |
41 | ### ObjectId#toString() => String
42 |
43 | ### ObjectId#toJSON() => String
44 |
45 | ## running the tests
46 |
47 | From package root:
48 |
49 | $ npm install
50 | $ npm test
51 |
52 | ## contributors
53 |
54 | jden @leJDen
55 |
56 | ## license
57 |
58 | MIT. (c) 2013 Agile Diagnosis See LICENSE.md
59 |
--------------------------------------------------------------------------------
/app/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | let Objectid = require('objectid')
4 |
5 |
6 | let path = require('path'),
7 | userConfig = require('./user-config'),
8 | appest = require('./appest'),
9 | conf = userConfig.readConfig('Appest')
10 |
11 | const Appest = Object.assign({}, appest, conf)
12 |
13 | let App = {
14 | $el: document.getElementById('js-add'),
15 | createTask (model) {
16 | const api = Appest.protocol + Appest.api_domain + '/api/v2/task'
17 |
18 | fetch(api, {
19 | credentials: 'include',
20 | method: 'post',
21 | headers: {
22 | 'Accept': 'application/json',
23 | 'Content-Type': 'application/json'
24 | },
25 | body: JSON.stringify(model)
26 | }).then((res) => {
27 | if(res.status >= 200 && res.status < 300) {
28 | this.$el.value = ''
29 | }
30 | })
31 | },
32 |
33 | initEvent () {
34 | this.$el.addEventListener('keyup', (event) => {
35 | if(event.keyCode === 13) {
36 | let model = {
37 | assignee: null,
38 | content: '',
39 | deleted: 0,
40 | dueDate: null,
41 | id: Objectid().toString(),
42 | isAllDay: null,
43 | items: [],
44 | local: true,
45 | priority: 0,
46 | projectId: Appest.user.inboxId,
47 | remindTime: null,
48 | reminder: null,
49 | reminders: null,
50 | status: 0,
51 | timeZone: 'Asia/Shanghai',
52 | title: this.$el.value,
53 | }
54 | this.createTask(model)
55 | }
56 | }, false)
57 | },
58 |
59 | init () {
60 | this.initEvent()
61 | }
62 |
63 | }
64 |
65 | App.init()
66 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/lib/nconf/stores/argv.js:
--------------------------------------------------------------------------------
1 | /*
2 | * argv.js: Simple memory-based store for command-line arguments.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var util = require('util'),
9 | Memory = require('./memory').Memory;
10 |
11 | //
12 | // ### function Argv (options)
13 | // #### @options {Object} Options for this instance.
14 | // Constructor function for the Argv nconf store, a simple abstraction
15 | // around the Memory store that can read command-line arguments.
16 | //
17 | var Argv = exports.Argv = function (options, usage) {
18 | Memory.call(this, options);
19 |
20 | this.type = 'argv';
21 | this.readOnly = true;
22 | this.options = options || false;
23 | this.usage = usage;
24 | };
25 |
26 | // Inherit from the Memory store
27 | util.inherits(Argv, Memory);
28 |
29 | //
30 | // ### function loadSync ()
31 | // Loads the data passed in from `process.argv` into this instance.
32 | //
33 | Argv.prototype.loadSync = function () {
34 | this.loadArgv();
35 | return this.store;
36 | };
37 |
38 | //
39 | // ### function loadArgv ()
40 | // Loads the data passed in from the command-line arguments
41 | // into this instance.
42 | //
43 | Argv.prototype.loadArgv = function () {
44 | var self = this,
45 | yargs, argv;
46 |
47 | yargs = typeof this.options === 'object'
48 | ? require('yargs')(process.argv.slice(2)).options(this.options)
49 | : require('yargs')(process.argv.slice(2));
50 |
51 | if (typeof this.usage === 'string') { yargs.usage(this.usage) }
52 |
53 | argv = yargs.argv
54 |
55 | if (!argv) {
56 | return;
57 | }
58 |
59 | this.readOnly = false;
60 | Object.keys(argv).forEach(function (key) {
61 | if (typeof argv[key] !== 'undefined') {
62 | self.set(key, argv[key]);
63 | }
64 | });
65 |
66 | this.showHelp = yargs.showHelp
67 | this.help = yargs.help
68 |
69 | this.readOnly = true;
70 | return this.store;
71 | };
72 |
--------------------------------------------------------------------------------
/app/node_modules/objectid/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "objectid",
3 | "version": "3.2.1",
4 | "description": "mongodb objectid utilities",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "node node_modules/mocha/bin/mocha"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+ssh://git@github.com/AgileDiagnosis/objectid.git"
12 | },
13 | "keywords": [
14 | "mongodb",
15 | "objectid"
16 | ],
17 | "author": {
18 | "name": "Agile Diagnosis",
19 | "email": "hello@agilediagnosis.com"
20 | },
21 | "contributors": [
22 | {
23 | "name": "jden",
24 | "email": "jason@denizac.org"
25 | }
26 | ],
27 | "license": "MIT",
28 | "devDependencies": {
29 | "bson": "~0.1.8",
30 | "chai": "~1.5.0",
31 | "chai-interface": "~1.1.0",
32 | "mocha": "~1.8.2",
33 | "mongodb": "~1.2.12"
34 | },
35 | "dependencies": {
36 | "bson": "^0.1.9"
37 | },
38 | "gitHead": "5bbce7750dda1e82d01a7de57266d16e29fbb3ce",
39 | "bugs": {
40 | "url": "https://github.com/AgileDiagnosis/objectid/issues"
41 | },
42 | "homepage": "https://github.com/AgileDiagnosis/objectid#readme",
43 | "_id": "objectid@3.2.1",
44 | "_shasum": "a3b7a2b4d65f3a8348ef8497f023069b5cb019de",
45 | "_from": "objectid@>=3.2.1 <4.0.0",
46 | "_npmVersion": "3.1.0",
47 | "_nodeVersion": "0.10.36",
48 | "_npmUser": {
49 | "name": "jden",
50 | "email": "jason@denizac.org"
51 | },
52 | "dist": {
53 | "shasum": "a3b7a2b4d65f3a8348ef8497f023069b5cb019de",
54 | "size": 3402,
55 | "noattachment": false,
56 | "tarball": "http://registry.npm.taobao.org/objectid/download/objectid-3.2.1.tgz"
57 | },
58 | "maintainers": [
59 | {
60 | "name": "jden",
61 | "email": "jason@denizac.org"
62 | }
63 | ],
64 | "directories": {},
65 | "publish_time": 1437500306619,
66 | "_cnpm_publish_time": 1437500306619,
67 | "_resolved": "https://registry.npm.taobao.org/objectid/download/objectid-3.2.1.tgz",
68 | "readme": "ERROR: No README data found!"
69 | }
70 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/helpers.js:
--------------------------------------------------------------------------------
1 | /*
2 | * helpers.js: Test helpers for nconf.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var assert = require('assert'),
9 | spawn = require('child_process').spawn,
10 | util = require('util'),
11 | fs = require('fs'),
12 | path = require('path'),
13 | nconf = require('../lib/nconf');
14 |
15 | exports.assertMerged = function (err, merged) {
16 | merged = merged instanceof nconf.Provider
17 | ? merged.store.store
18 | : merged;
19 |
20 | assert.isNull(err);
21 | assert.isObject(merged);
22 | assert.isTrue(merged.apples);
23 | assert.isTrue(merged.bananas);
24 | assert.isObject(merged.candy);
25 | assert.isTrue(merged.candy.something1);
26 | assert.isTrue(merged.candy.something2);
27 | assert.isTrue(merged.candy.something3);
28 | assert.isTrue(merged.candy.something4);
29 | assert.isTrue(merged.dates);
30 | assert.isTrue(merged.elderberries);
31 | };
32 |
33 | exports.assertSystemConf = function (options) {
34 | return {
35 | topic: function () {
36 | var env = null;
37 |
38 | if (options.env) {
39 | env = {}
40 | Object.keys(process.env).forEach(function (key) {
41 | env[key] = process.env[key];
42 | });
43 |
44 | Object.keys(options.env).forEach(function (key) {
45 | env[key] = options.env[key];
46 | });
47 | }
48 |
49 | var child = spawn('node', [options.script].concat(options.argv), { env: env });
50 | child.stdout.once('data', this.callback.bind(this, null));
51 | },
52 | "should respond with the value passed into the script": function (_, data) {
53 | assert.equal(data.toString(), 'foobar');
54 | }
55 | }
56 | }
57 |
58 | // copy a file
59 | exports.cp = function (from, to, callback) {
60 | fs.readFile(from, function (err, data) {
61 | if (err) return callback(err);
62 | fs.writeFile(to, data, callback);
63 | });
64 | };
65 |
66 | exports.fixture = function (file) {
67 | return path.join(__dirname, 'fixtures', file);
68 | };
69 |
--------------------------------------------------------------------------------
/app/sign/icon.mustache:
--------------------------------------------------------------------------------
1 | {
2 | 'functions': true
3 | }
4 |
5 | $sprite: (
6 | {{#items}}
7 | {{name}}: (
8 | offset-x: {{px.offset_x}},
9 | offset-y: {{px.offset_y}},
10 | width: {{px.width}},
11 | height: {{px.height}},
12 | total-width: {{px.total_width}},
13 | total-height: {{px.total_height}},
14 | image: '{{{escaped_image}}}'
15 | ),
16 | {{/items}}
17 | parts: (
18 | total-width: {{items.0.px.total_width}},
19 | total-height: {{items.0.px.total_height}},
20 | image: '{{{items.0.escaped_image}}}'
21 | )
22 | );
23 |
24 | {{#options.functions}}
25 |
26 | @mixin sprite-size($image) {
27 | background-size: map-get(map-get($sprite, $image), 'total-width') map-get(map-get($sprite, $image), 'total-height');
28 | }
29 |
30 | @mixin sprite-width($image) {
31 | width: map-get(map-get($sprite, $image), 'width');
32 | }
33 |
34 | @mixin sprite-height($image) {
35 | height: map-get(map-get($sprite, $image), 'height');
36 | }
37 |
38 | @mixin sprite-position($image) {
39 | background-position: map-get(map-get($sprite, $image), 'offset-x') map-get(map-get($sprite, $image), 'offset-y');
40 | }
41 |
42 | @mixin sprite-image($image) {
43 | background-image: url(map-get(map-get($sprite, $image), 'image') + '.png');
44 | }
45 |
46 | @mixin sprite-image-retina($image) {
47 | background-image: url(map-get(map-get($sprite, $image), 'image') + '@2.png');
48 | }
49 |
50 |
51 | {{/options.functions}}
52 |
53 |
54 | {{#items}}
55 | .icon-{{name}} {
56 | @include sprite-width("{{name}}");
57 | @include sprite-height("{{name}}");
58 | @include sprite-position("{{name}}");
59 | }
60 | {{/items}}
61 |
62 |
63 | .icon_sign {
64 | @include sprite-size('parts');
65 | background-repeat: no-repeat;
66 | display: inline-block;
67 | @media
68 | only screen and (-webkit-min-device-pixel-ratio: 2),
69 | only screen and ( min--moz-device-pixel-ratio: 2),
70 | only screen and ( -o-min-device-pixel-ratio: 2/1),
71 | only screen and ( min-device-pixel-ratio: 2),
72 | only screen and ( min-resolution: 192dpi),
73 | only screen and ( min-resolution: 2dppx) {
74 |
75 | @include sprite-size('parts');
76 |
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | shell = require('gulp-shell'),
3 | rename = require('gulp-rename'),
4 | del = require('del'),
5 | packager = require('electron-packager'),
6 | builder = require('electron-builder'),
7 | argv = require('yargs').argv,
8 | pjson = require('./package.json')
9 |
10 |
11 |
12 | gulp.task('config', function () {
13 | var name = argv.site === 'dida' ? 'dida' : 'tick'
14 | gulp.src(['./app/' + 'appest-' + name + '.js'])
15 | .pipe(rename(function(path) {
16 | path.basename = 'appest'
17 | }))
18 | .pipe(gulp.dest('./app'))
19 | })
20 |
21 |
22 | gulp.task('pkg:packager', function () {
23 | var name = argv.site === 'dida' ? 'dida' : 'ticktick'
24 | var opts = {
25 | 'dir': './app',
26 | 'arch': 'x64',
27 | 'platform': 'darwin,win32',
28 | 'all': false,
29 | 'app-category-type': 'public.app-category.utilities',
30 | 'app-version': pjson.version,
31 | 'asar': false,
32 | 'icon': './app/icons/icon.png',
33 | // 'ignore': /node_modules/,
34 | 'name': name,
35 | 'out': './pkg',
36 | 'overwrite': true
37 | }
38 | packager(opts, function done (err, appPath) {
39 | console.log(appPath)
40 | })
41 | })
42 |
43 | gulp.task('pkg:clean', function () {
44 | del(['./pkg'])
45 | })
46 |
47 | gulp.task('pkg:builder:dida', shell.task([
48 | 'electron-builder \"pkg/dida-darwin-x64/dida.app\" --platform=osx --out=\"pkg/osx\" --config=builder.json',
49 | 'electron-builder \"pkg/dida-win32-x64\" --platform=win --out=\"pkg/win64\" --config=builder.json',
50 | // 'electron-builder \"pkg/dida-win32-ia32\" --platform=win --out=\"pkg/win32\" --config=builder.json'
51 | ]))
52 |
53 | gulp.task('pkg:builder:tick', shell.task([
54 | 'electron-builder \"pkg/ticktick-darwin-x64/ticktick.app\" --platform=osx --out=\"pkg/osx\" --config=builder-tick.json',
55 | 'electron-builder \"pkg/ticktick-win32-x64\" --platform=win --out=\"pkg/win64\" --config=builder-tick.json',
56 | // 'electron-builder \"pkg/ticktick-win32-ia32\" --platform=win --out=\"pkg/win32\" --config=builder-tick.json'
57 | ]))
58 |
59 | gulp.task('pkg:dida', shell.task([
60 | 'gulp pkg:clean',
61 | 'gulp config --site dida',
62 | 'gulp pkg:packager --site dida',
63 | 'gulp pkg:builder:dida'
64 | ]))
65 |
66 | gulp.task('pkg:tick', shell.task([
67 | 'gulp pkg:clean',
68 | 'gulp config --site tick',
69 | 'gulp pkg:packager --site tick',
70 | 'gulp pkg:builder:tick'
71 | ]))
72 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nconf",
3 | "description": "Hierarchical node.js configuration with files, environment variables, command-line arguments, and atomic object merging.",
4 | "version": "0.8.4",
5 | "author": {
6 | "name": "Charlie Robbins",
7 | "email": "charlie.robbins@gmail.com"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+ssh://git@github.com/flatiron/nconf.git"
12 | },
13 | "keywords": [
14 | "configuration",
15 | "key value store",
16 | "plugabble"
17 | ],
18 | "dependencies": {
19 | "async": "^1.4.0",
20 | "ini": "^1.3.0",
21 | "secure-keys": "^1.0.0",
22 | "yargs": "^3.19.0"
23 | },
24 | "devDependencies": {
25 | "coveralls": "^2.11.4",
26 | "istanbul": "^0.4.1",
27 | "vows": "0.8.x"
28 | },
29 | "main": "./lib/nconf",
30 | "scripts": {
31 | "test": "vows test/*-test.js test/**/*-test.js --spec",
32 | "cover": "istanbul cover vows -- test/*-test.js test/**/*-test.js --spec",
33 | "coveralls": "cat coverage/lcov.info | coveralls"
34 | },
35 | "engines": {
36 | "node": ">= 0.4.0"
37 | },
38 | "license": "MIT",
39 | "gitHead": "3d4e58957878fab80fb3125784c04b615cf2f52e",
40 | "bugs": {
41 | "url": "https://github.com/flatiron/nconf/issues"
42 | },
43 | "homepage": "https://github.com/flatiron/nconf#readme",
44 | "_id": "nconf@0.8.4",
45 | "_shasum": "9502234f7ad6238cab7f92d7c068c20434d3ff93",
46 | "_from": "nconf@>=0.8.4 <0.9.0",
47 | "_npmVersion": "2.14.7",
48 | "_nodeVersion": "4.2.3",
49 | "_npmUser": {
50 | "name": "jcrugzz",
51 | "email": "jcrugzz@gmail.com"
52 | },
53 | "dist": {
54 | "shasum": "9502234f7ad6238cab7f92d7c068c20434d3ff93",
55 | "size": 36052,
56 | "noattachment": false,
57 | "tarball": "http://registry.npm.taobao.org/nconf/download/nconf-0.8.4.tgz"
58 | },
59 | "maintainers": [
60 | {
61 | "name": "indexzero",
62 | "email": "charlie.robbins@gmail.com"
63 | },
64 | {
65 | "name": "jcrugzz",
66 | "email": "jcrugzz@gmail.com"
67 | }
68 | ],
69 | "_npmOperationalInternal": {
70 | "host": "packages-9-west.internal.npmjs.com",
71 | "tmp": "tmp/nconf-0.8.4.tgz_1454488758244_0.9802679584827274"
72 | },
73 | "directories": {},
74 | "publish_time": 1454488758997,
75 | "_cnpm_publish_time": 1454488758997,
76 | "_resolved": "https://registry.npm.taobao.org/nconf/download/nconf-0.8.4.tgz",
77 | "readme": "ERROR: No README data found!"
78 | }
79 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/lib/nconf/stores/env.js:
--------------------------------------------------------------------------------
1 | /*
2 | * env.js: Simple memory-based store for environment variables
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var util = require('util'),
9 | common = require('../common'),
10 | Memory = require('./memory').Memory;
11 |
12 | //
13 | // ### function Env (options)
14 | // #### @options {Object} Options for this instance.
15 | // Constructor function for the Env nconf store, a simple abstraction
16 | // around the Memory store that can read process environment variables.
17 | //
18 | var Env = exports.Env = function (options) {
19 | Memory.call(this, options);
20 |
21 | options = options || {};
22 | this.type = 'env';
23 | this.readOnly = true;
24 | this.whitelist = options.whitelist || [];
25 | this.separator = options.separator || '';
26 | this.lowerCase = options.lowerCase || false;
27 |
28 | if (({}).toString.call(options.match) === '[object RegExp]'
29 | && typeof options !== 'string') {
30 | this.match = options.match;
31 | }
32 |
33 | if (options instanceof Array) {
34 | this.whitelist = options;
35 | }
36 | if (typeof(options) === 'string') {
37 | this.separator = options;
38 | }
39 | };
40 |
41 | // Inherit from the Memory store
42 | util.inherits(Env, Memory);
43 |
44 | //
45 | // ### function loadSync ()
46 | // Loads the data passed in from `process.env` into this instance.
47 | //
48 | Env.prototype.loadSync = function () {
49 | this.loadEnv();
50 | return this.store;
51 | };
52 |
53 | //
54 | // ### function loadEnv ()
55 | // Loads the data passed in from `process.env` into this instance.
56 | //
57 | Env.prototype.loadEnv = function () {
58 | var self = this;
59 |
60 | var env = process.env;
61 |
62 | if (this.lowerCase) {
63 | Object.keys(env).forEach(function (key) {
64 | env[key.toLowerCase()] = env[key];
65 | });
66 | }
67 |
68 | this.readOnly = false;
69 | Object.keys(env).filter(function (key) {
70 | if (self.match && self.whitelist.length) {
71 | return key.match(self.match) || self.whitelist.indexOf(key) !== -1
72 | }
73 | else if (self.match) {
74 | return key.match(self.match);
75 | }
76 | else {
77 | return !self.whitelist.length || self.whitelist.indexOf(key) !== -1
78 | }
79 | }).forEach(function (key) {
80 | if (self.separator) {
81 | self.set(common.key.apply(common, key.split(self.separator)), env[key]);
82 | }
83 | else {
84 | self.set(key, env[key]);
85 | }
86 | });
87 |
88 | this.readOnly = true;
89 | return this.store;
90 | };
91 |
92 |
--------------------------------------------------------------------------------
/app/sign/src/styles/_color.scss:
--------------------------------------------------------------------------------
1 | /* ========== Color Palettes ========== */
2 |
3 | $white: #fff;
4 | $black: #000;
5 | $bistre: #333;
6 | $darkgrey: #737373;
7 | $manatee: #aaa;
8 | $red: #ff3180;
9 | $indigo: #617fde;
10 | $bluesky: #516bc1;
11 | $theme-red: #fd7897;
12 | $theme-green: #06ce90;
13 |
14 | // min-cal
15 | $bluegray: #5a76bc;
16 | $ballblue: #617fde;
17 | $cobalt: #9cb3ed;
18 | $vanilla: #ffc817;
19 |
20 | // tk-cal
21 | $paleorange: #fff2e2;
22 | $lightorange: #ffab3c;
23 | $lightgrayishblue: rgba(97, 127, 222, 0.2);
24 | $grayishblue: #eff2fb;
25 |
26 |
27 | $whitegray: #fdfdfd;
28 |
29 | $vwhitegray: #fcfcfc;
30 |
31 | $pink: #e86499;
32 | $tuftsblue: #8ea0cb;
33 |
34 |
35 | $brandeisblue: #6d8ee1;
36 |
37 | $steelblue: #5c7bc5;
38 | $ceruleanblue: #5a77bf;
39 |
40 | $orangered: #fd5d5f;
41 | $mediumseagreen: #3cc6cc;
42 |
43 | $mulberry: #e86499;
44 | $shamrock: #28e0bf;
45 | $springgreen: #49d498;
46 | $yellow: #ffefd8;
47 |
48 | $grey: #ddd;
49 | $cadetgrey: #ababab;
50 | $ashgrey: #f3f3f3;
51 | $platinum: #f7f7f7;
52 | $timberwolf: #ececec;
53 | $lavendergray: #c7c7c7;
54 |
55 | $whitelilac: #ebebeb;
56 |
57 | $disabled: #a8a8a8;
58 |
59 | $verylightgray: #fefefe;
60 |
61 | $lightwhite: #fafafa;
62 |
63 | $white4: rgba(225,225,225,0.4);
64 | $white6: rgba(225,225,225,0.6);
65 | $white8: rgba(225,225,225,0.8);
66 |
67 | $black05: rgba(0,0,0,.05);
68 | $black08: rgba(0,0,0,.08);
69 | $black1: rgba(0,0,0,.1);
70 | $black2: rgba(0,0,0,.2);
71 | $black3: rgba(0,0,0,.3);
72 | $black4: rgba(0,0,0,.4);
73 |
74 | $grey15: rgba(243,243,243,0.6);
75 |
76 | // list color
77 | $l-color-0: transparent;
78 | $l-color-1: #90ABD6;
79 | $l-color-2: #499FB4;
80 | $l-color-3: #3CB878;
81 | $l-color-4: #7FDD81;
82 | $l-color-5: #C4E365;
83 | $l-color-6: #E864A8;
84 | $l-color-7: #FD5E5E;
85 | $l-color-8: #F3BB4C;
86 | $l-color-9: #FFE954;
87 |
88 | // priority color
89 | $priority-high: #ff3180;
90 | $priority-medium: #ffc817;
91 | $priority-low: #617fde;
92 |
93 |
94 |
95 | // activity
96 | $limegreen: #18d791;
97 | $softred: rgba(241, 89, 100,0.8);
98 | $moderateblue: rgba(100,132,213,0.8);
99 |
100 | $lightblack: rgba(0,0,0,0.1);
101 |
102 | $lightgray: rgba(0, 0, 0, 0.15);
103 |
104 | $blackwhite: #d3dbf3;
105 | $blackblue: #5a7bcf;
106 |
107 | $opacityindigo: rgba(97,127,222,0.1);
108 | $opacitywhite: rgba(255,255,255,0.3);
109 |
110 |
111 | // dark theme
112 | $dark-deepgray: #313643;
113 | $dark-lightgray: #3f4658;
114 | $dark-lightgray1: rgba(49, 54, 67, 0.1);
115 | $dark-lightgray2: rgba(49, 54, 67, 0.2);
116 |
--------------------------------------------------------------------------------
/app/sign/src/styles/_functions.scss:
--------------------------------------------------------------------------------
1 | // Foundation by ZURB
2 | // foundation.zurb.com
3 | // Licensed under MIT Open Source
4 |
5 | // This is the default html and body font-size for the base rem value.
6 | $rem-base: 16px !default;
7 |
8 | // IMPORT ONCE
9 | // We use this to prevent styles from being loaded multiple times for compenents that rely on other components.
10 | $modules: () !default;
11 | @mixin exports($name) {
12 | @if (index($modules, $name) == false or index($modules, $name) == null) {
13 | $modules: append($modules, $name);
14 | @content;
15 | }
16 | }
17 |
18 | //
19 | // @functions
20 | //
21 |
22 |
23 | // RANGES
24 | // We use these functions to define ranges for various things, like media queries.
25 | @function lower-bound($range){
26 | @if length($range) <= 0 {
27 | @return 0;
28 | }
29 | @return nth($range,1);
30 | }
31 |
32 | @function upper-bound($range) {
33 | @if length($range) < 2 {
34 | @return 999999999999;
35 | }
36 | @return nth($range, 2);
37 | }
38 |
39 | // STRIP UNIT
40 | // It strips the unit of measure and returns it
41 | @function strip-unit($num) {
42 | @return $num / ($num * 0 + 1);
43 | }
44 |
45 | // CONVERT TO REM
46 | @function convert-to-rem($value, $base-value: $rem-base) {
47 | $value: strip-unit($value) / strip-unit($base-value) * 1rem;
48 | @if ($value == 0rem) { $value: 0; } // Turn 0rem into 0
49 | @return $value;
50 | }
51 |
52 | @function data($attr) {
53 | @if $namespace {
54 | @return '[data-' + $namespace + '-' + $attr + ']';
55 | }
56 |
57 | @return '[data-' + $attr + ']';
58 | }
59 |
60 | // REM CALC
61 |
62 | // New Syntax, allows to optionally calculate on a different base value to counter compounding effect of rem's.
63 | // Call with 1, 2, 3 or 4 parameters, 'px' is not required but supported:
64 | //
65 | // rem-calc(10 20 30px 40);
66 | //
67 | // Space delimited, if you want to delimit using comma's, wrap it in another pair of brackets
68 | //
69 | // rem-calc((10, 20, 30, 40px));
70 | //
71 | // Optionally call with a different base (eg: 8px) to calculate rem.
72 | //
73 | // rem-calc(16px 32px 48px, 8px);
74 | //
75 | // If you require to comma separate your list
76 | //
77 | // rem-calc((16px, 32px, 48), 8px);
78 |
79 | @function rem-calc($values, $base-value: $rem-base) {
80 | //$max: length($values);
81 |
82 | //@if $max == 1 { @return convert-to-rem(nth($values, 1), $base-value); }
83 |
84 | //$remValues: ();
85 | //@for $i from 1 through $max {
86 | // $remValues: append($remValues, convert-to-rem(nth($values, $i), $base-value));
87 | //}
88 | //@return $remValues;
89 | @return $values + 0px;
90 | }
91 |
--------------------------------------------------------------------------------
/app/sign/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | spritesmith = require('gulp.spritesmith'),
3 | minifycss = require('gulp-cssnano'),
4 | rename = require('gulp-rename'),
5 | shell = require('gulp-shell'),
6 | del = require('del'),
7 | autoprefixer = require('gulp-autoprefixer'),
8 | sass = require('gulp-sass')
9 |
10 |
11 | var dirs = {
12 | template : 'icon.mustache',
13 | styles : './src/styles',
14 | dest : './dist',
15 | images: {
16 | dest: './src/images',
17 | tick_sign_icons : './src/images/tick/sign-icons',
18 | icons : './src/images/common/sign-icons'
19 | },
20 | }
21 |
22 | var config = {
23 | 'sign' : {
24 | 'src' : [dirs.images.icons + '/*'],
25 | 'imgName' : 'sign-icons.png',
26 | 'cssName' : 'sign-icons.scss',
27 | 'imgDest' : dirs.dest,
28 | 'buildDest': dirs.build,
29 | 'cssDest' : dirs.styles,
30 | 'cssTemplate' : dirs.template,
31 | 'padding' : 0
32 | },
33 |
34 | 'sign2' : {
35 | 'src' : [dirs.images.icons + '@2/*'],
36 | 'imgName' : 'sign-icons@2.png',
37 | 'cssName' : 'sign-icons@2.scss',
38 | 'imgDest' : dirs.dest,
39 | 'buildDest': dirs.build,
40 | 'cssDest' : dirs.styles,
41 | 'cssTemplate' : dirs.template,
42 | 'padding' : 0
43 | }
44 | }
45 |
46 | function sprite(cfg) {
47 | var sprite = gulp.src(cfg.src)
48 | .pipe(spritesmith({
49 | imgName: cfg.imgName,
50 | cssName: cfg.cssName,
51 | algorithm: 'binary-tree',
52 | cssFormat: 'scss',
53 | cssTemplate: cfg.cssTemplate,
54 | engine: 'pngsmith',
55 | padding : cfg.padding
56 | }))
57 |
58 | sprite.img.pipe(gulp.dest(cfg.imgDest))
59 | sprite.css.pipe(gulp.dest(cfg.cssDest))
60 | }
61 |
62 | gulp.task('styles', function () {
63 | gulp.src(dirs.styles + '/main.scss')
64 | .pipe(sass())
65 | .pipe(autoprefixer({
66 | browsers: ['last 2 version', 'safari 5', 'ie 7', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'],
67 | cascade: false
68 | }))
69 | .pipe(rename({
70 | basename: 'sign'
71 | }))
72 | .pipe(minifycss({ keepSpecialComments : 0 }))
73 | .pipe(rename({
74 | suffix: '.min'
75 | }))
76 | .pipe(gulp.dest(dirs.dest))
77 | })
78 |
79 | gulp.task('sprite', function () {
80 | sprite(config.sign)
81 | sprite(config.sign2)
82 | })
83 |
84 | gulp.task('clean', function() {
85 | del([dirs.dest], {
86 | force: true
87 | })
88 | })
89 |
90 | gulp.task('build', shell.task([
91 | 'gulp clean',
92 | 'gulp sprite',
93 | 'gulp styles'
94 | ]))
95 |
96 | gulp.task('watch', function () {
97 | gulp.watch('./src/**/*', ['sprite','styles'])
98 | })
99 |
--------------------------------------------------------------------------------
/app/main.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | let path = require('path'),
4 | electron = require('electron')
5 |
6 | let app = electron.app
7 |
8 | let Menu = electron.Menu,
9 | BrowserWindow = electron.BrowserWindow,
10 | ipc = electron.ipcMain,
11 | globalShortcut = electron.globalShortcut
12 |
13 | let userConfig = require('./user-config'),
14 | menu = require('./menu'),
15 | appest = require('./appest')
16 |
17 | let setAppest = data => {
18 | userConfig.saveConfig(data)
19 | }
20 |
21 | // register shortcut
22 | let registerShortcut = () => {
23 | let ret = globalShortcut.register('Command+Shift+A', () => {
24 | if(indexWindow) {
25 | indexWindow.show()
26 | indexWindow.focus()
27 | }
28 | })
29 | if (!ret) {
30 | console.log('registration failed')
31 | }
32 | }
33 |
34 | let unRegisterShortcut = () => {
35 | globalShortcut.unregisterAll()
36 | }
37 |
38 | // app.commandLine.appendSwitch('ignore-certificate-errors', 'true')
39 |
40 | // Report crashes to our server.
41 | electron.crashReporter.start()
42 |
43 | // Quit when all windows are closed.
44 | app.on('window-all-closed', () => {
45 | // On OS X it is common for applications and their menu bar
46 | // to stay active until the user quits explicitly with Cmd + Q
47 | // if (process.platform != 'darwin') {
48 | unRegisterShortcut()
49 | app.quit()
50 | // }
51 | })
52 |
53 | let signin = data => {
54 | loginWindow && loginWindow.close()
55 | setAppest(data)
56 | if(indexWindow) {
57 | indexWindow.show()
58 | indexWindow.focus()
59 | } else {
60 | openIndex()
61 | }
62 | }
63 |
64 | // 登录
65 | ipc.on('signin', (event, data) => {
66 | signin(data)
67 | })
68 |
69 | // 登出
70 | ipc.on('signout', (event, data) => {
71 | userConfig.clearConfig()
72 | indexWindow && indexWindow.close()
73 | if(loginWindow) {
74 | loginWindow.show()
75 | loginWindow.focus()
76 | } else {
77 | openLogin()
78 | }
79 | })
80 |
81 | // This method will be called when Electron has finished
82 | // initialization and is ready to create browser windows.
83 | app.on('ready', () => {
84 | let config = userConfig.readConfig('Appest')
85 | if(config && config.user && config.user.inboxId) {
86 | openIndex()
87 | } else {
88 | openLogin()
89 | }
90 | Menu.setApplicationMenu(menu)
91 | registerShortcut()
92 | })
93 |
94 | // 默认窗口状态
95 | let defaultWin = {
96 | width: 620,
97 | height: 600,
98 | minWidth: 600,
99 | resizable: false,
100 | title: appest.productName,
101 | icon: path.resolve('./icons/', 'icon.png')
102 | }
103 |
104 | // 登陆窗口
105 | let loginWindow
106 | let openLogin = () => {
107 |
108 | let win = Object.assign({}, defaultWin)
109 |
110 | loginWindow = new BrowserWindow(win)
111 |
112 | loginWindow.loadURL('file://' + __dirname + '/signin.html')
113 |
114 | // loginWindow.webContents.openDevTools()
115 |
116 | loginWindow.on('closed', () => {
117 | loginWindow.destroy()
118 | loginWindow = null
119 | })
120 | }
121 |
122 | // 登录之后
123 | let indexWindow = null
124 | let openIndex = () => {
125 | if (indexWindow)
126 | return
127 |
128 | let win = Object.assign({}, defaultWin, {
129 | height: 55,
130 | transparent: false,
131 | frame: false
132 | })
133 |
134 | indexWindow = new BrowserWindow(win)
135 |
136 | indexWindow.loadURL('file://' + __dirname + '/index.html')
137 |
138 | // indexWindow.webContents.openDevTools()
139 |
140 | indexWindow.on('closed', () => {
141 | indexWindow.destroy()
142 | indexWindow = null
143 | })
144 | }
145 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/lib/nconf/common.js:
--------------------------------------------------------------------------------
1 | /*
2 | * utils.js: Utility functions for the nconf module.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var fs = require('fs'),
9 | async = require('async'),
10 | formats = require('./formats'),
11 | Memory = require('./stores/memory').Memory;
12 |
13 | var common = exports;
14 |
15 | //
16 | // ### function path (key)
17 | // #### @key {string} The ':' delimited key to split
18 | // Returns a fully-qualified path to a nested nconf key.
19 | // If given null or undefined it should return an empty path.
20 | // '' should still be respected as a path.
21 | //
22 | common.path = function (key, separator) {
23 | separator = separator || ':';
24 | return key == null ? [] : key.split(separator);
25 | };
26 |
27 | //
28 | // ### function key (arguments)
29 | // Returns a `:` joined string from the `arguments`.
30 | //
31 | common.key = function () {
32 | return Array.prototype.slice.call(arguments).join(':');
33 | };
34 |
35 | //
36 | // ### function key (arguments)
37 | // Returns a joined string from the `arguments`,
38 | // first argument is the join delimiter.
39 | //
40 | common.keyed = function () {
41 | return Array.prototype.slice.call(arguments, 1).join(arguments[0]);
42 | };
43 |
44 | //
45 | // ### function loadFiles (files, callback)
46 | // #### @files {Object|Array} List of files (or settings object) to load.
47 | // #### @callback {function} Continuation to respond to when complete.
48 | // Loads all the data in the specified `files`.
49 | //
50 | common.loadFiles = function (files, callback) {
51 | if (!files) {
52 | return callback(null, {});
53 | }
54 |
55 | var options = Array.isArray(files) ? { files: files } : files;
56 |
57 | //
58 | // Set the default JSON format if not already
59 | // specified
60 | //
61 | options.format = options.format || formats.json;
62 |
63 | function parseFile (file, next) {
64 | fs.readFile(file, function (err, data) {
65 | return !err
66 | ? next(null, options.format.parse(data.toString()))
67 | : next(err);
68 | });
69 | }
70 |
71 | async.map(options.files, parseFile, function (err, objs) {
72 | return err ? callback(err) : callback(null, common.merge(objs));
73 | });
74 | };
75 |
76 | //
77 | // ### function loadFilesSync (files)
78 | // #### @files {Object|Array} List of files (or settings object) to load.
79 | // Loads all the data in the specified `files` synchronously.
80 | //
81 | common.loadFilesSync = function (files) {
82 | if (!files) {
83 | return;
84 | }
85 |
86 | //
87 | // Set the default JSON format if not already
88 | // specified
89 | //
90 | var options = Array.isArray(files) ? { files: files } : files;
91 | options.format = options.format || formats.json;
92 |
93 | return common.merge(options.files.map(function (file) {
94 | return options.format.parse(fs.readFileSync(file, 'utf8'));
95 | }));
96 | };
97 |
98 | //
99 | // ### function merge (objs)
100 | // #### @objs {Array} Array of object literals to merge
101 | // Merges the specified `objs` using a temporary instance
102 | // of `stores.Memory`.
103 | //
104 | common.merge = function (objs) {
105 | var store = new Memory();
106 |
107 | objs.forEach(function (obj) {
108 | Object.keys(obj).forEach(function (key) {
109 | store.merge(key, obj[key]);
110 | });
111 | });
112 |
113 | return store.store;
114 | };
115 |
116 | //
117 | // ### function capitalize (str)
118 | // #### @str {string} String to capitalize
119 | // Capitalizes the specified `str`.
120 | //
121 | common.capitalize = function (str) {
122 | return str && str[0].toUpperCase() + str.slice(1);
123 | };
124 |
--------------------------------------------------------------------------------
/app/menu.js:
--------------------------------------------------------------------------------
1 | // menu
2 | 'use strict'
3 |
4 | let electron = require('electron')
5 |
6 | let app = electron.app,
7 | shell = electron.shell,
8 | Menu = electron.Menu,
9 | ipc = electron.ipcMain
10 |
11 | let appest = require('./appest')
12 |
13 | let template = [{
14 | label: 'Edit',
15 | submenu: [{
16 | label: 'Undo',
17 | accelerator: 'CmdOrCtrl+Z',
18 | role: 'undo'
19 | }, {
20 | label: 'Redo',
21 | accelerator: 'Shift+CmdOrCtrl+Z',
22 | role: 'redo'
23 | }, {
24 | type: 'separator'
25 | }, {
26 | label: 'Cut',
27 | accelerator: 'CmdOrCtrl+X',
28 | role: 'cut'
29 | }, {
30 | label: 'Copy',
31 | accelerator: 'CmdOrCtrl+C',
32 | role: 'copy'
33 | }, {
34 | label: 'Paste',
35 | accelerator: 'CmdOrCtrl+V',
36 | role: 'paste'
37 | }, {
38 | label: 'Select All',
39 | accelerator: 'CmdOrCtrl+A',
40 | role: 'selectall'
41 | }, ]
42 | }, {
43 | label: 'View',
44 | submenu: [{
45 | label: 'Reload',
46 | accelerator: 'CmdOrCtrl+R',
47 | click (item, focusedWindow) {
48 | if (focusedWindow)
49 | focusedWindow.reload()
50 | }
51 | }, {
52 | label: 'Toggle Full Screen',
53 | accelerator: ( () => {
54 | if (process.platform === 'darwin')
55 | return 'Ctrl+Command+F'
56 | else
57 | return 'F11'
58 | })(),
59 | click (item, focusedWindow) {
60 | if (focusedWindow)
61 | focusedWindow.setFullScreen(!focusedWindow.isFullScreen())
62 | }
63 | },
64 | {
65 | label: 'Toggle Developer Tools',
66 | accelerator: ( () => {
67 | if (process.platform === 'darwin')
68 | return 'Alt+Command+I'
69 | else
70 | return 'Ctrl+Shift+I'
71 | })(),
72 | click (item, focusedWindow) {
73 | if (focusedWindow)
74 | focusedWindow.toggleDevTools()
75 | }
76 | },
77 | ]
78 | }, {
79 | label: 'Window',
80 | role: 'window',
81 | submenu: [{
82 | label: 'Minimize',
83 | accelerator: 'CmdOrCtrl+M',
84 | role: 'minimize'
85 | }, {
86 | label: 'Close',
87 | accelerator: 'CmdOrCtrl+W',
88 | role: 'close'
89 | }, ]
90 | }, {
91 | label: 'Help',
92 | role: 'help',
93 | submenu: [{
94 | label: 'Learn More',
95 | click () {
96 | shell.openExternal('https://help.' + appest.domain)
97 | }
98 | }, ]
99 | }, ]
100 |
101 | if (process.platform === 'darwin') {
102 | let name = appest.productName
103 | // let name = app.getName()
104 | template.unshift({
105 | label: name,
106 | submenu: [{
107 | label: 'About ' + name,
108 | role: 'about'
109 | }, {
110 | type: 'separator'
111 | }, {
112 | label: 'Services',
113 | role: 'services',
114 | submenu: []
115 | }, {
116 | type: 'separator'
117 | }, {
118 | label: 'Hide ' + name,
119 | accelerator: 'Command+H',
120 | role: 'hide'
121 | }, {
122 | label: 'Hide Others',
123 | accelerator: 'Command+Alt+H',
124 | role: 'hideothers'
125 | }, {
126 | label: 'Show All',
127 | role: 'unhide'
128 | }, {
129 | type: 'separator'
130 | }, {
131 | label: 'Login Out',
132 | accelerator: 'Command+Shift+Q',
133 | click () {
134 | ipc._events.signout()
135 | }
136 | }, {
137 | type: 'separator'
138 | }, {
139 | label: 'Quit',
140 | accelerator: 'Command+Q',
141 | click () {
142 | app.quit()
143 | }
144 | }, ]
145 | })
146 | // Window menu.
147 | template[3].submenu.push({
148 | type: 'separator'
149 | }, {
150 | label: 'Bring All to Front',
151 | role: 'front'
152 | })
153 | }
154 |
155 | let menu = Menu.buildFromTemplate(template)
156 |
157 | module.exports = menu
158 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/hierarchy-test.js:
--------------------------------------------------------------------------------
1 | /*
2 | * hierarchy-test.js: Basic tests for hierarchical file stores.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var assert = require('assert'),
9 | fs = require('fs'),
10 | path = require('path'),
11 | spawn = require('child_process').spawn,
12 | vows = require('vows'),
13 | nconf = require('../lib/nconf');
14 |
15 | var configDir = path.join(__dirname, 'fixtures', 'hierarchy'),
16 | globalConfig = path.join(configDir, 'global.json'),
17 | userConfig = path.join(configDir, 'user.json');
18 |
19 | vows.describe('nconf/hierarchy').addBatch({
20 | "When using nconf": {
21 | "configured with two file stores": {
22 | topic: function () {
23 | nconf.add('user', { type: 'file', file: userConfig });
24 | nconf.add('global', { type: 'file', file: globalConfig });
25 | nconf.load();
26 | return nconf;
27 | },
28 | "should have the appropriate keys present": function () {
29 | assert.equal(nconf.get('title'), 'My specific title');
30 | assert.equal(nconf.get('color'), 'green');
31 | assert.equal(nconf.get('movie'), 'Kill Bill');
32 | }
33 | },
34 | "configured with two file stores using `file`": {
35 | topic: function () {
36 | nconf.file('user', userConfig);
37 | nconf.file('global', globalConfig);
38 | nconf.load();
39 | return nconf;
40 | },
41 | "should have the appropriate keys present": function () {
42 | assert.equal(nconf.get('title'), 'My specific title');
43 | assert.equal(nconf.get('color'), 'green');
44 | assert.equal(nconf.get('movie'), 'Kill Bill');
45 | }
46 | },
47 | "configured with .argv(), .env() and .file()": {
48 | topic: function () {
49 | var configFile = path.join(__dirname, 'fixtures', 'load-save.json'),
50 | script = path.join(__dirname, 'fixtures', 'scripts', 'nconf-hierarchical-load-save.js'),
51 | argv = ['--foo', 'foo', '--bar', 'bar'],
52 | that = this,
53 | data = '',
54 | child;
55 |
56 | try { fs.unlinkSync(configFile) }
57 | catch (ex) { }
58 |
59 | child = spawn('node', [script].concat(argv));
60 |
61 | child.stdout.on('data', function (d) {
62 | data += d;
63 | });
64 |
65 | child.on('close', function () {
66 | fs.readFile(configFile, 'utf8', that.callback.bind(null, null, data));
67 | });
68 | },
69 | "should not persist information passed in to process.env and process.argv to disk ": function (_, data, _, ondisk){
70 | assert.equal(data, 'foo');
71 | assert.deepEqual(JSON.parse(ondisk), {
72 | database: {
73 | host: '127.0.0.1',
74 | port: 5984
75 | }
76 | });
77 | }
78 | },
79 | "configured with .argv(), .file() and invoked with nested command line options": {
80 | topic: function () {
81 | var script = path.join(__dirname, 'fixtures', 'scripts', 'nconf-hierarchical-load-merge.js'),
82 | argv = ['--candy:something', 'foo', '--candy:something5:second', 'bar'],
83 | that = this,
84 | data = '',
85 | child;
86 |
87 | child = spawn('node', [script].concat(argv));
88 |
89 | child.stdout.on('data', function (d) {
90 | data += d;
91 | });
92 |
93 | child.on('close', function() {
94 | that.callback(null, data);
95 | });
96 | },
97 | "should merge nested objects ": function (err, data) {
98 | assert.deepEqual(JSON.parse(data), {
99 | apples: true,
100 | candy: {
101 | something: 'foo',
102 | something1: true,
103 | something2: true,
104 | something5: {
105 | first: 1,
106 | second: 'bar'
107 | }
108 | }
109 | });
110 | }
111 | }
112 | }
113 | }).export(module);
114 |
--------------------------------------------------------------------------------
/app/sign/src/styles/_mixins.scss:
--------------------------------------------------------------------------------
1 |
2 | @mixin centerX {
3 | position: absolute;
4 | left: 50%;
5 | transform: translateX(-50%);
6 | }
7 |
8 | @mixin centerY {
9 | position: absolute;
10 | top: 50%;
11 | transform: translateY(-50%);
12 | }
13 |
14 | @mixin center {
15 | position: absolute;
16 | top: 50%;
17 | left: 50%;
18 | transform: translate(-50%, -50%);
19 | }
20 |
21 | @mixin ellipsis {
22 | max-width: 100%;
23 | white-space: nowrap;
24 | text-overflow: ellipsis;
25 | overflow: hidden;
26 | }
27 |
28 | // fix inline-block ele bug
29 | @mixin inlineblockfix {
30 | font-size: 0;
31 | }
32 |
33 | //clear floats
34 | @mixin clearfix {
35 | &:before, &:after { content: " "; display: table; }
36 | &:after { clear: both; }
37 | }
38 |
39 | //user-select
40 | @mixin user-select($type: text) {
41 | -moz-user-select: $type;
42 | -webkit-user-select: $type;
43 | -ms-user-select: $type;
44 | }
45 |
46 | //
47 | @mixin liheight($height) {
48 | height: $height;
49 | line-height: $height;
50 | }
51 |
52 | @mixin minliheight($height) {
53 | min-height: $height;
54 | line-height: $height;
55 | }
56 |
57 | //
58 | @mixin single-transition($property:all, $speed:300ms, $ease:ease-out) {
59 | transition: $property $speed $ease;
60 | }
61 |
62 | // create isosceles triangles
63 | // $triangle-size - Used to set border-size. No default, set a px or em size.
64 | // $triangle-color - Used to set border-color which makes up triangle. No default
65 | // $triangle-direction - Used to determine which direction triangle points. Options: top, bottom, left, right
66 | @mixin css-triangle($triangle-size, $triangle-color, $triangle-direction) {
67 | border: inset $triangle-size;
68 | content: "";
69 | display: block;
70 | height: 0;
71 | width: 0;
72 | @if ($triangle-direction == top) {
73 | border-color: $triangle-color transparent transparent transparent;
74 | border-top-style: solid;
75 | }
76 | @if ($triangle-direction == bottom) {
77 | border-color: transparent transparent $triangle-color transparent;
78 | border-bottom-style: solid;
79 | }
80 | @if ($triangle-direction == left) {
81 | border-color: transparent transparent transparent $triangle-color;
82 | border-left-style: solid;
83 | }
84 | @if ($triangle-direction == right) {
85 | border-color: transparent $triangle-color transparent transparent;
86 | border-right-style: solid;
87 | }
88 | }
89 |
90 | // create the icon with three lines aka the hamburger icon, the menu-icon or the navicon
91 | // $width - Width of hamburger icon in rem
92 | // $left - If false, icon will be centered horizontally || explicitly set value in rem
93 | // $top - If false, icon will be centered vertically || explicitly set value in rem
94 | // $thickness - thickness of lines in hamburger icon, set value in px
95 | // $gap - spacing between the lines in hamburger icon, set value in px
96 | // $color - icon color
97 | // $hover-color - icon color during hover
98 | // $offcanvas - Set to true of @include in offcanvas
99 | @mixin hamburger($width, $left, $top, $thickness, $gap, $color, $hover-color, $offcanvas) {
100 | span::after {
101 | content: "";
102 | display: block;
103 | height: 0;
104 | position: absolute;
105 |
106 | @if $offcanvas {
107 | @if $top {
108 | top: $top;
109 | }
110 | @else {
111 | top: 50%;
112 | margin-top: (-$width/2);
113 | }
114 | @if $left {
115 | left: $left;
116 | }
117 | @else {
118 | left: (rem-calc(50) - $width)/2;
119 | }
120 | }
121 | @else {
122 | top: 50%;
123 | #{$opposite-direction}: 15px;
124 | }
125 |
126 | box-shadow:
127 | 0 0 0 $thickness $color,
128 | 0 $gap + $thickness 0 $thickness $color,
129 | 0 (2 * $gap + 2*$thickness) 0 $thickness $color;
130 | width: $width;
131 | }
132 | span:hover:after {
133 | box-shadow:
134 | 0 0 0 $thickness $hover-color,
135 | 0 $gap + $thickness 0 $thickness $hover-color,
136 | 0 (2 * $gap + 2*$thickness) 0 $thickness $hover-color;
137 | }
138 | }
--------------------------------------------------------------------------------
/app/sign/src/styles/sign-icons.scss:
--------------------------------------------------------------------------------
1 | $sprite: (
2 | email-blue: (
3 | offset-x: -64px,
4 | offset-y: 0px,
5 | width: 24px,
6 | height: 24px,
7 | total-width: 112px,
8 | total-height: 92px,
9 | image: 'sign-icons.png'
10 | ),
11 | email-gray: (
12 | offset-x: -64px,
13 | offset-y: -24px,
14 | width: 24px,
15 | height: 24px,
16 | total-width: 112px,
17 | total-height: 92px,
18 | image: 'sign-icons.png'
19 | ),
20 | lock-blue: (
21 | offset-x: -88px,
22 | offset-y: 0px,
23 | width: 24px,
24 | height: 24px,
25 | total-width: 112px,
26 | total-height: 92px,
27 | image: 'sign-icons.png'
28 | ),
29 | lock-gray: (
30 | offset-x: -88px,
31 | offset-y: -24px,
32 | width: 24px,
33 | height: 24px,
34 | total-width: 112px,
35 | total-height: 92px,
36 | image: 'sign-icons.png'
37 | ),
38 | logo: (
39 | offset-x: 0px,
40 | offset-y: 0px,
41 | width: 64px,
42 | height: 68px,
43 | total-width: 112px,
44 | total-height: 92px,
45 | image: 'sign-icons.png'
46 | ),
47 | name-blue: (
48 | offset-x: 0px,
49 | offset-y: -68px,
50 | width: 24px,
51 | height: 24px,
52 | total-width: 112px,
53 | total-height: 92px,
54 | image: 'sign-icons.png'
55 | ),
56 | name-gray: (
57 | offset-x: -24px,
58 | offset-y: -68px,
59 | width: 24px,
60 | height: 24px,
61 | total-width: 112px,
62 | total-height: 92px,
63 | image: 'sign-icons.png'
64 | ),
65 | parts: (
66 | total-width: 112px,
67 | total-height: 92px,
68 | image: 'sign-icons.png'
69 | )
70 | );
71 |
72 |
73 | @mixin sprite-size($image) {
74 | background-size: map-get(map-get($sprite, $image), 'total-width') map-get(map-get($sprite, $image), 'total-height');
75 | }
76 |
77 | @mixin sprite-width($image) {
78 | width: map-get(map-get($sprite, $image), 'width');
79 | }
80 |
81 | @mixin sprite-height($image) {
82 | height: map-get(map-get($sprite, $image), 'height');
83 | }
84 |
85 | @mixin sprite-position($image) {
86 | background-position: map-get(map-get($sprite, $image), 'offset-x') map-get(map-get($sprite, $image), 'offset-y');
87 | }
88 |
89 | @mixin sprite-image($image) {
90 | background-image: url(map-get(map-get($sprite, $image), 'image') + '.png');
91 | }
92 |
93 | @mixin sprite-image-retina($image) {
94 | background-image: url(map-get(map-get($sprite, $image), 'image') + '@2.png');
95 | }
96 |
97 |
98 |
99 |
100 | .icon-email-blue {
101 | @include sprite-width("email-blue");
102 | @include sprite-height("email-blue");
103 | @include sprite-position("email-blue");
104 | }
105 | .icon-email-gray {
106 | @include sprite-width("email-gray");
107 | @include sprite-height("email-gray");
108 | @include sprite-position("email-gray");
109 | }
110 | .icon-lock-blue {
111 | @include sprite-width("lock-blue");
112 | @include sprite-height("lock-blue");
113 | @include sprite-position("lock-blue");
114 | }
115 | .icon-lock-gray {
116 | @include sprite-width("lock-gray");
117 | @include sprite-height("lock-gray");
118 | @include sprite-position("lock-gray");
119 | }
120 | .icon-logo {
121 | @include sprite-width("logo");
122 | @include sprite-height("logo");
123 | @include sprite-position("logo");
124 | }
125 | .icon-name-blue {
126 | @include sprite-width("name-blue");
127 | @include sprite-height("name-blue");
128 | @include sprite-position("name-blue");
129 | }
130 | .icon-name-gray {
131 | @include sprite-width("name-gray");
132 | @include sprite-height("name-gray");
133 | @include sprite-position("name-gray");
134 | }
135 |
136 |
137 | .icon_sign {
138 | @include sprite-size('parts');
139 | background-repeat: no-repeat;
140 | display: inline-block;
141 | @media
142 | only screen and (-webkit-min-device-pixel-ratio: 2),
143 | only screen and ( min--moz-device-pixel-ratio: 2),
144 | only screen and ( -o-min-device-pixel-ratio: 2/1),
145 | only screen and ( min-device-pixel-ratio: 2),
146 | only screen and ( min-resolution: 192dpi),
147 | only screen and ( min-resolution: 2dppx) {
148 |
149 | @include sprite-size('parts');
150 |
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/app/sign/src/styles/sign-icons@2.scss:
--------------------------------------------------------------------------------
1 | $sprite: (
2 | email-blue: (
3 | offset-x: -128px,
4 | offset-y: 0px,
5 | width: 48px,
6 | height: 48px,
7 | total-width: 224px,
8 | total-height: 184px,
9 | image: 'sign-icons@2.png'
10 | ),
11 | email-gray: (
12 | offset-x: -128px,
13 | offset-y: -48px,
14 | width: 48px,
15 | height: 48px,
16 | total-width: 224px,
17 | total-height: 184px,
18 | image: 'sign-icons@2.png'
19 | ),
20 | lock-blue: (
21 | offset-x: -176px,
22 | offset-y: 0px,
23 | width: 48px,
24 | height: 48px,
25 | total-width: 224px,
26 | total-height: 184px,
27 | image: 'sign-icons@2.png'
28 | ),
29 | lock-gray: (
30 | offset-x: -176px,
31 | offset-y: -48px,
32 | width: 48px,
33 | height: 48px,
34 | total-width: 224px,
35 | total-height: 184px,
36 | image: 'sign-icons@2.png'
37 | ),
38 | logo: (
39 | offset-x: 0px,
40 | offset-y: 0px,
41 | width: 128px,
42 | height: 136px,
43 | total-width: 224px,
44 | total-height: 184px,
45 | image: 'sign-icons@2.png'
46 | ),
47 | name-blue: (
48 | offset-x: 0px,
49 | offset-y: -136px,
50 | width: 48px,
51 | height: 48px,
52 | total-width: 224px,
53 | total-height: 184px,
54 | image: 'sign-icons@2.png'
55 | ),
56 | name-gray: (
57 | offset-x: -48px,
58 | offset-y: -136px,
59 | width: 48px,
60 | height: 48px,
61 | total-width: 224px,
62 | total-height: 184px,
63 | image: 'sign-icons@2.png'
64 | ),
65 | parts: (
66 | total-width: 224px,
67 | total-height: 184px,
68 | image: 'sign-icons@2.png'
69 | )
70 | );
71 |
72 |
73 | @mixin sprite-size($image) {
74 | background-size: map-get(map-get($sprite, $image), 'total-width') map-get(map-get($sprite, $image), 'total-height');
75 | }
76 |
77 | @mixin sprite-width($image) {
78 | width: map-get(map-get($sprite, $image), 'width');
79 | }
80 |
81 | @mixin sprite-height($image) {
82 | height: map-get(map-get($sprite, $image), 'height');
83 | }
84 |
85 | @mixin sprite-position($image) {
86 | background-position: map-get(map-get($sprite, $image), 'offset-x') map-get(map-get($sprite, $image), 'offset-y');
87 | }
88 |
89 | @mixin sprite-image($image) {
90 | background-image: url(map-get(map-get($sprite, $image), 'image') + '.png');
91 | }
92 |
93 | @mixin sprite-image-retina($image) {
94 | background-image: url(map-get(map-get($sprite, $image), 'image') + '@2.png');
95 | }
96 |
97 |
98 |
99 |
100 | .icon-email-blue {
101 | @include sprite-width("email-blue");
102 | @include sprite-height("email-blue");
103 | @include sprite-position("email-blue");
104 | }
105 | .icon-email-gray {
106 | @include sprite-width("email-gray");
107 | @include sprite-height("email-gray");
108 | @include sprite-position("email-gray");
109 | }
110 | .icon-lock-blue {
111 | @include sprite-width("lock-blue");
112 | @include sprite-height("lock-blue");
113 | @include sprite-position("lock-blue");
114 | }
115 | .icon-lock-gray {
116 | @include sprite-width("lock-gray");
117 | @include sprite-height("lock-gray");
118 | @include sprite-position("lock-gray");
119 | }
120 | .icon-logo {
121 | @include sprite-width("logo");
122 | @include sprite-height("logo");
123 | @include sprite-position("logo");
124 | }
125 | .icon-name-blue {
126 | @include sprite-width("name-blue");
127 | @include sprite-height("name-blue");
128 | @include sprite-position("name-blue");
129 | }
130 | .icon-name-gray {
131 | @include sprite-width("name-gray");
132 | @include sprite-height("name-gray");
133 | @include sprite-position("name-gray");
134 | }
135 |
136 |
137 | .icon_sign {
138 | @include sprite-size('parts');
139 | background-repeat: no-repeat;
140 | display: inline-block;
141 | @media
142 | only screen and (-webkit-min-device-pixel-ratio: 2),
143 | only screen and ( min--moz-device-pixel-ratio: 2),
144 | only screen and ( -o-min-device-pixel-ratio: 2/1),
145 | only screen and ( min-device-pixel-ratio: 2),
146 | only screen and ( min-resolution: 192dpi),
147 | only screen and ( min-resolution: 2dppx) {
148 |
149 | @include sprite-size('parts');
150 |
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/app/signin.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Sign In
6 |
7 |
8 |
9 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/app/sign/src/styles/_global.scss:
--------------------------------------------------------------------------------
1 | /* 定义一些全局的 class */
2 |
3 |
4 | /* 大小规则 .xx-tny, .xx-sml, .xx-med, .xx-lrg
5 | *
6 | * button: .btn-tny 26, .btn-sml 30, .btn-med 36, .btn-lrg
7 | * text: .text-tny 12, .text-sml 13, .text-med 16, .text-lrg 22
8 | * icon tny 14 sml 18 med 32 lrg 40
9 | * line: .line-sml 8
10 | */
11 |
12 | // font-size class
13 | .text-tny {
14 | font-size: $base-font-size-tny;
15 | }
16 |
17 | .text-sml {
18 | font-size: $base-font-size-sml;
19 | }
20 |
21 | .text-def {
22 | font-size: $base-font-size-def;
23 | }
24 |
25 | .text-med {
26 | font-size: $base-font-size-med;
27 | }
28 |
29 | .text-lrg {
30 | font-size: $base-font-size-lrg;
31 | }
32 |
33 |
34 | .left { float: left !important; }
35 | .right { float: right !important; }
36 | .clearfix { @include clearfix; }
37 |
38 | .hide {
39 | display: none !important;
40 | }
41 |
42 | .hidden {
43 | display: none;
44 | }
45 |
46 | .invisible {
47 | visibility: hidden;
48 | }
49 |
50 | // Font smoothing
51 | // Antialiased font smoothing works best for light text on a dark background.
52 | // Apply to single elements instead of globally to body.
53 | // Note this only applies to webkit-based desktop browsers and Firefox 25 (and later) on the Mac.
54 | .antialiased {
55 | -webkit-font-smoothing: antialiased;
56 | -moz-osx-font-smoothing: grayscale;
57 | }
58 |
59 | .divider {
60 | height: 1px;
61 | width: 100%;
62 | }
63 |
64 | .l-divider {
65 | height: 1px;
66 | margin: 10px 0;
67 | width: 100%;
68 | }
69 |
70 | // icon size tny 14 sml 18 med 24
71 | .i-tny {
72 | width: 14px;
73 | height: 14px;
74 | }
75 | .i-sml {
76 | width: 16px;
77 | height: 16px;
78 | }
79 | .i-med {
80 | width: 32px;
81 | height: 32px;
82 | }
83 |
84 | .i-lrg {
85 | width: 40px;
86 | height: 40px;
87 | }
88 |
89 | .i-lrg-x {
90 | width: 48px;
91 | height: 48px;
92 | }
93 |
94 | .i-xl {
95 | width: 100px;
96 | height: 100px;
97 | }
98 |
99 | .i-xxl {
100 | width: 180px;
101 | height: 180px;
102 | }
103 |
104 | .i-xxxl {
105 | width: 192px;
106 | height: 192px;
107 | }
108 |
109 | .i-redeem {
110 | width: 156px;
111 | height: 96px;
112 | }
113 |
114 | // adaptive line
115 | .line-right,
116 | .line-left {
117 | position: relative;
118 | }
119 | .line-right {
120 | z-index: 1;
121 | float: right;
122 | }
123 |
124 | .b-h {
125 | height: 100%;
126 | }
127 |
128 |
129 |
130 | .drag {
131 | visibility: hidden;
132 | position: absolute;
133 | cursor: move;
134 | }
135 |
136 | .shadow {
137 | border: $base-border;
138 | box-shadow: $base-box-shadow;
139 | border-radius: $base-border-radius;
140 | }
141 |
142 | .pop-shadow {
143 | border: $base-border;
144 | box-shadow: $base-pop-shadow;
145 | border-radius: $base-border-radius;
146 | }
147 |
148 | .dropdown-toggle {
149 | cursor: pointer;
150 | }
151 |
152 | img.round {
153 | border-radius: 50%;
154 | overflow: hidden;
155 | }
156 |
157 | .btns {
158 | line-height: 1;
159 | }
160 |
161 | .nowrap {
162 | white-space: nowrap;
163 | }
164 |
165 | body > svg {
166 | display: none;
167 | }
168 |
169 | /* text align */
170 | .text-center {
171 | text-align: center;
172 | }
173 |
174 | .text-left {
175 | text-align: left;
176 | }
177 |
178 | .text-right {
179 | text-align: right;
180 | }
181 | /* text align end */
182 |
183 | // sort
184 | .drag-help {
185 | width: rem-calc(360);
186 | max-width: rem-calc(360);
187 | opacity: 0.9;
188 | }
189 |
190 | // 行高 设置
191 | .line-sml {
192 | line-height: rem-calc(21);
193 | }
194 |
195 | .file-wrap {
196 | overflow: hidden;
197 | }
198 |
199 | // 最好用 select-disabled
200 | .select-disabled *,
201 | .can-not-select * {
202 | @include user-select(none);
203 | }
204 |
205 | .select-enabled,
206 | .select-enabled *,
207 | .can-select,
208 | .can-select * {
209 | @include user-select(text);
210 | }
211 |
212 | .select-disabled,
213 | .can-not-select {
214 | input,
215 | textarea,
216 | *[contenteditable] {
217 | @include user-select(text);
218 | }
219 | }
220 |
221 | .tl-body {
222 | .antiscroll-wrap {
223 | position: static; // 为了拖出去
224 | }
225 | }
226 |
227 | .loading-view {
228 | width: 100%;
229 | height: 100%;
230 | background-color: $white;
231 | position: absolute;
232 | top: 0;
233 | z-index: $zindex-loadview;
234 | text-align: center;
235 |
236 | .logo {
237 | position: relative;
238 | height: 100%;
239 | top: 50%;
240 | margin-top: rem-calc(-100);
241 | }
242 | }
243 |
244 | .avoid-event {
245 | svg {
246 | pointer-events: none;
247 | }
248 | }
249 |
--------------------------------------------------------------------------------
/app/sign/src/styles/_sign.scss:
--------------------------------------------------------------------------------
1 | /*sign style*/
2 |
3 | body {
4 | line-height: 1;
5 | font-family: $font-family;
6 | background: $whitegray;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | .sign {
12 | max-width: 400px;
13 | min-width: 300px;
14 | margin: 48px auto;
15 | color: $base-font-color;
16 | }
17 |
18 | .card {
19 | position: relative;
20 | margin: 0 auto;
21 | }
22 |
23 | .logo {
24 | text-align: center;
25 | margin-bottom: $s-base-divider;
26 | }
27 |
28 | .card-section {
29 | background-color: $white;
30 | border: $base-border;
31 | border-radius: 2px;
32 | padding: 40px 50px;
33 | }
34 |
35 | .form {
36 | position: relative;
37 | }
38 |
39 | .sign {
40 | .row {
41 | position: relative;
42 | border-bottom: 1px solid $base-border-color;
43 | border-radius: 1px;
44 | transition: border-color ease-in-out .15s;
45 | margin-bottom: 28px;
46 |
47 | &.active {
48 | // border-bottom: 1px solid $base-focus-border-color;
49 | transition: border-color ease-in-out .15s;
50 | }
51 |
52 | &.name input,
53 | &.email input,
54 | &.password input {
55 | border: 0 none;
56 | font-size: 16px;
57 | padding: 10px 10px 8px 8px;
58 | width: calc(100% - 70px);
59 | }
60 |
61 | &.submit,
62 | &.forgot-password {
63 | border-bottom: none;
64 | }
65 |
66 | &.submit {
67 | margin: 0 auto;
68 | margin-bottom: 12px;
69 | }
70 |
71 | &.forgot-password {
72 | margin: 0;
73 | text-align: left;
74 | font-size: 13px;
75 | }
76 |
77 | }
78 |
79 | }
80 |
81 | .input-bar {
82 | position: relative;
83 | display: block;
84 | width: 100%;
85 | height: 1px;
86 |
87 | &:before,
88 | &:after {
89 | content: '';
90 | height: 1px;
91 | width: 0;
92 | bottom: -1px;
93 | position: absolute;
94 | background-color: $base-focus-border-color;
95 | border-radius: 1px;
96 | transition: all .28s cubic-bezier(.4,0,.2,1);
97 | }
98 |
99 | &:before {
100 | left: 50%;
101 | border-top-right-radius: 0;
102 | border-bottom-right-radius: 0;
103 | }
104 |
105 | &:after {
106 | right: 50%;
107 | border-top-left-radius: 0;
108 | border-bottom-left-radius: 0;
109 | }
110 | }
111 |
112 |
113 |
114 | input:focus ~ .input-bar:before {
115 | left: 0%;
116 | width: 51%;
117 | }
118 |
119 | input:focus ~ .input-bar:after {
120 | right: 0%;
121 | width: 50%;
122 | }
123 |
124 | /*插件*/
125 | .switch-site {
126 | display: none;
127 | }
128 | .chrome-extension .forgot-password .link {
129 | float: right;
130 | }
131 |
132 | .chrome-extension .forgot-password .switch-site {
133 | display: inline;
134 | float: left;
135 | }
136 |
137 | .sign .row .icon {
138 | position: relative;
139 | top: 6px;
140 | }
141 |
142 | .middle-line {
143 | overflow: hidden;
144 | text-align: center;
145 | }
146 |
147 | .middle-line:before,
148 | .middle-line:after {
149 | background-color: $base-border-color;
150 | content: "";
151 | display: inline-block;
152 | height: 1px;
153 | position: relative;
154 | vertical-align: middle;
155 | width: 50%;
156 | }
157 | .middle-line:before {
158 | right: 0.5em;
159 | margin-left: -50%;
160 | }
161 | .middle-line:after {
162 | left: 0.5em;
163 | margin-right: -50%;
164 | }
165 |
166 | .sns-title {
167 | color: $lavendergray;
168 | font-size: 13px;
169 | padding: 30px 0 36px;
170 | }
171 |
172 | .signin-sns ul {
173 | text-align: center;
174 |
175 | li {
176 | display: inline-block;
177 |
178 | &.second {
179 | margin: 0 42px;
180 | }
181 |
182 | &:hover {
183 | opacity: .9;
184 | }
185 | }
186 | }
187 |
188 |
189 | .link.signup,
190 | .link.signin,
191 | .link.sign-link {
192 | text-align: center;
193 | padding-top: 35px;
194 | font-size: 14px;
195 | }
196 |
197 | .link {
198 | &.message {
199 | line-height: 25px;
200 | padding: 40px 0 0;
201 | }
202 |
203 | &.success {
204 | padding: 40px 0;
205 | }
206 | }
207 |
208 | .button {
209 | font-size: 16px;
210 | width: 100%;
211 | }
212 |
213 | .error {
214 | position: absolute;
215 | right: 0;
216 | z-index: 2;
217 |
218 | .warn {
219 | display: none;
220 | color: $base-font-color-alert;
221 | font-size: 13px;
222 | margin-top: 6px;
223 | line-height: 1.1;
224 | }
225 |
226 | &.long {
227 | position: relative;
228 | }
229 | }
230 |
231 | @media #{$small-only} {
232 | .sign {
233 | width: 95%;
234 |
235 | .signin-sns ul li:nth-child(2) {
236 | margin: 0 10px;
237 | }
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/app/sign/src/scripts/sign.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | let ipc = require('electron').ipcRenderer
4 | let Appest = require(__dirname + '/appest')
5 |
6 | let homeUrl = Appest.protocol + Appest.domain
7 | let emailRegexp = /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,9}$/i
8 |
9 | let View = {
10 | password: '',
11 | email: '',
12 | isPasswordOK: false,
13 | isEmailValid: false,
14 |
15 | initDom () {
16 | this.$empty = $('#login_length_warn_empty')
17 | this.$warn = $('#login_length_warn')
18 | this.$ewarn = $('#email_invalid_warn')
19 | this.$blank = $('#not_blank')
20 | this.$ps = $('#password')
21 | this.$eps = $('#error_username_password')
22 | this.$spt = $('.submit input')
23 | this.$submit = $('.submit')
24 | this.$name = $('#username')
25 | },
26 |
27 | init () {
28 | let _this = this
29 | this.initDom()
30 |
31 | this.$name.change(() => {
32 | _this.checkEmailFormat()
33 | }).keyup(() => {
34 | _this.checkingEmailFormat()
35 | })
36 |
37 | this.$ps.keyup(() => {
38 | _this.checkingPassword1()
39 | })
40 |
41 | $('#submit-btn').click(() => {
42 | event.preventDefault()
43 | _this.submit()
44 | })
45 |
46 | $('input').keydown(() => {
47 | if (event.keyCode === 13) {
48 | _this.submit()
49 | }
50 | })
51 |
52 | $('.required').focus(() => {
53 | let
54 | parent = $(event.target).parent(),
55 | element = parent.find('i').first(),
56 | iconClass = 'icon-' + element.attr('icon') + '-gray',
57 | activeIcon = 'icon-' + element.attr('icon') + '-blue'
58 |
59 | parent.addClass('active')
60 | element.removeClass(iconClass)
61 | element.addClass(activeIcon)
62 | }).blur(() => {
63 | let
64 | parent = $(event.target).parent(),
65 | element = parent.find('i').first(),
66 | iconClass = 'icon-' + element.attr('icon') + '-gray',
67 | activeIcon = 'icon-' + element.attr('icon') + '-blue'
68 |
69 | parent.removeClass('active')
70 | element.addClass(iconClass)
71 | element.removeClass(activeIcon)
72 | })
73 | },
74 |
75 | submit () {
76 | this.checkEmailFormat()
77 | this.checkPassword1()
78 | this.postLogin()
79 | },
80 |
81 | checkEmailFormat () {
82 | this.isEmailValid = false
83 | this.email = this.$name.val()
84 | $('#error_no_user_info').fadeOut(200)
85 | let isMatch = this.email.match(emailRegexp)
86 | if (isMatch) {
87 | this.$ewarn.fadeOut(200)
88 | this.$blank.fadeOut(200)
89 | this.isEmailValid = true
90 | } else {
91 | if (this.email.length > 0) {
92 | this.$blank.fadeOut(200)
93 | this.$ewarn.fadeIn(200)
94 | } else {
95 | this.$blank.fadeIn(200)
96 | }
97 | }
98 | },
99 |
100 | checkingEmailFormat () {
101 | this.email = this.$name.val()
102 | let isMatch = this.email.match(emailRegexp)
103 | this.$ewarn.fadeOut(200)
104 | if (this.email.length > 0) {
105 | this.$blank.fadeOut(200)
106 | }
107 | return isMatch
108 | },
109 |
110 | checkPassword1 () {
111 | this.password = this.$ps.val()
112 | this.isPasswordOK = false
113 |
114 | let isMatch = this.password.length >= 6
115 |
116 | if (isMatch) {
117 | this.$empty.fadeOut(200)
118 | this.$warn.fadeOut(200)
119 | this.isPasswordOK = true
120 | } else {
121 | if (this.password.length > 0) {
122 | this.$empty.fadeOut(200)
123 | this.$warn.fadeIn(200)
124 | } else {
125 | this.$empty.fadeIn(200)
126 | }
127 | }
128 | },
129 |
130 | checkingPassword1 () {
131 | this.$eps.fadeOut(200)
132 | this.password = this.$ps.val()
133 | if ((this.password.length >= 6)) {
134 | this.$warn.fadeOut(200)
135 | } else if (this.password.length > 0) {
136 | this.$empty.fadeOut(200)
137 | }
138 | },
139 |
140 | postLogin () {
141 | if (!this.isPasswordOK || !this.isEmailValid)
142 | return
143 |
144 | this.$spt.attr('disabled')
145 | this.$submit.addClass('waiting ing')
146 |
147 | let url = homeUrl + '/api/v2/user/signon?wc=true&remember=true'
148 |
149 | let _this = this
150 | $.ajax({
151 | type: 'POST',
152 | url: url,
153 | contentType: 'application/json',
154 | data: JSON.stringify({
155 | username: this.email,
156 | password: this.password
157 | }),
158 | success (data) {
159 | ipc.send('signin', data)
160 | },
161 | error (err) {
162 | _this.loginError(err)
163 | }
164 | })
165 | },
166 |
167 | loginError (err) {
168 | this.$spt.removeAttr('disabled')
169 | this.$submit.removeClass('waiting ing')
170 | let obj = $.parseJSON(err.responseText)
171 | if (obj && obj.errorCode === 'username_password_not_match') {
172 | this.$eps.fadeIn(200)
173 | } else {
174 | $('#login_server_error').fadeIn(200)
175 | }
176 | }
177 | }
178 |
179 | View.init()
180 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/nconf-test.js:
--------------------------------------------------------------------------------
1 | /*
2 | * file-store-test.js: Tests for the nconf File store.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var fs = require('fs'),
9 | path = require('path'),
10 | vows = require('vows'),
11 | assert = require('assert'),
12 | nconf = require('../lib/nconf'),
13 | data = require('./fixtures/data').data;
14 |
15 | vows.describe('nconf').addBatch({
16 | "When using the nconf": {
17 | "should have the correct methods set": function () {
18 | assert.isFunction(nconf.key);
19 | assert.isFunction(nconf.path);
20 | assert.isFunction(nconf.use);
21 | assert.isFunction(nconf.get);
22 | assert.isFunction(nconf.set);
23 | assert.isFunction(nconf.clear);
24 | assert.isFunction(nconf.load);
25 | assert.isFunction(nconf.save);
26 | assert.isFunction(nconf.reset);
27 | assert.isFunction(nconf.required);
28 | },
29 | "the use() method": {
30 | "should instaniate the correct store": function () {
31 | nconf.use('memory');
32 | nconf.load();
33 | assert.instanceOf(nconf.stores['memory'], nconf.Memory);
34 | }
35 | },
36 | "it should": {
37 | topic: function () {
38 | fs.readFile(path.join(__dirname, '..', 'package.json'), this.callback);
39 | },
40 | "have the correct version set": function (err, data) {
41 | assert.isNull(err);
42 | data = JSON.parse(data.toString());
43 | assert.equal(nconf.version, data.version);
44 | }
45 | },
46 | "the required() method": {
47 | "should throw error with missing keys": function() {
48 | nconf.set('foo:bar:bazz', 'buzz');
49 | assert.throws(nconf.required.bind(nconf, ['missing', 'foo:bar:bazz']), Error);
50 | },
51 | "should return true if all required keys exist": function() {
52 | nconf.set('foo:bar:bazz', 'buzz');
53 | assert.isTrue(nconf.required(['foo:bar:bazz']));
54 | }
55 | }
56 | }
57 | }).addBatch({
58 | "When using the nconf": {
59 | "with the memory store": {
60 | "the set() method": {
61 | "should respond with true": function () {
62 | assert.isTrue(nconf.set('foo:bar:bazz', 'buzz'));
63 | }
64 | },
65 | "the get() method": {
66 | "without a callback": {
67 | "should respond with the correct value": function () {
68 | assert.equal(nconf.get('foo:bar:bazz'), 'buzz');
69 | }
70 | },
71 | "with a callback": {
72 | topic: function () {
73 | nconf.get('foo:bar:bazz', this.callback);
74 | },
75 | "should respond with the correct value": function (err, value) {
76 | assert.equal(value, 'buzz');
77 | }
78 | }
79 | }
80 | }
81 | }
82 | }).addBatch({
83 | "When using the nconf": {
84 | "with the memory store": {
85 | "the get() method": {
86 | "should respond allow access to the root": function () {
87 | assert(nconf.get(null));
88 | assert(nconf.get(undefined));
89 | assert(nconf.get());
90 | }
91 | },
92 | "the set() method": {
93 | "should respond allow access to the root and complain about non-objects": function () {
94 | assert(!nconf.set(null, null));
95 | assert(!nconf.set(null, undefined));
96 | assert(!nconf.set(null));
97 | assert(!nconf.set(null, ''));
98 | assert(!nconf.set(null, 1));
99 | var original = nconf.get();
100 | assert(nconf.set(null, nconf.get()));
101 | assert.notEqual(nconf.get(), original);
102 | assert.deepEqual(nconf.get(), original)
103 | }
104 | }
105 | }
106 | }
107 | }).addBatch({
108 | "When using nconf": {
109 | "with the memory store": {
110 | "the clear() method": {
111 | "should respond with the true": function () {
112 | assert.equal(nconf.get('foo:bar:bazz'), 'buzz');
113 | assert.isTrue(nconf.clear('foo:bar:bazz'));
114 | assert.isTrue(typeof nconf.get('foo:bar:bazz') === 'undefined');
115 | }
116 | },
117 | "the load() method": {
118 | "without a callback": {
119 | "should respond with the merged store": function () {
120 | assert.deepEqual(nconf.load(), {
121 | title: 'My specific title',
122 | color: 'green',
123 | movie: 'Kill Bill'
124 | });
125 | }
126 | },
127 | "with a callback": {
128 | topic: function () {
129 | nconf.load(this.callback.bind(null, null));
130 | },
131 | "should respond with the merged store": function (ign, err, store) {
132 | assert.isNull(err);
133 | assert.deepEqual(store, {
134 | title: 'My specific title',
135 | color: 'green',
136 | movie: 'Kill Bill'
137 | });
138 | }
139 | }
140 | }
141 | }
142 | }
143 | }).export(module);
144 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/stores/memory-store-test.js:
--------------------------------------------------------------------------------
1 | /*
2 | * memory-store-test.js: Tests for the nconf Memory store.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var vows = require('vows'),
9 | assert = require('assert'),
10 | nconf = require('../../lib/nconf'),
11 | merge = require('../fixtures/data').merge;
12 |
13 | vows.describe('nconf/stores/memory').addBatch({
14 | "When using the nconf memory store": {
15 | topic: new nconf.Memory(),
16 | "the set() method": {
17 | "should respond with true": function (store) {
18 | assert.isTrue(store.set('foo:bar:bazz', 'buzz'));
19 | assert.isTrue(store.set('falsy:number', 0));
20 | assert.isTrue(store.set('falsy:string:empty', ''));
21 | assert.isTrue(store.set('falsy:string:value', 'value'));
22 | assert.isTrue(store.set('falsy:boolean', false));
23 | assert.isTrue(store.set('falsy:object', null));
24 | }
25 | },
26 | "the get() method": {
27 | "should respond with the correct value": function (store) {
28 | assert.equal(store.get('foo:bar:bazz'), 'buzz');
29 | assert.equal(store.get('falsy:number'), 0);
30 | assert.equal(store.get('falsy:string:empty'), '');
31 | assert.equal(store.get('falsy:string:value'), 'value');
32 | assert.equal(store.get('falsy:boolean'), false);
33 | assert.equal(store.get('falsy:object'), null);
34 | },
35 | "should not fail when retrieving non-existent keys": {
36 | "at the root level": function (store) {
37 | assert.doesNotThrow(function() {
38 | assert.equal(store.get('this:key:does:not:exist'), undefined);
39 | }, TypeError);
40 | },
41 | "within numbers": function (store) {
42 | assert.doesNotThrow(function() {
43 | assert.equal(store.get('falsy:number:not:exist'), undefined);
44 | }, TypeError);
45 | },
46 | "within booleans": function (store) {
47 | assert.doesNotThrow(function() {
48 | assert.equal(store.get('falsy:boolean:not:exist'), undefined);
49 | }, TypeError);
50 | },
51 | "within objects": function (store) {
52 | assert.doesNotThrow(function() {
53 | assert.equal(store.get('falsy:object:not:exist'), undefined);
54 | }, TypeError);
55 | },
56 | "within empty strings": function (store) {
57 | assert.doesNotThrow(function() {
58 | assert.equal(store.get('falsy:string:empty:not:exist'), undefined);
59 | }, TypeError);
60 | },
61 | "within non-empty strings": function (store) {
62 | assert.doesNotThrow(function() {
63 | assert.equal(store.get('falsy:string:value:not:exist'), undefined);
64 | }, TypeError);
65 | }
66 | }
67 | },
68 | "the clear() method": {
69 | "should respond with the true": function (store) {
70 | assert.equal(store.get('foo:bar:bazz'), 'buzz');
71 | assert.isTrue(store.clear('foo:bar:bazz'));
72 | assert.isTrue(typeof store.get('foo:bar:bazz') === 'undefined');
73 | }
74 | },
75 | "the merge() method": {
76 | "when overriding an existing literal value": function (store) {
77 | store.set('merge:literal', 'string-value');
78 | store.merge('merge:literal', merge);
79 | assert.deepEqual(store.get('merge:literal'), merge);
80 | },
81 | "when overriding an existing Array value": function (store) {
82 | store.set('merge:array', [1,2,3,4]);
83 | store.merge('merge:array', merge);
84 | assert.deepEqual(store.get('merge:literal'), merge);
85 | },
86 | "when merging into an existing Object value": function (store) {
87 | store.set('merge:object', {
88 | prop1: 2,
89 | prop2: 'prop2',
90 | prop3: {
91 | bazz: 'bazz'
92 | },
93 | prop4: ['foo', 'bar']
94 | });
95 | store.merge('merge:object', merge);
96 |
97 | assert.equal(store.get('merge:object:prop1'), 1);
98 | assert.equal(store.get('merge:object:prop2').length, 3);
99 | assert.deepEqual(store.get('merge:object:prop3'), {
100 | foo: 'bar',
101 | bar: 'foo',
102 | bazz: 'bazz'
103 | });
104 | assert.equal(store.get('merge:object:prop4').length, 2);
105 | }
106 | }
107 | },
108 | "When using the nconf memory store with different logical separator": {
109 | topic: new nconf.Memory({logicalSeparator: '||' }),
110 | "when storing with : (colon)": {
111 | "should store the config atomicly": function (store) {
112 | store.set('foo:bar:bazz', 'buzz');
113 | assert.isTrue(typeof store.get('foo:bar') === 'undefined');
114 | assert.equal(store.get('foo:bar:bazz'), 'buzz');
115 | }
116 | },
117 | "when storing with separator": {
118 | "should be able to read the object": function (store) {
119 | store.set('foo||bar||bazz', 'buzz');
120 | assert.equal(store.get('foo||bar').bazz, 'buzz');
121 | assert.equal(store.get('foo').bar.bazz, 'buzz');
122 | }
123 | }
124 | }
125 | }).export(module);
126 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/complete-test.js:
--------------------------------------------------------------------------------
1 | /*
2 | * complete-test.js: Complete test for multiple stores.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var fs = require('fs'),
9 | path = require('path'),
10 | vows = require('vows'),
11 | assert = require('assert'),
12 | nconf = require('../lib/nconf'),
13 | data = require('./fixtures/data').data,
14 | helpers = require('./helpers');
15 |
16 | var completeTest = helpers.fixture('complete-test.json'),
17 | complete = helpers.fixture('complete.json');
18 |
19 | // prime the process.env
20 | process.env['NCONF_foo'] = 'bar';
21 | process.env.FOO = 'bar';
22 | process.env.BAR = 'zalgo';
23 | process.env.NODE_ENV = 'debug';
24 | process.env.FOOBAR = 'should not load';
25 |
26 | vows.describe('nconf/multiple-stores').addBatch({
27 | "When using the nconf with multiple providers": {
28 | topic: function () {
29 | var that = this;
30 | helpers.cp(complete, completeTest, function () {
31 | nconf.env({
32 | // separator: '__',
33 | match: /^NCONF_/,
34 | whitelist: ['NODE_ENV', 'FOO', 'BAR']
35 | });
36 | nconf.file({ file: completeTest });
37 | nconf.use('argv', { type: 'literal', store: data });
38 | that.callback();
39 | });
40 | },
41 | "should have the correct `stores`": function () {
42 | assert.isObject(nconf.stores.env);
43 | assert.isObject(nconf.stores.argv);
44 | assert.isObject(nconf.stores.file);
45 | },
46 | "env vars": {
47 | "are present": function () {
48 | ['NODE_ENV', 'FOO', 'BAR', 'NCONF_foo'].forEach(function (key) {
49 | assert.equal(nconf.get(key), process.env[key]);
50 | });
51 | }
52 | },
53 | "json vars": {
54 | topic: function () {
55 | fs.readFile(complete, 'utf8', this.callback);
56 | },
57 | "are present": function (err, data) {
58 | assert.isNull(err);
59 | data = JSON.parse(data);
60 | Object.keys(data).forEach(function (key) {
61 | assert.deepEqual(nconf.get(key), data[key]);
62 | });
63 | }
64 | },
65 | "literal vars": {
66 | "are present": function () {
67 | Object.keys(data).forEach(function (key) {
68 | assert.deepEqual(nconf.get(key), data[key]);
69 | });
70 | }
71 | },
72 | "and saving *synchronously*": {
73 | topic: function () {
74 | nconf.set('weebls', 'stuff');
75 | return nconf.save();
76 | },
77 | "correct return value": function (topic) {
78 | Object.keys(topic).forEach(function (key) {
79 | assert.deepEqual(topic[key], nconf.get(key));
80 | });
81 | },
82 | "the file": {
83 | topic: function () {
84 | fs.readFile(completeTest, 'utf8', this.callback);
85 | },
86 | "saved correctly": function (err, data) {
87 | data = JSON.parse(data);
88 | Object.keys(data).forEach(function (key) {
89 | assert.deepEqual(data[key], nconf.get(key));
90 | });
91 | assert.equal(nconf.get('weebls'), 'stuff');
92 | }
93 | }
94 | },
95 | teardown: function () {
96 | // remove the file so that we can test saving it async
97 | fs.unlinkSync(completeTest);
98 | }
99 | }
100 | }).addBatch({
101 | // Threw this in it's own batch to make sure it's run separately from the
102 | // sync check
103 | "When using the nconf with multiple providers": {
104 | "and saving *asynchronously*": {
105 | topic: function () {
106 | nconf.set('weebls', 'crap');
107 | nconf.save(this.callback);
108 | },
109 | "correct return value": function (err, data) {
110 | assert.isNull(err);
111 | Object.keys(data).forEach(function (key) {
112 | assert.deepEqual(data[key], nconf.get(key));
113 | });
114 | },
115 | "the file": {
116 | topic: function () {
117 | fs.readFile(completeTest, 'utf8', this.callback);
118 | },
119 | "saved correctly": function (err, data) {
120 | assert.isNull(err);
121 | data = JSON.parse(data);
122 | Object.keys(data).forEach(function (key) {
123 | assert.deepEqual(nconf.get(key), data[key]);
124 | });
125 | assert.equal(nconf.get('weebls'), 'crap');
126 | }
127 | }
128 | },
129 | teardown: function () {
130 | fs.unlinkSync(completeTest);
131 | nconf.remove('file');
132 | nconf.remove('memory');
133 | nconf.remove('argv');
134 | nconf.remove('env');
135 | }
136 | }
137 | }).addBatch({
138 | // Threw this in it's own batch to make sure it's run separately from the
139 | // sync check
140 | "When using env with lowerCase:true": {
141 | topic: function () {
142 | var that = this;
143 | helpers.cp(complete, completeTest, function () {
144 | nconf.env({ lowerCase: true });
145 | that.callback();
146 | });
147 | },
148 | "env vars": {
149 | "keys also available as lower case": function () {
150 | Object.keys(process.env).forEach(function (key) {
151 | assert.equal(nconf.get(key.toLowerCase()), process.env[key]);
152 | });
153 | }
154 | },
155 | teardown: function () {
156 | nconf.remove('env');
157 | }
158 | }
159 | }).export(module);
--------------------------------------------------------------------------------
/app/node_modules/nconf/lib/nconf/stores/memory.js:
--------------------------------------------------------------------------------
1 | /*
2 | * memory.js: Simple memory storage engine for nconf configuration(s)
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var common = require('../common');
9 |
10 | //
11 | // ### function Memory (options)
12 | // #### @options {Object} Options for this instance
13 | // Constructor function for the Memory nconf store which maintains
14 | // a nested json structure based on key delimiters `:`.
15 | //
16 | // e.g. `my:nested:key` ==> `{ my: { nested: { key: } } }`
17 | //
18 | var Memory = exports.Memory = function (options) {
19 | options = options || {};
20 | this.type = 'memory';
21 | this.store = {};
22 | this.mtimes = {};
23 | this.readOnly = false;
24 | this.loadFrom = options.loadFrom || null;
25 | this.logicalSeparator = options.logicalSeparator || ':';
26 |
27 | if (this.loadFrom) {
28 | this.store = common.loadFilesSync(this.loadFrom);
29 | }
30 | };
31 |
32 | //
33 | // ### function get (key)
34 | // #### @key {string} Key to retrieve for this instance.
35 | // Retrieves the value for the specified key (if any).
36 | //
37 | Memory.prototype.get = function (key) {
38 | var target = this.store,
39 | path = common.path(key, this.logicalSeparator);
40 |
41 | //
42 | // Scope into the object to get the appropriate nested context
43 | //
44 | while (path.length > 0) {
45 | key = path.shift();
46 | if (target && target.hasOwnProperty(key)) {
47 | target = target[key];
48 | continue;
49 | }
50 | return undefined;
51 | }
52 |
53 | return target;
54 | };
55 |
56 | //
57 | // ### function set (key, value)
58 | // #### @key {string} Key to set in this instance
59 | // #### @value {literal|Object} Value for the specified key
60 | // Sets the `value` for the specified `key` in this instance.
61 | //
62 | Memory.prototype.set = function (key, value) {
63 | if (this.readOnly) {
64 | return false;
65 | }
66 |
67 | var target = this.store,
68 | path = common.path(key, this.logicalSeparator);
69 |
70 | if (path.length === 0) {
71 | //
72 | // Root must be an object
73 | //
74 | if (!value || typeof value !== 'object') {
75 | return false;
76 | }
77 | else {
78 | this.reset();
79 | this.store = value;
80 | return true;
81 | }
82 | }
83 |
84 | //
85 | // Update the `mtime` (modified time) of the key
86 | //
87 | this.mtimes[key] = Date.now();
88 |
89 | //
90 | // Scope into the object to get the appropriate nested context
91 | //
92 | while (path.length > 1) {
93 | key = path.shift();
94 | if (!target[key] || typeof target[key] !== 'object') {
95 | target[key] = {};
96 | }
97 |
98 | target = target[key];
99 | }
100 |
101 | // Set the specified value in the nested JSON structure
102 | key = path.shift();
103 | target[key] = value;
104 | return true;
105 | };
106 |
107 | //
108 | // ### function clear (key)
109 | // #### @key {string} Key to remove from this instance
110 | // Removes the value for the specified `key` from this instance.
111 | //
112 | Memory.prototype.clear = function (key) {
113 | if (this.readOnly) {
114 | return false;
115 | }
116 |
117 | var target = this.store,
118 | value = target,
119 | path = common.path(key, this.logicalSeparator);
120 |
121 | //
122 | // Remove the key from the set of `mtimes` (modified times)
123 | //
124 | delete this.mtimes[key];
125 |
126 | //
127 | // Scope into the object to get the appropriate nested context
128 | //
129 | for (var i = 0; i < path.length - 1; i++) {
130 | key = path[i];
131 | value = target[key];
132 | if (typeof value !== 'function' && typeof value !== 'object') {
133 | return false;
134 | }
135 | target = value;
136 | }
137 |
138 | // Delete the key from the nested JSON structure
139 | key = path[i];
140 | delete target[key];
141 | return true;
142 | };
143 |
144 | //
145 | // ### function merge (key, value)
146 | // #### @key {string} Key to merge the value into
147 | // #### @value {literal|Object} Value to merge into the key
148 | // Merges the properties in `value` into the existing object value
149 | // at `key`. If the existing value `key` is not an Object, it will be
150 | // completely overwritten.
151 | //
152 | Memory.prototype.merge = function (key, value) {
153 | if (this.readOnly) {
154 | return false;
155 | }
156 |
157 | //
158 | // If the key is not an `Object` or is an `Array`,
159 | // then simply set it. Merging is for Objects.
160 | //
161 | if (typeof value !== 'object' || Array.isArray(value) || value === null) {
162 | return this.set(key, value);
163 | }
164 |
165 | var self = this,
166 | target = this.store,
167 | path = common.path(key, this.logicalSeparator),
168 | fullKey = key;
169 |
170 | //
171 | // Update the `mtime` (modified time) of the key
172 | //
173 | this.mtimes[key] = Date.now();
174 |
175 | //
176 | // Scope into the object to get the appropriate nested context
177 | //
178 | while (path.length > 1) {
179 | key = path.shift();
180 | if (!target[key]) {
181 | target[key] = {};
182 | }
183 |
184 | target = target[key];
185 | }
186 |
187 | // Set the specified value in the nested JSON structure
188 | key = path.shift();
189 |
190 | //
191 | // If the current value at the key target is not an `Object`,
192 | // or is an `Array` then simply override it because the new value
193 | // is an Object.
194 | //
195 | if (typeof target[key] !== 'object' || Array.isArray(target[key])) {
196 | target[key] = value;
197 | return true;
198 | }
199 |
200 | return Object.keys(value).every(function (nested) {
201 | return self.merge(common.keyed(self.logicalSeparator, fullKey, nested), value[nested]);
202 | });
203 | };
204 |
205 | //
206 | // ### function reset (callback)
207 | // Clears all keys associated with this instance.
208 | //
209 | Memory.prototype.reset = function () {
210 | if (this.readOnly) {
211 | return false;
212 | }
213 |
214 | this.mtimes = {};
215 | this.store = {};
216 | return true;
217 | };
218 |
219 | //
220 | // ### function loadSync
221 | // Returns the store managed by this instance
222 | //
223 | Memory.prototype.loadSync = function () {
224 | return this.store || {};
225 | };
226 |
--------------------------------------------------------------------------------
/app/node_modules/objectid/test.js:
--------------------------------------------------------------------------------
1 | var chai = require('chai')
2 | chai.should()
3 | var expect = chai.expect
4 | chai.use(require('chai-interface'))
5 |
6 | var ObjectId = require('./index')
7 | var NativeObjectId = require('mongodb').ObjectID
8 | var bson = require('bson').BSONPure
9 |
10 | var testOid = '511083bb08ce6b1b00000003'
11 |
12 | describe('objectid', function () {
13 | it ('has interface', function () {
14 | // constructor
15 | ObjectId.should.be.a('function')
16 |
17 | // static
18 | ObjectId.should.have.interface({
19 | equals: Function,
20 | tryParse: Function,
21 | isValid: Function
22 | })
23 |
24 | // instance
25 | ObjectId().should.be.an('object')
26 |
27 | })
28 |
29 | it('has a bsontype to work with the `bson` module', function () {
30 | var id = ObjectId()
31 | id._bsontype.should.equal('ObjectID');
32 | })
33 |
34 | it('serializes the same as a bson ObjectID', function () {
35 | var id1 = ObjectId(testOid)
36 | var id2 = bson.ObjectID(testOid)
37 |
38 | var b1 = bson.BSON.serialize(id1)
39 | var b2 = bson.BSON.serialize(id2)
40 |
41 | bson.BSON.deserialize(b1).id.should.equal(bson.BSON.deserialize(b2).id)
42 |
43 | })
44 |
45 | describe('#toJSON', function () {
46 | it('JSON serializes to its id string', function () {
47 | var id = ObjectId(testOid)
48 | JSON.stringify(id).should.equal('"' + testOid + '"')
49 | })
50 | })
51 |
52 | it('casts native driver ObjectIds', function () {
53 | var nativeOid = new NativeObjectId()
54 | var oid = ObjectId(nativeOid)
55 | oid.should.be.instanceof(ObjectId.constructor)
56 | oid.toString().should.equal(nativeOid.toString())
57 | })
58 |
59 | it('generates a new objectId', function () {
60 | var oid = ObjectId()
61 | oid.should.not.equal(undefined)
62 | })
63 |
64 |
65 | it('casts itself to itself', function () {
66 | var oid = ObjectId()
67 | var oid2 = ObjectId(oid)
68 | oid2.should.be.instanceof(ObjectId.constructor)
69 | oid.toString().should.equal(oid2.toString())
70 | })
71 |
72 | it('returns the same object if casting an ObjectId', function () {
73 | var oid = ObjectId()
74 | var oid2 = ObjectId(oid)
75 | expect(oid === oid2).to.equal(true)
76 | })
77 |
78 | it('casts strings to ObjectIds', function () {
79 | var oid = '511083bb08ce6b1b00000003'
80 | var oid2 = ObjectId(oid)
81 | oid.should.equal(oid2.toString())
82 | })
83 |
84 | it('throws if called as a cast of an invalid objectid', function () {
85 | expect(function () {
86 | var oid = ObjectId('fsodfisohj')
87 | }).to.throw(/invalid/i)
88 | })
89 |
90 | it('throws when casting falsy values', function () {
91 | expect(function () {
92 | var id
93 | ObjectId(id)
94 | }).to.throw(/invalid/i)
95 | expect(function () {
96 | var id = false
97 | ObjectId(id)
98 | }).to.throw(/invalid/i)
99 | expect(function () {
100 | var id = null
101 | ObjectId(id)
102 | }).to.throw(/invalid/i)
103 | expect(function () {
104 | var id = ''
105 | ObjectId(id)
106 | }).to.throw(/invalid/i)
107 | expect(function () {
108 | var id = 0
109 | ObjectId(id)
110 | }).to.throw(/invalid/i)
111 | })
112 |
113 | describe('.isValid', function () {
114 | it('validates ObjectIds as 24 character hex strings', function () {
115 | ObjectId.isValid('foo').should.equal(false)
116 | ObjectId.isValid('511083bb08ce6b1b00000003').should.equal(true)
117 | ObjectId.isValid('sdf').should.equal(false)
118 | ObjectId.isValid(123).should.equal(false)
119 | ObjectId.isValid(null).should.equal(false)
120 | ObjectId.isValid({}).should.equal(false)
121 | ObjectId.isValid(['foo']).should.equal(false)
122 | })
123 |
124 | it('validates itself', function () {
125 | ObjectId.isValid(ObjectId()).should.equal(true)
126 | })
127 |
128 | it('validates mongo native driver ObjectIds', function () {
129 | ObjectId.isValid(new NativeObjectId).should.equal(true)
130 | })
131 |
132 | it('false for 1-element array of ObjectId', function () {
133 | ObjectId.isValid([ObjectId()]).should.equal(false)
134 | })
135 |
136 | })
137 |
138 | describe('.equals', function () {
139 | it('returns true if oidA and oidB are the same instance', function () {
140 | var oidA = ObjectId()
141 | var oidB = oidA
142 | ObjectId.equals(oidA, oidB).should.equal(true)
143 | })
144 | it('returns true if oidA and oidB are stringwise equal', function () {
145 | var oidA = ObjectId('511083bb08ce6b1b00000003')
146 | var oidB = '511083bb08ce6b1b00000003'
147 | ObjectId.equals(oidA, oidB).should.equal(true)
148 | })
149 | it('returns false if A or B are not ObjectIds', function () {
150 | ObjectId.equals('sdfsdfsdfsdf', testOid).should.equal(false)
151 | ObjectId.equals('511083bb08ce6b1b00000003', ['511083bb08ce6b1b00000003']).should.equal(false)
152 | })
153 | it('is also on ObjectId.prototype', function () {
154 | var oidA = ObjectId()
155 | var oidB = oidA
156 | oidA.equals(oidB).should.equal(true)
157 | })
158 | it('curries arguments', function () {
159 | var oidA = ObjectId()
160 | var eq = ObjectId.equals(oidA)
161 | eq.should.be.a('function')
162 | eq('sdfsdf').should.equal(false)
163 | eq(oidA).should.equal(true)
164 | })
165 | })
166 |
167 | describe('.tryParse', function () {
168 | it('returns false if the first argument cannot be cast to an objectId', function () {
169 | var out = {}
170 | ObjectId.tryParse('sdfsdf', out, 'oid').should.equal(false)
171 | })
172 | it('returns true and casts the oid to the out object if possible', function () {
173 | var out = {}
174 | ObjectId.tryParse('511083bb08ce6b1b00000003', out, 'oid').should.equal(true)
175 | out.oid.should.be.instanceof(ObjectId.constructor)
176 | out.oid.toString().should.equal('511083bb08ce6b1b00000003')
177 | })
178 | it('returns false if trying to parse an empty objectId', function () {
179 | var out = {}
180 | ObjectId.tryParse(undefined, out, 'oid').should.equal(false)
181 | })
182 | it('returns true for a native ObjectId', function () {
183 | var out = {}
184 | var oid = new NativeObjectId()
185 | ObjectId.tryParse(oid, out, 'oid').should.equal(true)
186 |
187 | })
188 | })
189 |
190 | })
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/provider-test.js:
--------------------------------------------------------------------------------
1 | /*
2 | * provider-test.js: Tests for the nconf Provider object.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var assert = require('assert'),
9 | fs = require('fs'),
10 | path = require('path'),
11 | spawn = require('child_process').spawn,
12 | vows = require('vows'),
13 | helpers = require('./helpers'),
14 | nconf = require('../lib/nconf');
15 |
16 | var fixturesDir = path.join(__dirname, 'fixtures'),
17 | mergeFixtures = path.join(fixturesDir, 'merge'),
18 | files = [path.join(mergeFixtures, 'file1.json'), path.join(mergeFixtures, 'file2.json')],
19 | override = JSON.parse(fs.readFileSync(files[0]), 'utf8');
20 |
21 | function assertProvider(test) {
22 | return {
23 | topic: new nconf.Provider(),
24 | "should use the correct File store": test
25 | };
26 | }
27 |
28 | vows.describe('nconf/provider').addBatch({
29 | "When using nconf": {
30 | "an instance of 'nconf.Provider'": {
31 | "calling the use() method with the same store type and different options": {
32 | topic: new nconf.Provider().use('file', { file: files[0] }),
33 | "should use a new instance of the store type": function (provider) {
34 | var old = provider.stores['file'];
35 |
36 | assert.equal(provider.stores.file.file, files[0]);
37 | provider.use('file', { file: files[1] });
38 |
39 | assert.notStrictEqual(old, provider.stores.file);
40 | assert.equal(provider.stores.file.file, files[1]);
41 | }
42 | },
43 | "when 'argv' is true": helpers.assertSystemConf({
44 | script: path.join(fixturesDir, 'scripts', 'provider-argv.js'),
45 | argv: ['--something', 'foobar']
46 | }),
47 | "when 'env' is true": helpers.assertSystemConf({
48 | script: path.join(fixturesDir, 'scripts', 'provider-env.js'),
49 | env: { SOMETHING: 'foobar' }
50 | })
51 | },
52 | "the default nconf provider": {
53 | "when 'argv' is set to true": helpers.assertSystemConf({
54 | script: path.join(fixturesDir, 'scripts', 'nconf-argv.js'),
55 | argv: ['--something', 'foobar'],
56 | env: { SOMETHING: true }
57 | }),
58 | "when 'env' is set to true": helpers.assertSystemConf({
59 | script: path.join(fixturesDir, 'scripts', 'nconf-env.js'),
60 | env: { SOMETHING: 'foobar' }
61 | }),
62 | "when 'argv' is set to true and process.argv is modified": helpers.assertSystemConf({
63 | script: path.join(fixturesDir, 'scripts', 'nconf-change-argv.js'),
64 | argv: ['--something', 'badValue', 'evenWorse', 'OHNOEZ', 'foobar']
65 | }),
66 | "when hierarchical 'argv' get": helpers.assertSystemConf({
67 | script: path.join(fixturesDir, 'scripts', 'nconf-hierarchical-file-argv.js'),
68 | argv: ['--something', 'foobar'],
69 | env: { SOMETHING: true }
70 | }),
71 | "when 'env' is set to true with a nested separator": helpers.assertSystemConf({
72 | script: path.join(fixturesDir, 'scripts', 'nconf-nested-env.js'),
73 | env: { SOME_THING: 'foobar' }
74 | })
75 | }
76 | }
77 | }).addBatch({
78 | "When using nconf": {
79 | "an instance of 'nconf.Provider'": {
80 | "the merge() method": {
81 | topic: new nconf.Provider().use('file', { file: files[1] }),
82 | "should have the result merged in": function (provider) {
83 | provider.load();
84 | provider.merge(override);
85 | helpers.assertMerged(null, provider.stores.file.store);
86 | assert.equal(provider.stores.file.store.candy.something, 'file1');
87 | },
88 | "should merge Objects over null": function (provider) {
89 | provider.load();
90 | provider.merge(override);
91 | assert.equal(provider.stores.file.store.unicorn.exists, true);
92 | }
93 | }
94 | }
95 | }
96 | }).addBatch({
97 | "When using nconf": {
98 | "an instance of 'nconf.Provider'": {
99 | "the load() method": {
100 | "when sources are passed in": {
101 | topic: new nconf.Provider({
102 | sources: {
103 | user: {
104 | type: 'file',
105 | file: files[0]
106 | },
107 | global: {
108 | type: 'file',
109 | file: files[1]
110 | }
111 | }
112 | }),
113 | "should respect the hierarchy ": function (provider) {
114 | var merged = provider.load();
115 |
116 | helpers.assertMerged(null, merged);
117 | assert.equal(merged.candy.something, 'file1');
118 | }
119 | },
120 | "when multiple stores are used": {
121 | topic: new nconf.Provider().overrides({foo: {bar: 'baz'}})
122 | .add('file1', {type: 'file', file: files[0]})
123 | .add('file2', {type: 'file', file: files[1]}),
124 | "should respect the hierarchy": function(provider) {
125 | var merged = provider.load();
126 |
127 | helpers.assertMerged(null, merged);
128 | assert.equal(merged.foo.bar, 'baz');
129 | assert.equal(merged.candy.something, 'file1');
130 | }
131 | }
132 | }
133 | }
134 | }
135 | }).addBatch({
136 | "When using nconf": {
137 | "an instance of 'nconf.Provider'": {
138 | "the .file() method": {
139 | "with a single filepath": assertProvider(function (provider) {
140 | provider.file(helpers.fixture('store.json'));
141 | assert.isObject(provider.stores.file);
142 | }),
143 | "with a name and a filepath": assertProvider(function (provider) {
144 | provider.file('custom', helpers.fixture('store.json'));
145 | assert.isObject(provider.stores.custom);
146 | }),
147 | "with a single object": assertProvider(function (provider) {
148 | provider.file({
149 | dir: helpers.fixture(''),
150 | file: 'store.json',
151 | search: true
152 | });
153 |
154 | assert.isObject(provider.stores.file);
155 | assert.equal(provider.stores.file.file, helpers.fixture('store.json'));
156 | }),
157 | "with a name and an object": assertProvider(function (provider) {
158 | provider.file('custom', {
159 | dir: helpers.fixture(''),
160 | file: 'store.json',
161 | search: true
162 | });
163 |
164 | assert.isObject(provider.stores.custom);
165 | assert.equal(provider.stores.custom.file, helpers.fixture('store.json'));
166 | })
167 | }
168 | }
169 | }
170 | }).export(module);
171 |
--------------------------------------------------------------------------------
/app/sign/src/styles/_variables.scss:
--------------------------------------------------------------------------------
1 |
2 |
3 | @import "functions";
4 | @import "mixins";
5 | @import "color";
6 |
7 |
8 |
9 | /* ========== background-color ========= */
10 | // base bg
11 | $base-bg: $white;
12 |
13 | // active bg color
14 | $base-active-bg: $indigo;
15 | $base-active-light-bg: $ashgrey;
16 | $base-alert-bg: $red;
17 | $base-disabled-bg: $disabled;
18 |
19 | // divider
20 | $base-divider-bg: $grey;
21 |
22 |
23 |
24 | /* ========== font ========== */
25 |
26 | // defined font size
27 | $body-font-size: rem-calc(14);
28 | $base-font-size-tny: rem-calc(12);
29 | $base-font-size-sml: rem-calc(13);
30 | $base-font-size-def: $body-font-size;
31 | $base-font-size-med: rem-calc(16);
32 | $base-font-size-mid: rem-calc(20);
33 | $base-font-size-lrg: rem-calc(22);
34 |
35 | // defined font color
36 | $base-font-color: $bistre; // 333 正常
37 | $base-font-color-primary: $bistre; //333 重要
38 | $base-font-color-secondary: $darkgrey; // 737373 次要
39 | $base-font-color-alert: $red; // f15964 警告 提醒
40 | $base-font-color-info: $manatee; //aaa 消息信息
41 | $base-font-color-link: $indigo;
42 | $base-font-color-deepbg: $white; // fff 白色
43 | $base-font-color-title: $indigo;
44 |
45 | $base-font-color-info-title: $manatee; // aaa
46 |
47 | $base-font-color-holder: $lavendergray;// c7c7c7
48 |
49 |
50 | $font-family: -apple-system,".SFNSText-Regular",'Helvetica Neue','Hiragino Sans GB','WenQuanYi Micro Hei','Microsoft Yahei',sans-serif;
51 |
52 |
53 | $font-weight-normal: normal !default;
54 | $font-weight-bold: bold !default;
55 |
56 | $body-bg: $white !default;
57 | $body-font-color: $base-font-color;
58 | $body-font-family: $font-family !default;
59 | $body-font-weight: $font-weight-normal !default;
60 | $body-font-style: normal !default;
61 |
62 | $font-smoothing-webkit: antialiased !default;
63 | $font-smoothing-moz: grayscale !default;
64 |
65 | $base-font-size: 100% !default;
66 | $base-line-height: 1.5 !default;
67 |
68 |
69 |
70 | /* ========== Media Query Ranges ========== */
71 |
72 | $small-breakpoint: 460px !default;
73 |
74 | $small-col-breakpoint: 560px !default;
75 |
76 | $medium-breakpoint: 920px !default;
77 | $large-breakpoint: 1020px !default;
78 | $xlarge-breakpoint: 1920px !default;
79 | $popup-breakpoint: 610px !default;
80 |
81 | $small-range: (0, $small-breakpoint) !default;
82 | $small-col-range: ($small-breakpoint + 1px, $small-col-breakpoint) !default;
83 | $medium-range: ($small-breakpoint + 1px, $medium-breakpoint) !default;
84 | $large-range: ($medium-breakpoint + 1px, $large-breakpoint) !default;
85 | $xlarge-range: ($large-breakpoint + 1px, $xlarge-breakpoint) !default;
86 | $popup-range: (0, $popup-breakpoint) !default;
87 |
88 | $screen: "only screen" !default;
89 |
90 | $popup-low: "#{$screen} and (max-width:#{upper-bound($popup-range)})" !default;
91 |
92 | $landscape: "#{$screen} and (orientation: landscape)" !default;
93 | $portrait: "#{$screen} and (orientation: portrait)" !default;
94 |
95 | $small-up: $screen !default;
96 | $small-only: "#{$screen} and (max-width: #{upper-bound($small-range)})" !default;
97 |
98 | $small-col-only: "#{$screen} and (min-width: #{lower-bound($small-col-range)}) and (max-width:#{upper-bound($small-col-range)})" !default;
99 |
100 | $medium-up: "#{$screen} and (min-width:#{lower-bound($medium-range)})" !default;
101 | $medium-only: "#{$screen} and (min-width:#{lower-bound($medium-range)}) and (max-width:#{upper-bound($medium-range)})" !default;
102 | $medium-low: "#{$screen} and (max-width:#{upper-bound($medium-range)})" !default;
103 |
104 | $large-up: "#{$screen} and (min-width:#{lower-bound($large-range)})" !default;
105 | $large-only: "#{$screen} and (min-width:#{lower-bound($large-range)}) and (max-width:#{upper-bound($large-range)})" !default;
106 | $large-low: "#{$screen} and (max-width:#{upper-bound($large-range)})" !default;
107 |
108 | $xlarge-up: "#{$screen} and (min-width:#{lower-bound($xlarge-range)})" !default;
109 | $xlarge-only: "#{$screen} and (min-width:#{lower-bound($xlarge-range)}) and (max-width:#{upper-bound($xlarge-range)})" !default;
110 |
111 | $xxlarge-up: "#{$screen} and (min-width:#{lower-bound($xlarge-range)})" !default;
112 |
113 | $retina: (
114 | "#{$screen} and (min-device-pixel-ratio: 2)",
115 | "#{$screen} and (min-resolution: 192dpi)",
116 | "#{$screen} and (min-resolution: 2dppx)"
117 | );
118 |
119 | /* ========== /Media Query Ranges ========== */
120 |
121 | // grid
122 | $grid-left-width: rem-calc(260);
123 | // $grid-right-width: rem-calc(460);
124 | $grid-right-width: 36%;
125 |
126 | $grid-right-width-col-2: 45%;
127 |
128 | $grid-right-width-col-1: 70%;
129 |
130 | $grid-left-bg: $base-active-bg;
131 |
132 |
133 | //We use this as cursors values for enabling the option of having custom cursors in the whole site's stylesheet
134 | $cursor-auto-value: auto !default;
135 | $cursor-crosshair-value: crosshair !default;
136 | $cursor-default-value: default !default;
137 | $cursor-disabled-value: not-allowed !default;
138 | $cursor-pointer-value: pointer !default;
139 | $cursor-help-value: help !default;
140 | $cursor-text-value: text !default;
141 |
142 | // border
143 | $base-border-color: $timberwolf;
144 |
145 | $base-focus-border-color: $indigo;
146 | $base-focus-border: 1px solid $base-focus-border-color;
147 |
148 | $base-border-style: 1px solid;
149 |
150 | $base-border: 1px solid $base-border-color;
151 | $base-border-radius: rem-calc(4);
152 | $global-radius: $base-border-radius;
153 | $list-border-width: $base-border-radius;
154 |
155 | $input-base-border-color: $grey;
156 |
157 |
158 | // box-shadow
159 | $base-box-shadow: 0 6px 20px rgba(0,0,0,.15) !default;
160 | $base-pop-shadow: 0 12px 40px rgba(0,0,0,.3) !default;
161 | $base-input-box-shadow: 0 0 8px rgba(0, 0, 0, 0.06) !default;
162 |
163 | $pop-box-shdow: 0 7px 18px rgba(0, 0, 0, 0.12);
164 | $pop-down-box-shdow: 0 -7px 18px rgba(0, 0, 0, 0.12);
165 |
166 | // float
167 | $default-float: left !default;
168 | $opposite-direction: right !default;
169 |
170 |
171 | // main padding
172 | $col-padding: rem-calc(20);
173 | $row-padding: rem-calc(10);
174 |
175 | // z-index master list
176 | $zindex-1: 1 !default;
177 | $zindex-2: 2 !default;
178 | $zindex-3: 3 !default;
179 |
180 | $zindex-navbar: 1000 !default;
181 | $zindex-dropdown: 1000 !default;
182 | $zindex-popover: 1060 !default;
183 | $zindex-tooltip: 1070 !default;
184 | $zindex-navbar-fixed: 1030 !default;
185 | $zindex-modal-background: 1040 !default;
186 | $zindex-loadview: 1045 !default;
187 | $zindex-modal: 1050 !default;
188 | $zindex-drag: 1080 !default;
189 |
190 | // icon size
191 | $base-icon-size: rem-calc(24);
192 |
193 | $small-icon-size: rem-calc(14);
194 |
195 | $li-line-height: rem-calc(36) !default;
196 |
197 | // avatar size
198 | $avatar-size-sml: rem-calc(16);
199 | $avatar-size: rem-calc(36);
200 | $avatar-size-lrg: rem-calc(60);
201 |
202 |
203 | $base-transition-duration: .2s;
204 | $base-transition-timing-function: ease;
205 |
206 |
207 | $base-list-padding-t-b: rem-calc(5);
208 | // select list
209 | $base-list-padding: $base-list-padding-t-b 0;
210 |
211 | $base-modal-padding: rem-calc(24);
212 |
--------------------------------------------------------------------------------
/app/sign/src/styles/_button.scss:
--------------------------------------------------------------------------------
1 | //
2 | // @variables
3 |
4 | $primary-color: $indigo !default;
5 | $secondary-color: $whitelilac !default;
6 | $alert-color: $red !default;
7 | $normal-color: $white;
8 | // $success-color: #43AC6A !default;
9 | // $warning-color: #f08a24 !default;
10 | // $info-color: #a0d3e8 !default;
11 | //
12 |
13 | $button-transition-duration: .2s;
14 | $button-transition-timing-function: ease;
15 |
16 | // all buttons min width
17 | $button-min-width: rem-calc(100) !default;
18 |
19 | // all buttons padding right and left
20 | $button-padding-rl: rem-calc(12) !default;
21 |
22 | // padding top and bottom for buttons.
23 | $button-tny: rem-calc(7) !default;
24 | $button-sml: rem-calc(8) !default;
25 | $button-med: rem-calc(11) !default;
26 | $button-lrg: rem-calc(13) !default;
27 |
28 | // the display property.
29 | $button-display: inline-block !default;
30 | $button-margin-bottom: rem-calc(0) !default;
31 |
32 | // button text styles.
33 | $button-font-family: $body-font-family !default;
34 | $button-font-color: $white !default;
35 |
36 | $button-font-tny: $base-font-size-sml !default;
37 | $button-font-sml: $body-font-size !default;
38 | $button-font-med: $body-font-size !default;
39 | $button-font-lrg: $body-font-size !default;
40 | $button-font-weight: $font-weight-normal !default;
41 | $button-font-align: center !default;
42 |
43 | // hover effects.
44 | $button-function-factor: -5% !default;
45 |
46 | // active / keypress effects
47 | $button-active-function-factor: -20% !default;
48 |
49 | // We use these to control button border styles.
50 | $button-border-width: 0 !default;
51 | $button-border-style: solid !default;
52 |
53 | $button-bg-color: $primary-color !default;
54 | $button-bg-hover: scale-color($button-bg-color, $lightness: $button-function-factor) !default;
55 | $button-bg-active: scale-color($button-bg-color, $lightness: $button-active-function-factor) !default;
56 |
57 |
58 | $secondary-button-bg-color: $secondary-color !default;
59 | $secondary-button-bg-hover: scale-color($secondary-color, $lightness: $button-function-factor) !default;
60 | $secondary-button-bg-active: scale-color($secondary-color, $lightness: $button-active-function-factor) !default;
61 | $secondary-button-font-color: $bistre !default;
62 |
63 | $alert-button-bg-color: $alert-color !default;
64 | $alert-button-bg-hover: scale-color($alert-color, $lightness: $button-function-factor) !default;
65 | $alert-button-bg-active: scale-color($alert-color, $lightness: $button-active-function-factor) !default;
66 |
67 | $normal-button-bg-color: $normal-color;
68 | $normal-button-bg-hover: scale-color($normal-button-bg-color, $lightness: $button-function-factor) !default;
69 | $normal-button-bg-active: scale-color($normal-button-bg-color, $lightness: $button-active-function-factor) !default;
70 | $normal-button-font-color: $base-font-color-info;
71 |
72 |
73 | // the default radius used throughout the core.
74 | $button-radius: $global-radius !default;
75 | $button-round: $global-radius !default;
76 |
77 | // set default opacity and cursor for disabled buttons.
78 | $button-disabled-opacity: .7 !default;
79 | $button-disabled-cursor: $cursor-default-value !default;
80 |
81 |
82 | //
83 | // @MIXIN
84 | //
85 | // We use this mixin to create a default button base.
86 | //
87 | // $style - Sets base styles. Can be set to false. Default: true.
88 | // $display - Used to control display property. Default: $button-display || inline-block
89 |
90 | @mixin button-base($display:$button-display) {
91 | -webkit-appearance: none;
92 | -moz-appearance: none;
93 | box-shadow: none;
94 | border-radius:$button-radius;
95 | border-style: $button-border-style;
96 | border-width: $button-border-width;
97 | padding-left: $button-padding-rl;
98 | padding-right: $button-padding-rl;
99 | min-width: $button-min-width;
100 | cursor: $cursor-pointer-value;
101 | font-family: $button-font-family;
102 | font-weight: $button-font-weight;
103 | line-height: 1;
104 | margin: 0 0 $button-margin-bottom;
105 | position: relative;
106 | text-align: $button-font-align;
107 | text-decoration: none;
108 | outline: none;
109 | color: $button-font-color;
110 | @if $display { display: $display; }
111 | }
112 |
113 | // @MIXIN
114 | //
115 | // We use this mixin to add button size styles
116 | //
117 | // $padding - Used to build padding for buttons Default: $button-med ||= rem-calc(12)
118 |
119 | @mixin button-size($padding:$button-med) {
120 |
121 | // We control which padding styles come through
122 | padding-top: $padding;
123 | padding-bottom: $padding;
124 | // We control the font-size based on mixin input.
125 | @if $padding == $button-med { font-size: $button-font-med;}
126 | @else if $padding == $button-tny { font-size: $button-font-tny; }
127 | @else if $padding == $button-sml { font-size: $button-font-sml; }
128 | @else if $padding == $button-lrg { font-size: $button-font-lrg; }
129 |
130 | }
131 |
132 | // @MIXIN
133 | //
134 | // we use this mixin to create the button hover and border colors
135 |
136 | // @MIXIN
137 | //
138 | // We use this mixin to add button color styles
139 | //
140 | // $bg - Background color. We can set $bg:false for a transparent background. Default: $primary-color.
141 | // $radius - If true, set to button radius which is $button-radius || explicitly set radius amount in px (ex. $radius:10px). Default: false
142 | // $disabled - We can set $disabled:true to create a disabled transparent button. Default: false
143 | // $bg-hover - Button Hover Background Color. Default: $button-bg-hover
144 | @mixin button-style($bg:$button-bg-color, $disabled:false, $bg-hover:$button-bg-hover, $bg-active:$button-bg-active, $color:$button-font-color) {
145 |
146 | color: $color;
147 | // We control which background styles are used,
148 | // these can be removed by setting $bg:false
149 |
150 | background-color: $bg;
151 |
152 | @if $disabled == false {
153 | &:hover,
154 | &:focus { background-color: $bg-hover; }
155 | &:active { background-color: $bg-active; }
156 | }
157 |
158 | // We can set $disabled:true to create a disabled transparent button.
159 | @if $disabled {
160 | cursor: $button-disabled-cursor;
161 | opacity: $button-disabled-opacity;
162 | }
163 |
164 | }
165 |
166 |
167 | // class
168 | button, .button, .btn {
169 | @include button-base;
170 | @include button-size;
171 | @include button-style;
172 |
173 | @include single-transition(background-color, $button-transition-duration, $button-transition-timing-function);
174 |
175 | &.btn-primary { @include button-style($bg:$button-bg-color, $bg-hover:$button-bg-hover, $bg-active: $button-bg-active); }
176 | &.btn-secondary,
177 | &.btn-cancel { @include button-style($bg:$secondary-button-bg-color, $bg-hover:$secondary-button-bg-hover, $bg-active: $secondary-button-bg-active, $color: $secondary-button-font-color); }
178 | &.btn-alert { @include button-style($bg:$alert-button-bg-color, $bg-hover:$alert-button-bg-hover, $bg-active: $alert-button-bg-active); }
179 |
180 | &.btn-normal { @include button-style($bg:$normal-button-bg-color, $bg-hover:$normal-button-bg-hover, $bg-active: $normal-button-bg-active, $color: $normal-button-font-color); }
181 |
182 | &.btn-tny { @include button-size($padding:$button-tny); }
183 | &.btn-sml { @include button-size($padding:$button-sml); }
184 | &.btn-med { @include button-size($padding:$button-med); }
185 | &.btn-lrg { @include button-size($padding:$button-lrg); }
186 |
187 | &.disabled, &[disabled] { @include button-style($bg:$button-bg-color, $disabled:true, $bg-hover:$button-bg-hover);
188 | &.btn-primary { @include button-style($bg:$button-bg-color, $disabled:true, $bg-hover:$button-bg-hover); }
189 | &.btn-cancel { @include button-style($bg:$secondary-button-bg-color, $disabled:true, $color: $secondary-button-font-color); }
190 | &.btn-alert { @include button-style($bg:$alert-button-bg-color, $disabled:true, $bg-hover:$alert-button-bg-hover); }
191 | }
192 | }
193 |
194 | //firefox 2px fix
195 | button::-moz-focus-inner {border:0; padding:0;}
196 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/lib/nconf/stores/file.js:
--------------------------------------------------------------------------------
1 | /*
2 | * file.js: Simple file storage engine for nconf files
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var crypto = require('crypto'),
9 | fs = require('fs'),
10 | path = require('path'),
11 | util = require('util'),
12 | Secure = require('secure-keys'),
13 | formats = require('../formats'),
14 | Memory = require('./memory').Memory,
15 | exists = fs.exists || path.exists,
16 | existsSync = fs.existsSync || path.existsSync;
17 |
18 | //
19 | // ### function File (options)
20 | // #### @options {Object} Options for this instance
21 | // Constructor function for the File nconf store, a simple abstraction
22 | // around the Memory store that can persist configuration to disk.
23 | //
24 | var File = exports.File = function (options) {
25 | if (!options || !options.file) {
26 | throw new Error ('Missing required option `file`');
27 | }
28 |
29 | Memory.call(this, options);
30 |
31 | this.type = 'file';
32 | this.file = options.file;
33 | this.dir = options.dir || process.cwd();
34 | this.format = options.format || formats.json;
35 | this.secure = options.secure;
36 | this.spacing = options.json_spacing
37 | || options.spacing
38 | || 2;
39 |
40 | if (this.secure) {
41 | this.secure = Buffer.isBuffer(this.secure) || typeof this.secure === 'string'
42 | ? { secret: this.secure.toString() }
43 | : this.secure;
44 |
45 | this.secure.alg = this.secure.alg || 'aes-256-ctr';
46 | if (this.secure.secretPath) {
47 | this.secure.secret = fs.readFileSync(this.secure.secretPath, 'utf8');
48 | }
49 |
50 | if (!this.secure.secret) {
51 | throw new Error('secure.secret option is required');
52 | }
53 |
54 | this.keys = new Secure({
55 | secret: this.secure.secret,
56 | alg: this.secure.alg,
57 | format: this.format
58 | });
59 | }
60 |
61 | if (options.search) {
62 | this.search(this.dir);
63 | }
64 | };
65 |
66 | // Inherit from the Memory store
67 | util.inherits(File, Memory);
68 |
69 | //
70 | // ### function save (value, callback)
71 | // #### @value {Object} _Ignored_ Left here for consistency
72 | // #### @callback {function} Continuation to respond to when complete.
73 | // Saves the current configuration object to disk at `this.file`
74 | // using the format specified by `this.format`.
75 | //
76 | File.prototype.save = function (value, callback) {
77 | if (!callback) {
78 | callback = value;
79 | value = null;
80 | }
81 |
82 | fs.writeFile(this.file, this.stringify(), callback);
83 | };
84 |
85 | //
86 | // ### function saveSync (value, callback)
87 | // #### @value {Object} _Ignored_ Left here for consistency
88 | // #### @callback {function} **Optional** Continuation to respond to when complete.
89 | // Saves the current configuration object to disk at `this.file`
90 | // using the format specified by `this.format` synchronously.
91 | //
92 | File.prototype.saveSync = function (value) {
93 | fs.writeFileSync(this.file, this.stringify());
94 | return this.store;
95 | };
96 |
97 | //
98 | // ### function load (callback)
99 | // #### @callback {function} Continuation to respond to when complete.
100 | // Responds with an Object representing all keys associated in this instance.
101 | //
102 | File.prototype.load = function (callback) {
103 | var self = this;
104 |
105 | exists(self.file, function (exists) {
106 | if (!exists) {
107 | return callback(null, {});
108 | }
109 |
110 | //
111 | // Else, the path exists, read it from disk
112 | //
113 | fs.readFile(self.file, function (err, data) {
114 | if (err) {
115 | return callback(err);
116 | }
117 |
118 | try {
119 | // Deals with string that include BOM
120 | var stringData = data.toString();
121 | if (stringData.charAt(0) === '\uFEFF') {
122 | stringData = stringData.substr(1);
123 | }
124 |
125 | self.store = self.parse(stringData);
126 | }
127 | catch (ex) {
128 | return callback(new Error("Error parsing your configuration file: [" + self.file + ']: ' + ex.message));
129 | }
130 |
131 | callback(null, self.store);
132 | });
133 | });
134 | };
135 |
136 | //
137 | // ### function loadSync (callback)
138 | // Attempts to load the data stored in `this.file` synchronously
139 | // and responds appropriately.
140 | //
141 | File.prototype.loadSync = function () {
142 | if (!existsSync(this.file)) {
143 | this.store = {};
144 | return this.store;
145 | }
146 |
147 | //
148 | // Else, the path exists, read it from disk
149 | //
150 | try {
151 | // Deals with file that include BOM
152 | var fileData = fs.readFileSync(this.file, 'utf8');
153 | if (fileData.charAt(0) === '\uFEFF') {
154 | fileData = fileData.substr(1);
155 | }
156 |
157 | this.store = this.parse(fileData);
158 | }
159 | catch (ex) {
160 | throw new Error("Error parsing your configuration file: [" + this.file + ']: ' + ex.message);
161 | }
162 |
163 | return this.store;
164 | };
165 |
166 | //
167 | // ### function stringify ()
168 | // Returns an encrypted version of the contents IIF
169 | // `this.secure` is enabled
170 | //
171 | File.prototype.stringify = function () {
172 | var data = this.store,
173 | self = this;
174 |
175 | if (this.secure) {
176 | data = this.keys.encrypt(data);
177 | }
178 |
179 | return this.format.stringify(data, null, this.spacing);
180 | };
181 |
182 | //
183 | // ### function parse (contents)
184 | // Returns a decrypted version of the contents IFF
185 | // `this.secure` is enabled.
186 | //
187 | File.prototype.parse = function (contents) {
188 | var parsed = this.format.parse(contents),
189 | self = this;
190 |
191 | if (!this.secure) {
192 | return parsed;
193 | }
194 |
195 | return this.keys.decrypt(parsed);
196 |
197 | };
198 |
199 |
200 | //
201 | // ### function search (base)
202 | // #### @base {string} Base directory (or file) to begin searching for the target file.
203 | // Attempts to find `this.file` by iteratively searching up the
204 | // directory structure
205 | //
206 | File.prototype.search = function (base) {
207 | var looking = true,
208 | fullpath,
209 | previous,
210 | stats;
211 |
212 | base = base || process.cwd();
213 |
214 | if (this.file[0] === '/') {
215 | //
216 | // If filename for this instance is a fully qualified path
217 | // (i.e. it starts with a `'/'`) then check if it exists
218 | //
219 | try {
220 | stats = fs.statSync(fs.realpathSync(this.file));
221 | if (stats.isFile()) {
222 | fullpath = this.file;
223 | looking = false;
224 | }
225 | }
226 | catch (ex) {
227 | //
228 | // Ignore errors
229 | //
230 | }
231 | }
232 |
233 | if (looking && base) {
234 | //
235 | // Attempt to stat the realpath located at `base`
236 | // if the directory does not exist then return false.
237 | //
238 | try {
239 | var stat = fs.statSync(fs.realpathSync(base));
240 | looking = stat.isDirectory();
241 | }
242 | catch (ex) {
243 | return false;
244 | }
245 | }
246 |
247 | while (looking) {
248 | //
249 | // Iteratively look up the directory structure from `base`
250 | //
251 | try {
252 | stats = fs.statSync(fs.realpathSync(fullpath = path.join(base, this.file)));
253 | looking = stats.isDirectory();
254 | }
255 | catch (ex) {
256 | previous = base;
257 | base = path.dirname(base);
258 |
259 | if (previous === base) {
260 | //
261 | // If we've reached the top of the directory structure then simply use
262 | // the default file path.
263 | //
264 | try {
265 | stats = fs.statSync(fs.realpathSync(fullpath = path.join(this.dir, this.file)));
266 | if (stats.isDirectory()) {
267 | fullpath = undefined;
268 | }
269 | }
270 | catch (ex) {
271 | //
272 | // Ignore errors
273 | //
274 | }
275 |
276 | looking = false;
277 | }
278 | }
279 | }
280 |
281 | //
282 | // Set the file for this instance to the fullpath
283 | // that we have found during the search. In the event that
284 | // the search was unsuccessful use the original value for `this.file`.
285 | //
286 | this.file = fullpath || this.file;
287 |
288 | return fullpath;
289 | };
290 |
--------------------------------------------------------------------------------
/app/sign/dist/sign.min.css:
--------------------------------------------------------------------------------
1 | .text-tny{font-size:12px}.text-sml{font-size:13px}.text-def{font-size:14px}.text-med{font-size:16px}.text-lrg{font-size:22px}.left{float:left!important}.right{float:right!important}.clearfix:after,.clearfix:before{content:" ";display:table}.clearfix:after{clear:both}.hide{display:none!important}.hidden{display:none}.invisible{visibility:hidden}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.divider,.l-divider{height:1px;width:100%}.l-divider{margin:10px 0}.i-tny{width:14px;height:14px}.i-sml{width:16px;height:16px}.i-med{width:32px;height:32px}.i-lrg{width:40px;height:40px}.i-lrg-x{width:48px;height:48px}.i-xl{width:100px;height:100px}.i-xxl{width:180px;height:180px}.i-xxxl{width:192px;height:192px}.i-redeem{width:156px;height:96px}.line-left,.line-right{position:relative}.line-right{z-index:1;float:right}.b-h{height:100%}.drag{visibility:hidden;position:absolute;cursor:move}.shadow{box-shadow:0 6px 20px rgba(0,0,0,.15)}.pop-shadow,.shadow{border:1px solid #ececec;border-radius:4px}.pop-shadow{box-shadow:0 12px 40px rgba(0,0,0,.3)}.dropdown-toggle{cursor:pointer}img.round{border-radius:50%;overflow:hidden}.btns{line-height:1}.nowrap{white-space:nowrap}body>svg{display:none}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.drag-help{width:360px;max-width:360px;opacity:.9}.line-sml{line-height:21px}.file-wrap{overflow:hidden}.can-not-select *,.select-disabled *{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.can-not-select [contenteditable],.can-not-select input,.can-not-select textarea,.can-select,.can-select *,.select-disabled [contenteditable],.select-disabled input,.select-disabled textarea,.select-enabled,.select-enabled *{-moz-user-select:text;-webkit-user-select:text;-ms-user-select:text}.tl-body .antiscroll-wrap{position:static}.loading-view{width:100%;height:100%;background-color:#fff;position:absolute;top:0;z-index:3;text-align:center}.loading-view .logo{position:relative;height:100%;top:50%;margin-top:-100px}.avoid-event svg{pointer-events:none}.btn,.button,button{-webkit-appearance:none;-moz-appearance:none;box-shadow:none;border-radius:4px;border-style:solid;border-width:0;padding:11px 12px;min-width:100px;cursor:pointer;font-family:-apple-system,\.SFNSText-Regular,Helvetica Neue,Hiragino Sans GB,WenQuanYi Micro Hei,Microsoft Yahei,sans-serif;font-weight:400;line-height:1;margin:0;position:relative;text-align:center;text-decoration:none;outline:none;display:inline-block;font-size:14px;color:#fff;background-color:#617fde;-webkit-transition:background-color .2s ease;transition:background-color .2s ease}.btn:focus,.btn:hover,.button:focus,.button:hover,button:focus,button:hover{background-color:#5474db}.btn:active,.button:active,button:active{background-color:#2c54d3}.btn.btn-primary,.button.btn-primary,button.btn-primary{color:#fff;background-color:#617fde}.btn.btn-primary:focus,.btn.btn-primary:hover,.button.btn-primary:focus,.button.btn-primary:hover,button.btn-primary:focus,button.btn-primary:hover{background-color:#5474db}.btn.btn-primary:active,.button.btn-primary:active,button.btn-primary:active{background-color:#2c54d3}.btn.btn-cancel,.btn.btn-secondary,.button.btn-cancel,.button.btn-secondary,button.btn-cancel,button.btn-secondary{color:#333;background-color:#ebebeb}.btn.btn-cancel:focus,.btn.btn-cancel:hover,.btn.btn-secondary:focus,.btn.btn-secondary:hover,.button.btn-cancel:focus,.button.btn-cancel:hover,.button.btn-secondary:focus,.button.btn-secondary:hover,button.btn-cancel:focus,button.btn-cancel:hover,button.btn-secondary:focus,button.btn-secondary:hover{background-color:#dfdfdf}.btn.btn-cancel:active,.btn.btn-secondary:active,.button.btn-cancel:active,.button.btn-secondary:active,button.btn-cancel:active,button.btn-secondary:active{background-color:#bcbcbc}.btn.btn-alert,.button.btn-alert,button.btn-alert{color:#fff;background-color:#ff3180}.btn.btn-alert:focus,.btn.btn-alert:hover,.button.btn-alert:focus,.button.btn-alert:hover,button.btn-alert:focus,button.btn-alert:hover{background-color:#f27}.btn.btn-alert:active,.button.btn-alert:active,button.btn-alert:active{background-color:#f3005d}.btn.btn-normal,.button.btn-normal,button.btn-normal{color:#aaa;background-color:#fff}.btn.btn-normal:focus,.btn.btn-normal:hover,.button.btn-normal:focus,.button.btn-normal:hover,button.btn-normal:focus,button.btn-normal:hover{background-color:#f2f2f2}.btn.btn-normal:active,.button.btn-normal:active,button.btn-normal:active{background-color:#ccc}.btn.btn-tny,.button.btn-tny,button.btn-tny{padding-top:7px;padding-bottom:7px;font-size:13px}.btn.btn-sml,.button.btn-sml,button.btn-sml{padding-top:8px;padding-bottom:8px;font-size:14px}.btn.btn-med,.button.btn-med,button.btn-med{padding-top:11px;padding-bottom:11px;font-size:14px}.btn.btn-lrg,.button.btn-lrg,button.btn-lrg{padding-top:13px;padding-bottom:13px;font-size:14px}.btn.disabled,.btn.disabled.btn-primary,.btn[disabled],.btn[disabled].btn-primary,.button.disabled,.button.disabled.btn-primary,.button[disabled],.button[disabled].btn-primary,button.disabled,button.disabled.btn-primary,button[disabled],button[disabled].btn-primary{color:#fff;background-color:#617fde;cursor:default;opacity:.7}.btn.disabled.btn-cancel,.btn[disabled].btn-cancel,.button.disabled.btn-cancel,.button[disabled].btn-cancel,button.disabled.btn-cancel,button[disabled].btn-cancel{color:#333;background-color:#ebebeb;cursor:default;opacity:.7}.btn.disabled.btn-alert,.btn[disabled].btn-alert,.button.disabled.btn-alert,.button[disabled].btn-alert,button.disabled.btn-alert,button[disabled].btn-alert{color:#fff;background-color:#ff3180;cursor:default;opacity:.7}button::-moz-focus-inner{border:0;padding:0}.btns .btn-loading,.btns.ing .btn-initial{display:none}.btns.ing .btn-loading{display:inline-block}.icon-email-blue{width:24px;height:24px;background-position:-64px 0}.icon-email-gray{width:24px;height:24px;background-position:-64px -24px}.icon-lock-blue{width:24px;height:24px;background-position:-88px 0}.icon-lock-gray{width:24px;height:24px;background-position:-88px -24px}.icon-logo{width:64px;height:68px;background-position:0 0}.icon-name-blue{width:24px;height:24px;background-position:0 -68px}.icon-name-gray{width:24px;height:24px;background-position:-24px -68px}.icon_sign{background-size:112px 92px;background-repeat:no-repeat;display:inline-block}@media only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min--moz-device-pixel-ratio:2),only screen and (min-device-pixel-ratio:2),only screen and (min-resolution:2dppx),only screen and (min-resolution:192dpi){.icon_sign{background-size:112px 92px}}::-webkit-input-placeholder{color:#c7c7c7}:-moz-placeholder,::-moz-placeholder{color:#c7c7c7}:-ms-input-placeholder{color:#c7c7c7!important}a,body,div,html,i,li,p,span,ul{margin:0;padding:0;border:0;outline:0;font-size:100%;font:inherit}ol,ul{list-style:none}a{text-decoration:none}a,a:hover{color:#617fde}a:hover{text-decoration:underline}a:active,a:hover{outline:0}a:visited{color:#617fde;text-decoration:none}input,input:focus{outline:0;box-shadow:none}img{border-radius:50%}.button{cursor:pointer;-webkit-appearance:none}body{line-height:1;font-family:-apple-system,\.SFNSText-Regular,Helvetica Neue,Hiragino Sans GB,WenQuanYi Micro Hei,Microsoft Yahei,sans-serif;background:#fdfdfd;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.sign{max-width:400px;min-width:300px;margin:48px auto;color:#333}.card{position:relative;margin:0 auto}.logo{text-align:center;margin-bottom:36px}.card-section{background-color:#fff;border:1px solid #ececec;border-radius:2px;padding:40px 50px}.form{position:relative}.sign .row{position:relative;border-bottom:1px solid #ececec;border-radius:1px;margin-bottom:28px}.sign .row,.sign .row.active{-webkit-transition:border-color ease-in-out .15s;transition:border-color ease-in-out .15s}.sign .row.email input,.sign .row.name input,.sign .row.password input{border:0 none;font-size:16px;padding:10px 10px 8px 8px;width:calc(100% - 70px)}.sign .row.forgot-password,.sign .row.submit{border-bottom:none}.sign .row.submit{margin:0 auto;margin-bottom:12px}.sign .row.forgot-password{margin:0;text-align:left;font-size:13px}.input-bar{position:relative;display:block;width:100%;height:1px}.input-bar:after,.input-bar:before{content:'';height:1px;width:0;bottom:-1px;position:absolute;background-color:#617fde;border-radius:1px;-webkit-transition:all .28s cubic-bezier(.4,0,.2,1);transition:all .28s cubic-bezier(.4,0,.2,1)}.input-bar:before{left:50%;border-top-right-radius:0;border-bottom-right-radius:0}.input-bar:after{right:50%;border-top-left-radius:0;border-bottom-left-radius:0}input:focus~.input-bar:before{left:0;width:51%}input:focus~.input-bar:after{right:0;width:50%}.switch-site{display:none}.chrome-extension .forgot-password .link{float:right}.chrome-extension .forgot-password .switch-site{display:inline;float:left}.sign .row .icon{position:relative;top:6px}.middle-line{overflow:hidden;text-align:center}.middle-line:after,.middle-line:before{background-color:#ececec;content:"";display:inline-block;height:1px;position:relative;vertical-align:middle;width:50%}.middle-line:before{right:.5em;margin-left:-50%}.middle-line:after{left:.5em;margin-right:-50%}.sns-title{color:#c7c7c7;font-size:13px;padding:30px 0 36px}.signin-sns ul{text-align:center}.signin-sns ul li{display:inline-block}.signin-sns ul li.second{margin:0 42px}.signin-sns ul li:hover{opacity:.9}.link.sign-link,.link.signin,.link.signup{text-align:center;padding-top:35px;font-size:14px}.link.message{line-height:25px;padding:40px 0 0}.link.success{padding:40px 0}.button{font-size:16px;width:100%}.error{position:absolute;right:0;z-index:2}.error .warn{display:none;color:#ff3180;font-size:13px;margin-top:6px;line-height:1.1}.error.long{position:relative}@media only screen and (max-width:460px){.sign{width:95%}.sign .signin-sns ul li:nth-child(2){margin:0 10px}}
--------------------------------------------------------------------------------
/app/node_modules/nconf/test/stores/file-store-test.js:
--------------------------------------------------------------------------------
1 | /*
2 | * file-store-test.js: Tests for the nconf File store.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var fs = require('fs'),
9 | path = require('path'),
10 | vows = require('vows'),
11 | assert = require('assert'),
12 | nconf = require('../../lib/nconf'),
13 | data = require('../fixtures/data').data,
14 | store;
15 |
16 | vows.describe('nconf/stores/file').addBatch({
17 | "When using the nconf file store": {
18 | "with a valid JSON file": {
19 | topic: function () {
20 | var filePath = path.join(__dirname, '..', 'fixtures', 'store.json');
21 | fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
22 | this.store = store = new nconf.File({ file: filePath });
23 | return null;
24 | },
25 | "the load() method": {
26 | topic: function () {
27 | this.store.load(this.callback);
28 | },
29 | "should load the data correctly": function (err, data) {
30 | assert.isNull(err);
31 | assert.deepEqual(data, this.store.store);
32 | }
33 | }
34 | },
35 | "with a malformed JSON file": {
36 | topic: function () {
37 | var filePath = path.join(__dirname, '..', 'fixtures', 'malformed.json');
38 | this.store = new nconf.File({ file: filePath });
39 | return null;
40 | },
41 | "the load() method with a malformed JSON config file": {
42 | topic: function () {
43 | this.store.load(this.callback.bind(null, null));
44 | },
45 | "should respond with an error and indicate file name": function (_, err) {
46 | assert.isTrue(!!err);
47 | assert.match(err, /malformed\.json/);
48 | }
49 | }
50 | },
51 | "with a valid UTF8 JSON file that contains a BOM": {
52 | topic: function () {
53 | var filePath = path.join(__dirname, '..', 'fixtures', 'bom.json');
54 | this.store = store = new nconf.File({ file: filePath });
55 | return null;
56 | },
57 | "the load() method": {
58 | topic: function () {
59 | this.store.load(this.callback);
60 | },
61 | "should load the data correctly": function (err, data) {
62 | assert.isNull(err);
63 | assert.deepEqual(data, this.store.store);
64 | }
65 | },
66 | "the loadSync() method": {
67 | topic: function () {
68 | var data = this.store.loadSync();
69 | return data;
70 | },
71 | "should load the data correctly": function (result) {
72 | assert.deepEqual(result, this.store.store);
73 | }
74 | }
75 | },
76 | "with a valid UTF8 JSON file that contains no BOM": {
77 | topic: function () {
78 | var filePath = path.join(__dirname, '..', 'fixtures', 'no-bom.json');
79 | this.store = store = new nconf.File({ file: filePath });
80 | return null;
81 | },
82 | "the load() method": {
83 | topic: function () {
84 | this.store.load(this.callback);
85 | },
86 | "should load the data correctly": function (err, data) {
87 | assert.isNull(err);
88 | assert.deepEqual(data, this.store.store);
89 | }
90 | },
91 | "the loadSync() method": {
92 | topic: function () {
93 | var data = this.store.loadSync();
94 | return data;
95 | },
96 | "should load the data correctly": function (result) {
97 | assert.deepEqual(result, this.store.store);
98 | }
99 | }
100 | }
101 | }
102 | }).addBatch({
103 | "When using the nconf file store": {
104 | topic: function () {
105 | var tmpPath = path.join(__dirname, '..', 'fixtures', 'tmp.json'),
106 | tmpStore = new nconf.File({ file: tmpPath });
107 | return tmpStore;
108 | },
109 | "the save() method": {
110 | topic: function (tmpStore) {
111 | var that = this;
112 |
113 | Object.keys(data).forEach(function (key) {
114 | tmpStore.set(key, data[key]);
115 | });
116 |
117 | tmpStore.save(function () {
118 | fs.readFile(tmpStore.file, function (err, d) {
119 | fs.unlinkSync(tmpStore.file);
120 |
121 | return err
122 | ? that.callback(err)
123 | : that.callback(err, JSON.parse(d.toString()));
124 | });
125 | });
126 | },
127 | "should save the data correctly": function (err, read) {
128 | assert.isNull(err);
129 | assert.deepEqual(read, data);
130 | }
131 | }
132 | }
133 | }).addBatch({
134 | "When using the nconf file store": {
135 | topic: function () {
136 | var tmpPath = path.join(__dirname, '..', 'fixtures', 'tmp.json'),
137 | tmpStore = new nconf.File({ file: tmpPath });
138 | return tmpStore;
139 | },
140 | "the saveSync() method": {
141 | topic: function (tmpStore) {
142 | var that = this;
143 |
144 | Object.keys(data).forEach(function (key) {
145 | tmpStore.set(key, data[key]);
146 | });
147 |
148 | var saved = tmpStore.saveSync();
149 |
150 | fs.readFile(tmpStore.file, function (err, d) {
151 | fs.unlinkSync(tmpStore.file);
152 |
153 | return err
154 | ? that.callback(err)
155 | : that.callback(err, JSON.parse(d.toString()), saved);
156 | });
157 | },
158 | "should save the data correctly": function (err, read, saved) {
159 | assert.isNull(err);
160 | assert.deepEqual(read, data);
161 | assert.deepEqual(read, saved);
162 | }
163 | }
164 | }
165 | }).addBatch({
166 | "When using the nconf file store": {
167 | "the set() method": {
168 | "should respond with true": function () {
169 | assert.isTrue(store.set('foo:bar:bazz', 'buzz'));
170 | assert.isTrue(store.set('falsy:number', 0));
171 | assert.isTrue(store.set('falsy:string', ''));
172 | assert.isTrue(store.set('falsy:boolean', false));
173 | assert.isTrue(store.set('falsy:object', null));
174 | }
175 | },
176 | "the get() method": {
177 | "should respond with the correct value": function () {
178 | assert.equal(store.get('foo:bar:bazz'), 'buzz');
179 | assert.equal(store.get('falsy:number'), 0);
180 | assert.equal(store.get('falsy:string'), '');
181 | assert.equal(store.get('falsy:boolean'), false);
182 | assert.equal(store.get('falsy:object'), null);
183 | }
184 | },
185 | "the clear() method": {
186 | "should respond with the true": function () {
187 | assert.equal(store.get('foo:bar:bazz'), 'buzz');
188 | assert.isTrue(store.clear('foo:bar:bazz'));
189 | assert.isTrue(typeof store.get('foo:bar:bazz') === 'undefined');
190 | }
191 | }
192 | }
193 | }).addBatch({
194 | "When using the nconf file store": {
195 | "the search() method": {
196 | "when the target file exists higher in the directory tree": {
197 | topic: function () {
198 | var filePath = this.filePath = path.join(process.env.HOME, '.nconf');
199 | fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
200 | return new (nconf.File)({
201 | file: '.nconf'
202 | })
203 | },
204 | "should update the file appropriately": function (store) {
205 | store.search();
206 | assert.equal(store.file, this.filePath);
207 | fs.unlinkSync(this.filePath);
208 | }
209 | },
210 | "when the target file doesn't exist higher in the directory tree": {
211 | topic: function () {
212 | var filePath = this.filePath = path.join(__dirname, '..', 'fixtures', 'search-store.json');
213 | return new (nconf.File)({
214 | dir: path.dirname(filePath),
215 | file: 'search-store.json'
216 | })
217 | },
218 | "should update the file appropriately": function (store) {
219 | store.search();
220 | assert.equal(store.file, this.filePath);
221 | }
222 | }
223 | }
224 | }
225 | }).addBatch({
226 | "When using the nconf file store": {
227 | topic: function () {
228 | var secureStore = new nconf.File({
229 | file: path.join(__dirname, '..', 'fixtures', 'secure.json'),
230 | secure: 'super-secretzzz'
231 | });
232 |
233 | secureStore.store = data;
234 | return secureStore;
235 | },
236 | "the stringify() method should encrypt properly": function (store) {
237 | var contents = JSON.parse(store.stringify());
238 | Object.keys(data).forEach(function (key) {
239 | assert.isObject(contents[key]);
240 | assert.isString(contents[key].value);
241 | assert.equal(contents[key].alg, 'aes-256-ctr');
242 | });
243 | },
244 | "the parse() method should decrypt properly": function (store) {
245 | var contents = store.stringify();
246 | var parsed = store.parse(contents);
247 | assert.deepEqual(parsed, data);
248 | },
249 | "the load() method should decrypt properly": function (store) {
250 | store.load(function (err, loaded) {
251 | assert.isNull(err);
252 | assert.deepEqual(loaded, data);
253 | });
254 | },
255 | "the loadSync() method should decrypt properly": function (store) {
256 | var loaded = store.loadSync()
257 | assert.deepEqual(loaded, data);
258 | }
259 | }
260 | }).export(module);
261 |
262 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/README.md:
--------------------------------------------------------------------------------
1 | # nconf
2 |
3 | [](https://www.npmjs.com/package/nconf)[](https://www.npmjs.com/package/nconf)[](https://travis-ci.org/indexzero/nconf)[](https://coveralls.io/github/indexzero/nconf)[](https://david-dm.org/indexzero/nconf)
4 |
5 | Hierarchical node.js configuration with files, environment variables, command-line arguments, and atomic object merging.
6 |
7 | ## Example
8 | Using nconf is easy; it is designed to be a simple key-value store with support for both local and remote storage. Keys are namespaced and delimited by `:`. Let's dive right into sample usage:
9 |
10 | ``` js
11 | var fs = require('fs'),
12 | nconf = require('nconf');
13 |
14 | //
15 | // Setup nconf to use (in-order):
16 | // 1. Command-line arguments
17 | // 2. Environment variables
18 | // 3. A file located at 'path/to/config.json'
19 | //
20 | nconf.argv()
21 | .env()
22 | .file({ file: 'path/to/config.json' });
23 |
24 | //
25 | // Set a few variables on `nconf`.
26 | //
27 | nconf.set('database:host', '127.0.0.1');
28 | nconf.set('database:port', 5984);
29 |
30 | //
31 | // Get the entire database object from nconf. This will output
32 | // { host: '127.0.0.1', port: 5984 }
33 | //
34 | console.log('foo: ' + nconf.get('foo'));
35 | console.log('NODE_ENV: ' + nconf.get('NODE_ENV'));
36 | console.log('database: ' + nconf.get('database'));
37 |
38 | //
39 | // Save the configuration object to disk
40 | //
41 | nconf.save(function (err) {
42 | fs.readFile('path/to/your/config.json', function (err, data) {
43 | console.dir(JSON.parse(data.toString()))
44 | });
45 | });
46 | ```
47 |
48 | If you run the above script:
49 |
50 | ``` bash
51 | $ NODE_ENV=production sample.js --foo bar
52 | ```
53 |
54 | The output will be:
55 |
56 | ```
57 | foo: bar
58 | NODE_ENV: production
59 | database: { host: '127.0.0.1', port: 5984 }
60 | ```
61 |
62 | ## Hierarchical configuration
63 |
64 | Configuration management can get complicated very quickly for even trivial applications running in production. `nconf` addresses this problem by enabling you to setup a hierarchy for different sources of configuration with no defaults. **The order in which you attach these configuration sources determines their priority in the hierarchy.** Let's take a look at the options available to you
65 |
66 | 1. **nconf.argv(options)** Loads `process.argv` using yargs. If `options` is supplied it is passed along to yargs.
67 | 2. **nconf.env(options)** Loads `process.env` into the hierarchy.
68 | 3. **nconf.file(options)** Loads the configuration data at options.file into the hierarchy.
69 | 4. **nconf.defaults(options)** Loads the data in options.store into the hierarchy.
70 | 5. **nconf.overrides(options)** Loads the data in options.store into the hierarchy.
71 |
72 | A sane default for this could be:
73 |
74 | ``` js
75 | var nconf = require('nconf');
76 |
77 | //
78 | // 1. any overrides
79 | //
80 | nconf.overrides({
81 | 'always': 'be this value'
82 | });
83 |
84 | //
85 | // 2. `process.env`
86 | // 3. `process.argv`
87 | //
88 | nconf.env().argv();
89 |
90 | //
91 | // 4. Values in `config.json`
92 | //
93 | nconf.file('/path/to/config.json');
94 |
95 | //
96 | // Or with a custom name
97 | // Note: A custom key must be supplied for hierarchy to work if multiple files are used.
98 | //
99 | nconf.file('custom', '/path/to/config.json');
100 |
101 | //
102 | // Or searching from a base directory.
103 | // Note: `name` is optional.
104 | //
105 | nconf.file(name, {
106 | file: 'config.json',
107 | dir: 'search/from/here',
108 | search: true
109 | });
110 |
111 | //
112 | // 5. Any default values
113 | //
114 | nconf.defaults({
115 | 'if nothing else': 'use this value'
116 | });
117 | ```
118 |
119 | ## API Documentation
120 |
121 | The top-level of `nconf` is an instance of the `nconf.Provider` abstracts this all for you into a simple API.
122 |
123 | ### nconf.add(name, options)
124 | Adds a new store with the specified `name` and `options`. If `options.type` is not set, then `name` will be used instead:
125 |
126 | ``` js
127 | nconf.add('supplied', { type: 'literal', store: { 'some': 'config' });
128 | nconf.add('user', { type: 'file', file: '/path/to/userconf.json' });
129 | nconf.add('global', { type: 'file', file: '/path/to/globalconf.json' });
130 | ```
131 |
132 | ### nconf.use(name, options)
133 | Similar to `nconf.add`, except that it can replace an existing store if new options are provided
134 |
135 | ``` js
136 | //
137 | // Load a file store onto nconf with the specified settings
138 | //
139 | nconf.use('file', { file: '/path/to/some/config-file.json' });
140 |
141 | //
142 | // Replace the file store with new settings
143 | //
144 | nconf.use('file', { file: 'path/to/a-new/config-file.json' });
145 | ```
146 |
147 | ### nconf.remove(name)
148 | Removes the store with the specified `name.` The configuration stored at that level will no longer be used for lookup(s).
149 |
150 | ``` js
151 | nconf.remove('file');
152 | ```y
153 |
154 | ### nconf.required(keys)
155 | Declares a set of string keys to be mandatory, and throw an error if any are missing.
156 |
157 | ```js
158 | nconf.defaults({
159 | keya: 'a',
160 | });
161 |
162 | nconf.required(['keya', 'keyb']);
163 | // Error: Missing required keys: keyb
164 | ```
165 |
166 | ## Storage Engines
167 |
168 | ### Memory
169 | A simple in-memory storage engine that stores a nested JSON representation of the configuration. To use this engine, just call `.use()` with the appropriate arguments. All calls to `.get()`, `.set()`, `.clear()`, `.reset()` methods are synchronous since we are only dealing with an in-memory object.
170 |
171 | ``` js
172 | nconf.use('memory');
173 | ```
174 |
175 | ### Argv
176 | Responsible for loading the values parsed from `process.argv` by `yargs` into the configuration hierarchy. See the [yargs option docs](https://github.com/bcoe/yargs#optionskey-opt) for more on the option format.
177 |
178 | ``` js
179 | //
180 | // Can optionally also be an object literal to pass to `yargs`.
181 | //
182 | nconf.argv({
183 | "x": {
184 | alias: 'example',
185 | describe: 'Example description for usage generation',
186 | demand: true,
187 | default: 'some-value'
188 | }
189 | });
190 | ```
191 |
192 | ### Env
193 | Responsible for loading the values parsed from `process.env` into the configuration hierarchy.
194 |
195 | ``` js
196 | //
197 | // Can optionally also be an Array of values to limit process.env to.
198 | //
199 | nconf.env(['only', 'load', 'these', 'values', 'from', 'process.env']);
200 |
201 | //
202 | // Can also specify a separator for nested keys (instead of the default ':')
203 | //
204 | nconf.env('__');
205 | // Get the value of the env variable 'database__host'
206 | var dbHost = nconf.get('database:host');
207 |
208 | //
209 | // Or use all options
210 | //
211 | nconf.env({
212 | separator: '__',
213 | match: /^whatever_matches_this_will_be_whitelisted/
214 | whitelist: ['database__host', 'only', 'load', 'these', 'values', 'if', 'whatever_doesnt_match_but_is_whitelisted_gets_loaded_too']
215 | });
216 | var dbHost = nconf.get('database:host');
217 | ```
218 |
219 | ### Literal
220 | Loads a given object literal into the configuration hierarchy. Both `nconf.defaults()` and `nconf.overrides()` use the Literal store.
221 |
222 | ``` js
223 | nconf.defaults({
224 | 'some': 'default value'
225 | });
226 | ```
227 |
228 | ### File
229 | Based on the Memory store, but provides additional methods `.save()` and `.load()` which allow you to read your configuration to and from file. As with the Memory store, all method calls are synchronous with the exception of `.save()` and `.load()` which take callback functions.
230 |
231 | It is important to note that setting keys in the File engine will not be persisted to disk until a call to `.save()` is made. Note a custom key must be supplied as the first parameter for hierarchy to work if multiple files are used.
232 |
233 | ``` js
234 | nconf.file('path/to/your/config.json');
235 | // add multiple files, hierarchically. notice the unique key for each file
236 | nconf.file('user', 'path/to/your/user.json');
237 | nconf.file('global', 'path/to/your/global.json');
238 | ```
239 |
240 | The file store is also extensible for multiple file formats, defaulting to `JSON`. To use a custom format, simply pass a format object to the `.use()` method. This object must have `.parse()` and `.stringify()` methods just like the native `JSON` object.
241 |
242 | If the file does not exist at the provided path, the store will simply be empty.
243 |
244 | #### Encrypting file contents
245 |
246 | As of `nconf@0.8.0` it is now possible to encrypt and decrypt file contents using the `secure` option:
247 |
248 | ``` js
249 | nconf.file('secure-file', {
250 | file: 'path/to/secure-file.json',
251 | secure: {
252 | secret: 'super-secretzzz-keyzz',
253 | alg: 'aes-256-ctr'
254 | }
255 | })
256 | ```
257 |
258 | This will encrypt each key using [`crypto.createCipher`](https://nodejs.org/api/crypto.html#crypto_crypto_createcipher_algorithm_password), defaulting to `aes-256-ctr`. The encrypted file contents will look like this:
259 |
260 | ```
261 | {
262 | "config-key-name": {
263 | "alg": "aes-256-ctr", // cipher used
264 | "value": "af07fbcf" // encrypted contents
265 | },
266 | "another-config-key": {
267 | "alg": "aes-256-ctr", // cipher used
268 | "value": "e310f6d94f13" // encrypted contents
269 | },
270 | }
271 | ```
272 |
273 | ### Redis
274 | There is a separate Redis-based store available through [nconf-redis][0]. To install and use this store simply:
275 |
276 | ``` bash
277 | $ npm install nconf
278 | $ npm install nconf-redis
279 | ```
280 |
281 | Once installing both `nconf` and `nconf-redis`, you must require both modules to use the Redis store:
282 |
283 | ``` js
284 | var nconf = require('nconf');
285 |
286 | //
287 | // Requiring `nconf-redis` will extend the `nconf`
288 | // module.
289 | //
290 | require('nconf-redis');
291 |
292 | nconf.use('redis', { host: 'localhost', port: 6379, ttl: 60 * 60 * 1000 });
293 | ```
294 |
295 | ## Installation
296 | ```
297 | npm install nconf --save
298 | ```
299 |
300 | ## Run Tests
301 | Tests are written in vows and give complete coverage of all APIs and storage engines.
302 |
303 | ``` bash
304 | $ npm test
305 | ```
306 |
307 | #### Author: [Charlie Robbins](http://nodejitsu.com)
308 | #### License: MIT
309 |
310 | [0]: http://github.com/indexzero/nconf-redis
311 |
--------------------------------------------------------------------------------
/app/node_modules/nconf/lib/nconf/provider.js:
--------------------------------------------------------------------------------
1 | /*
2 | * provider.js: Abstraction providing an interface into pluggable configuration storage.
3 | *
4 | * (C) 2011, Charlie Robbins and the Contributors.
5 | *
6 | */
7 |
8 | var async = require('async'),
9 | common = require('./common');
10 |
11 | //
12 | // ### function Provider (options)
13 | // #### @options {Object} Options for this instance.
14 | // Constructor function for the Provider object responsible
15 | // for exposing the pluggable storage features of `nconf`.
16 | //
17 | var Provider = exports.Provider = function (options) {
18 | //
19 | // Setup default options for working with `stores`,
20 | // `overrides`, `process.env` and `process.argv`.
21 | //
22 | options = options || {};
23 | this.stores = {};
24 | this.sources = [];
25 | this.init(options);
26 | };
27 |
28 | //
29 | // Define wrapper functions for using basic stores
30 | // in this instance
31 | //
32 |
33 | ['argv', 'env'].forEach(function (type) {
34 | Provider.prototype[type] = function () {
35 | var args = [type].concat(Array.prototype.slice.call(arguments));
36 | return this.add.apply(this, args);
37 | };
38 | });
39 |
40 | //
41 | // ### function file (key, options)
42 | // #### @key {string|Object} Fully qualified options, name of file store, or path.
43 | // #### @path {string|Object} **Optional** Full qualified options, or path.
44 | // Adds a new `File` store to this instance. Accepts the following options
45 | //
46 | // nconf.file({ file: '.jitsuconf', dir: process.env.HOME, search: true });
47 | // nconf.file('path/to/config/file');
48 | // nconf.file('userconfig', 'path/to/config/file');
49 | // nconf.file('userconfig', { file: '.jitsuconf', search: true });
50 | //
51 | Provider.prototype.file = function (key, options) {
52 | if (arguments.length == 1) {
53 | options = typeof key === 'string' ? { file: key } : key;
54 | key = 'file';
55 | }
56 | else {
57 | options = typeof options === 'string'
58 | ? { file: options }
59 | : options;
60 | }
61 |
62 | options.type = 'file';
63 | return this.add(key, options);
64 | };
65 |
66 | //
67 | // Define wrapper functions for using
68 | // overrides and defaults
69 | //
70 | ['defaults', 'overrides'].forEach(function (type) {
71 | Provider.prototype[type] = function (options) {
72 | options = options || {};
73 | if (!options.type) {
74 | options.type = 'literal';
75 | }
76 |
77 | return this.add(type, options);
78 | };
79 | });
80 |
81 | //
82 | // ### function use (name, options)
83 | // #### @type {string} Type of the nconf store to use.
84 | // #### @options {Object} Options for the store instance.
85 | // Adds (or replaces) a new store with the specified `name`
86 | // and `options`. If `options.type` is not set, then `name`
87 | // will be used instead:
88 | //
89 | // provider.use('file');
90 | // provider.use('file', { type: 'file', filename: '/path/to/userconf' })
91 | //
92 | Provider.prototype.use = function (name, options) {
93 | options = options || {};
94 | var type = options.type || name;
95 |
96 | function sameOptions (store) {
97 | return Object.keys(options).every(function (key) {
98 | return options[key] === store[key];
99 | });
100 | }
101 |
102 | var store = this.stores[name],
103 | update = store && !sameOptions(store);
104 |
105 | if (!store || update) {
106 | if (update) {
107 | this.remove(name);
108 | }
109 |
110 | this.add(name, options);
111 | }
112 |
113 | return this;
114 | };
115 |
116 | //
117 | // ### function add (name, options)
118 | // #### @name {string} Name of the store to add to this instance
119 | // #### @options {Object} Options for the store to create
120 | // Adds a new store with the specified `name` and `options`. If `options.type`
121 | // is not set, then `name` will be used instead:
122 | //
123 | // provider.add('memory');
124 | // provider.add('userconf', { type: 'file', filename: '/path/to/userconf' })
125 | //
126 | Provider.prototype.add = function (name, options, usage) {
127 | options = options || {};
128 | var type = options.type || name;
129 |
130 | if (!require('../nconf')[common.capitalize(type)]) {
131 | throw new Error('Cannot add store with unknown type: ' + type);
132 | }
133 |
134 | this.stores[name] = this.create(type, options, usage);
135 |
136 | if (this.stores[name].loadSync) {
137 | this.stores[name].loadSync();
138 | }
139 |
140 | return this;
141 | };
142 |
143 | //
144 | // ### function remove (name)
145 | // #### @name {string} Name of the store to remove from this instance
146 | // Removes a store with the specified `name` from this instance. Users
147 | // are allowed to pass in a type argument (e.g. `memory`) as name if
148 | // this was used in the call to `.add()`.
149 | //
150 | Provider.prototype.remove = function (name) {
151 | delete this.stores[name];
152 | return this;
153 | };
154 |
155 | //
156 | // ### function create (type, options)
157 | // #### @type {string} Type of the nconf store to use.
158 | // #### @options {Object} Options for the store instance.
159 | // Creates a store of the specified `type` using the
160 | // specified `options`.
161 | //
162 | Provider.prototype.create = function (type, options, usage) {
163 | return new (require('../nconf')[common.capitalize(type.toLowerCase())])(options, usage);
164 | };
165 |
166 | //
167 | // ### function init (options)
168 | // #### @options {Object} Options to initialize this instance with.
169 | // Initializes this instance with additional `stores` or `sources` in the
170 | // `options` supplied.
171 | //
172 | Provider.prototype.init = function (options) {
173 | var self = this;
174 |
175 | //
176 | // Add any stores passed in through the options
177 | // to this instance.
178 | //
179 | if (options.type) {
180 | this.add(options.type, options);
181 | }
182 | else if (options.store) {
183 | this.add(options.store.name || options.store.type, options.store);
184 | }
185 | else if (options.stores) {
186 | Object.keys(options.stores).forEach(function (name) {
187 | var store = options.stores[name];
188 | self.add(store.name || name || store.type, store);
189 | });
190 | }
191 |
192 | //
193 | // Add any read-only sources to this instance
194 | //
195 | if (options.source) {
196 | this.sources.push(this.create(options.source.type || options.source.name, options.source));
197 | }
198 | else if (options.sources) {
199 | Object.keys(options.sources).forEach(function (name) {
200 | var source = options.sources[name];
201 | self.sources.push(self.create(source.type || source.name || name, source));
202 | });
203 | }
204 | };
205 |
206 | //
207 | // ### function get (key, callback)
208 | // #### @key {string} Key to retrieve for this instance.
209 | // #### @callback {function} **Optional** Continuation to respond to when complete.
210 | // Retrieves the value for the specified key (if any).
211 | //
212 | Provider.prototype.get = function (key, callback) {
213 | if (typeof key === 'function') {
214 | // Allow a * key call to be made
215 | callback = key;
216 | key = null;
217 | }
218 |
219 | //
220 | // If there is no callback we can short-circuit into the default
221 | // logic for traversing stores.
222 | //
223 | if (!callback) {
224 | return this._execute('get', 1, key, callback);
225 | }
226 |
227 | //
228 | // Otherwise the asynchronous, hierarchical `get` is
229 | // slightly more complicated because we do not need to traverse
230 | // the entire set of stores, but up until there is a defined value.
231 | //
232 | var current = 0,
233 | names = Object.keys(this.stores),
234 | self = this,
235 | response,
236 | mergeObjs = [];
237 |
238 | async.whilst(function () {
239 | return typeof response === 'undefined' && current < names.length;
240 | }, function (next) {
241 | var store = self.stores[names[current]];
242 | current++;
243 |
244 | if (store.get.length >= 2) {
245 | return store.get(key, function (err, value) {
246 | if (err) {
247 | return next(err);
248 | }
249 |
250 | response = value;
251 |
252 | // Merge objects if necessary
253 | if (response && typeof response === 'object' && !Array.isArray(response)) {
254 | mergeObjs.push(response);
255 | response = undefined;
256 | }
257 |
258 | next();
259 | });
260 | }
261 |
262 | response = store.get(key);
263 |
264 | // Merge objects if necessary
265 | if (response && typeof response === 'object' && !Array.isArray(response)) {
266 | mergeObjs.push(response);
267 | response = undefined;
268 | }
269 |
270 | next();
271 | }, function (err) {
272 | if (!err && mergeObjs.length) {
273 | response = common.merge(mergeObjs.reverse());
274 | }
275 | return err ? callback(err) : callback(null, response);
276 | });
277 | };
278 |
279 | //
280 | // ### function set (key, value, callback)
281 | // #### @key {string} Key to set in this instance
282 | // #### @value {literal|Object} Value for the specified key
283 | // #### @callback {function} **Optional** Continuation to respond to when complete.
284 | // Sets the `value` for the specified `key` in this instance.
285 | //
286 | Provider.prototype.set = function (key, value, callback) {
287 | return this._execute('set', 2, key, value, callback);
288 | };
289 |
290 |
291 | //
292 | // ### function required (keys)
293 | // #### @keys {array} List of keys
294 | // Throws an error if any of `keys` has no value, otherwise returns `true`
295 | Provider.prototype.required = function (keys) {
296 | if (!Array.isArray(keys)) {
297 | throw new Error('Incorrect parameter, array expected');
298 | }
299 |
300 | var missing = [];
301 | keys.forEach(function(key) {
302 | if (typeof this.get(key) === 'undefined') {
303 | missing.push(key);
304 | }
305 | }, this);
306 |
307 | if (missing.length) {
308 | throw new Error('Missing required keys: ' + missing.join(', '));
309 | } else {
310 | return true;
311 | }
312 |
313 | };
314 |
315 | //
316 | // ### function reset (callback)
317 | // #### @callback {function} **Optional** Continuation to respond to when complete.
318 | // Clears all keys associated with this instance.
319 | //
320 | Provider.prototype.reset = function (callback) {
321 | return this._execute('reset', 0, callback);
322 | };
323 |
324 | //
325 | // ### function clear (key, callback)
326 | // #### @key {string} Key to remove from this instance
327 | // #### @callback {function} **Optional** Continuation to respond to when complete.
328 | // Removes the value for the specified `key` from this instance.
329 | //
330 | Provider.prototype.clear = function (key, callback) {
331 | return this._execute('clear', 1, key, callback);
332 | };
333 |
334 | //
335 | // ### function merge ([key,] value [, callback])
336 | // #### @key {string} Key to merge the value into
337 | // #### @value {literal|Object} Value to merge into the key
338 | // #### @callback {function} **Optional** Continuation to respond to when complete.
339 | // Merges the properties in `value` into the existing object value at `key`.
340 | //
341 | // 1. If the existing value `key` is not an Object, it will be completely overwritten.
342 | // 2. If `key` is not supplied, then the `value` will be merged into the root.
343 | //
344 | Provider.prototype.merge = function () {
345 | var self = this,
346 | args = Array.prototype.slice.call(arguments),
347 | callback = typeof args[args.length - 1] === 'function' && args.pop(),
348 | value = args.pop(),
349 | key = args.pop();
350 |
351 | function mergeProperty (prop, next) {
352 | return self._execute('merge', 2, prop, value[prop], next);
353 | }
354 |
355 | if (!key) {
356 | if (Array.isArray(value) || typeof value !== 'object') {
357 | return onError(new Error('Cannot merge non-Object into top-level.'), callback);
358 | }
359 |
360 | return async.forEach(Object.keys(value), mergeProperty, callback || function () { })
361 | }
362 |
363 | return this._execute('merge', 2, key, value, callback);
364 | };
365 |
366 | //
367 | // ### function load (callback)
368 | // #### @callback {function} Continuation to respond to when complete.
369 | // Responds with an Object representing all keys associated in this instance.
370 | //
371 | Provider.prototype.load = function (callback) {
372 | var self = this;
373 |
374 | function getStores () {
375 | var stores = Object.keys(self.stores);
376 | stores.reverse();
377 | return stores.map(function (name) {
378 | return self.stores[name];
379 | });
380 | }
381 |
382 | function loadStoreSync(store) {
383 | if (!store.loadSync) {
384 | throw new Error('nconf store ' + store.type + ' has no loadSync() method');
385 | }
386 |
387 | return store.loadSync();
388 | }
389 |
390 | function loadStore(store, next) {
391 | if (!store.load && !store.loadSync) {
392 | return next(new Error('nconf store ' + store.type + ' has no load() method'));
393 | }
394 |
395 | return store.loadSync
396 | ? next(null, store.loadSync())
397 | : store.load(next);
398 | }
399 |
400 | function loadBatch (targets, done) {
401 | if (!done) {
402 | return common.merge(targets.map(loadStoreSync));
403 | }
404 |
405 | async.map(targets, loadStore, function (err, objs) {
406 | return err ? done(err) : done(null, common.merge(objs));
407 | });
408 | }
409 |
410 | function mergeSources (data) {
411 | //
412 | // If `data` was returned then merge it into
413 | // the system store.
414 | //
415 | if (data && typeof data === 'object') {
416 | self.use('sources', {
417 | type: 'literal',
418 | store: data
419 | });
420 | }
421 | }
422 |
423 | function loadSources () {
424 | var sourceHierarchy = self.sources.splice(0);
425 | sourceHierarchy.reverse();
426 |
427 | //
428 | // If we don't have a callback and the current
429 | // store is capable of loading synchronously
430 | // then do so.
431 | //
432 | if (!callback) {
433 | mergeSources(loadBatch(sourceHierarchy));
434 | return loadBatch(getStores());
435 | }
436 |
437 | loadBatch(sourceHierarchy, function (err, data) {
438 | if (err) {
439 | return callback(err);
440 | }
441 |
442 | mergeSources(data);
443 | return loadBatch(getStores(), callback);
444 | });
445 | }
446 |
447 | return self.sources.length
448 | ? loadSources()
449 | : loadBatch(getStores(), callback);
450 | };
451 |
452 | //
453 | // ### function save (callback)
454 | // #### @callback {function} **optional** Continuation to respond to when
455 | // complete.
456 | // Instructs each provider to save. If a callback is provided, we will attempt
457 | // asynchronous saves on the providers, falling back to synchronous saves if
458 | // this isn't possible. If a provider does not know how to save, it will be
459 | // ignored. Returns an object consisting of all of the data which was
460 | // actually saved.
461 | //
462 | Provider.prototype.save = function (value, callback) {
463 | if (!callback && typeof value === 'function') {
464 | callback = value;
465 | value = null;
466 | }
467 |
468 | var self = this,
469 | names = Object.keys(this.stores);
470 |
471 | function saveStoreSync(memo, name) {
472 | var store = self.stores[name];
473 |
474 | //
475 | // If the `store` doesn't have a `saveSync` method,
476 | // just ignore it and continue.
477 | //
478 | if (store.saveSync) {
479 | var ret = store.saveSync();
480 | if (typeof ret == 'object' && ret !== null) {
481 | memo.push(ret);
482 | }
483 | }
484 | return memo;
485 | }
486 |
487 | function saveStore(memo, name, next) {
488 | var store = self.stores[name];
489 |
490 | //
491 | // If the `store` doesn't have a `save` or saveSync`
492 | // method(s), just ignore it and continue.
493 | //
494 |
495 | if (store.save) {
496 | return store.save(value, function (err, data) {
497 | if (err) {
498 | return next(err);
499 | }
500 |
501 | if (typeof data == 'object' && data !== null) {
502 | memo.push(data);
503 | }
504 |
505 | next(null, memo);
506 | });
507 | }
508 | else if (store.saveSync) {
509 | memo.push(store.saveSync());
510 | }
511 |
512 | next(null, memo);
513 | }
514 |
515 | //
516 | // If we don't have a callback and the current
517 | // store is capable of saving synchronously
518 | // then do so.
519 | //
520 | if (!callback) {
521 | return common.merge(names.reduce(saveStoreSync, []));
522 | }
523 |
524 | async.reduce(names, [], saveStore, function (err, objs) {
525 | return err ? callback(err) : callback(null, common.merge(objs));
526 | });
527 | };
528 |
529 | //
530 | // ### @private function _execute (action, syncLength, [arguments])
531 | // #### @action {string} Action to execute on `this.store`.
532 | // #### @syncLength {number} Function length of the sync version.
533 | // #### @arguments {Array} Arguments array to apply to the action
534 | // Executes the specified `action` on all stores for this instance, ensuring a callback supplied
535 | // to a synchronous store function is still invoked.
536 | //
537 | Provider.prototype._execute = function (action, syncLength /* [arguments] */) {
538 | var args = Array.prototype.slice.call(arguments, 2),
539 | callback = typeof args[args.length - 1] === 'function' && args.pop(),
540 | destructive = ['set', 'clear', 'merge', 'reset'].indexOf(action) !== -1,
541 | self = this,
542 | response,
543 | mergeObjs = [],
544 | keys = Object.keys(this.stores);
545 |
546 |
547 | function runAction (name, next) {
548 | var store = self.stores[name];
549 |
550 | if (destructive && store.readOnly) {
551 | return next();
552 | }
553 |
554 | return store[action].length > syncLength
555 | ? store[action].apply(store, args.concat(next))
556 | : next(null, store[action].apply(store, args));
557 | }
558 |
559 | if (callback) {
560 | return async.forEach(keys, runAction, function (err) {
561 | return err ? callback(err) : callback();
562 | });
563 | }
564 |
565 | keys.forEach(function (name) {
566 | if (typeof response === 'undefined') {
567 | var store = self.stores[name];
568 |
569 | if (destructive && store.readOnly) {
570 | return;
571 | }
572 |
573 | response = store[action].apply(store, args);
574 |
575 | // Merge objects if necessary
576 | if (response && action === 'get' && typeof response === 'object' && !Array.isArray(response)) {
577 | mergeObjs.push(response);
578 | response = undefined;
579 | }
580 | }
581 | });
582 |
583 | if (mergeObjs.length) {
584 | response = common.merge(mergeObjs.reverse());
585 | }
586 |
587 | return response;
588 | }
589 |
590 | //
591 | // Throw the `err` if a callback is not supplied
592 | //
593 | function onError(err, callback) {
594 | if (callback) {
595 | return callback(err);
596 | }
597 |
598 | throw err;
599 | }
600 |
--------------------------------------------------------------------------------