├── index.js ├── examples ├── external-json.json ├── external-json.js ├── simple.js ├── simple-array.js └── sails-local.js ├── .editorconfig ├── scripts └── test.sh ├── .travis.yml ├── package.json ├── .jshintrc ├── tests └── unit │ ├── examples-spec.js │ └── repository-spec.js ├── README.md ├── .gitignore ├── .npmignore ├── lib └── main.js ├── .jscsrc └── LICENSE.md /index.js: -------------------------------------------------------------------------------- 1 | // Simply export the main entry point in lib directory 2 | module.exports = require('./lib/main'); 3 | -------------------------------------------------------------------------------- /examples/external-json.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 80, 3 | "environment": "development", 4 | "db": { 5 | "host": "localhost", 6 | "user": "root", 7 | "password": "" 8 | }, 9 | "pm2": true 10 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*.js] 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | -------------------------------------------------------------------------------- /examples/external-json.js: -------------------------------------------------------------------------------- 1 | // load config from environment with default provided as an object 2 | var config = require('../index').load('envlift-app', require('./external-json.json')); 3 | 4 | // export the config for testability 5 | module.exports = config; 6 | -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e; 4 | 5 | echo "jscs v`jscs --version`"; 6 | jscs lib tests/unit; 7 | 8 | echo; 9 | 10 | jshint --version; 11 | jshint lib tests/unit; 12 | echo "No code lint issues found."; 13 | 14 | echo 15 | echo "Running unit tests..." 16 | echo "mocha v`mocha --version`"; 17 | 18 | mocha tests/unit/**/*-spec.js; 19 | -------------------------------------------------------------------------------- /examples/simple.js: -------------------------------------------------------------------------------- 1 | // load config from environment with default provided as an object 2 | var config = require('../index').load('envlift-app', { 3 | port: 80, 4 | environment: 'development', 5 | db: { 6 | host: 'localhost', 7 | user: 'root', 8 | password: '' 9 | } 10 | }); 11 | 12 | // export the config for testability 13 | module.exports = config; 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - '0.10' 5 | 6 | deploy: 7 | provider: npm 8 | email: help@getpostman.com 9 | api_key: 10 | secure: DLravddZPOY21EgEj9li1eWuJXpYGdRs3Xh3yNaujhn1dlAZtX1gK/3pbN6ib8BRIw21Ij8KEB51fgKEDMqsHVSPUD/0f8yEFR+GwiArPMXp9pZ0Momr1UP5EbLGL9SSZiZFQqT8kZspHn77jSOUkVFz2+rkvRkCDuwjwNgKfAc= 11 | on: 12 | tags: true 13 | repo: postmanlabs/env-lift 14 | branch: master 15 | -------------------------------------------------------------------------------- /examples/simple-array.js: -------------------------------------------------------------------------------- 1 | // load config from environment with default provided as an object 2 | var config = require('../index').load('envlift-app', { 3 | port: 80, 4 | environment: 'development', 5 | db: { 6 | host: 'localhost', 7 | user: 'root', 8 | password: '' 9 | }, 10 | hostnames: [ // Reference array that should be overridden by env-variables. 11 | {host: 'somehost', port: '8080'}, 12 | {host: 'someotherhost', port: '8080'} 13 | ] 14 | }); 15 | 16 | // export the config for testability 17 | module.exports = config; 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "env-lift", 3 | "version": "0.0.3", 4 | "description": "Simple namespaced environment variable configuration management solution", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/postmanlabs/env-lift.git" 9 | }, 10 | "keywords": [ 11 | "environment", 12 | "env", 13 | "process.env", 14 | "config", 15 | "configuration", 16 | "postman" 17 | ], 18 | "author": "Postman Labs ", 19 | "license": "Apache 2.0", 20 | "bugs": { 21 | "url": "https://github.com/postmanlabs/env-lift/issues" 22 | }, 23 | "homepage": "https://github.com/postmanlabs/env-lift", 24 | "devDependencies": { 25 | "expect.js": "^0.3.1", 26 | "jscs": "^3.0.7", 27 | "jshint": "^2.6.3", 28 | "mocha": "^3.0.2", 29 | "winston": "^3.13.0" 30 | }, 31 | "scripts": { 32 | "test": "scripts/test.sh" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": false, 3 | "camelcase": true, 4 | "curly": true, 5 | "eqeqeq": false, 6 | "es3": false, 7 | "forin": false, 8 | "freeze": true, 9 | "immed": true, 10 | "indent": 4, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "noempty": true, 15 | "nonew": false, 16 | "plusplus": false, 17 | "quotmark": "single", 18 | "undef": true, 19 | "unused": true, 20 | "trailing": true, 21 | "asi": false, 22 | "boss": true, 23 | "debug": false, 24 | "eqnull": true, 25 | "evil": false, 26 | "expr": true, 27 | "funcscope": false, 28 | "globalstrict": false, 29 | "iterator": false, 30 | "lastsemic": false, 31 | "laxbreak": false, 32 | "laxcomma": false, 33 | "loopfunc": false, 34 | "maxlen": 120, 35 | "multistr": false, 36 | "notypeof": false, 37 | "proto": false, 38 | "scripturl": false, 39 | "smarttabs": false, 40 | "shadow": false, 41 | "sub": false, 42 | "supernew": false, 43 | 44 | "browser": false, 45 | "devel": false, 46 | "node": true, 47 | 48 | "onevar": true, 49 | 50 | "globals": { 51 | "module": true, 52 | "process": true, 53 | "console": true, 54 | "require": true 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/unit/examples-spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileOverview This test specs runs tests on examples 3 | */ 4 | var expect = require('expect.js'); 5 | 6 | process.env.ENVLIFT_APP_PORT = '8081'; 7 | process.env.ENVLIFT_APP_ENVIRONMENT = 'production'; 8 | process.env.ENVLIFT_APP_DB_USER = 'toor'; 9 | process.env.ENVLIFT_APP_PM2 = 'false'; 10 | process.env.ENVLIFT_APP_HOSTNAMES_0_HOST = 'localhost'; 11 | process.env.ENVLIFT_APP_HOSTNAMES_0_PORT = '9191'; 12 | process.env.ENVLIFT_APP_HOSTNAMES_1_HOST = 'newhost'; 13 | process.env.ENVLIFT_APP_HOSTNAMES_1_PORT = '2222'; 14 | 15 | 16 | process.env.ENVLIFT_APP_MYSQL_HOST='postman' 17 | process.env.ENVLIFT_APP_MYSQL_PASSWORD='securepwd' 18 | process.env.ENVLIFT_APP_MYSQL_PORT=4321 19 | 20 | process.env.ENVLIFT_APP_FUNCTIONPROPERTY='shouldnotoverride' 21 | 22 | /* global describe, it */ 23 | describe('examples', function () { 24 | it('sails-local', function () { 25 | expect(require('../../examples/sails-local.js').port).to.be(8081); 26 | expect(typeof require('../../examples/sails-local.js').circularProperty).to.equal('object'); 27 | expect(typeof require('../../examples/sails-local.js').functionProperty).to.equal('function'); 28 | }); 29 | 30 | it('simple-config', function () { 31 | expect(require('../../examples/simple.js').environment).to.be('production'); 32 | }); 33 | 34 | it('external-json', function () { 35 | expect(require('../../examples/external-json.js').db.user).to.be('toor'); 36 | expect(require('../../examples/external-json.js').pm2).to.be(false); 37 | }); 38 | 39 | it('simple-array', function () { 40 | expect(require('../../examples/simple-array.js').hostnames).to.eql([{ 41 | host: 'localhost', 42 | port: 9191 43 | }, { 44 | host: 'newhost', 45 | port: 2222 46 | }]); 47 | }); 48 | 49 | it('same name sub-property as parent property', function () { 50 | expect(require('../../examples/sails-local.js').mySQL.host).to.be('postman'); 51 | expect(require('../../examples/sails-local.js').mySQL.port).to.be(4321); 52 | }); 53 | 54 | }); 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Master Build Status 2 | 3 | # env-lift 4 | 5 | *env-lift* provides a NodeJS module to easily read configurations from environment variables. The module makes it super 6 | easy to abstract configuration loading from environment in an organised and namespaced manner. 7 | 8 | 9 | ## Installing env-lift 10 | 11 | The easiest way to install env-lift is from the NPM registry. Switch to your project directory and run the following 12 | command. Once installation completes, refer to the usage guidelines or the examples directory to use it in your project. 13 | 14 | ```terminal 15 | npm install env-lift --save 16 | ``` 17 | 18 | ## Usage 19 | 20 | The best way to understand how to use this module is to refer to examples. A couple of them is located within the 21 | /examples directory and here we would elaborate on a few use cases. 22 | 23 | ### A simple use case where config is stored in an external JSON file 24 | 25 | In this use-case, let us assume that you are storing your config in a simple javascript variable. For your production 26 | server, you are possibly modifying the variables and running your application. In reality, the use-case could be that 27 | you are fetching the configuration from a separate JSON file. But for all practical purposes, the example here could be 28 | morphed to meet those scenarios. 29 | 30 | __Original Code:__ 31 | 32 | ```javascript 33 | var config = { 34 | port: 80, 35 | environment: 'development', 36 | db: { 37 | host: 'localhost', 38 | user: 'root', 39 | password: '' 40 | } 41 | }; 42 | ``` 43 | 44 | __Updated code using env-lift:__ 45 | 46 | ```javascript 47 | var config = require('env-lift').load('my-app', { 48 | port: 80, 49 | environment: 'development', 50 | db: { 51 | host: 'localhost', 52 | user: 'root', 53 | password: '' 54 | } 55 | }); 56 | ``` 57 | 58 | At this stage, if you can override the values of the configuration using environment variables. 59 | 60 | ```terminal 61 | export MY_APP_PORT=8080; 62 | export MY_APP_DB_HOST="example.com"; 63 | ``` 64 | 65 | Executing the above terminal exports before running your app would return port as 8080 and also return db host as 66 | _example.com_. 67 | 68 | ## Some gotchas 69 | 70 | - The keys are expected to be all uppercase alphanumeric. 71 | - The first letter of the environment variable cannot be a number. 72 | - If your key has non-alphanumeric characters, they are replaced by underscore character 73 | 74 | ## Contributing 75 | 76 | Contribution is accepted in form of Pull Requests that passes Travis CI tests. You should install this repository using 77 | `npm install -d` and run `npm test` locally before sending Pull Request. -------------------------------------------------------------------------------- /examples/sails-local.js: -------------------------------------------------------------------------------- 1 | winston = require('winston'); 2 | 3 | /** 4 | * @fileOverview This is a variation of a SailsJS local.js file that uses env-lift to provide configuration overrides 5 | * from environment variables. 6 | */ 7 | module.exports = require('../index').load('envlift-app', { 8 | 9 | // Your SSL certificate and key, if you want to be able to serve HTTP responses 10 | // over https:// and/or use websockets over the wss:// protocol 11 | // (recommended for HTTP, strongly encouraged for WebSockets) 12 | // 13 | // In this example, we'll assume you created a folder in your project, `config/ssl` 14 | // and dumped your certificate/key files there: 15 | // ssl: { 16 | // ca: require('fs').readFileSync(__dirname + './ssl/my_apps_ssl_gd_bundle.crt'), 17 | // key: require('fs').readFileSync(__dirname + './ssl/my_apps_ssl.key'), 18 | // cert: require('fs').readFileSync(__dirname + './ssl/my_apps_ssl.crt') 19 | // }, 20 | // ssl: { 21 | // key: require('fs').readFileSync(__dirname + '/ssl/sync_ssl.key'), 22 | // cert: require('fs').readFileSync(__dirname + '/ssl/sync_ssl.crt') 23 | // }, 24 | 25 | // The `port` setting determines which TCP port your app will be deployed on 26 | // Ports are a transport-layer concept designed to allow many different 27 | // networking applications run at the same time on a single computer. 28 | // More about ports: http://en.wikipedia.org/wiki/Port_(computer_networking) 29 | // 30 | // By default, if it's set, Sails uses the `PORT` environment variable. 31 | // Otherwise it falls back to port 1337. 32 | // 33 | // In production, you'll probably want to change this setting 34 | // to 80 (http://) or 443 (https://) if you have an SSL certificate 35 | 36 | port: 1337, 37 | 38 | // The runtime "environment" of your Sails app is either 'development' or 'production'. 39 | // 40 | // In development, your Sails app will go out of its way to help you 41 | // (for instance you will receive more descriptive error and debugging output)0 42 | // 43 | // In production, Sails configures itself (and its dependencies) to optimize performance. 44 | // You should always put your app in production mode before you deploy it to a server- 45 | // This helps ensure that your Sails app remains stable, performant, and scalable. 46 | // 47 | // By default, Sails sets its environment using the `NODE_ENV` environment variable. 48 | // If NODE_ENV is not set, Sails will run in the 'development' environment. 49 | 50 | environment: 'development', 51 | 52 | mySQL: { 53 | host: 'localhost', 54 | password: 'password', 55 | port: 1234, 56 | adapter: 'sails-mysql', 57 | database: 'test_database', 58 | user: 'god' 59 | }, 60 | 61 | connections: { 62 | mySQL: { 63 | adapter: 'sails-mysql', 64 | port: 2345, 65 | host: 'localhost', 66 | user: 'root', 67 | password: '', 68 | database: 'test_database' 69 | } 70 | }, 71 | 72 | models: { 73 | connection: 'mySQL', 74 | migrate: 'safe' 75 | }, 76 | 77 | log: { 78 | level: 'info' 79 | }, 80 | 81 | circularProperty: winston.createLogger({ 82 | format: winston.format.combine(winston.format.json()), 83 | transports: [new winston.transports.Console()] 84 | }), 85 | 86 | functionProperty: new Function() 87 | }); 88 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### JetBrains template 2 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 3 | 4 | *.iml 5 | 6 | ## Directory-based project format: 7 | .idea/ 8 | # if you remove the above rule, at least ignore the following: 9 | 10 | # User-specific stuff: 11 | # .idea/workspace.xml 12 | # .idea/tasks.xml 13 | # .idea/dictionaries 14 | 15 | # Sensitive or high-churn files: 16 | # .idea/dataSources.ids 17 | # .idea/dataSources.xml 18 | # .idea/sqlDataSources.xml 19 | # .idea/dynamic.xml 20 | # .idea/uiDesigner.xml 21 | 22 | # Gradle: 23 | # .idea/gradle.xml 24 | # .idea/libraries 25 | 26 | # Mongo Explorer plugin: 27 | # .idea/mongoSettings.xml 28 | 29 | ## File-based project format: 30 | *.ipr 31 | *.iws 32 | 33 | ## Plugin-specific files: 34 | 35 | # IntelliJ 36 | out/ 37 | 38 | # mpeltonen/sbt-idea plugin 39 | .idea_modules/ 40 | 41 | # JIRA plugin 42 | atlassian-ide-plugin.xml 43 | 44 | # Crashlytics plugin (for Android Studio and IntelliJ) 45 | com_crashlytics_export_strings.xml 46 | crashlytics.properties 47 | crashlytics-build.properties 48 | 49 | 50 | ### SublimeText template 51 | # cache files for sublime text 52 | *.tmlanguage.cache 53 | *.tmPreferences.cache 54 | *.stTheme.cache 55 | 56 | # workspace files are user-specific 57 | *.sublime-workspace 58 | 59 | # project files should be checked into the repository, unless a significant 60 | # proportion of contributors will probably not be using SublimeText 61 | # *.sublime-project 62 | 63 | # sftp configuration file 64 | sftp-config.json 65 | 66 | 67 | ### Windows template 68 | # Windows image file caches 69 | Thumbs.db 70 | ehthumbs.db 71 | 72 | # Folder config file 73 | Desktop.ini 74 | 75 | # Recycle Bin used on file shares 76 | $RECYCLE.BIN/ 77 | 78 | # Windows Installer files 79 | *.cab 80 | *.msi 81 | *.msm 82 | *.msp 83 | 84 | # Windows shortcuts 85 | *.lnk 86 | 87 | 88 | ### OSX template 89 | .DS_Store 90 | .AppleDouble 91 | .LSOverride 92 | 93 | # Icon must end with two \r 94 | Icon 95 | 96 | # Thumbnails 97 | ._* 98 | 99 | # Files that might appear in the root of a volume 100 | .DocumentRevisions-V100 101 | .fseventsd 102 | .Spotlight-V100 103 | .TemporaryItems 104 | .Trashes 105 | .VolumeIcon.icns 106 | 107 | # Directories potentially created on remote AFP share 108 | .AppleDB 109 | .AppleDesktop 110 | Network Trash Folder 111 | Temporary Items 112 | .apdisk 113 | 114 | 115 | ### Node template 116 | # Logs 117 | logs 118 | *.log 119 | 120 | # Runtime data 121 | pids 122 | *.pid 123 | *.seed 124 | 125 | # Directory for instrumented libs generated by jscoverage/JSCover 126 | lib-cov 127 | 128 | # Coverage directory used by tools like istanbul 129 | coverage 130 | 131 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 132 | .grunt 133 | 134 | # node-waf configuration 135 | .lock-wscript 136 | 137 | # Compiled binary addons (http://nodejs.org/api/addons.html) 138 | build/Release 139 | 140 | # Dependency directory 141 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 142 | node_modules 143 | 144 | ### Linux template 145 | *~ 146 | 147 | # KDE directory preferences 148 | .directory 149 | 150 | # Linux trash folder which might appear on any partition or disk 151 | .Trash-* 152 | 153 | 154 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | ### NPM Specific: Disregard recursive project files 2 | ### =============================================== 3 | /.jscsrc 4 | /.editorconfig 5 | /.gitmodules 6 | /.jshintrc 7 | /tests 8 | 9 | ### Borrowed from .gitignore 10 | ### ======================== 11 | 12 | ### JetBrains template 13 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 14 | 15 | *.iml 16 | 17 | ## Directory-based project format: 18 | .idea/ 19 | # if you remove the above rule, at least ignore the following: 20 | 21 | # User-specific stuff: 22 | # .idea/workspace.xml 23 | # .idea/tasks.xml 24 | # .idea/dictionaries 25 | 26 | # Sensitive or high-churn files: 27 | # .idea/dataSources.ids 28 | # .idea/dataSources.xml 29 | # .idea/sqlDataSources.xml 30 | # .idea/dynamic.xml 31 | # .idea/uiDesigner.xml 32 | 33 | # Gradle: 34 | # .idea/gradle.xml 35 | # .idea/libraries 36 | 37 | # Mongo Explorer plugin: 38 | # .idea/mongoSettings.xml 39 | 40 | ## File-based project format: 41 | *.ipr 42 | *.iws 43 | 44 | ## Plugin-specific files: 45 | 46 | # IntelliJ 47 | out/ 48 | 49 | # mpeltonen/sbt-idea plugin 50 | .idea_modules/ 51 | 52 | # JIRA plugin 53 | atlassian-ide-plugin.xml 54 | 55 | # Crashlytics plugin (for Android Studio and IntelliJ) 56 | com_crashlytics_export_strings.xml 57 | crashlytics.properties 58 | crashlytics-build.properties 59 | 60 | 61 | ### SublimeText template 62 | # cache files for sublime text 63 | *.tmlanguage.cache 64 | *.tmPreferences.cache 65 | *.stTheme.cache 66 | 67 | # workspace files are user-specific 68 | *.sublime-workspace 69 | 70 | # project files should be checked into the repository, unless a significant 71 | # proportion of contributors will probably not be using SublimeText 72 | # *.sublime-project 73 | 74 | # sftp configuration file 75 | sftp-config.json 76 | 77 | 78 | ### Windows template 79 | # Windows image file caches 80 | Thumbs.db 81 | ehthumbs.db 82 | 83 | # Folder config file 84 | Desktop.ini 85 | 86 | # Recycle Bin used on file shares 87 | $RECYCLE.BIN/ 88 | 89 | # Windows Installer files 90 | *.cab 91 | *.msi 92 | *.msm 93 | *.msp 94 | 95 | # Windows shortcuts 96 | *.lnk 97 | 98 | 99 | ### OSX template 100 | .DS_Store 101 | .AppleDouble 102 | .LSOverride 103 | 104 | # Icon must end with two \r 105 | Icon 106 | 107 | # Thumbnails 108 | ._* 109 | 110 | # Files that might appear in the root of a volume 111 | .DocumentRevisions-V100 112 | .fseventsd 113 | .Spotlight-V100 114 | .TemporaryItems 115 | .Trashes 116 | .VolumeIcon.icns 117 | 118 | # Directories potentially created on remote AFP share 119 | .AppleDB 120 | .AppleDesktop 121 | Network Trash Folder 122 | Temporary Items 123 | .apdisk 124 | 125 | 126 | ### Node template 127 | # Logs 128 | logs 129 | *.log 130 | 131 | # Runtime data 132 | pids 133 | *.pid 134 | *.seed 135 | 136 | # Directory for instrumented libs generated by jscoverage/JSCover 137 | lib-cov 138 | 139 | # Coverage directory used by tools like istanbul 140 | coverage 141 | 142 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 143 | .grunt 144 | 145 | # node-waf configuration 146 | .lock-wscript 147 | 148 | # Compiled binary addons (http://nodejs.org/api/addons.html) 149 | build/Release 150 | 151 | # Dependency directory 152 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 153 | node_modules 154 | 155 | ### Linux template 156 | *~ 157 | 158 | # KDE directory preferences 159 | .directory 160 | 161 | # Linux trash folder which might appear on any partition or disk 162 | .Trash-* 163 | 164 | 165 | -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | var E = '', 2 | TRUE = 'true', 3 | FALSE = 'false', 4 | NUMBER = 'number', 5 | OBJECT = 'object', 6 | /** 7 | * Default separator while retrieving values of multi-level keys. 8 | * @const 9 | * @type {string} 10 | */ 11 | DEFAULT_SEPARATOR = '_', // default separator value constant 12 | 13 | /** 14 | * Accepts a string and replaces all non alphabetic characters with default separator and converts characters to 15 | * uppercase. 16 | * 17 | * @param {object} key 18 | * @param {string=} [separator=} 19 | * @returns {string} 20 | */ 21 | rekey = function (key, separator) { 22 | return (typeof key === NUMBER) ? key : (key.toUpperCase().replace(/[^A-Z0-9]/g, separator || E)); 23 | }, 24 | 25 | /** 26 | * Stores the set of typecast functions to be applied when retrieving values from environment. 27 | * 28 | * @enum 29 | * @type {Object} 30 | */ 31 | typecasts = { 32 | 'string': String, 33 | 'number': Number, 34 | 'undefined': String, 35 | 'boolean': function (value) { 36 | value = (value && value.toString) ? value.toString().trim().toLowerCase() : value; 37 | 38 | if (!isNaN(value)) { 39 | return Number(value); 40 | } 41 | if (value === FALSE) { 42 | return false; 43 | } 44 | if (value === TRUE) { 45 | return true; 46 | } 47 | } 48 | }, 49 | 50 | // main function that parses objects 51 | lift; 52 | 53 | /** 54 | * Recursively traverses through objects and whenever native value types are encountered, replaces it with corresponding 55 | * data from environment variables. 56 | * 57 | * @param {object} obj 58 | * @param {string=} [namespace=] - Ensure that the namespace is pre-transformed. This improves performance. 59 | * @param {string=} [separator=_] 60 | * @param {function} transformer - The key name to pick data is forwarded as parameter and the value returned by the 61 | * transformer function is used to lookup environment variables. 62 | * @param {boolean} _debug 63 | * @param {Set} visitedObjects - Set to track already visited objects while recursive config loading, initially empty. 64 | */ 65 | lift = function (obj, namespace, separator, transformer, _debug, visitedObjects) { 66 | var allKeys, 67 | cast, 68 | eKey; 69 | 70 | // Do not load function values from environment config 71 | if (typeof obj === 'function') { 72 | return obj; 73 | } 74 | 75 | // Check if obj is already present in visitedObjects without using .has function 76 | for (let ob of visitedObjects) { 77 | if (ob === obj) { 78 | return obj; 79 | } 80 | } 81 | 82 | visitedObjects.add(obj); 83 | 84 | // iterate on each item in this object and operate on their keys. 85 | if (Array.isArray(obj)) { 86 | allKeys = Array.apply(null, { 87 | length: obj.length 88 | }).map(Number.call, Number); 89 | } 90 | else if (typeof obj === OBJECT) { 91 | allKeys = Object.keys(obj); 92 | } 93 | else { 94 | allKeys = []; // If this happens, the loop will be skipped completely 95 | } 96 | 97 | // iterate on each item in this object and operate on their keys. 98 | allKeys.forEach(function (key) { 99 | // only process keys that are owned by this object 100 | if (obj.hasOwnProperty && !obj.hasOwnProperty(key)) { 101 | return; 102 | } 103 | 104 | // determine the type of the value and extract the casting function. 105 | cast = typecasts[typeof obj[key]]; 106 | !cast && (obj[key] === null) && (cast = typecasts.undefined); // specially handle null 107 | 108 | // generate the equivalent environment key for the namespace 109 | eKey = (namespace || E) + separator + (transformer ? transformer(key, separator) : key); 110 | 111 | // debug log 112 | _debug && (process.env[eKey] !== undefined) && console.log('env-lift: %s=%s', eKey, process.env[eKey], 113 | cast ? ('[' + cast(process.env[eKey]) + ']') : E); 114 | 115 | // if a cast function is there, it implies that native value is detected and we need to lookup environment 116 | if (cast) { 117 | if (process.env[eKey] !== undefined) { 118 | // if environment has a defined variable, we replace the original value with this. 119 | obj[key] = cast(process.env[eKey]); 120 | } 121 | } 122 | // otherwise, we recurse into the value of the property 123 | else { 124 | lift(obj[key], eKey, separator, transformer, _debug, visitedObjects); 125 | } 126 | }); 127 | 128 | return obj; 129 | }; 130 | 131 | module.exports = /** @lends module:env-lift */ { 132 | /** 133 | * Replaces values in `reference` object with equivalent definition of environment variables prefixed with 134 | * `namespace` and object's key path. 135 | * 136 | * @note This function mutes the original reference object. 137 | * 138 | * @param {string} namespace 139 | * @param {object} reference 140 | * 141 | * @example 142 | * require('env-lift').load('test', { 143 | * port: 123, 144 | * name: 'Sample Text' 145 | * }); 146 | * 147 | * // if there is an environment variable TEST_PORT=8080 148 | * // The above would return: { 149 | * // port: 8080, 150 | * // name: 'Sample Text' 151 | * // } 152 | */ 153 | load: function (namespace, reference) { 154 | var debug = !!process.env.ENV_LIFT_DEBUG, 155 | nsKey = rekey(namespace || E, DEFAULT_SEPARATOR); 156 | 157 | debug && console.log('env-lift: debugging %s', nsKey); 158 | return lift(reference, nsKey, DEFAULT_SEPARATOR, rekey, debug, new Set()); 159 | } 160 | }; 161 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | // "disallowAnonymousFunctions": false, 3 | // "disallowCapitalizedComments": false, 4 | // "disallowCommaBeforeLineBreak": false, 5 | // "disallowDanglingUnderscores": true, 6 | "disallowEmptyBlocks": true, 7 | "disallowFunctionDeclarations": true, 8 | // "disallowImplicitTypeConversion": [], 9 | // "disallowKeywordsOnNewLine": [], 10 | "disallowKeywords": ["with"], 11 | "disallowMixedSpacesAndTabs": true, 12 | "disallowMultipleLineBreaks": true, 13 | "disallowMultipleLineStrings": true, 14 | // "disallowMultipleVarDecl": false, 15 | "disallowNewlineBeforeBlockStatements": true, 16 | // "disallowOperatorBeforeLineBreak": false, 17 | // "disallowPaddingNewlinesBeforeKeywords": false, 18 | "disallowPaddingNewlinesInBlocks": true, 19 | // "disallowPaddingNewLinesInObjects": false, 20 | // "disallowQuotedKeysInObjects": false, 21 | // "disallowSemicolons": false, 22 | // "disallowSpaceAfterBinaryOperators": false, 23 | // "disallowSpaceAfterKeywords": false, 24 | // "disallowSpaceAfterLineComment": false, 25 | // "disallowSpaceAfterObjectKeys": false, 26 | "disallowSpaceAfterPrefixUnaryOperators": true, 27 | // "disallowSpaceBeforeBinaryOperators": false, 28 | // "disallowSpaceBeforeBlockStatements": false, 29 | // "disallowSpaceBeforeKeywords": false, 30 | // "disallowSpaceBeforeObjectValues": false, 31 | "disallowSpaceBeforePostfixUnaryOperators": true, 32 | // "disallowSpaceBetweenArguments": false, 33 | // "disallowSpacesInAnonymousFunctionExpression": { 34 | // "beforeOpeningRoundBrace": false, 35 | // "beforeOpeningCurlyBrace": false 36 | // }, 37 | "disallowSpacesInCallExpression": true, 38 | // "disallowSpacesInConditionalExpression": { 39 | // "afterTest": false, 40 | // "beforeConsequent": false, 41 | // "afterConsequent": false, 42 | // "beforeAlternate": false 43 | // }, 44 | // "disallowSpacesInForStatement": false, 45 | // "disallowSpacesInFunctionDeclaration": { 46 | // "beforeOpeningRoundBrace": false, 47 | // "beforeOpeningCurlyBrace": false 48 | // }, 49 | // "disallowSpacesInFunctionExpression": { 50 | // "beforeOpeningRoundBrace": false, 51 | // "beforeOpeningCurlyBrace": false 52 | // }, 53 | // "disallowSpacesInFunctionExpression": { 54 | // "beforeOpeningRoundBrace": true, 55 | // "beforeOpeningCurlyBrace": true 56 | // }, 57 | // "disallowSpacesInNamedFunctionExpression": { 58 | // "beforeOpeningRoundBrace": false, 59 | // "beforeOpeningCurlyBrace": false 60 | // }, 61 | "disallowSpacesInsideArrayBrackets": "all", 62 | "disallowSpacesInsideObjectBrackets": "all", 63 | "disallowSpacesInsideParentheses": { "only": [ "{", "}" ] }, 64 | "disallowTrailingComma": true, 65 | "disallowTrailingWhitespace": true, 66 | // "disallowYodaConditions": false, 67 | "maximumLineLength": { 68 | "value": 120, 69 | "allowComments": false, 70 | "allowRegex": true 71 | }, 72 | 73 | // "requireAlignedObjectValues": false, 74 | // "requireAnonymousFunctions": false, 75 | "requireBlocksOnNewline": 2, 76 | "requireCamelCaseOrUpperCaseIdentifiers": true, 77 | // "requireCapitalizedComments": true, 78 | "requireCapitalizedConstructors": true, 79 | // "requireCommaBeforeLineBreak": false, 80 | "requireCurlyBraces": true, 81 | "requireDotNotation": "except_snake_case", 82 | // "requireFunctionDeclarations": false, 83 | "requireKeywordsOnNewLine": ["else", "catch", "case", "default", "finally"], 84 | "requireLineBreakAfterVariableAssignment": true, 85 | "requireLineFeedAtFileEnd": true, 86 | "requireMultipleVarDecl": "onevar", 87 | // "requireNewlineBeforeBlockStatements": false, 88 | "requireOperatorBeforeLineBreak": true, 89 | // "requirePaddingNewlinesBeforeKeywords": [], 90 | // "requirePaddingNewlinesInBlocks": false, 91 | // "requirePaddingNewlinesInBlocks": false, 92 | "requireParenthesesAroundIIFE": true, 93 | // "requireQuotedKeysInObjects": false, 94 | "requireSpaceAfterBinaryOperators": true, 95 | "requireSpaceAfterKeywords": true, 96 | "requireSpaceAfterLineComment": { 97 | "allExcept": ["!", "#", "%", "^", "*", "=", "?"] 98 | }, 99 | // "requireSpaceAfterObjectKeys": false, 100 | // "requireSpaceAfterPrefixUnaryOperators": false, 101 | "requireSpaceBeforeBinaryOperators": true, 102 | "requireSpaceBeforeBlockStatements": true, 103 | // "requireSpaceBeforeKeywords": false, 104 | "requireSpaceBeforeObjectValues": true, 105 | // "requireSpaceBeforePostfixUnaryOperators": false, 106 | "requireSpaceBetweenArguments": true, 107 | "requireSpacesInAnonymousFunctionExpression": { 108 | "beforeOpeningRoundBrace": true, 109 | "beforeOpeningCurlyBrace": true 110 | }, 111 | //"requireSpacesInCallExpression": false, 112 | "requireSpacesInConditionalExpression": { 113 | "afterTest": true, 114 | "beforeConsequent": true, 115 | "afterConsequent": true, 116 | "beforeAlternate": true 117 | }, 118 | "requireSpacesInForStatement": true, 119 | "requireSpacesInFunctionDeclaration": { 120 | "beforeOpeningRoundBrace": true, 121 | "beforeOpeningCurlyBrace": true 122 | }, 123 | "requireSpacesInFunctionExpression": { 124 | "beforeOpeningRoundBrace": true, 125 | "beforeOpeningCurlyBrace": true 126 | }, 127 | // "requireSpacesInNamedFunctionExpression": { 128 | // "beforeOpeningRoundBrace": true, 129 | // "beforeOpeningCurlyBrace": true 130 | // }, 131 | // "requireSpacesInsideArrayBrackets": false, 132 | "requireSpacesInsideObjectBrackets": "allButNested", 133 | // "requireSpacesInsideParentheses": false, 134 | // "requireTrailingComma": false, 135 | // "requireYodaConditions": false, 136 | // "safeContextKeyword": [ ], 137 | "validateIndentation": 4, 138 | "validateLineBreaks": "LF", 139 | "validateParameterSeparator": ", ", 140 | "validateQuoteMarks": "'" 141 | } 142 | -------------------------------------------------------------------------------- /tests/unit/repository-spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileOverview This test specs runs tests on the package.json file of repository. It has a set of strict tests on the 3 | * content of the file as well. Any change to package.json must be accompanied by valid test case in this spec-sheet. 4 | */ 5 | var expect = require('expect.js'); 6 | 7 | /* global describe, it */ 8 | describe('repository', function () { 9 | var fs = require('fs'); 10 | 11 | describe('package.json', function () { 12 | var content, 13 | json; 14 | 15 | it('must exist', function () { 16 | expect(fs.existsSync('./package.json')).to.be.ok(); 17 | }); 18 | 19 | it('must have readable content', function () { 20 | expect(content = fs.readFileSync('./package.json').toString()).to.be.ok(); 21 | }); 22 | 23 | it('content must be valid JSON', function () { 24 | expect(json = JSON.parse(content)).to.be.ok(); 25 | }); 26 | 27 | describe('package.json JSON data', function () { 28 | it('must have valid name, description and author', function () { 29 | expect(json.name).to.equal('env-lift'); 30 | expect(json.description) 31 | .to.equal('Simple namespaced environment variable configuration management solution'); 32 | expect(json.author).to.equal('Postman Labs '); 33 | expect(json.license).to.equal('Apache 2.0'); 34 | }); 35 | 36 | it('must have a valid version string in form of ..', function () { 37 | /* jshint ignore:start */ 38 | expect(json.version).to.match(/^((\d+)\.(\d+)\.(\d+))(?:-([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?(?:\+([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?$/); 39 | /* jshint ignore:end */ 40 | }); 41 | }); 42 | 43 | describe('script definitions', function () { 44 | var props = {}; 45 | 46 | it('files must exist', function () { 47 | var prop, 48 | propBase; 49 | 50 | expect(json.scripts).to.be.ok(); 51 | 52 | for (prop in json.scripts) { 53 | props[prop] = { 54 | base: (propBase = prop.substr(0, prop.indexOf('-') > -1 ? 55 | prop.indexOf('-') : undefined)), 56 | path: 'scripts/' + propBase + '.sh' 57 | }; 58 | expect(fs.existsSync(props[prop].path)).to.be.ok(); 59 | } 60 | }); 61 | 62 | it('must be defined as per standards `[script]: scripts/[name].sh`', function () { 63 | for (var prop in json.scripts) { 64 | expect(json.scripts[prop]).to.match(new RegExp(props[prop].path, 'g')); 65 | } 66 | }); 67 | 68 | it('must have the hashbang defined', function () { 69 | var fileContent, 70 | prop; 71 | 72 | for (prop in json.scripts) { 73 | fileContent = fs.readFileSync(props[prop].path).toString(); 74 | expect(/^#!\/(bin\/bash|usr\/bin\/env\s(node|bash))[\r\n][\W\w]*$/g.test(fileContent)).to.be.ok(); 75 | } 76 | }); 77 | }); 78 | 79 | describe('devDependencies', function () { 80 | it('must exist', function () { 81 | expect(json.devDependencies).to.be.a('object'); 82 | }); 83 | 84 | it('must have specified version for dependencies ', function () { 85 | for (var item in json.devDependencies) { 86 | expect(json.devDependencies[item]).to.be.ok(); 87 | } 88 | }); 89 | 90 | it('must point to specific package version; (*) not expected', function () { 91 | for (var item in json.devDependencies) { 92 | expect(json.devDependencies[item]).not.to.equal('*'); 93 | } 94 | }); 95 | }); 96 | 97 | describe('main entry script', function () { 98 | it('must point to a valid file', function () { 99 | expect(json.main).to.equal('index.js'); 100 | expect(fs.existsSync(json.main)).to.be.ok(); 101 | }); 102 | }); 103 | }); 104 | 105 | describe('README.md', function () { 106 | it('must exist', function () { 107 | expect(fs.existsSync('./README.md')).to.be.ok(); 108 | }); 109 | 110 | it('must have readable content', function () { 111 | expect(fs.readFileSync('./README.md').toString()).to.be.ok(); 112 | }); 113 | }); 114 | 115 | describe('LICENSE.md', function () { 116 | it('must exist', function () { 117 | expect(fs.existsSync('./LICENSE.md')).to.be.ok(); 118 | }); 119 | 120 | it('must have readable content', function () { 121 | expect(fs.readFileSync('./LICENSE.md').toString()).to.be.ok(); 122 | }); 123 | }); 124 | 125 | describe('.gitignore file', function () { 126 | it('must exist', function () { 127 | expect(fs.existsSync('./.gitignore')).to.be.ok(); 128 | }); 129 | 130 | it('must have readable content', function () { 131 | expect(fs.readFileSync('./.gitignore').toString()).to.be.ok(); 132 | }); 133 | }); 134 | 135 | describe('.npmignore file', function () { 136 | it('must exist', function () { 137 | expect(fs.existsSync('./.npmignore')).to.be.ok(); 138 | }); 139 | 140 | it('must be a superset of .gitignore (.npmi = .npmi + .gi)', function () { 141 | // normalise the ignore file text contents 142 | var gi = fs.readFileSync('./.gitignore').toString().replace(/#.*\n/g, '\n').replace(/\n+/g, '\n'), 143 | npmi = fs.readFileSync('./.npmignore').toString().replace(/#.*\n/g, '\n').replace(/\n+/g, '\n'); 144 | 145 | expect(npmi.substr(-gi.length)).to.eql(gi); 146 | }); 147 | }); 148 | }); 149 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2015 Postdot Technologies Pvt. Ltd. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | --------------------------------------------------------------------------------