├── .gitignore ├── package.json ├── profile ├── cmyk-adobe-coated-fogra27.icc ├── cmyk-adobe-coated-fogra39.icc ├── cmyk-adobe-coated-gracol2006.icc ├── cmyk-adobe-japan-200-newspaper.icc ├── cmyk-adobe-japan-2001-coated.icc ├── cmyk-adobe-japan-2001-uncoated.icc ├── cmyk-adobe-japan-2003-web-coated.icc ├── cmyk-adobe-japan-web-coated.icc ├── cmyk-adobe-uncoated-fogra29.icc ├── cmyk-adobe-us-web-coated-swop.icc ├── cmyk-adobe-us-web-uncoated.icc ├── cmyk-adobe-web-coated-fogra28.icc ├── cmyk-adobe-web-coated-swop-2006-g3.icc ├── cmyk-adobe-web-coated-swop-2006-g5.icc ├── cmyk-eci-iso-coated-v2-300.icc ├── cmyk-eci-iso-coated-v2-eci.icc ├── cmyk-eci-iso-uncoated-yellowish.icc ├── cmyk-eci-pso-coated-300-npscreen-iso12647.icc ├── cmyk-eci-pso-coated-npscreen-iso12647.icc ├── cmyk-eci-pso-lwc-improved.icc ├── cmyk-eci-pso-lwc-standard.icc ├── cmyk-eci-pso-mfc-paper.icc ├── cmyk-eci-pso-snp-paper.icc ├── cmyk-eci-pso-uncoated-iso12647.icc ├── cmyk-eci-pso-uncoated-npscreen-iso12647.icc ├── cmyk-eci-sc-paper.icc ├── lab-apple.icc ├── rgb-adobe-1998.icc ├── rgb-apple.icc ├── rgb-colormatch.icc ├── rgb-pal-secam.icc ├── rgb-smpte-c.icc ├── rgb-video-hd.icc ├── rgb-video-ntsc.icc ├── rgb-video-pal.icc ├── srgb-apple.icc ├── xyz-d50.icc ├── xyz-d55.icc └── xyz-d65.icc ├── readme.md ├── shell ├── 3.sh └── 4.sh ├── test └── transicc.js └── transicc.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "transicc", 3 | "version": "1.2.1", 4 | "description": "A nodejs wrapper for LittleCMSs transicc command line utility. Easily perform true ICC Profile-based color conversions from inside node.", 5 | "main": "transicc.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/jpederson/node-transicc.git" 9 | }, 10 | "scripts": { 11 | "test": "node_modules/.bin/mocha -w" 12 | }, 13 | "keywords": [ 14 | "color", 15 | "conversion", 16 | "ICC", 17 | "ICC profiles", 18 | "node", 19 | "LittleCMS", 20 | "transicc" 21 | ], 22 | "author": "James Pederson", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/jpederson/node-transicc/issues" 26 | }, 27 | "homepage": "https://github.com/jpederson/node-transicc", 28 | "dependencies": {}, 29 | "devDependencies": { 30 | "mocha": "*", 31 | "should": "*" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /profile/cmyk-adobe-coated-fogra27.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-adobe-coated-fogra27.icc -------------------------------------------------------------------------------- /profile/cmyk-adobe-coated-fogra39.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-adobe-coated-fogra39.icc -------------------------------------------------------------------------------- /profile/cmyk-adobe-coated-gracol2006.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-adobe-coated-gracol2006.icc -------------------------------------------------------------------------------- /profile/cmyk-adobe-japan-200-newspaper.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-adobe-japan-200-newspaper.icc -------------------------------------------------------------------------------- /profile/cmyk-adobe-japan-2001-coated.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-adobe-japan-2001-coated.icc -------------------------------------------------------------------------------- /profile/cmyk-adobe-japan-2001-uncoated.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-adobe-japan-2001-uncoated.icc -------------------------------------------------------------------------------- /profile/cmyk-adobe-japan-2003-web-coated.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-adobe-japan-2003-web-coated.icc -------------------------------------------------------------------------------- /profile/cmyk-adobe-japan-web-coated.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-adobe-japan-web-coated.icc -------------------------------------------------------------------------------- /profile/cmyk-adobe-uncoated-fogra29.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-adobe-uncoated-fogra29.icc -------------------------------------------------------------------------------- /profile/cmyk-adobe-us-web-coated-swop.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-adobe-us-web-coated-swop.icc -------------------------------------------------------------------------------- /profile/cmyk-adobe-us-web-uncoated.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-adobe-us-web-uncoated.icc -------------------------------------------------------------------------------- /profile/cmyk-adobe-web-coated-fogra28.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-adobe-web-coated-fogra28.icc -------------------------------------------------------------------------------- /profile/cmyk-adobe-web-coated-swop-2006-g3.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-adobe-web-coated-swop-2006-g3.icc -------------------------------------------------------------------------------- /profile/cmyk-adobe-web-coated-swop-2006-g5.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-adobe-web-coated-swop-2006-g5.icc -------------------------------------------------------------------------------- /profile/cmyk-eci-iso-coated-v2-300.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-eci-iso-coated-v2-300.icc -------------------------------------------------------------------------------- /profile/cmyk-eci-iso-coated-v2-eci.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-eci-iso-coated-v2-eci.icc -------------------------------------------------------------------------------- /profile/cmyk-eci-iso-uncoated-yellowish.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-eci-iso-uncoated-yellowish.icc -------------------------------------------------------------------------------- /profile/cmyk-eci-pso-coated-300-npscreen-iso12647.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-eci-pso-coated-300-npscreen-iso12647.icc -------------------------------------------------------------------------------- /profile/cmyk-eci-pso-coated-npscreen-iso12647.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-eci-pso-coated-npscreen-iso12647.icc -------------------------------------------------------------------------------- /profile/cmyk-eci-pso-lwc-improved.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-eci-pso-lwc-improved.icc -------------------------------------------------------------------------------- /profile/cmyk-eci-pso-lwc-standard.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-eci-pso-lwc-standard.icc -------------------------------------------------------------------------------- /profile/cmyk-eci-pso-mfc-paper.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-eci-pso-mfc-paper.icc -------------------------------------------------------------------------------- /profile/cmyk-eci-pso-snp-paper.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-eci-pso-snp-paper.icc -------------------------------------------------------------------------------- /profile/cmyk-eci-pso-uncoated-iso12647.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-eci-pso-uncoated-iso12647.icc -------------------------------------------------------------------------------- /profile/cmyk-eci-pso-uncoated-npscreen-iso12647.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-eci-pso-uncoated-npscreen-iso12647.icc -------------------------------------------------------------------------------- /profile/cmyk-eci-sc-paper.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/cmyk-eci-sc-paper.icc -------------------------------------------------------------------------------- /profile/lab-apple.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/lab-apple.icc -------------------------------------------------------------------------------- /profile/rgb-adobe-1998.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/rgb-adobe-1998.icc -------------------------------------------------------------------------------- /profile/rgb-apple.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/rgb-apple.icc -------------------------------------------------------------------------------- /profile/rgb-colormatch.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/rgb-colormatch.icc -------------------------------------------------------------------------------- /profile/rgb-pal-secam.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/rgb-pal-secam.icc -------------------------------------------------------------------------------- /profile/rgb-smpte-c.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/rgb-smpte-c.icc -------------------------------------------------------------------------------- /profile/rgb-video-hd.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/rgb-video-hd.icc -------------------------------------------------------------------------------- /profile/rgb-video-ntsc.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/rgb-video-ntsc.icc -------------------------------------------------------------------------------- /profile/rgb-video-pal.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/rgb-video-pal.icc -------------------------------------------------------------------------------- /profile/srgb-apple.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/srgb-apple.icc -------------------------------------------------------------------------------- /profile/xyz-d50.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/xyz-d50.icc -------------------------------------------------------------------------------- /profile/xyz-d55.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/xyz-d55.icc -------------------------------------------------------------------------------- /profile/xyz-d65.icc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpederson/node-transicc/3e0ab82e9acf6cceadad8ccbf49bca0cc2f3fd99/profile/xyz-d65.icc -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## node-transicc 2 | 3 | A simple nodejs module that wraps the LittleCMS transicc command line utility, to allow you to make true ICC Profile-based color conversions inside your node apps. The goal of this project is to enable accurate color conversions, like those achieved in most image editing programs - unlike pure math-based conversions (which fail in situations like using CMYK). 4 | 5 | ***** 6 | 7 | ![GitHub release](https://img.shields.io/github/release/jpederson/node-transicc.svg?label=github) ![npm](https://img.shields.io/npm/v/transicc.svg) 8 | 9 | ***** 10 | 11 | ### Installation 12 | 13 | First, install [LittleCMS](https://github.com/mm2/Little-CMS) using the commands below on Unix/Linux/OSX (binaries available for other OSs). It's a small, open source C-based color management system - transicc uses a LittleCMS command line utility by the same name to perform the actual profile comparisons. 14 | 15 | ```shell 16 | git clone https://github.com/mm2/Little-CMS.git 17 | cd Little-CMS 18 | ./configure 19 | make 20 | make check 21 | sudo make install 22 | ``` 23 | 24 | Next, you're ready to install the node module... 25 | 26 | ```shell 27 | npm install transicc --save 28 | ``` 29 | 30 | ... and start converting colors! 31 | 32 | ```js 33 | var transicc = require( "transicc" ); 34 | 35 | transicc( "cmyk", "rgb", [ 100, 0, 0, 0 ], function( err, rgb ){ 36 | if ( err ) throw( err ); 37 | console.log( rgb ); // same as Photoshop, yo! 38 | }); 39 | ``` 40 | 41 | The error parameter in the callback was added in transicc v1.2.0. 42 | 43 | ***** 44 | 45 | ### Bundled ICC Profiles 46 | 47 | Several ICC profiles are bundled with transicc for your convenience. Here's a complete list of the values you can enter into the input or output options of transicc. 48 | 49 | #### CMYK 50 | 51 | - `cmyk` (shortcut to `cmyk-adobe-us-web-coated-swop`) 52 | - `cmyk-adobe-coated-fogra27` 53 | - `cmyk-adobe-coated-fogra39` 54 | - `cmyk-adobe-coated-gracol2006` 55 | - `cmyk-adobe-japan-200-newspaper` 56 | - `cmyk-adobe-japan-2001-coated` 57 | - `cmyk-adobe-japan-2001-uncoated` 58 | - `cmyk-adobe-japan-2003-web-coated` 59 | - `cmyk-adobe-japan-web-coated` 60 | - `cmyk-adobe-uncoated-fogra29` 61 | - `cmyk-adobe-us-web-coated-swop` 62 | - `cmyk-adobe-us-web-uncoated` 63 | - `cmyk-adobe-web-coated-fogra28` 64 | - `cmyk-adobe-web-coated-swop-2006-g3` 65 | - `cmyk-adobe-web-coated-swop-2006-g5` 66 | - `cmyk-eci-iso-coated-v2-300` 67 | - `cmyk-eci-iso-coated-v2-eci` 68 | - `cmyk-eci-iso-uncoated-yellowish` 69 | - `cmyk-eci-pso-coated-300-npscreen-iso12647` 70 | - `cmyk-eci-pso-coated-npscreen-iso12647` 71 | - `cmyk-eci-pso-lwc-improved` 72 | - `cmyk-eci-pso-lwc-standard` 73 | - `cmyk-eci-pso-mfc-paper` 74 | - `cmyk-eci-pso-snp-paper` 75 | - `cmyk-eci-pso-uncoated-iso12647` 76 | - `cmyk-eci-pso-uncoated-npscreen-iso12647` 77 | - `cmyk-eci-sc-paper` 78 | 79 | #### Lab 80 | 81 | - `lab` (shortcut to `lab-apple`) 82 | 83 | #### RGB 84 | 85 | - `rgb` (shortcut to `rgb-adobe-1998`) 86 | - `rgb-adobe-1998` 87 | - `rgb-apple` 88 | - `rgb-colormatch` 89 | - `rgb-pal-secam` 90 | - `rgb-smpte-c` 91 | - `rgb-video-hd` 92 | - `rgb-video-ntsc` 93 | - `rgb-video-pal` 94 | 95 | #### sRGB 96 | 97 | - `srgb` (shortcut to `srgb-apple`) 98 | - `srgb-apple` 99 | 100 | #### XYZ 101 | 102 | - `xyz` (shortcut to `xyz-d65` - the 'standard' luminant associated with daylight) 103 | - `xyz-d50` 104 | - `xyz-d55` 105 | - `xyz-d65` 106 | 107 | **Note:** These profiles are the property of their respective owners, and were copied as-is (simply renamed for easier organization). By using this module, you accept the terms of service agreements associated with their use as provided by Adobe, Apple, ECI, and the ICC. 108 | 109 | If there's another ICC profile you'd like bundled with this package, please ensure that the creator of that profile is OK with it being bundled in other software. Once you know that, pull requests away! 110 | 111 | -------------------------------------------------------------------------------- /shell/3.sh: -------------------------------------------------------------------------------- 1 | echo "$3\n$4\n$5\n" | transicc -i $1 -o $2 -n -------------------------------------------------------------------------------- /shell/4.sh: -------------------------------------------------------------------------------- 1 | echo "$3\n$4\n$5\n$6\n" | transicc -i $1 -o $2 -n -------------------------------------------------------------------------------- /test/transicc.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var transicc = require( "../transicc" ), 4 | should = require( "should" ); 5 | 6 | 'use strict'; 7 | 8 | // Since we're not responsible for the accuracy of profiles 9 | // we just want to test to make sure a conversion works. 10 | 11 | describe('transicc', function () { 12 | 13 | it('should equal rgb( 0, 172, 236 )', function (done) { 14 | 15 | // convert between adobe cmyk and apple rgb 16 | transicc( "cmyk", "rgb", [ 100, 0, 0, 0 ], function( err, response ) { 17 | 18 | response[0].should.equal( '0.0000' ); 19 | response[1].should.equal( '160.2024' ); 20 | response[2].should.equal( '224.1492' ); 21 | done(); 22 | 23 | }); 24 | 25 | }); 26 | 27 | }); 28 | 29 | -------------------------------------------------------------------------------- /transicc.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var spawn = require( "child_process" ).spawn; 4 | 5 | 6 | // new switch in 1.1.2 to replace symlinks for shortcut profiles 7 | var profile_path = function( profile_name ){ 8 | switch ( profile_name ) { 9 | 10 | // use Adobe's CMYK profile 11 | case "cmyk": 12 | profile_name = "cmyk-adobe-us-web-uncoated"; 13 | break; 14 | 15 | // use Apple's lab profile 16 | case "lab": 17 | profile_name = "lab-apple"; 18 | break; 19 | 20 | // use AdobeRGB for RGB by default 21 | case "rgb": 22 | profile_name = "rgb-adobe-1998"; 23 | break; 24 | 25 | // use Apple's sRGB profile 26 | case "srgb": 27 | profile_name = "srgb-apple"; 28 | break; 29 | 30 | // use XYZ with a luminant of d65 by default 31 | case "xyz": 32 | profile_name = "xyz-d65"; 33 | break; 34 | } 35 | 36 | return "profile/"+profile_name+".icc"; 37 | } 38 | 39 | 40 | // generic function to pass profiles and parameters to the 41 | // LittleCMS transicc command line utility. 42 | module.exports = function( input_profile, output_profile, args, callback ) { 43 | 44 | // create an array of arguments we'll pass to the transicc command 45 | var cmd_arg = []; 46 | 47 | // add the input profile 48 | cmd_arg.push( profile_path( input_profile ) ); 49 | 50 | // add the output profile 51 | cmd_arg.push( profile_path( output_profile ) ); 52 | 53 | 54 | // ensure a valid number of arguments 55 | if ( args.length < 3 && args.length > 4 ) { 56 | callback( new Error('Invalid number of arguments.'), null ); 57 | return; 58 | } 59 | 60 | 61 | // loop through the arguments and add them to the command args 62 | for ( var i = 0; i < args.length; i++ ) { 63 | cmd_arg.push( args[i] ); 64 | } 65 | 66 | 67 | // spawn the command and create an empty response 68 | var cmd = spawn( "./shell/"+args.length+".sh", cmd_arg, { 69 | cwd: __dirname 70 | }), 71 | response; 72 | 73 | 74 | // when we receive output from the command 75 | cmd.stdout.on( 'data', function ( data ) { 76 | 77 | // parse the output 78 | response = new String( data ).split( " " ); 79 | 80 | }); 81 | 82 | 83 | // output errors to the console - only for debugging. 84 | // cmd.stderr.on('data', function (data) { console.log('stderr: ' + data); }); 85 | 86 | 87 | // once the command is finished 88 | cmd.on( 'close', function ( code ) { 89 | 90 | // since we're working asynchronously, we can't return 91 | // so we'll pass our response into a callback function. 92 | callback( null, response ); 93 | 94 | }); 95 | 96 | }; 97 | 98 | --------------------------------------------------------------------------------