├── .gitignore ├── .travis.yml ├── test ├── fixtures │ ├── js │ │ ├── fixture-jsx.js │ │ └── fixture.js │ ├── jsx │ │ ├── fixture.jsx │ │ └── nested │ │ │ └── fixture-js.jsx │ └── browserify │ │ └── module.jsx ├── expected │ ├── default_options │ ├── extension_option │ ├── vanilla_js │ ├── multiple_jsx_files │ └── browserify ├── browserify_test.js ├── transformers_test.js └── react_test.js ├── main.js ├── .jshintrc ├── lib └── transformers.js ├── LICENSE-MIT ├── package.json ├── tasks └── react.js ├── Gruntfile.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | tmp 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | -------------------------------------------------------------------------------- /test/fixtures/js/fixture-jsx.js: -------------------------------------------------------------------------------- 1 | (function(greeting) { 2 | return greeting; 3 | })(

Howdy

); 4 | -------------------------------------------------------------------------------- /test/expected/default_options: -------------------------------------------------------------------------------- 1 | (function(greeting) { 2 | return greeting; 3 | })(React.createElement("p", null, "Howdy")); 4 | -------------------------------------------------------------------------------- /test/fixtures/js/fixture.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Plain JS file 3 | */ 4 | 5 | (function(greeting) { 6 | return greeting; 7 | })('

Howdy

'); 8 | -------------------------------------------------------------------------------- /test/fixtures/jsx/fixture.jsx: -------------------------------------------------------------------------------- 1 | var FixtureComponent = React.createClass({ 2 | render: function() { 3 | return ( 4 |

Howdy

5 | ); 6 | } 7 | }); 8 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module Dependencies 3 | */ 4 | 5 | var Transformers = require('./lib/transformers.js'); 6 | 7 | /** 8 | * Exports 9 | */ 10 | 11 | module.exports = Transformers; 12 | -------------------------------------------------------------------------------- /test/expected/extension_option: -------------------------------------------------------------------------------- 1 | var FixtureComponent = React.createClass({displayName: "FixtureComponent", 2 | render: function() { 3 | return ( 4 | React.createElement("p", null, "Howdy") 5 | ); 6 | } 7 | }); 8 | -------------------------------------------------------------------------------- /test/fixtures/browserify/module.jsx: -------------------------------------------------------------------------------- 1 | var ModuleComponent = React.createClass({ 2 | render: function() { 3 | return ( 4 |

Module

5 | ); 6 | } 7 | }); 8 | 9 | module.exports = ModuleComponent; 10 | -------------------------------------------------------------------------------- /test/fixtures/jsx/nested/fixture-js.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Plain JS File with .jsx extension 3 | */ 4 | 5 | var FixtureComponent = React.createClass({ 6 | render: function() { 7 | return '

Howdy

'; 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /test/expected/vanilla_js: -------------------------------------------------------------------------------- 1 | /** 2 | * Plain JS File with .jsx extension 3 | */ 4 | 5 | var FixtureComponent = React.createClass({displayName: "FixtureComponent", 6 | render: function() { 7 | return '

Howdy

'; 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": true, 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": true, 10 | "boss": true, 11 | "eqnull": true, 12 | "node": true 13 | } 14 | -------------------------------------------------------------------------------- /test/expected/multiple_jsx_files: -------------------------------------------------------------------------------- 1 | var FixtureComponent = React.createClass({displayName: "FixtureComponent", 2 | render: function() { 3 | return ( 4 | React.createElement("p", null, "Howdy") 5 | ); 6 | } 7 | }); 8 | 9 | /** 10 | * Plain JS File with .jsx extension 11 | */ 12 | 13 | var FixtureComponent = React.createClass({displayName: "FixtureComponent", 14 | render: function() { 15 | return '

Howdy

'; 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /test/browserify_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Transformers = require('../lib/transformers'); 4 | var fs = require('fs'); 5 | 6 | exports.transformers = { 7 | setUp: function(done) { 8 | done(); 9 | }, 10 | source_js: function(test) { 11 | test.expect(1); 12 | 13 | var actual = fs.readFileSync('tmp/browserify/module.js').toString(); 14 | var expected = fs.readFileSync('test/expected/browserify').toString(); 15 | 16 | test.equal(actual, expected, 'JSX should be compiled by browserify'); 17 | test.done(); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /test/expected/browserify: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 0.10.0" 27 | }, 28 | "scripts": { 29 | "test": "./node_modules/.bin/grunt" 30 | }, 31 | "dependencies": { 32 | "react-tools": "^0.13.0", 33 | "through": "~2.3.6" 34 | }, 35 | "devDependencies": { 36 | "grunt": "~0.4.5", 37 | "grunt-browserify": "~3.5.0", 38 | "grunt-cli": "~0.1.13", 39 | "grunt-contrib-clean": "~0.6.0", 40 | "grunt-contrib-jshint": "~0.11.0", 41 | "grunt-contrib-nodeunit": "~0.4.1" 42 | }, 43 | "peerDependencies": { 44 | "grunt": "~0.4.2" 45 | }, 46 | "keywords": [ 47 | "gruntplugin", 48 | "react", 49 | "jsx" 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /test/react_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var grunt = require('grunt'); 4 | 5 | exports.react = { 6 | setUp: function(done) { 7 | done(); 8 | }, 9 | 10 | default_options_js: function(test) { 11 | test.expect(1); 12 | 13 | var actual = grunt.file.read('tmp/js/fixture.js'); 14 | var expected = grunt.file.read('test/fixtures/js/fixture.js'); 15 | 16 | test.equal(actual, expected, 'should leave vanilla JS alone'); 17 | test.done(); 18 | }, 19 | 20 | default_options_jsx_as_js: function(test) { 21 | test.expect(1); 22 | 23 | var actual = grunt.file.read('tmp/js/fixture-jsx.js'); 24 | var expected = grunt.file.read('test/expected/default_options'); 25 | 26 | test.equal(actual, expected, 'should convert JSX into JS'); 27 | test.done(); 28 | }, 29 | 30 | extension_option_js_as_jsx: function(test) { 31 | test.expect(1); 32 | 33 | var actual = grunt.file.read('tmp/jsx/nested/fixture-js.js'); 34 | var expected = grunt.file.read('test/expected/vanilla_js'); 35 | 36 | test.equal(actual, expected, 'should convert even vanilla JS'); 37 | test.done(); 38 | }, 39 | 40 | extension_option_jsx: function(test) { 41 | test.expect(1); 42 | 43 | var actual = grunt.file.read('tmp/jsx/fixture.js'); 44 | var expected = grunt.file.read('test/expected/extension_option'); 45 | 46 | test.equal(actual, expected, 'should convert JSX into JS'); 47 | test.done(); 48 | }, 49 | 50 | multiple_jsx_files: function(test) { 51 | test.expect(1); 52 | 53 | var actual = grunt.file.read('tmp/multiple_jsx_files.js'); 54 | var expected = grunt.file.read('test/expected/multiple_jsx_files'); 55 | 56 | test.equal(actual, expected, 'should convert JSX into JS'); 57 | test.done(); 58 | } 59 | }; 60 | -------------------------------------------------------------------------------- /tasks/react.js: -------------------------------------------------------------------------------- 1 | /* 2 | * grunt-react 3 | * https://github.com/ericclemmons/grunt-react 4 | * 5 | * Copyright (c) 2013 Eric Clemmons, contributors 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | module.exports = function(grunt) { 12 | 13 | var transform = require('react-tools').transform; 14 | 15 | grunt.registerMultiTask('react', 'Compile Facebook React JSX templates into JavaScript', function() { 16 | var done = this.async(); 17 | 18 | var options = this.options(); 19 | grunt.verbose.writeflags(options, 'Options'); 20 | 21 | if (this.files.length < 1) { 22 | grunt.verbose.warn('Destination not written because no source files were provided.'); 23 | } 24 | 25 | grunt.util.async.forEachSeries(this.files, function(f, nextFileObj) { 26 | var destFile = f.dest; 27 | 28 | var files = f.src.filter(function(filepath) { 29 | if (!grunt.file.exists(filepath)) { 30 | grunt.log.warn('Source file "' + filepath + '" not found.'); 31 | return false; 32 | } else { 33 | return true; 34 | } 35 | }); 36 | 37 | if (files.length === 0) { 38 | if (f.src.length < 1) { 39 | grunt.log.warn('Destination not written because no source files were found.'); 40 | } 41 | 42 | // No src files, go to next target. Warn would have been issued above. 43 | return nextFileObj(); 44 | } 45 | 46 | var compiled = []; 47 | grunt.util.async.concatSeries(files, function(file, next) { 48 | grunt.verbose.writeln('[react] Compiling ' + file.cyan + ' --> ' + destFile.cyan); 49 | 50 | try { 51 | compiled.push(transform(grunt.file.read(file), options)); 52 | } catch (e) { 53 | grunt.event.emit('react.error', file, e); 54 | grunt.fail.warn(e); 55 | } finally { 56 | next(); 57 | } 58 | }, function () { 59 | grunt.file.write(destFile, compiled.join(grunt.util.normalizelf(grunt.util.linefeed))); 60 | grunt.verbose.writeln('[react] File ' + destFile.cyan + ' created.'); 61 | nextFileObj(); 62 | }); 63 | 64 | }, done); 65 | }); 66 | }; 67 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /* 2 | * grunt-react 3 | * https://github.com/ericclemmons/grunt-react 4 | * 5 | * Copyright (c) 2013 Eric Clemmons, contributors 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | module.exports = function(grunt) { 12 | 13 | // Project configuration. 14 | grunt.initConfig({ 15 | jshint: { 16 | all: [ 17 | 'Gruntfile.js', 18 | 'tasks/*.js', 19 | '<%= nodeunit.tests %>' 20 | ], 21 | options: { 22 | jshintrc: '.jshintrc' 23 | }, 24 | }, 25 | 26 | // Used for testing the transformer 27 | browserify: { 28 | options: { 29 | transform: [ require('./main').browserify ] 30 | }, 31 | module: { 32 | src: 'test/fixtures/browserify/module.jsx', 33 | dest: 'tmp/browserify/module.js' 34 | } 35 | }, 36 | 37 | // Before generating any new files, remove any previously-created files. 38 | clean: { 39 | tests: ['tmp'] 40 | }, 41 | 42 | // Configuration to be run (and then tested). 43 | react: { 44 | single_js_files: { 45 | files: { 46 | 'tmp/js/fixture.js': 'test/fixtures/js/fixture.js', 47 | 'tmp/js/fixture-jsx.js': 'test/fixtures/js/fixture-jsx.js' 48 | } 49 | }, 50 | single_jsx_files: { 51 | files: { 52 | 'tmp/jsx/fixture.js': 'test/fixtures/jsx/fixture.jsx', 53 | 'tmp/jsx/nested/fixture-js.js': 'test/fixtures/jsx/nested/fixture-js.jsx' 54 | } 55 | }, 56 | multiple_jsx_files: { 57 | files: { 58 | 'tmp/multiple_jsx_files.js': ['test/fixtures/jsx/fixture.jsx', 'test/fixtures/jsx/nested/fixture-js.jsx'] 59 | } 60 | }, 61 | dynamic_mappings: { 62 | files: [ 63 | { 64 | expand: true, 65 | cwd: 'test/fixtures', 66 | src: ['**/*.js'], 67 | dest: 'tmp/dynamic_mappings/js', 68 | ext: '.js' 69 | }, 70 | { 71 | expand: true, 72 | cwd: 'test/fixtures', 73 | src: ['**/*.jsx'], 74 | dest: 'tmp/dynamic_mappings/jsx', 75 | ext: '.js' 76 | } 77 | ] 78 | } 79 | }, 80 | 81 | // Unit tests. 82 | nodeunit: { 83 | tests: ['test/*_test.js'] 84 | }, 85 | 86 | }); 87 | 88 | // Actually load this plugin's task(s). 89 | grunt.loadTasks('tasks'); 90 | 91 | // These plugins provide necessary tasks. 92 | grunt.loadNpmTasks('grunt-browserify'); 93 | grunt.loadNpmTasks('grunt-contrib-jshint'); 94 | grunt.loadNpmTasks('grunt-contrib-clean'); 95 | grunt.loadNpmTasks('grunt-contrib-nodeunit'); 96 | 97 | // Whenever the "test" task is run, first clean the "tmp" dir, then run this 98 | // plugin's task(s), then test the result. 99 | grunt.registerTask('test', ['clean', 'react', 'browserify', 'nodeunit']); 100 | 101 | // By default, lint and run all tests. 102 | grunt.registerTask('default', ['jshint', 'test']); 103 | 104 | }; 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [DEPRECATED] grunt-react 2 | 3 | [![Build Status](https://travis-ci.org/ericclemmons/grunt-react.png?branch=master)](https://travis-ci.org/ericclemmons/grunt-react) 4 | [![Dependencies](https://david-dm.org/ericclemmons/grunt-react.png)](https://david-dm.org/ericclemmons/grunt-react) 5 | [![devDependencies](https://david-dm.org/ericclemmons/grunt-react/dev-status.png)](https://david-dm.org/ericclemmons/grunt-react#info=devDependencies&view=table) 6 | 7 | > Grunt task for compiling [Facebook React](http://facebook.github.io/react/)'s JSX templates into JavaScript. 8 | 9 | It also works great with `grunt-browserify`! 10 | 11 | - - - 12 | 13 | ## DEPRECATION NOTICE 14 | 15 | On **June 12th, 2015**, the React team has deprecated `JSTransform` and `react-tools`, which this project uses: 16 | > http://facebook.github.io/react/blog/2015/06/12/deprecating-jstransform-and-react-tools.html 17 | 18 | Please use [`grunt-babel`](https://github.com/babel/grunt-babel) instead. 19 | 20 | - - - 21 | 22 | ## Getting Started 23 | This plugin requires Grunt `~0.4.0` 24 | 25 | If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command: 26 | 27 | ```shell 28 | npm install grunt-react --save-dev 29 | ``` 30 | 31 | Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript: 32 | 33 | ```js 34 | grunt.loadNpmTasks('grunt-react'); 35 | ``` 36 | 37 | ## The "react" task 38 | 39 | ### Overview 40 | In your project's Gruntfile, add a section named `react` to the data object passed into `grunt.initConfig()`. 41 | 42 | ```js 43 | grunt.initConfig({ 44 | react: { 45 | single_file_output: { 46 | files: { 47 | 'path/to/output/dir/output.js': 'path/to/jsx/templates/dir/input.jsx' 48 | } 49 | }, 50 | combined_file_output: { 51 | files: { 52 | 'path/to/output/dir/combined.js': [ 53 | 'path/to/jsx/templates/dir/input1.jsx', 54 | 'path/to/jsx/templates/dir/input2.jsx' 55 | ] 56 | } 57 | }, 58 | dynamic_mappings: { 59 | files: [ 60 | { 61 | expand: true, 62 | cwd: 'path/to/jsx/templates/dir', 63 | src: ['**/*.jsx'], 64 | dest: 'path/to/output/dir', 65 | ext: '.js' 66 | } 67 | ] 68 | } 69 | }, 70 | }) 71 | ``` 72 | 73 | ### Options 74 | 75 | These options are passed to react-tools. 76 | 77 | #### options.extension 78 | Type: `String` 79 | Default value: `js` 80 | 81 | Extension of files to search for JSX-syntax & convert to JS. 82 | 83 | #### options.ignoreMTime 84 | Type: `Boolean` 85 | Default value: `false` 86 | 87 | Speed up compilation of JSX files by skipping files not modified since last pass. 88 | 89 | #### options.harmony 90 | Type: `Boolean` 91 | Default value: `false` 92 | 93 | Turns on JS transformations such as ES6 Classes. 94 | 95 | #### options.sourceMap 96 | Type: `Boolean` 97 | Default value: `false` 98 | 99 | Append inline source map at the end of the transformed source 100 | 101 | Turns on JS transformations such as ES6 Classes. 102 | 103 | #### options.es6module 104 | Type: `Boolean` 105 | Default value: `false` 106 | 107 | Allows use of ES6 module syntax. This option does not affect ES6 transformations enabled or disabled by options.harmony. 108 | 109 | - - - 110 | 111 | ### Recommended Usage 112 | Writing your applications in CommonJS format will allow you to use [Browserify](http://browserify.org/) to 113 | concatenate your files. Plus, with `grunt-react`, your templates will be converted from JSX to JS *automatically*! 114 | 115 | First, install `grunt-browserify` to your project: 116 | 117 | ```shell 118 | npm install grunt-browserify --save-dev 119 | ``` 120 | 121 | Second, register `grunt-browserify` in your Gruntfile: 122 | 123 | ```js 124 | grunt.loadNpmTasks('grunt-browserify'); 125 | ``` 126 | 127 | Finally, add the following task to your Gruntfile: 128 | 129 | ```js 130 | browserify: { 131 | options: { 132 | transform: [ require('grunt-react').browserify ] 133 | }, 134 | app: { 135 | src: 'path/to/source/main.js', 136 | dest: 'path/to/target/output.js' 137 | } 138 | } 139 | ``` 140 | 141 | You've successfully concatenated your JSX & JS files into one file! 142 | 143 | - - - 144 | 145 | ### Usage Examples 146 | 147 | #### Recommended Options 148 | 149 | I recommend naming your React Components with the `.jsx` extension: 150 | 151 | ```js 152 | /** 153 | * @jsx React.DOM 154 | */ 155 | 156 | var MyComponent = React.createClass({ 157 | ... 158 | render: function() { 159 | return ( 160 |

Howdy

161 | ); 162 | } 163 | }); 164 | ``` 165 | 166 | Then, set your Gruntfile to use: 167 | 168 | ```js 169 | grunt.initConfig({ 170 | react: { 171 | files: { 172 | expand: true, 173 | cwd: 'path/to/jsx/templates/dir', 174 | src: ['**/*.jsx'], 175 | dest: 'path/to/output/dir', 176 | ext: '.js' 177 | } 178 | }, 179 | }) 180 | ``` 181 | 182 | This will output the following: 183 | 184 | ```js 185 | /** 186 | * @jsx React.DOM 187 | */ 188 | 189 | var MyComponent = React.createClass({displayName: 'MyComponent', 190 | render: function() { 191 | return ( 192 | React.DOM.p(null, "Howdy") 193 | ); 194 | } 195 | }); 196 | ``` 197 | 198 | ## Troubleshooting 199 | 200 | If you encounter a file compilation error, you can run `grunt --verbose` to see specifics about each file being transformed. 201 | 202 | ## Contributing 203 | In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/). 204 | 205 | ## Release History 206 | 207 | - v0.12.2 208 | + Move verbose logging to `grunt --verbose` ([#53](https://github.com/ericclemmons/grunt-react/pull/53)) 209 | 210 | - v0.12.1 211 | + Fix issue with Browserify ([#46](https://github.com/ericclemmons/grunt-react/pull/49)) 212 | 213 | - v0.12.0 214 | + Update all `dependencies` & `devDependencies` 215 | 216 | - v0.11.0 217 | + Update `react-tools` to `v0.13.0` ([#45](https://github.com/ericclemmons/grunt-react/pull/45)) 218 | 219 | - v0.10.0 220 | + Update `react-tools` to `v0.12.0` ([#40](https://github.com/ericclemmons/grunt-react/pull/40)). 221 | (See release notes: http://facebook.github.io/react/blog/2014/10/28/react-v0.12.html) 222 | 223 | - v0.9.0 224 | + Continue compilation despite error. ([#31](https://github.com/ericclemmons/grunt-react/pull/31)) 225 | - v0.8.4 226 | + Add support for `harmony` via additional options. ([#32](https://github.com/ericclemmons/grunt-react/pull/32)) 227 | - v0.8.3 228 | + Update to `react-tools` at `^v0.11.0` ([#33](https://github.com/ericclemmons/grunt-react/pull/33)) 229 | - v0.8.2 230 | - Emit `react.error` for Growl & other notifications ([#23](https://github.com/ericclemmons/grunt-react/pull/23)) 231 | - v0.8.1 232 | - Throw a proper error when React fails ([#25](https://github.com/ericclemmons/grunt-react/pull/25)) 233 | - v0.8.0 234 | - Update to React v0.10.0 ([#27](https://github.com/ericclemmons/grunt-react/pull/27)) 235 | - v0.7.0 236 | - Update to React v0.9.0 ([#24](https://github.com/ericclemmons/grunt-react/pull/24)) 237 | - v0.6.0 238 | - Task changes to allow for flexible file options as found in the `grunt-contrib-*` projects. 239 | - Taking hints from `grunt-contrib-less` to allow for compiling single files separately, dynamic mappings and combining. 240 | - Removed `extension` option as this is determined by flexible file matching now. 241 | - Removed MT time ignoring, this can be easily done with the `grunt-newer` plugin. 242 | - Errors are ignored and skipped by default to match how other grunt plugins work. 243 | - v0.5.2 244 | - `grunt.fail` instead of throwing an error ([#11](https://github.com/ericclemmons/grunt-react/pull/11)) 245 | - v0.5.1 246 | - Add file name to errors ([#15](https://github.com/ericclemmons/grunt-react/pull/15)) 247 | - v0.5.0 248 | - Update to `react-tools` `~v0.5.0` 249 | - v0.4.1 250 | - Add logging to make it easier catch errors, thanks to @lorefnon ([#5](https://github.com/ericclemmons/grunt-react/pull/5)) 251 | - v0.4.0 252 | - Update to react-tools ~0.4.0, thanks to @Agent-H ([#3](https://github.com/ericclemmons/grunt-react/pull/3)) 253 | - v0.3.0 254 | - No longer uses `bin/jsx`, thanks to @petehunt ([#2](https://github.com/ericclemmons/grunt-react/pull/2)) 255 | - Add `ignoreMTime` option 256 | - v0.2.0 257 | - Add `require('grunt-react').browserify()` and `require('grunt-react').source()` for compiling within Node 258 | - v0.1.0 259 | - Initial release 260 | 261 | 262 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/ericclemmons/grunt-react/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 263 | --------------------------------------------------------------------------------