1'use strict'; 2/** EMIT - Emissions Modeling Inventory Tool 3 * 4 * Chad Meister, BLM CO 2019 5 * BETA (0.2.0) Pub Date: 9/20/2020 6 * JS Entry File: script.js 7 * 8 */ 9 10/** SET ENVIRONMENT VARIABLES */ 11 12var emit = (function() { 13 let _db = new loki('emit'), _fs, _version = '0.2.0', _doc, 14 _user = { logged: false, profile: undefined }, // profile needs to contain sub collections for preferences, theme!! 15 _proj = { projs: [], active: undefined, forms: [], data: undefined, saved: true }, 16 _computed = {}, 17 _map = { admin: undefined, geo: [] }; 18 //_nav; 19 // session log 20 21 let url_1 = 'https://script.google.com/macros/s/AKfycbyAHDySU_Flh8--9PH_MNKiYMn2iZPl88dfEuSqIsg3Y0TZzPw/exec', 22 url_2 = 'https://us-central1-arctic-defender-258123.cloudfunctions.net/'; 23 24 25 /** INITIALIZE FIREBASE & EMIT */ 26 27 // axios({ method: 'get', params: { call: 'config' }, url: url_1 }).then((res) => { 28 // firebase.initializeApp(res.data.config); 29 // _fs = firebase.firestore(); 30 // _db.addCollection('modules').insert(res.data.modules); 31 // _db.addCollection('forms').insert(res.data.forms); 32 // _db.addCollection('lookups').insert(res.data.lookups); 33 // app.setLoading({ val: false }); 34 35 // document.getElementById('title').style.display = 'block'; 36 37 // firebase.auth().onAuthStateChanged((user) => { 38 // console.log('auth state change', user); 39 // if (user) { 40 // axios({ method: 'get', params: { call: 'init' }, url: url_1 }).then((res) => { 41 // for (let n in res.data) { _db.addCollection(n).insert(res.data[n]) } 42 // }).catch((error) => { 43 // alert('Warning: Application initialization failed, please reload the app from the entry link or press F5'); 44 // }).finally(() => { app.setLoading({ val: false }) }); 45 46 // if (user.emailVerified || user.email == '[email protected]') { 47 // _fs.collection('user_data').doc(user.uid).get().then((doc) => { 48 // if (doc.exists) { 49 // _user.profile = { ...doc.data(), _id: user.uid }; 50 // _user.profile['created'] = user.metadata.creationTime; 51 // _user.profile['last_log'] = user.metadata.lastSignInTime; 52 // _user.logged = true; 53 54 // app.$q.notify({ color: 'grey-8', position: 'top', message: 'Please wait for EMIT to finish initialization' }); 55 // router.push('main'); 56 // _fs.collection('user_data').doc(user.uid).update({ log_cnt: ++_user.profile.log_cnt }); 57 58 // if (_user.profile.acct_type == 'external' && _user.profile.govt == true) { 59 // _fs.collection('projects').where('agency_review', '==', true).get().then((docs) => { 60 // docs.forEach(doc => { 61 // _proj.projs.push({ ...doc.data(), _id: doc.id }); 62 // }); 63 // }); 64 // } 65 66 // if (_user.profile.acct_type == 'external') { 67 // let owned = _fs.collection('projects').where('owner', 'in', [firebase.auth().currentUser.uid, 'default']).get().then((docs) => { 68 // return docs; 69 // }); 70 71 // let shared = _fs.collection('projects').where(`shared.${firebase.auth().currentUser.uid}.access_level`, 'in', ['Read-Only', 'Write-Limited', 'Full-Write']).get().then((docs) => { 72 // return docs; 73 // }); 74 75 // Promise.all([owned, shared]).then(results => { 76 // results.forEach(res => { 77 // res.docs.forEach(doc => { 78 // _proj.projs.push({ ...doc.data(), _id: doc.id }); 79 // }); 80 // }); 81 // router.push('modules'); 82 // }).catch(e => { console.log("@promise error", e) }); 83 // } 84 85 // if (_user.profile.acct_type == 'internal' && _user.profile.title != 'Air Resource Specialist') { 86 // _fs.collection('projects').where('field_office', 'in', _user.profile.flds).get().then((docs) => { 87 // docs.forEach(doc => { 88 // _proj.projs.push({ ...doc.data(), _id: doc.id }); 89 // }); 90 // router.push('modules'); 91 // }); 92 93 // } else if (_user.profile.acct_type == 'internal') { setTimeout(() => { router.push('modules') }, 500) } 94 95 // } else { app.$q.notify({ message: 'User data NOT found, contact adminstrator.' }) } 96 97 // }).catch(function(error) { console.log("Error getting user documents: ", error) }); 98 99 // } else { app.$q.notify({ message: 'Please finish the registration process to login' }) } 100 101 // } else { _user.logged = false } 102 // }); 103 104 // // firebase.analytics(); HERE 105 // console.log('fb initialization complete'); 106 107 // }).catch((error) => { alert('Warning: Application initialization failed, please reload the page (press F5) before continuing') }); 108 109 110 111 /** FIREBASE FUNCTIONS */ 112 113 function fire(req) { 114 switch (req.op) { 115 116 case 'register': {
117 app.setLoading({ val: true }); 118 firebase.auth().createUserWithEmailAndPassword(req.user.email, req.user.passcode).then((data) => { 119 120 let { user } = data; 121 if (user) { 122 user.updateProfile({ displayName: req.user.fName }).then(() => { 123 user.sendEmailVerification().catch((error) => { console.error('Email Verification Error', error) }); 124 delete req.user.passcode; 125 126 _fs.collection('user_data').doc(user.uid).set(req.user).then((doc) => { 127 firebase.auth().signOut().then(() => { 128 router.push('/'); 129 app.notify({ title: 'Success', message: 'Verify your email address to finish the registration process!' }); 130 }); 131 }).catch((error) => { console.error("Error Adding Extended Profile Doc: ", error) }); 132 133 }); 134 } 135 }).catch((error) => { console.error("Registration Error: ", error) }); 136 } break; 137 138 case 'sign_in': { 139 console.log('@ sign in'); 140 app.setLoading({ val: true }); 141 firebase.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION).then(() => { 142 143 firebase.auth().signInWithEmailAndPassword(req.username, req.passcode).catch((error) => { 144 // console.log(error) 145 app.notify({ message: "Please verify your credentials" }); 146 app.setLoading({ val: false }); 147 }); 148 149 }).catch((error) => { console.error("Sign in Error: ", error) }); 150 } break; 151 152 case 'reset_passcode': { 153 firebase.auth().sendPasswordResetEmail(req.user).then(() => { 154 app.notify({ message: "Email reset link sent." }); 155 }).catch((error) => { alert("Auth Error:\n" + error); }); 156 app.setLoading({ val: false }); 157 } break; 158 159 case 'create_proj': { 160 _fs.collection('projects').add(req.proj).then((ref) => { 161 162 _fs.collection('projects').doc(ref.id).get().then((doc) => { 163 _proj.projs.push({ ...doc.data(), _id: doc.id }); 164 app.notify({ color: 'positive', textColor: 'grey-2', icon: 'check_circle', position: 'top', message: 'SUCCESS: Project created!' }); 165 req.callback('create', doc.id); 166 }); 167 168 }).catch((error) => { 169 console.error("Error creating project: ", error); 170 app.setLoading({ val: false }); 171 }); 172 } break; 173 174 case 'get_proj': { 175 _proj.active = _proj.projs.filter(proj => proj._id == req.proj_id)[0]; 176 177 _doc = _fs.collection('proj_data').doc(req.proj_id).onSnapshot(doc => { 178 let loaded = (_proj.data) ? true : false; 179 if (doc.exists) { 180 _proj.data = doc.data().vm; 181 _proj.forms = doc.data().forms; 182 183 if (loaded && req.update) { 184 _fs.collection('projects').doc(req.proj_id).update({ 185 access_cnt: ++_proj.active.access_cnt, 186 last_user: firebase.auth().currentUser.email 187 // last access date => NOT functioning server side due to Unix Code translation issues 188 }); 189 } 190 } 191
192 if (!loaded) { loadModule() } 193 app.$eventHub.$emit('update'); 194 }); 195 196 197 } break; 198 199 case 'copy_proj': { 200 _fs.collection('proj_data').doc(req.proj_id).get().then((data) => { 201 if (data.exists) { 202 203 _fs.collection('projects').add(req.proj).then((ref) => { 204 _fs.collection('projects').doc(ref.id).get().then((doc) => { 205 _proj.projs.push({ ...doc.data(), _id: doc.id }); 206 207 _fs.collection('proj_data').doc(ref.id).set({ vm: data.data().vm, forms: data.data().forms }).then(() => { 208 app.notify({ color: 'positive', textColor: 'grey-2', icon: 'done_outline', position: 'top', message: 'SUCCESS: Project data copied!' }); 209 req.callback('copy', ref.id); 210 }); 211 212 }); 213 }); 214 } else { 215 app.notify({ color: 'negative', textColor: 'grey-2', icon: 'close', position: 'bottom', message: 'Error: Cannot copy an empty project!' }); 216 app.setLoading({ val: false }); 217 } 218 }).catch((error) => { 219 console.error("Copy Error: ", error); 220 app.setLoading({ val: false }); 221 }); 222 } break; 223 224 case 'save_proj': { 225 let proj = JSON.parse(JSON.stringify(_proj.data)); 226 let forms = JSON.parse(JSON.stringify(_proj.forms)); 227 228 _fs.collection('proj_data').doc(_proj.active._id).set({ vm: proj, forms: forms }, { merge: true }).then(() => { 229 app.notify({ color: 'positive', textColor: 'grey-2', icon: 'done_outline', position: 'top', message: 'SUCCESS: Project data saved!' }); 230 }).catch((error) => { console.error("Error saving project: ", error) }); 231 } break; 232 233 case 'delete_proj': { 234 _fs.collection('proj_data').doc(req.proj_id).delete().then(() => { 235 236 _fs.collection('projects').doc(req.proj_id).delete().then(() => { 237 for (let n = 0; n < _proj.projs.length; n++) { 238 if (_proj.projs[n]._id == req.proj_id) { _proj.projs.splice(n, 1); break; } 239 } 240 req.callback('delete'); 241 }); 242 243 }).catch((error) => { console.error("Delete Error: ", error) }); 244 } break; 245 246 case 'share_proj': { 247 if (req.type == 'share') { 248 _fs.collection('user_data').where('email', '==', req.share_email).get().then((docs) => { 249 250 docs.forEach((doc) => { 251 let user = doc.data(); 252 if (user.acct_type != 'internal') { 253 _fs.collection('projects').doc(req.proj_id).set({ shared: { [doc.id]: { user_email: req.share_email, access_level: req.access_level } } }, { merge: true }).then(() => { 254 255 _fs.collection('projects').doc(req.proj_id).get().then((doc) => { 256 for (let n = 0; n < _proj.projs.length; n++) { 257 if (_proj.projs[n]._id == doc.id) { _proj.projs.splice(n, 1, { ...doc.data(), _id: doc.id }); break; } 258 } 259 req.callback('admin'); 260 }); 261 262 }); 263 } else { app.notify({ message: 'Internal user sharing is prohibited!' }) } 264 }); 265 266 }).catch((error) => { console.error("Share Error: " + error) }); 267 268 } else { 269 _fs.collection('projects').doc(req.proj_id).update({ [`shared.${req.user}`]: firebase.firestore.FieldValue.delete() }).then(() => { 270 271 _fs.collection('projects').doc(req.proj_id).get().then((doc) => { 272 for (let n = 0; n < _proj.projs.length; n++) { 273 if (_proj.projs[n]._id == doc.id) { _proj.projs.splice(n, 1, { ...doc.data(), _id: doc.id }); break; } 274 } 275 req.callback('admin'); 276 }); 277 278 }); 279 } 280 } break; 281 282 case 'update_proj': { 283 _fs.collection('projects').doc(req.proj_id).update({ [req.fld]: req.val }).then(() => { 284 req.callback('admin'); 285 }).catch((error) => { console.error("Error updating project: ", error) }); 286 } break; 287 288 case 'ars_query': { 289 _fs.collection('projects').where('field_office', '==', req.fld).get().then((docs) => { 290 //console.log('NEW Docs ', docs); 291 docs.forEach(doc => { 292 _proj.projs.push({ ...doc.data(), _id: doc.id }); 293 }); 294 req.callback('hello!'); 295 }); 296 } break; 297 } 298 } 299 300 301 302 /** INITIALIZE VUE.js VARIABLES (APP, EVENTBUS, ROUTER, ETC... ) */ 303 304 const routes = [ 305 { 306 path: '/', component: () => import('./routes/landing.js'), 307 beforeEnter: (to, from, next) => { 308 if (!_user.logged) { next() } 309 } 310 }, 311 { 312 path: '/register', props: { url: url_1 }, component: () => import('./routes/register.js'), 313 beforeEnter: (to, from, next) => { 314 if (!_user.logged) { next() } 315 } 316 }, 317 { path: '/dev', props: { url: url_1 }, component: () => import('./routes/devnotes.js') }, 318 { path: '/faq', props: { url: url_1 }, component: () => import('./routes/faq.js') }, 319 { 320 path: '/main', props: { version: _version }, component: () => import('./routes/main.js'), 321 beforeEnter: (to, from, next) => { 322 if (_user.logged) { next() } 323 }, 324 children: [ 325 //{ path: '/settings', name: 'settings', component: () => import('./routes/settings.js') }, 326 { path: '/modules', name: 'modules', props: { version: _version }, component: () => import('./routes/modules.js') }, // consider killing version here... removing v integrity check!!! 327 { 328 path: '/module', name: 'module', component: () => import(`./modules/${_proj.active.module}.js`), 329 beforeEnter: (to, from, next) => { 330 (_proj.active) ? next() : app.notify({ message: 'Project is NOT loaded, navigation cancelled.' }); 331 }, 332 }, 333 { path: '/emissions', name: 'emissions', component: () => import('./routes/emissions.js') }, 334 { path: '/reports', name: 'reports', props: { url: url_1 }, component: () => import('./routes/reports.js') }, 335 ] 336 }, 337 ]; 338 339 const router = new VueRouter({ routes }); 340 341 router.afterEach((to, from) => { // move to before leave in route? 342 if (from.name == 'module' && _proj.data) { 343 console.log('Updating calculations...'); 344 let calcs = _db.getCollection('fields').find({ 345 '$and': [ 346 { module: _proj.active.module }, 347 { element: 'Calculation' }, 348 { type: { '$ne': 'Emissions' } } 349 ] 350 }); 351 352 calcs.forEach((calc) => { 353 console.log(calc.name); 354 for (let j = 0; j < _proj.data[calc.component].length; j++) { 355 _proj.data[calc.component][j][calc.name] = _computed[c
355alc.name](_proj.data[calc.component][j]); 356 } 357 }); 358 } 359 }); 360 361 362 363 Vue.prototype.$eventHub = new Vue(); 364 const app = new Vue({ 365 el: '#app', 366 router, 367 data() { 368 return {} 369 }, 370 created() { 371 this.$eventHub.$on('loading', this.setLoading); 372 // this.$eventHub.$on('saved', this.setSaved); 373 //console.log(this.$q.dark.isActive) // true, false 374 375 376 }, 377 methods: { 378 setLoading(o) { 379 if (o.val == true) { 380 this.$q.loading.show({ message: o.msg }); 381 } else { 382 this.$q.loading.hide(); 383 this.$q.loadingBar.increment(100); 384 } 385 }, 386 notify(o) { this.$q.notify(o) }, 387 setSaved(val) { _proj.saved = val } 388 }, 389 mounted() { 390 //console.log(Quasar.components); 391 //console.log(Quasar.components.QBtn); 392 //this.$q.dark.set(true) 393 } 394 }); 395 396 397 398 /** STATE & PROPERTY FUNCTIONS */ 399 400 function property(prop, id) { 401 switch (prop) { 402 case 'start-up': return (!_db.getCollection('lookups')) ? true : false; break; // MOVE to bd check!!! 403 case 'acct': return { type: _user.profile.acct_type, govt: _user.profile.govt }; break; 404 case 'profile': return _user.profile; break; 405 case 'init': return (_db.getCollection('modules')) ? true : false; break; // MOVE to bd check!!! 406 case 'projects': return _proj.projs; break; 407 case 'loaded': return (_proj.active) ? true : false; break; 408 case 'proj': return _proj.active; break; 409 case 'module': return _proj.active.module; break; 410 case 'model': return _proj.data; break; 411 case 'forms': return _proj.forms; break; 412 case 'vm': return _proj.data[id]; break; 413 case 'pctFed': return (_proj.data) ? _proj.data['development'][0].pctFed : 0; break; // THIS WILL FAIL IN OTHER MODULES, habndle it?!?!?! 414 case 'map': return _map[id]; break; 415 416 } 417 } 418 419 420 421 /** MODULE FUNCTIONS */ 422 423 function loadModule() { 424 if (_proj.data == undefined) { // NEW Project 425 let model = {}; 426 let forms = query({ typ: 'find', coll: 'forms', q: { module: _proj.active.module } }); 427 428 forms.forEach(function(form) { 429 _proj.forms.push(true); 430 model[form.name] = []; 431 432 let fields = emit.qry({ 433 typ: 'find', coll: 'fields', q: { 434 '$and': [ 435 { module: _proj.active.module }, 436 { component: form.name }, 437 { element: { '$and': [{ '$ne': 'Header' }, { '$ne': 'Button' }] } } 438 ] 439 } 440 }); 441 442 let m = {}; 443 fields.forEach(function(fld) { 444 if (fld.type != 'Emissions') { m[fld.name] = '' } 445 if (fld.element == 'Calculation') { _computed[fld.name] = new Function('o', fld.equation) } 446 }); 447 448 model[form.name].push(m); 449 }); 450 451 _proj.data = model; 452 453 } else { // Re-load of Existing Model Data 454 455 let calcs = emit.qry({ 456 typ: 'find', coll: 'fields', q: { 457 '$and': [ 458 { module: _proj.active.module }, 459 { element: 'Calculation' } 460 ] 461 } 462 }); 463 464 calcs.forEach(calc => { _computed[calc.name] = new Function('o', calc.equation) }); 465 466 467 // This NEEDS to be managed by a Cloud Function!! 468 if (_proj.active.model_version != _version) { // Check Version (two way data integrity control) 469 470 let forms = query({ typ: 'find', coll: 'forms', q: { module: _proj.active.module } }); 471 forms.forEach(function(form) { 472 let fields = emit.qry({ 473 typ: 'find', coll: 'fields', q: { 474 '$and': [ 475 { module: _proj.active.module }, 476 { component: form.name }, 477 { element: { '$and': [{ '$ne': 'Header' }, { '$ne': 'Button' }, { '$ne': 'Query' }] } } 478 ] 479 } 480 }); 481 482 let mFlds = []; 483 fields.forEach(function(fld) { 484 if (fld.type != 'Emissions') { 485 if (_proj.data[form.name][0].hasOwnProperty(fld.name) == false) { 486 if (fld.alias != '') { mFlds.push(fld.alias) } 487 for (let n = 0; n < _proj.data[form.name].length; n++) { 488 _proj.data[form.name][n][fld.name] = (fld.alias) ? _proj.data[form.name][n][fld.alias] : ''; 489 } 490 } 491 } 492 }); 493 }); 494 } 495 } 496 router.push('module'); 497 } 498 499 500 function unloadModule() { 501 router.push('modules'); 502 _doc(); 503 _proj.active = undefined; 504 _proj.forms = []; 505 _proj.data = undefined; 506 _computed = {}; 507 _map.admin = undefined; 508 _map.geo = []; 509 } 510 511 512 function emissions() { 513 if (!_proj.data) { return [] } 514
515 let flds = query({ typ: 'find', coll: 'fields', q: { type: 'Emissions' } }), key = 1, // add module to query { $and : [{ range: 'Emissions' },{ $or : [{ module: this.module},{module: 'all' }] } ]} 516 pols = ['pm10', 'pm25', 'voc', 'nox', 'co', 'so2', 'haps', 'co2', 'ch4', 'n2o', 'co2e'], oEFs, emis = []; 517 518 console.log('Starting emissions compilation'); 519 let calc_start = window.performance.now(); 520 for (let j = 0; j < flds.length; j++) { 521 let model = _proj.data[flds[j].component]; 522 523 for (let k = 0; k < model.length; k++) { 524 if (/^\d+$/.test(flds[j].ref)) { 525 if (Array.isArray(model[k].efs) && model[k].efs.length > 0) { 526 oEFs = model[k].efs[flds[j].ref]; 527 console.log(flds[j].name, oEFs) 528 } else { continue } 529 } else { 530 if (typeof model[k][flds[j].ref] === 'object') { 531 oEFs = model[k][flds[j].ref]; 532 } else { continue } 533 } 534 535 if (model[k][flds[j].def_val] && model[k][flds[j].def_val] != '') { 536 let eName = flds[j].label.split('_') 537 let e = { id: key, name: '', units: flds[j].range, ref: flds[j].desc.split(','), permit: model[k].permit, deps: flds[j].dep }; 538 539 if (eName.length > 1) { 540 if (typeof model[k][eName[1]] === 'object') { 541 e.name = eName[0] + ' - ' + model[k][eName[1]].label; 542 } else { e.name = eName[0] + ' - ' + model[k][eName[1]] } 543 } else { e.name = eName[0] } 544 545 for (let n = 0; n < pols.length; n++) { 546 e[pols[n]] = (oEFs[pols[n]] * emit.calc(flds[j].name, model[k])).toFixed(4); 547 } 548 emis.push(e); 549 key++; 550 } 551 } 552 } 553 554 let calc_end = window.performance.now(); 555 console.log('Calculation runtime: ' + (calc_end - calc_start).toFixed(4) + ' ms'); 556 // if settings showCalcTimes => app.$message.info('Calculation runtime: ' + (calc_end - calc_start).toFixed(4) + ' ms'); 557 return emis; 558 } 559 560 561 562 563 /** DB Functions */ 564 565 function query(qry) { 566 let res, coll; 567 568 switch (qry.typ) { 569 case 'check': return _db.getCollection(qry.coll); break; 570 571 case 'find': 572 res = JSON.stringify(_db.getCollection(qry.coll).find(qry.q)); 573 return JSON.parse(res); 574 break; 575 576 case 'lookup': 577 let lu = _db.getCollection('lookups').findOne(qry.q); 578 if (qry.map) { 579 let ary = lu.data.split(','); 580 return ary.map(item => { return { label: item, value: item } }) 581 } else { 582 return lu.data.split(','); 583 } 584 break; 585 586 case 'replace': 587 coll = _db.getCollection(qry.coll); 588 res = coll.findOne(qry.q); 589 if (res != null) { coll.remove(res.$loki) } 590 coll.insert(qry.doc); 591 break; 592 593 case 'load': // Any subactivity that creates a cusutom loki entry needs to be loaded on the module create hook! 594 coll = _db.getCollection(qry.coll); 595 coll.insert(qry.doc); 596 break; 597 598 case 'add': 599 for (let n in qry.data) { _db.addCollection(n).insert(qry.data[n]) } break; 600 601 } 602 } 603 604 605 606 /** CLOSURE ACCESS */ 607 608 return { 609 recover: function() { resetPass() }, 610 nav: function(route) { (route != -1) ? router.push(route).catch(err => { }) : router.go(-1) }, 611 ajax: function(req) { return request(req) }, 612 getProp: function(prop, id) { return property(prop, id) }, 613 qry: function(qry) { return query(qry) }, 614 fb: function(req) { fire(req) }, 615 fs: function(req) { return fire(req) }, 616 calc: function(prop, vm) { return _computed[prop](vm) }, 617 emis: function() { return emissions() }, 618 619 ifLoaded: function(frame) { templatesLoaded(frame) }, // kill for prod => render fucntion eliminate the need for this 620 eject: function() { unloadModule() }, 621 setMap: function(marks) { _map.geo = marks; console.log('geo =', _map.geo) }, 622 datSize: function() { return _proj.data }, 623 624 log: function(prop) { return _proj.data }, // kill for prod 625 } 626})(); 627 628 629 630 631 632 633/** HELPER FUNCTIONS 634 * 635 * 636 * 637 */ 638
639function getVM(sub, ret_prop, cond_prop, val) { // cond must always match "==" val, should always return a number, returns first match only! 640 let data = emit.getProp('vm', sub); 641 if (cond_prop) { 642 for (let n = 0; n < data.length; n++) { 643 if (data[n][cond_prop] == val) { return Number(data[n][ret_prop]); } 644 } 645 return 0; 646 } else { 647 return data[0][ret_prop]; 648 } 649} 650 651function getVMAry(sub, prop) { 652 let data = emit.getProp('vm', sub), list = []; 653 for (let n = 0; n < data.length; n++) { 654 if (data[n][prop] != '' && data[n][prop] != null) { 655 if (typeof data[n][prop] != 'object') { 656 list.push({ label: data[n][prop], value: data[n][prop] }); 657 } else { 658 list.push(data[n][prop]); 659 } 660 } 661 } 662 return list; 663} 664 665function totalProd(o, target) { 666 let flow, dev = emit.getProp('vm', 'development')[0]; 667 //console.log('@ eur target =', target); 668 //console.log('model =', o); 669 //console.log('dev = ', dev); 670 671 switch (dev.decCurv.value) { 672 case 'Hyperbolic': 673 flow = Number(dev[target]) / Math.pow(1 + 0.51 * dev.nomDec * dev.lop, 1.96078); 674 console.log('flow =', flow); 675 return ((Math.pow(dev[target], 0.51) / (-0.49 * dev.nomDec)) * (Math.pow(flow, 0.49) - Math.pow(dev[target], 0.49)) * o.compWells / 1000); 676 break; 677 case 'Exponential': 678 flow = dev[target] * Math.pow(2.718281828459, -dev.effDec / 100 * dev.lop); 679 console.log('flow =', flow); 680 return (((dev[target] - flow) / (dev.effDec / 100)) * o.compWells / 1000); 681 break; 682 case 'Harmonic': 683 flow = dev[target] / (1 + dev.nomDec * dev.lop); 684 console.log('flow =', flow); 685 return ((dev[target] / dev.nomDec * Math.log(dev[target] / flow)) * o.compWells / 1000); 686 break; 687 default: return NaN; 688 } 689} 690 691function calcGOR(o) { 692 if (o.api && o.dump) { 693 if (o.api < 30) { 694 return (0.459524 * o.dump + 8.071429); 695 } else if (o.api >= 30 && o.api < 40) { 696 return (0.801190 * o.dump + 11.821429); 697 } else { // api is > 40 698 return (1.119048 * o.dump + 14.642857); 699 } 700 } else { return 0 } 701} 702 703 704function sumAry(ary) { // could combine above with VM 705 let val = 0; 706 for (let x = 0; x < ary.length; x++) { 707 if (ary[x] != '') { val += Number(ary[x]) } 708 } 709 return val; 710} 711 712 713function mapVMAry(model, fn) { 714 let m = emit.getProp('vm', model); 715 return m.map(fn); 716} 717 718function sumVMAry(model, prop, cntNull) { 719 let m = emit.getProp('vm', model); 720 if (prop) { 721 let val = 0; 722 for (let i = 0; i < m.length; i++) { 723 if (cntNull) { 724 val += (m[i][prop] != '') ? Number(m[i][prop]) : 1; 725 } else { 726 if (m[i][prop] != '') { val += Number(m[i][prop]) } 727 } 728 } 729 return val; 730 } else { return m.length } 731} 732 733 734function exportTable(csv, filename) { 735 let csvFile = new Blob([csv], { type: "text/csv" }); 736 let dlLink = document.createElement("a"); 737 dlLink.download = filename; 738 dlLink.href = window.URL.createObjectURL(csvFile); 739 dlLink.click(); 740 window.URL.revokeObjectURL(dlLink.href); 741} 742 743function switchAry(val, op, ary) { 744 let aLen = ary.length / 2; 745 for (let pos = 0; pos < ary.length; pos++) { 746 switch (op) { 747 case '=': if (ary[pos] == val) { return ary[Number(pos + aLen)] } break; 748 case '>': if (Number(val) > Number(ary[pos])) { return ary[Number(pos + aLen)] } break; 749 case '<': if (Number(val) < Number(ary[pos])) { return ary[Number(pos + aLen)] } 750 } 751 } 752} 753 754function aryMax(arr) { //maxAry 755 let max = arr.reduce(function(a, b) { 756 return Math.max(a, b); 757 }); 758 return max; 759} 760 761/* 762function decline(typ, yr) { 763 if (typ == 'Exponential') { 764 return 114 * Math.pow(Math.E, -0.117 * yr); 765 } else { // hyperbolic 766 return 56.652 * Math.pow(yr, -0.963); 767 } 768} 769*/ 770 771 772 773 774 775 776 777 778 779function memorySizeOf(obj) { 780 var bytes = 0; 781 782 function sizeOf(obj) { 783 if (obj !== null && obj !== undefined) { 784 switch (typeof obj) { 785 case 'number': 786 bytes += 8; 787 break; 788 case 'string': 789 bytes += obj.length * 2; 790 break; 791 case 'boolean': 792 bytes += 4; 793 break; 794 case 'object': 795 var objClass = Object.prototype.toString.call(obj).slice(8, -1); 796 if (objClass === 'Object' || objClass === 'Array') { 797 for (var key in obj) { 798 if (!obj.hasOwnProperty(key)) continue; 799 sizeOf(obj[key]); 800 } 801 } else bytes += obj.toString().length * 2; 802 break; 803 } 804 } 805 return bytes; 806 }; 807 808 function formatByteSize(bytes) { 809 if (bytes < 1024) return bytes + " bytes"; 810 else if (bytes < 1048576) return (bytes / 1024).toFixed(3) + " KiB"; 811 else if (bytes < 1073741824) return (bytes / 1048576).toFixed(3) + " MiB"; 812 else return (bytes / 1073741824).toFixed(3) + " GiB"; 813 }; 814 815 return formatByteSize(sizeOf(obj)); 816};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.