2018-11-17 17:24:34 +00:00
|
|
|
|
from contextlib import suppress
|
2018-06-10 16:47:49 +00:00
|
|
|
|
from distutils.version import StrictVersion
|
|
|
|
|
from enum import Enum, IntEnum, unique
|
2018-11-17 17:24:34 +00:00
|
|
|
|
from typing import Set, Union
|
2018-06-10 16:47:49 +00:00
|
|
|
|
|
2018-10-16 06:46:55 +00:00
|
|
|
|
import inflection
|
|
|
|
|
|
2018-06-10 16:47:49 +00:00
|
|
|
|
|
|
|
|
|
@unique
|
|
|
|
|
class SnapshotSoftware(Enum):
|
2018-07-14 14:41:22 +00:00
|
|
|
|
"""The software used to perform the Snapshot."""
|
2018-06-10 16:47:49 +00:00
|
|
|
|
Workbench = 'Workbench'
|
|
|
|
|
AndroidApp = 'AndroidApp'
|
|
|
|
|
Web = 'Web'
|
|
|
|
|
DesktopApp = 'DesktopApp'
|
|
|
|
|
|
2018-10-16 06:46:55 +00:00
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
2018-06-10 16:47:49 +00:00
|
|
|
|
|
|
|
|
|
@unique
|
|
|
|
|
class RatingSoftware(Enum):
|
2018-07-14 14:41:22 +00:00
|
|
|
|
"""The software used to compute the Score."""
|
|
|
|
|
ECost = 'ECost'
|
|
|
|
|
"""
|
|
|
|
|
The eReuse.org rate algorithm that focuses maximizing refurbishment
|
|
|
|
|
of devices in general, specially penalizing very low and very high
|
|
|
|
|
devices in order to stimulate medium-range devices.
|
|
|
|
|
|
|
|
|
|
This model is cost-oriented.
|
|
|
|
|
"""
|
|
|
|
|
EMarket = 'EMarket'
|
2018-06-10 16:47:49 +00:00
|
|
|
|
|
2018-10-16 06:46:55 +00:00
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
2018-06-10 16:47:49 +00:00
|
|
|
|
|
|
|
|
|
RATE_POSITIVE = 0, 10
|
|
|
|
|
RATE_NEGATIVE = -3, 5
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@unique
|
|
|
|
|
class RatingRange(IntEnum):
|
|
|
|
|
"""
|
|
|
|
|
The human translation to score range.
|
|
|
|
|
|
2018-11-17 16:03:03 +00:00
|
|
|
|
You can compare them: ScoreRange.VERY_LOW < ScoreRange.LOW.
|
|
|
|
|
There are four levels:
|
|
|
|
|
|
|
|
|
|
1. Very low.
|
|
|
|
|
2. Low.
|
|
|
|
|
3. Medium.
|
|
|
|
|
4. High.
|
2018-06-10 16:47:49 +00:00
|
|
|
|
"""
|
|
|
|
|
VERY_LOW = 2
|
|
|
|
|
LOW = 3
|
|
|
|
|
MEDIUM = 4
|
|
|
|
|
HIGH = 5
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def from_score(cls, val: Union[int, float]) -> 'RatingRange':
|
|
|
|
|
assert 0 <= val <= 10, 'Value is not a valid score.'
|
|
|
|
|
|
|
|
|
|
if val <= cls.VERY_LOW:
|
|
|
|
|
return cls.VERY_LOW
|
|
|
|
|
elif val <= cls.LOW:
|
|
|
|
|
return cls.LOW
|
|
|
|
|
elif val <= cls.MEDIUM:
|
|
|
|
|
return cls.MEDIUM
|
|
|
|
|
else:
|
|
|
|
|
return cls.HIGH
|
|
|
|
|
|
2018-10-16 06:46:55 +00:00
|
|
|
|
def __str__(self):
|
|
|
|
|
return inflection.humanize(self.name)
|
|
|
|
|
|
|
|
|
|
def __format__(self, format_spec):
|
|
|
|
|
return str(self)
|
|
|
|
|
|
2018-06-10 16:47:49 +00:00
|
|
|
|
|
2018-07-14 14:41:22 +00:00
|
|
|
|
@unique
|
|
|
|
|
class PriceSoftware(Enum):
|
|
|
|
|
Ereuse = 'Ereuse'
|
|
|
|
|
|
|
|
|
|
|
2018-06-10 16:47:49 +00:00
|
|
|
|
@unique
|
|
|
|
|
class AggregateRatingVersions(Enum):
|
|
|
|
|
v1 = StrictVersion('1.0')
|
|
|
|
|
"""
|
2018-07-14 14:41:22 +00:00
|
|
|
|
This version is set to aggregate :class:`ereuse_devicehub.resources.
|
|
|
|
|
event.models.WorkbenchRate` version X and :class:`ereuse_devicehub.
|
|
|
|
|
resources.event.models.PhotoboxRate` version Y.
|
2018-06-10 16:47:49 +00:00
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@unique
|
|
|
|
|
class AppearanceRange(Enum):
|
|
|
|
|
"""Grades the imperfections that aesthetically affect the device, but not its usage."""
|
|
|
|
|
Z = '0. The device is new.'
|
|
|
|
|
A = 'A. Is like new (without visual damage)'
|
|
|
|
|
B = 'B. Is in really good condition (small visual damage in difficult places to spot)'
|
|
|
|
|
C = 'C. Is in good condition (small visual damage in parts that are easy to spot, not screens)'
|
|
|
|
|
D = 'D. Is acceptable (visual damage in visible parts, not screens)'
|
|
|
|
|
E = 'E. Is unacceptable (considerable visual damage that can affect usage)'
|
|
|
|
|
|
2018-10-16 06:46:55 +00:00
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
2018-06-10 16:47:49 +00:00
|
|
|
|
|
2019-03-10 19:41:10 +00:00
|
|
|
|
@unique
|
|
|
|
|
class AppearanceRangev2(Enum):
|
|
|
|
|
"""Based on usage condition of a device and its functionality aspects/characteristics."""
|
|
|
|
|
Z = 'Z. The device is new'
|
|
|
|
|
A = 'A. Is like new; without visual damage'
|
|
|
|
|
B = 'B. Is in really good condition; small visual damage in difficult places to spot'
|
|
|
|
|
C = 'C. Is in good condition; small visual damage in parts that are easy to spot, minor cosmetic blemishes on cabinet)'
|
|
|
|
|
D = 'D. Is acceptable; visual damage in visible parts, major cosmetic blemishes on cabinet, missing cosmetic parts..'
|
|
|
|
|
E = 'E. Is unacceptable; considerable visual damage, missing essential parts,.'
|
|
|
|
|
NONE = 'NA. Grade doesn’t exists'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
APPEARANCE_RANGE = 0.5, -0.3
|
|
|
|
|
|
|
|
|
|
|
2018-06-10 16:47:49 +00:00
|
|
|
|
@unique
|
|
|
|
|
class FunctionalityRange(Enum):
|
|
|
|
|
"""Grades the defects of a device that affect its usage."""
|
|
|
|
|
# todo sync with https://github.com/ereuse/rdevicescore#input
|
|
|
|
|
A = 'A. Everything works perfectly (buttons, and in case of screens there are no scratches)'
|
|
|
|
|
B = 'B. There is a button difficult to press or a small scratch in an edge of a screen'
|
|
|
|
|
C = 'C. A non-important button (or similar) doesn\'t work; screen has multiple scratches in edges'
|
|
|
|
|
D = 'D. Multiple buttons don\'t work; screen has visual damage resulting in uncomfortable usage'
|
|
|
|
|
|
2018-10-16 06:46:55 +00:00
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
2018-06-10 16:47:49 +00:00
|
|
|
|
|
2019-02-27 22:36:26 +00:00
|
|
|
|
FUNCTIONALITY_RANGE = -0.25, 0.5
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@unique
|
|
|
|
|
class FunctionalityRangev2(Enum):
|
|
|
|
|
"""Grade the buttons and chassis that affect its usage, like screen defect or camera defects"""
|
|
|
|
|
A = 'A. All the buttons works perfectly, no screen/camera defects and chassis without issues'
|
|
|
|
|
B = 'B. There is a button difficult to press or unstable it, a screen/camera defect or chassis problem'
|
|
|
|
|
C = 'C. Multiple buttons don\'t work; broken or unusable it, some screen/camera defects and chassis problems'
|
|
|
|
|
D = 'D. All buttons. screen or chassis don\'t work; broken or unusable it, difficult to usage.'
|
|
|
|
|
NONE = 'NA. Grade doesn’t exists'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
2019-03-10 19:41:10 +00:00
|
|
|
|
|
|
|
|
|
@unique
|
|
|
|
|
class BatteryHealthRange(Enum):
|
|
|
|
|
"""Grade the battery health status, depending on self report Android system"""
|
|
|
|
|
A = 'A. The battery health is very good'
|
|
|
|
|
B = 'B. Battery health is good'
|
|
|
|
|
C = 'C. Battery health is overheat / over voltage status but can stand the minimum duration'
|
|
|
|
|
D = 'D. Battery health is bad; can’t stand the minimum duration time'
|
|
|
|
|
E = 'E. Battery health is very bad; and status is dead; unusable or miss it '
|
|
|
|
|
NONE = 'NA. Grade doesn’t exists'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
2018-06-10 16:47:49 +00:00
|
|
|
|
@unique
|
|
|
|
|
class Bios(Enum):
|
|
|
|
|
"""How difficult it has been to set the bios to boot from the network."""
|
|
|
|
|
A = 'A. If by pressing a key you could access a boot menu with the network boot'
|
|
|
|
|
B = 'B. You had to get into the BIOS, and in less than 5 steps you could set the network boot'
|
|
|
|
|
C = 'C. Like B, but with more than 5 steps'
|
|
|
|
|
D = 'D. Like B or C, but you had to unlock the BIOS (i.e. by removing the battery)'
|
|
|
|
|
E = 'E. The device could not be booted through the network.'
|
|
|
|
|
|
2018-10-16 06:46:55 +00:00
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
2018-06-10 16:47:49 +00:00
|
|
|
|
|
2019-02-27 22:36:26 +00:00
|
|
|
|
# TODO add all grade tables (chassis defects, camera defects, buttons test, connectivity, ..)
|
|
|
|
|
|
2018-06-10 16:47:49 +00:00
|
|
|
|
@unique
|
|
|
|
|
class Orientation(Enum):
|
|
|
|
|
Vertical = 'vertical'
|
|
|
|
|
Horizontal = 'Horizontal'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@unique
|
2018-10-08 08:37:32 +00:00
|
|
|
|
class TestDataStorageLength(Enum):
|
2018-06-10 16:47:49 +00:00
|
|
|
|
Short = 'Short'
|
|
|
|
|
Extended = 'Extended'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@unique
|
|
|
|
|
class ImageSoftware(Enum):
|
|
|
|
|
Photobox = 'Photobox'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@unique
|
|
|
|
|
class ImageMimeTypes(Enum):
|
|
|
|
|
"""Supported image Mimetypes for Devicehub."""
|
|
|
|
|
jpg = 'image/jpeg'
|
|
|
|
|
png = 'image/png'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@unique
|
|
|
|
|
class SnapshotExpectedEvents(Enum):
|
|
|
|
|
"""Events that Workbench can perform when processing a device."""
|
2018-07-02 10:52:54 +00:00
|
|
|
|
Benchmark = 'Benchmark'
|
2018-06-10 16:47:49 +00:00
|
|
|
|
TestDataStorage = 'TestDataStorage'
|
|
|
|
|
StressTest = 'StressTest'
|
2018-07-19 19:25:06 +00:00
|
|
|
|
EraseBasic = 'EraseBasic'
|
2018-06-10 16:47:49 +00:00
|
|
|
|
EraseSectors = 'EraseSectors'
|
2018-07-02 10:52:54 +00:00
|
|
|
|
SmartTest = 'SmartTest'
|
2018-06-10 16:47:49 +00:00
|
|
|
|
Install = 'Install'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOX_RATE_5 = 1, 5
|
|
|
|
|
BOX_RATE_3 = 1, 3
|
2018-06-12 14:50:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# After looking at own databases
|
|
|
|
|
|
|
|
|
|
@unique
|
|
|
|
|
class RamInterface(Enum):
|
2018-09-08 14:46:39 +00:00
|
|
|
|
"""
|
|
|
|
|
The interface or type of RAM.
|
|
|
|
|
|
|
|
|
|
The more common type of RAM nowadays for RamModules is SDRAM.
|
|
|
|
|
Note that we have not added all sub-types (please contact if
|
|
|
|
|
you want them). See more here
|
|
|
|
|
https://en.wikipedia.org/wiki/Category:SDRAM.
|
|
|
|
|
|
|
|
|
|
Although SDRAM is the generic naming for any DDR we include it
|
|
|
|
|
here for those cases where there is no more specific information.
|
|
|
|
|
Please, try to always use DDRø-6 denominations.
|
|
|
|
|
"""
|
|
|
|
|
SDRAM = 'SDRAM'
|
|
|
|
|
DDR = 'DDR SDRAM'
|
|
|
|
|
DDR2 = 'DDR2 SDRAM'
|
|
|
|
|
DDR3 = 'DDR3 SDRAM'
|
|
|
|
|
DDR4 = 'DDR4 SDRAM'
|
|
|
|
|
DDR5 = 'DDR5 SDRAM'
|
|
|
|
|
DDR6 = 'DDR6 SDRAM'
|
2018-06-12 14:50:05 +00:00
|
|
|
|
|
2018-10-03 12:51:22 +00:00
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.value
|
|
|
|
|
|
2018-06-12 14:50:05 +00:00
|
|
|
|
|
|
|
|
|
@unique
|
|
|
|
|
class RamFormat(Enum):
|
|
|
|
|
DIMM = 'DIMM'
|
|
|
|
|
SODIMM = 'SODIMM'
|
|
|
|
|
|
2018-10-03 12:51:22 +00:00
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.value
|
|
|
|
|
|
2018-06-12 14:50:05 +00:00
|
|
|
|
|
|
|
|
|
@unique
|
|
|
|
|
class DataStorageInterface(Enum):
|
|
|
|
|
ATA = 'ATA'
|
|
|
|
|
USB = 'USB'
|
|
|
|
|
PCI = 'PCI'
|
2018-06-20 21:18:15 +00:00
|
|
|
|
|
2018-10-03 12:51:22 +00:00
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.value
|
|
|
|
|
|
2018-06-20 21:18:15 +00:00
|
|
|
|
|
|
|
|
|
@unique
|
2018-06-26 13:35:13 +00:00
|
|
|
|
class DisplayTech(Enum):
|
2018-06-20 21:18:15 +00:00
|
|
|
|
CRT = 'Cathode ray tube (CRT)'
|
|
|
|
|
TFT = 'Thin-film-transistor liquid-crystal (TFT)'
|
|
|
|
|
LED = 'LED-backlit (LED)'
|
|
|
|
|
PDP = 'Plasma display panel (Plasma)'
|
|
|
|
|
LCD = 'Liquid-crystal display (any of TFT, LED, Blue Phase, IPS)'
|
|
|
|
|
OLED = 'Organic light-emitting diode (OLED)'
|
|
|
|
|
AMOLED = 'Organic light-emitting diode (AMOLED)'
|
2018-06-26 13:36:21 +00:00
|
|
|
|
|
2018-10-03 12:51:22 +00:00
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
2018-06-26 13:36:21 +00:00
|
|
|
|
|
|
|
|
|
@unique
|
|
|
|
|
class ComputerChassis(Enum):
|
|
|
|
|
"""The chassis of a computer."""
|
|
|
|
|
Tower = 'Tower'
|
|
|
|
|
Docking = 'Docking'
|
2018-10-03 12:51:22 +00:00
|
|
|
|
AllInOne = 'All in one'
|
2018-06-26 13:36:21 +00:00
|
|
|
|
Microtower = 'Microtower'
|
2018-10-03 12:51:22 +00:00
|
|
|
|
PizzaBox = 'Pizza box'
|
2018-06-26 13:36:21 +00:00
|
|
|
|
Lunchbox = 'Lunchbox'
|
|
|
|
|
Stick = 'Stick'
|
|
|
|
|
Netbook = 'Netbook'
|
|
|
|
|
Handheld = 'Handheld'
|
|
|
|
|
Laptop = 'Laptop'
|
|
|
|
|
Convertible = 'Convertible'
|
|
|
|
|
Detachable = 'Detachable'
|
|
|
|
|
Tablet = 'Tablet'
|
2018-10-03 12:51:22 +00:00
|
|
|
|
Virtual = 'Non-physical device'
|
|
|
|
|
|
2018-10-25 10:36:25 +00:00
|
|
|
|
def __str__(self):
|
2018-10-16 14:30:10 +00:00
|
|
|
|
return inflection.humanize(inflection.underscore(self.value))
|
2018-08-03 16:15:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ReceiverRole(Enum):
|
|
|
|
|
"""
|
|
|
|
|
The role that the receiver takes in the reception;
|
|
|
|
|
the meaning of the reception.
|
|
|
|
|
"""
|
|
|
|
|
Intermediary = 'Generic user in the workflow of the device.'
|
|
|
|
|
FinalUser = 'The user that will use the device.'
|
|
|
|
|
CollectionPoint = 'A collection point.'
|
|
|
|
|
RecyclingPoint = 'A recycling point.'
|
|
|
|
|
Transporter = 'An user that ships the devices to another one.'
|
2018-10-13 12:53:46 +00:00
|
|
|
|
|
|
|
|
|
|
2018-10-23 13:37:37 +00:00
|
|
|
|
class PrinterTechnology(Enum):
|
|
|
|
|
"""Technology of the printer."""
|
|
|
|
|
Toner = 'Toner / Laser'
|
|
|
|
|
Inkjet = 'Liquid inkjet'
|
|
|
|
|
SolidInk = 'Solid ink'
|
|
|
|
|
Dye = 'Dye-sublimation'
|
|
|
|
|
Thermal = 'Thermal'
|
2018-11-08 16:37:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Severity(IntEnum):
|
|
|
|
|
"""A flag evaluating the event execution. Ex. failed events
|
2019-02-03 16:12:53 +00:00
|
|
|
|
have the value `Severity.Error`. Devicehub uses 4 severity levels:
|
2018-11-08 16:37:14 +00:00
|
|
|
|
|
2019-02-03 16:12:53 +00:00
|
|
|
|
* Info: default neutral severity. The event succeeded.
|
|
|
|
|
* Notice: The event succeeded but it is raising awareness.
|
2018-11-08 16:37:14 +00:00
|
|
|
|
Notices are not usually that important but something
|
|
|
|
|
(good or bad) worth checking.
|
2019-02-03 16:12:53 +00:00
|
|
|
|
* Warning: The event succeeded but there is something important
|
2018-11-08 16:37:14 +00:00
|
|
|
|
to check negatively affecting the event.
|
2019-02-03 16:12:53 +00:00
|
|
|
|
* Error: the event failed.
|
2018-11-08 16:37:14 +00:00
|
|
|
|
|
|
|
|
|
Devicehub specially raises user awareness when an event
|
|
|
|
|
has a Severity of ``Warning`` or greater.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
Info = 0
|
|
|
|
|
Notice = 1
|
|
|
|
|
Warning = 2
|
|
|
|
|
Error = 3
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
if self == self.Info:
|
|
|
|
|
m = '✓'
|
|
|
|
|
elif self == self.Notice:
|
|
|
|
|
m = 'ℹ️'
|
|
|
|
|
elif self == self.Warning:
|
|
|
|
|
m = '⚠'
|
|
|
|
|
else:
|
|
|
|
|
m = '❌'
|
|
|
|
|
return m
|
2018-11-15 12:35:19 +00:00
|
|
|
|
|
2018-11-21 13:26:56 +00:00
|
|
|
|
def __format__(self, format_spec):
|
|
|
|
|
return str(self)
|
|
|
|
|
|
2018-11-15 12:35:19 +00:00
|
|
|
|
|
|
|
|
|
class PhysicalErasureMethod(Enum):
|
|
|
|
|
"""Methods of physically erasing the data-storage, usually
|
|
|
|
|
destroying the whole component.
|
|
|
|
|
|
|
|
|
|
Certified data-storage destruction mean, as of `UNE-EN 15713
|
|
|
|
|
<https://www.une.org/encuentra-tu-norma/busca-tu-norma/norma?c=N0044792>`_,
|
|
|
|
|
reducing the material to a size making it undecipherable, illegible,
|
|
|
|
|
and non able to be re-built.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
Shred = 'Reduction of the data-storage to the required certified ' \
|
|
|
|
|
'standard sizes.'
|
|
|
|
|
Disintegration = 'Reduction of the data-storage to smaller sizes ' \
|
|
|
|
|
'than the certified standard ones.'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ErasureStandards(Enum):
|
2018-11-17 16:03:03 +00:00
|
|
|
|
"""Software erasure standards."""
|
|
|
|
|
|
2018-11-15 12:35:19 +00:00
|
|
|
|
HMG_IS5 = 'British HMG Infosec Standard 5 (HMG IS5)'
|
|
|
|
|
"""`British HMG Infosec Standard 5 (HMG IS5)
|
|
|
|
|
<https://en.wikipedia.org/wiki/Infosec_Standard_5>`_.
|
|
|
|
|
|
|
|
|
|
In order to follow this standard, an erasure must have the
|
|
|
|
|
following steps:
|
|
|
|
|
|
|
|
|
|
1. A first step writing zeroes to the data-storage units.
|
|
|
|
|
2. A second step erasing with random data, verifying the erasure
|
|
|
|
|
success in each hard-drive sector.
|
|
|
|
|
|
|
|
|
|
And be an :class:`ereuse_devicehub.resources.event.models.EraseSectors`.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.value
|
|
|
|
|
|
|
|
|
|
@classmethod
|
2018-11-17 17:24:34 +00:00
|
|
|
|
def from_data_storage(cls, erasure) -> Set['ErasureStandards']:
|
|
|
|
|
"""Returns a set of erasure standards."""
|
|
|
|
|
from ereuse_devicehub.resources.event import models as events
|
|
|
|
|
standards = set()
|
|
|
|
|
if isinstance(erasure, events.EraseSectors):
|
|
|
|
|
with suppress(ValueError):
|
|
|
|
|
first_step, *other_steps = erasure.steps
|
|
|
|
|
if isinstance(first_step, events.StepZero) \
|
|
|
|
|
and all(isinstance(step, events.StepRandom) for step in other_steps):
|
|
|
|
|
standards.add(cls.HMG_IS5)
|
|
|
|
|
return standards
|