View difference between Paste ID: 5jizAWKE and VzTw3iX8
SHOW: | | - or go back to the newest paste.
1
-- *-*  <- Absolutely needed, do not delete.
2
3
-- BeeAlverizer 1.1 fork of BeeAnalyzer 4
4
-- Original code by Direwolf20
5
-- Hotfixes by Mandydax, Mikeyhun and MaaadMike
6
7
-- Major overhaul and rewrite to make work without turtle by Damaged
8
9
10
-- JSON lib located at http://pastebin.com/jy3QenZn save as JSON.lua
11-
-- Be careful of case
11+
-- Be careful of case 
12
13
if not fs.exists("JSON.lua") then
14
   shell.run("pastebin", "get", "jy3QenZn", "JSON.lua")
15
end
16
17
local JSON = (loadfile "JSON.lua")()
18
JSON.strictTypes = true
19
 
20
-- Build: http://users.on.net/~damageinc/Alveary%20placement.jpg
21
22
-- Make sure you name this program "bee" (careful of case)
23
24
-- Direction definitions.
25
26
-- When looking at computer, what direction is it?
27
-- Or simply put the direction in the label EG: bee1.west
28
29
local alvearyDirection = "west"
30
31
for i,case in pairs({ ".west", ".east", ".north", ".south" }) do
32
   if string.find(os.getComputerLabel(),case) then
33
      alvearyDirection = string.sub(case, 2)
34
      break
35
   end
36
end
37
print("I appear to be facing: "..alvearyDirection)
38
local analyzerDirection
39
local junkDirection
40
41
if alvearyDirection == "west" then
42
   analyzerDirection = "south"
43
   junkDirection = "north"
44
end
45
if alvearyDirection == "north" then
46
   analyzerDirection = "west"
47
   junkDirection = "east"
48
end
49
if alvearyDirection == "east" then
50
   analyzerDirection = "north"
51
   junkDirection = "south"
52
end
53
if alvearyDirection == "south" then
54
   analyzerDirection = "east"
55
   junkDirection = "west"
56
end
57
58
59
60
61
62
63
64
-- attribute scoring for same species tie-breaking -----------------------------
65
local droneTarget
66
local princessSlot = 0
67
alveary = peripheral.wrap("back")
68
memoryChest = peripheral.wrap("top")
69
local maxMem = memoryChest.getInventorySize()
70
-- Fix for some versions returning bees.species.*
71
function fixName(name)
72
   return name:gsub("bees%.species%.",""):gsub("^.", string.upper)
73
end
74
75
function getBeeData(i)
76
   return memoryChest.getStackInSlot(i)["beeInfo"]
77
end 
78
79
function getPrimarySpecies(i)
80
   local thisBee = getBeeData(i)
81
   if thisBee["speciesPrimary"] ~= nil then
82
      return fixName(thisBee["speciesPrimary"])
83
   else
84
      return fixName(thisBee["active"]["species"])
85
   end
86
end
87
88
function getSecondarySpecies(i)
89
   if getBeeData(i)["speciesSecondary"] ~= nil then
90
      return fixName(getBeeData(i)["speciesSecondary"])
91
   else
92
      return fixName(getBeeData(i)["inactive"]["species"])
93
   end
94
end
95
96
scoresFertility = {
97
   [1] = 0.1,
98
   [2] = 0.2,
99
   [3] = 0.3,
100
   [4] = 0.4
101
}
102
scoresSpeed = {
103
   ["0.3"] = 0.01, -- Slowest
104
   ["0.6"] = 0.02, -- Slower
105
   ["0.8"] = 0.03, -- Slow
106
   ["1"]   = 0.04, -- Normal
107
   ["1.2"] = 0.05, -- Fast
108
   ["1.4"] = 0.06, -- Faster
109
   ["1.7"] = 0.07  -- Fastest
110
}
111
scoresAttrib = {
112
   diurnal       = 0.004,
113
   nocturnal     = 0.003,
114
   tolerantFlyer = 0.002,
115
   caveDwelling  = 0.0001
116
}
117
scoresTolerance = {
118
   ["NONE"]   = 0.00000,
119
   ["UP 1"]   = 0.00001,
120
   ["UP 2"]   = 0.00002,
121
   ["UP 3"]   = 0.00003,
122
   ["UP 4"]   = 0.00004,
123
   ["UP 5"]   = 0.00005,
124
   ["DOWN 1"] = 0.00001,
125
   ["DOWN 2"] = 0.00002,
126
   ["DOWN 3"] = 0.00003,
127
   ["DOWN 4"] = 0.00004,
128
   ["DOWN 5"] = 0.00005,
129
   ["BOTH 1"] = 0.00002,
130
   ["BOTH 2"] = 0.00004,
131
   ["BOTH 3"] = 0.00006,
132
   ["BOTH 4"] = 0.00008,
133
   ["BOTH 5"] = 0.00010
134
}
135
136
-- the bee graph ---------------------------------------------------------------
137
138
bees = {}
139
140
function addParent(parent, offspring)
141
   if bees[parent] then
142
      bees[parent].mutateTo[offspring] = true
143
      else
144
      bees[parent] = {
145
         --name = parent,
146
         score = nil,
147
         mutateTo = {[offspring]=true},
148
         mutateFrom = {}
149
      }
150
   end
151
end
152
153
function addOffspring(offspring, parentss)
154
   if bees[offspring] then
155
      for i, parents in ipairs(parentss) do
156
         table.insert(bees[offspring].mutateFrom, parents)
157
      end
158
      else
159
      bees[offspring] = {
160
         score = nil,
161
         mutateTo = {},
162
         mutateFrom = parentss
163
      }
164
   end
165
   for i, parents in ipairs(parentss) do
166
      for i, parent in ipairs(parents) do
167
         addParent(parent, offspring)
168
      end
169
   end
170
end
171
172
-- score bees that have no parent combinations as 1
173
-- iteratively find the next bee up the line and increase the score
174
function scoreBees()
175
   -- find all bees with no mutateFrom data
176
   local beeCount = 0
177
   local beeScore = 1
178
   for name, beeData in pairs(bees) do
179
      if #beeData.mutateFrom == 0 then
180
         beeData.score = beeScore
181
         else
182
         beeCount = beeCount + 1
183
      end
184
   end
185
   while beeCount > 0 do
186
      beeScore = beeScore * 2
187
      -- find all bees where all parent combos are scored
188
      for name, beeData in pairs(bees) do
189
         if not beeData.score then
190
            local scoreBee = true
191
            for i, beeParents in ipairs(beeData.mutateFrom) do
192
               local parent1 = bees[beeParents[1]]
193
               local parent2 = bees[beeParents[2]]
194
               
195
               if not parent1.score
196
                  or parent1.score == beeScore
197
                  or not parent2.score
198
                  or parent2.score == beeScore then
199
                  scoreBee = false
200
                  break
201
               end
202
            end
203
            if scoreBee then
204
               beeData.score = beeScore
205
               beeCount = beeCount - 1
206
            end
207
         end
208
      end
209
   end
210
end
211
212
-- produce combinations from 1 or 2 lists
213
function choose(list, list2)
214
   local newList = {}
215
   if list2 then
216
      for i = 1, #list2 do
217
         for j = 1, #list do
218
            if list[j] ~= list[i] then
219
               table.insert(newList, {list[j], list2[i]})
220
            end
221
         end
222
      end
223
      else
224
      for i = 1, #list do
225
         for j = i, #list do
226
            if list[i] ~= list[j] then
227
               table.insert(newList, {list[i], list[j]})
228
            end
229
         end
230
      end
231
   end
232
   return newList
233
end
234
235
236
for key, value in pairs (alveary.getBeeBreedingData()) do
237
   addOffspring( fixName(value.result), {{ fixName(value.allele1), fixName(value.allele2) }} )
238
end
239
scoreBees()
240
241
-- logging ---------------------------------------------------------------------
242
243
local logFile = fs.open("bee.log", "w")
244
function log(msg)
245
   msg = msg or ""
246
   logFile.write(tostring(msg))
247
   logFile.flush()
248
   io.write(msg)
249
end
250
function logLine(msg)
251
   msg = msg or ""
252
   logFile.write(msg.."\n")
253
   logFile.flush()
254
   io.write(msg.."\n")
255
end
256
257
function logTable(table)
258
   for key, value in pairs (table) do
259
      logLine(key .. " = " .. tostring(value))
260
   end
261
end
262
263
264
-- analyzing functions ---------------------------------------------------------
265
266
function clearSystem()
267
   -- clear out alveary
268
   for i = 2,9 do
269
      memoryChest.pullItem(alvearyDirection,i)
270
   end
271
   -- clear out analyzer
272
   for i = 1, 12 do
273
      memoryChest.pullItem(analyzerDirection,i)
274
   end
275
end
276
277
function analyzeBees()
278
   princessSlot = 0
279
   logLine("analyzing bees...")
280
   memoryChest.condenseItems()
281
   local highestScore
282
   local highestScoreDrone
283
   for i,data in pairs(memoryChest.getAllStacks()) do
284
      data = memoryChest.getStackInSlot(i) 
285-
      sleep(10)
285+
286
         memoryChest.pushItem(junkDirection,i)
287
         print("P")
288
      else
289
         print("B")
290
         --print(JSON:encode(data["beeInfo"]))
291
         --print(data["beeInfo"]["isAnalyzed"]) 
292
         if data["beeInfo"]["isAnalyzed"] == false then
293
            memoryChest.pushItemIntoSlot(analyzerDirection,i,64,3)
294
            while memoryChest.pullItemIntoSlot(analyzerDirection,9,61,i) == 0 do sleep(1) end
295
         end
296
         if string.find(data["rawName"], "princess") then
297
            princessSlot = i
298
         end
299
      end
300
   end
301
end
302
303
local droneData
304
droneData = { }
305
306
function sortBees()
307
   droneData = { }
308
   if princessSlot ~= 0 then
309
      logLine("scoring drones...")
310
      for i,data in pairs(memoryChest.getAllStacks()) do
311
         if i ~= princessSlot then
312
            -- check for untargeted species
313
            if memoryChest.getStackInSlot(i) ~= nil and (not bees[getPrimarySpecies(i)].targeted or not bees[getSecondarySpecies(i)].targeted) then
314-
         -- check for untargeted species
314+
315-
         if memoryChest.getStackInSlot(i) ~= nil and (not bees[getPrimarySpecies(i)].targeted or not bees[getSecondarySpecies(i)].targeted) then
315+
            else
316-
            memoryChest.pushItem(junkDirection,i)
316+
               droneData[i] = scoreBee(i)
317
               if droneData[i] == 0 then
318-
            if string.find(data["rawName"], "princess") then
318+
                  memoryChest.pushItem(junkDirection,i)
319-
               princessSlot = i
319+
                  droneData[i] = nil
320
               end
321
            end
322
         end
323
      end
324
      -- find the best drone
325
      logLine("sorting drones...")
326
      highestScore = 0
327-
            droneData[i] = scoreBee(i)
327+
328-
            if droneData[i] == 0 then
328+
329
            highestScore = beeScore 
330
            highestScoreDrone = i
331
         end
332
      end
333
      printHeader()
334
      for i = 1, maxMem do
335
         if memoryChest.getStackInSlot(i) ~= nil then
336
            printBee(i)
337
         end
338
      end
339
   end
340
   logLine()
341
   return highestScoreDrone
342
end
343
344
function getBees()
345
   -- get bees from apiary
346
   log("waiting for bees.")
347
   local firstPass = true
348
   local highScore
349
   while true do
350
      local gotStuff = false
351
      for i = 3,9 do
352
         if memoryChest.pullItem(alvearyDirection,i) ~= 0 then
353
            gotStuff = true
354
         end
355
      end
356
      if gotStuff == true then
357
         break
358
      end
359
      if firstPass then
360
         firstPass = false
361
         logLine()
362
         logLine("First time waiting:")
363
         logLine("-compacting bees")
364
         for i = 1,maxMem do
365
            if droneData[i] ~= nil then
366
               if i ~= 1 then
367
                  for j = 1,i-1 do
368
                     if memoryChest.getStackInSlot(j) == nil then
369
                        memoryChest.swapStacks(i, j)
370
                        droneData[j] = droneData[i]
371
                        droneData[i] = nil
372
                        break
373
                     end
374
                  end
375
               end
376
            end
377
         end
378
         logLine("-resorting bees in chest")
379
         for i = 1,maxMem do
380
            if droneData[i] ~= nil then
381
               if memoryChest.getStackInSlot(i) ~= nil then
382
                  highScore = i
383
                  for j = i + 1, maxMem do
384
                     if memoryChest.getStackInSlot(j) ~= nil then
385
                        if droneData[j] > droneData[highScore] then
386
                           highScore = j
387
                        end
388
                     end
389
                  end
390
                  -- swap bees
391
                  if highScore ~= i then
392
                     memoryChest.swapStacks(i, highScore)
393
                     droneData[i], droneData[highScore] = droneData[highScore], droneData[i]
394
                  end
395
               end
396
            end
397
         end
398
         logLine("-discarding excess")
399
         for i = maxMem, maxMem - (maxMem / 10) do
400
            if droneData[i] ~= nil then
401
               memoryChest.pushItem(junkDirection,i)
402
               droneData[i] = nil
403
            end
404
         end   
405
      else
406
         sleep(10)
407
      end
408
      log(".")
409
   end
410
   log("*")
411
   logLine()
412
end
413
414
function scoreBee(droneID)
415
   local beeDataDrone = getBeeData(droneID)
416
   local beeDataPrincess = getBeeData(princessSlot)
417
   local droneSpecies = {getPrimarySpecies(droneID), getSecondarySpecies(droneID)}
418
   -- check for untargeted species
419
   if not bees[droneSpecies[1]].targeted or not bees[droneSpecies[2]].targeted then
420
      return 0
421
   end
422
   local princessSpecies = {getPrimarySpecies(princessSlot), getSecondarySpecies(princessSlot)}
423
   local score
424
   local maxScore = 0
425
   for _, combo in ipairs({{princessSpecies[1], droneSpecies[1]}
426
      ,{princessSpecies[1], droneSpecies[2]}
427
      ,{princessSpecies[2], droneSpecies[1]}
428
   ,{princessSpecies[2], droneSpecies[2]}}) do
429
      -- find maximum score for each combo
430
      score = (bees[combo[1]].score + bees[combo[2]].score) / 2
431
      for name, beeData in pairs(bees) do
432
         if beeData.targeted then
433
            for i, parents in ipairs(beeData.mutateFrom) do
434
               if combo[1] == parents[1] and combo[2] == parents[2]
435
                  or combo[2] == parents[1] and combo[1] == parents[2] then
436
                  score = (score + beeData.score) / 2
437
               end
438
            end
439
         end
440
      end
441
      maxScore = maxScore + score
442
   end
443
   -- add one for each combination that results in the maximum score
444
   score = maxScore
445
   -- score attributes
446
   score = score + math.max(scoresFertility[beeDataDrone["active"]["fertility"]], scoresFertility[beeDataPrincess["active"]["fertility"]])
447
   score = score + math.min(scoresSpeed[tostring(beeDataDrone["active"]["speed"])], scoresSpeed[tostring(beeDataPrincess["active"]["speed"])])
448
   if beeDataDrone["active"]["nocturnal"] or beeDataPrincess["active"]["nocturnal"] then score = score + scoresAttrib["nocturnal"] end
449
   if beeDataDrone["active"]["tolerantFlyer"] or beeDataPrincess["active"]["tolerantFlyer"] then score = score + scoresAttrib["tolerantFlyer"] end
450
   if beeDataDrone["active"]["caveDwelling"] or beeDataPrincess["active"]["caveDwelling"] then score = score + scoresAttrib["caveDwelling"] end
451
   score = score + math.max(scoresTolerance[string.upper(beeDataDrone["active"]["temperatureTolerance"])], scoresTolerance[string.upper(beeDataPrincess["active"]["temperatureTolerance"])])
452
   score = score + math.max(scoresTolerance[string.upper(beeDataDrone["active"]["humidityTolerance"])], scoresTolerance[string.upper(beeDataPrincess["active"]["humidityTolerance"])])
453
   return score
454
end
455
456
function printHeader()
457
   logLine()
458
   logLine("sl t species f spd n f c tmp hmd score ")
459
   logLine("--|-|-------|-|---|-|-|-|---|---|------")
460
end
461
462
-- string constants for console output
463
toleranceString = {
464
   ["NONE"] = "  - ",
465
   ["UP 1"] = " +1 ",
466
   ["UP 2"] = " +2 ",
467
   ["UP 3"] = " +3 ",
468
   ["UP 4"] = " +4 ",
469
   ["UP 5"] = " +5 ",
470
   ["DOWN 1"] = " -1 ",
471
   ["DOWN 2"] = " -2 ",
472
   ["DOWN 3"] = " -3 ",
473
   ["DOWN 4"] = " -4 ",
474
   ["DOWN 5"] = " -5 ",
475
   ["BOTH 1"] = "+-1 ",
476
   ["BOTH 2"] = "+-2 ",
477
   ["BOTH 3"] = "+-3 ",
478
   ["BOTH 4"] = "+-4 ",
479
   ["BOTH 5"] = "+-5 "
480
}
481
482
speedString = {
483
   ["0.3"] = "0.3", -- Slowest
484
   ["0.6"] = "0.6", -- Slower
485
   ["0.8"] = "0.8", -- Slow
486
   ["1"]   = "1.0", -- Normal
487
   ["1.2"] = "1.2", -- Fast
488
   ["1.4"] = "1.4", -- Faster
489
   ["1.7"] = "1.7"  -- Fastest
490
}
491
492
function printBee(i)
493
   local beeData = getBeeData(i)
494
   log(i < 10 and " "..i.." " or i.." ")
495
   -- type
496
   log(string.find(memoryChest.getStackInSlot(i)["rawName"], "princess") and "P " or "D ")
497
   -- species
498
   log(getPrimarySpecies(i):gsub("bees%.species%.",""):sub(1,3)..":"..getSecondarySpecies(i):gsub("bees%.species%.",""):sub(1,3).." ")
499
   -- fertility
500
   log(tostring(beeData["active"]["fertility"]).." ")
501
   -- speed
502
   log(speedString[tostring(beeData["active"]["speed"])].." ")
503
   -- nocturnal
504
   log(beeData["active"]["nocturnal"] and "X " or "- ")
505
   -- flyer
506
   log(beeData["active"]["tolerantFlyer"] and "X " or "- ")
507
   -- cave dwelling
508
   log(beeData["active"]["caveDwelling"] and "X " or "- ")
509
   -- temperature tolerance
510
   log(toleranceString[string.upper(beeData["active"]["temperatureTolerance"])])
511
   -- humidity tolerance
512
   log(toleranceString[string.upper(beeData["active"]["humidityTolerance"])])
513
   -- score
514
   log(droneData[i] and string.format("%5.1d", droneData[i]).." " or "      ")
515
   logLine()
516
end
517
518
function dropExcess()
519
   logLine("dropping excess...")
520
   for i = ( maxMem - 9 ), maxMem do
521
      -- drop drones over ( max inv - 9 ) to clear space for newly bred bees and product
522
      memoryChest.pushItem(junkDirection,i)
523
   end 
524
end
525
526
function isPurebred(droneID)
527
   -- check if princess and drone are exactly the same and no chance for mutation
528
   local princessPrimary = getPrimarySpecies(princessSlot)
529
   if princessPrimary ~= getSecondarySpecies(princessSlot) then
530
      return false
531
   end
532
   if getPrimarySpecies(droneID) ~= princessPrimary then
533
      return false
534
   end
535
   if getSecondarySpecies(droneID) ~= princessPrimary then
536
      return false
537
   end
538
   local droneBeeData = getBeeData(droneID)
539
   local princessBeeData = getBeeData(princessSlot)
540
   for i,key in pairs({ "fertility", "speed", "nocturnal", "tolerantFlyer", "caveDwelling", "temperatureTolerance", "humidityTolerance" }) do
541
      if
542
         droneBeeData["active"][key] ~= princessBeeData["active"][key] or
543
         droneBeeData["inactive"][key] ~= princessBeeData["inactive"][key]
544
      then
545
         return false
546
      end
547
   end
548-
   for i, target in ipairs(tArgs) do
548+
549-
      targetBee(target)
549+
550-
      for name, data in pairs(bees) do
550+
551-
         if data.targeted and data.score > 1 then
551+
552-
            logLine(name .. string.rep(" ", 20-#name), data.score)
552+
553
-- set species and all parents to targeted
554
function targetBee(name)
555
   local bee = bees[name]
556
   if bee and not bee.targeted then
557
      bee.targeted = true
558
      for i, parents in ipairs(bee.mutateFrom) do
559
         for j, parent in ipairs(parents) do
560
            targetBee(parent)
561
         end
562
      end
563
   end
564
end
565
566
tArgs = { ... }
567
568
if fs.exists("bee.data") and #tArgs == 0 then
569
   local recoveredData = fs.open("bee.data", "r")
570
   local historyData = recoveredData.readLine()
571
   if historyData then
572
      historyData = JSON:decode(historyData)
573
      tArgs[1] = historyData["target"]
574
      if historyData["count"] ~= nil then
575
         tArgs[2] = historyData["count"]
576
      end
577
      logLine("Recovered old data.")
578
   end
579
   recoveredData.close()
580
end 
581
582
583-
      droneTarget = analyzeBees()
583+
584
   local myProgramName
585-
         if isPurebred(droneTarget) then
585+
586
      if type(fileName) == "string" then
587
         if fileName ~= "" then
588
            local tempFile = fs.open(fileName,"r")
589
            if string.sub(tempFile.readLine(),4,6) == "*-*" then
590
               myProgramName = fileName
591
               break
592
            end
593
         end
594
      end
595
   end
596
   return myProgramName
597
end
598
      
599
600
-- set bee graph entry to targeted if species was specified on the command line
601
-- otherwise set all entries to targeted
602
603
local totalDrones
604
local alwaysBreed
605
606
if #tArgs > 0 then
607
   logLine("targeting bee species:")
608
   fs.delete("bee.data")
609
   recoveredData = fs.open("bee.data", "w")
610
   local tempArray = {}
611
   tempArray["target"] = tArgs[1]
612
   if tArgs[2] ~= nil then
613
      tempArray["count"] = math.min(math.max(tonumber(tArgs[2]),1),64)
614
      totalDrones = math.max(tonumber(tArgs[2]),1)
615
   end
616
   recoveredData.write( JSON:encode( tempArray ) )
617
   recoveredData.close()
618
   if type(tArgs[1]) == "string" then
619
      print(string.lower(tArgs[1]))
620
      while true do
621
         if tArgs[1]:gsub("^.", string.upper) == "Breedprincess" then
622
            analyzeBees()
623
            targetBee(getPrimarySpecies(princessSlot))
624
            break
625
         end
626
         if tArgs[1]:gsub("^.", string.upper) == "Breeddrone" then
627
            analyzeBees()
628
            targetBee(getPrimarySpecies(1))
629
            break
630
         end
631
         if true then
632
            targetBee(tArgs[1]:gsub("^.", string.upper))
633
            break
634
         end
635
         break
636
      end
637
   else
638
      print("You must enter a valid target mutation")
639
   end
640
   for name, data in pairs(bees) do
641
      if data.targeted and data.score > 1 then
642
         logLine(name .. string.rep(" ", 20-#name), data.score)
643
      end
644
   end
645
   local myProgramName = findMe()
646
   logLine("Found program:"..myProgramName)
647
   if myProgramName ~= nil then
648
      fs.delete("startup")
649
      local startupFile = fs.open("startup","w")
650
      startupFile.write("shell.run(\""..myProgramName.."\")")
651
      startupFile.close()
652
   else
653
      logLine("Cannot find program name, you edited the first line of the program didn't you!")
654
   end
655
else
656
   for _, beeData in pairs(bees) do
657
      beeData.targeted = true
658
   end
659
end
660
661
-- breeding loop ---------------------------------------------------------------
662
663
  
664
665
logLine("Clearing system...")
666
clearSystem()
667
if not memoryChest.getAllStacks() then
668
   print("No bees to work on, add bees and restart")
669
else
670
   redstone.setOutput("bottom", true)
671
   while true do
672
      analyzeBees()
673
      droneTarget = sortBees()
674
      if princessSlot ~= 0 then
675
         if isPurebred(droneTarget) and memoryChest.getStackInSlot(droneTarget)["qty"] == totalDrone then
676
            logLine("Bees are purebred.")
677
            logLine("Princess: "..princessSlot)
678
            logLine("Drone: "..droneTarget)
679
            redstone.setOutput("bottom", false)
680
            fs.delete("bee.data")
681
            fs.delete("startup")
682
            break
683
         end
684
         memoryChest.pushItemIntoSlot(alvearyDirection,princessSlot,1,1)
685
         memoryChest.pushItemIntoSlot(alvearyDirection,droneTarget,1,2)
686
         dropExcess()
687
      end
688
      getBees()
689
   end
690
end
691
logFile.close()