-1

I can read code, and adjust code a bit.

I've got access to a company email (say invoice@rr.com).

I want code which looks through all new mail in the inbox of invoice@rr.com (best if this works even when Outlook is not open, but a manually clicked macro would make me happy) and reply to all (with attachment) when:

  • there is more then one attachment (exception is one .xml and one .pdf file)
  • the attachment is not .pdf, .xml or .icf
  • when there is no attachment at all
  • when the title has the word "reminder"
  • when the message has the word "reminder"

Besides that, the code needs to move the mail to a subfolder called "send back".

I've been reading forums and one of the problems is a picture in a signature also counts as an attachment.

First try after help from Tony:

Sub reply()

'still need to get rid of all the stuff i dont use below (up to the *) but still not sure about the code so I left it here for now
Dim olInspector As Outlook.Inspector
Dim olDocument As Outlook.DocumentItem
Dim olSelection As Outlook.Selection
Dim olReply As MailItem
Dim olAtt As Attachment
Dim olFileType As String
Dim AttachCount As Long
Dim AttachDtl() As String
Dim ExcelWkBk As Excel.Workbook
Dim FileName As String
Dim FolderTgt As MAPIFolder
Dim HtmlBody As String
Dim InterestingItem As Boolean
Dim InxAttach As Long
Dim InxItemCrnt As Long
Dim PathName As String
Dim ReceivedTime As Date
Dim RowCrnt As Long
Dim SenderEmailAddress As String
Dim SenderName As String
Dim Subject As String
Dim TextBody As String
Dim myDestFolder As Outlook.Folder
'*

Set myDestFolder = Session.Folders("Outlook Data File").Folders("replied")
Set Myselect = Outlook.ActiveExplorer.Selection '(i use this in my test to only process selected test mails)
'Set FolderTgt = Session.Folders("invoice@rr.com").Folders("Inbox") ***(this will replace the code above)
For InxItemCrnt = Myselect.Items.Count To 1 Step -1 '(myselect = foldertgt in live)
With Myselect.Items.Item(InxItemCrnt) '(myselect = foldertgt in live)

'still need a workaround for mail with (1 .PDF and 1 .ICF) or (1 .PDF and 1 .XML)
'those combinations are the only combinations when more then one attachment is allowed

'1st filter
If AttachCount = 0 Then 'no attachment = reply
Reply0
.move myDestFolder
Else

'2nd filter
If AttachCount > 1 Then 'more then one attachment = reply
Reply1
.move myDestFolder
Else

'3rd filter
If InStr(Subject, "Reminder") = 0 Then 'reminders need to go to a different mailbox
Reply2
.move myDestFolder
Else

'4th filter
Select Case olFileType
Case ".pdf, .icf, .xml"
If olFileType = LCase$(Right$(olAtt.FileName, 4)) Then
Exit Sub 'if attachment = pdf or ICF then this sub can exit
Else
Reply3 'all mails with incorrect files
.move myDestFolder
End Select
End If
End If
End If
End If
End With



'replies below


Reply0:
        Set olReply = Item.Reply '// Reply if no attachment found
        olReply.Body = "this is an automatic generated mail." & vbCrLf & vbCrLf & vbCrLf & vbCrLf & vbCrLf & ".... insert text...." 'still need to insert some text
        olReply.Send

Reply1:
        Set olReply = Item.Reply '// Reply more then one attachment
        olReply.Body = "this is an automatic generated mail." & vbCrLf & vbCrLf & vbCrLf & vbCrLf & vbCrLf & ".... insert text...." 'still need to insert some text
        olReply.Send

Reply2:
        Set olReply = Item.Reply '// Reply reminders need to go to reminder@rr.com
        olReply.Body = "this is an automatic generated mail." & vbCrLf & vbCrLf & vbCrLf & vbCrLf & vbCrLf & ".... insert text...." 'still need to insert some text
        olReply.Send

Reply3:
        Set olReply = Item.Reply '// Reply not correct file
        olReply.Body = "this is an automatic generated mail." & vbCrLf & vbCrLf & vbCrLf & vbCrLf & vbCrLf & ".... insert text...." 'still need to insert some text
        olReply.Send

Next


    Set olInspector = Nothing
    Set olDocument = Nothing
    Set olSelection = Nothing
    Set olAtt = Nothing
End Sub

2nd try after some more help from Tony: (note: I'm Dutch so some code has dutch words I'll explain them in English behind the code, it basicly is copy paste from his answer, all credits to Tony)

Sub reply()

  Dim Fso As New FileSystemObject
  Dim DiagFile As TextStream
  Dim FldrInvInbox As MAPIFolder
  Dim InxA As Long
  Dim InxItemCrnt As Long
  Dim NumIcfAttach As Long
  Dim NumPdfAttach As Long
  Dim NumXmlAttach As Long
  Dim NumDocAttach As Long
  Dim NumDoxAttach As Long
  Dim PathDiag As String
  Dim Pos As Long
  Dim ProcessThisEmail As Boolean
  Dim Subject As String
  Dim ReminderInBody As Boolean
  Dim ReminderInSubject As Boolean
  Dim ReminderInBody1 As Boolean
  Dim ReminderInSubject1 As Boolean

  Set FldrInvInbox = Session.Folders("invoice@rr.com").Folders("Postvak IN") 'Postvak IN = Inbox)

  PathDiag = "z:\VBA test" 'location for diagnostics report

  Set DiagFile = Fso.CreateTextFile(PathDiag & "\Diag.txt", True, False)

  For InxItemCrnt = FldrInvInbox.Items.Count To 1 Step -1

  With FldrInvInbox.Items.Item(InxItemCrnt)

      ' It is unlikely an Inbox will contain anything but emails
      ' but it does no harm to check
      If .Class = olMail Then

      ' Extract information that will identify if this email is to be processed

      ProcessThisEmail = True  ' Assume True until find otherwise


     'Below i'm looking for reminder, payment reminder and other similiar text in subject, dutch words are betalingsherinnering and openstaande posten

        If InStr(1, LCase(.Subject), "betalingsherinnering") = 0 Then
          ReminderInSubject = False
        Else
          ReminderInSubject = True
          ProcessThisEmail = False
        End If

    If InStr(1, LCase(.Subject), "openstaande posten") = 0 Then
          ReminderInSubject1 = False
        Else
          ReminderInSubject1 = True
          ProcessThisEmail = False
        End If

     'Below i'm looking for reminder, payment reminder and other similiar text in mail, dutch words are betalingsherinnering and openstaande posten
        If InStr(1, LCase(.Body), "betalingsherinnering") = 0 Then
          ReminderInBody = False
        Else
          ReminderInBody = True
          ProcessThisEmail = False
        End If


        If InStr(1, LCase(.Body), "openstaande posten") = 0 Then
          ReminderInBody1 = False
        Else
          ReminderInBody1 = True
          ProcessThisEmail = False
        End If

        NumIcfAttach = 0
        NumPdfAttach = 0
        NumXmlAttach = 0
        NumDocAttach = 0

        For InxA = 1 To .Attachments.Count

          Select Case LCase(Right$(.Attachments(InxA).FileName, "3"))
            Case "txt"
              NumIcfAttach = NumIcfAttach + 1 'code will be changed soon, need to look at ICF in the name of the attachment

            Case "pdf"
              NumPdfAttach = NumPdfAttach + 1

            Case "doc"
              NumDocAttach = NumDocAttach + 1

            Case "xml"
              NumXmlAttach = NumXmlAttach + 1

          End Select
        Next InxA
      Else  ' Not email
        ProcessThisEmail = False
      End If
    End With

    ' Decide if email is to be processed

    If ProcessThisEmail = True Then

      If NumXmlAttach > 1 Then
        ProcessThisEmail = False
        Else
    If NumDocAttach <> 0 Then
        ProcessThisEmail = False
        Else
    If NumPdfAttach > 1 Then
        ProcessThisEmail = False
        Else
    If NumIcfAttach > 1 Then
        ProcessThisEmail = False
        Else
    If NumIcfAttach + NumPdfAttach = 2 Then
        ProcessThisEmail = True
        Else
    If NumXmlAttach + NumPdfAttach = 2 Then
        ProcessThisEmail = True
        Else
    If NumXmlAttach = 1 And NumIcfAttach = 0 And NumPdfAttach = 0 And NumDocAttach = 0 Then
        ProcessThisEmail = True
        Else
    If NumPdfAttach = 1 And NumIcfAttach = 0 And NumXmlAttach = 0 And NumDocAttach = 0 Then
        ProcessThisEmail = True
        Else
    If NumIcfAttach = 1 And NumXmlAttach = 0 And NumPdfAttach = 0 And NumDocAttach = 0 Then
        ProcessThisEmail = True
        Else
    If NumXmlAttach + NumPdfAttach + NumIcfAttach = 0 Then
        ProcessThisEmail = False
        Else
    If NumXmlAttach + NumIcfAttach = 2 Then
        ProcessThisEmail = False
        Else
    If NumXmlAttach + NumPdfAttach + NumIcfAttach = 3 Then
        ProcessThisEmail = False
        Else
    If NumIcfAttach + NumPdfAttach <> 2 Then
        ProcessThisEmail = False
        Else
    If NumXmlAttach + NumPdfAttach <> 2 Then
        ProcessThisEmail = False
        Else
        Procisthisemail = False

      End If
      End If
      End If
      End If
      End If
      End If
      End If
      End If
      End If
      End If
      End If
      End If
      End If
      End If
      End If

    ' Output diagnostic information

    DiagFile.WriteLine "----- " & InxItemCrnt & " -----"
    With FldrInvInbox.Items.Item(InxItemCrnt)
      DiagFile.WriteLine "ReceivedTime=" & .ReceivedTime
      DiagFile.WriteLine "Sender=" & .Sender
      Subject = .Subject
      For Pos = Len(Subject) To 1 Step -1
       If AscW(Mid(Subject, Pos, 1)) < 1 Or _
          AscW(Mid(Subject, Pos, 1)) > 255 Then
         Subject = Replace(Subject, Mid(Subject, Pos, 1), "?")
       End If
      Next
      DiagFile.WriteLine "Subject=" & Subject
      DiagFile.WriteLine "Reminders: Subject 1=" & ReminderInSubject & _
                         " Subject 2=" & ReminderInSubject1 & _
                         " Body 1=" & ReminderInBody & _
                         " Body 2=" & ReminderInBody1
      DiagFile.WriteLine "Attachment counts: ICF=" & NumIcfAttach & _
                         " PDF=" & NumPdfAttach & " XML=" & NumXmlAttach & _
                         " Doc=" & NumDocAttach

      DiagFile.WriteLine "ProcessThisEmail=" & ProcessThisEmail

    End With

    ' Process email if required

    If ProcessThisEmail Then

    End If

  Next InxItemCrnt

  DiagFile.Close

End Sub
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Wilco RR
  • 1
  • 3
  • 5
    Can you show us your current attempted code? – 0m3r Aug 03 '18 at 16:51
  • Without your code we have no clue as to how far you have got. Do you know how to access the Inbox of invoice@rr.com from your system? Do you know how to count and access the attachments of an email? Do you know how to check the extension of an attachment? Do you know how to check if the title includes "remainder"? Do you know how to check if body includes "remainder"? None of these are particularly difficult and you should be able to find examples of each task. Can you merge the separate pieces of code? – Tony Dallimore Aug 05 '18 at 16:02
  • Have a look at this answer of mine: https://stackoverflow.com/a/12146315/973283. The question has nothing to do with your requirement but the answer might be helpful. It reads down an Inbox outputting selected properties of every email to an Excel workbook. It shows how to access subject, text body, html body and the attachments. If you extracted the relevant bits, you would be a long way towards your goal. – Tony Dallimore Aug 05 '18 at 16:10
  • thank you Tony and 0m3r for the response i'll post it later today after i tried to get relevant parts of code from the post of Tony. Busy with other stuff in the company but will post today! thank you so much in advance! – Wilco RR Aug 06 '18 at 06:45
  • Tony Dallimore i've entered some untested code. This is 3 hours of work (for me) going to test it tomorrow, stuff like Dim ExcelWkBk As Excel.Workbook need to be delete before i can test it and running out of time today, need to get some of my daily work done now. – Wilco RR Aug 06 '18 at 13:07
  • Thanks so far Tony for the answers given below, i'm going to test it further today, and the HTML tip is great! I'll update this post today in which i hope to clarify my selection methods to come to a response – Wilco RR Aug 13 '18 at 06:40

1 Answers1

1

My first reaction is: there is way too much untested code in your revised question. I plan to review your code but most of this answer is a tutorial explaining how I would have tackled your requirement.

None of us were born with the knowledge to write the macro you need. I started with Excel VBA which I believe was lucky since the training material for Excel VBA is much better than that for Outlook VBA. I visited a good library and borrowed several “Teach yourself to program Excel” books. I tried them all and then bought the one that was best for my learning style. I would recommend you invest a few days learning Excel VBA. I am confident that this investment will quickly repay itself. I did buy a highly recommended Outlook VBA but was not impressed. The transition from Excel to Outlook was not as easy as it could have been because I have never found a good explanation of the Outlook Object Model. Most of my knowledge is the result of much experimentation over many years. This background means I can usually look at some badly explained Outlook property and be able to deduce what they meant to say.

One of my advantages is that I have spent time studying development and testing theory. There is little in your code that is wrong but I believe a different approach would produce the desired result more quickly.

Another advantage which I would recommend to you is a folder on my system named “Resources” with sub-folders by topic. Every time I complete a development, I look through the code for ideas I might need again. I capture each idea in a file in the appropriate sub-folder with sample code, references to the source and notes on anything I found difficult. I don’t use VBA often enough to remember everything I have learnt. Being able to look for relevant files when starting a new development saves me a lot of time.

That’s enough general points. From your original question, I think you need the following for your requirement:

  • To read up or down the Inbox of invoice@rr.com.
  • To identify the number of attachments of an email and, if any, their extensions.
  • To check if the title of an email includes "remainder".
  • To check if body of an email includes "remainder".
  • To reply to selected emails
  • To move selected emails to folder “send back”

Your original specification of which emails were to be selected is not clear to me. Your added code is a little clearer but adds the complication that you appear to envisage different replies for different emails.

In your code, you do not read up or down the Inbox of invoice@rr.com. Instead you use Inspector to process selected emails. This would allow you to select an email with no attachments, say, and test how you code handles it. I do not think this is a good idea. For me, reading down the inbox and selecting the emails to be processed is the larger and more complicated block of code. I would want to write and test that code before writing the code to replying or moving emails. I would not want to reply to emails until I knew I had everything else correct. I would not want to move emails to a different folder until near the end of testing because I would not want to move them back for a retest.

The potential problem with my approach is the number of emails in the Inbox of invoice@rr.com. How do I test each email is correctly identified as needing a reply or not needing a reply? VBA comes with some diagnostic aids but one of my favourite technique is to write the envelope for my code but to output diagnostic text identifying the decisions made by the code without acting on those decisions. The code I have written shows what I mean by this.

To output diagnostic text, I can use something like Debug.Print "xxxx=" & xxxx where xxxx is a variable. This outputs to the Immediate Window which is often the most convenient technique. But you can only see the last 200 or so displays with Debug.Print and I suspect this will not be enough. Instead I will output to a text file. I do not do this often enough to remember the syntax so I have a file to remind me. File “Output to diagnostic file.txt” contains:

  ' Needs reference to Microsoft Scripting Runtime  

  Dim Fso As New FileSystemObject
  Dim DiagFile As TextStream
  Dim PathDiag As String

  PathDiag = ThisWorkbook.Path
  PathDiag = CreateObject("WScript.Shell").specialfolders("Desktop")

  Set DiagFile = Fso.CreateTextFile(PathDiag & "\Diag.txt", True, False)

  DiagFile.WriteLine ""

  DiagFile.Close

I do not need the reminder about “Microsoft Scripting Runtime” for Outlook because I referenced it when I first installed Outlook. You will need to open the Outlook VBA Editor, click Tools and select References from the drop down menu. Scroll down the list of libraries and tick “Microsoft Scripting Runtime”. Without this reference, the compiler will not recognise “FileSystemObject” or “TextStream”. I use the first value for PathDiag if I am working with Excel. Here I will use the second value which will create the file on the desktop.

I have taken code from the answer I referenced in my comment. I renamed some of the variables and simplified the handling of attachments. I inserted code from file “Output to diagnostic file.txt”. I added code to extract the values needed for selecting emails. This code only involves simple (for me) statements that I remember how to use correctly. I added the code to output diagnostics to the text file. Here I hit a problem. Execution stopped on DiagFile.WriteLine “Subject=" & .Subject saying this an invalid call. It took me a while to identify the cause and add code to fix it. I will explain this latter. Here is my code:

Option Explicit
Sub ReplyToInvoiceEmails()

  Dim Fso As New FileSystemObject
  Dim DiagFile As TextStream
  Dim FldrInvInbox As MAPIFolder
  Dim InxA As Long
  Dim InxItemCrnt As Long
  Dim NumIcoAttach As Long
  Dim NumPdfAttach As Long
  Dim NumXmlAttach As Long
  Dim PathDiag As String
  Dim Pos As Long
  Dim ProcessThisEmail As Boolean
  Dim Subject As String
  Dim ReminderInBody As Boolean
  Dim ReminderInSubject As Boolean

  Set FldrInvInbox = Session.Folders("tonydallimore23@gmail.com").Folders("Inbox")

  PathDiag = CreateObject("WScript.Shell").specialfolders("Desktop")

  Set DiagFile = Fso.CreateTextFile(PathDiag & "\Diag.txt", True, False)

  For InxItemCrnt = FldrInvInbox.Items.Count To 1 Step -1

    With FldrInvInbox.Items.Item(InxItemCrnt)

      ' It is unlikely an Inbox will contain anything but emails
      ' but it does no harm to check
      If .Class = olMail Then

        ' Extract information that will identify if this email is to be processed

        ProcessThisEmail = True  ' Assume True until find otherwise

        If InStr(1, LCase(.Subject), "reminder") = 0 Then
          ReminderInSubject = False
        Else
          ReminderInSubject = True
        End If

        If InStr(1, LCase(.Body), "reminder") = 0 Then
          ReminderInBody = False
        Else
          ReminderInBody = True
        End If

        NumIcoAttach = 0
        NumPdfAttach = 0
        NumXmlAttach = 0
        For InxA = 1 To .Attachments.Count
          Select Case LCase(Right$(.Attachments(InxA).Filename, "3"))
            Case "ico"
              NumIcoAttach = NumIcoAttach + 1
            Case "pdf"
              NumPdfAttach = NumPdfAttach + 1
            Case "xml"
              NumXmlAttach = NumXmlAttach + 1
          End Select
        Next InxA
      Else  ' Not email
        ProcessThisEmail = False
      End If
    End With

    ' Decide if email is to be processed

    If ProcessThisEmail Then
      If ReminderInSubject Or ReminderInBody Then
        ProcessThisEmail = False
      ElseIf NumXmlAttach = 1 Then
        ProcessThisEmail = False
      End If
    End If

    ' Output diagnostic information

    DiagFile.WriteLine "----- " & InxItemCrnt & " -----"
    With FldrInvInbox.Items.Item(InxItemCrnt)
      DiagFile.WriteLine "ReceivedTime=" & .ReceivedTime
      DiagFile.WriteLine "Sender=" & .Sender
      Subject = .Subject
      For Pos = Len(Subject) To 1 Step -1
       If AscW(Mid(Subject, Pos, 1)) < 1 Or _
          AscW(Mid(Subject, Pos, 1)) > 255 Then
         Subject = Replace(Subject, Mid(Subject, Pos, 1), "?")
       End If
      Next
      DiagFile.WriteLine "Subject=" & Subject
      DiagFile.WriteLine "Reminders: Subject=" & ReminderInSubject & _
                         " Body=" & ReminderInBody
      DiagFile.WriteLine "Attachment counts: ICO=" & NumIcoAttach & _
                         " PDF=" & NumPdfAttach & " XML=" & NumXmlAttach
      DiagFile.WriteLine "ProcessThisEmail=" & ProcessThisEmail

    End With

    ' Process email if required

    If ProcessThisEmail Then

    End If

  Next InxItemCrnt

  DiagFile.Close

End Sub

The first executable statement is Set FldrInvInbox = Session.Folders("tonydallimore23@gmail.com").Folders("Inbox"). You must replace "tonydallimore23@gmail.com" with "invoice@rr.com" or the real name for this store. Apart from this change, this code should run without problems on your system.

Next are the statements to prepare the diagnostic text file and then: For InxItemCrnt = FldrInvInbox.Items.Count To 1 Step -1.

FldrInvInbox.Items is a collection holding all the items in FldrInvInbox. A collection is like an array (if you know what an array is) except you can add items to the middle of a collection and delete items from the middle. FldrInvInbox.Items.Count is the number of items in FldrInvInbox.Items. I am accessing items in this collection by their position. If the code decides item 5 is to be moved to another folder, item 6 become item 5, item 7 becomes item 6 and so on. This would mess up the For-Loop. I am accessing this collection starting from the end. If I move item 1000 to a different folder then items 1 to 999, which I have yet to process, do not move so the For-Loop works properly.

The next block of code extracts properties to variables. I think I have extracted every property you need but you must check. The next block of code decides if an email is to be processed. I like to divide code into blocks like this because it is easier to write and easier to understand if you need to change it in a year’s time. I do not understand how you want to select emails and I am sure my selection code is wrong. You will have to correct this block of code or provide more information on the selection process so I can correct it.

Next is code to create the diagnostic output. On my system, the diagnostic output looks like:

----- 55 -----
ReceivedTime=09/08/2018 13:03:09
Sender=TechTarget Channel Media
Subject=Channel ecosystem sees major shift in partner types
Reminders: Subject=False Body=False
Attachment counts: ICO=0 PDF=0 XML=0
ProcessThisEmail=True
----- 54 -----
ReceivedTime=09/08/2018 11:48:10
Sender=TechTarget
Subject=Industrial control systems a specialised cyber target
Reminders: Subject=False Body=False
Attachment counts: ICO=0 PDF=0 XML=0
ProcessThisEmail=True
----- 53 -----

The first three lines of each email identify the email so you can locate it in the folder. The second three lines are the selection values which I know are wrong.

If I had missed some selection values, you will have to add them. You will have to correct my selection code. You want every “ProcessThisEmail=True/False” line to be correct before we move on to the reply code.

The problem I encountered with the diagnostic code was because of emojis. Execution stopped on the statement outputting the subject for some emails and it took me sometime to locate the cause. The diagnostic file is a simple ASCII text file and an emoji cannot be output to an ASCII text file. I thought of ignoring the problem since you were unlikely to have emojis in your subject. I decided to fix the problem because you have neither the experience to diagnose the problem nor to experience fix it if you did diagnose it. Have a look at my code and try to understand what I have done.

I need you to complete tmy code before we move on to the next section. I will add some text about the next section later but this section is much later than I promised so I will post what I have now.

This next paragraphs are to get you thinking about the email bodies you will create and the ones you have checked for “Reminder”.

An Outlook email can have three bodies: a text body, an Html body and a Rich Text Format (RTF) body. I have never received an email with a RTF body. I have seen a question about them but to my mind they are obsolete; perhaps they were useful before Html became so well known. I will ignore the theoretical existence of RTF bodies. An Outlook email can have a text body, an Html body or both. If there is an Html body, that is the body that is shown to the user. I rarely receive emails without an Html body. The Html bodies I receive vary enormously in both appearance and the Html used to create that appearance. Many are very complicated with style sheets and nested table so the result will look good on a laptop or a smartphone or whatever device the user views it on. I said, an Outlook email can have an Html body without a text body but I cannot find one in my archives for the last few years. I suspect they are being created by Outlook from the Html body by deleting all the Html tags and adding carriage-return-linefeeds to mark deleted paragraphs and table cells.

With an Outlook email, property Body is the text body and property HtmlBody is the Html body. In my code I only check the text body for “Reminder”. This seems sensible since the text body will be a lot smaller and I cannot find an email without a text body. If you want to be ultra-cautious, I will show you how to check the Html body if there is no text body or you might like to consider how to do this as a training exercise.

In your code you have:

olReply.Body = "this is an automatic generated mail." & vbCrLf & vbCrLf & _
               vbCrLf & vbCrLf & vbCrLf & ".... insert text...."

You might find that the following gives a more attractive appearance since email packages tend to use a more attractive font when displaying Html bodies if none is specified:

olReply.Body = ""
olReply.HtmlBody = "<HTML><BODY>" & _
                   "<P>this is an automatic generated mail.</P>" & _
                   "<P>.... insert text....</P>" & _
                   "</BODY>" & "</HTML>"

This is very basic Html and is now depreciated but it shows an Html body could be created for little more effort than creating a text body. Html also allows formatting (bold, italic, font size, font colour and so on) which might be helpful.

Tony Dallimore
  • 12,335
  • 7
  • 32
  • 61