FOSSology  4.7.1
Open Source License Compliance by Open Source Software
DeciderAgent.php
Go to the documentation of this file.
1 <?php
2 /*
3  Author: Daniele Fognini
4  SPDX-FileCopyrightText: © 2014-2019 Siemens AG
5  SPDX-FileCopyrightText: © 2021 Orange by Piotr Pszczola <piotr.pszczola@orange.com>
6  SPDX-FileCopyrightText: © 2021 Kaushlendra Pratap <kaushlendrapratap.9837@gmail.com>
7  SPDX-FileCopyrightText: © Fossology contributors
8 
9  SPDX-License-Identifier: GPL-2.0-only
10 */
50 namespace Fossology\Decider;
51 
71 use Symfony\Component\Process\Process;
72 
73 include_once(__DIR__ . "/version.php");
74 
79 class DeciderAgent extends Agent
80 {
81  const RULES_NOMOS_IN_MONK = 0x1;
82  const RULES_NOMOS_MONK_NINKA = 0x2;
83  const RULES_WIP_SCANNER_UPDATES = 0x8;
84  const RULES_OJO_NO_CONTRADICTION = 0x10;
85  const RULES_COPYRIGHT_FALSE_POSITIVE = 0x20;
86  const RULES_COPYRIGHT_FALSE_POSITIVE_CLUTTER = 0x40;
87  const RULES_LICENSE_TYPE_CONCLUSION = 0x80;
88  const RULES_KOTOBA_NO_CONTRADICTION = 0x100;
89  const RULES_RESO_NO_CONTRADICTION = 0x200;
90  const RULES_ALL = self::RULES_NOMOS_IN_MONK | self::RULES_NOMOS_MONK_NINKA |
91  self::RULES_WIP_SCANNER_UPDATES |
92  self::RULES_OJO_NO_CONTRADICTION | self::RULES_RESO_NO_CONTRADICTION |
93  self::RULES_LICENSE_TYPE_CONCLUSION | self::RULES_KOTOBA_NO_CONTRADICTION;
94 
98  private $activeRules;
102  private $licenseType;
106  private $uploadDao;
118  private $clearingDao;
122  private $highlightDao;
126  private $showJobsDao;
130  private $decisionTypes;
134  private $licenseMap = null;
138  private $licenseMapUsage = null;
139 
143  private $copyrightDao;
144 
149 
153  private $licenseDao;
154 
155  function __construct($licenseMapUsage=null)
156  {
157  parent::__construct(AGENT_DECIDER_NAME, AGENT_DECIDER_VERSION, AGENT_DECIDER_REV);
158 
159  $this->uploadDao = $this->container->get('dao.upload');
160  $this->clearingDao = $this->container->get('dao.clearing');
161  $this->highlightDao = $this->container->get('dao.highlight');
162  $this->showJobsDao = $this->container->get('dao.show_jobs');
163  $this->decisionTypes = $this->container->get('decision.types');
164  $this->clearingDecisionProcessor = $this->container->get('businessrules.clearing_decision_processor');
165  $this->agentLicenseEventProcessor = $this->container->get('businessrules.agent_license_event_processor');
166  $this->copyrightDao = $this->container->get('dao.copyright');
167  $this->compatibilityDao = $this->container->get('dao.compatibility');
168  $this->licenseDao = $this->container->get('dao.license');
169  $this->licenseMapUsage = $licenseMapUsage;
170  $this->agentSpecifOptions = "r:t:";
171  }
172 
177  function processUploadId($uploadId)
178  {
179  $args = $this->args;
180  $this->activeRules = array_key_exists('r', $args) ? intval($args['r']) : self::RULES_ALL;
181  $this->licenseType = array_key_exists('t', $args) ?
182  $this->getLicenseType(str_replace(["'", '"'], "", $args['t'])) : "";
183  $this->licenseMap = new LicenseMap($this->dbManager, $this->groupId, $this->licenseMapUsage);
184 
185  if (array_key_exists("r", $args) && (($this->activeRules&self::RULES_COPYRIGHT_FALSE_POSITIVE)== self::RULES_COPYRIGHT_FALSE_POSITIVE)) {
186  $this->getCopyrightsToDisableFalsePositivesClutter($uploadId, false);
187  }
188  if (array_key_exists("r", $args) && (($this->activeRules&self::RULES_COPYRIGHT_FALSE_POSITIVE_CLUTTER)== self::RULES_COPYRIGHT_FALSE_POSITIVE_CLUTTER)) {
189  $this->getCopyrightsToDisableFalsePositivesClutter($uploadId, true);
190  }
191  $parentBounds = $this->uploadDao->getParentItemBounds($uploadId);
192  foreach ($this->uploadDao->getContainedItems($parentBounds) as $item) {
193  $process = $this->processItem($item);
194  $this->heartbeat($process);
195  }
196  return true;
197  }
198 
208  private function processItem(Item $item)
209  {
210  $itemTreeBounds = $item->getItemTreeBounds();
211 
212  $unMappedMatches = $this->agentLicenseEventProcessor->getLatestScannerDetectedMatches($itemTreeBounds);
213  $projectedScannerMatches = $this->remapByProjectedId($unMappedMatches);
214 
215  $lastDecision = $this->clearingDao->getRelevantClearingDecision($itemTreeBounds, $this->groupId);
216 
217  if (null!==$lastDecision && $lastDecision->getType()==DecisionTypes::IRRELEVANT) {
218  return 0;
219  }
220 
221  $currentEvents = $this->clearingDao->getRelevantClearingEvents($itemTreeBounds, $this->groupId);
222 
223  $markAsWip = false;
224  if (null !== $lastDecision && $projectedScannerMatches
225  && ($this->activeRules & self::RULES_WIP_SCANNER_UPDATES) == self::RULES_WIP_SCANNER_UPDATES) {
226  $licensesFromDecision = array();
227  foreach ($lastDecision->getClearingLicenses() as $clearingLicense) {
228  $licenseIdFromEvent = $this->licenseMap->getProjectedId($clearingLicense->getLicenseId());
229  $licensesFromDecision[$licenseIdFromEvent] = $licenseIdFromEvent;
230  }
231  $markAsWip = $this->existsUnhandledMatch($projectedScannerMatches,$licensesFromDecision);
232  }
233 
234  if (null !== $lastDecision && $markAsWip) {
235  $this->clearingDao->markDecisionAsWip($item->getId(), $this->userId, $this->groupId);
236  return 1;
237  }
238 
239  /* Kotoba stores findings as clearing events, which would trip the guard
240  below. Auto-conclude here when all events are from kotoba and no scanner
241  license is unaccounted for. */
242  if (null === $lastDecision && count($currentEvents) > 0
243  && ($this->activeRules & self::RULES_KOTOBA_NO_CONTRADICTION) == self::RULES_KOTOBA_NO_CONTRADICTION) {
244  if ($this->autodecideIfKotobaMatchesNoContradiction($itemTreeBounds, $projectedScannerMatches, $currentEvents)) {
245  return 1;
246  }
247  }
248 
249  if (null!==$lastDecision || 0<count($currentEvents)) {
250  return 0;
251  }
252 
253  $haveDecided = false;
254 
255  if (!$haveDecided && ($this->activeRules&self::RULES_OJO_NO_CONTRADICTION) == self::RULES_OJO_NO_CONTRADICTION) {
256  $haveDecided = $this->autodecideIfOjoMatchesNoContradiction($itemTreeBounds, $projectedScannerMatches);
257  }
258 
259  if (!$haveDecided && ($this->activeRules&self::RULES_RESO_NO_CONTRADICTION) == self::RULES_RESO_NO_CONTRADICTION) {
260  $haveDecided = $this->autodecideIfResoMatchesNoContradiction($itemTreeBounds, $projectedScannerMatches);
261  }
262 
263  if (!$haveDecided && ($this->activeRules&self::RULES_NOMOS_IN_MONK) == self::RULES_NOMOS_IN_MONK) {
264  $haveDecided = $this->autodecideNomosMatchesInsideMonk($itemTreeBounds, $projectedScannerMatches);
265  }
266 
267  if (!$haveDecided && ($this->activeRules&self::RULES_NOMOS_MONK_NINKA)== self::RULES_NOMOS_MONK_NINKA) {
268  $haveDecided = $this->autodecideNomosMonkNinka($itemTreeBounds, $projectedScannerMatches);
269  }
270 
271  if (!$haveDecided && ($this->activeRules &
272  self::RULES_LICENSE_TYPE_CONCLUSION) ==
273  self::RULES_LICENSE_TYPE_CONCLUSION) {
274  $haveDecided = $this->autodecideLicenseType($itemTreeBounds,
275  $projectedScannerMatches);
276  }
277 
278  if (!$haveDecided && $markAsWip) {
279  $this->clearingDao->markDecisionAsWip($item->getId(), $this->userId, $this->groupId);
280  }
281 
282  return ($haveDecided||$markAsWip ? 1 : 0);
283  }
284 
291  private function existsUnhandledMatch($projectedScannerMatches, $licensesFromDecision)
292  {
293  foreach (array_keys($projectedScannerMatches) as $projectedLicenseId) {
294  if (!array_key_exists($projectedLicenseId, $licensesFromDecision)) {
295  return true;
296  }
297  }
298  return false;
299  }
300 
309  private function autodecideIfOjoMatchesNoContradiction(ItemTreeBounds $itemTreeBounds, $matches)
310  {
311  $licenseMatchExists = count($matches) > 0;
312  foreach ($matches as $licenseMatches) {
313  $licenseMatchExists = $licenseMatchExists && $this->areOtherScannerFindingsAndOJOAgreed($licenseMatches);
314  }
315 
316  if ($licenseMatchExists) {
317  try {
318  $this->clearingDecisionProcessor->makeDecisionFromLastEvents(
319  $itemTreeBounds, $this->userId, $this->groupId,
320  DecisionTypes::IDENTIFIED, false);
321  } catch (\Exception $e) {
322  echo "Can not auto decide as file '" .
323  $itemTreeBounds->getItemId() . "' contains candidate license.\n";
324  }
325  }
326  return $licenseMatchExists;
327  }
328 
339  private function autodecideIfKotobaMatchesNoContradiction(ItemTreeBounds $itemTreeBounds, $projectedScannerMatches, $currentEvents)
340  {
341  $accountedLicenses = array();
342  foreach ($currentEvents as $event) {
343  if ($event->getEventType() != ClearingEventTypes::KOTOBA) {
344  return false; // human event present; do not override
345  }
346  $projectedId = $this->licenseMap->getProjectedId($event->getLicenseId());
347  $accountedLicenses[$projectedId] = true;
348  }
349 
350  foreach (array_keys($projectedScannerMatches) as $projectedLicenseId) {
351  if (!array_key_exists($projectedLicenseId, $accountedLicenses)) {
352  return false; // unaccounted scanner license: contradiction
353  }
354  }
355 
356  try {
357  $this->clearingDecisionProcessor->makeDecisionFromLastEvents(
358  $itemTreeBounds, $this->userId, $this->groupId,
359  DecisionTypes::IDENTIFIED, false);
360  } catch (\Exception $e) {
361  echo "Can not auto decide as file '" .
362  $itemTreeBounds->getItemId() . "' contains candidate license.\n";
363  return false;
364  }
365  return true;
366  }
367 
376  private function autodecideIfResoMatchesNoContradiction(ItemTreeBounds $itemTreeBounds, $matches)
377  {
378  $licenseMatchExists = count($matches) > 0;
379  foreach ($matches as $licenseMatches) {
380  $licenseMatchExists = $licenseMatchExists && $this->areOtherScannerFindingsAndRESOAgreed($licenseMatches);
381  }
382 
383  if ($licenseMatchExists) {
384  try {
385  $this->clearingDecisionProcessor->makeDecisionFromLastEvents(
386  $itemTreeBounds, $this->userId, $this->groupId,
387  DecisionTypes::IDENTIFIED, false);
388  } catch (\Exception $e) {
389  echo "Can not auto decide as file '" .
390  $itemTreeBounds->getItemId() . "' contains candidate license.\n";
391  }
392  }
393  return $licenseMatchExists;
394  }
395 
404  private function autodecideNomosMonkNinka(ItemTreeBounds $itemTreeBounds, $matches)
405  {
406  $canDecide = (count($matches)>0);
407 
408  foreach ($matches as $licenseMatches) {
409  if (!$canDecide) { // &= is not lazy
410  break;
411  }
412  $canDecide &= $this->areNomosMonkNinkaAgreed($licenseMatches);
413  }
414 
415  if ($canDecide) {
416  $this->clearingDecisionProcessor->makeDecisionFromLastEvents($itemTreeBounds, $this->userId, $this->groupId, DecisionTypes::IDENTIFIED, $global=true);
417  }
418  return $canDecide;
419  }
420 
429  private function autodecideNomosMatchesInsideMonk(ItemTreeBounds $itemTreeBounds, $matches)
430  {
431  $canDecide = (count($matches)>0);
432 
433  foreach ($matches as $licenseMatches) {
434  if (!$canDecide) { // &= is not lazy
435  break;
436  }
437  $canDecide &= $this->areNomosMatchesInsideAMonkMatch($licenseMatches);
438  }
439 
440  if ($canDecide) {
441  $this->clearingDecisionProcessor->makeDecisionFromLastEvents($itemTreeBounds, $this->userId, $this->groupId, DecisionTypes::IDENTIFIED, $global=true);
442  }
443  return $canDecide;
444  }
445 
455  private function autodecideLicenseType(ItemTreeBounds $itemTreeBounds,
456  $matches)
457  {
458  $canDecide = $this->noLicenseConflict($itemTreeBounds, $matches);
459  if ($canDecide) {
460  $canDecide &= $this->allLicenseInType($matches);
461  }
462 
463  if ($canDecide) {
464  $this->clearingDecisionProcessor
465  ->makeDecisionFromLastEvents($itemTreeBounds, $this->userId,
466  $this->groupId, DecisionTypes::IDENTIFIED, DecisionScopes::ITEM, [], true);
467  }
468  return $canDecide;
469  }
470 
477  protected function remapByProjectedId($matches)
478  {
479  $remapped = array();
480  foreach ($matches as $licenseId => $licenseMatches) {
481  $projectedId = $this->licenseMap->getProjectedId($licenseId);
482 
483  foreach ($licenseMatches as $agent => $agentMatches) {
484  $haveId = array_key_exists($projectedId, $remapped);
485  $haveAgent = $haveId && array_key_exists($agent, $remapped[$projectedId]);
486  if ($haveAgent) {
487  $remapped[$projectedId][$agent] = array_merge($remapped[$projectedId][$agent], $agentMatches);
488  } else {
489  $remapped[$projectedId][$agent] = $agentMatches;
490  }
491  }
492  }
493  return $remapped;
494  }
495 
502  private function isRegionIncluded($small, $big)
503  {
504  return ($big[0] >= 0) && ($small[0] >= $big[0]) && ($small[1] <= $big[1]);
505  }
506 
512  private function areNomosMatchesInsideAMonkMatch($licenseMatches)
513  {
514  if (!array_key_exists("nomos", $licenseMatches)) {
515  return false;
516  }
517  if (!array_key_exists("monk", $licenseMatches)) {
518  return false;
519  }
520 
521  foreach ($licenseMatches["nomos"] as $licenseMatch) {
522  $matchId = $licenseMatch->getLicenseFileId();
523  $nomosRegion = $this->highlightDao->getHighlightRegion($matchId);
524 
525  $found = false;
526  foreach ($licenseMatches["monk"] as $monkLicenseMatch) {
527  $monkRegion = $this->highlightDao->getHighlightRegion($monkLicenseMatch->getLicenseFileId());
528  if ($this->isRegionIncluded($nomosRegion, $monkRegion)) {
529  $found = true;
530  break;
531  }
532  }
533  if (!$found) {
534  return false;
535  }
536  }
537 
538  return true;
539  }
540 
546  protected function areNomosMonkNinkaAgreed($licenseMatches)
547  {
548  $scanners = array('nomos','monk','ninka');
549  $vote = array();
550  foreach ($scanners as $scanner) {
551  if (!array_key_exists($scanner, $licenseMatches)) {
552  return false;
553  }
554  foreach ($licenseMatches[$scanner] as $licenseMatch) {
555  $licId = $licenseMatch->getLicenseId();
556  $vote[$licId][$scanner] = true;
557  }
558  }
559 
560  foreach ($vote as $licId=>$voters) {
561  if (count($voters) != 3) {
562  return false;
563  }
564  }
565  return true;
566  }
567 
574  protected function getLicenseIdsOfMatchesForScanner($scanner, $licenseMatches)
575  {
576  if (array_key_exists($scanner, $licenseMatches) === true) {
577  return array_map(
578  function ($match) {
579  return $match->getLicenseId();
580  }, $licenseMatches[$scanner]);
581  }
582  return [];
583  }
584 
590  protected function areOtherScannerFindingsAndOJOAgreed($licenseMatches)
591  {
592  $findingsByOjo = $this->getLicenseIdsOfMatchesForScanner('ojo', $licenseMatches);
593  if (count($findingsByOjo) == 0) {
594  // nothing to do
595  return false;
596  }
597 
598  $findingsByOtherScanner = $this->getLicenseIdsOfMatchesForScanner('nomos', $licenseMatches);
599  if (count($findingsByOtherScanner) == 0) {
600  // nothing found by other scanner, so no contradiction
601  return true;
602  }
603  foreach ($findingsByOtherScanner as $findingsByScanner) {
604  if (in_array($findingsByScanner, $findingsByOjo) === false) {
605  // contradiction found
606  return false;
607  }
608  }
609  return true;
610  }
611 
617  protected function areOtherScannerFindingsAndRESOAgreed($licenseMatches)
618  {
619  $findingsByReso = $this->getLicenseIdsOfMatchesForScanner('reso', $licenseMatches);
620  if (count($findingsByReso) == 0) {
621  // nothing to do
622  return false;
623  }
624 
625  $findingsByOtherScanner = $this->getLicenseIdsOfMatchesForScanner('nomos', $licenseMatches);
626  if (count($findingsByOtherScanner) == 0) {
627  // nothing found by other scanner, so no contradiction
628  return true;
629  }
630  foreach ($findingsByOtherScanner as $findingsByScanner) {
631  if (in_array($findingsByScanner, $findingsByReso) === false) {
632  // contradiction found
633  return false;
634  }
635  }
636  return true;
637  }
638 
646  $clutter_flag): void
647  {
648  if (empty($uploadId)) {
649  return;
650  }
651  $agentName = 'copyright';
652  $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
653  $scanJobProxy = new ScanJobProxy($GLOBALS['container']->get('dao.agent'), $uploadId);
654  $scanJobProxy->createAgentStatus(array($agentName));
655  $selectedScanners = $scanJobProxy->getLatestSuccessfulAgentIds();
656  if (!array_key_exists($agentName, $selectedScanners)) {
657  return;
658  }
659  $latestXpAgentId = $selectedScanners[$agentName];
660  $extrawhere = ' agent_fk='.$latestXpAgentId;
661  $allCopyrights = $this->copyrightDao->getScannerEntries('copyright',
662  $uploadTreeTableName, $uploadId, null, $extrawhere);
663 
664  if (empty($allCopyrights)) {
665  echo "No copyrights found for upload $uploadId. Skipping false positive deactivation.\n";
666  return;
667  }
668 
669  $copyrightJSON = json_encode($allCopyrights);
670  $tmpFile = tmpfile();
671  $tmpFilePath = stream_get_meta_data($tmpFile)['uri'];
672  fwrite($tmpFile, $copyrightJSON);
673  $deactivatedCopyrightData = $this->callCopyrightDeactivationClutterRemovalScript($tmpFilePath, $clutter_flag);
674  if (empty($deactivatedCopyrightData)) {
675  fclose($tmpFile);
676  return;
677  }
678  $deactivatedCopyrights = json_decode($deactivatedCopyrightData, true);
679  foreach ($deactivatedCopyrights as $deactivatedCopyright) {
680  $item = $deactivatedCopyright['uploadtree_pk'];
681  $itemTreeBounds = $this->uploadDao->getItemTreeBounds($item, $uploadTreeTableName);
682  $hash = $deactivatedCopyright['hash'];
683  $content = $deactivatedCopyright['content'];
684  $cpTable = 'copyright';
685  if ($deactivatedCopyright['is_copyright'] == "t") {
686  $action = '';
687  if (array_key_exists('decluttered_content', $deactivatedCopyright) &&
688  !empty($deactivatedCopyright['decluttered_content'])) {
689  $content = $deactivatedCopyright['decluttered_content'];
690  } else {
691  // No text update. Nothing to do.
692  $this->heartbeat(1);
693  continue;
694  }
695  } else {
696  $action = 'delete';
697  }
698  $this->copyrightDao->updateTable($itemTreeBounds, $hash, $content, $this->userId, $cpTable, $action);
699  $this->heartbeat(1);
700  }
701  fclose($tmpFile);
702  }
703 
710  private function callCopyrightDeactivationClutterRemovalScript($tmpFilePath,
711  $clutter_flag): string
712  {
713  $script = "copyrightDeactivationClutterRemovalScript.py";
714  $args = ["python3", __DIR__ . "/$script", "--file", $tmpFilePath];
715  if ($clutter_flag) {
716  $args[] = "--clutter";
717  }
718 
719  $sleepTime = 5;
720  $maxSleepTime = 25;
721 
722  $process = new Process($args);
723  $process->setTimeout(null); // Remove timeout to run indefinitely.
724  $process->setEnv(set_python_path());
725  $process->start();
726 
727  do {
728  $this->heartbeat(0);
729  sleep($sleepTime);
730  if ($sleepTime < $maxSleepTime) {
731  $sleepTime += 5;
732  }
733  } while ($process->isRunning());
734 
735  echo $process->getErrorOutput();
736 
737  return $process->getOutput();
738  }
739 
745  private function getLicenseType($licenseType)
746  {
747  global $SysConf;
748  $licenseTypes = array_map('trim', explode(',',
749  $SysConf['SYSCONFIG']['LicenseTypes']));
750  if (in_array($licenseType, $licenseTypes)) {
751  return $licenseType;
752  }
753  return "";
754  }
755 
763  protected function noLicenseConflict($itemTreeBounds, $licenseMatches)
764  {
765  $shortnames = [];
766  foreach ($licenseMatches as $agentMatch) {
767  foreach ($agentMatch as $agentLicenseMatches) {
768  foreach ($agentLicenseMatches as $licenseMatch) {
769  $shortnames[$licenseMatch->getLicenseId()] = $licenseMatch
770  ->getLicenseRef()->getShortName();
771  }
772  }
773  }
774  foreach ($shortnames as $shortname) {
775  try {
776  if (! $this->compatibilityDao->getCompatibilityForFile($itemTreeBounds,
777  $shortname)) {
778  return false;
779  }
780  } catch (InvalidAgentStageException $_) {
781  return false;
782  }
783  }
784  return true;
785  }
786 
792  protected function allLicenseInType($licenseMatches)
793  {
794  $licenseTypes = [];
795  foreach ($licenseMatches as $agentMatch) {
796  foreach ($agentMatch as $agentLicenseMatches) {
797  foreach ($agentLicenseMatches as $licenseMatch) {
798  if (!array_key_exists($licenseMatch->getLicenseId(), $licenseTypes)) {
799  $licenseTypes[$licenseMatch->getLicenseId()] = $this->licenseDao
800  ->getLicenseType($licenseMatch->getLicenseId());
801  }
802  }
803  }
804  }
805  if (! in_array($this->licenseType, $licenseTypes)) {
806  return false;
807  }
808  if (! empty(array_diff($licenseTypes, [$this->licenseType]))) {
809  return false;
810  }
811  return true;
812  }
813 }
Agent to decide license findings in an upload.
existsUnhandledMatch($projectedScannerMatches, $licensesFromDecision)
Check if matches contains unhandled match.
areOtherScannerFindingsAndRESOAgreed($licenseMatches)
Check if the finding by only contains one single license and that no other scanner (nomos) has produc...
autodecideIfResoMatchesNoContradiction(ItemTreeBounds $itemTreeBounds, $matches)
Auto decide matches which are in nomos, monk, OJO and Reso findings.
processItem(Item $item)
Given an item, check with the $activeRules and apply rules to it.
areOtherScannerFindingsAndOJOAgreed($licenseMatches)
Check if the finding by only contains one single license and that no other scanner (nomos) has produc...
callCopyrightDeactivationClutterRemovalScript($tmpFilePath, $clutter_flag)
autodecideNomosMatchesInsideMonk(ItemTreeBounds $itemTreeBounds, $matches)
Auto decide matches by nomos which are in monk findings.
noLicenseConflict($itemTreeBounds, $licenseMatches)
Check if findings by all agents are same or not.
autodecideNomosMonkNinka(ItemTreeBounds $itemTreeBounds, $matches)
Auto decide matches which are in nomos, monk and ninka findings.
processUploadId($uploadId)
Given an upload ID, process the items in it.
allLicenseInType($licenseMatches)
Check if findings by all agents are same or not.
autodecideLicenseType(ItemTreeBounds $itemTreeBounds, $matches)
Auto decide matches where there is no license conflict.
getLicenseIdsOfMatchesForScanner($scanner, $licenseMatches)
extracts the matches corresponding to a scanner from a $licenseMatches structure
isRegionIncluded($small, $big)
Check if the small highlight region is inside big one.
autodecideIfOjoMatchesNoContradiction(ItemTreeBounds $itemTreeBounds, $matches)
Auto decide matches which are in nomos, monk and OJO findings.
areNomosMatchesInsideAMonkMatch($licenseMatches)
Check if matches by nomos are inside monk findings.
getCopyrightsToDisableFalsePositivesClutter($uploadId, $clutter_flag)
remapByProjectedId($matches)
Given a set of matches, remap according to project id instead of license id.
areNomosMonkNinkaAgreed($licenseMatches)
Check if findings by all agents are same or not.
autodecideIfKotobaMatchesNoContradiction(ItemTreeBounds $itemTreeBounds, $projectedScannerMatches, $currentEvents)
Auto-conclude when kotoba events cover all scanner findings.
Structure of an Agent with all required parameters.
Definition: Agent.php:41
heartbeat($newProcessed)
Send hear beat to the scheduler.
Definition: Agent.php:203
Utility functions to process ClearingDecision.
Wrapper class for license map.
Definition: LicenseMap.php:19
set_python_path()
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:16
Namespace for decider agent.
Definition: decider.php:13