├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── custom.md │ └── feature_request.md ├── CODE_OF_CONDUCT.md ├── Dockerfile ├── LICENSE ├── README.md ├── action.yml ├── build ├── demo └── github action.png └── dist └── index.js /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at irizviali@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | 3 | LABEL "com.github.actions.name"="React Native Android Build APK" 4 | LABEL "com.github.actions.description"="This github action automatically builds the android apk under the artifact section" 5 | LABEL "com.github.actions.icon"="archive" 6 | LABEL "com.github.actions.color"="blue" 7 | 8 | LABEL version="1.1.2" 9 | LABEL repository="https://github.com/realabbas/Github-Actions-React-Native" 10 | LABEL homepage="https://github.com/realabbas/Github-Actions-React-Native" 11 | LABEL maintainer="Ali Abbas>" 12 | 13 | COPY build /usr/local/bin/build 14 | 15 | ENTRYPOINT ["/usr/local/bin/build"] 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 realabbas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Github Action for React Native Build](https://raw.githubusercontent.com/realabbas/Github-Actions-React-Native/master/demo/github%20action.png) 2 | 3 | This github action automatically builds the android apk under the artifact section whenever a commit is pushed into the master branch 4 | 5 | ![Visitors](https://visitor-badge.glitch.me/badge?page_id=realabbas.github-actions-react-native) 6 | 7 | ## Installation 8 | 9 | Add the *action.yml* as follows ``` .github/workflows/build.yml ``` in the project. 10 | For more reference see the official [docs](https://help.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow#creating-a-workflow-file) 11 | 12 | ``` 13 | name: react-native-android-build-apk 14 | on: 15 | push: 16 | branches: 17 | - master 18 | jobs: 19 | install-and-test: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v3 23 | - name: Install npm dependencies 24 | run: | 25 | npm install 26 | build-android: 27 | needs: install-and-test 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v3 31 | - name: Install npm dependencies 32 | run: | 33 | npm install 34 | - name: Build Android Release 35 | run: | 36 | cd android && ./gradlew assembleRelease 37 | - name: Upload Artifact 38 | uses: actions/upload-artifact@v1 39 | with: 40 | name: app-release.apk 41 | path: android/app/build/outputs/apk/release/ 42 | 43 | ``` 44 | 45 | Build will be triggered as soon as the commit is pushed to the master branch. 46 | 47 | ## Troubleshoot 48 | 49 | ### Gradlew commands not working 50 | 51 | You can try to execute the following command before run gradle commands. 52 | 53 | ``` 54 | chmod +x ./gradlew 55 | ``` 56 | 57 | 58 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: "React Native Android Build APK" 2 | description: "This github action automatically builds the android apk under the artifact section" 3 | author: "realabbas" 4 | branding: 5 | icon: "archive" 6 | color: "blue" 7 | on: 8 | push: 9 | branches: 10 | - master 11 | jobs: 12 | # First Job 13 | install-and-test: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Install npm dependencies 18 | run: | 19 | npm install 20 | # For testing 21 | - name: Run tests 22 | run: | 23 | npm test 24 | # Second Job 25 | build-android: 26 | needs: install-and-test 27 | runs-on: ubuntu-latest 28 | steps: 29 | - uses: actions/checkout@v2 30 | - name: Install npm dependencies 31 | run: | 32 | npm install 33 | 34 | - name: Cache Gradle Wrapper 35 | uses: actions/cache@v2 36 | with: 37 | path: ~/.gradle/wrapper 38 | key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} 39 | 40 | - name: Cache Gradle Dependencies 41 | uses: actions/cache@v2 42 | with: 43 | path: ~/.gradle/caches 44 | key: ${{ runner.os }}-gradle-caches-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} 45 | restore-keys: | 46 | ${{ runner.os }}-gradle-caches- 47 | 48 | - name: Make Gradlew Executable 49 | run: cd android && chmod +x ./gradlew 50 | # Build Command 51 | 52 | - name: Build Android Release 53 | run: | 54 | cd android && gradlew assembleRelease --no-daemon 55 | 56 | # Upload to Artifact 57 | - name: Upload Artifact 58 | uses: actions/upload-artifact@v1 59 | with: 60 | name: app-release.apk 61 | path: android/app/build/outputs/apk/release/ 62 | -------------------------------------------------------------------------------- /build: -------------------------------------------------------------------------------- 1 | 2 | #!/bin/bash 3 | # 4 | # Run a build-script, from within the repository. 5 | # 6 | 7 | set -e 8 | 9 | # Get the name of the script 10 | script=$1 11 | 12 | # Ensure something was specified 13 | if [ -z "${script}" ]; then 14 | echo "*********************************" 15 | echo " You must specify a build-script" 16 | echo "*********************************" 17 | exit 1 18 | fi 19 | 20 | # Ensure it exists 21 | if [ ! -e "${script}" ]; then 22 | echo "*****************************************************************" 23 | echo " build script not present - looked for ${script}" 24 | echo "*****************************************************************" 25 | exit 1 26 | fi 27 | 28 | # Ensure the script is executable. 29 | chmod 755 ${script} >/dev/null 2>/dev/null || true 30 | 31 | # Run it 32 | ${script} 33 | -------------------------------------------------------------------------------- /demo/github action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realabbas/Github-Actions-React-Native/1fb0843b16f9c57d517d9b118e53412172711774/demo/github action.png -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | /******/ (function(modules, runtime) { // webpackBootstrap 3 | /******/ "use strict"; 4 | /******/ // The module cache 5 | /******/ var installedModules = {}; 6 | /******/ 7 | /******/ // The require function 8 | /******/ function __webpack_require__(moduleId) { 9 | /******/ 10 | /******/ // Check if module is in cache 11 | /******/ if(installedModules[moduleId]) { 12 | /******/ return installedModules[moduleId].exports; 13 | /******/ } 14 | /******/ // Create a new module (and put it into the cache) 15 | /******/ var module = installedModules[moduleId] = { 16 | /******/ i: moduleId, 17 | /******/ l: false, 18 | /******/ exports: {} 19 | /******/ }; 20 | /******/ 21 | /******/ // Execute the module function 22 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 23 | /******/ 24 | /******/ // Flag the module as loaded 25 | /******/ module.l = true; 26 | /******/ 27 | /******/ // Return the exports of the module 28 | /******/ return module.exports; 29 | /******/ } 30 | /******/ 31 | /******/ 32 | /******/ __webpack_require__.ab = __dirname + "/"; 33 | /******/ 34 | /******/ // the startup function 35 | /******/ function startup() { 36 | /******/ // Load entry module and return exports 37 | /******/ return __webpack_require__(198); 38 | /******/ }; 39 | /******/ 40 | /******/ // run startup 41 | /******/ return startup(); 42 | /******/ }) 43 | /************************************************************************/ 44 | /******/ ({ 45 | 46 | /***/ 87: 47 | /***/ (function(module) { 48 | 49 | module.exports = require("os"); 50 | 51 | /***/ }), 52 | 53 | /***/ 198: 54 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 55 | 56 | "use strict"; 57 | 58 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 59 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 60 | return new (P || (P = Promise))(function (resolve, reject) { 61 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 62 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 63 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 64 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 65 | }); 66 | }; 67 | var __importStar = (this && this.__importStar) || function (mod) { 68 | if (mod && mod.__esModule) return mod; 69 | var result = {}; 70 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 71 | result["default"] = mod; 72 | return result; 73 | }; 74 | Object.defineProperty(exports, "__esModule", { value: true }); 75 | const core = __importStar(__webpack_require__(470)); 76 | const wait_1 = __webpack_require__(521); 77 | function run() { 78 | return __awaiter(this, void 0, void 0, function* () { 79 | try { 80 | const ms = core.getInput('milliseconds'); 81 | core.debug(`Waiting ${ms} milliseconds ...`); 82 | core.debug(new Date().toTimeString()); 83 | yield wait_1.wait(parseInt(ms, 10)); 84 | core.debug(new Date().toTimeString()); 85 | core.setOutput('time', new Date().toTimeString()); 86 | } 87 | catch (error) { 88 | core.setFailed(error.message); 89 | } 90 | }); 91 | } 92 | run(); 93 | 94 | 95 | /***/ }), 96 | 97 | /***/ 431: 98 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 99 | 100 | "use strict"; 101 | 102 | Object.defineProperty(exports, "__esModule", { value: true }); 103 | const os = __webpack_require__(87); 104 | /** 105 | * Commands 106 | * 107 | * Command Format: 108 | * ##[name key=value;key=value]message 109 | * 110 | * Examples: 111 | * ##[warning]This is the user warning message 112 | * ##[set-secret name=mypassword]definatelyNotAPassword! 113 | */ 114 | function issueCommand(command, properties, message) { 115 | const cmd = new Command(command, properties, message); 116 | process.stdout.write(cmd.toString() + os.EOL); 117 | } 118 | exports.issueCommand = issueCommand; 119 | function issue(name, message) { 120 | issueCommand(name, {}, message); 121 | } 122 | exports.issue = issue; 123 | const CMD_PREFIX = '##['; 124 | class Command { 125 | constructor(command, properties, message) { 126 | if (!command) { 127 | command = 'missing.command'; 128 | } 129 | this.command = command; 130 | this.properties = properties; 131 | this.message = message; 132 | } 133 | toString() { 134 | let cmdStr = CMD_PREFIX + this.command; 135 | if (this.properties && Object.keys(this.properties).length > 0) { 136 | cmdStr += ' '; 137 | for (const key in this.properties) { 138 | if (this.properties.hasOwnProperty(key)) { 139 | const val = this.properties[key]; 140 | if (val) { 141 | // safely append the val - avoid blowing up when attempting to 142 | // call .replace() if message is not a string for some reason 143 | cmdStr += `${key}=${escape(`${val || ''}`)};`; 144 | } 145 | } 146 | } 147 | } 148 | cmdStr += ']'; 149 | // safely append the message - avoid blowing up when attempting to 150 | // call .replace() if message is not a string for some reason 151 | const message = `${this.message || ''}`; 152 | cmdStr += escapeData(message); 153 | return cmdStr; 154 | } 155 | } 156 | function escapeData(s) { 157 | return s.replace(/\r/g, '%0D').replace(/\n/g, '%0A'); 158 | } 159 | function escape(s) { 160 | return s 161 | .replace(/\r/g, '%0D') 162 | .replace(/\n/g, '%0A') 163 | .replace(/]/g, '%5D') 164 | .replace(/;/g, '%3B'); 165 | } 166 | //# sourceMappingURL=command.js.map 167 | 168 | /***/ }), 169 | 170 | /***/ 470: 171 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 172 | 173 | "use strict"; 174 | 175 | Object.defineProperty(exports, "__esModule", { value: true }); 176 | const command_1 = __webpack_require__(431); 177 | const path = __webpack_require__(622); 178 | /** 179 | * The code to exit an action 180 | */ 181 | var ExitCode; 182 | (function (ExitCode) { 183 | /** 184 | * A code indicating that the action was successful 185 | */ 186 | ExitCode[ExitCode["Success"] = 0] = "Success"; 187 | /** 188 | * A code indicating that the action was a failure 189 | */ 190 | ExitCode[ExitCode["Failure"] = 1] = "Failure"; 191 | })(ExitCode = exports.ExitCode || (exports.ExitCode = {})); 192 | //----------------------------------------------------------------------- 193 | // Variables 194 | //----------------------------------------------------------------------- 195 | /** 196 | * sets env variable for this action and future actions in the job 197 | * @param name the name of the variable to set 198 | * @param val the value of the variable 199 | */ 200 | function exportVariable(name, val) { 201 | process.env[name] = val; 202 | command_1.issueCommand('set-env', { name }, val); 203 | } 204 | exports.exportVariable = exportVariable; 205 | /** 206 | * exports the variable and registers a secret which will get masked from logs 207 | * @param name the name of the variable to set 208 | * @param val value of the secret 209 | */ 210 | function exportSecret(name, val) { 211 | exportVariable(name, val); 212 | command_1.issueCommand('set-secret', {}, val); 213 | } 214 | exports.exportSecret = exportSecret; 215 | /** 216 | * Prepends inputPath to the PATH (for this action and future actions) 217 | * @param inputPath 218 | */ 219 | function addPath(inputPath) { 220 | command_1.issueCommand('add-path', {}, inputPath); 221 | process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`; 222 | } 223 | exports.addPath = addPath; 224 | /** 225 | * Gets the value of an input. The value is also trimmed. 226 | * 227 | * @param name name of the input to get 228 | * @param options optional. See InputOptions. 229 | * @returns string 230 | */ 231 | function getInput(name, options) { 232 | const val = process.env[`INPUT_${name.replace(' ', '_').toUpperCase()}`] || ''; 233 | if (options && options.required && !val) { 234 | throw new Error(`Input required and not supplied: ${name}`); 235 | } 236 | return val.trim(); 237 | } 238 | exports.getInput = getInput; 239 | /** 240 | * Sets the value of an output. 241 | * 242 | * @param name name of the output to set 243 | * @param value value to store 244 | */ 245 | function setOutput(name, value) { 246 | command_1.issueCommand('set-output', { name }, value); 247 | } 248 | exports.setOutput = setOutput; 249 | //----------------------------------------------------------------------- 250 | // Results 251 | //----------------------------------------------------------------------- 252 | /** 253 | * Sets the action status to failed. 254 | * When the action exits it will be with an exit code of 1 255 | * @param message add error issue message 256 | */ 257 | function setFailed(message) { 258 | process.exitCode = ExitCode.Failure; 259 | error(message); 260 | } 261 | exports.setFailed = setFailed; 262 | //----------------------------------------------------------------------- 263 | // Logging Commands 264 | //----------------------------------------------------------------------- 265 | /** 266 | * Writes debug message to user log 267 | * @param message debug message 268 | */ 269 | function debug(message) { 270 | command_1.issueCommand('debug', {}, message); 271 | } 272 | exports.debug = debug; 273 | /** 274 | * Adds an error issue 275 | * @param message error issue message 276 | */ 277 | function error(message) { 278 | command_1.issue('error', message); 279 | } 280 | exports.error = error; 281 | /** 282 | * Adds an warning issue 283 | * @param message warning issue message 284 | */ 285 | function warning(message) { 286 | command_1.issue('warning', message); 287 | } 288 | exports.warning = warning; 289 | //# sourceMappingURL=core.js.map 290 | 291 | /***/ }), 292 | 293 | /***/ 521: 294 | /***/ (function(__unusedmodule, exports) { 295 | 296 | "use strict"; 297 | 298 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 299 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 300 | return new (P || (P = Promise))(function (resolve, reject) { 301 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 302 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 303 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 304 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 305 | }); 306 | }; 307 | Object.defineProperty(exports, "__esModule", { value: true }); 308 | function wait(milliseconds) { 309 | return __awaiter(this, void 0, void 0, function* () { 310 | return new Promise(resolve => { 311 | if (isNaN(milliseconds)) { 312 | throw new Error('milliseconds not a number'); 313 | } 314 | setTimeout(() => resolve('done!'), milliseconds); 315 | }); 316 | }); 317 | } 318 | exports.wait = wait; 319 | 320 | 321 | /***/ }), 322 | 323 | /***/ 622: 324 | /***/ (function(module) { 325 | 326 | module.exports = require("path"); 327 | 328 | /***/ }) 329 | 330 | /******/ }); 331 | --------------------------------------------------------------------------------