Add war-log upload endpoint and processing
							parent
							
								
									2fa616570c
								
							
						
					
					
						commit
						84b19310b6
					
				| 
						 | 
					@ -11,5 +11,6 @@ module.exports = {
 | 
				
			||||||
  squads: '/squads',
 | 
					  squads: '/squads',
 | 
				
			||||||
  users: '/users',
 | 
					  users: '/users',
 | 
				
			||||||
  account: '/account',
 | 
					  account: '/account',
 | 
				
			||||||
  request: '/request'
 | 
					  request: '/request',
 | 
				
			||||||
 | 
					  wars: '/wars'
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,58 @@
 | 
				
			||||||
 | 
					"use strict";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const mongoose = require('mongoose');
 | 
				
			||||||
 | 
					const Schema = mongoose.Schema;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PlayerSchema = new Schema({
 | 
				
			||||||
 | 
					  name: {
 | 
				
			||||||
 | 
					    type: String,
 | 
				
			||||||
 | 
					    required: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  fraction: {
 | 
				
			||||||
 | 
					    type: String,
 | 
				
			||||||
 | 
					    enum: ['BLUFOR', 'OPFOR'],
 | 
				
			||||||
 | 
					    required: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  warId: {
 | 
				
			||||||
 | 
					    type: mongoose.Schema.Types.ObjectId,
 | 
				
			||||||
 | 
					    ref: 'War',
 | 
				
			||||||
 | 
					    required: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  kill: {
 | 
				
			||||||
 | 
					    type: Number,
 | 
				
			||||||
 | 
					    get: v => Math.round(v),
 | 
				
			||||||
 | 
					    set: v => Math.round(v),
 | 
				
			||||||
 | 
					    required: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  death: {
 | 
				
			||||||
 | 
					    type: Number,
 | 
				
			||||||
 | 
					    get: v => Math.round(v),
 | 
				
			||||||
 | 
					    set: v => Math.round(v),
 | 
				
			||||||
 | 
					    required: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  friendlyFire: {
 | 
				
			||||||
 | 
					    type: Number,
 | 
				
			||||||
 | 
					    get: v => Math.round(v),
 | 
				
			||||||
 | 
					    set: v => Math.round(v),
 | 
				
			||||||
 | 
					    required: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  respawn: {
 | 
				
			||||||
 | 
					    type: Number,
 | 
				
			||||||
 | 
					    get: v => Math.round(v),
 | 
				
			||||||
 | 
					    set: v => Math.round(v),
 | 
				
			||||||
 | 
					    required: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  flagTouch: {
 | 
				
			||||||
 | 
					    type: Number,
 | 
				
			||||||
 | 
					    get: v => Math.round(v),
 | 
				
			||||||
 | 
					    set: v => Math.round(v),
 | 
				
			||||||
 | 
					    default: 0
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}, {
 | 
				
			||||||
 | 
					  collection: 'player',
 | 
				
			||||||
 | 
					  timestamps: {createdAt: 'timestamp'}
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					// optional more indices
 | 
				
			||||||
 | 
					PlayerSchema.index({timestamp: 1});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = mongoose.model('Player', PlayerSchema);
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					"use strict";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const mongoose = require('mongoose');
 | 
				
			||||||
 | 
					const Schema = mongoose.Schema;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const WarSchema = new Schema({
 | 
				
			||||||
 | 
					  date: {
 | 
				
			||||||
 | 
					    type: Date,
 | 
				
			||||||
 | 
					    required: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  ptBlufor: {
 | 
				
			||||||
 | 
					    type: Number,
 | 
				
			||||||
 | 
					    get: v => Math.round(v),
 | 
				
			||||||
 | 
					    set: v => Math.round(v),
 | 
				
			||||||
 | 
					    required: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  ptOpfor: {
 | 
				
			||||||
 | 
					    type: Number,
 | 
				
			||||||
 | 
					    get: v => Math.round(v),
 | 
				
			||||||
 | 
					    set: v => Math.round(v),
 | 
				
			||||||
 | 
					    required: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  bestPlayerId: {
 | 
				
			||||||
 | 
					    type: mongoose.Schema.Types.ObjectId,
 | 
				
			||||||
 | 
					    ref: 'Player',
 | 
				
			||||||
 | 
					    default: null
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}, {
 | 
				
			||||||
 | 
					  collection: 'war',
 | 
				
			||||||
 | 
					  timestamps: {createdAt: 'timestamp'}
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					// optional more indices
 | 
				
			||||||
 | 
					WarSchema.index({timestamp: 1});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = mongoose.model('War', WarSchema);
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
					@ -25,7 +25,8 @@
 | 
				
			||||||
    "jimp": "^0.2.27",
 | 
					    "jimp": "^0.2.27",
 | 
				
			||||||
    "jsonwebtoken": "^7.4.0",
 | 
					    "jsonwebtoken": "^7.4.0",
 | 
				
			||||||
    "lodash": "^4.17.4",
 | 
					    "lodash": "^4.17.4",
 | 
				
			||||||
    "mongoose": "^4.3.0",
 | 
					    "mkdirp": "^0.5.1",
 | 
				
			||||||
 | 
					    "mongoose": "^4.11.1",
 | 
				
			||||||
    "morgan": "~1.6.1",
 | 
					    "morgan": "~1.6.1",
 | 
				
			||||||
    "multer": "^1.3.0",
 | 
					    "multer": "^1.3.0",
 | 
				
			||||||
    "node-sha1": "^1.0.1",
 | 
					    "node-sha1": "^1.0.1",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,150 @@
 | 
				
			||||||
 | 
					"use strict";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// modules
 | 
				
			||||||
 | 
					const fs = require('fs');
 | 
				
			||||||
 | 
					const mkdirp = require("mkdirp");
 | 
				
			||||||
 | 
					const {exec} = require('child_process');
 | 
				
			||||||
 | 
					const express = require('express');
 | 
				
			||||||
 | 
					const multer = require('multer');
 | 
				
			||||||
 | 
					const storage = multer.memoryStorage();
 | 
				
			||||||
 | 
					const upload = multer({storage: storage});
 | 
				
			||||||
 | 
					const logger = require('debug')('cc:squads');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// HTTP status codes by name
 | 
				
			||||||
 | 
					const codes = require('./http-codes');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const apiAuthenticationMiddleware = require('../middleware/auth-middleware');
 | 
				
			||||||
 | 
					// const checkMT = require('../middleware/permission-check').checkMT();
 | 
				
			||||||
 | 
					const routerHandling = require('../middleware/router-handling');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Mongoose Model using mongoDB
 | 
				
			||||||
 | 
					const WarModel = require('../models/war');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const wars = express.Router();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// routes **********************
 | 
				
			||||||
 | 
					wars.route('/')
 | 
				
			||||||
 | 
					// .get((req, res, next) => {
 | 
				
			||||||
 | 
					//   const filter = {};
 | 
				
			||||||
 | 
					//   WarModel.find(filter, {}, {sort: {date: 'asc'}}, (err, items) => {
 | 
				
			||||||
 | 
					//     if (err) {
 | 
				
			||||||
 | 
					//       err.status = codes.servererror;
 | 
				
			||||||
 | 
					//       return next(err);
 | 
				
			||||||
 | 
					//     }
 | 
				
			||||||
 | 
					//     if (items) {
 | 
				
			||||||
 | 
					//       res.locals.items = items;
 | 
				
			||||||
 | 
					//     } else {
 | 
				
			||||||
 | 
					//       res.locals.items = [];
 | 
				
			||||||
 | 
					//     }
 | 
				
			||||||
 | 
					//     res.locals.processed = true;
 | 
				
			||||||
 | 
					//     next();
 | 
				
			||||||
 | 
					//   });
 | 
				
			||||||
 | 
					// })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .post(upload.single('log'), (req, res, next) => {
 | 
				
			||||||
 | 
					    const war = new WarModel(req.body);
 | 
				
			||||||
 | 
					    // timestamp and default are set automatically by Mongoose Schema Validation
 | 
				
			||||||
 | 
					    if (req.file) {
 | 
				
			||||||
 | 
					      const timestamp = new Date();
 | 
				
			||||||
 | 
					      const uploadDate = timestamp.toISOString().slice(0, 10) + '_' + timestamp.toTimeString().slice(0, 8)
 | 
				
			||||||
 | 
					      const folderName = __dirname + '/../resource/logs/' + uploadDate;
 | 
				
			||||||
 | 
					      mkdirp(folderName, function (err) {
 | 
				
			||||||
 | 
					        if (err) {
 | 
				
			||||||
 | 
					          return next(err);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        fs.appendFile(folderName + '/war.log', new Buffer(req.file.buffer), (err) => {
 | 
				
			||||||
 | 
					          if (err) {
 | 
				
			||||||
 | 
					            next(err);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          exec(__dirname + '/../war-parser/run.sh ' + folderName + ' | tee resource/logs/' + uploadDate + '/score.log'  , (error, stdout, stderr) => {
 | 
				
			||||||
 | 
					            console.log("log")
 | 
				
			||||||
 | 
					            if (error) {
 | 
				
			||||||
 | 
					              return next(error);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            console.log(`stdout: ${stdout}`);
 | 
				
			||||||
 | 
					            console.log(`stderr: ${stderr}`);
 | 
				
			||||||
 | 
					            res.locals.items={};
 | 
				
			||||||
 | 
					            return next();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          // exec(__dirname + '/../war-parser/clean.sh ' + folderName + ' | tee resource/logs/' + uploadDate + '/clean.log' , (error) => {
 | 
				
			||||||
 | 
					          //   if (error) {
 | 
				
			||||||
 | 
					          //     return next(error);
 | 
				
			||||||
 | 
					          //   }
 | 
				
			||||||
 | 
					          //
 | 
				
			||||||
 | 
					          // });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // war.save((err) => {
 | 
				
			||||||
 | 
					      //   if (err) {
 | 
				
			||||||
 | 
					      //     err.status = codes.wrongrequest;
 | 
				
			||||||
 | 
					      //     err.message += ' in fields: ' + Object.getOwnPropertyNames(err.errors);
 | 
				
			||||||
 | 
					      //     return next(err);
 | 
				
			||||||
 | 
					      //   }
 | 
				
			||||||
 | 
					      //   res.status(codes.created);
 | 
				
			||||||
 | 
					      //   res.locals.items = war;
 | 
				
			||||||
 | 
					      //   fs.appendFile(__dirname + '/../resource/squad/' + war.id + '.png', new Buffer(req.file.buffer), (err) => {
 | 
				
			||||||
 | 
					      //     if (err) next(err);
 | 
				
			||||||
 | 
					      //   });
 | 
				
			||||||
 | 
					      //   next();
 | 
				
			||||||
 | 
					      // })
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      const err = new Error('no Logfile provided');
 | 
				
			||||||
 | 
					      err.status = codes.wrongmediasend;
 | 
				
			||||||
 | 
					      next(err);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .all(
 | 
				
			||||||
 | 
					    routerHandling.httpMethodNotAllowed
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// wars.route('/:id')
 | 
				
			||||||
 | 
					//   .get((req, res, next) => {
 | 
				
			||||||
 | 
					//     WarModel.findById(req.params.id, (err, item) => {
 | 
				
			||||||
 | 
					//       if (err) {
 | 
				
			||||||
 | 
					//         err.status = codes.servererror;
 | 
				
			||||||
 | 
					//         return next(err);
 | 
				
			||||||
 | 
					//       }
 | 
				
			||||||
 | 
					//       else if (!item) {
 | 
				
			||||||
 | 
					//         err = new Error("item not found");
 | 
				
			||||||
 | 
					//         err.status = codes.notfound;
 | 
				
			||||||
 | 
					//         return next(err);
 | 
				
			||||||
 | 
					//       }
 | 
				
			||||||
 | 
					//       res.locals.items = item;
 | 
				
			||||||
 | 
					//       next();
 | 
				
			||||||
 | 
					//     });
 | 
				
			||||||
 | 
					//   })
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//   .delete(apiAuthenticationMiddleware, checkHl, (req, res, next) => {
 | 
				
			||||||
 | 
					//     WarModel.findByIdAndRemove(req.params.id, (err, item) => {
 | 
				
			||||||
 | 
					//       if (err) {
 | 
				
			||||||
 | 
					//         err.status = codes.wrongrequest;
 | 
				
			||||||
 | 
					//       }
 | 
				
			||||||
 | 
					//       else if (!item) {
 | 
				
			||||||
 | 
					//         err = new Error("item not found");
 | 
				
			||||||
 | 
					//         err.status = codes.notfound;
 | 
				
			||||||
 | 
					//       }
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//       // delete graphic
 | 
				
			||||||
 | 
					//       fs.unlink(__dirname + '/../resource/squad/' + req.params.id + '.png', (err) => {
 | 
				
			||||||
 | 
					//         if (err) next(err);
 | 
				
			||||||
 | 
					//       });
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//       // we don't set res.locals.items  and thus it will send a 204 (no content) at the end. see last handler user.use(..)
 | 
				
			||||||
 | 
					//       res.locals.processed = true;
 | 
				
			||||||
 | 
					//       next(err); // this works because err is in normal case undefined and that is the same as no parameter
 | 
				
			||||||
 | 
					//     });
 | 
				
			||||||
 | 
					//   })
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//   .all(
 | 
				
			||||||
 | 
					//     routerHandling.httpMethodNotAllowed
 | 
				
			||||||
 | 
					//   );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// this middleware function can be used, if you like or remove it
 | 
				
			||||||
 | 
					// it looks for object(s) in res.locals.items and if they exist, they are send to the client as json
 | 
				
			||||||
 | 
					wars.use(routerHandling.emptyResponse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = wars;
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,7 @@ const awardingRouter = require('./routes/awardings');
 | 
				
			||||||
const requestRouter = require('./routes/request');
 | 
					const requestRouter = require('./routes/request');
 | 
				
			||||||
const signatureRouter = require('./routes/signatures');
 | 
					const signatureRouter = require('./routes/signatures');
 | 
				
			||||||
const commandRouter = require('./routes/command');
 | 
					const commandRouter = require('./routes/command');
 | 
				
			||||||
 | 
					const warRouter = require('./routes/war');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Configuration ***********************************
 | 
					// Configuration ***********************************
 | 
				
			||||||
// mongoose promise setup
 | 
					// mongoose promise setup
 | 
				
			||||||
| 
						 | 
					@ -75,6 +76,7 @@ app.use(urls.ranks, rankRouter);
 | 
				
			||||||
app.use(urls.decorations, decorationRouter);
 | 
					app.use(urls.decorations, decorationRouter);
 | 
				
			||||||
app.use(urls.request, requestRouter);
 | 
					app.use(urls.request, requestRouter);
 | 
				
			||||||
app.use(urls.awards, awardingRouter);
 | 
					app.use(urls.awards, awardingRouter);
 | 
				
			||||||
 | 
					app.use(urls.wars, warRouter);
 | 
				
			||||||
app.use(urls.command, apiAuthenticationMiddleware, checkAdmin, commandRouter);
 | 
					app.use(urls.command, apiAuthenticationMiddleware, checkAdmin, commandRouter);
 | 
				
			||||||
app.use(urls.account, apiAuthenticationMiddleware, checkAdmin, accountRouter);
 | 
					app.use(urls.account, apiAuthenticationMiddleware, checkAdmin, accountRouter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
"use strict"
 | 
					"use strict";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// modules used for graphic manipulation
 | 
					// modules used for graphic manipulation
 | 
				
			||||||
const jimp = require('jimp');
 | 
					const jimp = require('jimp');
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,20 +1,15 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FILE="$1"
 | 
					FILE="$1/war.log"
 | 
				
			||||||
FILTER=("Budget" "Mission" "Abschuss" "Respawn" "Punkte")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
pat=$(echo ${FILTER[@]}|tr " " "|")
 | 
					while IFS='' read -r line || [[ -n "$line" ]]; do
 | 
				
			||||||
 | 
					      case "$line" in
 | 
				
			||||||
 | 
					        *"Budget"* | *"Mission"* | *"Abschuss"* | *"Respawn"* | *"Punkte"*)
 | 
				
			||||||
while IFS= read -r line; do
 | 
					          echo $line;
 | 
				
			||||||
  if [[ $line =~ [^[:space:]] ]]; then
 | 
					 | 
				
			||||||
     RES="$(grep -Ew "$pat" <<< "$line")"
 | 
					 | 
				
			||||||
     if [[ ${RES} =~ [^[:space:]] ]]; then
 | 
					 | 
				
			||||||
       echo ${RES}
 | 
					 | 
				
			||||||
          echo ""
 | 
					          echo ""
 | 
				
			||||||
     fi
 | 
					          ;;
 | 
				
			||||||
  fi
 | 
					      esac
 | 
				
			||||||
done < <(cat ${FILE} )
 | 
					done < ${FILE}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Add OPT Scoreboard
 | 
					# Add OPT Scoreboard
 | 
				
			||||||
while IFS= read -r line; do
 | 
					while IFS= read -r line; do
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,5 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
createScoreboardHeader() {
 | 
					 | 
				
			||||||
    printf "%25s %8s %8s %8s %8s %8s\n" "Name" "Kill" "FF" "Death" "Respawn"
 | 
					 | 
				
			||||||
    echo "---------------------------------------------------------------------------"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
createScoreboard() {
 | 
					createScoreboard() {
 | 
				
			||||||
    NAME="$1"
 | 
					    NAME="$1"
 | 
				
			||||||
    FILE="$2"
 | 
					    FILE="$2"
 | 
				
			||||||
| 
						 | 
					@ -34,14 +29,16 @@ createScoreboard() {
 | 
				
			||||||
      esac
 | 
					      esac
 | 
				
			||||||
    done < <(grep -- "${ESC_NAME}" ${FILE})
 | 
					    done < <(grep -- "${ESC_NAME}" ${FILE})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #echo {\"name\":\"$NAME\", \"kill\":${KILL}, \"ff\":${FF}, \"death\":${DEATH}, \"respawn\":${RESPAWN}},
 | 
					    printf "\t{\"name\":\"$NAME\", \"kill\":${KILL}, \"ff\":${FF}, \"death\":${DEATH}, \"respawn\":${RESPAWN}}"
 | 
				
			||||||
    if [[ $NAME =~ [^[:space:]] ]]; then
 | 
					    if [[ -z ${3} ]]; then
 | 
				
			||||||
        printf "%25s %8s %8s %8s %8s %8s\n" "$NAME" $KILL $FF $DEATH $RESPAWN
 | 
					      printf ",\n"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      printf "\n"
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FILE="$1"
 | 
					FILE="$1/war.log"
 | 
				
			||||||
PLAYERS=()
 | 
					PLAYERS=()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
while IFS='' read -r line || [[ -n "$line" ]]; do
 | 
					while IFS='' read -r line || [[ -n "$line" ]]; do
 | 
				
			||||||
| 
						 | 
					@ -68,10 +65,13 @@ while IFS='' read -r line || [[ -n "$line" ]]; do
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
done < ${FILE}
 | 
					done < ${FILE}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
createScoreboardHeader
 | 
					echo "["
 | 
				
			||||||
 | 
					
 | 
				
			||||||
for i in "${PLAYERS[@]}"
 | 
					for ((i=0; i<${#PLAYERS[*]}; i++));
 | 
				
			||||||
do
 | 
					do
 | 
				
			||||||
   :
 | 
					  if [[ "$((i+1))" -eq "${#PLAYERS[*]}" ]]; then
 | 
				
			||||||
   createScoreboard "$i" ${FILE}
 | 
					    last="true"
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					  createScoreboard "${PLAYERS[i]}" ${FILE} ${last}
 | 
				
			||||||
done
 | 
					done
 | 
				
			||||||
 | 
					echo "]"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue