예제 #1
0
    def testGlobRawVMDKExtension(self):
        """Test the glob function for a RAW VMDK extension scheme."""
        segment_filenames = ['image-f001.vmdk']
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        # Test single segment file: 001.
        path_spec = fake_path_spec.FakePathSpec(location='/image-f001.vmdk')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test non exiting segment file: 001.
        expected_segment_file_path_specs = []

        path_spec = fake_path_spec.FakePathSpec(location='/bogus-f000.vmdk')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test multiple segment files: 001-010.
        segment_filenames = [
            'image-f001.vmdk', 'image-f002.vmdk', 'image-f003.vmdk',
            'image-f004.vmdk', 'image-f005.vmdk', 'image-f006.vmdk',
            'image-f007.vmdk', 'image-f008.vmdk', 'image-f009.vmdk',
            'image-f010.vmdk'
        ]
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        path_spec = fake_path_spec.FakePathSpec(location='/image-f001.vmdk')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)
예제 #2
0
파일: raw.py 프로젝트: olivierh59500/dfvfs
    def testGlobRawAsbExtension(self):
        """Test the glob function for a RAW ASB extension scheme."""
        segment_filenames = [u'image001.asb']
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        # Test single segment file: 001.
        path_spec = fake_path_spec.FakePathSpec(location=u'/image001.asb')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test non exiting segment file: 001.
        expected_segment_file_path_specs = []

        path_spec = fake_path_spec.FakePathSpec(location=u'/bogus000.asb')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test multiple segment files: 001-010.
        segment_filenames = [
            u'image001.asb', u'image002.asb', u'image003.asb', u'image004.asb',
            u'image005.asb', u'image006.asb', u'image007.asb', u'image008.asb',
            u'image009.asb', u'image010.asb'
        ]
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        path_spec = fake_path_spec.FakePathSpec(location=u'/image001.asb')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)
예제 #3
0
    def ScanForStorageMediaImage(self, source_path_spec):
        """Scans the path specification for a supported storage media image format.

    Args:
      source_path_spec (PathSpec): source path specification.

    Returns:
      PathSpec: storage media image path specification or None if no supported
          storage media image type was found.

    Raises:
      BackEndError: if the source cannot be scanned or more than one storage
          media image type is found.
    """
        try:
            type_indicators = analyzer.Analyzer.GetStorageMediaImageTypeIndicators(
                source_path_spec, resolver_context=self._resolver_context)
        except RuntimeError as exception:
            raise errors.BackEndError(
                ('Unable to process source path specification with error: '
                 '{0!s}').format(exception))

        if not type_indicators:
            # The RAW storage media image type cannot be detected based on
            # a signature so we try to detect it based on common file naming schemas.
            file_system = resolver.Resolver.OpenFileSystem(
                source_path_spec, resolver_context=self._resolver_context)
            raw_path_spec = path_spec_factory.Factory.NewPathSpec(
                definitions.TYPE_INDICATOR_RAW, parent=source_path_spec)

            try:
                # The RAW glob function will raise a PathSpecError if the path
                # specification is unsuitable for globbing.
                glob_results = raw.RawGlobPathSpec(file_system, raw_path_spec)
            except errors.PathSpecError:
                glob_results = None

            file_system.Close()

            if not glob_results:
                return None

            return raw_path_spec

        if len(type_indicators) > 1:
            raise errors.BackEndError(
                'Unsupported source found more than one storage media image types.'
            )

        return path_spec_factory.Factory.NewPathSpec(type_indicators[0],
                                                     parent=source_path_spec)
예제 #4
0
    def _OpenFileObject(self, path_spec):
        """Opens the file-like object defined by path specification.

    Args:
      path_spec: the path specification (instance of path.PathSpec).

    Returns:
      A file-like object or None.

    Raises:
      PathSpecError: if the path specification is invalid.
    """
        if not path_spec.HasParent():
            raise errors.PathSpecError(
                u'Unsupported path specification without parent.')

        parent_path_spec = path_spec.parent

        file_system = resolver.Resolver.OpenFileSystem(
            parent_path_spec, resolver_context=self._resolver_context)

        # Note that we cannot use pysmraw's glob function since it does not
        # handle the file system abstraction dfvfs provides.
        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        if not segment_file_path_specs:
            return

        if parent_path_spec.IsSystemLevel():
            # Typically the file-like object cache should have room for 127 items.
            self._resolver_context.SetMaximumNumberOfFileObjects(
                len(segment_file_path_specs) + 127)

        file_objects = []
        for segment_file_path_spec in segment_file_path_specs:
            file_object = resolver.Resolver.OpenFileObject(
                segment_file_path_spec,
                resolver_context=self._resolver_context)
            file_objects.append(file_object)

        raw_handle = pysmraw.handle()
        raw_handle.open_file_objects(file_objects)
        return raw_handle
예제 #5
0
    def testGlobRawSinglecExtension(self):
        """Test the glob function for a RAW single extension scheme."""
        # Test single segment file: dd.
        segment_filenames = ['ímynd.dd']
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        path_spec = fake_path_spec.FakePathSpec(location='/ímynd.dd')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test single segment file: dmg.
        segment_filenames = ['image.dmg']
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        path_spec = fake_path_spec.FakePathSpec(location='/image.dmg')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test single segment file: img.
        segment_filenames = ['image.img']
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        path_spec = fake_path_spec.FakePathSpec(location='/image.img')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test single segment file: raw.
        segment_filenames = ['image.raw']
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        path_spec = fake_path_spec.FakePathSpec(location='/image.raw')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)
예제 #6
0
    def testGlobRawNumericSuffix(self):
        """Test the glob function for a RAW numeric suffix scheme."""
        segment_filenames = ['image1']
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        # Test single segment file: 000.
        path_spec = fake_path_spec.FakePathSpec(location='/image1')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test non exiting segment file: 000.
        expected_segment_file_path_specs = []

        path_spec = fake_path_spec.FakePathSpec(location='/bogus1')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test multiple segment files: 000-010.
        segment_filenames = [
            'image0', 'image1', 'image2', 'image3', 'image4', 'image5',
            'image6', 'image7', 'image8', 'image9', 'image10'
        ]
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        path_spec = fake_path_spec.FakePathSpec(location='/image0')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test multiple segment files: 1-10.
        segment_filenames = [
            'image1', 'image2', 'image3', 'image4', 'image5', 'image6',
            'image7', 'image8', 'image9', 'image10'
        ]
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        path_spec = fake_path_spec.FakePathSpec(location='/image1')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test multiple segment files: 001-010.
        segment_filenames = [
            'image001', 'image002', 'image003', 'image004', 'image005',
            'image006', 'image007', 'image008', 'image009', 'image010'
        ]
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        path_spec = fake_path_spec.FakePathSpec(location='/image001')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)
예제 #7
0
    def testGlobRawAlphabeticalSuffix(self):
        """Test the glob function for a RAW alphabetical suffix scheme."""
        segment_filenames = ['imageaaa']
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        # Test single segment file: aaa.
        path_spec = fake_path_spec.FakePathSpec(location='/imageaaa')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test non exiting segment file: aaa.
        expected_segment_file_path_specs = []

        path_spec = fake_path_spec.FakePathSpec(location='/bogusaaa')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test multiple segment files: aaa-aak.
        segment_filenames = [
            'imageaaa', 'imageaab', 'imageaac', 'imageaad', 'imageaae',
            'imageaaf', 'imageaag', 'imageaah', 'imageaai', 'imageaaj',
            'imageaak'
        ]
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        path_spec = fake_path_spec.FakePathSpec(location='/imageaaa')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test multiple segment files: AAA-AAk.
        segment_filenames = [
            'imageAAA', 'imageAAB', 'imageAAC', 'imageAAD', 'imageAAE',
            'imageAAF', 'imageAAG', 'imageAAH', 'imageAAI', 'imageAAJ',
            'imageAAK'
        ]
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        path_spec = fake_path_spec.FakePathSpec(location='/imageAAA')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)
예제 #8
0
    def GetBasePathSpec(self, source_path):
        """Determines the base path specification.

    Args:
      source_path: the source path.

    Returns:
      The base path specification (instance of dfvfs.PathSpec).

    Raises:
      RuntimeError: if the source path does not exists, or if the source path
                    is not a file or directory, or if the format of or within
                    the source file is not supported.
    """
        if not os.path.exists(source_path):
            raise RuntimeError(u'No such source: {0:s}.'.format(source_path))

        stat_info = os.stat(source_path)

        if (not stat.S_ISDIR(stat_info.st_mode)
                and not stat.S_ISREG(stat_info.st_mode)):
            raise RuntimeError(
                u'Unsupported source: {0:s} not a file or directory.'.format(
                    source_path))

        if stat.S_ISDIR(stat_info.st_mode):
            path_spec = path_spec_factory.Factory.NewPathSpec(
                definitions.TYPE_INDICATOR_OS, location=source_path)

        elif stat.S_ISREG(stat_info.st_mode):
            path_spec = path_spec_factory.Factory.NewPathSpec(
                definitions.TYPE_INDICATOR_OS, location=source_path)

            type_indicators = analyzer.Analyzer.GetStorageMediaImageTypeIndicators(
                path_spec)

            if len(type_indicators) > 1:
                raise RuntimeError((
                    u'Unsupported source: {0:s} found more than one storage media '
                    u'image types.').format(source_path))

            if len(type_indicators) == 1:
                path_spec = path_spec_factory.Factory.NewPathSpec(
                    type_indicators[0], parent=path_spec)

            if not type_indicators:
                # The RAW storage media image type cannot be detected based on
                # a signature so we try to detect it based on common file naming
                # schemas.
                file_system = resolver.Resolver.OpenFileSystem(path_spec)
                raw_path_spec = path_spec_factory.Factory.NewPathSpec(
                    definitions.TYPE_INDICATOR_RAW, parent=path_spec)

                glob_results = raw.RawGlobPathSpec(file_system, raw_path_spec)
                if glob_results:
                    path_spec = raw_path_spec

            # In case we did not find a storage media image type we keep looking
            # since not all RAW storage media image naming schemas are known and
            # its type can only detected by its content.

            path_spec = self._GetUpperLevelVolumeSystemPathSpec(path_spec)

            # In case we did not find a volume system type we keep looking
            # since we could be dealing with a store media image that contains
            # a single volume.

            type_indicators = analyzer.Analyzer.GetFileSystemTypeIndicators(
                path_spec)

            if len(type_indicators) > 1:
                raise RuntimeError((
                    u'Unsupported source: {0:s} found more than one file system '
                    u'types.').format(source_path))

            if not type_indicators:
                logging.warning(u'Unable to find a supported file system.')
                path_spec = path_spec_factory.Factory.NewPathSpec(
                    definitions.TYPE_INDICATOR_OS, location=source_path)

            elif type_indicators[0] != definitions.TYPE_INDICATOR_TSK:
                raise RuntimeError((
                    u'Unsupported source: {0:s} found unsupported file system '
                    u'type: {1:s}.').format(source_path, type_indicators[0]))

            else:
                path_spec = path_spec_factory.Factory.NewPathSpec(
                    definitions.TYPE_INDICATOR_TSK,
                    location=u'/',
                    parent=path_spec)

        return path_spec
예제 #9
0
        (u'Unsupported source: {0:s} found more than one storage media '
         u'image types.').format(source_path))

if len(type_indicators) == 1:
    path_spec = path_spec_factory.Factory.NewPathSpec(type_indicators[0],
                                                      parent=path_spec)

if not type_indicators:
    # The RAW storage media image type cannot be detected based on
    # a signature so we try to detect it based on common file naming
    # schemas.
    file_system = resolver.Resolver.OpenFileSystem(path_spec)
    raw_path_spec = path_spec_factory.Factory.NewPathSpec(
        definitions.TYPE_INDICATOR_RAW, parent=path_spec)

    glob_results = raw.RawGlobPathSpec(file_system, raw_path_spec)
    if glob_results:
        path_spec = raw_path_spec

volume_system_path_spec = path_spec_factory.Factory.NewPathSpec(
    definitions.TYPE_INDICATOR_TSK_PARTITION, location=u'/', parent=path_spec)

volume_system = tsk_volume_system.TSKVolumeSystem()
volume_system.Open(volume_system_path_spec)

volume_identifiers = []
for volume in volume_system.volumes:
    volume_identifier = getattr(volume, 'identifier', None)
    if volume_identifier:
        volume_identifiers.append(volume_identifier)
예제 #10
0
파일: raw.py 프로젝트: olivierh59500/dfvfs
    def testGlobRawNumericExtension(self):
        """Test the glob function for a RAW numeric extension scheme."""
        segment_filenames = [u'image.000']
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        # Test single segment file: 000.
        path_spec = fake_path_spec.FakePathSpec(location=u'/image.000')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test non exiting segment file: 000.
        expected_segment_file_path_specs = []

        path_spec = fake_path_spec.FakePathSpec(location=u'/bogus.000')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test multiple segment files: 000-010.
        segment_filenames = [
            u'image.000', u'image.001', u'image.002', u'image.003',
            u'image.004', u'image.005', u'image.006', u'image.007',
            u'image.008', u'image.009', u'image.010'
        ]
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        path_spec = fake_path_spec.FakePathSpec(location=u'/image.000')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test multiple segment files: 001-010.
        segment_filenames = [
            u'image.001', u'image.002', u'image.003', u'image.004',
            u'image.005', u'image.006', u'image.007', u'image.008',
            u'image.009', u'image.010'
        ]
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        path_spec = fake_path_spec.FakePathSpec(location=u'/image.001')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)

        # Test multiple segment files: 1-10.
        segment_filenames = [
            u'image.1', u'image.2', u'image.3', u'image.4', u'image.5',
            u'image.6', u'image.7', u'image.8', u'image.9', u'image.10'
        ]
        expected_segment_file_path_specs = []
        file_system = self._BuildFileFakeFileSystem(
            segment_filenames, expected_segment_file_path_specs)

        path_spec = fake_path_spec.FakePathSpec(location=u'/image.1')
        path_spec = raw_path_spec.RawPathSpec(parent=path_spec)

        segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec)
        self.assertEqual(len(segment_file_path_specs),
                         len(expected_segment_file_path_specs))
        self.assertEqual(segment_file_path_specs,
                         expected_segment_file_path_specs)