List of commits:
Subject Hash Author Date (UTC)
Apparently updating addresses works, as long as you don't ask for more than 10 per minute. That seems to be working so far. 9276b2acb2cc3067c53fc16317a8960db3f6fcca Luigi Bai 2020-09-08 22:44:24
More information about how to use the software. Not much, yet. Enough to get started, I think. 393fce58bbcfeaee947cb2b0e17d81d16da49612 Luigi Bai 2020-09-08 22:31:02
Don't write to console.err if there's a rejectionFunction. 630b8ec76a21733a6bb93d98ca54563aadd61da4 Luigi Bai 2020-09-08 22:30:29
Remove trailing comma on all rows. e7605fa152a841eefc7fcab6bb7cfd64daf28b17 Luigi Bai 2020-09-07 22:43:36
Allow passing in query for Case.sqlAllCases() 346862c0720ef9054426048cc95caa8f6b068868 Luigi Bai 2020-09-07 22:43:09
This version works in MS-SQL. 4e3f33f464173c91c3f4ac4b6acb0235ed2d6720 Luigi Bai 2020-09-07 19:11:54
Add headers. 4da1ccbdb2e3e852050de3460bc9ac9ba061ed7a Luigi Bai 2020-09-07 16:28:52
loadDockets now works to local. 96ba8f7419f63be6612fe1efd3e24d5d30eaf20a Luigi Bai 2020-09-06 20:59:06
Fix for new column names. 5791d77e19585c494e51c6062ab45440e5af0903 Luigi Bai 2020-09-06 20:44:50
Add headers 32cb7264c06b28dc0404b715f24fd2d82b66633b Luigi Bai 2020-09-06 20:44:29
Have a working version of xfer - now transfers data to MS SQL Server from SQLITE3. 428e493bcc5b7f718a741db046d08905f47d0f1c Luigi Bai 2020-09-05 22:11:55
Stupid MS SQL Server assumes case insensitive collation for text/char columns. Who does that? 2700846d8c1233d27664fb74b582293ddb8cb32a Luigi Bai 2020-09-05 21:11:17
Fixed MS schema - 4096 too big for varchar. ca3870f7e244d83e58d74c7f231baacbc19ba8fa Luigi Bai 2020-09-04 17:04:05
Remove interstitial console.log 19481f6692d9f93e75aa173bee9716261ef54db0 Luigi Bai 2020-09-04 12:07:33
Added license/copyright info. Added shim for Promise. Rewrote xferData with await and shim. 3930998d32fb2a19239e63b1b07bf1804c7ea46e Luigi Bai 2020-09-04 12:04:32
Fixed a typo. Ugh. 64718362e042d4a987d3161f999de087edb7bc8a Luigi Bai 2020-09-04 03:59:37
Must have an example of the creds.js file to learn from. 13d0e75c21bf8194c53e148e37cc6f85d8152de3 Luigi Bai 2020-09-04 03:59:16
Transfer local data to cloud based MS SQL-Server database. 8035b6dac5ce05ced62474409ab46ca490a6db4a Luigi Bai 2020-09-04 03:50:32
Learned that package-lock.json should also be committed. 20222232bd2e5388b76d3330e6f695b5aacfe393 Luigi Bai 2020-09-03 11:04:05
Fixed SPDX license expression. c894ba842750ff63035c850095ac93399495f4bc Luigi Bai 2020-09-03 11:01:27
Commit 9276b2acb2cc3067c53fc16317a8960db3f6fcca - Apparently updating addresses works, as long as you don't ask for more than 10 per minute. That seems to be working so far.
Author: Luigi Bai
Author date (UTC): 2020-09-08 22:44
Committer name: Luigi Bai
Committer date (UTC): 2020-09-08 22:44
Parent(s): 393fce58bbcfeaee947cb2b0e17d81d16da49612
Signer:
Signing key:
Signing status: N
Tree: b9091470b18c60d5e1578a70ba85deac1c7bc7bc
File Lines added Lines deleted
lib/OdysseyInfo.class.js 105 181
updateAddress.js 44 24
File lib/OdysseyInfo.class.js changed (mode: 100644) (index 8580a15..741a005)
... ... const hp = require("htmlparser2");
24 24 const DomHandler = require("domhandler").DomHandler; const DomHandler = require("domhandler").DomHandler;
25 25 const du = require("domutils"); const du = require("domutils");
26 26
27 /*
28 function postURLData(oiObj, reqPath, data, cb) {
29 let opts = new httpOpts();
30 opts.host = "odysseyportal.harriscountytx.gov";
31 opts.path = reqPath;
32 opts.method = "POST";
33 opts.headers["content-type"] = "application/x-www-form-urlencoded";
34 oiObj.referURL && (opts.headers["referer"] = oiObj.referURL);
35
36 let reqURL = opts.protocol+"//"+opts.host+reqPath;
37 opts.headers["cookie"] = oiObj.jar.getSetCookieStringsSync(reqURL);
38
39 oiObj.debug && console.log(opts);
40 oiObj.debug && console.log(reqURL);
41
42 // With the data all set up, now connect and parse:
43 let req = https.request(opts, (res) => {
44 oiObj.debug && console.log(res.headers);
45 res.headers["set-cookie"] && res.headers["set-cookie"].map((cookie) => { oiObj.jar.setCookieSync(cookie, reqURL); });
46
47 // What to do with incoming data:
48 let doc = "";
49 res.on("data", (d) => {
50 oiObj.verbose && console.log("postURLData", d.toString());
51 doc = doc + d;
52 }).on("end", () => {
53 oiObj.referURL = reqURL;
54 cb(doc);
55 });
56
57 });
58
59 req.on('error', (e) => {
60 console.error(reqURL, e);
61 });
62
63 let us = new URLSearchParams(data);
64 oiObj.debug && console.log("data: ", us.toString());
65 req.write(us.toString());
66
67 // Ok GO:
68 req.end();
69 };
70
71 function getURL(oiObj, argv) {
72 if (!argv.requestPath) {
73 throw new Error("Must include a request path.");
74 }
75
76 let opts = new httpOpts();
77 opts.protocol = "https:";
78 opts.host = "odysseyportal.harriscountytx.gov";
79 opts.path = argv.requestPath;
80 opts.method = "GET";
81 oiObj.referURL && (opts.headers["referer"] = oiObj.referURL);
82
83 let reqURL = opts.protocol+"//"+opts.host+"/"+argv.requestPath;
84 opts.headers["cookie"] = oiObj.jar.getSetCookieStringsSync(reqURL);
85
86 oiObj.debug && console.log(opts);
87 oiObj.debug && console.log(reqURL);
88
89 // With the data all set up, now connect and parse:
90 let req = https.request(opts, (res) => {
91 oiObj.debug && console.log(res.headers);
92 res.headers["set-cookie"] && res.headers["set-cookie"].map((cookie) => { oiObj.jar.setCookieSync(cookie, argv.requestURL); });
93
94 // What to do with incoming data:
95 let doc = "";
96 res.on("data", (d) => {
97 oiObj.verbose && console.log("getURL", d.toString());
98 if (argv.parser) {
99 argv.parser.parseChunk(d);
100 } else {
101 doc = doc + d;
102 }
103 }).on("end", () => {
104 oiObj.referURL = argv.requestURL;
105 argv.parser && argv.parser.done();
106 argv.callback && argv.callback(doc);
107 });
108
109 });
110
111 req.on('error', (e) => {
112 console.error(reqURL, e);
113 });
114
115 // Ok GO:
116 req.end();
117 };
118 */
119
120 function getCaseIDParser(oiObj, callback) {
27 function getCaseIDParser(oiObj, callback, errFN) {
121 28 // <a class="caseLink" data-caseid="jBTdKQrus6pMdAW2SPPMBA2" data-caseid-num="6402180">205100178940</a> // <a class="caseLink" data-caseid="jBTdKQrus6pMdAW2SPPMBA2" data-caseid-num="6402180">205100178940</a>
122 29 let handler = new DomHandler((err, dom) => { let handler = new DomHandler((err, dom) => {
123 30 if (err) { if (err) {
124 console.error("caseIDParser", err);
31 errFN && "function" === typeof errFN && errFN({ msg: "caseIDParser", err: err });
125 32 } else { } else {
126 33 // Find the containing node: // Find the containing node:
127 34 let idLinks = du.filter((node) => { let idLinks = du.filter((node) => {
 
... ... function getCaseIDParser(oiObj, callback) {
129 36 }, dom); }, dom);
130 37
131 38 if (1 !== idLinks.length) { if (1 !== idLinks.length) {
132 throw new Error("Unable to find caseID.");
39 errFN && "function" === typeof errFN && errFN({ msg: "caseIDParser: unable to find caseID", html: du.getOuterHTML(dom) });
133 40 } }
134 41
135 oiObj.caseID = idLinks[0].attribs["data-caseid"];
136
137 // Now use the callback to process the hrefs:
138 (callback && "function" === typeof callback) && callback();
42 try {
43 oiObj.caseID = idLinks[0].attribs["data-caseid"];
44 oiObj.caseURL = idLinks[0].attribs["data-url"];
45 if (!oiObj.caseURL && oiObj.debug) {
46 console.log("Can't find data-URL", idLinks[0], oiObj);
47 }
48 // Now use the callback to process the hrefs:
49 (callback && "function" === typeof callback) && callback();
50 } catch (e) {
51 console.error(e, idLinks);
52 }
139 53 }; };
140 54 }, { }, {
141 55 normalizeWhitespace: true normalizeWhitespace: true
 
... ... function getCaseIDParser(oiObj, callback) {
144 58 return new hp.Parser(handler); return new hp.Parser(handler);
145 59 }; };
146 60
147 function getCaseInfoParser(oiObj, callback) {
61 function getCaseInfoParser(oiObj, callback, errFN) {
148 62 // <a class="caseLink" data-caseid="jBTdKQrus6pMdAW2SPPMBA2" data-caseid-num="6402180">205100178940</a> // <a class="caseLink" data-caseid="jBTdKQrus6pMdAW2SPPMBA2" data-caseid-num="6402180">205100178940</a>
149 63 let handler = new DomHandler((err, dom) => { let handler = new DomHandler((err, dom) => {
150 64 if (err) { if (err) {
151 console.error("caseIDParser", err);
65 errFN && "function" === typeof errFN && errFN({ msg: "caseInfoParser", err: err });
152 66 } else { } else {
67 oiObj.debug && console.log("Finding party info");
68
153 69 // Find the containing node: // Find the containing node:
154 70 let partyInfo = du.filter((node) => { let partyInfo = du.filter((node) => {
155 71 return ("div" === node.name && "divPartyInformation_body" === node.attribs.id); return ("div" === node.name && "divPartyInformation_body" === node.attribs.id);
156 72 }, dom); }, dom);
157 73
158 74 if (1 !== partyInfo.length) { if (1 !== partyInfo.length) {
159 throw new Error("Unable to find party info.");
75 errFN && "function" === typeof errFN && errFN({ msg: "caseIDParser: unable to find party info", oi: oiObj });
160 76 } }
161 77
162 78 // Each party is in a <div class="col-md-8"/> // Each party is in a <div class="col-md-8"/>
 
... ... function getCaseInfoParser(oiObj, callback) {
165 81 }, partyInfo); }, partyInfo);
166 82
167 83 // Each of those has a <p><span>class</span>name</p> and <p>Address</p>: // Each of those has a <p><span>class</span>name</p> and <p>Address</p>:
168 this.parties = [];
84 oiObj.parties = [];
169 85 partyDivs.forEach((partyDiv) => { partyDivs.forEach((partyDiv) => {
170 86 let party = {}; let party = {};
171 87 let pDivs = du.filter((node) => { let pDivs = du.filter((node) => {
 
... ... function getCaseInfoParser(oiObj, callback) {
198 114 return val.data; return val.data;
199 115 }); });
200 116
201 this.parties.push(party);
117 oiObj.parties.push(party);
202 118 }); });
203 119
204 120 // Now do the callback: // Now do the callback:
205 (callback && "function" === typeof callback) && callback(oiObj.parties);
121 callback && "function" === typeof callback && callback(oiObj.parties);
206 122 }; };
207 123 }, { }, {
208 124 normalizeWhitespace: true normalizeWhitespace: true
 
... ... function getCaseInfoParser(oiObj, callback) {
210 126
211 127 return new hp.Parser(handler); return new hp.Parser(handler);
212 128 }; };
213
129
214 130 module.exports = class OdysseyInfo { module.exports = class OdysseyInfo {
215 131 constructor(caseNumber, argv) { constructor(caseNumber, argv) {
216 132 if (! caseNumber) { if (! caseNumber) {
217 133 throw new Error("Must define a case number!"); throw new Error("Must define a case number!");
218 134 } }
219 135 let opts = argv || {}; let opts = argv || {};
220 this.caseNum = caseNumber;
136 this.caseNumber = caseNumber;
221 137 this.debug = opts.debug; this.debug = opts.debug;
138 this.verbose = opts.verbose;
222 139 }; };
223 140
224 findCase(cb) {
225 let host = "odysseyportal.harriscountytx.gov";
226 let hc = new HTTPConversation();
227
228 hc.getURL({ reqHost: host, reqPath: "/OdysseyPortalJP", callback: () => {
229 hc.getURL({ reqHost: host, reqPath: "/OdysseyPortalJP/Home/Dashboard/29", callback: () => {
230 hc.postURLData({
231 reqHost: host,
232 reqPath: "/OdysseyPortalJP/SmartSearch/SmartSearch/SmartSearch",
233 data: [
234 [ "Settings.CaptchaEnabled", "False" ],
235 [ "Settings.CaptchaDisabledForAuthenticated", "False" ],
236 [ "caseCriteria.SearchCriteria", this.caseNum ],
237 [ "caseCriteria.JudicialOfficerSearchBy", "" ],
238 [ "caseCriteria.NameMiddle", "" ],
239 [ "caseCriteria.NameSuffix", "" ],
240 [ "caseCriteria.AdvancedSearchOptionsOpen", "false" ],
241 [ "caseCriteria.CourtLocation_input", "Harris County JPs Odyssey Portal" ],
242 [ "caseCriteria.CourtLocation", "Harris County JPs Odyssey Portal" ],
243 [ "caseCriteria.SearchBy_input", "Smart Search" ],
244 [ "caseCriteria.SearchBy", "SmartSearch" ],
245 [ "caseCriteria.SearchCases", "true" ],
246 [ "caseCriteria.SearchCases", "false" ],
247 [ "caseCriteria.SearchJudgments", "true" ],
248 [ "caseCriteria.SearchJudgments", "false" ],
249 [ "caseCriteria.SearchByPartyName", "true" ],
250 [ "caseCriteria.SearchByNickName", "false" ],
251 [ "caseCriteria.SearchByBusinessName", "false" ],
252 [ "caseCriteria.UseSoundex", "false" ],
253 [ "caseCriteria.Gender_input", "" ],
254 [ "caseCriteria.Gender", "" ],
255 [ "caseCriteria.Race_input", "" ],
256 [ "caseCriteria.Race", "" ],
257 [ "caseCriteria.FBINumber", "" ],
258 [ "caseCriteria.SONumber", "" ],
259 [ "caseCriteria.BookingNumber", "" ],
260 [ "caseCriteria.CaseType_input", "" ],
261 [ "caseCriteria.CaseType", "" ],
262 [ "caseCriteria.CaseStatus_input", "" ],
263 [ "caseCriteria.CaseStatus", "" ],
264 [ "caseCriteria.FileDateStart", "" ],
265 [ "caseCriteria.FileDateEnd", "" ],
266 [ "caseCriteria.JudicialOfficer_input", "" ],
267 [ "caseCriteria.JudicialOfficer", "" ],
268 [ "caseCriteria.JudgmentType_input", "" ],
269 [ "caseCriteria.JudgmentType", "" ],
270 [ "caseCriteria.JudgmentDateFrom", "" ],
271 [ "caseCriteria.JudgmentDateTo", "" ]
272 ],
273 callback: () => {
274 hc.getURL({ reqHost: host, reqPath: "/OdysseyPortalJP/Home/WorkspaceMode?p=0", callback: () => {
275 setTimeout(() => {
276 hc.getURL({
277 reqHost: host,
278 reqPath: "/OdysseyPortalJP/SmartSearch/SmartSearchResults?_="+(new Date()).valueOf(),
279 parser: getCaseIDParser(this, () => {
280 this.debug && console.log("CaseID: ", this.caseID);
281 hc.getURL({
282 reqHost: host,
283 reqPath: "/OdysseyPortalJP/Case/CaseDetail?eid="+this.caseID+"&tabIndex=3&_="+(new Date()).valueOf(),
284 parser: getCaseInfoParser(this, (info) => {
285 if (cb && "function" === typeof cb) {
286 cb(this);
287 } else {
288 console.log(this);
289 }
290 })
291 });
292 })
293 });
294 }, 1000);
141 findCasePromise() {
142 return new Promise((resFN, rejFN) => {
143 let host = "odysseyportal.harriscountytx.gov";
144 let hc = new HTTPConversation({ rejectFN: rejFN });
145
146 this.verbose && console.log("Getting front page", this);
147 hc.getURL({ reqHost: host, reqPath: "/OdysseyPortalJP", callback: () => {
148 this.verbose && console.log("Got front page.");
149 hc.getURL({ reqHost: host, reqPath: "/OdysseyPortalJP/Home/Dashboard/29", callback: () => {
150 this.verbose && console.log("Got Dashboard page.");
151 hc.postURLData({
152 reqHost: host,
153 reqPath: "/OdysseyPortalJP/SmartSearch/SmartSearch/SmartSearch",
154 data: [
155 [ "Settings.CaptchaEnabled", "False" ],
156 [ "Settings.CaptchaDisabledForAuthenticated", "False" ],
157 [ "caseCriteria.SearchCriteria", this.caseNumber ],
158 [ "caseCriteria.JudicialOfficerSearchBy", "" ],
159 [ "caseCriteria.NameMiddle", "" ],
160 [ "caseCriteria.NameSuffix", "" ],
161 [ "caseCriteria.AdvancedSearchOptionsOpen", "false" ],
162 [ "caseCriteria.CourtLocation_input", "Harris County JPs Odyssey Portal" ],
163 [ "caseCriteria.CourtLocation", "Harris County JPs Odyssey Portal" ],
164 [ "caseCriteria.SearchBy_input", "Smart Search" ],
165 [ "caseCriteria.SearchBy", "SmartSearch" ],
166 [ "caseCriteria.SearchCases", "true" ],
167 [ "caseCriteria.SearchCases", "false" ],
168 [ "caseCriteria.SearchJudgments", "true" ],
169 [ "caseCriteria.SearchJudgments", "false" ],
170 [ "caseCriteria.SearchByPartyName", "true" ],
171 [ "caseCriteria.SearchByNickName", "false" ],
172 [ "caseCriteria.SearchByBusinessName", "false" ],
173 [ "caseCriteria.UseSoundex", "false" ],
174 [ "caseCriteria.Gender_input", "" ],
175 [ "caseCriteria.Gender", "" ],
176 [ "caseCriteria.Race_input", "" ],
177 [ "caseCriteria.Race", "" ],
178 [ "caseCriteria.FBINumber", "" ],
179 [ "caseCriteria.SONumber", "" ],
180 [ "caseCriteria.BookingNumber", "" ],
181 [ "caseCriteria.CaseType_input", "" ],
182 [ "caseCriteria.CaseType", "" ],
183 [ "caseCriteria.CaseStatus_input", "" ],
184 [ "caseCriteria.CaseStatus", "" ],
185 [ "caseCriteria.FileDateStart", "" ],
186 [ "caseCriteria.FileDateEnd", "" ],
187 [ "caseCriteria.JudicialOfficer_input", "" ],
188 [ "caseCriteria.JudicialOfficer", "" ],
189 [ "caseCriteria.JudgmentType_input", "" ],
190 [ "caseCriteria.JudgmentType", "" ],
191 [ "caseCriteria.JudgmentDateFrom", "" ],
192 [ "caseCriteria.JudgmentDateTo", "" ]
193 ],
194 callback: () => {
195 this.verbose && console.log("Got POST data, calling workspace.");
196 hc.getURL({ reqHost: host, reqPath: "/OdysseyPortalJP/Home/WorkspaceMode?p=0", callback: () => {
197 setTimeout(() => {
198 hc.getURL({
199 reqHost: host,
200 reqPath: "/OdysseyPortalJP/SmartSearch/SmartSearchResults?_="+(new Date()).valueOf(),
201 parser: getCaseIDParser(this, () => {
202 this.debug && console.log("CaseID: ", this.caseID);
203 hc.getURL({
204 reqHost: host,
205 reqPath: "/OdysseyPortalJP/Case/CaseDetail?eid="+this.caseID+"&tabIndex=3&_="+(new Date()).valueOf(),
206 // reqPath: this.caseURL + "&_="+(new Date()).valueOf(),
207 parser: getCaseInfoParser(this, () => {
208 if (resFN && "function" === typeof resFN) {
209 resFN(this);
210 } else {
211 console.log(this);
212 }
213 }, rejFN)
214 });
215 }, rejFN)
216 });
217 }, 1000);
218 }});
295 219 }}); }});
296 }});
220 }});
297 221 }}); }});
298 }});
222 });
299 223 }; };
300 224 }; };
File updateAddress.js copied from file updateStatus.js (similarity 51%) (mode: 100644) (index 66cb763..7d2bdf3)
17 17 Copyright 2020 Luigi Bai Copyright 2020 Luigi Bai
18 18 */ */
19 19 const DAO = require("./lib/sqlDAO"); const DAO = require("./lib/sqlDAO");
20 const Case = require("./lib/Case.class.js");
20 const Case = require("./lib/Case.class");
21 const OdysseyInfo = require("./lib/OdysseyInfo.class");
21 22
22 23 let opts = require("./creds")["SQLITE3"]; let opts = require("./creds")["SQLITE3"];
23 24 opts.connectCallback = (database) => { opts.connectCallback = (database) => {
24 25 // Prep the databse to update each case as we get its updated info: // Prep the databse to update each case as we get its updated info:
25 let dao = new DAO.CaseCtlr(database);
26 dao.stmts.update = dao.prepare(
26 let pDao = new DAO.PartyCtlr(database);
27 pDao.stmts.update = pDao.prepare(
27 28 database, database,
28 "UPDATE cases SET filed_Date = $fd, case_status = $status WHERE casenumber = $cnum"
29 "UPDATE party SET party_address = $pa WHERE casenumber = $cnum AND party_role = $pr AND party_name = $pn"
29 30 ); );
31 let cDao = new DAO.CaseCtlr(database);
32 cDao.stmts.update = cDao.prepare(
33 database,
34 "UPDATE cases SET odyssey_ID = $oid WHERE casenumber = $cnum"
35 );
36
30 37
31 38 // Track all the update promises, then wait until they're done: // Track all the update promises, then wait until they're done:
32 39 let promises = []; let promises = [];
33 Case.sqlAllCases({
34 database: database,
40 database.each(
41 "SELECT casenumber as caseNumber FROM cases WHERE casenumber IS NOT NULL AND odyssey_ID IS NULL ORDER BY casenumber DESC LIMIT 10",
35 42 // This is the callback used for each case: // This is the callback used for each case:
36 rowCallback: caseObj => {
37 promises.push(
38 // Load the data from the website, then
39 caseObj.loadCaseFromURL()
40 .then(caseO => {
41 // store it into the database:
42 caseO.storeSQL(database);
43 (caseO.caseNumber && caseO.filedDate && caseO.caseStatus) &&
44 dao.update({
45 $cnum: caseO.caseNumber,
46 $fd: caseO.filedDate,
47 $status: caseO.caseStatus
43 (err, caseObj) => {
44 if (! caseObj.caseNumber) console.error("Database had case with no casenuber.");
45 else {
46 promises.push(
47 // Grab the
48 (new OdysseyInfo(caseObj.caseNumber))
49 .findCasePromise()
50 .then(oi => {
51 // Store the OdysseyID into Cases
52 cDao.update({
53 $cnum: oi.caseNumber,
54 $oid: oi.caseID
48 55 }); });
49 })
50 .catch(e => { console.error("loadCaseFromURL", caseObj, e); })
51 );
56 // Store the party addresses
57 oi.parties.forEach(party => {
58 pDao.update({
59 $pa: party.address.join(" "),
60 $cnum: oi.caseNumber,
61 $pr: party.role,
62 $pn: party.name
63 });
64 });
65 })
66 .catch(err => {
67 console.error("Error retrieving OI", caseObj, err);
68 })
69 );
70 }
52 71 }, },
53 completionCallback: () => {
72 () => {
54 73 // And this is the callback used when the SELECT is finished: // And this is the callback used when the SELECT is finished:
55 74 Promise.all(promises) Promise.all(promises)
56 75 .finally(() => { .finally(() => {
57 76 // Shut down the database, and the HTTPS agent: // Shut down the database, and the HTTPS agent:
58 77 require("./lib/httpOptions").getGlobalAgent().destroy(); require("./lib/httpOptions").getGlobalAgent().destroy();
59 dao.finalize();
78 pDao.finalize();
79 cDao.finalize();
60 80 DAO.disconnect(database); DAO.disconnect(database);
61 81 }) })
62 82 ; ;
63 83 } }
64 });
84 );
65 85 }; };
66 86
67 87 DAO.connect(opts); DAO.connect(opts);
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/datajams-lbai/datajams-evictions

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/datajams-lbai/datajams-evictions

Clone this repository using git:
git clone git://git.rocketgit.com/user/datajams-lbai/datajams-evictions

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main