├── .gitignore ├── test ├── custom │ ├── foo.js │ └── index.js ├── dir │ ├── custom │ │ ├── bar.js │ │ └── index.js │ └── index.js ├── require-test.js └── method-test.js ├── muk.gif ├── .travis.yml ├── History.md ├── package.json ├── lib ├── index.js ├── require.js └── method.js ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | -------------------------------------------------------------------------------- /test/custom/foo.js: -------------------------------------------------------------------------------- 1 | module.exports = 'grimer'; 2 | -------------------------------------------------------------------------------- /test/dir/custom/bar.js: -------------------------------------------------------------------------------- 1 | module.exports = 'dustoff'; 2 | -------------------------------------------------------------------------------- /test/dir/custom/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require; 2 | -------------------------------------------------------------------------------- /muk.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fent/node-muk/HEAD/muk.gif -------------------------------------------------------------------------------- /test/custom/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function(path, callback) { 2 | // tests that the `require()` calls work asynchronously 3 | // without having to edit `require.cache` 4 | process.nextTick(function() { 5 | callback(null, require(path)); 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.12" 4 | - "1" 5 | - "2" 6 | - "3" 7 | - "4" 8 | - "6" 9 | notifications: 10 | email: 11 | on_success: change 12 | on_failure: change 13 | sudo: false 14 | after_success: 15 | - npm install -g codecov 16 | - codecov 17 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.5.1 / 2016-06-12 3 | ================== 4 | 5 | * fix: should check process.env 6 | * fix: can't redefine process.env when node<4 7 | 8 | 0.5.0 / 2016-06-11 9 | ================== 10 | 11 | * feat: add isMocked method to check if the member of the object is mocked 12 | 13 | 0.4.0 / 2015-09-17 14 | ================== 15 | 16 | * Support mocking accessor descriptor 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "muk", 3 | "description": "Mock object methods and dependencies.", 4 | "keywords": [ 5 | "test", 6 | "mock", 7 | "dependency" 8 | ], 9 | "version": "0.5.3", 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/fent/node-muk.git" 13 | }, 14 | "author": "fent (https://github.com/fent)", 15 | "main": "./lib/index.js", 16 | "scripts": { 17 | "test": "istanbul cover node_modules/.bin/_mocha -- -R spec test/*-test.js" 18 | }, 19 | "directories": { 20 | "lib": "./lib" 21 | }, 22 | "devDependencies": { 23 | "mocha": "*", 24 | "istanbul": "0" 25 | }, 26 | "license": "MIT", 27 | "files": [ 28 | "lib" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /test/dir/index.js: -------------------------------------------------------------------------------- 1 | var muk = require('../..'); 2 | var assert = require('assert'); 3 | 4 | 5 | module.exports = function testMockDependency(dir, filename) { 6 | var original; 7 | 8 | it('Original loads without mock', function() { 9 | original = require(dir)(filename); 10 | }); 11 | 12 | it('Correctly mocks dependency', function() { 13 | var deps = {}; 14 | var mock = deps[filename] = { existsSync: function() { return true; } }; 15 | 16 | var result = muk(dir, deps)(filename); 17 | assert.equal(result, mock, 'returned module is mocked object'); 18 | }); 19 | 20 | it('Original module is restored when require() is called', function() { 21 | delete require.cache[require.resolve(dir)]; 22 | 23 | var result = require(dir)(filename); 24 | assert.equal(result, original, 25 | 'requiring module again returns orignal module'); 26 | }); 27 | }; 28 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var mockMethod = require('./method'); 4 | var mockRequire = require('./require'); 5 | 6 | 7 | /** 8 | * Mocks a member of an object. 9 | * 10 | * @param {Object|string} obj 11 | * @param {!string|Object} key 12 | * @param {!Function} method 13 | */ 14 | var muk = module.exports = function mock(obj, key, method) { 15 | if (typeof obj === 'string') { 16 | return mockRequire(obj, key, module.parent); 17 | } else { 18 | mockMethod(obj, key, method); 19 | } 20 | }; 21 | 22 | /** 23 | * check whether the member of the object is mocked 24 | */ 25 | muk.isMocked = mockMethod.isMocked; 26 | 27 | /** 28 | * Restore all mocks 29 | */ 30 | muk.restore = mockMethod.restore; 31 | 32 | // delete this module from the cache so that the next time it gets 33 | // require()'d it will be aware of the new parent 34 | // in case it gets require()'d from a different directory 35 | delete require.cache[require.resolve(__filename)]; 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2012 by fent 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 | -------------------------------------------------------------------------------- /lib/require.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Module = require('module'); 4 | var path = require('path'); 5 | 6 | 7 | /** 8 | * Mocks a call to `require()` 9 | * 10 | * @param {string} filename 11 | * @param {Object} deps 12 | * @param {Object} parent 13 | */ 14 | module.exports = function mockRequire(filename, deps, parent) { 15 | filename = Module._resolveFilename(filename, parent); 16 | var m = require.cache[filename] = new Module(filename, parent); 17 | m.filename = filename; 18 | m.paths = Module._nodeModulePaths(path.dirname(filename)); 19 | 20 | // load children 21 | var children = {}; 22 | Object.keys(deps).forEach(function(key) { 23 | var childpath = Module._resolveFilename(key, m); 24 | var child = children[childpath] = new Module(childpath, m); 25 | child.filename = path; 26 | child.paths = Module._nodeModulePaths(path.dirname(childpath)); 27 | child.loaded = true; 28 | child.exports = deps[key]; 29 | }); 30 | 31 | m.require = function(path) { 32 | var childpath = Module._resolveFilename(path, m); 33 | var child = children[childpath]; 34 | if (child) { 35 | return child.exports; 36 | } else { 37 | return Module._load(path, m); 38 | } 39 | }; 40 | 41 | // load module 42 | m.load(filename); 43 | 44 | // delete module from cache so it can be required normally 45 | delete require.cache[filename]; 46 | 47 | return m.exports; 48 | }; 49 | -------------------------------------------------------------------------------- /test/require-test.js: -------------------------------------------------------------------------------- 1 | var muk = require('..'); 2 | var assert = require('assert'); 3 | 4 | 5 | function testMockDependency(dir, filename) { 6 | var deps = {}; 7 | var mock = deps[filename] = { existsSync: function() { return true; } }; 8 | var original; 9 | 10 | it('Original loads without mock', function(done) { 11 | require(dir)(filename, function(err, result) { 12 | original = result; 13 | done(); 14 | }); 15 | }); 16 | 17 | it('Correctly mocks dependency', function(done) { 18 | muk(dir, deps)(filename, function(err, result) { 19 | assert.equal(result, mock, 'returned module is mocked object'); 20 | done(); 21 | }); 22 | }); 23 | 24 | it('Correctly requires non-mocked dependency', function(done) { 25 | muk(dir, deps)('assert', function(err, result) { 26 | assert.equal(assert, result, 27 | 'returned module is the same one used in these tests'); 28 | done(); 29 | }); 30 | }); 31 | 32 | it('Original module is restored when require() is called', function(done) { 33 | delete require.cache[require.resolve(dir)]; 34 | 35 | require(dir)(filename, function(err, result) { 36 | assert.equal(result, original, 37 | 'requiring module again returns orignal module'); 38 | done(); 39 | }); 40 | }); 41 | } 42 | 43 | 44 | describe('Mock required user land dependency', function() { 45 | testMockDependency('./custom', 'mocha'); 46 | }); 47 | 48 | describe('Mock require native module', function() { 49 | testMockDependency('./custom', 'fs'); 50 | }); 51 | 52 | describe('Mock required relative file', function() { 53 | testMockDependency('./custom', './foo'); 54 | }); 55 | 56 | describe('Mock required relative file in a different dir', function() { 57 | require('./dir')('./custom', './bar'); 58 | }); 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # muk 2 | 3 | ### * Abandoned * 4 | Abandoned in favor of splitting up the functionality into 5 | * [muk-prop](https://github.com/fent/muk-prop.js) - Mock object methods and properties 6 | * [muk-require](https://github.com/fent/node-muk-require) - Mock dependencies 7 | 8 | [![Build Status](https://secure.travis-ci.org/fent/node-muk.svg)](http://travis-ci.org/fent/node-muk) 9 | [![Dependency Status](https://gemnasium.com/fent/node-muk.svg)](https://gemnasium.com/fent/node-muk) 10 | [![codecov](https://codecov.io/gh/fent/node-muk/branch/master/graph/badge.svg)](https://codecov.io/gh/fent/node-muk) 11 | 12 | ![muk](muk.gif) 13 | 14 | # Usage 15 | 16 | Mock dependencies. 17 | 18 | **foo.js** 19 | ```js 20 | var request = require('request'); 21 | 22 | module.exports = function foo(url) { 23 | // do something with request 24 | }; 25 | ``` 26 | 27 | **test.js** 28 | ```js 29 | var mockedRequest = function(url, options, callback) { 30 | // mock a request here 31 | }; 32 | 33 | var foo = muk('./foo', { 34 | request: mockedRequest 35 | }); 36 | ``` 37 | 38 | You can also mock modules required with a relative path. 39 | 40 | **some/where/else/foo.js** 41 | ```js 42 | var bar = require('./bar'); 43 | 44 | module.exports = function() { 45 | // do something with bar 46 | }; 47 | ``` 48 | 49 | **some/where/else/bar.js** 50 | ```js 51 | exports.attack = 'sludge attack!'; 52 | ``` 53 | 54 | **test.js** 55 | ```js 56 | var foo = muk('./some/where/else/foo', { './bar': 'hey!!' }); 57 | ``` 58 | 59 | Comes with object method mocking too. 60 | 61 | ```js 62 | var fs = require('fs'); 63 | var muk = require('muk'); 64 | 65 | muk(fs, 'readFile', function(path, callback) { 66 | process.nextTick(callback.bind(null, null, 'file contents here')); 67 | }); 68 | ``` 69 | 70 | Check if member has been mocked. 71 | 72 | ```js 73 | muk.isMocked(fs, 'readFile'); // true 74 | ``` 75 | 76 | Restore all mocked methods after tests. 77 | 78 | ```js 79 | muk.restore(); 80 | 81 | fs.readFile(file, function(err, data) { 82 | // will actually read from `file` 83 | }); 84 | ``` 85 | 86 | 87 | # Install 88 | 89 | npm install muk 90 | 91 | 92 | # Tests 93 | Tests are written with [mocha](http://visionmedia.github.com/mocha/) 94 | 95 | ```bash 96 | npm test 97 | ``` 98 | 99 | # License 100 | MIT 101 | -------------------------------------------------------------------------------- /lib/method.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // keep track of mocks 4 | var mocks = []; 5 | var cache = new Map(); 6 | 7 | 8 | /** 9 | * Mocks a method of an object. 10 | * 11 | * @param {Object} obj 12 | * @param {string} key 13 | * @param {!Function} method 14 | */ 15 | var method = module.exports = function mockMethod(obj, key, method) { 16 | method = method === undefined ? function() {} : method; 17 | var hasOwnProperty = obj.hasOwnProperty(key); 18 | mocks.push({ 19 | obj: obj, 20 | key: key, 21 | descriptor: Object.getOwnPropertyDescriptor(obj, key), 22 | // Make sure the key exists on object not the prototype 23 | hasOwnProperty: hasOwnProperty 24 | }); 25 | 26 | // delete the origin key, redefine it below 27 | if (hasOwnProperty) { 28 | delete obj[key]; 29 | } 30 | 31 | // set a flag that checks if it is mocked 32 | var flag = cache.get(obj); 33 | if (!flag) { 34 | flag = new Set(); 35 | cache.set(obj, flag); 36 | } 37 | flag.add(key); 38 | 39 | // Can't not delete the property of process.env before node@4 40 | if (obj === process.env) { 41 | obj[key] = method; 42 | return; 43 | } 44 | 45 | Object.defineProperty(obj, key, { 46 | writable: true, 47 | configurable: true, 48 | enumerable: true, 49 | value: method 50 | }); 51 | 52 | }; 53 | 54 | /** 55 | * Restore all mocks 56 | */ 57 | method.restore = function restoreMocks() { 58 | for (var i = mocks.length - 1; i >= 0; i--) { 59 | var m = mocks[i]; 60 | if (!m.hasOwnProperty) { 61 | // delete the mock key, use key on the prototype 62 | delete m.obj[m.key]; 63 | } else { 64 | // can't redefine process.env when node<4 65 | // https://github.com/nodejs/node/pull/2999 66 | if (m.obj === process.env) { 67 | m.obj[m.key] = m.descriptor.value; 68 | } else { 69 | // redefine the origin key instead of the mock key 70 | Object.defineProperty(m.obj, m.key, m.descriptor); 71 | } 72 | } 73 | } 74 | mocks = []; 75 | cache.clear(); 76 | 77 | /* 78 | requireMocks.forEach(function(m) { 79 | if (m.existed) { 80 | require.cache[m.filename].exports = m.original; 81 | } else { 82 | delete require.cache[m.filename]; 83 | } 84 | }); 85 | requireMocks = []; 86 | */ 87 | }; 88 | 89 | method.isMocked = function isMocked(obj, key) { 90 | var flag = cache.get(obj); 91 | return flag ? flag.has(key) : false; 92 | } 93 | -------------------------------------------------------------------------------- /test/method-test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var muk = require('..'); 4 | var assert = require('assert'); 5 | var fs = require('fs'); 6 | 7 | 8 | describe('Mock methods', function() { 9 | var readFile = fs.readFile; 10 | var mkdir = fs.mkdir; 11 | 12 | afterEach(muk.restore); 13 | 14 | it('Contains original methods', function() { 15 | assert.equal(typeof fs.readFile, 'function', 16 | 'fs.readFile is function'); 17 | assert.equal(typeof fs.readFileSync, 'function', 18 | 'fs.readFileSync is function'); 19 | }); 20 | 21 | it('Methods are new objects after mocked', function() { 22 | var readFileMock = function(path, callback) { 23 | process.nextTick(callback.bind(null, null, 'hello!')); 24 | }; 25 | 26 | var mkdirMock = function(path, callback) { 27 | process.nextTick(callback.bind(null, null)); 28 | }; 29 | 30 | muk(fs, 'readFile', readFileMock); 31 | muk(fs, 'mkdir', mkdirMock); 32 | assert.equal(fs.readFile, readFileMock, 'object method is equal to mock'); 33 | assert.equal(fs.mkdir, mkdirMock, 'object method is equal to mock'); 34 | }); 35 | 36 | it('No errors calling new mocked methods', function(done) { 37 | var readFileMock = function(path, callback) { 38 | process.nextTick(callback.bind(null, null, 'hello!')); 39 | }; 40 | muk(fs, 'readFile', readFileMock); 41 | 42 | fs.readFile('grimer', function(err, data) { 43 | if (err) return done(err); 44 | 45 | assert.equal(data, 'hello!', 'data matches'); 46 | done(); 47 | }); 48 | }); 49 | 50 | it('Should have original methods after muk.restore()', function() { 51 | muk.restore(); 52 | assert.equal(fs.readFile, readFile, 'original method is restored'); 53 | assert.equal(fs.mkdir, mkdir, 'original method is restored'); 54 | 55 | var readFileMock = function(path, callback) { 56 | process.nextTick(callback.bind(null, null, 'hello!')); 57 | }; 58 | muk(fs, 'readFile', readFileMock); 59 | muk(fs, 'readFile', readFileMock); 60 | muk.restore(); 61 | assert.equal(fs.readFile, readFile, 'mock twices, original method should be restored too'); 62 | }); 63 | 64 | it('should mock method on prototype', function() { 65 | var readFile = fs.readFile; 66 | var newFs = Object.create(fs); 67 | var readFileMock = function(path, callback) { 68 | process.nextTick(callback.bind(null, null, 'hello!')); 69 | }; 70 | muk(newFs, 'readFile', readFileMock); 71 | assert.equal(newFs.readFile, readFileMock, 'object method is equal to mock'); 72 | 73 | muk.restore(); 74 | assert.equal(newFs.readFile, readFile, 'object method is equal to origin'); 75 | }); 76 | }); 77 | 78 | describe('Mock property', function () { 79 | var config = { 80 | enableCache: true, 81 | delay: 10 82 | }; 83 | var home = process.env.HOME; 84 | 85 | afterEach(muk.restore); 86 | 87 | it('Contains original property', function () { 88 | assert.equal(config.enableCache, true, 'enableCache is true'); 89 | assert.equal(config.delay, 10, 'delay is 10'); 90 | }); 91 | 92 | it('Property are new after mocked', function () { 93 | muk(config, 'enableCache', false); 94 | muk(config, 'delay', 0); 95 | muk(process.env, 'HOME', '/mockhome'); 96 | 97 | assert.equal(config.enableCache, false, 'enableCache is false'); 98 | assert.equal(config.delay, 0, 'delay is 0'); 99 | assert.equal(process.env.HOME, '/mockhome', 'process.env.HOME is /mockhome'); 100 | }); 101 | 102 | it('Should have original properties after muk.restore()', function () { 103 | muk(config, 'enableCache', false); 104 | muk(config, 'enableCache', false); 105 | muk(config, 'delay', 0); 106 | muk(process.env, 'HOME', '/mockhome'); 107 | muk(config, 'notExistProp', 'value'); 108 | muk(process.env, 'notExistProp', 0); 109 | muk.restore(); 110 | 111 | assert.equal(config.enableCache, true, 'enableCache is true'); 112 | assert.equal(config.delay, 10, 'delay is 10'); 113 | assert.equal(process.env.HOME, home, 'process.env.HOME is ' + home); 114 | assert(!hasOwnProperty(config, 'notExistProp'), 'notExistProp is deleted'); 115 | assert(!hasOwnProperty(process.env, 'notExistProp'), 'notExistProp is deleted'); 116 | }); 117 | 118 | it('should mock function when method is null', function() { 119 | muk(config, 'enableCache'); 120 | assert.equal(typeof config.enableCache, 'function', 'enableCache is function'); 121 | assert.equal(config.enableCache(), undefined, 'enableCache return undefined'); 122 | }); 123 | 124 | it('should mock property on prototype', function() { 125 | var newConfig = Object.create(config); 126 | muk(newConfig, 'enableCache', false); 127 | assert.deepEqual(Object.keys(newConfig), ['enableCache'], 'obj should contain properties'); 128 | assert.equal(newConfig.enableCache, false, 'enableCache is false'); 129 | 130 | muk.restore(); 131 | assert.equal(newConfig.enableCache, true, 'enableCache is false'); 132 | }); 133 | }); 134 | 135 | describe('Mock getter', function() { 136 | var obj = { 137 | get a() { 138 | return 1; 139 | } 140 | }; 141 | 142 | afterEach(muk.restore); 143 | 144 | it('Contains original getter', function() { 145 | assert.equal(obj.a, 1, 'property a of obj is 1'); 146 | }); 147 | 148 | it('Methods are new getter after mocked', function() { 149 | muk(obj, 'a', 2); 150 | assert.equal(obj.a, 2, 'property a of obj is equal to mock'); 151 | }); 152 | 153 | it('Should have original getter after muk.restore()', function() { 154 | muk(obj, 'a', 2); 155 | muk.restore(); 156 | assert.equal(obj.a, 1, 'property a of obj is equal to origin'); 157 | }); 158 | 159 | it('should mock property on prototype', function() { 160 | var newObj = Object.create(obj); 161 | muk(newObj, 'a', 2); 162 | assert.deepEqual(Object.keys(newObj), ['a'], 'obj should contain properties'); 163 | assert.equal(newObj.a, 2, 'property a of obj is equal to mock'); 164 | 165 | muk.restore(); 166 | assert.equal(newObj.a, 1, 'property a of obj is equal to origin'); 167 | }); 168 | }); 169 | 170 | describe('Mock check', function() { 171 | 172 | afterEach(muk.restore); 173 | 174 | it('Should check whether is mocked', function() { 175 | var obj = { 176 | a: 1, 177 | }; 178 | assert.equal(muk.isMocked(obj, 'a'), false, 'obj should not be mocked'); 179 | 180 | muk(obj, 'a', 2); 181 | assert.ok(muk.isMocked(obj, 'a'), 'obj should be mocked'); 182 | }); 183 | 184 | it('Should not be enumerable', function() { 185 | var obj = { 186 | a: 1, 187 | }; 188 | muk(obj, 'a', 2); 189 | assert.deepEqual(Object.keys(obj), ['a']); 190 | 191 | var keys = []; 192 | for (var key in obj) { 193 | keys.push(key); 194 | } 195 | assert.deepEqual(keys, ['a']); 196 | }); 197 | 198 | it('Should be restored', function() { 199 | var obj = { 200 | a: 1, 201 | }; 202 | muk(obj, 'a', 2); 203 | assert.equal(muk.isMocked(obj, 'a'), true); 204 | muk.restore(); 205 | assert.equal(obj.a, 1); 206 | assert.equal(muk.isMocked(obj, 'a'), false); 207 | }); 208 | 209 | it('Should check different type', function() { 210 | var obj = { 211 | a: 1, 212 | b: '1', 213 | c: true, 214 | d: {}, 215 | get e() { 216 | return 1; 217 | }, 218 | }; 219 | muk(obj, 'a', 2); 220 | assert.ok(muk.isMocked(obj, 'a')); 221 | 222 | muk(obj, 'b', '2'); 223 | assert.ok(muk.isMocked(obj, 'b')); 224 | 225 | muk(obj, 'c', false); 226 | assert.ok(muk.isMocked(obj, 'c')); 227 | 228 | muk(obj, 'd', { d: 1 }); 229 | assert.ok(muk.isMocked(obj, 'd')); 230 | 231 | muk(obj, 'e', 2); 232 | assert.ok(muk.isMocked(obj, 'e')); 233 | }); 234 | 235 | it('should check process.env', function() { 236 | muk(process.env, 'HOME', '/mockhome'); 237 | assert.equal(process.env.HOME, '/mockhome'); 238 | assert.ok(muk.isMocked(process.env, 'HOME')); 239 | }); 240 | }); 241 | 242 | function hasOwnProperty(obj, prop) { 243 | return Object.prototype.hasOwnProperty.call(obj, prop); 244 | } 245 | --------------------------------------------------------------------------------