-2

I'm getting this error.

[enter image description here][enter image description here]

public class TelephoneMysteryResultHandler
    {
    //
    public static void handleBeforeInsert(List<Mystery_Shopping_Schedule__c> TriggerNew) {
        Set<Id> clientIds = new Set<Id>();
        List<Mystery_Shopping_Schedule__c> UpdateMSS = new List<Mystery_Shopping_Schedule__c>();
        for(Mystery_Shopping_Schedule__c mss : TriggerNew) {
            if(mss.Send_Schedule__c != false) {
                clientIds.add(mss.Client_Information_Detail__c);
                UpdateMSS.add(mss);
            }
        }
        
        if(!clientIds.isEmpty() && !UpdateMSS.isEmpty()) {
            populateStartEndDateEmail(UpdateMSS,clientIds);
        }
    }
    //
    public static void handleBeforeUpdate(List<Mystery_Shopping_Schedule__c> TriggerNew, Map<Id,Mystery_Shopping_Schedule__c> TriggerOld) {
        Set<Id> clientIds = new Set<Id>();
        List<Mystery_Shopping_Schedule__c> UpdateMSS = new List<Mystery_Shopping_Schedule__c>();
        for(Mystery_Shopping_Schedule__c mss : TriggerNew) {
            if(mss.Send_Schedule__c != false && TriggerOld.get(mss.Id).Send_Schedule__c != true) {
                clientIds.add(mss.Client_Information_Detail__c);
                UpdateMSS.add(mss);
            }
        }
        
        if(!clientIds.isEmpty() && !UpdateMSS.isEmpty()) {
            populateStartEndDateEmail(UpdateMSS,clientIds);
        }
    }
    
    //
    public static void handleAfterInsert(List<Mystery_Shopping_Schedule__c> listOfNewMSS) {
        
        for(Mystery_Shopping_Schedule__c mssRecord : listOfNewMSS) {
            if(mssRecord.Send_Schedule__c != false) {
                //Get the name of Email Template that should be use based on the Date and Time Status of the Telephone Mystery Result
                String emailTemplateName = identifyEmailTemplateNameBasedOnDateTimeStatus(mssRecord.Date_Status__c);
                if(String.isNotBlank(emailTemplateName)) {
                    sendEmailToShopper(mssRecord,getShopperInquiryTemplate(emailTemplateName));
                }
            }
        }
    }
    //
    
    public static void handleAfterUpdate(List<Mystery_Shopping_Schedule__c> listOfNewMSS,Map<Id,Mystery_Shopping_Schedule__c> TriggerOld) {
        for(Mystery_Shopping_Schedule__c mssRecord : listOfNewMSS) {
            if(mssRecord.Send_Schedule__c != false && TriggerOld.get(mssRecord.Id).Send_Schedule__c != true) {
                //Get the name of Email Template that should be use based on the Date and Time Status of the Telephone Mystery Result
                String emailTemplateName = identifyEmailTemplateNameBasedOnDateTimeStatus(mssRecord.Date_Status__c);
                System.debug('Email Template Name = ' + emailTemplateName);
                if(String.isNotBlank(emailTemplateName)) {
                    sendEmailToShopper(mssRecord,getShopperInquiryTemplate(emailTemplateName));
                }
            }
            
        }
    }
    //
    public static void populateStartEndDateEmail(List<Mystery_Shopping_Schedule__c> UpdateMSS,Set<Id> clientIds)
    {
        
        Integer timeZoneHrs;
        Integer timeZoneMin;
        String finStrTime;
        String FinendTime;
        Time subthours;
        Time subtendhours;
        
        Map<Id, Client_Information_Details__c> clientInfo = new Map<Id, Client_Information_Details__c>([SELECT Id, 
                                                                                                        tolabel(Time_Zone__c) 
                                                                                                        FROM Client_Information_Details__c 
                                                                                                        where Id IN: clientIds]);
        if(clientInfo.isEmpty()) return;
        
        for(Mystery_Shopping_Schedule__c mss : UpdateMSS) {
            if(clientInfo.containsKey(mss.Client_Information_Detail__c) && clientInfo.get(mss.Client_Information_Detail__c).Time_Zone__c != null) {
                
                String timeZone = clientInfo.get(mss.Client_Information_Detail__c).Time_Zone__c.subStringAfter(' ');
                String t;
                
                if(TimeZone != null || TimeZone != '')
                {
                    t= TimeZone;
                    //t = Integer.valueof(TimeZone.trim());
                }
                else
                {
                    t = '0';
                }
                
                system.debug('invite : '+t);
                if(t!= null && t.contains(':'))
                {
                    t = t.replaceall(':30',' ');
                    timeZoneHrs = Integer.valueof(t.trim());
                    timeZoneHrs = timeZoneHrs * -1;
                    if(timeZoneHrs > 0)
                    {
                        system.debug('>0');
                        timeZoneMin = -30;
                    }
                    else
                    {
                        system.debug('<0');
                        timeZoneMin = 30;
                    }
                    timeZoneMin = timeZoneMin * -1;
                    system.debug(t);
                    system.debug(timeZoneHrs);
                    system.debug(timeZoneMin);
                }
                else if(t!= null && !t.contains(':'))
                {
                    timeZoneHrs = Integer.valueof(t.trim());
                    timeZoneHrs = timeZoneHrs * -1;
                    timeZoneMin = 0;
                    system.debug(t);
                    system.debug(timeZoneHrs);
                }
                
                system.debug('invite after : '+timeZoneHrs);
                system.debug('invite after : '+timeZoneMin);
                
                System.debug('date of call' + mss.Date_of_Call__c);
                
                if(mss.Start_Time_Email_Template__c != null){
                    system.debug('timeZoneHrs: '+timeZoneHrs);
                    system.debug('timeZoneMin: '+timeZoneMin);
                    System.debug('Start Time ===' +mss.Start_Time_Email_Template__c);
                    subthours=mss.Start_Time_Email_Template__c.addHours(timeZoneHrs);
                    subthours=subthours.addMinutes(timeZoneMin);
                    String strTime=String.valueOf(subthours);
                    String repstrTime=strTime.remove(':');
                    finStrTime=repstrTime.removeEnd('.000Z');
                }
                else{
                    finStrTime='043000';
                }
                if(mss.End_Time_Email_Template__c != null)
                {
                    system.debug('timeZoneHrs: '+timeZoneHrs);
                    system.debug('timeZoneMin: '+timeZoneMin);
                    System.debug('End Time ===' +mss.End_Time_Email_Template__c);
                    subtendhours=mss.End_Time_Email_Template__c.addHours(timeZoneHrs);
                    subtendhours=subtendhours.addMinutes(timeZoneMin);
                    String enTime=String.valueOf(subtendhours);
                    String replendTime=enTime.remove(':');
                    FinendTime=replendTime.removeEnd('.000Z');
                }
                else{
                    FinendTime='083000';
                }
                system.debug('finstrTime'+FinStrTime);
                system.debug('finendTime'+FinendTime);
                Integer strYear=mss.Date_of_Call__c.year();
                Integer strMonth=mss.Date_of_Call__c.month();
                Integer strDay=mss.Date_of_Call__c.day();
                String month;
                String day;
                if(strMonth < 9)
                {
                    month='0'+string.valueOf(strMonth);
                }
                else
                {
                    month=string.valueOf(strMonth);
                }
                if(strDay < 9)
                {
                    day='0'+string.valueOf(strDay);
                }
                else
                {
                    day=string.valueOf(strDay);
                }
                string startdatetime;
                String checksTime = FinStrTime.substring(0,2);
                String checkTime = FinendTime.substring(0,2);
                if((checkTime == '00' || checkTime == '01' || checkTime == '02' || checkTime == '03' || checkTime == '04' || checkTime == '05' || checkTime == '06' || checkTime == '07' || checkTime == '08' || checkTime == '09' || checkTime == '10' || checkTime == '11')
                   &&
                   (checksTime != '00' || checksTime != '01' || checksTime != '02' || checksTime != '03' || checksTime != '04' || checksTime != '05' || checksTime != '06' || checksTime != '07' || checksTime != '08' || checksTime != '09' || checksTime != '10' || checksTime != '11'))
                {
                    strDay = strDay+1;
                    day=string.valueOf(strDay);
                    
                    
                    startdatetime=String.valueOf(strYear)+month+day+'T'+FinStrTime+'Z';
                    mss.Start_Date_Email__c = startdatetime;
                    System.debug('start date'+startdatetime);
                    
                }
                else {
                    startdatetime=String.valueOf(strYear)+month+day+'T'+FinStrTime+'Z';
                    mss.Start_Date_Email__c = startdatetime;
                    System.debug('start date'+startdatetime);
                }
                String enddatetime;
                
                
                enddatetime= String.valueOf(strYear)+month+day+'T'+FinendTime+'Z';
                mss.End_Date_Email__c = enddatetime;
                System.debug('end date'+enddatetime);
            }
        }
    }
    //
    private static string identifyEmailTemplateNameBasedOnDateTimeStatus(String dateTimeStatus) {
        String emailTemplateName = ''; 
        //If Date and Time Status equals to Flexible, Flexible Date Only, and Flexible Time Only
        
        if(dateTimeStatus == 'Flexible' || dateTimeStatus == 'Flexible Date Only' || dateTimeStatus == 'Flexible Time Only') {
            emailTemplateName = 'Shopper_Inquiry_Assignment';
        }
        else {
            emailTemplateName = 'Shopper_Inquiry_Assignment_No_Flexibility';
        }
        return emailTemplateName;
    }
    //
    private static Id getShopperInquiryTemplate(String emailTemplateName) {
        return [SELECT Id FROM EmailTemplate WHERE DeveloperName = :emailTemplateName LIMIT 1].Id;
    }
    
    //method to send mail to a list of users
    private static void sendEmailToShopper(Mystery_Shopping_Schedule__c mssRecord, Id shopperInquiryEmailTemplateId) {
        
        Datetime dtimeOfShopper;
        Date dateOfShoper;
        String shopperDate;
        Date dtOfCall; 
        String dateOfCall;
        Date altDate;
        String altDateOfCall;
        
        if(mssRecord.Shopper_Date_of_Call__c != null) {
            dtimeOfShopper = mssRecord.Shopper_Date_of_Call__c;
            dateOfShoper = dtimeOfShopper.date();
            shopperDate = dateOfShoper.format();
        }
        
        if(mssRecord.Date_of_Call__c != null) {
            dtOfCall = mssRecord.Date_of_Call__c;
            dateOfCall = dtOfCall.format();
        }
        
        if(mssRecord.Alternate_Date_of_Call__c != null) {
            altDate = mssRecord.Alternate_Date_of_Call__c;
            altDateOfCall = altDate.format();
        }
        
        if(shopperInquiryEmailTemplateId == null) return;
        
        // Pick a dummy Contact
        Contact c = [SELECT id, Email FROM Contact WHERE Email = 'test@test.com' LIMIT 1];
        
        // Send Email to Shopper
        Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
        String txtInvite = '';
        email.setToAddresses(new List<String> {mssRecord.Shopper_Email__c});    
        Messaging.EmailFileAttachment attach = new Messaging.EmailFileAttachment();   
        attach.filename = 'Appointment.ics'; 
        attach.ContentType ='text/calendar';
        attach.inline = true;     
        
        String allStrings = mssRecord.Type_of_Call__c + ' Mystery Shop Assignment for '+ mssRecord.Account_Name__c+'\n';
        txtInvite += 'BEGIN:VCALENDAR\n';        
        txtInvite += 'PRODID::-//hacksw/handcal//NONSGML v1.0//EN\n';
        txtInvite += 'VERSION:2.0\n';
        txtInvite += 'METHOD:PUBLISH\n';
        txtInvite += 'X-MS-OLK-FORCEINSPECTOROPEN:TRUE\n';
        txtInvite += 'BEGIN:VEVENT\n';
        txtInvite += 'CLASS:PUBLIC\n';
        txtInvite += 'ORGANIZER;CN='+mssRecord.createdby.Name+':MAILTO:'+mssRecord.createdby.Email+'\n';
        txtInvite += 'CREATED:20091026T203709Z\n';        
        txtInvite += 'DTEND:'+mssRecord.End_Date_Email__c+'\n';
        txtInvite += 'DTSTAMP:20191026T203709Z\n';        
        txtInvite += 'DTSTART:'+mssRecord.Start_Date_Email__c+'\n';
        txtInvite += 'LAST-MODIFIED:20091026T203709Z\n';
        txtInvite += 'LOCATION:'+mssRecord.Client_City__c+'\n';
        txtInvite += 'PRIORITY:5\n';
        txtInvite += 'SEQUENCE:0\n';
        txtInvite += 'SUMMARY;';
        txtInvite += 'LANGUAGE=en-us:Oculus ' +allStrings + '\n';
        txtInvite += 'DESCRIPTION:Hello, '+ mssRecord.Shopper_Name__c +'! Here is your '+ shopperDate +' Oculus Assignment' ;
        txtInvite += '\\n\\nSTEP ONE ';
        txtInvite += '\\nReview the client information and requirements ' + mssRecord.Account_Name__c + ' located in ' + mssRecord.Client_City__c + ', ' + mssRecord.Client_Province__c + ', '+ mssRecord.Client_Country__c;
        txtInvite += '\\n\\nSTEP TWO';
        txtInvite += '\\nThe call type is '+ mssRecord.Type_of_Call__c + '.';
        txtInvite += '\\n'+mssRecord.Call_Type_Explanation__c;
        txtInvite += '\\n\\nWill you make a reservation? ' + mssRecord.Confirm__c;
        txtInvite += '\\n\\nDetails in your local time zone.';
        txtInvite += '\\nYou must complete the call starting at ' + shopperDate;
        txtInvite += '\\n\\nIMPORTANT:\\nYou have a two hour window to complete this call.';
        txtInvite += '\\n\\nClient Time Zone and Alternative Time Option';
        txtInvite += '\\nYou must complete the call on ' + dateOfCall + ' between ' + mssRecord.Time_Of_Calls__c +', '+ mssRecord.Time_Zone__c + ' Time Zone.';
        txtInvite += '\\n\\nIf you missed the call, it can be completed at ' + altDateOfCall + ' between ' + mssRecord.Alternate_Time_of_Calls__c + ', in the client\'s time zone, which is ' + mssRecord.Time_Zone__c + ' Time Zone.';
        txtInvite += '\\n\\nSTEP THREE \\nReview the Alias & Scenario Details. You are REQUIRED to use the Alias and Scenario details below. Please Review Carefully.';
        txtInvite += '\\n\\nALIAS INFORMATION';
        txtInvite += '\\n' + mssRecord.Alias_Name_fr__c + '\\nPersonality: ' + mssRecord.Suggested_Caller_Style__c + '\\nAlias Company: ' + mssRecord.AskedCompanyName__c + '\\nAlias Phone: ' + mssRecord.Alias_Telephone_Number_fr__c;
        txtInvite += '\\nAlias Address: ' + mssRecord.Alias_Address_fr__c + ', ' + mssRecord.Alias_City_fr__c +', ' + mssRecord.Alias_Province_State_fr__c+', '+ mssRecord.Alias_Postal_Code_fr__c;
        txtInvite += '\\n\\n' + mssRecord.Alias_Email_fr__c;
        txtInvite += '\\n\\nAlias Credit Card Details\\n' + mssRecord.Alias_Card_Type__c;
        txtInvite += '\\n\\nNumber: '+ mssRecord.Alias_Credit_Card_Number_fr__c;
        txtInvite += '\\n\\nExpiry: ' + mssRecord.Alias_Credit_Card_Expiry_fr__c;
        txtInvite += '\\n\\nDates to Check\\n'+ mssRecord.Dates_to_Check__c;
        txtInvite += '\\n\\nOpening Statement\\n' + mssRecord.Suggested_Opening__c;
        txtInvite += '\\n\\nScenario:\\n' + mssRecord.Scenario__c + ' ' + mssRecord.Specific_Call__c;
        txtInvite += '\\n\\nClosing Statement:\\n' + mssRecord.Call_Closing__c;
        txtInvite += '\\n\\nAdditional Information\\n' + mssRecord.Internal_Info__c;
        txtInvite += '\\n\\nSTEP FOUR\\nCall Recording Requirements\\n\\nYou are required to record this conversation.';
        txtInvite += '\\n\\nKeep coughing and talking to a minimum.\\n\\nCall \\nenter access code';
        txtInvite += '\\n'+ mssRecord.Mystery_Call_Pin__c;
        txtInvite += '\\n\\nThe system will dial the location automatically.\\nExtension, if listed:';
        txtInvite += '\\n' + mssRecord.Shop_Call_Extension__c;
        txtInvite += '\\n\\nPlease send any questions regarding your calls to our office. We are here to help.';
        txtInvite += '\\n\\n\\nCall Notes, Terms & Conditions.';
        txtInvite += '\\n\\n1. Each call should be attempted 3 times.';
        txtInvite += '\\nAfter three separate attempts, please inform the office that you were not able to get through with the 3 times you attempted. (They should be at least 15 minutes apart)';
        txtInvite += '\\n\\nIf you have been placed on hold for more than four minutes, your call is complete.\\nPlease hang up and inform your manager.';
        txtInvite += '\\n\\n2. If the system is not accepting the number, call the office immediately.';
        txtInvite += '\\n\\n3. Do not reschedule your call. The times are sensitive. Please contact the office or use the listed alternative time.';
        txtInvite += '\\n\\n4. If conducting a confirmation call, once you have a confirmation number, please ensure you forward the number to  or your manager.';
        
        
        txtInvite += 'TRANSP:OPAQUE\n';
        
        txtInvite += 'X-ALT-DESC;FMTTYPE=text/html:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"><HTML><HEAD><META NAME="Generator" CONTENT="MS Exchange Server version 08.00.0681.000"><TITLE></TITLE></HEAD><BODY>Hello, '+mssRecord.Shopper_Name__c + '! Here is your ' + shopperDate + ' TEST';
        txtInvite += '<br><b>STEP ONE</b>';
        txtInvite += '<br>Review the client information and requirements ' + mssRecord.Account_Name__c + ' located in ' + mssRecord.Client_City__c + ', ' + mssRecord.Client_Province__c + ', ' + mssRecord.Client_Country__c;
        txtInvite += '<br><b>STEP TWO</b>';
        txtInvite += '<br>The call type is ' + mssRecord.Type_of_Call__c + '.<br> ' + mssRecord.Call_Type_Explanation__c;
        txtInvite += '<br><br>Will you make a reservation? ' + mssRecord.Confirm__c;
        txtInvite += '<br><br>Details in your local time zone. <br>You must complete the call starting at ' + shopperDate;
        txtInvite += '<br><br>IMPORTANT: <br>You have a two hour window to complete this call.';
        txtInvite += '<br><br>Client Time Zone and Alternative Time Option <br>You must complete the call on ' + dateOfCall + ' between ' + mssRecord.Time_Of_Calls__c + ', ' + mssRecord.Time_Zone__c + ' Time Zone.';
        txtInvite += '<br><br><br>If you missed the call, it can be completed at ' + altDateOfCall + ' between ' + mssRecord.Alternate_Time_of_Calls__c + ', in the client\'s time zone, which is' + mssRecord.Time_Zone__c + ' Time Zone.';
        txtInvite += '<br><br><b>STEP THREE</b>';
        txtInvite += '<br>Review the Alias & Scenario Details. You are REQUIRED to use the Alias and Scenario details below. Please Review Carefully.';
        txtInvite += '<br><br>ALIAS INFORMATION';
        txtInvite += '<br>'+mssRecord.Alias_Name_fr__c;
        txtInvite += '<br>Personality: '+ mssRecord.Suggested_Caller_Style__c;
        txtInvite += '<br>Alias Company: '+ mssRecord.AskedCompanyName__c;
        txtInvite += '<br>Alias Phone: '+ mssRecord.Alias_Telephone_Number_fr__c;
        txtInvite += '<br>Alias Address: '+ mssRecord.Alias_Address_fr__c + ', ' + mssRecord.Alias_City_fr__c + ', ' + mssRecord.Alias_Province_State_fr__c + ', ' + mssRecord.Alias_Postal_Code_fr__c;
        txtInvite += '<br><br>' + mssRecord.Alias_Email_fr__c;
        txtInvite += '<br><br>Alias Credit Card Details';
        txtInvite += '<br>'+ mssRecord.Alias_Card_Type__c + 'Number: '+ mssRecord.Alias_Credit_Card_Number_fr__c;
        txtInvite += '<br>Expiry: ' + mssRecord.Alias_Credit_Card_Expiry_fr__c;
        txtInvite += '<br><br>Dates to Check';
        txtInvite += '<br>' + mssRecord.Dates_to_Check__c;
        txtInvite += '<br><br>Opening Statement';
        txtInvite += '<br>' + mssRecord.Suggested_Opening__c;
        txtInvite += '<br><br>Scenario:';
        txtInvite += '<br>' + mssRecord.Scenario__c;
        txtInvite += '<br>' + mssRecord.Specific_Call__c;
        txtInvite += '<br><br>Closing Statement:';
        txtInvite += '<br>' + mssRecord.Call_Closing__c;
        txtInvite += '<br><br>Additional Information';
        txtInvite += '<br>' + mssRecord.Internal_Info__c;
        txtInvite += '<br><br><b>STEP FOUR</b>';
        txtInvite += '<br><b>Call Recording Requirements</b>';
        txtInvite += '<br>You are required to record this conversation.';
        txtInvite += '<br>Keep coughing and talking to a minimum.';
        txtInvite += '<br>enter access code';
        txtInvite += '<br>'+mssRecord.Mystery_Call_Pin__c;
        txtInvite += '<br><br><br>The system will dial the location automatically.';
        txtInvite += '<br>Extension, if listed:';
        txtInvite += '<br>' + mssRecord.Shop_Call_Extension__c;
        txtInvite += '<br><br>People Care Support ● <a href=""></a>';
        txtInvite += '<br><br>Please send any questions regarding your calls to our office. We are here to help.';
        txtInvite += '<br><br><br>Call Notes, Terms & Conditions.';
        txtInvite += '<br><br>1. Each call should be attempted 3 times.';
        txtInvite += '<br>After three separate attempts, please inform the office that you were not able to get through with the 3 times you attempted. (They should be at least 15 minutes apart)';
        txtInvite += '<br><br>If you have been placed on hold for more than four minutes, your call is complete.';
        txtInvite += '<br>Please hang up and inform your manager.';
        txtInvite += '<br><br>2. If the system is not accepting the number, call the office immediately.';
        txtInvite += '<br><br>3. Do not reschedule your call. The times are sensitive. Please contact the office or use the listed alternative time.';
        txtInvite += '<br><br>System ID: MCS-57526';
        txtInvite += '<br>'+' '+'</BODY></HTML>\n';
        
        txtInvite += 'X-MICROSOFT-CDO-BUSYSTATUS:BUSY\n';
        txtInvite += 'X-MICROSOFT-CDO-IMPORTANCE:1\n';
        //set reminder
        txtInvite += 'BEGIN:VALARM\n';
        txtInvite += 'ACTION:Display\n';
        txtInvite += 'DESCRIPTION:Oculus '+allStrings;
        txtInvite += 'SUMMARY:Event Alarm\n';
        txtInvite += 'TRIGGER:-PT15M\n';
        txtInvite += 'END:VALARM\n';
        txtInvite += 'END:VEVENT\n';
        txtInvite += 'END:VCALENDAR';
        
        attach.body = Blob.valueOf(txtInvite);
        email.setFileAttachments(new Messaging.EmailFileAttachment[] {attach});   
        email.setTargetObjectId(c.Id);  
        email.setTreatTargetObjectAsRecipient(false);
        email.setWhatId(mssRecord.Id);
        email.setSaveAsActivity(true);
        email.setTemplateId(shopperInquiryEmailTemplateId);
        try{
            Messaging.sendEmail(new List<Messaging.Email> {email});
        }
        catch(EmailException ee) {
            System.debug('EMail Exceptipn = ' + ee.getMessage());
        }
    }
}
  • 1
    Never call methods which consume governors inside a loop. – Adrian Larson Jul 27 at 19:58
2

You're calling

    Messaging.sendEmail(new List<Messaging.Email> {email});

in a loop, via sendEmailToShopper(), in both handleAfterUpdate() and handleAfterInsert(). As the error message tells you, you can only invoke an email send 10 times in a transaction. Note that doesn't mean 10 emails - it means 10 sends.

You're going to have to bulkify your code in much the same way that you do for DML and SOQL. Making sendEmailToShopper() return an email object that you can add to a list and send in a batch would be a good start on this project.

| improve this answer | |
  • That what I was missing. Thank you so much David – MayankSh Jul 28 at 10:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.