/* ---------------------------------------------------------------------------- Question Server GitLab: This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ------------------------------------------------------------------------- */ module.exports = { ProcessIncomingRequest: ProcessIncomingRequest, CheckData: CheckData, NLoad: NLoad, LoadJSON: LoadJSON, ProcessQA: ProcessQA } const staticFile = './public/data/static' const dataFile = './public/data.json' const recDataFile = './stats/recdata' const versionFile = './public/version' const motdFile = './public/motd' const qaFile = './public/qa' var logger = require('../utils/logger.js') var utils = require('../utils/utils.js') class Question { constructor (q, a, i) { this.Q = q this.A = a this.I = i } toString () { var r = '?' + this.Q + '\n!' + this.A if (this.I) { r += '\n>' + this.I } return r } HasQuestion () { return this.Q !== undefined } HasAnswer () { return this.A !== undefined } HasImage () { return this.I !== undefined } IsComplete () { return this.HasQuestion() && this.HasAnswer() } Compare (q2, i) { if (typeof q2 === 'string') { var qmatchpercent = Question.CompareString(this.Q, q2) if (i == undefined || i.length == 0) { return qmatchpercent } else { if (this.HasImage()) { const imatchpercent = this.HasImage() ? Question.CompareString(this.I.join(' '), i.join(' ')) : 0 return (qmatchpercent + imatchpercent) / 2 } else { qmatchpercent -= 30 if (qmatchpercent < 0) { return 0 } else { return qmatchpercent } } } } else { const qmatchpercent = Question.CompareString(this.Q, q2.Q) const amatchpercent = Question.CompareString(this.A, q2.A) if (this.I !== undefined) { const imatchpercent = this.I === undefined ? Question.CompareString(this.I.join(' '), q2.I.join( ' ')) : 0 return (qmatchpercent + amatchpercent + imatchpercent) / 3 } else { return (qmatchpercent + amatchpercent) / 2 } } } // static CompareString (s1, s2) { // // if (s1 == undefined || s2 == undefined) // // return 0; // s1 = SimplifyStringForComparison(s1).split(' ') // s2 = SimplifyStringForComparison(s2).split(' ') // var match = 0 // for (var i = 0; i < s1.length; i++) { // if (s2.includes(s1[i])) { match++ } // } // var percent = Math.round(((match / s1.length) * 100).toFixed(2)) // matched words percent // var lengthDifference = Math.abs(s2.length - s1.length) // percent -= lengthDifference * 3 // if (percent < 0) { percent = 0 } // return percent // } } class Subject { constructor (n) { this.Name = n this.Questions = [] } get length () { return this.Questions.length } AddQuestion (q) { this.Questions.push(q) } Search (q, img) { const minMatchAmmount = 90 var r = [] for (let i = 0; i < this.length; i++) { let percent = this.Questions[i].Compare(q, img) if (percent > minMatchAmmount) { r.push({ q: this.Questions[i], match: percent }) } } for (let i = 0; i < r.length; i++) { for (var j = i; j < r.length; j++) { if (r[i].match < r[j].match) { var tmp = r[i] r[i] = r[j] r[j] = tmp } } } return r } toString () { var r = [] for (var i = 0; i < this.Questions.length; i++) { r.push(this.Questions[i].toString()) } return '+' + this.Name + '\n' + r.join('\n') } } class QuestionDB { constructor () { this.Subjects = [] } get length () { return this.Subjects.length } // get activeIndexes () { // var r = [] // for (var i = 0; i < this.length; i++) { // if (GM_getValue('Is' + i + 'Active')) { // r.push(i) // } // } // return r // } // GetIfActive (ind) { // return GM_getValue('Is' + ind + 'Active') // } // ChangeActive (i, value) { // GM_setValue('Is' + i + 'Active', !!value) // } AddQuestion (subj, q) { var i = 0 while (i < this.Subjects.length && this.Subjects[i].Name !== subj) { i++ } if (i < this.Subjects.length) { this.Subjects[i].AddQuestion(q) } else { const n = new Subject(subj) n.AddQuestion(q) this.Subjects.push(n) } } Search (q, img) { var r = [] for (let i = 0; i < this.length; i++) { if (this.GetIfActive(i)) { r = r.concat(this.Subjects[i].Search(q, img)) } } for (let i = 0; i < r.length; i++) { for (var j = i; j < r.length; j++) { if (r[i].match < r[j].match) { var tmp = r[i] r[i] = r[j] r[j] = tmp } } } return r } AddSubject (subj) { var i = 0 while (i < this.length && subj.Name !== this.Subjects[i].Name) { i++ } if (i < this.length) { this.Subjects.concat(subj.Questions) } else { this.Subjects.push(subj) } } toString () { var r = [] for (var i = 0; i < this.Subjects.length; i++) { r.push(this.Subjects[i].toString()) } return r.join('\n\n') } } function Process (d, file) { try { logger.Log('File: ' + file) if (d.data.split('\n').length > 1) { var oldFile = utils.ReadFile(file) var newFile = oldFile + '\n' if (d.data[0] === '+') { newFile += d.data } else { newFile += '+' + d.data } var newRes = CheckData(newFile) var oldRes = CheckData(oldFile) if (oldRes.count > 0) { logger.Log('\t\told public result: ' + oldRes.count, logger.GetColor('blue')) } else { logger.Log('\t\told public NLOD error, ' + oldRes.log, logger.GetColor('redbg'), true) } if (newRes.count > 0) { logger.Log('\t\tnew file result: ' + newRes.count, logger.GetColor('blue')) } else { logger.Log('\t\tnew file NLOD error, ' + newRes.log, logger.GetColor('redbg'), true) } utils.WriteFile(newFile, file) logger.Log('\t\tNew data written to: ' + file) return newRes.count - oldRes.count } else { logger.Log('\t\tNo new data') } } catch (e) { logger.Log('\tError at processing data! File: ' + file, logger.GetColor('redbg')) logger.Log(e.toString(), logger.GetColor('redbg')) } return -1 } function ProcessIncomingRequest (data) { if (data === undefined) { logger.Log('\tRecieved data is undefined!', logger.GetColor('redbg')) return } try { let towrite = logger.GetDateString() + '\n' towrite += '------------------------------------------------------------------------------\n' towrite += data towrite += '\n------------------------------------------------------------------------------\n' utils.AppendToFile(towrite, recDataFile) } catch (e) { logger.log('Error writing recieved data.') } try { var d = JSON.parse(data) var dfile = utils.ReadFile(dataFile) data = LoadJSON(dfile) var allQuestions = [] for (let i = 0; i < d.allData.length; i++) { allQuestions.push(new Question(d.allData[i].Q, d.allData[i].A, d.allData[i].I)) } var questions = [] for (let i = 0; i < d.data.length; i++) { let q = new Question(d.data[i].Q, d.data[i].A, d.data[i].I) questions.push(q) data.AddQuestion(d.subj, q) } logger.Log('\t' + d.subj) var msg = 'All / new count: ' + allQuestions.length + ' / ' + questions.length if (d.version !== undefined) { msg += '. Version: ' + d.version } var color = logger.GetColor('green') try { data.version = utils.ReadFile(versionFile) data.motd = utils.ReadFile(motdFile) } catch (e) { logger.Log('MOTD/Version writing/reading error!') } if (data !== undefined && d.data.length > 0) { utils.WriteBackup() utils.WriteFile(JSON.stringify(data), dataFile) msg += ' - Data file written!' color = logger.GetColor('blue') } logger.Log('\t' + msg, color) } catch (e) { logger.Log('Couldnt parse JSON data, trying old format...', logger.GetColor('redbg')) d = SetupData(data) var qcount = -1 try { var splitted = d.alldata.split('\n') var count = 0 for (var i = 0; i < splitted.length; i++) { if (splitted[i][0] === '?') { count++ } } qcount = count } catch (e) { console.log('Error :c'); console.log(e) } logger.Log('\tProcessing data: ' + d.subj + ' (' + d.type + '), count: ' + qcount, logger.GetColor('green')) if (d.subj === undefined) { logger.Log(JSON.stringify(d), logger.GetColor('red')) return } var newStatItems = Process(d, staticFile) PrintNewCount(d, newStatItems, staticFile) } } function PrintNewCount (d, newItems, file) { if (newItems > 0) { var count = 0 var splitted = d.alldata.split('\n') for (var i = 0; i < splitted.length; i++) { if (splitted[i].startsWith('?')) { count++ } } logger.Log('\t' + file + ' All / New: ' + count + ' / ' + newItems, logger.GetColor('cyan')) } } function SetupData (data) { var pdata = data.split('<#>') if (pdata.length <= 0) { logger.Log('Data length is zero !', logger.GetColor('redbg')) throw 'No data recieved!' } var d = {} // parsed data for (var i = 0; i < pdata.length; i++) { var td = pdata[i].split('<=>') if (td.length === 2) { d[td[0]] = td[1] } else { logger.Log('Invalid parameter!', logger.GetColor('redbg')) throw 'Invalid parameter recieved!' } } return d } function CheckData (data) { try { var presult = NLoad(data) return presult } catch (e) { logger.Log('Load error, ' + e.toString(), logger.GetColor('redbg'), true) return { count: -1, log: [e.toString()] } } } function NLoad (resource) { var resultLog = [] var allCount = 0 if (resource === undefined) { throw 'A megadott adat undefined!' } resource = resource.split('\n') // splitting by enters if (resource.length === 1) { throw 'A megadott adat nem sorokból áll!' } var data = [] // initializing data declared at the begining function AddNewSubj (name) { data.push({ 'questions': [] }) // ads aa new object, with an empty array in it GetCurrSubj().name = name // sets the name for it GetCurrSubj().count = 0 // setting count to default // setting if its active only if its undefined, otherwise previous user setting shouldt be overwritten } function AddItem () // adds an item to the last subjects questions { GetCurrSubj().count++ allCount++ // incrementing all count GetCurrSubj().questions.push({}) // adding a new empty object to the last item in the data } function GetLastItem () // returns the last item of the last item of data { var q = GetCurrSubj().questions.length // questions length return GetCurrSubj().questions[q - 1] } function GetCurrSubj () { return data[data.length - 1] } // ? : question // ! : answer // > : image JSON data // + : subject name // checking for name for (var j = 0; j < resource.length; j++) // goes through resources { if (resource[j][0] == '+') // if there is a name identifier { break // breaks, couse there will be a name } if (resource[j][0] == '?' || resource[j][0] == '!' || resource[j][0] == '>') // if it begins with another identifier: { AddNewSubj('NONAME') // there is no name (for the first question at least), so setting it noname. break } // else it does nothing, continues to check } var jumped = 0 // the amount of lines it processed for (var i = 0; i < resource.length; i += jumped) // gouing through the resource { jumped = 0 // resetting it to 0 var currRawDataQ = resource[i] // current question var currRawDataA = resource[i + 1] // current answer var currRawDataI = resource[i + 2] // current image if (currRawDataQ != undefined && currRawDataQ[0] == '?' && currRawDataA != undefined && currRawDataA[0] == '!') // if the current line is ? and the next is ! its a data { AddItem() GetLastItem().q = currRawDataQ.substr(1) GetLastItem().a = currRawDataA.substr(1) jumped += 2 if (currRawDataI != undefined && currRawDataI[0] == '>') { GetLastItem().i = currRawDataI.substr(1) jumped++ } } else if (currRawDataQ[0] == '+') // if its a new subject { AddNewSubj(currRawDataQ.substr(1)) jumped++ } else { // this should be invalid question order resultLog.push('Warning @ line ' + i + ':' + currRawDataQ + ' ' + currRawDataA + ' ' + currRawDataI) jumped++ } } // end of parsing all data return { count: allCount, log: resultLog } } // loading stuff function LoadJSON (resource) { var count = -1 try { var d = JSON.parse(resource) var r = new QuestionDB() var rt = [] var allCount = -1 for (var i = 0; i < d.Subjects.length; i++) { let s = new Subject(d.Subjects[i].Name) var j = 0 for (j = 0; j < d.Subjects[i].Questions.length; j++) { var currQ = d.Subjects[i].Questions[j] s.AddQuestion(new Question(currQ.Q, currQ.A, currQ.I)) } rt.push({ name: d.Subjects[i].Name, count: j }) allCount += j r.AddSubject(s) } return r } catch (e) { logger.Log('Error loading sutff', logger.GetColor('redbg'), true) } } function ProcessQA () { if (!utils.FileExists(qaFile)) { utils.WriteFile('', qaFile) } let a = utils.ReadFile(qaFile).split('\n') let r = [] let ind = 0 for (let i = 0; i < a.length; i++) { if (a[i] == '#') { ind++ } else { if (r[ind] == undefined) { r[ind] = {} } if (r[ind].q == undefined) { r[ind].q = a[i] } else { if (r[ind].a == undefined) { r[ind].a = [] } r[ind].a.push(a[i]) } } } return r }