<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-3011483083044505303</atom:id><lastBuildDate>Wed, 03 Jul 2024 12:44:25 +0000</lastBuildDate><category>apex</category><category>Dreamforce</category><category>Visualforce</category><category>SOQL</category><category>API</category><category>AppExchange</category><category>collection</category><category>collections</category><category>lab coat challenge</category><category>list</category><category>lists</category><category>method</category><category>methods</category><category>Social</category><category>df15</category><category>Mobile</category><category>Apex REST</category><category>Callout</category><category>formula</category><category>Chatter</category><category>admin</category><category>developer tools</category><category>iOS</category><category>salesforce</category><category>Android</category><category>Design</category><category>Error</category><category>Objective-C</category><category>SDK</category><category>SalesforceDevs</category><category>df14</category><category>&#39;13</category><category>13</category><category>2013</category><category>CSS</category><category>DF16</category><category>Describe</category><category>Javascript</category><category>Release</category><category>Workflow</category><category>administration</category><category>cron</category><category>date</category><category>integration</category><category>lab coat lesson</category><category>now</category><category>regex</category><category>report</category><category>Cloud</category><category>Google</category><category>HttpCalloutMock</category><category>MultiStaticResourceCalloutock</category><category>SOAP</category><category>SaaSy</category><category>Security</category><category>StaticResourceCalloutMock</category><category>Touch</category><category>architecture</category><category>bucket</category><category>case</category><category>chart</category><category>design pattern</category><category>email service</category><category>if</category><category>pageMessage</category><category>popup</category><category>reRender</category><category>round</category><category>salesforce1</category><category>summer</category><category>test</category><category>tools</category><category>utility</category><category>web service</category><category>wrapper</category><category>wsdl2apex</category><category>&#39;14</category><category>14</category><category>2.0</category><category>Attachment</category><category>Bootstrap</category><category>BootstrapSF1</category><category>Business Time</category><category>Change Set</category><category>CronJob</category><category>CronJobdetail</category><category>Custom Permission</category><category>Custom Permissions</category><category>DF13</category><category>DeleteRestrictedByFkException</category><category>Deployment</category><category>Geolocation</category><category>IFrame</category><category>InputFile</category><category>Loops</category><category>Modal</category><category>OAuth</category><category>Pattern</category><category>Picklist</category><category>Process Builder</category><category>Rating</category><category>Responsive</category><category>Sales</category><category>Schema</category><category>Styling</category><category>UI</category><category>Visualforce; actionPoller; functions</category><category>Winter &#39;14</category><category>add-ons</category><category>adderror</category><category>addons</category><category>arduino</category><category>attribute</category><category>batch</category><category>bug</category><category>button</category><category>caeser</category><category>callouts</category><category>categorize</category><category>chrome</category><category>classify</category><category>components</category><category>credential</category><category>cti</category><category>cypher</category><category>day of the week</category><category>daysBetween</category><category>display</category><category>dynamic</category><category>elements</category><category>email</category><category>email to case</category><category>email-to-case</category><category>embed api</category><category>emulation</category><category>encrypt</category><category>error handling</category><category>exception</category><category>exercise</category><category>extensions</category><category>firefox</category><category>for reference</category><category>for view</category><category>geocoding</category><category>google maps</category><category>google maps API</category><category>hack</category><category>httprequest</category><category>httpresponse</category><category>injection</category><category>internet explorer</category><category>iot</category><category>javascript api</category><category>jquery</category><category>keepass</category><category>lastreferenceddate</category><category>lastvieweddate</category><category>left</category><category>manager</category><category>matcher</category><category>message</category><category>mid</category><category>missing</category><category>outbound</category><category>password</category><category>phone</category><category>random</category><category>requires</category><category>rest</category><category>right</category><category>rollback</category><category>savepoint</category><category>schedule</category><category>scheduled</category><category>screen</category><category>service</category><category>settings</category><category>sfdc</category><category>shift</category><category>simulation</category><category>sms</category><category>static maps</category><category>system.scheduleBatch</category><category>tablet</category><category>telephony</category><category>test coverage</category><category>testing</category><category>token</category><category>triggers</category><category>try/catch</category><category>username</category><category>view</category><category>webservice</category><category>winter &#39;13</category><title>CRM Science</title><description>Senior Expertise. Lean Delivery. On Shore. Focused on Your Success.</description><link>http://blog.crmscience.com/</link><managingEditor>noreply@blogger.com (Anonymous)</managingEditor><generator>Blogger</generator><openSearch:totalResults>91</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-5491886231297620574</guid><pubDate>Mon, 14 Mar 2016 10:44:00 +0000</pubDate><atom:updated>2016-03-21T17:47:53.044-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">Apex REST</category><category domain="http://www.blogger.com/atom/ns#">API</category><category domain="http://www.blogger.com/atom/ns#">DF16</category><category domain="http://www.blogger.com/atom/ns#">salesforce</category><category domain="http://www.blogger.com/atom/ns#">SalesforceDevs</category><category domain="http://www.blogger.com/atom/ns#">sfdc</category><title>Lab Coat Challenge 8: Scripting Scripts</title><description>&lt;div style=&quot;font-size: 18px;&quot;&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlSb8z692_wT21MgqV-f2JY59CxuAaRpM-yivFa2h6mBHFcSyBsF871JxoE_2S7wJnPQU4o5i4RZMcXPlbXk07o4Ivlwl1JqbgJyguYwCDgUryMqwJqt0bPA8WeCpBznqRn-5gYMDL8dE/s1600/LabCoat+Challenge+8.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;367&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlSb8z692_wT21MgqV-f2JY59CxuAaRpM-yivFa2h6mBHFcSyBsF871JxoE_2S7wJnPQU4o5i4RZMcXPlbXk07o4Ivlwl1JqbgJyguYwCDgUryMqwJqt0bPA8WeCpBznqRn-5gYMDL8dE/s640/LabCoat+Challenge+8.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Salesforce Devs, we have a&amp;nbsp;Lab Coat Challenge for you challenge your ability to&amp;nbsp;utilize queries and DMLs. Review the challenge, take a look at the starter code, and then give it your best attempt. If you come up with&amp;nbsp;the right answer, you will&amp;nbsp;earn a Lab Coat Badge.&lt;br /&gt;
&lt;h2 style=&quot;font-size: 24px;&quot;&gt;
&lt;span style=&quot;color: #0957a2;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h2 style=&quot;font-size: 24px;&quot;&gt;
&lt;span style=&quot;color: #0957a2;&quot;&gt;Overview&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
Today’s challenge is related with queries and DMLs.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&lt;h2 style=&quot;font-size: 24px;&quot;&gt;
&lt;span style=&quot;color: #0957a2;&quot;&gt;Challenge&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
There are two orgs. Org A has 10 Accounts that need to find their way into Org B. Org B has no accounts. &amp;nbsp;Neither org allows you to use Data Loading tools (Data Loader, Workbench, etc). &amp;nbsp;Both orgs allow you to run Apex. Write an Apex script that outputs an Apex script that will run on Org B and create those 10 Account records.&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h2 style=&quot;font-size: 24px;&quot;&gt;
&lt;span style=&quot;color: #0957a2;&quot;&gt;Starter Code &amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;div&gt;
&lt;span style=&quot;color: #0957a2;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;script src=&quot;https://gist.github.com/LabCoatTeam/0bb4911a168a87afca66.js&quot;&gt;&lt;/script&gt;
&lt;span style=&quot;color: #0957a2;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: #0957a2;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br data-cke-eol=&quot;1&quot; /&gt;
&lt;div style=&quot;font-size: 24px; text-align: center;&quot;&gt;
&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;a dataquery=&quot;#txtMedia24gp&quot; href=&quot;http://www.crmscience.com/#!lab-coat-challenges/cwzw&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;color: #0957a2;&quot;&gt;Submit Your Answers Here&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
</description><link>http://blog.crmscience.com/2016/03/labcoat-challenge-8-scripting-scripts.html</link><author>noreply@blogger.com (Unknown)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlSb8z692_wT21MgqV-f2JY59CxuAaRpM-yivFa2h6mBHFcSyBsF871JxoE_2S7wJnPQU4o5i4RZMcXPlbXk07o4Ivlwl1JqbgJyguYwCDgUryMqwJqt0bPA8WeCpBznqRn-5gYMDL8dE/s72-c/LabCoat+Challenge+8.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-2426757227727110085</guid><pubDate>Mon, 14 Mar 2016 05:28:00 +0000</pubDate><atom:updated>2016-03-21T17:48:07.001-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">Apex REST</category><category domain="http://www.blogger.com/atom/ns#">API</category><category domain="http://www.blogger.com/atom/ns#">AppExchange</category><category domain="http://www.blogger.com/atom/ns#">DF16</category><category domain="http://www.blogger.com/atom/ns#">salesforce</category><category domain="http://www.blogger.com/atom/ns#">SalesforceDevs</category><title>Lab Coat Challenge 7: Merge Text</title><description>&lt;br data-cke-eol=&quot;1&quot; /&gt;
&lt;div class=&quot;cke_widget_wrapper cke_widget_block cke_image_nocaption cke_widget_selected&quot; data-cke-display-name=&quot;image&quot; data-cke-filter=&quot;off&quot; data-cke-widget-id=&quot;1&quot; data-cke-widget-wrapper=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;div class=&quot;align-center cke_widget_element&quot; data-cke-widget-data=&quot;%7B%22hasCaption%22%3Afalse%2C%22src%22%3A%22%2F%2Fstatic.wixstatic.com%2Fmedia%2F96f234_507c87b9825f4ad992e63354856f8b3f.png%22%2C%22alt%22%3A%22%22%2C%22width%22%3A%22469.5%22%2C%22height%22%3A%22268.06935483870967%22%2C%22lock%22%3Atrue%2C%22align%22%3A%22center%22%2C%22classes%22%3Anull%7D&quot; data-cke-widget-keep-attr=&quot;0&quot; data-cke-widget-upcasted=&quot;1&quot; data-widget=&quot;image&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;span class=&quot;cke_image_resizer_wrapper&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-cke-saved-src=&quot;//static.wixstatic.com/media/96f234_507c87b9825f4ad992e63354856f8b3f.png/v1/fill/w_470,h_268/96f234_507c87b9825f4ad992e63354856f8b3f.png&quot; src=&quot;//static.wixstatic.com/media/96f234_507c87b9825f4ad992e63354856f8b3f.png/v1/fill/w_470,h_268/96f234_507c87b9825f4ad992e63354856f8b3f.png&quot; wix-comp=&quot;{&amp;quot;id&amp;quot;:&amp;quot;innercomp_txtMedia1k7h&amp;quot;,&amp;quot;dataQuery&amp;quot;:&amp;quot;txtMedia1k7h&amp;quot;,&amp;quot;propertyQuery&amp;quot;:&amp;quot;txtMedia1k7h&amp;quot;,&amp;quot;componentType&amp;quot;:&amp;quot;wysiwyg.viewer.components.WPhoto&amp;quot;,&amp;quot;styleId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;skin&amp;quot;:&amp;quot;wysiwyg.viewer.skins.photo.NoSkinPhoto&amp;quot;,&amp;quot;display&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;marginLeft&amp;quot;:&amp;quot;auto&amp;quot;,&amp;quot;marginRight&amp;quot;:&amp;quot;auto&amp;quot;,&amp;quot;width&amp;quot;:0.76,&amp;quot;src&amp;quot;:&amp;quot;//static.wixstatic.com/media/96f234_507c87b9825f4ad992e63354856f8b3f.png&amp;quot;,&amp;quot;isFullSize&amp;quot;:false,&amp;quot;post-cover-photo&amp;quot;:&amp;quot;//static.wixstatic.com/media/96f234_507c87b9825f4ad992e63354856f8b3f.png&amp;quot;}&quot; /&gt;&lt;span class=&quot;cke_image_px_indicator&quot;&gt;​&lt;/span&gt;&lt;span class=&quot;cke_image_resizer&quot; title=&quot;Click and drag to resize&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: 18px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-size: 18px;&quot;&gt;Salesforce Devs, we have a&amp;nbsp;Lab Coat Challenge for you that will test your mental ability. Review the challenge, take a look at the starter code, and then give it your best attempt. If you come up with&amp;nbsp;the right answer, you will&amp;nbsp;earn a Lab Coat Badge. We&#39;ll share your success on Twitter!&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 style=&quot;font-size: 18px;&quot;&gt;
&lt;/h4&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h2 style=&quot;font-size: 24px;&quot;&gt;
&lt;span style=&quot;color: #0957a2;&quot;&gt;Overview&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;h4&gt;
&lt;/h4&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
Today’s challenge has to do with merging text.&lt;/div&gt;
&lt;div style=&quot;font-size: 24px;&quot;&gt;
&lt;h2&gt;
&lt;/h2&gt;
&lt;/div&gt;
&lt;h2 style=&quot;font-size: 24px;&quot;&gt;
&lt;span style=&quot;color: #0957a2;&quot;&gt;Challenge&lt;/span&gt;&lt;/h2&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&lt;br /&gt;
Hi {!FirstName},&lt;/div&gt;
&lt;h4 style=&quot;font-size: 18px;&quot;&gt;
&lt;/h4&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
We hope you enjoy {!Number__c}. &amp;nbsp;Show us your {!ChallengeSkillset__c} chops!&lt;/div&gt;
&lt;h4 style=&quot;font-size: 18px;&quot;&gt;
&lt;/h4&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
Hang on..., that’s not a typo or a merge fail. It’s the gist of this Lab Coat Challenge. You’re developing a way to construct a dynamic query that includes all of the placeholders in a given piece of text. Your objective is to take in a string of text, with one or more merge fields, pluck out the fields, and build your query string out.&lt;/div&gt;
&lt;h4 style=&quot;font-size: 18px;&quot;&gt;
&lt;/h4&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
For example, for the above sample, your query string would need to pull in the FirstName field (IE: &amp;nbsp;SELECT Id, FirstName, ChallengeNumber__c, ChallengeSkillset__c…).&lt;/div&gt;
&lt;h4 style=&quot;font-size: 18px;&quot;&gt;
&lt;/h4&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 24px;&quot;&gt;
&lt;h2 style=&quot;font-size: 24px;&quot;&gt;
&lt;span style=&quot;color: #0957a2;&quot;&gt;Starter Code&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;h4 style=&quot;font-size: 18px;&quot;&gt;
&lt;/h4&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
You must use the following code and can only add to the code provided below.&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/LabCoatTeam/888d895a4ddffcbb1fcf.js&quot;&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 24px; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 24px; text-align: center;&quot;&gt;
&lt;a dataquery=&quot;#txtMedia1yl4&quot; href=&quot;https://www.blogger.com/null&quot;&gt;&lt;span style=&quot;color: #0957a2;&quot;&gt;Submit Your Answers Here&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br data-cke-eol=&quot;1&quot; /&gt;</description><link>http://blog.crmscience.com/2016/03/labcoat-challenge-merge-text.html</link><author>noreply@blogger.com (Unknown)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-767175383981506802</guid><pubDate>Mon, 14 Mar 2016 05:13:00 +0000</pubDate><atom:updated>2016-03-21T17:48:16.707-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">collection</category><category domain="http://www.blogger.com/atom/ns#">collections</category><category domain="http://www.blogger.com/atom/ns#">DF16</category><category domain="http://www.blogger.com/atom/ns#">Dreamforce</category><category domain="http://www.blogger.com/atom/ns#">lab coat challenge</category><category domain="http://www.blogger.com/atom/ns#">list</category><category domain="http://www.blogger.com/atom/ns#">lists</category><category domain="http://www.blogger.com/atom/ns#">method</category><category domain="http://www.blogger.com/atom/ns#">methods</category><category domain="http://www.blogger.com/atom/ns#">salesforce</category><category domain="http://www.blogger.com/atom/ns#">SalesforceDevs</category><title>Lab Coat Challenge 6: Quick Mode</title><description>&lt;div style=&quot;font-size: 18px; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHR0rGVFL-D6ECUt_ajZVWf6FrW8z95zCbSFtf6WHxO5eAUkybsHturjkiIR-GdRYg1hmGRelcWLrw5_0JleLZIK3k3Qstf-UgSp1TD0rHswB6LQS13q2m4RGC-9HBqFwrUSIiz6fW3Y4/s1600/LabCoat+Challenge+6.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;364&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHR0rGVFL-D6ECUt_ajZVWf6FrW8z95zCbSFtf6WHxO5eAUkybsHturjkiIR-GdRYg1hmGRelcWLrw5_0JleLZIK3k3Qstf-UgSp1TD0rHswB6LQS13q2m4RGC-9HBqFwrUSIiz6fW3Y4/s640/LabCoat+Challenge+6.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
Hey there dev&#39;s and dev&#39;s-to-be! We have a &#39;Quick&#39; Lab Coat Challenge for you. Review the challenge, take a look at the starter code, and then give it your best shot. Get the right answer and earn your Lab Coat Badge.&lt;/div&gt;
&lt;h2 style=&quot;font-size: 24px;&quot;&gt;
&lt;span style=&quot;color: #0957a2;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h2 style=&quot;font-size: 24px;&quot;&gt;
&lt;span style=&quot;color: #0957a2;&quot;&gt;Overview&lt;/span&gt;&lt;/h2&gt;
&lt;h2 style=&quot;font-size: 18px;&quot;&gt;
&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h2 style=&quot;font-size: 18px;&quot;&gt;
&lt;span style=&quot;font-weight: normal;&quot;&gt;Today’s challenge has to do with finding the mode of a given set of integers&lt;/span&gt;&lt;/h2&gt;
&lt;div style=&quot;font-size: 24px;&quot;&gt;
&lt;span style=&quot;color: #1468a8;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h2 style=&quot;font-size: 24px;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;Challenge&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;h2 style=&quot;font-size: 24px;&quot;&gt;
&lt;span style=&quot;font-size: 18px; font-weight: normal;&quot;&gt;Using the smallest amount of code (least statements - no run on lines of multiple statements!), determine what the “mode” (most frequent number) of a set of integers is. For more information on mode go to: &lt;a href=&quot;http://www.mathgoodies.com/lessons/vol8/mode.html&quot;&gt;http://www.mathgoodies.com/lessons/vol8/mode.html&lt;/a&gt;. &amp;nbsp;For this challenge, if the solution is multimodal (having more than one mode), choose the lowest number of the results (IE: &amp;nbsp;If 2, 3, and 10 are modes for a set of integers, the solution will be 2).&lt;/span&gt;&lt;/h2&gt;
&lt;div style=&quot;font-size: 24px;&quot;&gt;
&lt;span style=&quot;color: #0957a2;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h2 style=&quot;font-size: 24px;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;Starter Code&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;h2&gt;
&lt;span style=&quot;font-size: 18px;&quot;&gt;You must use the following code and can only add to the code provided below.&lt;/span&gt;&lt;/h2&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
/* &amp;nbsp;LAB COAT CHALLENGE: What is the minimum amount of lines&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;needed in order to find the mode of the following list&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;of integers? */&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
// &amp;nbsp;lists of integers to be used in the asserts&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
list&amp;lt;Integer&amp;gt; numbers1 = new list&amp;lt;Integer&amp;gt; {2,5,1,2,7,1,2,6,4,6,2,3,8,9};&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
list&amp;lt;Integer&amp;gt; numbers2 = new list&amp;lt;Integer&amp;gt; {2,5,1,6,7,8,1,5};&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
list&amp;lt;Integer&amp;gt; numbers3 = new list&amp;lt;Integer&amp;gt; {5,4,7,1,7,2,3,5,4};&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
list&amp;lt;Integer&amp;gt; numbers4 = new list&amp;lt;Integer&amp;gt; {5,4,7,2,1,7,1,2,5,4};&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
// &amp;nbsp;Test your code&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
system.assertEquals(mode(numbers1), new set&amp;lt;Integer&amp;gt; {2});&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
system.assertEquals(mode(numbers2), new set&amp;lt;Integer&amp;gt; {1,5});&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
system.assertEquals(mode(numbers3), new set&amp;lt;Integer&amp;gt; {4,5,7});&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
system.assertEquals(mode(numbers4), new set&amp;lt;Integer&amp;gt;());&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
// &amp;nbsp;YOUR CHANGES START BELOW&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
// &amp;nbsp;&amp;nbsp;Implement the following method&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
set&amp;lt;Integer&amp;gt; mode(list&amp;lt;Integer&amp;gt; listOfIntegersToTest) {&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;set&amp;lt;Integer&amp;gt; returnValues = new set&amp;lt;Integer&amp;gt;();&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;// Your code here&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 18px;&quot;&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;return returnValues;&lt;/div&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-size: 24px; text-align: center;&quot;&gt;
&lt;a dataquery=&quot;#txtMediao69&quot; href=&quot;https://www.blogger.com/null&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;Submit Your Answers Here&lt;/span&gt;&lt;/b&gt;&lt;/a&gt;&lt;/div&gt;
</description><link>http://blog.crmscience.com/2016/03/labcoat-challenge-6-quick-mode.html</link><author>noreply@blogger.com (Unknown)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHR0rGVFL-D6ECUt_ajZVWf6FrW8z95zCbSFtf6WHxO5eAUkybsHturjkiIR-GdRYg1hmGRelcWLrw5_0JleLZIK3k3Qstf-UgSp1TD0rHswB6LQS13q2m4RGC-9HBqFwrUSIiz6fW3Y4/s72-c/LabCoat+Challenge+6.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-1079164891269975450</guid><pubDate>Mon, 30 Nov 2015 21:45:00 +0000</pubDate><atom:updated>2015-12-01T16:02:49.386-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">developer tools</category><category domain="http://www.blogger.com/atom/ns#">lab coat lesson</category><category domain="http://www.blogger.com/atom/ns#">Process Builder</category><category domain="http://www.blogger.com/atom/ns#">salesforce</category><category domain="http://www.blogger.com/atom/ns#">SalesforceDevs</category><category domain="http://www.blogger.com/atom/ns#">triggers</category><category domain="http://www.blogger.com/atom/ns#">Workflow</category><title>Salesforce Triggers, Workflow, and Process Builder</title><description>&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;b id=&quot;docs-internal-guid-7146392d-5a43-4d8c-6503-64d967c708bd&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibHm7ir50PR5hhNuHDd5mzBBY4Hemd63c2uB9sC_t-r7r5YqXmMYaaCXxyttdnkdrVztCqc4QjKCd-QN6-q4IPCowufUD98Mkb4hZwt98stuCXmkUbp32vAraTzPS6f_Aaiq_6gE0tXhw/s1600/unnamed-2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;313&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibHm7ir50PR5hhNuHDd5mzBBY4Hemd63c2uB9sC_t-r7r5YqXmMYaaCXxyttdnkdrVztCqc4QjKCd-QN6-q4IPCowufUD98Mkb4hZwt98stuCXmkUbp32vAraTzPS6f_Aaiq_6gE0tXhw/s640/unnamed-2.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;
&lt;/b&gt; &lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;
&lt;/b&gt; &lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;The Question:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;
&lt;/b&gt; &lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;font-family: arial; font-size: large;&quot;&gt;&lt;span style=&quot;line-height: 33.12px; white-space: pre-wrap;&quot;&gt;How is it possible for triggers to fire three times on a single save of a record?  There are many reasons this can happen in the Salesforce1 platform.  Our problem had to do with Workflow and Process Builder.  We were expecting only 1 extra trigger to fire because we were using workflow field updates and process builder field updates, figuring that the additional DML would be grouped at the end and fire one more time. But instead we found 2 extra triggers fired.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: arial; font-size: large;&quot;&gt;&lt;span style=&quot;line-height: 33.12px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt; &lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;The Problem:&lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;
&lt;/b&gt; &lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-size: large; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;A DML (Data Manipulation Language) operation is happening and it causes the trigger to fire. Then, the workflow rule executes and that causes the trigger to fire a 2nd time. Then, the Process Builder flow fires and inside the Process Builder flow, the trigger fires a 3rd time.&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;
&lt;/b&gt; &lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-size: large; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;When the Process Builder flow is deactivated, the trigger fires twice. &amp;nbsp;When the Process Builder flow is left active and all the workflow rules are deactivated, the trigger fires twice, as well.&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirnx8EmEpm2EEEKaHzb9a9OyyKJwW5NdI1I3qjmMBibQmzDiEI2wYs1FaYxPaUDOYpKRRNGNvq8C_E0lS0MxFgSHtlwf5fXYfR4Yzx-y3lckNRcoI3ziLB1ELyZTKr3G5TYxBYImqQBVY/s1600/unnamed-3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;436&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirnx8EmEpm2EEEKaHzb9a9OyyKJwW5NdI1I3qjmMBibQmzDiEI2wYs1FaYxPaUDOYpKRRNGNvq8C_E0lS0MxFgSHtlwf5fXYfR4Yzx-y3lckNRcoI3ziLB1ELyZTKr3G5TYxBYImqQBVY/s640/unnamed-3.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;
&lt;/b&gt; &lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;The Solution:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;
&lt;/b&gt; &lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-size: large; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;The answer is to set a static variable during the first execution, and then reference this variable to determine whether or not subsequent code should be executed.  But be careful in the unit tests; after each DML in unit test, the flag will have to be set to false again if you intend to try insert, then update, then update etc., since each unit test is in the same context and considered the &quot;same execution.&quot;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;
&lt;/b&gt; &lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;&lt;b&gt;Here is how the trigger starts out:&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;
&lt;/b&gt; &lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
// prevent recursive trigger calls
if(!OfferTriggerHandler.OfferTriggerIsRunning) {
    OfferTriggerHandler.OfferTriggerIsRunning = true;
    ... other code
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiY5fdnAgYAeXaU9WtWIkeVyRVYzOVpFIEQ-RJUOzrvwa4H2pJcSu_YXEry1X4vIkbiEDloFhiGeyHbkYVEuzC44JYWkGhTv219FzLEPAS0alPNTu_X9T7LSgmuRx3WHIZzi6ctCdwN1AM/s1600/IMG_5351.JPG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;480&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiY5fdnAgYAeXaU9WtWIkeVyRVYzOVpFIEQ-RJUOzrvwa4H2pJcSu_YXEry1X4vIkbiEDloFhiGeyHbkYVEuzC44JYWkGhTv219FzLEPAS0alPNTu_X9T7LSgmuRx3WHIZzi6ctCdwN1AM/s640/IMG_5351.JPG&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;
&lt;/b&gt; &lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-size: x-large; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Further Exploration:&lt;/span&gt;&lt;/div&gt;
&lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;
&lt;/b&gt; &lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Many might have known the ‘before and after executions’ in the order of executions, but perhaps hadn’t seen that the Process Builder causes a third run. &amp;nbsp;The question arises, as to where the Process Builder runs in the order? A review of the Salesforce Developers Force.com Apex Developer’s Guide: &lt;/span&gt;&lt;a href=&quot;https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers_order_of_execution.htm&quot; style=&quot;text-decoration: none;&quot;&gt;&lt;span style=&quot;background-color: transparent; color: #1155cc; font-family: &amp;quot;arial&amp;quot;; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Triggers and Workflow&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;, does not list it in the order of execution running as it did in the example above. &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;
&lt;/b&gt; &lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSEza-AKHhePA7M57ErScW08HgW6cIX4cJWTNf1rWEqy8hTKdm78Mikm6dWnG3u0XBe8rWeUKtXKRXVO7ZH7doE4v3GxLJznquEL8AQ13KgKgdg_Q4Lclkj9OilWGiYSj6ALgA5p0uN4M/s1600/Process+Builder.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;356&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSEza-AKHhePA7M57ErScW08HgW6cIX4cJWTNf1rWEqy8hTKdm78Mikm6dWnG3u0XBe8rWeUKtXKRXVO7ZH7doE4v3GxLJznquEL8AQ13KgKgdg_Q4Lclkj9OilWGiYSj6ALgA5p0uN4M/s640/Process+Builder.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot;; font-size: large; line-height: 1.38; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/b&gt;&lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot;; font-size: large; line-height: 1.38; white-space: pre-wrap;&quot;&gt; &lt;/span&gt;&lt;/b&gt; &lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot;; font-size: large; line-height: 1.38; white-space: pre-wrap;&quot;&gt;The Process Builder can be set up to cause a re-execution. So one might still wonder if the Process Builder re-triggers from the top of the execution, entirely? The thinking of our team at CRM Science is that it is both Workflow, and Process Builder. One might have imagined that Salesforce would combine Workflow, and Process Builder, into the same steps so they don’t run trigger so much.  On &quot;busier&quot; objects or objects prone to bulk inserts/updates through data loads, you may find yourself avoiding introducing processes into the mix.  If you have the capability to do so, stick with triggers; at least, for now. &lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;b style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;
&lt;/b&gt; &lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-size: x-large; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Considerations For Large Salesforce Orgs&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-size: large; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;In really large Salesforce Orgs triggers on core CRM objects can become a bane of an admin or developer’s existence if the last group in charge of the org didn’t control usage. &amp;nbsp;Stick to as few triggers as possible per object (ideal is one), as little logic as possible within the trigger bodies, and utilize a common trigger handler method for further processing.  For developer friendly orgs, consider the creation of a control system, like a Custom setting, to easily enable and disable home-brewed triggers in your Production environment.&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;arial&amp;quot;; font-size: large; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 24px; text-align: center;&quot;&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;Have A Salesforce Puzzle? Let&#39;s Solve It Together!&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 24px; text-align: center;&quot;&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;Contact Us &lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;a dataquery=&quot;#txtMedia185z&quot; href=&quot;https://www.blogger.com/null&quot;&gt;Here&lt;/a&gt;&lt;/span&gt;.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 24px; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;iframe allowfullscreen=&quot;&quot; class=&quot;YOUTUBE-iframe-video&quot; data-thumbnail-src=&quot;https://i.ytimg.com/vi/rbZhcrpmI1k/0.jpg&quot; frameborder=&quot;0&quot; height=&quot;266&quot; src=&quot;https://www.youtube.com/embed/rbZhcrpmI1k?feature=player_embedded&quot; width=&quot;320&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 24px; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot;; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br data-cke-eol=&quot;1&quot; /&gt;&lt;/span&gt;&lt;/div&gt;
</description><link>http://blog.crmscience.com/2015/11/salesforce-triggers-workflow-and.html</link><author>noreply@blogger.com (Unknown)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibHm7ir50PR5hhNuHDd5mzBBY4Hemd63c2uB9sC_t-r7r5YqXmMYaaCXxyttdnkdrVztCqc4QjKCd-QN6-q4IPCowufUD98Mkb4hZwt98stuCXmkUbp32vAraTzPS6f_Aaiq_6gE0tXhw/s72-c/unnamed-2.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-6141404213879160427</guid><pubDate>Tue, 15 Sep 2015 19:14:00 +0000</pubDate><atom:updated>2020-07-23T13:04:49.939-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">adderror</category><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">error handling</category><category domain="http://www.blogger.com/atom/ns#">pageMessage</category><category domain="http://www.blogger.com/atom/ns#">rollback</category><category domain="http://www.blogger.com/atom/ns#">savepoint</category><category domain="http://www.blogger.com/atom/ns#">try/catch</category><category domain="http://www.blogger.com/atom/ns#">Visualforce</category><title>Stop Drop &amp; Rollback -- How to handle errors properly in Apex/Salesforce with Try, Catch, Rollback Best Practices</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://www.crmscience.com/lab-coat-lessons&quot;&gt;&lt;img alt=&quot;Visit our website&quot; border=&quot;0&quot; data-original-height=&quot;300&quot; data-original-width=&quot;1600&quot; height=&quot;120&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiMZW2AjEu-qQrMD6QIOtSX7VLLGnSBv1oUIKukZ3XG2IZCIGwQuUzsAWtVvOyjbRO54lS16uF_NwS0-yJ_MebVQqM_fEqWcqYdFp_-7urHs0pS0I5BPl35Hg5A3F_RI-_seyFupLSSTo/s640/Blogger-Banner-01.png&quot; title=&quot;&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;span style=&quot;font-weight: 700;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;b&gt;&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;a href=&quot;https://www.crmscience.com/single-post/2020/05/20/How-Salesforce-Developers-Handle-Errors-with-Try-Catch-Rollback-Best-Practices&quot; target=&quot;_blank&quot;&gt;Click to read an updated version of this blog.&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;
&lt;a href=&quot;http://4.bp.blogspot.com/-UdbBwM7aYMI/VcpKaE-IEII/AAAAAAAAAEc/Eko0Rt5HPdk/s1600/Smokeybear1944.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://4.bp.blogspot.com/-UdbBwM7aYMI/VcpKaE-IEII/AAAAAAAAAEc/Eko0Rt5HPdk/s320/Smokeybear1944.jpg&quot; /&gt;&lt;/a&gt;&lt;b&gt;Smokey Says - Care &lt;u&gt;will&lt;/u&gt; prevent 9 out of 10 Apex errors!&lt;/b&gt;&lt;br /&gt;
There are some assumptions that we know about when coding in Salesforce in regards to protecting the developer from saving partial-processed data in Salesforce.&lt;br /&gt;
&lt;br /&gt;
- Any exceptions that happen in code(within the same entire execution) will roll back the entire execution so that all database changes leading up to the failure will not be committed to the database. &amp;nbsp;This is true for triggered code, page controllers, asynchronous code, etc. &amp;nbsp;This was a GREAT thing as I started developing in Salesforce and really protected the data for the customers.&lt;br /&gt;
&lt;br /&gt;
- The above is only true if: 1. You are not using try/catch blocks around DML operations(which results in undesirable errors on top of standard pages or white-screen error pages from custom pages) 2. Or you are using try/catch blocks and are properly handling the error inside the &#39;catch&#39;.&lt;br /&gt;
&lt;br /&gt;
There are many uses of try/catch which I won&#39;t cover here but you can &lt;a href=&quot;https://developer.salesforce.com/docs/atlas.en-us.apex_workbook.meta/apex_workbook/apex7_2.htm&quot; target=&quot;_blank&quot;&gt;check that out here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
My Experience&lt;/h3&gt;
The more custom work I did the more I realized that I was using try/catch all over the place but didn&#39;t immediately understand the dangerous implications of using it. &amp;nbsp;I&#39;ve talked about this topic many times with other developers, explaining my experience, and it can be a complex one to discuss but I&#39;ll try to lay out some hypothetical situations.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Situations&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;You want to use try/catch in a page controller so that you can show a friendly error on the screen for the user. &amp;nbsp;There are 2 DML operations in the &#39;button click&#39; action, and say the error happens on the second DML. &amp;nbsp;So you tell the user there is an issue by adding a pagemessage. &amp;nbsp;Did you do anything to undo the 1st DML which was a success? Salesforce will not roll-back that DML for you because you&#39;ve essentially &quot;caught&quot; the error that would have done that. &amp;nbsp;&lt;b&gt;Result: Bad data. You need to roll-back.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;You&#39;ve got a trigger on Case that will roll-up some custom information to the Account. &amp;nbsp;This important logic will keep the data in-check. &amp;nbsp;But sometimes there is an issue when you run the DML Update to the accounts, so you wrap the DML in a try/catch and perform a system.debug to figure things out a bit better. &amp;nbsp;You&#39;ve deployed things like this to production since it is very rare. &amp;nbsp;By &quot;catching&quot; this error and the only handling you&#39;ve done is a debug, you have told Salesforce not to roll-back the changes to the original Cases that fired the trigger. &amp;nbsp;You&#39;ll end up with Cases(newer changes) out of sync with Account(failed update) in your database. &amp;nbsp;The solution is that you need to attach a &quot;.adderror()&quot; to the appropriate Case records in the trigger which will tell salesforce to roll-back changes and will show your custom more descriptive error to the user(or to the calling code / external system). &lt;b&gt;Result: Bad data. You need to .addError&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;h3&gt;
Code Examples - VF Controller&lt;/h3&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;VF Controller Good Example no try/catch - Standard exception handling, SF handles database protection &lt;u&gt;KEY: Do nothing extra (Good)&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

// New account
Account a = new Account(Name = &#39;New Account&#39;);
insert a;
// If DML failed, salesforce shows error and rolls-back the new record

// New Case linked to account
Case c = new Case(subject = &#39;I need help&#39;, accountId = a.id);
insert c;
// If DML failed, salesforce shows error and rolls-back the new record

// If we get this far in code, both DML&#39;s finished properly
system.debug(&#39;Success&#39;);

&lt;/script&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;VF Controller&amp;nbsp;&lt;/b&gt;&lt;b&gt;&lt;u&gt;Bad&lt;/u&gt; Example with try/catch - Account will insert without the case&lt;/b&gt;&lt;br /&gt;
Since we are using try/catch below, we are able to show the user a nicer error message with the ApexPages.addMessage method.  BUT, we are now taking over the standard salesforce pattern of &quot;error and rollback&quot;.  And we are forgetting to rollback ourselves.

&lt;br /&gt;
&lt;div&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

// New account
Account a = new Account(Name = &#39;New Account&#39;);
try{

    insert a;
    system.debug(&#39;Success&#39;);

} catch(dmlexception e){

  // If DML failed, ends up here
  system.debug(&#39;Error inserting account: &#39; + e);
  ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,&#39;Could not insert account record. Error: &#39; + e));
}

// ************ Assume that the account was a success above, continue below ***********


// New Case linked to account
Case c = new Case(subject = &#39;I need help&#39;, accountId = a.id);
try{

    insert c;
    system.debug(&#39;Success&#39;);

} catch(dmlexception e){

  // ************ Assume the CASE insert FAILED ***********
  // If DML failed, ends up here
  system.debug(&#39;Error inserting case: &#39; + e);
  ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,&#39;Could not insert Case record. Error: &#39; + e));

}

// If we get this far in code, something may have failed and been caught above, or everything worked.
system.debug(&#39;Potential Success&#39;);

&lt;/script&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;VF Controller&amp;nbsp;&lt;/b&gt;&lt;b&gt;Good Example with try/catch - If Case fails, Account insert will rollback &lt;u&gt;KEY: Using Database Rollback (Best Practice)&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

// Record the place &quot;in time&quot; where we would ultimately like to return the state of the database to upon an error.
Savepoint sp = Database.setSavepoint(); // &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;

// New account
Account a = new Account(Name = &#39;New Account&#39;);
try{

    insert a;
    system.debug(&#39;Success&#39;);

} catch(dmlexception e){

 // If DML failed, ends up here
 system.debug(&#39;Error inserting account: &#39; + e);
 ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,&#39;Could not insert account record. Error: &#39; + e));

 // Upon error roll back the database 
 // this example would not do anything since Account is first, and upon failure &quot;a&quot; would not be in the database anyway
 Database.rollback(sp); // &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;
}

// ************ Assume that the account was a success above, continue below ***********


// New Case linked to account
Case c = new Case(subject = &#39;I need help&#39;, accountId = a.id);
try{

    insert c;
    system.debug(&#39;Success&#39;);

} catch(dmlexception e){

 // ************ Assume the CASE insert FAILED ***********
 // If DML failed, ends up here
 system.debug(&#39;Error inserting case: &#39; + e);
 ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,&#39;Could not insert Case record. Error: &#39; + e));

 // Upon error roll back the database
 // This line would &quot;undo&quot; the account insert above and once the user sees the error message on screen we can 
 // feel confident that the database is not soiled with invalid information. In this example we are preventing 
 // accounts without a case from being inserted on each attempt.
 Database.rollback(sp); // &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;

 // You should fix your sobject variables now, they may have invalid Ids, look for Part 2 of this blog article to explain.
 // You may also need to handle the pagereference / redirect conditionally here, typically just refresh the page to see errors which means returning null.

}

// If we get this far in code, something may have failed and been caught above, or everything worked.
system.debug(&#39;Potential Success, conditional refresh of page or redirect etc.&#39;);

&lt;/script&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Code Examples - Trigger&lt;/h3&gt;
&lt;b&gt;Trigger Good Example no try/catch -&amp;nbsp;&lt;/b&gt;&lt;b&gt;Standard exception handling,&amp;nbsp;&lt;/b&gt;&lt;b&gt;SF handles database protection&amp;nbsp;&lt;/b&gt;&lt;b&gt;&lt;u&gt;KEY: Do nothing extra (Good)&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[


trigger CaseTrigger on Case (after insert) {
 
 system.debug(&#39;***CaseTrigger begin&#39;);

 // In this example trigger we are simply wanting to flag at the Account level
 // that the Account has a Case linked to it, which is a lookup field on Case
 // so we wouldn&#39;t be able to do a rollup count.
 // In reality we would also want to track deletes of Cases but that is skipped 
 // for demonstration purposes.
  
 // bulk map of accounts that we need to update
 map&lt;Id, Account&gt; accountsForUpdateMap = new map&lt;Id, Account&gt;();

 // find accounts to update
 for(Case c : trigger.new){
  // if this case is linked to an account and we&#39;ve not already tagged this account
  if(c.AccountId != null &amp;&amp; !accountsForUpdate.containsKey(c.AccountId))
   // add this account to the map
   accountsForUpdate.put(c.AccountId, new Account(Id = c.AccountId, HasACase__c = true));
 }

 // check to see if we need to perform DML
 if(!accountsForUpdate.isEmpty())
  // let&#39;s do the DML
  update accountsForUpdate.values();
 
 // If we get this far in code, the DML finished properly
 system.debug(&#39;Success&#39;);

 // If anything were to go wrong in the above DML, since we do NOT have a try/catch then the server
 // will automatically rollback the changes (In this instance the Cases in this trigger
 // would not be inserted into the database since the account DML update failed. This is usually 
 // desired so that the Account data is accurate.)
 // A complex error would show on the calling page or calling code that fired this trigger

}

    

&lt;/script&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Trigger &lt;u&gt;Bad&lt;/u&gt; example with try/catch - Account update could fail but we didn&#39;t stop the Cases from being inserted&lt;/b&gt;&lt;br /&gt;
&lt;div&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[


trigger CaseTrigger on Case (after insert) {
 
 system.debug(&#39;***CaseTrigger begin&#39;);

 // In this example trigger we are simply wanting to flag at the Account level
 // that the Account has a Case linked to it, which is a lookup field on Case
 // so we wouldn&#39;t be able to do a rollup count.
 // In reality we would also want to track deletes of Cases but that is skipped 
 // for demonstration purposes.
  
 // bulk map of accounts that we need to update
 map&lt;Id, Account&gt; accountsForUpdateMap = new map&lt;Id, Account&gt;();

 // find accounts to update
 for(Case c : trigger.new){
  // if this case is linked to an account and we&#39;ve not already tagged this account
  if(c.AccountId != null &amp;&amp; !accountsForUpdate.containsKey(c.AccountId))
   // add this account to the map
   accountsForUpdate.put(c.AccountId, new Account(Id = c.AccountId, HasACase__c = true));
 }

 // check to see if we need to perform DML
 if(!accountsForUpdate.isEmpty()){
  try{
   // let&#39;s do the DML
   update accountsForUpdate.values();
  } catch(dmlexception e){
   // ************ Assume the ACCOUNT update FAILED ***********
   // If DML failed, ends up here
   system.debug(&#39;Error updating account: &#39; + e);
  }

 }

 // If we get this far in code, something may have failed and been caught above, or everything worked.
 system.debug(&#39;Potential Success&#39;);

 // If anything were to go wrong in the above DML, since we do have a try/catch the server
 // will NOT automatically rollback the changes. (In this instance the Cases in this trigger
 // WOULD be inserted into the database. This is usually NOT desired since the 
 // Account data is inaccurate.)
 // NO error would show on the calling page or calling code that fired this trigger. 

}

    

&lt;/script&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Trigger Good example with try/catch - If Account update fails, we flag the Cases with an error which will show to user and prevent the Case inserts&amp;nbsp;&lt;/b&gt;&lt;b&gt;&lt;u&gt;KEY: Use .addError() method (Best Practice)&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[


trigger CaseTrigger on Case (after insert) {
 
 system.debug(&#39;***CaseTrigger begin&#39;);

 // In this example trigger we are simply wanting to flag at the Account level
 // that the Account has a Case linked to it, which is a lookup field on Case
 // so we wouldn&#39;t be able to do a rollup count.
 // In reality we would also want to track deletes of Cases but that is skipped 
 // for demonstration purposes.
  
 // bulk map of accounts that we need to update
 map&lt;Id, Account&gt; accountsForUpdateMap = new map&lt;Id, Account&gt;();

 // find accounts to update
 for(Case c : trigger.new){
  // if this case is linked to an account and we&#39;ve not already tagged this account
  if(c.AccountId != null &amp;&amp; !accountsForUpdate.containsKey(c.AccountId))
   // add this account to the map
   accountsForUpdate.put(c.AccountId, new Account(Id = c.AccountId, HasACase__c = true));
 }

 // check to see if we need to perform DML
 if(!accountsForUpdate.isEmpty()){
  try{
   // let&#39;s do the DML
   update accountsForUpdate.values();
  } catch(dmlexception e){
   // ************ Assume the ACCOUNT update FAILED ***********
   // If DML failed, ends up here
   system.debug(&#39;Error updating account: &#39; + e);

   // Let&#39;s force the database to roll-back by adding an error to these records just 
   // like salesforce would normally do.  Our error can be more descriptive though.
            
   // Build a map of Case trigger rows keyed on the Account Id   
   map&lt;id, list&lt;case&gt;&gt; accountIdCaseMap = new map&lt;id, list&lt;case&gt;&gt;();
   for(Case c : trigger.new){
    // if this case is linked to an account that failed
    if(c.AccountId != null)
     // if we already found this account and this is another case, add this 
     // case to that list
     if(accountIdCaseMap.containsKey(c.AccountId))
      accountIdCaseMap.get(c.AccountId).add(c);
     // Add this account id with a new list of Case
     else      
      accountIdCaseMap.put(c.AccountId, new list&lt;case&gt;(c));
   }

   // Loop through the errors and tag the proper cases   
   for ( Integer i = 0; i &lt; e.getNumDml(); i++ ){
    // for this dml error, get the id of the failed account, tag the matching cases.
    for(Case c : accountIdCaseMap.get(e.getDmlId( i )))
     // add an error to this row, which will prevent this row from being updated
     c.addError(&#39;Unable to update linked Account record due to an error: &#39; + 
        e.getDmlMessage( i ));
   }
       
  }

 }

 // If we get this far in code, something may have failed and been caught above, or everything worked.
 system.debug(&#39;Potential Success&#39;);

 // If anything were to go wrong in the above DML, since we do have a try/catch the server
 // will NOT automatically rollback the changes. But since we have used the .addError method on the 
 // correct trigger rows we have effectively prevented the case inserts.
 // Our error would show to the user on the standard page or to the calling code that fired the trigger.

}

    

&lt;/script&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;h3&gt;
Other Tips&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
- When using the generic exception class, it will catch any type of error besides for limits and some other situations. Be careful not to put too much inside the same Try block as it&#39;ll be more difficult to figure out what caused the error. Best practice would be use specific exception classes like dmlexception and only put a single DML in that try block.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
- Make sure to test your catch blocks. &amp;nbsp;In your manual tests you can configure a dummy &quot;requirement&quot; on an object or a validation rule you know will fail, or leave out a required field. Then attempt the custom button, standard button, whatever it is that starts the code which should fail and see how your catch block operates. &amp;nbsp;For unit tests this could be more difficult but you could employ some special logic to conditionally fill in data or fail to fill in data in your code. &amp;nbsp;Say your controller would be looking for &quot;Unit Test *** Fail DML Required Field&quot; it could know to purposely clear a field on a record before the DML which would then fire your catch block. &amp;nbsp;Or you have a Unique field setup in an object and let your unit test try to insert 2 records with the same values in that field. &amp;nbsp;There&#39;s many other things you could do, up to you.&lt;/div&gt;
</description><link>http://blog.crmscience.com/2015/09/stop-drop-rollback-how-to-handle-errors.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiMZW2AjEu-qQrMD6QIOtSX7VLLGnSBv1oUIKukZ3XG2IZCIGwQuUzsAWtVvOyjbRO54lS16uF_NwS0-yJ_MebVQqM_fEqWcqYdFp_-7urHs0pS0I5BPl35Hg5A3F_RI-_seyFupLSSTo/s72-c/Blogger-Banner-01.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-5643762873072129225</guid><pubDate>Tue, 15 Sep 2015 18:08:00 +0000</pubDate><atom:updated>2015-09-20T14:34:11.420-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Callout</category><category domain="http://www.blogger.com/atom/ns#">callouts</category><category domain="http://www.blogger.com/atom/ns#">Dreamforce</category><category domain="http://www.blogger.com/atom/ns#">HttpCalloutMock</category><category domain="http://www.blogger.com/atom/ns#">MultiStaticResourceCalloutock</category><category domain="http://www.blogger.com/atom/ns#">StaticResourceCalloutMock</category><category domain="http://www.blogger.com/atom/ns#">test</category><category domain="http://www.blogger.com/atom/ns#">test coverage</category><title>Dreamforce &#39;15 Session:  Enhanced Web Service Testing:  A Better Mock Structure</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnQ7wFNYnc-poZdzWSu_vIFLyCvkVefkPsM5KxXC81wgDwQnv8yjx7I3SSguhyphenhyphen5X7HPn55SwsCHtkpwuojvAIAUSbSwzfwt9WzU-j4eCpg5Abiz-h2EZRXc9oq1lBH-hJ7OTqx4-wbEF4/s1600/Kirk_DF15.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnQ7wFNYnc-poZdzWSu_vIFLyCvkVefkPsM5KxXC81wgDwQnv8yjx7I3SSguhyphenhyphen5X7HPn55SwsCHtkpwuojvAIAUSbSwzfwt9WzU-j4eCpg5Abiz-h2EZRXc9oq1lBH-hJ7OTqx4-wbEF4/s320/Kirk_DF15.jpg&quot; width=&quot;240&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;Session Title:&lt;/b&gt;  Enhanced Web Service Testing:  A Better Mock Structure&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;When:&lt;/b&gt;  Tuesday, 9/15/15 at 5:30 PM&lt;br /&gt;
&lt;b&gt;Where:&lt;/b&gt;  Moscone West - 2007&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Details&lt;/b&gt;&lt;br /&gt;
Salesforce provides an interface for testing callouts named HttpCalloutMock used to cover remote callouts. While adequate for simple callouts, in the real world you often need something more flexible, as in the case of multiple and varying responses from the same or varying endpoints. More precise testing and coverage can be obtained by extending the standard interface. Join us as we demonstrate a solution to use to enable the flexibility required for complex integration and synchronization apps.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Deck:&lt;/b&gt;&amp;nbsp; &lt;a href=&quot;http://bit.ly/df15_kirk_deck&quot;&gt;http://bit.ly/df15_kirk_deck&lt;/a&gt;&lt;br /&gt;
&lt;b&gt;Unmanaged Package:&lt;/b&gt; &amp;nbsp;&lt;a href=&quot;https://login.salesforce.com/packaging/installPackage.apexp?p0=04t61000000ROdv&quot;&gt;http://bit.ly/df15_kirk_pack_v1_1&lt;/a&gt;&lt;br /&gt;
&lt;b&gt;Original Blog Post:&lt;/b&gt; &amp;nbsp;&lt;a href=&quot;http://blog.crmscience.com/2014/12/test-coverage-pattern-for-multi-callout.html&quot;&gt;http://blog.crmscience.com/2014/12/test-coverage-pattern-for-multi-callout.html&lt;/a&gt;</description><link>http://blog.crmscience.com/2015/09/enhanced-web-service-testing-better.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnQ7wFNYnc-poZdzWSu_vIFLyCvkVefkPsM5KxXC81wgDwQnv8yjx7I3SSguhyphenhyphen5X7HPn55SwsCHtkpwuojvAIAUSbSwzfwt9WzU-j4eCpg5Abiz-h2EZRXc9oq1lBH-hJ7OTqx4-wbEF4/s72-c/Kirk_DF15.jpg" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-1677398549233524787</guid><pubDate>Tue, 08 Sep 2015 16:17:00 +0000</pubDate><atom:updated>2015-09-08T12:19:45.204-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">collection</category><category domain="http://www.blogger.com/atom/ns#">collections</category><category domain="http://www.blogger.com/atom/ns#">df15</category><category domain="http://www.blogger.com/atom/ns#">Dreamforce</category><category domain="http://www.blogger.com/atom/ns#">lab coat challenge</category><category domain="http://www.blogger.com/atom/ns#">list</category><category domain="http://www.blogger.com/atom/ns#">lists</category><category domain="http://www.blogger.com/atom/ns#">method</category><category domain="http://www.blogger.com/atom/ns#">methods</category><category domain="http://www.blogger.com/atom/ns#">random</category><title>Lab Coat Challenges: Challenge #5 Now Available</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCnlGiU6aPrbP8YQygxnG2XpKxZVUpMTVmbqtq1efc3R3GR5KbEUnvbPC2fJfygKOapYXi9J2olicZmjGR8pBhuEraGzzhoCdTtP6g4pxjiapRlHHtF7p85K8XW4MJzCw8nzxrCUBLXp8/s1600/LabCoatChallenge_LinkedInPostHeader5.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCnlGiU6aPrbP8YQygxnG2XpKxZVUpMTVmbqtq1efc3R3GR5KbEUnvbPC2fJfygKOapYXi9J2olicZmjGR8pBhuEraGzzhoCdTtP6g4pxjiapRlHHtF7p85K8XW4MJzCw8nzxrCUBLXp8/s1600/LabCoatChallenge_LinkedInPostHeader5.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;h2&gt;Challenge 5: Magic 8 Ball&lt;/h2&gt;&lt;h3&gt;Hey developers (and budding developers)!&lt;/h3&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_Qm9NZ34wJ3hUGKLMhmA_xyRS4AFMrakGW0OlFR9s1yZjPJbwbe4xmslF66rtRarWeZiOJjrtZDdCJotpM9aKets1uI9ixxbbBenUQQ_HjvHEHH8yAhf0TULoWp13sJ-4w5whREomOSg/s1600/SaaSy.jpeg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_Qm9NZ34wJ3hUGKLMhmA_xyRS4AFMrakGW0OlFR9s1yZjPJbwbe4xmslF66rtRarWeZiOJjrtZDdCJotpM9aKets1uI9ixxbbBenUQQ_HjvHEHH8yAhf0TULoWp13sJ-4w5whREomOSg/s320/SaaSy.jpeg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Dreamforce is next week! &amp;nbsp;Who saw that coming? &amp;nbsp;If you follow us on Twitter (&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;a dataquery=&quot;#txtMediaomy&quot; href=&quot;https://www.twitter.com/crmscience&quot;&gt;@crmscience&lt;/a&gt;&lt;/span&gt;), you probably did. #CalendarCube.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Being next week, you might be strategizing when you&#39;re going to get your selfie in with &lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;a dataquery=&quot;#txtMediaflx&quot; href=&quot;https://www.twitter.com/toosaasy&quot;&gt;SaaSy&lt;/a&gt;&lt;/span&gt;. &amp;nbsp;With this week&#39;s challenge, we wanted to give you a way to wake up in the morning and definitely have an answer for &quot;Will I see SaaSy today?&quot;&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Objective&lt;/span&gt;&lt;/div&gt;&lt;div&gt;You&#39;ll be creating a magic 8 ball like method that returns a string. &amp;nbsp;This magic 8 ball, though, only answers one question... &quot;Will I see SaaSy today?&quot; &amp;nbsp;You know, because a Dreamforce without a SaaSy selfie is like eating a cupcake without icing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Within the method, determine how to randomly select return one of the valid answers.&lt;/div&gt;&lt;br /&gt;
&lt;a href=&quot;http://bit.ly/lcchal5&quot; target=&quot;_blank&quot;&gt;Click here for the full details, rules, and starter code!&lt;/a&gt;&lt;br /&gt;
&lt;br data-cke-eol=&quot;1&quot; /&gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;meta name=&quot;twitter:card&quot; content=&quot;summary&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:site&quot; content=&quot;@crmscience&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:creator&quot; content=&quot;@kirkevonphilly&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:title&quot; content=&quot;CRM Science Lab Coat Challenges&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:description&quot; content=&quot;Think you&#39;re pretty saavy when it comes to Salesforce?  Demonstrate your mastery of the platform and earn the best badge possible - an honorary CRM Science lab coat!&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:image&quot; content=&quot;https://dl.dropboxusercontent.com/s/1ndnwdj3hz73a3g/LabCoat_Developers.png&quot;&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
</description><link>http://blog.crmscience.com/2015/09/lab-coat-challenges-challenge-5-now.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCnlGiU6aPrbP8YQygxnG2XpKxZVUpMTVmbqtq1efc3R3GR5KbEUnvbPC2fJfygKOapYXi9J2olicZmjGR8pBhuEraGzzhoCdTtP6g4pxjiapRlHHtF7p85K8XW4MJzCw8nzxrCUBLXp8/s72-c/LabCoatChallenge_LinkedInPostHeader5.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-1367124148843359867</guid><pubDate>Tue, 08 Sep 2015 00:22:00 +0000</pubDate><atom:updated>2015-09-07T20:38:21.975-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">caeser</category><category domain="http://www.blogger.com/atom/ns#">collection</category><category domain="http://www.blogger.com/atom/ns#">collections</category><category domain="http://www.blogger.com/atom/ns#">cypher</category><category domain="http://www.blogger.com/atom/ns#">df15</category><category domain="http://www.blogger.com/atom/ns#">Dreamforce</category><category domain="http://www.blogger.com/atom/ns#">encrypt</category><category domain="http://www.blogger.com/atom/ns#">lab coat challenge</category><category domain="http://www.blogger.com/atom/ns#">list</category><category domain="http://www.blogger.com/atom/ns#">lists</category><category domain="http://www.blogger.com/atom/ns#">method</category><category domain="http://www.blogger.com/atom/ns#">methods</category><category domain="http://www.blogger.com/atom/ns#">shift</category><title>Lab Coat Coat Challenges:  Challenge #3 Responses!</title><description>&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoxRMiQKX0bwqUQRChtDMssNpoernVW89DK1Dxza5tGs8CNZYaJVq-oVQsyYqskI_-sG9Ep8pyGlp5FBKct9d4iKLF2QkhB_WIygnX_MMzdAiOK2TDeqe9JPa2AUrkSlI7KCMm0JKb97M/s1600/LabCoatChallenge_LinkedInPostHeader3Solved.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoxRMiQKX0bwqUQRChtDMssNpoernVW89DK1Dxza5tGs8CNZYaJVq-oVQsyYqskI_-sG9Ep8pyGlp5FBKct9d4iKLF2QkhB_WIygnX_MMzdAiOK2TDeqe9JPa2AUrkSlI7KCMm0JKb97M/s1600/LabCoatChallenge_LinkedInPostHeader3Solved.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Great round of submissions for this Lab Coat Challenge! &lt;br /&gt;
&lt;br /&gt;
It&#39;s interesting to see how everyone had a similar approach to resolving the problem and used different tools to get there. Some were able to create concise solutions that made use of system methods while others ended up replicating the same work or something very similar. Great example of where it pays to know (or, minimally know they exist) some of the more rarely used methods in the documentation.&lt;br /&gt;
&lt;br /&gt;
Thanks to everyone who has participated so far and for those that are checking these answers out now and think they can do better! &amp;nbsp;Keep the submissions coming and we hope you&#39;re enjoying these challenges!&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-size: 16px;&quot;&gt;Link: &amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://www.crmscience.com/lab-coat-challenges&quot; style=&quot;background-color: white; border: 0px; box-sizing: border-box; color: #737e7e; font-size: 16px; margin: 0px; outline: 0px; padding: 0px; text-decoration: none; vertical-align: baseline;&quot; target=&quot;_blank&quot;&gt;Lab Coat Challenges&lt;/a&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;Starter Code&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
//  Start with this
public String getResult(String letter, Integer step) {
    String result;
    
    //  Your code here! 


    return result;
}
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;Asserts for all code&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
//  Confirm your results
system.assertEquals(&#39;B&#39;, getResult(&#39;A&#39;,1));
system.assertEquals(&#39;C&#39;, getResult(&#39;A&#39;,2));
system.assertEquals(&#39;A&#39;, getResult(&#39;Z&#39;,1));

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/pramforce&quot;&gt;PramForce&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

//  Start with this
public String getResult(string letter, integer step) {
    String result;
    
    //  Your code here!
    
    // Validating first parameter data as expected as per scenario
    try{
       if(letter.length() == 1 ) {
           Integer checkNum = Integer.valueOf(letter);
           return &#39;Please provide first parameter as character&#39; ;
       } else {
           return &#39;Please provide string of length one Only&#39; ;
       }
    } catch(Exception e) {
        letter = letter.toUpperCase();
    }
    
    integer numOfCharacters = 26;
    integer minASCIIForAlphabet = 65;
    integer maxASCIIForAlphabet = minASCIIForAlphabet + (numOfCharacters-1) ;
    boolean isNegativeStep = step&lt;0?true:false;
    
    // Converting Letter to ASCII code
    Integer[] vals = letter.getChars();
    integer AsciiValueOfTarget = vals[0] + step;
    integer tempValue;
        
    // Calculate end result Ascii code if step is positive
    if( AsciiValueOfTarget&gt;maxASCIIForAlphabet ) {
        tempValue = maxASCIIForAlphabet  - vals[0];
        tempValue = step - tempValue ;
        
        if(tempValue&gt;numOfCharacters ) {
            AsciiValueOfTarget = (minASCIIForAlphabet-1)  + math.mod(tempValue,numOfCharacters );                
        } else {
            AsciiValueOfTarget = (minASCIIForAlphabet-1)+tempValue;                
        }
    } else IF(AsciiValueOfTarget &lt; minASCIIForAlphabet )  {
        
        // Calculate end result Ascii code if step is -ve
        tempValue = vals[0] - minASCIIForAlphabet;
        
        if((step*(-1))&lt;=tempValue) {
            AsciiValueOfTarget = vals[0] - tempValue;
        } else {
            step = (step * -1) - tempValue;
            AsciiValueOfTarget = math.mod(step ,numOfCharacters) == 0?vals[0]:(maxASCIIForAlphabet+1) - math.mod(step ,numOfCharacters);
        }           
    }

    // Converting ASCII code to text
    result = String.fromCharArray( new List&lt;integer&gt;{ AsciiValueOfTarget } );
    
    System.debug(&#39;Result--&gt;&gt;&#39;+result);
    return result;
}
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/@melmoussaoui&quot;&gt;melmoussaoui&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

//  Start with this
public String getResult(string letter, integer step) {
    String result;
    
    //  Your code here!  
    if(letter.getChars()[0] + step &gt; 90)
        result= String.fromCharArray(new Integer[]{letter.getChars()[0]+step-26});
    else
        result= String.fromCharArray(new Integer[]{letter.getChars()[0]+step});
    return result;
}

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/DeborahOrth&quot;&gt;DeborahOrth&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

//  Start with this
public String getResult(string letter, integer step) {
    String result;
    
    //  Your code here!  
    String alphabet = &#39;ABCDEFGHIJKLMNOPQRSTUVWXYZ&#39;;
    Integer newPosition = alphabet.indexOf(letter) + step;
    
    if( newPosition &gt;= 26) {
        result = alphabet.substring( newPosition-26, newPosition-25);
    } else {
        result = alphabet.substring( newPosition, newPosition+1);
    }
    
    return result;
}
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/DouglasCAyers&quot;&gt;DouglasCAyers&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

//  Start with this
public String getResult(string letter, integer step) {
    String result;
    
    //  Your code here! 
    String[] ALPHABET = new String[]{ &#39;A&#39;, &#39;B&#39;, &#39;C&#39;, &#39;D&#39;, &#39;E&#39;, &#39;F&#39;, &#39;G&#39;, &#39;H&#39;, &#39;I&#39;, &#39;J&#39;, &#39;K&#39;, &#39;L&#39;, &#39;M&#39;, &#39;N&#39;, &#39;O&#39;, &#39;P&#39;, &#39;Q&#39;, &#39;R&#39;, &#39;S&#39;, &#39;T&#39;, &#39;U&#39;, &#39;V&#39;, &#39;W&#39;, &#39;X&#39;, &#39;Y&#39;, &#39;Z&#39; };

    Integer index = letter.charAt(0) - 65;
    Integer newIndex = Math.mod(index + step, 26);
    result = ALPHABET[newIndex];

    return result;
}

//  Confirm your results
system.assertEquals(&#39;B&#39;, getResult(&#39;A&#39;,1));
system.assertEquals(&#39;C&#39;, getResult(&#39;A&#39;,2));
system.assertEquals(&#39;A&#39;, getResult(&#39;Z&#39;,1));

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/@scottpelak&quot;&gt;@scottpelak&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
//  Start with this
public String getResult(string letter, integer step) {
    String result;
    
    //  Your code here! 
 // Supports negative step
 Integer resultIndex = Math.mod(Dictionary.indexOf(letter) + step + DictionaryLength, DictionaryLength);
 return Dictionary.substring(resultIndex, resultIndex + 1);
}

public String Dictionary = &#39;ABCDEFGHIJKLMNOPQRSTUVWXYZ&#39;;
public Integer DictionaryLength = Dictionary.length();
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/MichaelWelburn&quot;&gt;MichaelWelburn&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
//  Start with this
public String getResult(string letter, integer step) {
    String result;
    
    //  Your code here!  
    Integer aChar = &#39;A&#39;.getChars()[0];
    Integer zChar = &#39;Z&#39;.getChars()[0];
    
    // Assuming always 1 uppercase letter as input...
    Integer i = letter.getChars()[0];
    i += step;
    
    while (i &gt; zChar) {
        i -= (zChar - aChar + 1);
    }
        
    return String.fromCharArray(new Integer[]{i});
}
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/venky_mass&quot;&gt;venky_mass&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

//  Start with this
public String getResult(string letter, integer step) {
    String result;
    
    //  Your code here!  
    Map&lt;String,Integer&gt; mapCharToHexValue = new Map&lt;String,Integer&gt;();
    mapCharToHexValue.put(&#39;0&#39;,0);
    mapCharToHexValue.put(&#39;1&#39;,1);
    mapCharToHexValue.put(&#39;2&#39;,2);
    mapCharToHexValue.put(&#39;3&#39;,3);
    mapCharToHexValue.put(&#39;4&#39;,4);
    mapCharToHexValue.put(&#39;5&#39;,5);
    mapCharToHexValue.put(&#39;6&#39;,6);
    mapCharToHexValue.put(&#39;7&#39;,7);
    mapCharToHexValue.put(&#39;8&#39;,8);
    mapCharToHexValue.put(&#39;9&#39;,9);
    mapCharToHexValue.put(&#39;A&#39;,10);
    mapCharToHexValue.put(&#39;B&#39;,11);
    mapCharToHexValue.put(&#39;C&#39;,12);
    mapCharToHexValue.put(&#39;D&#39;,13);
    mapCharToHexValue.put(&#39;E&#39;,14);
    mapCharToHexValue.put(&#39;F&#39;,15);
    mapCharToHexValue.put(&#39;a&#39;,10);
    mapCharToHexValue.put(&#39;b&#39;,11);
    mapCharToHexValue.put(&#39;c&#39;,12);
    mapCharToHexValue.put(&#39;d&#39;,13);
    mapCharToHexValue.put(&#39;e&#39;,14);
    mapCharToHexValue.put(&#39;f&#39;,15);
    Integer retValues;
    letter = EncodingUtil.convertToHex(Blob.valueOf(letter));
    
    for(Integer i=0;i&lt;letter.length();i+=2) {
     retValues = (mapCharToHexValue.get(letter.substring(i,i+1))*16) + (mapCharToHexValue.get(letter.substring(i+1,i+2))) ;
    }

    if(retValues+step &lt;=90)
     result = String.fromCharArray( new List&lt;integer&gt; { retValues+step } );
    else {
     Integer newVal = (retValues+step)-26;
     result = String.fromCharArray( new List&lt;integer&gt; { newVal } );
    }
    return result;
}
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/@SF_Tidbits&quot;&gt;@SF_Tidbits&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

//  Start with this
public String getResult(string letter, integer step) {
    String result;
    
    //  Your code here!  
    String key = &#39;ABCDEFGHIJKLMNOPQRSTUVWXYZ&#39;;
 
 Integer newIndex = key.lastIndexOfIgnoreCase(letter) + step;
 
 if( newIndex &gt; 25 ){
  newIndex -= 26;
 }
    
    return System.String.fromCharArray(new list&lt;integer&gt;{key.charAt(newIndex)});
}

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@anonymous&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
//  Start with this
public String getResult(string letter, integer step) {
    String result;
    
    //  Your code here!  
    
    // Hex map to convert for adding step in base 10
    map&lt;string, integer&gt;hexString2IntMap = new map&lt;string, integer&gt; {
        &#39;0&#39; =&gt; 0, &#39;1&#39; =&gt; 1, &#39;2&#39; =&gt; 2, &#39;3&#39; =&gt; 3, &#39;4&#39; =&gt; 4, &#39;5&#39; =&gt; 5,
        &#39;6&#39; =&gt; 6, &#39;7&#39; =&gt; 7, &#39;8&#39; =&gt; 8, &#39;9&#39; =&gt; 9, &#39;a&#39; =&gt; 10, &#39;b&#39; =&gt; 11,
        &#39;c&#39; =&gt; 12, &#39;d&#39; =&gt; 13, &#39;e&#39; =&gt; 14, &#39;f&#39; =&gt; 15
    };
                
 map&lt;integer, string&gt; baseTen2StringMap = new map&lt;integer, string&gt;{
     65 =&gt; &#39;A&#39;, 66 =&gt; &#39;B&#39;, 67 =&gt; &#39;C&#39;, 68 =&gt; &#39;D&#39;, 69 =&gt; &#39;E&#39;, 70 =&gt; &#39;F&#39;,
  71 =&gt; &#39;G&#39;, 72 =&gt; &#39;H&#39;, 73 =&gt; &#39;I&#39;, 74 =&gt; &#39;J&#39;, 75 =&gt; &#39;K&#39;, 76 =&gt; &#39;L&#39;,
        77 =&gt; &#39;M&#39;, 78 =&gt; &#39;N&#39;, 79 =&gt; &#39;O&#39;, 80 =&gt; &#39;P&#39;, 81 =&gt; &#39;Q&#39;, 82 =&gt; &#39;R&#39;,
        83 =&gt; &#39;S&#39;, 84 =&gt; &#39;T&#39;, 85 =&gt; &#39;U&#39;, 86 =&gt; &#39;V&#39;, 87 =&gt; &#39;W&#39;, 88 =&gt; &#39;X&#39;,
        89 =&gt; &#39;Y&#39;, 90 =&gt; &#39;Z&#39;
    };
                            
 // Get the hex encoding of the given input letter &#39;A&#39;, &#39;B&#39;, etc
 String hex = EncodingUtil.convertToHex(Blob.valueOf(letter));
    
    // Convert to base 10, add step, convert back to hex and decode for resulting letter
    integer hexStringBaseTen = (hexString2IntMap.get(hex.substring(0,1))) * 16 + (hexString2IntMap.get(hex.substring(1,2)))*1;
    hexStringBaseTen += step;
    
    // Subject chunks of 26 until we&#39;re between 65-80 (26 characters)
    while (hexStringBaseTen &gt; 80)
        hexStringBaseTen -= 26;
    result = baseTen2StringMap.get(hexStringBaseTen);
    
    return result;
}
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/nickforce&quot;&gt;nickforce&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
//  Start with this
public String getResult(String letter, Integer step) {
    String result;
    
    //  Your code here!  
    /*  Increment/Shift the provided letter by the step provided.
        IE:  getResult(&#39;A&#39;, 1) should yield &quot;B&quot; and getResult(&#39;A&#39;,2) should yield &quot;C&quot; */

    // static variable with alphabet
    String alphabet = &#39;ABCDEFGHIJKLMNOPQRSTUVWXYZ&#39;;

    // determine 0 based index of the resulting letter
    Integer shiftIndex = alphabet.indexOfAny(letter) + step;

    // If statement allows for looping from Z -&gt; A 
    if(shiftIndex &gt; 25) 
        shiftIndex = shiftIndex - 26;
    
    // grab resulting letter by index from the alphabet string
    result = alphabet.substring(shiftIndex, shiftIndex + 1);

    return result;
}
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/CloudAnatomy&quot;&gt;CloudAnatomy&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

//  Start with this
public String getResult(string letter, integer step) {
    String result;
    
    //  Your code here!  
    result = letter.getChars()[0] + Math.Mod(step,26) &gt; 90 ? 
         String.fromCharArray(new Integer[]{(letter.getChars()[0]+Math.Mod(step,26))-90+64}) :
   String.fromCharArray(new Integer[]{letter.getChars()[0]+Math.Mod(step,26)});
 
    return result;    
}
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/michaelbsalty&quot;&gt;michaelbsalty&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
//  Start with this
public String getResult(string letter, integer step) {
    String result;
    
    //  Your code here!  
    result = (letter != &#39;Z&#39;) ? 
         String.fromCharArray(new List&lt;integer&gt;{letter.toUpperCase().charAt(0)+step}) : 
      String.fromCharArray(new List&lt;integer&gt;{64+step});
 
    return result;    
}
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:card&quot; content=&quot;summary&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:site&quot; content=&quot;@crmscience&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:creator&quot; content=&quot;@kirkevonphilly&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:title&quot; content=&quot;CRM Science Lab Coat Challenges&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:description&quot; content=&quot;Think you&#39;re pretty saavy when it comes to Salesforce?  Demonstrate your mastery of the platform and earn the best badge possible - an honorary CRM Science lab coat!&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:image&quot; content=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoxRMiQKX0bwqUQRChtDMssNpoernVW89DK1Dxza5tGs8CNZYaJVq-oVQsyYqskI_-sG9Ep8pyGlp5FBKct9d4iKLF2QkhB_WIygnX_MMzdAiOK2TDeqe9JPa2AUrkSlI7KCMm0JKb97M/s1600/LabCoatChallenge_LinkedInPostHeader3Solved.png&quot;&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
</description><link>http://blog.crmscience.com/2015/09/lab-coat-coat-challenges-challenge-3.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoxRMiQKX0bwqUQRChtDMssNpoernVW89DK1Dxza5tGs8CNZYaJVq-oVQsyYqskI_-sG9Ep8pyGlp5FBKct9d4iKLF2QkhB_WIygnX_MMzdAiOK2TDeqe9JPa2AUrkSlI7KCMm0JKb97M/s72-c/LabCoatChallenge_LinkedInPostHeader3Solved.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-9192384104410073925</guid><pubDate>Tue, 01 Sep 2015 04:27:00 +0000</pubDate><atom:updated>2015-09-01T00:28:52.847-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">collection</category><category domain="http://www.blogger.com/atom/ns#">collections</category><category domain="http://www.blogger.com/atom/ns#">df15</category><category domain="http://www.blogger.com/atom/ns#">Dreamforce</category><category domain="http://www.blogger.com/atom/ns#">lab coat challenge</category><category domain="http://www.blogger.com/atom/ns#">list</category><category domain="http://www.blogger.com/atom/ns#">lists</category><category domain="http://www.blogger.com/atom/ns#">method</category><category domain="http://www.blogger.com/atom/ns#">methods</category><title>Lab Coat Challenges: Challenge #4 Now Available</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinMLAh23T16dZPl3qpFvX-RLpeVaWKnumRr54bOw0aCTX2L7ku6w8VThrX2zu6qfW9TSXgVXrDdhSsOCmjQNoa8BFWpmRiVcL2ORHY8W_kiat-ORauXpIPbnzQ238CWFDrU77IiIe599Y/s1600/LabCoatChallenge_LinkedInPostHeader4.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinMLAh23T16dZPl3qpFvX-RLpeVaWKnumRr54bOw0aCTX2L7ku6w8VThrX2zu6qfW9TSXgVXrDdhSsOCmjQNoa8BFWpmRiVcL2ORHY8W_kiat-ORauXpIPbnzQ238CWFDrU77IiIe599Y/s1600/LabCoatChallenge_LinkedInPostHeader4.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h2&gt;Challenge 4: Get Crackin&#39;&lt;/h2&gt;&lt;h3&gt;Hey developers (and budding developers)!&lt;/h3&gt;Think you&#39;re pretty saavy when it comes Salesforce? &amp;nbsp;Demonstrate your mastery of the platform and earn the best badge possible - an honorary CRM Science lab coat!&lt;br /&gt;
&lt;br /&gt;
The last challenge had you thinking with a particular mindset. &amp;nbsp;This week is a bit of a continuation of that.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Clue&lt;/b&gt;&lt;br /&gt;
k == a&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Objective&lt;/b&gt;&lt;br /&gt;
Programmatically determine how k relates to a and use that knowledge to decrypt the following string: &lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.crmscience.com/#!Challenge-4-Get-Crackin/c1xbq/55e3e9d90cf29a3653bc7e5d&quot; target=&quot;_blank&quot;&gt;Click here for the string!&lt;/a&gt;&lt;br /&gt;
&lt;br data-cke-eol=&quot;1&quot; /&gt; &lt;br /&gt;
&lt;meta name=&quot;twitter:card&quot; content=&quot;summary&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:site&quot; content=&quot;@crmscience&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:creator&quot; content=&quot;@kirkevonphilly&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:title&quot; content=&quot;CRM Science Lab Coat Challenges&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:description&quot; content=&quot;Think you&#39;re pretty saavy when it comes to Salesforce?  Demonstrate your mastery of the platform and earn the best badge possible - an honorary CRM Science lab coat!&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:image&quot; content=&quot;https://dl.dropboxusercontent.com/s/1ndnwdj3hz73a3g/LabCoat_Developers.png&quot;&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
</description><link>http://blog.crmscience.com/2015/09/lab-coat-challenges-challenge-4-now.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinMLAh23T16dZPl3qpFvX-RLpeVaWKnumRr54bOw0aCTX2L7ku6w8VThrX2zu6qfW9TSXgVXrDdhSsOCmjQNoa8BFWpmRiVcL2ORHY8W_kiat-ORauXpIPbnzQ238CWFDrU77IiIe599Y/s72-c/LabCoatChallenge_LinkedInPostHeader4.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-4660798565651639609</guid><pubDate>Tue, 25 Aug 2015 05:16:00 +0000</pubDate><atom:updated>2015-09-07T20:24:47.643-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">collection</category><category domain="http://www.blogger.com/atom/ns#">collections</category><category domain="http://www.blogger.com/atom/ns#">df15</category><category domain="http://www.blogger.com/atom/ns#">Dreamforce</category><category domain="http://www.blogger.com/atom/ns#">lab coat challenge</category><category domain="http://www.blogger.com/atom/ns#">list</category><category domain="http://www.blogger.com/atom/ns#">lists</category><category domain="http://www.blogger.com/atom/ns#">method</category><category domain="http://www.blogger.com/atom/ns#">methods</category><title>Lab Coat Coat Challenges:  Challenge #2 Responses!</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVWo1grrDry7XCj-Iienu3dSwKMBGHtM1QyvR4IH-gHwRHZodacB46I4ZhHv0-spwFoY9ZZ71jI5GEdp5rZ0ORoAVwaqkkNM7WkZUpmtKz13u6aDOGPfbqhVm70XaRiaq0sQIBRv6_xWY/s1600/LabCoatChallenge_LinkedInPostHeaderSolved2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;br /&gt;
&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVWo1grrDry7XCj-Iienu3dSwKMBGHtM1QyvR4IH-gHwRHZodacB46I4ZhHv0-spwFoY9ZZ71jI5GEdp5rZ0ORoAVwaqkkNM7WkZUpmtKz13u6aDOGPfbqhVm70XaRiaq0sQIBRv6_xWY/s1600/LabCoatChallenge_LinkedInPostHeaderSolved2.png&quot; /&gt;&lt;br /&gt;
&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;h2&gt;Responses are in!&lt;/h2&gt;&lt;div&gt;&lt;br /&gt;
Just like our first challenge, the second had a lot of great submissions.  A few common approaches early in the week and a few revisions later after we issued a &quot;Can you do it in a single FOR loop&quot; sub-challenge.&lt;br /&gt;
&lt;br /&gt;
Again - If you haven&#39;t had a chance to submit your answer for this challenge OR you think you can improve upon the answers below, please do!&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: &#39;Times New Roman&#39;; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;&quot;&gt;&lt;div style=&quot;margin: 0px;&quot;&gt;Link: &amp;nbsp;&lt;a href=&quot;http://www.crmscience.com/lab-coat-challenges&quot; target=&quot;_blank&quot;&gt;Lab Coat Challenges&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/EricFishmanSF&quot;&gt;EricFishmanSF&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

//  Start with this
String msg = &#39;eeS uoy ta !ecrofmaerD&#39;;

//  Your code here!

// split the string by space
List&lt;string&gt; msg_Lst = msg.split(&#39; &#39;);  

// a variable to keep all sentence
String revMsg = &#39; &#39;;  

// Loop through each word
for (String word : msg_Lst) {
    String revStr = &#39;&#39;;  
    
    // reverse each word instead of using string.reverse()
    for (Integer i = word.length()-1; i &gt;= 0; i--) {
        revStr += word.substring(i, i+1);
    }
    
    // concatinate to sentence variable
    revMsg += &#39; &#39; + revStr;
}

// remove not relevant spaces
msg = revMsg.trim(); 

//  Confirm your results
system.assertEquals(&#39;See you at Dreamforce!&#39;, msg);

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/melmoussaoui&quot;&gt;melmoussaoui&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

//  Start with this
String msg = &#39;eeS uoy ta !ecrofmaerD&#39;;
        
//  Your code here!
List&lt;string&gt; newMsg = new List&lt;string&gt;();
for(String s: msg.split(&#39; &#39;))
{   
    Integer [] chars =s.getChars();
    Integer [] newChars = new Integer[]{} ;
    for(Integer i = chars.size(); i&gt;0; i--)
    {
        newchars.add(chars[i-1]);
    }
    newmsg.add(String.fromCharArray(newchars));
}
msg = String.join(newmsg, &#39; &#39;);

//  Confirm your results
system.assertEquals(&#39;See you at Dreamforce!&#39;, msg);

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/DouglasCAyers&quot;&gt;DouglasCAyers&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

//  Start with this
String msg = &#39;eeS uoy ta !ecrofmaerD&#39;;
        
//  Your code here!
List&lt;string&gt; reverseWords = new List&lt;string&gt;();
String[] words = msg.split(&#39; &#39;);
for ( String word : words ) {
    reverseWords.add( reverse( word ) );
}
msg = String.join( reverseWords, &#39; &#39; );
        
System.debug( msg );
      
//  Confirm your results
system.assertEquals(&#39;See you at Dreamforce!&#39;, msg);
        
public string reverse( String text ) {
    String reverseText = &#39;&#39;;
    if ( String.isNotBlank(text) ) {
        for ( Integer i = text.length() - 1; i &gt;= 0; i-- ) {
            reverseText += text.mid( i, 1 );
        }
    }
    return reverseText;
}
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;Anonymous&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

//  Start with this
String msg = &#39;eeS uoy ta !ecrofmaerD&#39;;

//  Your code here!
List&lt;string&gt; msgArray = msg.split(&#39; &#39;);
msg = &#39;&#39;;
String temp = &#39;&#39;;

for(String s : msgArray){
    temp = &#39;&#39;;
    for(Integer i = s.length() - 1; i &gt; -1; i--){
        temp += s.substring(i,i+1);        
    }
    msg += temp + &#39; &#39;;
}

msg=msg.trim();

//  Confirm your results
system.assertEquals(&#39;See you at Dreamforce!&#39;, msg);
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/tet3&quot;&gt;tet3&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

//  Start with this
String msg = &#39;eeS uoy ta !ecrofmaerD&#39;;

//  Your code here!
String gsm = &#39; &#39;;
String[] sdrow = msg.split(&#39; &#39;);

for (String drow : sdrow) {
    for (Integer x = 0; x &lt; drow.length(); x++) {
        gsm = gsm + drow.subString(drow.length() - (x+1), drow.length() - x);
    }
    gsm = gsm + &#39; &#39;;
}

msg = gsm.trim();

//  Confirm your results
system.assertEquals(&#39;See you at Dreamforce!&#39;, msg);
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/debdeepSFDC&quot;&gt;debdeepSFDC&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

//  Start with this
String msg = &#39;eeS uoy ta !ecrofmaerD&#39;;
String reversedMsg=&#39;&#39;;

//  Your code here!
for (string str: msg.split(&#39; &#39;)){
    reversedMsg += flipOver(str+&#39; &#39;);
    msg=reversedMsg.trim();
}

string flipOver(string message){
    string word=&#39;&#39;;
    if (message.length() &gt; 0){
        word = flipOver(message.substring(1))+message.left(1);
    }
    return word;
}

//  Confirm your results
system.assertEquals(&#39;See you at Dreamforce!&#39;, msg);
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/DeborahOrth&quot;&gt;DeborahOrth&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

//  Start with this
String msg = &#39;eeS uoy ta !ecrofmaerD&#39;;

//  Your code here!
String reverseMsg=&#39;&#39;;
String reverseToken=&#39;&#39;;

//step thru each char in the string, tokens are deliniated by a space
for( integer i=0, j=msg.length();  i &lt; j; i++){
    if( String.isBlank(msg.mid(i,1))){
        reverseMsg += reverseToken + &#39; &#39;;
        reverseToken = &#39;&#39;;
    } else {
        reverseToken = msg.mid(i,1) + reverseToken;
    }
}

//set the resulting message to the reverse message &amp; the last token
msg = reverseMsg + reverseToken;

//  Confirm your results
system.assertEquals(&#39;See you at Dreamforce!&#39;, msg);
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/kirkevonphilly&quot;&gt;kirkevonphilly&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
////////////////////////
//  Solution 1
////////////////////////

//  Start with this
String msg = &#39;eeS uoy ta !ecrofmaerD&#39;;
        
//  Your code here!

//  Properties for running string and curren token
string working = &#39;&#39;;
string tmp = &#39;&#39;;

//  Loop through each character of the phrase
for (string str :msg.split(&#39;&#39;)) {
    
    //  If the character is a space, append the curren tmp and the space to the running string
    if (str == &#39; &#39;) {
        working += tmp + str;
        tmp = &#39;&#39;;
    } else
        //  Otherwise, add the character to the start
        tmp = str + tmp;
}
msg = working + tmp;

//  Confirm your results
system.assertEquals(&#39;See you at Dreamforce!&#39;, msg);

////////////////////////
//  Solution 2
////////////////////////

//  Start with this
String msg = &#39;eeS uoy ta !ecrofmaerD&#39;;

list&lt;string&gt; msgList = new list&lt;string&gt;{};
integer cursor = 0;

//  Loop through each character of the message - add artificial space due to split(&#39;&#39;)[0] results
for (string str :(&#39; &#39; + msg).split(&#39;&#39;)) {
    
    //  If it is a space or the cursor hasn&#39;t been moved, add it to the start
    if (str == &#39; &#39; || cursor == 0) {
       
        //  Add character to the start
        msgList.add(str);
       
        //  Update cursor location
        cursor = msgList.size(); 
    } else {

        //  Add to current cursor location
        msgList.add(cursor - 1, str);
    }
}

msg = &#39;&#39;;
for (string str :msgList)
    msg += str;

msg = msg.trim();

//  Confirm your results
system.assertEquals(&#39;See you at Dreamforce!&#39;, msg);
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:card&quot; content=&quot;summary&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:site&quot; content=&quot;@crmscience&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:creator&quot; content=&quot;@kirkevonphilly&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:title&quot; content=&quot;CRM Science Lab Coat Challenges - Solutions #1&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:description&quot; content=&quot;Solutions to the first @CRM Science #LabCoatChallenge have been posted.  Check them out!&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:image&quot; content=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVWo1grrDry7XCj-Iienu3dSwKMBGHtM1QyvR4IH-gHwRHZodacB46I4ZhHv0-spwFoY9ZZ71jI5GEdp5rZ0ORoAVwaqkkNM7WkZUpmtKz13u6aDOGPfbqhVm70XaRiaq0sQIBRv6_xWY/s1600/LabCoatChallenge_LinkedInPostHeaderSolved2.png&quot;&gt;</description><link>http://blog.crmscience.com/2015/08/lab-coat-coat-challenges-challenge-2.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVWo1grrDry7XCj-Iienu3dSwKMBGHtM1QyvR4IH-gHwRHZodacB46I4ZhHv0-spwFoY9ZZ71jI5GEdp5rZ0ORoAVwaqkkNM7WkZUpmtKz13u6aDOGPfbqhVm70XaRiaq0sQIBRv6_xWY/s72-c/LabCoatChallenge_LinkedInPostHeaderSolved2.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-3538705333752479699</guid><pubDate>Sun, 23 Aug 2015 21:58:00 +0000</pubDate><atom:updated>2015-08-23T23:07:13.584-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">collection</category><category domain="http://www.blogger.com/atom/ns#">collections</category><category domain="http://www.blogger.com/atom/ns#">df15</category><category domain="http://www.blogger.com/atom/ns#">Dreamforce</category><category domain="http://www.blogger.com/atom/ns#">lab coat challenge</category><category domain="http://www.blogger.com/atom/ns#">list</category><category domain="http://www.blogger.com/atom/ns#">lists</category><category domain="http://www.blogger.com/atom/ns#">method</category><category domain="http://www.blogger.com/atom/ns#">methods</category><title>Lab Coat Challenges: Challenge #3 Now Available</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSmOpqDQTMI_RqsHn0w8Bhp508EhAothAvJC630QT2C0MhwtoXCm1ZFnAXpGrB6TBg11KNv4JmaHBRKlQT8Jm75NKfDED2SBIzuPfpi_EfnpR2mhalYbdhHWgyfCOs8LhUv5sM2bQOmk/s1600/LabCoatChallenge_LinkedInPostHeader3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSmOpqDQTMI_RqsHn0w8Bhp508EhAothAvJC630QT2C0MhwtoXCm1ZFnAXpGrB6TBg11KNv4JmaHBRKlQT8Jm75NKfDED2SBIzuPfpi_EfnpR2mhalYbdhHWgyfCOs8LhUv5sM2bQOmk/s1600/LabCoatChallenge_LinkedInPostHeader3.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h2&gt;
Challenge 3: As Easy as A to B&lt;/h2&gt;
&lt;h3&gt;
Hey developers (and budding developers)!&lt;/h3&gt;
Think you&#39;re pretty saavy when it comes Salesforce? &amp;nbsp;Demonstrate your mastery of the platform and earn the best badge possible - an honorary CRM Science lab coat!&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: arial, &#39;ｍｓ ｐゴシック&#39;, &#39;ms pgothic&#39;, 돋움, dotum, helvetica, sans-serif; font-size: 12px;&quot;&gt;It&#39;s back to school already for a lot of young developers out there.&amp;nbsp; We though this would help them recall some of&amp;nbsp;that knowledge that might have been lost over the summer.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-family: arial, &#39;ｍｓ ｐゴシック&#39;, &#39;ms pgothic&#39;, 돋움, dotum, helvetica, sans-serif; font-size: 12px; font-stretch: normal; margin: 0px; max-width: 99.9000015258789%;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: arial, &#39;ｍｓ ｐゴシック&#39;, &#39;ms pgothic&#39;, 돋움, dotum, helvetica, sans-serif; font-size: 12px; font-stretch: normal; margin: 0px; max-width: 99.9000015258789%;&quot;&gt;
A... B... shoot, what comes next?&lt;/div&gt;
&lt;div style=&quot;font-family: arial, &#39;ｍｓ ｐゴシック&#39;, &#39;ms pgothic&#39;, 돋움, dotum, helvetica, sans-serif; font-size: 12px; font-stretch: normal; margin: 0px; max-width: 99.9000015258789%;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: arial, &#39;ｍｓ ｐゴシック&#39;, &#39;ms pgothic&#39;, 돋움, dotum, helvetica, sans-serif; font-size: 12px; font-stretch: normal; margin: 0px; max-width: 99.9000015258789%;&quot;&gt;
This week&#39;s challenge is all about finding the easiest way to increment characters.&amp;nbsp; How do you increment a string that is set to &quot;A&quot; to &quot;B?&quot;&amp;nbsp; How about &quot;S&quot; to &quot;T&quot; and so on?&lt;/div&gt;
&lt;div style=&quot;font-family: arial, &#39;ｍｓ ｐゴシック&#39;, &#39;ms pgothic&#39;, 돋움, dotum, helvetica, sans-serif; font-size: 12px; font-stretch: normal; margin: 0px; max-width: 99.9000015258789%;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: arial, &#39;ｍｓ ｐゴシック&#39;, &#39;ms pgothic&#39;, 돋움, dotum, helvetica, sans-serif; font-size: 12px; font-stretch: normal; margin: 0px; max-width: 99.9000015258789%;&quot;&gt;
If only if it were as simple as &quot;A&quot; + 1.&amp;nbsp; Or is it?&lt;/div&gt;
&lt;div style=&quot;font-family: arial, &#39;ｍｓ ｐゴシック&#39;, &#39;ms pgothic&#39;, 돋움, dotum, helvetica, sans-serif; font-size: 12px; font-stretch: normal; margin: 0px; max-width: 99.9000015258789%;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: arial, &#39;ｍｓ ｐゴシック&#39;, &#39;ms pgothic&#39;, 돋움, dotum, helvetica, sans-serif; font-size: 12px; font-stretch: normal; margin: 0px; max-width: 99.9000015258789%;&quot;&gt;
In the sample code, you&#39;ll be providing the body of a method that accepts two parameters:&lt;/div&gt;
&lt;ul class=&quot;font_8&quot; style=&quot;font-family: arial, &#39;ｍｓ ｐゴシック&#39;, &#39;ms pgothic&#39;, 돋움, dotum, helvetica, sans-serif; font-size: 12px; font-stretch: normal; margin-left: 0.5em; margin-right: 0px; padding-left: 1.3em; padding-right: 0px;&quot;&gt;
&lt;li style=&quot;color: inherit; font-family: inherit; font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit;&quot;&gt;&lt;div style=&quot;font-stretch: normal; margin: 0px;&quot;&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;Letter&amp;nbsp;&lt;/span&gt;- a string of a single letter that you&#39;ll be incrementing&lt;/div&gt;
&lt;/li&gt;
&lt;li style=&quot;color: inherit; font-family: inherit; font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit;&quot;&gt;&lt;div style=&quot;font-stretch: normal; margin: 0px;&quot;&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;Step&amp;nbsp;&lt;/span&gt;- an integer to control how far many steps the starting letter should be shifted.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
Up to the challenge? &amp;nbsp;&lt;a href=&quot;http://www.crmscience.com/#!Challenge-3-As-Easy-as-A-to-B/c1xbq/55da329c0cf20831ee3c45c9&quot; target=&quot;_blank&quot;&gt;Review the rules, full details and starter code here&lt;/a&gt;!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
</description><link>http://blog.crmscience.com/2015/08/lab-coat-challenges-challenge-3-now.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSmOpqDQTMI_RqsHn0w8Bhp508EhAothAvJC630QT2C0MhwtoXCm1ZFnAXpGrB6TBg11KNv4JmaHBRKlQT8Jm75NKfDED2SBIzuPfpi_EfnpR2mhalYbdhHWgyfCOs8LhUv5sM2bQOmk/s72-c/LabCoatChallenge_LinkedInPostHeader3.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-67641245672721969</guid><pubDate>Wed, 19 Aug 2015 04:42:00 +0000</pubDate><atom:updated>2015-08-19T12:45:33.580-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">collection</category><category domain="http://www.blogger.com/atom/ns#">collections</category><category domain="http://www.blogger.com/atom/ns#">df15</category><category domain="http://www.blogger.com/atom/ns#">Dreamforce</category><category domain="http://www.blogger.com/atom/ns#">lab coat challenge</category><category domain="http://www.blogger.com/atom/ns#">list</category><category domain="http://www.blogger.com/atom/ns#">lists</category><category domain="http://www.blogger.com/atom/ns#">method</category><category domain="http://www.blogger.com/atom/ns#">methods</category><title>Lab Coat Coat Challenges:  Challenge #1 Responses!</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwPwaLgQawdX2fWKgemJJGY8rPyYUfDJFrDCM0PZweju5pkDIfxvChUII0t-rYOrhyphenhyphenFhg55yuhD4nmGoWDvXmmmp7X_fsNHjuMsnsV8ilxaIL_NCWF0cPCFa9qlXTS1W9s1HcXPJi1OI8/s1600/LabCoatChallenge_LinkedInPostHeaderSolved.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwPwaLgQawdX2fWKgemJJGY8rPyYUfDJFrDCM0PZweju5pkDIfxvChUII0t-rYOrhyphenhyphenFhg55yuhD4nmGoWDvXmmmp7X_fsNHjuMsnsV8ilxaIL_NCWF0cPCFa9qlXTS1W9s1HcXPJi1OI8/s1600/LabCoatChallenge_LinkedInPostHeaderSolved.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;h2&gt;Responses are in for our first Lab Coat Challenge!&lt;/h2&gt;&lt;div&gt;We had some great responses over the last week from several Salesforce devs! &amp;nbsp;If you haven&#39;t had a chance to submit your answer for this challenge OR you think you can improve upon the answers below, please do!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: &#39;Times New Roman&#39;; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: &#39;Times New Roman&#39;; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;&quot;&gt;&lt;div style=&quot;margin: 0px;&quot;&gt;Link: &amp;nbsp;&lt;a href=&quot;http://www.crmscience.com/#!Challenge-1-Building-a-Simple-List-of-Strings/c1xbq/55ba76420cf285bbf300fe3d&quot; target=&quot;_blank&quot;&gt;Lab Coat Challenge #1&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
While all technically were valid answers, submissions generally fell into a few camps; those with structure that could be used and extended beyond the example strings and collections provided, those that would only work with the examples given, and those just being...&quot;slick.&quot; &amp;nbsp;We&#39;ll call it &quot;slick&quot; and leave the interpretation to you...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Early in the week, no two answers were the same. &amp;nbsp;By the end of the week, we had several that made use of the list.addAll() method. &amp;nbsp;Others techniques included various ways of pre-populating lists and even various string manipulations.&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;h4&gt;All code started with the following...&lt;br /&gt;
&lt;/h4&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
//  Properties to begin with
string string1 = &#39;string1&#39;;
string string2 = &#39;string2&#39;;
list&lt;string&gt; list1 = new list&lt;string&gt;{&#39;string3&#39;,&#39;string4&#39;};
list&lt;string&gt; list2 = new list&lt;string&gt;{&#39;string5&#39;,&#39;string6&#39;};
set&lt;string&gt; set1 = new set&lt;string&gt;{&#39;string7&#39;,&#39;string8&#39;};
set&lt;string&gt; set2 = new set&lt;string&gt;{&#39;string9&#39;,&#39;string10&#39;};

/*  Start here!  Add whatever code you need to consolidate 
    those strings into a single list called mergedList */

list&lt;string&gt; mergedList =
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h4&gt;All code was verified using...&lt;br /&gt;
&lt;/h4&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
/*  Make sure you end up with 10 strings in the mergeList 
    collection so your answer is valid! */
system.assert(mergedList.size() == 10);
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;h1&gt;So let&#39;s take a look at some of the responses!&lt;/h1&gt;&lt;div&gt;Note: &amp;nbsp;Some code might have been modified up for readability.&lt;/div&gt;&lt;div&gt;&lt;h3&gt;Anonymous&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

string1 += &#39;,&#39; + string2 + &#39;,&#39; + String.join(list1, &#39;,&#39;) + &#39;,&#39; + String.join(list2, &#39;,&#39;) + &#39;,&#39; + String.join(new List&lt;string&gt;(set1), &#39;,&#39;) + &#39;,&#39; + String.join(new List&lt;string&gt;(set2), &#39;,&#39;);
list&lt;string&gt; mergedList = string1.split(&#39;,&#39;);

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;Anonymous&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

list&lt;string&gt; mergedList = new list&lt;string&gt;{string1, string2};
mergedList.addAll(list1);
mergedList.addAll(list2);
mergedList.addAll(set1);
mergedList.addAll(set2);  

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/douglascayers&quot; target=&quot;_blank&quot;&gt;DouglasCAyers&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

////////////////////////////////////
// Answer 1
////////////////////////////////////
list&lt;string&gt; mergedList = new List&lt;string&gt;{ string1, string2 };
mergedList.addAll(list1);
mergedList.addAll(list2);
mergedList.addAll(set1);
mergedList.addAll(set2);

////////////////////////////////////
// Answer 2
////////////////////////////////////

list&lt;string&gt; mergedList = new List&lt;string&gt;();
for( Integer i = 1; i &lt;= 10; i++) {
    mergedList.add( &#39;string&#39; + i );
}    


]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;Anonymous&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

List&lt;string&gt; mergedList = new list&lt;string&gt;{string1, string2, list1.get(0), list1.get(1), list2.get(0), list2.get(1)};      
for (string setString1 : set1) {
    mergedList.add(setString1);
}

for (string setString2 : set2) {
    mergedList.add(setString2);
}

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/nitingupta9927&quot; target=&quot;_blank&quot;&gt;nitingupta9927&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

////////////////////////////////////
// Answer 1
////////////////////////////////////
list&lt;string&gt; mergedList = new List&lt;string&gt;{string1, string2};
mergedList.addAll(list1);
mergedList.addAll(list2);
mergedList.addAll(set1);
mergedList.addAll(set2);

////////////////////////////////////
// Answer 2
////////////////////////////////////
list&lt;string&gt; mergedList = new List&lt;string&gt;{string1, string2, list1[0], list1[1],list2[0], list2[1]};
mergedList.addAll(set1);
mergedList.addAll(set2);


]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;Dan Kelner&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

list&lt;string&gt; mergedList = new String[]{string1, string2};

//Can&#39;t keep set1 and set2 as sets because their remove() method doesn&#39;t return an object
List&lt;string&gt; list3 = new List&lt;string&gt;(set1);        
list3.addAll(set2);
while (!list1.isEmpty() || !list2.isEmpty() || !list3.isEmpty()){ 
    mergedList.add(
        !list1.isEmpty() ? list1.remove(0) : 
        (!list2.isEmpty() ? list2.remove(0) : 
        (!list3.isEmpty() ? list3.remove(0) : 
         null))
    );
}

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/ericfishmansf&quot; target=&quot;_blank&quot;&gt;EricFishmanSF&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

// create new list and add two strings based on list constructor        
list&lt;string&gt; mergedList = new list&lt;string&gt;{string1, string2};         

// add all list members to existing mergedList list
mergedList.addall (list1);
mergedList.addall (list2);
mergedList.addall (set1);
mergedList.addall (set2);

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/debdeepsfdc&quot; target=&quot;_blank&quot;&gt;debdeepsfdc&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

list1.add(string1);
list1.add(string2);
set1.addAll(set2);
list1.addAll(list2);
list1.addAll(set1);
list&lt;string&gt; mergedList = new list&lt;string&gt;(list1);

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;h1&gt;CRM Science Responses&lt;/h1&gt;&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/kirkevonphilly&quot; target=&quot;_blank&quot;&gt;kirkevonphilly&lt;/a&gt;&lt;/h3&gt;When we started preparing these challenges, I wanted to be sure to be able to provide an answer for each.  So how did I approach it?  Dynamically, of course!&lt;br /&gt;
&lt;br /&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

//  Start mergedList w/ the base strings
list&lt;string&gt; mergedList = new list&lt;string&gt;{string1, string2}; 

//  Create a map tag collection type to a list of that type
map&lt;string, list&lt;object&gt;&gt; collections = new map&lt;string, list&lt;object&gt;&gt; {
     &#39;lists&#39; =&gt; new list&lt;list&lt;string&gt;&gt;{list1, list2},
     &#39;sets&#39; =&gt; new list&lt;set&lt;string&gt;&gt;{set1, set2}
};

//  Loop through tags...
for (string str : collections.keyset())
    
    //  Treat inner list or set as a generic object
    for(object obj :collections.get(str))

        //  Do an addAll() based on the tag, using a ternary
        mergedList.addAll(str == &#39;lists&#39; ? (list&lt;string&gt;)obj : (new list&lt;string&gt;((set&lt;string&gt;)obj)));

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;@&lt;a href=&quot;https://www.twitter.com/mikekatulka&quot; target=&quot;_blank&quot;&gt;mikekatulka&lt;/a&gt;&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

// get the sets into an iterable format(list) and add to list1
list1.addAll((string.join(new List&lt;string&gt;(set1), &#39;,&#39;) + &#39;,&#39; + string.join(new List&lt;string&gt;(set2), &#39;,&#39;)).split(&#39;,&#39;));

// use the list constructor to append everything
list&lt;string&gt; mergedList = new List&lt;string&gt;{string1, string2, list1[0], list1[1], list1[2], list1[3], list1[4], list1[5], list2[0], list2[1]};

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;h3&gt;Tom Miller&lt;/h3&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

// Concat lists
list2.addAll(list1);

// To hold ending collection - constructor used to add both lists
list&lt;string&gt; mergedList = new list&lt;string&gt;(list2);

// set to set, use addAll
mergedList.addAll(
    (string.valueOf(set1).replace(&#39;}&#39;,&#39;&#39;).replace(&#39;{&#39;, &#39;&#39;) + 
     string.valueOf(set2).replace(&#39;{&#39;,&#39;,&#39;).replace(&#39;}&#39;,&#39;&#39;) + 
     string.valueOf( (string1+&#39;,&#39;+string2).split(&#39;,&#39;))
         .replace(&#39;)&#39;, &#39;&#39;).replace(&#39;(&#39;,&#39;,&#39;))
         .split(&#39;,&#39;) 
);

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;meta name=&quot;twitter:card&quot; content=&quot;summary&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:site&quot; content=&quot;@crmscience&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:creator&quot; content=&quot;@kirkevonphilly&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:title&quot; content=&quot;CRM Science Lab Coat Challenges - Solutions #1&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:description&quot; content=&quot;Solutions to the first @CRM Science #LabCoatChallenge have been posted.  Check them out!&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:image&quot; content=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwPwaLgQawdX2fWKgemJJGY8rPyYUfDJFrDCM0PZweju5pkDIfxvChUII0t-rYOrhyphenhyphenFhg55yuhD4nmGoWDvXmmmp7X_fsNHjuMsnsV8ilxaIL_NCWF0cPCFa9qlXTS1W9s1HcXPJi1OI8/s1600/LabCoatChallenge_LinkedInPostHeaderSolved.png&quot;&gt;</description><link>http://blog.crmscience.com/2015/08/lab-coat-coat-challenges-challenge-1.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwPwaLgQawdX2fWKgemJJGY8rPyYUfDJFrDCM0PZweju5pkDIfxvChUII0t-rYOrhyphenhyphenFhg55yuhD4nmGoWDvXmmmp7X_fsNHjuMsnsV8ilxaIL_NCWF0cPCFa9qlXTS1W9s1HcXPJi1OI8/s72-c/LabCoatChallenge_LinkedInPostHeaderSolved.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-1129516298236593283</guid><pubDate>Mon, 17 Aug 2015 02:54:00 +0000</pubDate><atom:updated>2015-08-19T12:51:01.380-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">collection</category><category domain="http://www.blogger.com/atom/ns#">collections</category><category domain="http://www.blogger.com/atom/ns#">df15</category><category domain="http://www.blogger.com/atom/ns#">Dreamforce</category><category domain="http://www.blogger.com/atom/ns#">lab coat challenge</category><category domain="http://www.blogger.com/atom/ns#">list</category><category domain="http://www.blogger.com/atom/ns#">lists</category><category domain="http://www.blogger.com/atom/ns#">method</category><category domain="http://www.blogger.com/atom/ns#">methods</category><title>Lab Coat Challenges: Challenge #2 Now Available</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaO6K9gfD20RBGovw-MxQpY5U-spCMCxa3vGujGWQnYJ3bMKQtKcVg76e46_YQ1hKLc2FMWf3igiPOx6Lot71klvz1jgD0yNMyPwLn0U7ZkDY53CMo43KXL_-gx2mte99eU6ZCR6TxCiU/s1600/LabCoatChallenge_LinkedInPostHeader_2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaO6K9gfD20RBGovw-MxQpY5U-spCMCxa3vGujGWQnYJ3bMKQtKcVg76e46_YQ1hKLc2FMWf3igiPOx6Lot71klvz1jgD0yNMyPwLn0U7ZkDY53CMo43KXL_-gx2mte99eU6ZCR6TxCiU/s1600/LabCoatChallenge_LinkedInPostHeader_2.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;h2&gt;Challenge 2: Reversing Text&lt;/h2&gt;&lt;h3&gt;Hey developers (and budding developers)!&lt;/h3&gt;Think you&#39;re pretty saavy when it comes Salesforce? &amp;nbsp;Demonstrate your mastery of the platform and earn the best badge possible - an honorary CRM Science lab coat!&lt;br /&gt;
&lt;br /&gt;
Challenge #2 is a simple task! &amp;nbsp;Turn &quot;eeS uoy ta !ecrofmaerD&quot; into &quot;See you at Dreamforce!&quot; &amp;nbsp;See what we did there? &amp;nbsp; How few statements do you need?&lt;br /&gt;
&lt;br /&gt;
Up to the challenge? &amp;nbsp;&lt;a href=&quot;http://www.crmscience.com/#!Challenge-2-Reversing-Text/c1xbq/55cea60d0cf2a8512f7d72d4&quot; target=&quot;_blank&quot;&gt;Review the rules, full details and starter code here&lt;/a&gt;!&lt;br /&gt;
&lt;meta name=&quot;twitter:card&quot; content=&quot;summary&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:site&quot; content=&quot;@crmscience&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:creator&quot; content=&quot;@kirkevonphilly&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:title&quot; content=&quot;CRM Science Lab Coat Challenges&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:description&quot; content=&quot;Think you&#39;re pretty saavy when it comes to Salesforce?  Demonstrate your mastery of the platform and earn the best badge possible - an honorary CRM Science lab coat!&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:image&quot; content=&quot;https://dl.dropboxusercontent.com/s/1ndnwdj3hz73a3g/LabCoat_Developers.png&quot;&gt;</description><link>http://blog.crmscience.com/2015/08/lab-coat-challenges-challenge-2-now.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaO6K9gfD20RBGovw-MxQpY5U-spCMCxa3vGujGWQnYJ3bMKQtKcVg76e46_YQ1hKLc2FMWf3igiPOx6Lot71klvz1jgD0yNMyPwLn0U7ZkDY53CMo43KXL_-gx2mte99eU6ZCR6TxCiU/s72-c/LabCoatChallenge_LinkedInPostHeader_2.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-6922074930616500485</guid><pubDate>Fri, 07 Aug 2015 14:20:00 +0000</pubDate><atom:updated>2020-02-21T18:10:40.224-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">collection</category><category domain="http://www.blogger.com/atom/ns#">collections</category><category domain="http://www.blogger.com/atom/ns#">df15</category><category domain="http://www.blogger.com/atom/ns#">Dreamforce</category><category domain="http://www.blogger.com/atom/ns#">lab coat challenge</category><category domain="http://www.blogger.com/atom/ns#">list</category><category domain="http://www.blogger.com/atom/ns#">lists</category><category domain="http://www.blogger.com/atom/ns#">method</category><category domain="http://www.blogger.com/atom/ns#">methods</category><title>Lab Coat Challenges:  Challenge #1 is Up!</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://www.crmscience.com/lab-coat-lessons&quot;&gt;&lt;img alt=&quot;Visit our website&quot; border=&quot;0&quot; data-original-height=&quot;300&quot; data-original-width=&quot;1600&quot; height=&quot;120&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiMZW2AjEu-qQrMD6QIOtSX7VLLGnSBv1oUIKukZ3XG2IZCIGwQuUzsAWtVvOyjbRO54lS16uF_NwS0-yJ_MebVQqM_fEqWcqYdFp_-7urHs0pS0I5BPl35Hg5A3F_RI-_seyFupLSSTo/s640/Blogger-Banner-01.png&quot; title=&quot;&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h2&gt;
&lt;br /&gt;&lt;/h2&gt;
&lt;h2&gt;
Introducing the CRM Science Lab Coat Challenges!&lt;/h2&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2S89wRRf2PPp10LDp-Q8RJhTgouyZAs0tEk91g55zaUFaP8OReABA36C1rGX7AY5bYO-UoXQjzDKgshi7KMP4hO4r9bklu-B_d75Hb4-wfv8FxbUqA7weKH5ntCzTbjb7aJ0blOFzhCM/s1600/LabCoat_Developers.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2S89wRRf2PPp10LDp-Q8RJhTgouyZAs0tEk91g55zaUFaP8OReABA36C1rGX7AY5bYO-UoXQjzDKgshi7KMP4hO4r9bklu-B_d75Hb4-wfv8FxbUqA7weKH5ntCzTbjb7aJ0blOFzhCM/s1600/LabCoat_Developers.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
Hey developers!&lt;/h3&gt;
Think you&#39;re pretty saavy when it comes Salesforce? &amp;nbsp;Demonstrate your mastery of the platform and earn the best badge possible - an honorary CRM Science lab coat!&lt;br /&gt;
&lt;br /&gt;
Challenge #1 is all about working with collections and doing so as efficiently as possible. &amp;nbsp;The gist is you have a few strings, few lists of strings, few sets of strings, and it&#39;s up to you to merge them all down into a single list of strings, using as little code as possible.&lt;br /&gt;
&lt;br /&gt;
Up to the challenge? &amp;nbsp;&lt;a href=&quot;http://www.crmscience.com/lab-coat-challenges&quot; target=&quot;_blank&quot;&gt;Get the full details here&lt;/a&gt;!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</description><link>http://blog.crmscience.com/2015/08/lab-coat-challenges-challenge-1-is-up.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiMZW2AjEu-qQrMD6QIOtSX7VLLGnSBv1oUIKukZ3XG2IZCIGwQuUzsAWtVvOyjbRO54lS16uF_NwS0-yJ_MebVQqM_fEqWcqYdFp_-7urHs0pS0I5BPl35Hg5A3F_RI-_seyFupLSSTo/s72-c/Blogger-Banner-01.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-6268263324444181423</guid><pubDate>Sat, 27 Jun 2015 22:36:00 +0000</pubDate><atom:updated>2020-02-21T17:58:42.234-05:00</atom:updated><title>How to Abort a Scheduled / Queued Apex Job by Name</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://www.crmscience.com/lab-coat-lessons&quot;&gt;&lt;img alt=&quot;https://www.crmscience.com/lab-coat-lessons&quot; border=&quot;0&quot; data-original-height=&quot;300&quot; data-original-width=&quot;1600&quot; height=&quot;120&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiMZW2AjEu-qQrMD6QIOtSX7VLLGnSBv1oUIKukZ3XG2IZCIGwQuUzsAWtVvOyjbRO54lS16uF_NwS0-yJ_MebVQqM_fEqWcqYdFp_-7urHs0pS0I5BPl35Hg5A3F_RI-_seyFupLSSTo/s640/Blogger-Banner-01.png&quot; title=&quot;&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://2.bp.blogspot.com/-TR0fyJ7ntqo/VY8kXmiQEKI/AAAAAAAAAEA/vla12-BS878/s1600/apex%2Bqueue%2Babort%2Bjob%2Bby%2Bname.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://2.bp.blogspot.com/-TR0fyJ7ntqo/VY8kXmiQEKI/AAAAAAAAAEA/vla12-BS878/s1600/apex%2Bqueue%2Babort%2Bjob%2Bby%2Bname.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
For the advanced salesforce developers out there.... in the past (before Winter 14 release) there was no way to query for a Scheduled, Future, or Batch job by the name that was given to it. You had to track the ID of the job as the job was being created and store this into a custom object or setting for future reference.&lt;br /&gt;
&lt;br /&gt;
Thanks to a &lt;a href=&quot;http://releasenotes.docs.salesforce.com/en-us/winter14/release-notes/rn_186_apex_job_name_type.htm&quot; target=&quot;_blank&quot;&gt;feature from Winter 14&lt;/a&gt; which stemmed from &lt;a href=&quot;https://success.salesforce.com/ideaview?id=08730000000K5fWAAS&quot; target=&quot;_blank&quot;&gt;this idea&lt;/a&gt;, you can easily query the CronTrigger object filtered by the job name. &amp;nbsp;Remember to increase your API version in your class if this does not work.&lt;br /&gt;
&lt;br /&gt;
Now we can query for the apex job by name and perform a system.abortjob with confidence that we have the correct job.&lt;br /&gt;
&lt;br /&gt;
Here is a nice block of code that can be used in your application or something to keep handy for an Execute Anyonymous situation.&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

    // loop through jobs located by name that we need to abort
    for(CronTrigger ct : [SELECT Id, CronJobDetail.Name, CronJobDetail.JobType 
                            FROM CronTrigger 
                           WHERE CronJobDetail.Name like &#39;Work Order%&#39;]){

        // abort the job, try/catch because the job might not exist 
        // if it&#39;s being aborted manually or from another execution
        try{
            system.abortJob(ct.id);
        } catch (exception e) {}
    }

&lt;/script&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;








&lt;/div&gt;
</description><link>http://blog.crmscience.com/2015/06/how-to-abort-scheduled-queued-apex-job.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiMZW2AjEu-qQrMD6QIOtSX7VLLGnSBv1oUIKukZ3XG2IZCIGwQuUzsAWtVvOyjbRO54lS16uF_NwS0-yJ_MebVQqM_fEqWcqYdFp_-7urHs0pS0I5BPl35Hg5A3F_RI-_seyFupLSSTo/s72-c/Blogger-Banner-01.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-6120992444231615424</guid><pubDate>Tue, 09 Jun 2015 16:28:00 +0000</pubDate><atom:updated>2015-06-09T12:28:55.247-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">API</category><category domain="http://www.blogger.com/atom/ns#">Change Set</category><category domain="http://www.blogger.com/atom/ns#">Deployment</category><category domain="http://www.blogger.com/atom/ns#">outbound</category><category domain="http://www.blogger.com/atom/ns#">requires</category><title>This change set requires the &quot;##.#&quot; or later platform version</title><description>&lt;h3&gt;
Overview&lt;br /&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;It&#39;s that time of the year again (one of three times, actually), where you might be attempting to make some fixes in a sandbox that has already been upgraded to the next release and uploading a Change Set from that org to Production where the next release hasn&#39;t been applied yet.&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h3&gt;
Error&lt;br /&gt;&lt;span style=&quot;font-size: small; font-weight: normal;&quot;&gt;This change set requires the &quot;##.#&quot; or later platform version&lt;/span&gt;&lt;/h3&gt;
&lt;h3&gt;
Scenario&lt;br /&gt;&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-size: small; font-weight: normal;&quot;&gt;Sandbox 1:  Summer &#39;15&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-size: small; font-weight: normal;&quot;&gt;Production:  Spring &#39;15&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/h3&gt;
&lt;h3&gt;
Resolution&lt;br /&gt;&lt;span style=&quot;font-size: small; font-weight: normal;&quot;&gt;By chance, did you get to this point by following a normal deployment pattern?  You know, where you deploy from a developer sandbox to a full sandbox and are now ready to deploy to Production?&amp;nbsp; &lt;/span&gt;&lt;/h3&gt;
&lt;h3&gt;
&lt;span style=&quot;font-size: small; font-weight: normal;&quot;&gt;Chances are, the full sandbox you deployed to was also upgraded to the next release.  You probably already know that upon upload, a Change Set&#39;s components are locked down.  But did you also know that the API version of that Change Set is set and locked based on the target org&#39;s API?&lt;/span&gt;&lt;/h3&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVqXyXgzHRl5QJuybmyc55g2z4QIEPKBPIYAwu8Hxxq7X1a2raKW4yP4g7ENCjgtTdfPKoRoaEKH3LLey8sJVZG0zbVgBk_5wvoSqjRWRplFApQEwo-m3QGxOI30XYqKkeQW4qSgH95lA/s1600/error.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVqXyXgzHRl5QJuybmyc55g2z4QIEPKBPIYAwu8Hxxq7X1a2raKW4yP4g7ENCjgtTdfPKoRoaEKH3LLey8sJVZG0zbVgBk_5wvoSqjRWRplFApQEwo-m3QGxOI30XYqKkeQW4qSgH95lA/s1600/error.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
This means that when you uploaded from your developer sandbox to the full sandbox, the Change Set was set to the latest API version and is now locked to it.  When you attempt to upload this same Change Set to production, you get the &quot;This change set requires...&quot; error message.&lt;br /&gt;
&lt;br /&gt;
Out of luck?  Nope!  Just &quot;Clone&quot; the Change Set and re-upload.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQSwfv4p5P_qIZtmVLHS4Tk3fEtpB1RV4hxJKC1dHISA2Py_oeruObVoUIdhyphenhyphen3beYYRlk9Zphu4YWrkwnBohjbHNcQP46eLU3x4W0-qY2u-ngs10_pZJW3SMIec7TlJCIl6NPsfuBbBbo/s1600/resolution.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQSwfv4p5P_qIZtmVLHS4Tk3fEtpB1RV4hxJKC1dHISA2Py_oeruObVoUIdhyphenhyphen3beYYRlk9Zphu4YWrkwnBohjbHNcQP46eLU3x4W0-qY2u-ngs10_pZJW3SMIec7TlJCIl6NPsfuBbBbo/s1600/resolution.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
When you create a new Change Set by cloning, you&#39;re creating a new instance of the Change Set with all the original components and is unlocked so new components can be added. &amp;nbsp;At this point, the API number has yet to be set as well.&lt;br /&gt;
&lt;br /&gt;
This time, don&#39;t upload to a sandbox first; upload it directly to Production so the Production org&#39;s API number is set on the Change Set and the upload is allowed.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBFoBS4HaU1hwhTSZP2vvSSvYXnUcPw_6sEmC47CqEOKTg0_30QpbFD5ygwy_bjFGPvA9wjO4IzTqeg6L7p9Uz6I2RkcGe_ovglDFt1rA04-f2WDUvWliCFPInrfH7toPjcto16L7ISuA/s1600/b531efc7-dd9e-4b32-9447-5fc2f924ce1d.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBFoBS4HaU1hwhTSZP2vvSSvYXnUcPw_6sEmC47CqEOKTg0_30QpbFD5ygwy_bjFGPvA9wjO4IzTqeg6L7p9Uz6I2RkcGe_ovglDFt1rA04-f2WDUvWliCFPInrfH7toPjcto16L7ISuA/s1600/b531efc7-dd9e-4b32-9447-5fc2f924ce1d.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;</description><link>http://blog.crmscience.com/2015/06/this-change-set-requires-or-later.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVqXyXgzHRl5QJuybmyc55g2z4QIEPKBPIYAwu8Hxxq7X1a2raKW4yP4g7ENCjgtTdfPKoRoaEKH3LLey8sJVZG0zbVgBk_5wvoSqjRWRplFApQEwo-m3QGxOI30XYqKkeQW4qSgH95lA/s72-c/error.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-4364172677191675291</guid><pubDate>Mon, 08 Jun 2015 15:23:00 +0000</pubDate><atom:updated>2015-06-10T10:10:33.337-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">button</category><category domain="http://www.blogger.com/atom/ns#">components</category><category domain="http://www.blogger.com/atom/ns#">Custom Permission</category><category domain="http://www.blogger.com/atom/ns#">Custom Permissions</category><category domain="http://www.blogger.com/atom/ns#">display</category><category domain="http://www.blogger.com/atom/ns#">dynamic</category><category domain="http://www.blogger.com/atom/ns#">elements</category><category domain="http://www.blogger.com/atom/ns#">UI</category><category domain="http://www.blogger.com/atom/ns#">Visualforce</category><title>User Level Visualforce UI Control w/ Custom Permissions</title><description>&lt;h3&gt;Overview&lt;/h3&gt;As you are developing a Visualforce interface for Salesforce.com users to interact with, you may find that certain form elements (panels, links/buttons, etc) may or should not apply to certain users. &amp;nbsp;Standard Salesforce user control can prevent users access to a specific page, objects, tabs, or other larger components without allowing much flexibility for the occasional granularity you need.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Sample Scenario&lt;/h3&gt;The objective below is to develop a page which offers four command buttons to perform four different actions (Purchase Media, Create Media, Borrow Media, and Rate Media) in a library environment. &amp;nbsp;In this library environment, there are three different groupings of users (listed in order of privilege); those will complete and full access, librarians, and borrowers. &amp;nbsp;Full access will be able to perform all actions, librarians can do all but purchase media, and borrows can only borrow and review media.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Approaches&lt;/h3&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;User Object Custom Fields:&lt;/b&gt; &amp;nbsp;You could create boolean toggles/checkboxes or minimally a multi-select picklist to allow org Admins to designate access on a per user level. &amp;nbsp;Downsides are that you&#39;re creating a field(s) and it leaves room for admin error (what was it... librarians can purchase or not?). &amp;nbsp;There&#39;s also the cost of querying for these fields via SOQL against the context&#39;s execution. &amp;nbsp;The fields could be included in a package, but would require post-installation configuration (maybe a post-install script to default all).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Custom Settings:&lt;/b&gt; &amp;nbsp;You could also create a Custom Setting of the hierarchy type, but still room for admin error. &amp;nbsp;On the pro-side, Custom Settings are cached and easily accessible via system methods, so it won&#39;t count against your SOQL queries. &amp;nbsp;Can also be included in a package and require the same post-install configuration or defaulting through a post-install script.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Custom Permissions:&lt;/b&gt; &amp;nbsp;Depending on your usage, these may or may not count against your SOQL limits. &amp;nbsp;Management is much easier as you can group individual permissions into a larger Permission Set and then apply the Permission Set(s) to a user. &amp;nbsp;Now all an Admin has to do is remember which Permission Set to apply to user(s). &amp;nbsp;Like the other two, can also be included in a package. &amp;nbsp;They also have the unique benefit in that they can be used to provide custom permissions to users authenticating in Connected App.&lt;/li&gt;
&lt;/ul&gt;&lt;h3&gt;Custom Permissions&amp;nbsp;&lt;/h3&gt;&lt;div&gt;Link: &amp;nbsp;&lt;a href=&quot;https://help.salesforce.com/apex/HTViewHelpDoc?id=custom_perms_overview.htm&amp;amp;language=en_US&quot; target=&quot;_blank&quot;&gt;Salesforce Documentation&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
We&#39;ll be checking out Custom Permission creation, assignment, and usage in the samples below. &amp;nbsp;To do so, we&#39;ll build a Visualforce page with four buttons, one for each possible permission, as well as show two page block sections that show which permissions the current user has. &amp;nbsp;One page block section will use the $Permission global variable to make that determination straight from Visualforce without a controller (see &quot;Global Variable Way&quot; below) and the other page block section will use Apex to determine applied permissions (see &quot;sObject/SOQL Way&quot;). &lt;br /&gt;
&lt;br /&gt;
Here&#39;s the end result:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjo-90iAJABNgYwWfAJOr_0Boykqa37FwJ46Ag8v0JaBzCktLpMPdUtQ0HpBFi_Ef6bUWiHfnn2Mr4pAdU34HzNX38YBMjqdTOZl1aNIMvbdk9Xw9B0Hrx7_K5IFz__dZa3xufpYuN-31Y/s1600/VFOverview.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;386&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjo-90iAJABNgYwWfAJOr_0Boykqa37FwJ46Ag8v0JaBzCktLpMPdUtQ0HpBFi_Ef6bUWiHfnn2Mr4pAdU34HzNX38YBMjqdTOZl1aNIMvbdk9Xw9B0Hrx7_K5IFz__dZa3xufpYuN-31Y/s640/VFOverview.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Before we get to the good stuff, let&#39;s see how to create the Custom Permissions and get them applied to a User first...&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Creating Custom Permissions&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;Navigate to Setup --&amp;gt; Build --&amp;gt; Develop --&amp;gt; Custom Permissions&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1CJnpVWbdMOaz7Q9KPO_FsoGDsgsTB57SV08JW7GraDQ7usRGLzkw1TmiypNvMqxtvS6UPdT_D9Csq80TbnStk-dGSFWRmXTuMkOCdx2sjJ2M0hlN1Hk2nRtVJ00u02LpF-iNufgjqn4/s1600/SetupCustomPermissions.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;150&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1CJnpVWbdMOaz7Q9KPO_FsoGDsgsTB57SV08JW7GraDQ7usRGLzkw1TmiypNvMqxtvS6UPdT_D9Csq80TbnStk-dGSFWRmXTuMkOCdx2sjJ2M0hlN1Hk2nRtVJ00u02LpF-iNufgjqn4/s200/SetupCustomPermissions.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Click on the &quot;New&quot; button and provide the various details about your Custom Setting. &amp;nbsp;The thing to remember here is it&#39;s up to you to determine what this &quot;permission&quot; stands for - at the end of the day, it&#39;s just a name that stands for a single or multiple privileges/abilities for a user to do thing. &amp;nbsp;In this example, anything within our Custom App involving the borrowing of books should refer to this setting.&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdYcjwcV-Pe4qYQ9OTQMCNOKUN_aRQvdN0bTdfY1gCG2zSuRHDRWJ7m_zeVcn2NXTJ8xBAFqKX0lEK5nTJm9JypBU-Lud_k9hOZWMWPKZwfVX3vPxqsxs8t3WoWw0DIddXn3NifS6OOrw/s1600/NewCustomPermission.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;106&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdYcjwcV-Pe4qYQ9OTQMCNOKUN_aRQvdN0bTdfY1gCG2zSuRHDRWJ7m_zeVcn2NXTJ8xBAFqKX0lEK5nTJm9JypBU-Lud_k9hOZWMWPKZwfVX3vPxqsxs8t3WoWw0DIddXn3NifS6OOrw/s320/NewCustomPermission.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;h3 style=&quot;clear: both;&quot;&gt;Assigning Custom Permissions to Permission Sets&lt;/h3&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Navigate to Setup --&amp;gt; Administer --&amp;gt; Manage Users --&amp;gt; Permission Sets&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8KBj97xLqmmeb3hRNw11BOAxAnIsFbAYA3byaUbv68QYgblVPp12yCHTEoWIgsGh1ki2evQXAdcy4ujzID5K-_rZlPitHpHWz1J713gRHI6daNQN1TQgRF7Z2Q8ntBWE-RmiMTRCH53Q/s1600/SetupPermSets.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;160&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8KBj97xLqmmeb3hRNw11BOAxAnIsFbAYA3byaUbv68QYgblVPp12yCHTEoWIgsGh1ki2evQXAdcy4ujzID5K-_rZlPitHpHWz1J713gRHI6daNQN1TQgRF7Z2Q8ntBWE-RmiMTRCH53Q/s200/SetupPermSets.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;Click on the &quot;New&quot; button, provide the required details about your permission set, and then click on the &quot;Save&quot; button.&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipMM5fpy-jsTg7Wm9taxe_y8Baj9UkWEwqsxFez-CPI-yFRrSqzkoL7Aj2NG20_-nuMbJf9zJXHp4Jk5thMRYFz4r1lHL17Yk5oSs7mRWFb_YuARFeeyDl2jEgdgDwgsB7zN4S5nlJXiA/s1600/CreatePermSet.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;282&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipMM5fpy-jsTg7Wm9taxe_y8Baj9UkWEwqsxFez-CPI-yFRrSqzkoL7Aj2NG20_-nuMbJf9zJXHp4Jk5thMRYFz4r1lHL17Yk5oSs7mRWFb_YuARFeeyDl2jEgdgDwgsB7zN4S5nlJXiA/s400/CreatePermSet.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;Within the &quot;Apps&quot; section, click on the &quot;Permission Sets&quot; link&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF_nPbpogapWXcMNbHnUN76CcVcMGdFOZO8YfKYxP6bAd3LsbOxU-iwQ17iDGVAa-asjf99nLCKjn7XJTkds8sdmbStJxhknXfalR3EenRapVlTMFvBJxOugkzkhPT9r7Y38Y2fYZU73k/s1600/PermSetCustomPermissions.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;310&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF_nPbpogapWXcMNbHnUN76CcVcMGdFOZO8YfKYxP6bAd3LsbOxU-iwQ17iDGVAa-asjf99nLCKjn7XJTkds8sdmbStJxhknXfalR3EenRapVlTMFvBJxOugkzkhPT9r7Y38Y2fYZU73k/s400/PermSetCustomPermissions.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;Select the appropriate permissions and then click on the &quot;Save&quot; button&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvfIUDbuyU8th6uaMvdFhClj9Bkf2Ln6EzpV3r5z_gSZO_2dEIz_w1b06YMozOpA4VMg2_kyV4sfaMKPaTlnw4vmRpZtu2QFUH1D9xBt6EmSEiTWfZq96yBhcR-2GvNOHn0ixM3zKCNpk/s1600/PermSetApplyCustomPerms.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;116&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvfIUDbuyU8th6uaMvdFhClj9Bkf2Ln6EzpV3r5z_gSZO_2dEIz_w1b06YMozOpA4VMg2_kyV4sfaMKPaTlnw4vmRpZtu2QFUH1D9xBt6EmSEiTWfZq96yBhcR-2GvNOHn0ixM3zKCNpk/s320/PermSetApplyCustomPerms.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;h3&gt;Assigning Permission Sets to Users&lt;/h3&gt;&lt;div&gt;&lt;ol&gt;&lt;li style=&quot;text-align: left;&quot;&gt;Navigate to Setup --&amp;gt; Administer --&amp;gt; Manage Users --&amp;gt; Users&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKsp5Kw3abvyEZj7duCQbe5KD18jge-KzRFQwagVz7FeX-yd-i50hEm87rpcryJi9izpP29U8zA1vwNWmDDeE2FJiNHCLMR1rxOHtp_ULYs1tdfGQzKnGbe9sofGY9gvoh4Gea6xKYEiY/s1600/Users.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKsp5Kw3abvyEZj7duCQbe5KD18jge-KzRFQwagVz7FeX-yd-i50hEm87rpcryJi9izpP29U8zA1vwNWmDDeE2FJiNHCLMR1rxOHtp_ULYs1tdfGQzKnGbe9sofGY9gvoh4Gea6xKYEiY/s1600/Users.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;Click on the name of a User&lt;/div&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwgtD9izvuSnXX9Eizq5f1VDYjlFcCe8GybEXTJRYny6ReRuDYvQpc0UF_2G8-OlycjqOzMYA2iKINjhodflU6Zac2p7S0PuQ7FMk1TY6toVCvOXjGRK67De9u5Z4DJ54_b2dJCsi0D2M/s1600/Users2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwgtD9izvuSnXX9Eizq5f1VDYjlFcCe8GybEXTJRYny6ReRuDYvQpc0UF_2G8-OlycjqOzMYA2iKINjhodflU6Zac2p7S0PuQ7FMk1TY6toVCvOXjGRK67De9u5Z4DJ54_b2dJCsi0D2M/s1600/Users2.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Within the User&#39;s Related Lists, hover over &quot;Permission Set Assignments&quot; and click on the &quot;Edit Assignments&quot; button&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8kv9Dqe7G9zebPhxKdGpKIk2mXOokgzvw60EKrnzSGPkBmDlVGkVwfD0ac7kASvv0N7xzIfI9WxFcAS_Flzd2rDiZI6Yrlfy1Fuc_WZUytxWC6u_8YEAq6HY9W05cm1GymaqyjQ5YKiI/s1600/EditAssignments.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;99&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8kv9Dqe7G9zebPhxKdGpKIk2mXOokgzvw60EKrnzSGPkBmDlVGkVwfD0ac7kASvv0N7xzIfI9WxFcAS_Flzd2rDiZI6Yrlfy1Fuc_WZUytxWC6u_8YEAq6HY9W05cm1GymaqyjQ5YKiI/s640/EditAssignments.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;To apply a Permission Set and its related Custom Permissions, move the Permission Set from the &quot;Available Permission Sets&quot; column to the &quot;Enabled Permissions Sets&quot; column.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs6gGt1NXzD-JcBu_6j_HNUP8n_XHZjCPhcKxd8A_mHdSNBzw-vciuRc3mvhNMcXDSXJYxroCEKUf_hcmZ74yHanwyvD1AT5hY4GfB-AyTld-ytb2tNJdoaiDBJQA7jwoaZt6C8sR8VHc/s1600/ApplyPermSet.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;146&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs6gGt1NXzD-JcBu_6j_HNUP8n_XHZjCPhcKxd8A_mHdSNBzw-vciuRc3mvhNMcXDSXJYxroCEKUf_hcmZ74yHanwyvD1AT5hY4GfB-AyTld-ytb2tNJdoaiDBJQA7jwoaZt6C8sR8VHc/s320/ApplyPermSet.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;&lt;h3&gt;&lt;br /&gt;
&lt;/h3&gt;&lt;h2&gt;Using Customer Permissions&lt;/h2&gt;&lt;div&gt;With the creation and assignment out of the way, let&#39;s look at how we can use them to control Visualforce UI elements based on their assignment. &amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjo-90iAJABNgYwWfAJOr_0Boykqa37FwJ46Ag8v0JaBzCktLpMPdUtQ0HpBFi_Ef6bUWiHfnn2Mr4pAdU34HzNX38YBMjqdTOZl1aNIMvbdk9Xw9B0Hrx7_K5IFz__dZa3xufpYuN-31Y/s1600/VFOverview.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;386&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjo-90iAJABNgYwWfAJOr_0Boykqa37FwJ46Ag8v0JaBzCktLpMPdUtQ0HpBFi_Ef6bUWiHfnn2Mr4pAdU34HzNX38YBMjqdTOZl1aNIMvbdk9Xw9B0Hrx7_K5IFz__dZa3xufpYuN-31Y/s640/VFOverview.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h3&gt;Global Variable Way&lt;/h3&gt;Directly from Visualforce, it&#39;s as easy as...&lt;br /&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
$Permission.&amp;lt;your_permission_name&amp;gt;
]]&gt;&lt;/script&gt;&lt;br /&gt;
Here&#39;s an example from the full VF page:&lt;br /&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
&lt;apex:pageBlockSectionItem &gt;
    &lt;!-- Quick label --&gt;
    &lt;apex:outputLabel value=&quot;Purchase Media&quot; /&gt;
    &lt;!-- Image of green/red circle, based on if $Permission.&lt;custompermission&gt; is applied or not. Images in StaticResource --&gt;
    &lt;apex:image value=&quot;{!IF($Permission.Purchase_Media, URLFOR($Resource.SampleImages, &#39;circle_green.png&#39;), URLFOR($Resource.SampleImages, &#39;circle_red.png&#39;))}&quot;/&gt;
&lt;/apex:pageBlockSectionItem&gt;
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;sObject/SOQL Way&lt;/h3&gt;We need to access several objects. &amp;nbsp;First we&#39;ll need to query for all CustomPermissions. &amp;nbsp;Then we&#39;ll query for SetupEntityAccess records that apply to the current user based on PermissionSetAssignments - see snippet below. &amp;nbsp;In the full sample, I&#39;ve set up a set&amp;lt;string&amp;gt; called LibraryPermissions that will contain the DeveloperNames of CustomPermissions applied to the current user. &amp;nbsp;I&#39;ll also create a method to return string.valueOf(LibraryPermissions) so the Visualforce page can just use CONTAINS(LibaryPermissionsStr, &#39;the permission I want to check&#39;).&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;Apex Snippet (full code at bottom)&lt;/h4&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

// &amp;nbsp;Determine the Custom Settings applied to the current user through Permission sets
for (SetupEntityAccess perm :[
        SELECT SetupEntityId
        FROM SetupEntityAccess
        // SetupEntityIds will be Ids of CustomPermission records previously queried
        WHERE SetupEntityId IN :PermissionsById.keySet()
        // ParentId will e Id of the PermissionSetId applied to the current user
            AND ParentId IN (
                SELECT PermissionSetId
                FROM PermissionSetAssignment
                WHERE AssigneeId = :UserInfo.getUserId()
            )
]) {
    if (PermissionsById.containsKey(perm.SetupEntityId)) {
        // LibraryPermissions only contain the names of CustomPermissions applied to the user
        LibraryPermissions.add(PermissionsById.get(perm.SetupEntityId)); &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 
    }
}

return LibraryPermissions;
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;h4&gt;VF Usage&lt;/h4&gt;&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
&lt;apex:pageBlockSectionItem &gt;
    &lt;apex:outputLabel value=&quot;Purchase Media&quot; /&gt;
    &lt;!-- getLibraryPermissionStr is a string of applied permissions as opposed to map[key] method. &amp;nbsp;Map may not have key, but string may have dupes or partials --&gt;
    &lt;apex:image value=&quot;{!IF(CONTAINS(LibraryPermissionsStr, &#39;Purchase_Media&#39;), URLFOR($Resource.SampleImages, &#39;circle_green.png&#39;), URLFOR($Resource.SampleImages, &#39;circle_red.png&#39;))}&quot;/&gt;
&lt;/apex:pageBlockSectionItem&gt;
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Practical Usage&lt;/h3&gt;Showing the permissions is one thing, but using Custom Permissions in a practical way that helps you control UI elements is another. &amp;nbsp;Using either technique, we can show/hide buttons that apply to that user according to the Permission Sets applied.&lt;br /&gt;
&lt;br /&gt;
Here&#39;s a quick snippet of &amp;nbsp;rendering commandButtons accordingly:&lt;br /&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
&lt;apex:pageBlockButtons &gt;
    &lt;apex:commandButton value=&quot;Purchase Media&quot; action=&quot;{!DummyMethod}&quot; rendered=&quot;{!$Permission.Purchase_Media}&quot; /&gt;
    &lt;apex:commandButton value=&quot;Create Media&quot; action=&quot;{!DummyMethod}&quot; rendered=&quot;{!$Permission.Create_Media}&quot; /&gt;
    &lt;apex:commandButton value=&quot;Borrow Media&quot; action=&quot;{!DummyMethod}&quot; rendered=&quot;{!$Permission.Borrow_Media}&quot; /&gt;
    &lt;apex:commandButton value=&quot;Review Media&quot; action=&quot;{!DummyMethod}&quot; rendered=&quot;{!$Permission.Review_Media}&quot; /&gt;
&lt;/apex:pageBlockButtons&gt;
]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;clear: both; text-align: left;&quot;&gt;Recap&lt;/h3&gt;&lt;div&gt;So there we go! &amp;nbsp;We&#39;ve effectively modified a UI by leveraging the semi-new Custom Permissions and demonstrated how they can be created, applied to a User through the use of Permissions Sets. &amp;nbsp;While showing/hiding buttons isn&#39;t too glorious of an example, we&#39;d love to hear how you use them in the comments or on Twitter&amp;nbsp;&lt;a href=&quot;http://www.twitter.com/crmscience&quot; target=&quot;_blank&quot;&gt;@crmscience&lt;/a&gt;!&lt;/div&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:card&quot; content=&quot;summary_large_image&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:site&quot; content=&quot;@crmscience&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:creator&quot; content=&quot;@kirkevonphilly&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:title&quot; content=&quot;User Level Visualforce UI Control w/ Custom Permissions&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:description&quot; content=&quot;As you are developing a Visualforce interface for Salesforce.com users to interact with, you may find that certain form elements (panels, links/buttons, etc) may or should not apply to certain users. Standard Salesforce user control can prevent users access to a specific page, objects, tabs, or other larger components without allowing much flexibility for the occasional granularity you need.&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:image&quot; content=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjo-90iAJABNgYwWfAJOr_0Boykqa37FwJ46Ag8v0JaBzCktLpMPdUtQ0HpBFi_Ef6bUWiHfnn2Mr4pAdU34HzNX38YBMjqdTOZl1aNIMvbdk9Xw9B0Hrx7_K5IFz__dZa3xufpYuN-31Y/s640/VFOverview.png&quot;&gt;</description><link>http://blog.crmscience.com/2015/06/user-level-visualforce-ui-control-w.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjo-90iAJABNgYwWfAJOr_0Boykqa37FwJ46Ag8v0JaBzCktLpMPdUtQ0HpBFi_Ef6bUWiHfnn2Mr4pAdU34HzNX38YBMjqdTOZl1aNIMvbdk9Xw9B0Hrx7_K5IFz__dZa3xufpYuN-31Y/s72-c/VFOverview.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-8367273713549539478</guid><pubDate>Sun, 26 Apr 2015 03:46:00 +0000</pubDate><atom:updated>2015-04-25T23:46:31.000-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">AppExchange</category><category domain="http://www.blogger.com/atom/ns#">architecture</category><category domain="http://www.blogger.com/atom/ns#">Design</category><category domain="http://www.blogger.com/atom/ns#">design pattern</category><category domain="http://www.blogger.com/atom/ns#">developer tools</category><category domain="http://www.blogger.com/atom/ns#">tools</category><category domain="http://www.blogger.com/atom/ns#">utility</category><title>Generically Calling External Classes from Managed Packages</title><description>Let’s say that you’re building a managed package but one of the target orgs for the package needs some custom logic to execute in the middle of your package logic or perhaps fork into completely different path that is not common to the rest of the orgs that install your package. Let’s say that you have two or three of these “special” orgs that are a minority of the package installs but important enough to handle. Here’s one way to handle such craziness...
&lt;br /&gt;
&lt;br /&gt;
The goal of this exercise is to be able to have the target org tell your package that there is some custom code that needs to be executed. We need a way to do this dynamically, and have it controlled by the target org. That feat can be achieve with a custom setting, an interface class, and dynamic class instantiation.
&lt;br /&gt;
&lt;br /&gt;
First, you’ll need to create a non-protected custom setting in your managed package. The custom setting is pretty simple, and contains the following text fields:
&lt;ul&gt;
&lt;li&gt;Name - the standard Name field is used to get the values if a specific forking may be needed at specific times.&lt;/li&gt;
&lt;li&gt;ClassName__c - used to hold the name of the external class that needs to be called.&lt;/li&gt;
&lt;li&gt;Namespace__c - used to hold a namespace in case the external class is located in a different extension package.&lt;/li&gt;
&lt;/ul&gt;

&lt;br /&gt;
Now that we have a way for the target org administrator to alert the package code that an external class needs to be called, we need to handle that in the package code itself. We’ll first Create Interface class and a method that is so generic, that it can be used with any number of parameters and can get a response that includes any response type. We do that by setting the return variable and the class parameter to the object data type, which can be casted to any type of other data type. That will allow different implementations to use this class in completely different ways.
&lt;br /&gt;
&lt;script class=&quot;brush: java&quot; type=&quot;syntaxhighlighter&quot;&gt;
&lt;![CDATA[
global with sharing class BasePackage {
 
    // define an interface with method blueprints
    global interface Extension {
         
        // define a generic class with generic params so
        // the class that implements the interface can
        // do whatever it wants
        object GenericMethod(object params);
     
    }
}
]]&gt;
&lt;/script&gt;

Now that the interface class is ready, it can be used in strategic locations around the code to call external classes as needed. If you need some added flexibility and have no fear, you can also blindly execute anything you can find in the custom setting. That can be done by instantiating an instance of the external class by dynamically instantiating the interface class, which provides a concrete type that can be instantiated. Note that you’ll need to make sure that you use the namespace in the forName method if you are pointing to a class in an external package. 
&lt;br /&gt;
&lt;script class=&quot;brush: java&quot; type=&quot;syntaxhighlighter&quot;&gt;
&lt;![CDATA[
// get the external class name from a custom setting
PackageExtension__c ext = PackageExtension__c.getInstance(&#39;extensionName&#39;);
 
if (ext == null) {
    // process normal business logic or just do nothing
     
} else {
    // define a type variable
    Type t;

    // get the type of the class outside the package that
    // implements the generic interface (make sure correct class 
    if  (ext.Namespace__c == null)
        t = Type.forName(ext.ClassName__c);
    else
        t = Type.forName(ext.Namespace__c, ext.ClassName__c);

    // using a concrete type of the interface, create a new
    // instance of the extension implementation
    BasePackage.Extension ExtensionClass = (BasePackage.Extension)t.newInstance();
     
    // use the extension class variable that was created to
    // call the generic method with any relevant variable
    object retList = ExtensionClass.GenericMethod(variablesCastedAsObject);                          
}
]]&gt;
&lt;/script&gt;

The code is now done and a new release of the managed package can be created. The only thing left to do is to use the new code from outside the package. You do that by creating a class in the target org or an extension package that implements the base package interface. Parameters that are sent into this class go by the normal apex rules, so maps and lists that are passed can be manipulated in the external class (passed by reference). Since the interface blueprint is flexible, the implementation can be static in case a callout needs to happen (needs to be static in some cases because a trigger starts the execution).
&lt;br /&gt;
&lt;script class=&quot;brush: java&quot; type=&quot;syntaxhighlighter&quot;&gt;
&lt;![CDATA[
public with sharing class MyExtension implements BasePackageNameSpace.BasePackage.Extension {
 
    // define a the generic class that is present
    // in the interface
    public static object GenericMethod(object params) {
 
            // cast input params into the expected type
            set&lt;id&gt; RecordIds = (set&lt;id&gt;)params;
      
            // use the concrete type variables to call the class
            // that does all the work
            ProcessFutureCallout(RecordIds);
         
            // return null or some other value as an object
            return null;
        }
    }
}
]]&gt;
&lt;/script&gt;</description><link>http://blog.crmscience.com/2015/04/generically-calling-external-classes.html</link><author>noreply@blogger.com (Unknown)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-3494355396253823904</guid><pubDate>Thu, 02 Apr 2015 12:52:00 +0000</pubDate><atom:updated>2015-04-25T21:12:48.553-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">Attachment</category><category domain="http://www.blogger.com/atom/ns#">Bootstrap</category><category domain="http://www.blogger.com/atom/ns#">BootstrapSF1</category><category domain="http://www.blogger.com/atom/ns#">IFrame</category><category domain="http://www.blogger.com/atom/ns#">InputFile</category><category domain="http://www.blogger.com/atom/ns#">Javascript</category><category domain="http://www.blogger.com/atom/ns#">jquery</category><category domain="http://www.blogger.com/atom/ns#">Mobile</category><category domain="http://www.blogger.com/atom/ns#">Modal</category><category domain="http://www.blogger.com/atom/ns#">Responsive</category><category domain="http://www.blogger.com/atom/ns#">salesforce1</category><category domain="http://www.blogger.com/atom/ns#">Styling</category><category domain="http://www.blogger.com/atom/ns#">Touch</category><category domain="http://www.blogger.com/atom/ns#">Visualforce</category><title>Salesforce1 Mobile - Fun with IFrames &amp; Matching the Styling</title><description>&lt;div style=&quot;padding: 0px 35px 0px 0px;&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://4.bp.blogspot.com/-qbb2zeq3TKQ/VRwXQBHHj7I/AAAAAAAAACs/lgbzGJGRXMU/s1600/salesforce1.gif&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-qbb2zeq3TKQ/VRwXQBHHj7I/AAAAAAAAACs/lgbzGJGRXMU/s1600/salesforce1.gif&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
When you start developing for mobile, you tend to find reasons for harnessing the device features that they come with (camera, location services). &amp;nbsp;If you&#39;ve ever had the need to snap a photo from Salesforce1 and attach it to a record(in a custom VisualForce page of course), you may have come across the wonderful tag &lt;a href=&quot;https://www.salesforce.com/us/developer/docs/pages/Content/pages_compref_inputFile.htm&quot; target=&quot;_blank&quot;&gt;&amp;lt;apex:InputFile /&amp;gt;&lt;/a&gt;. &amp;nbsp;It&#39;s a definite time-saver versus having to handle the complexities of file formats, sizes, viewstate, governor limits etc.&lt;br /&gt;
&lt;br /&gt;
My guess is that you&#39;ve also ran into issues when trying to rerender a part of this visualforce page, or perform an &quot;oncomplete&quot; action. &amp;nbsp;You would get this error if so:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;h3&gt;
&lt;i&gt;apex:inputFile can not be used in conjunction with an action component, apex:commandButton or apex:commandLink that specifies a rerender or oncomplete attribute&lt;/i&gt;&lt;/h3&gt;
&lt;/blockquote&gt;
&lt;br /&gt;
This means that any other part of the page that attempts one of these actions will not be able to do so, simply because the page contains an InputFile tag elsewhere. &amp;nbsp;I quickly found this solution (using an ActionRegion tag to wrap other parts of the page) that worked initially but as my page grew, the InputFile component broke. The component stopped firing the setter for my Attachment property. &amp;nbsp;The more I worked with trial and error, I decided to cut my losses and encapsulate it within an iframe so that &lt;u&gt;I could code with freedom on the main page.&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;It figures that I would find other solutions AFTER taking my plunge into this solution, but it was fun, and I can use this in other ways :)! &amp;nbsp;Here are other options to using Apex:InputFile tags in more complex situations:&amp;nbsp;&lt;a href=&quot;https://developer.salesforce.com/forums/ForumsMain?id=906F0000000Acd6IAC&quot;&gt;https://developer.salesforce.com/forums/ForumsMain?id=906F0000000Acd6IAC&lt;/a&gt;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
&lt;b&gt;A solution to divide the pages:&lt;/b&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Attachment page: Create a page that takes an ID as a url parameter for the ParentId, to be used to insert the attachment. In this page you have the InputFile tag which handles the file.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Parent page: Show the attachment page in an IFrame. Use javascript functions that can be fired between the child and the parent windows for a seamless user experience however you see fit. (same domain).&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://3.bp.blogspot.com/-Q4yhrW5k8H0/VRwK2iZFElI/AAAAAAAAACc/99bEYA01Ikw/s1600/mkdemos-developer-edition.na17.force.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-Q4yhrW5k8H0/VRwK2iZFElI/AAAAAAAAACc/99bEYA01Ikw/s1600/mkdemos-developer-edition.na17.force.png&quot; height=&quot;353&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
&lt;strong&gt;Link:&amp;nbsp;&lt;a href=&quot;http://mkdemos-developer-edition.na17.force.com/apex/AccountDetail?id=001o000000Sp1vS&quot; target=&quot;_blank&quot;&gt;Demo&lt;/a&gt;&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;This works in all browsers.&lt;/li&gt;
&lt;li&gt;The demo site was built for Salesforce1 and is a great example of using &lt;a href=&quot;http://developer.salesforcefoundation.org/bootstrap-sf1/index.html&quot; target=&quot;_blank&quot;&gt;Bootstrap SF1 Theme&lt;/a&gt;&amp;nbsp;along with the standard &lt;a href=&quot;http://bootstrapdocs.com/v3.0.1/docs/javascript/#js-overview&quot; target=&quot;_blank&quot;&gt;Bootstrap Javsascript library&lt;/a&gt; (matching the version to 3.0.1).&lt;/li&gt;
&lt;li&gt;The demo is responsive and works in the Salesforce1 app on mobile devices, desktop, and Salesforce1 through the browser.&lt;/li&gt;
&lt;li&gt;Other improvements would be&lt;/li&gt;
&lt;ol&gt;
&lt;li&gt;Implement swipe for the Details and Attachments tabs, and convert to &quot;tap&quot; instead of &quot;onclick&quot; events.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Best Practice: Use JS remoting and remove the view state for better mobile performance. &amp;nbsp;Implementing remoting on the parent page could be done with this iframe solution being handy.&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;h3&gt;
&lt;/h3&gt;
&lt;h3&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h2&gt;
&lt;b&gt;Link:&amp;nbsp;&lt;a href=&quot;https://github.com/Katulka/SalesforceIframeInputFile&quot; target=&quot;_blank&quot;&gt;GitHub&lt;/a&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;
&lt;br /&gt;
&lt;h3&gt;
&lt;strong&gt;Keys to the solution:&lt;/strong&gt;&lt;/h3&gt;
&lt;br /&gt;
&lt;i&gt;&lt;br /&gt;&lt;/i&gt;
&lt;i&gt;&lt;b&gt;AccountDetail page&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;ul class=&quot;task-list&quot;&gt;
&lt;li&gt;Contains an IFrame with id = &quot;attachmentIFrame&quot;&lt;/li&gt;
&lt;li&gt;Contains the submit button as part of the modal. It fires a javascript function from within the iframe to insert the attachment.&lt;/li&gt;
&lt;li&gt;Contains a close button which is unlimited and able to call an actionFunction which does contain an oncomplete rule (which navigates the user to the attachments tab list).&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
&lt;div class=&quot;modal-body&quot;&gt;
                        

 &lt;!-- IFRAME --&gt;
 &lt;iframe id=&quot;attachmentIFrame&quot; frameborder=&quot;0&quot; height=&quot;280px&quot; width=&quot;270&quot; 
 src=&quot;/apex/AttachmentUpload?ParentId={!Account.id}&quot;&gt;&lt;/iframe&gt;

&lt;/div&gt;
&lt;div class=&quot;modal-footer&quot;&gt;

 &lt;!-- SUBMIT/INSERT ATTACHMENT --&gt;
 &lt;button type=&quot;button&quot; class=&quot;btn btn-primary&quot; 
 onclick=&quot;document.getElementById(&#39;attachmentIFrame&#39;).contentWindow.processAttachment();&quot;&gt;
 Submit
 &lt;/button&gt;
 
 &lt;!-- CLOSE --&gt;
 &lt;button type=&quot;button&quot; class=&quot;btn btn-default&quot; data-dismiss=&quot;modal&quot; 
 onclick=&quot;refreshAttachments();&quot;&gt;Close&lt;/button&gt;

&lt;/div&gt;
]]&gt;&lt;/script&gt;

&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;i&gt;&lt;b&gt;AttachmentUpload page&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;ul class=&quot;task-list&quot;&gt;
&lt;li&gt;Contains the Apex:InputFile tag, and has an accessible javascript/actionFunction called &quot;processAttachment&quot;. This is the function that the parent page will call.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
&lt;!-- INPUTFILE TAG --&gt;
&lt;apex:inputfile id=&quot;attFile&quot; value=&quot;{!a.body}&quot; filename=&quot;{!a.name}&quot; /&gt;         
...
&lt;apex:actionFunction name=&quot;processAttachment&quot; action=&quot;{!ProcessAttachment}&quot; /&gt;
]]&gt;&lt;/script&gt;

&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;b&gt;AttachmentUpload class&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;ul class=&quot;task-list&quot;&gt;
&lt;li&gt;Contains page accessible method &quot;ProcessAttachment&quot; which will take the attachment property and perform the DML insert.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
// insert the attachment
public void ProcessAttachment(){
 system.debug(&#39;***ProcessAttachment&#39;);

 if (a.bodyLength &lt; 1 || a.name == null)
  ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,&#39;Please choose a file for upload.&#39;));
 else {

  // if the user provided an optional filename
  if(fname != null &amp;&amp; fname != &#39;&#39;){
   
   //get the file extension if one exists
   List&lt;String&gt; parts = (a.name).split(&#39;\\.&#39;);
   
   // a.name should contain just a file extension
   a.name = parts[parts.size()-1];
   
   // make sure we append the real filename so it includes proper extension
   a.name = fname + &#39;.&#39; + a.name;
  }

  a.ownerId = UserInfo.getUserId();
  a.parentid = getParentId();

  try {       
      insert a;
      ApexPages.addMessage(new ApexPages.message(ApexPages.severity.INFO,&#39;Attachment uploaded successfully. Click &quot;Choose File&quot; to upload another attachment, or &quot;Close&quot; if you are finished.&#39;));
  } catch(Exception e) {
      ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,&#39;Error uploading attachment.&#39;));
  } finally {
      // CLEAR FOR ANOTHER UPLOAD
      a = null;
      fname = null;
  }
 }
}

&lt;/script&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Salesforce1 &amp;amp; other Goodies:&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Salesforce1 navigation vs desktop navigation are different, see this JS function than helps to handle this (used here when clicking on a link to the attachment).&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

// function that handles navigation requests so this can run on SF1 or SF.com
function redirectToURL(theURL){
    if( (typeof sforce != &#39;undefined&#39;) &amp;&amp; (sforce.one != null) ) {
        // Navigate to the sf1 url
        sforce.one.navigateToURL(theURL);
    } else {
        //navigate to standard page
        window.location.assign(theURL);
    }
}

&lt;/script&gt;


&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;When the user clicks the Close button after they uploaded the attachment(s), we are able to show the Bootstrap tab very easily.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[

function showNavTab(tabName){
 $(&#39;#navTabs a[href=&quot;#&#39; + tabName + &#39;&quot;]&#39;).tab(&#39;show&#39;);
}

&lt;/script&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
By separating the inputFile tag, you can use rerender or oncomplete attributes on the parentpage again, without the need for actionRegion tags or multiple Form tags.&lt;br /&gt;
&lt;br /&gt;
Styling is done with the BootstrapSF1 package and the Bootstrap Javascript library to match. This will work in Salesforce1.

&lt;/div&gt;
</description><link>http://blog.crmscience.com/2015/04/salesforce1-mobile-fun-with-iframes.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-qbb2zeq3TKQ/VRwXQBHHj7I/AAAAAAAAACs/lgbzGJGRXMU/s72-c/salesforce1.gif" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-4190920446036294786</guid><pubDate>Fri, 16 Jan 2015 14:13:00 +0000</pubDate><atom:updated>2015-06-27T14:13:25.567-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">add-ons</category><category domain="http://www.blogger.com/atom/ns#">addons</category><category domain="http://www.blogger.com/atom/ns#">chrome</category><category domain="http://www.blogger.com/atom/ns#">credential</category><category domain="http://www.blogger.com/atom/ns#">extensions</category><category domain="http://www.blogger.com/atom/ns#">firefox</category><category domain="http://www.blogger.com/atom/ns#">internet explorer</category><category domain="http://www.blogger.com/atom/ns#">keepass</category><category domain="http://www.blogger.com/atom/ns#">manager</category><category domain="http://www.blogger.com/atom/ns#">password</category><category domain="http://www.blogger.com/atom/ns#">salesforce</category><category domain="http://www.blogger.com/atom/ns#">token</category><category domain="http://www.blogger.com/atom/ns#">tools</category><category domain="http://www.blogger.com/atom/ns#">username</category><category domain="http://www.blogger.com/atom/ns#">utility</category><title>Managing SFDC Credentials Using KeePass</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoYnsFArJxUns_9NqfU8HbYE2bBHk4kdHONg1j_ZBpk1-esU-q4WXfKhtJrfPrIHauqoYD9Sz-scig_xP78-Urvc6M8xdOAK-h40o5lNGbhDFnxqRpWU-tqZQ2ZsHAu3-f8jZ43yupRtM/s1600/KeePass.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoYnsFArJxUns_9NqfU8HbYE2bBHk4kdHONg1j_ZBpk1-esU-q4WXfKhtJrfPrIHauqoYD9Sz-scig_xP78-Urvc6M8xdOAK-h40o5lNGbhDFnxqRpWU-tqZQ2ZsHAu3-f8jZ43yupRtM/s1600/KeePass.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Fun Fact: &amp;nbsp;The longer you work with the Force.com Platform the more sets of credentials you are going to have to maintain.&lt;br /&gt;
&lt;br /&gt;
I should invest in a tally click counter to keep track of the number of times I log into various (and often the same) Salesforce orgs throughout the day. &amp;nbsp;At a certain point, to maintain your sanity, you need some sort of assistance to keep track of all your Salesforce org details.&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Username&lt;/li&gt;
&lt;li&gt;Password&lt;/li&gt;
&lt;li&gt;Token&lt;/li&gt;
&lt;li&gt;URL - login, test, etc&lt;/li&gt;
&lt;li&gt;Org Type - Group, Professional, etc&lt;/li&gt;
&lt;li&gt;Notes about the org&#39;s purpose - Dev Org for XYZ Project&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;Now, I&#39;ve used the &lt;a href=&quot;https://chrome.google.com/webstore/detail/forcecom-logins/ldjbglicecgnpkpdhpbogkednmmbebec?hl=en&quot; target=&quot;_blank&quot;&gt;Force.com Logins Chrome extension&lt;/a&gt; for the last few years to help keep track of a few of those items as well as to help pop-open a new session in a new window, tab, or &lt;a href=&quot;https://support.google.com/chrome/answer/95464?hl=en&quot; target=&quot;_blank&quot;&gt;Incognito session&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/forcecom-logins/ldjbglicecgnpkpdhpbogkednmmbebec?hl=en&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;75&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9uCPzFo3vR2TBqJjP-8xx1XGPxQgxx1V8oCBgTdDinf6MKFAzSaMAConpS8G79BpUo3TrukWpgOJhuwoGVhuD9rrtHyrdKf2a9SHN24XeV2F7PSn6tGFys14JC8d7cHSBYxxqChossto/s1600/ForceComLogins.PNG&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;While it&#39;s easy to search, it seemed to be growing unmanageable recently; the list was growing longer and I had a lot of old/stale entries. &amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;There were also a few long standing drawbacks:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Credentials are stored via Chrome&#39;s local storage as opposed to sync storage, meaning the credential data, an XML structure, stayed on one computer and wasn&#39;t replicated across all of my devices where Google&#39;s sync normally applies. &amp;nbsp;By day, I&#39;m often on one computer, which frequently requires updates to these credentials. &amp;nbsp;By night, I&#39;m on another computer and let&#39;s face it... getting up off the couch after a long day to retrieve your token from another computer&#39;s not going to happen. &amp;nbsp;Entire data dupe nightmare.&lt;/li&gt;
&lt;li&gt;Force.com Logins is a Chrome extension, so while I can open Chrome tabs, windows, and Incognito tabs just fine, sometimes you want or need a Firefox or Internet Explorer window. &amp;nbsp;There&#39;s a Firefox version (don&#39;t know if it is associated with Appirio or not), but I had trouble exporting my Chrome extension credentials and importing them into the Firefox verison.&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;So, what to do? &amp;nbsp;There&#39;s all kinds of password managers out there. &amp;nbsp;&lt;a href=&quot;https://lastpass.com/&quot; target=&quot;_blank&quot;&gt;LastPass&lt;/a&gt; and &lt;a href=&quot;https://agilebits.com/&quot; target=&quot;_blank&quot;&gt;1Password&lt;/a&gt; are two great examples. &amp;nbsp;Check out &lt;a href=&quot;http://lifehacker.com/5529133/five-best-password-managers&quot; target=&quot;_blank&quot;&gt;LifeHacker&#39;s Top Five Best Password Managers&lt;/a&gt; list to get a better feel for what they to.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;In a previous life, before the cloud was &quot;the cloud,&quot; I managed various systems credentials via an application called &lt;a href=&quot;http://keepass.info/&quot; target=&quot;_blank&quot;&gt;KeePass&lt;/a&gt;. &amp;nbsp;KeePass is a free, open-source program that allows you to create, organize, and store your various credentials in a local database, a .kdbx file. &amp;nbsp;You can keep this encrypted database on your hard drive or flash drive and use it to store endless hierarchies of credentials for all of your commonly visited websites, including Salesforce. &amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;I can quickly overcome both of those drawback bullet points above with KeePass:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;While the .kdbx file the stores all of your passwords is saved to your computer, there&#39;s nothing preventing you from storing the file in a Dropbox folder. &amp;nbsp;Sync that folder across your devices and never be left without your credentials again.&lt;/li&gt;
&lt;li&gt;Being open-source, there&#39;s various Chrome Extensions, Firefox add-on, and Internet Explorer... I don&#39;t even know what you call them... thingamabobs... that connect your browser to the KeePass program running in your system tray. &amp;nbsp;This can provide a list of credentials for the website you&#39;re currently visiting or an auto-population of creds, if you want. &amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;There&#39;s some additional perks too:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;I don&#39;t have to rely on those extensions, add-ons, and thingamabobs. &amp;nbsp;I can customize KeePass to have custom buttons to open a browser of my choice, in the standard mode or Incognito/Private mode, and automatically log into Salesforce for me - replicating the functionality of the Force.com Logins Chrome Extension, but allowing me to use the browser of my choice.&lt;/li&gt;
&lt;li&gt;There are global keyboard shortcuts (CTRL+ALT+K) that allow me quickly find my credentials and get logged in, without taking my hands off the keyboard.&lt;/li&gt;
&lt;li&gt;There&#39;s an &quot;AutoType&quot; feature that allows me to assign a shortcut key to the selected credential entry that will take fields from my credential (username, password, url, custom - oh, did I mention the ability to create custom fields for additional data points...like your token?) and automatically type that string into another window for you. &amp;nbsp;Admins and Developers - how many times do you have to type in your password, go look up what your latest security token is and then copy/paste it after your password for new Data Loader sessions or IDE projects? &amp;nbsp;Imaging highlighting your credential, pressing a set of keys and letting the program do the work for you.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Ok great. &amp;nbsp;It does a lot, solves my problems, but is it going to help you? &amp;nbsp;Maybe, give it a shot. &amp;nbsp;This approach of auto-logging you into a Salesforce org is no more secure than the Force.com Logins extension and it is very possible your credentials could be seen within your browser history or URL bar upon login. &amp;nbsp;Check out the review of the&amp;nbsp;&lt;a href=&quot;https://chrome.google.com/webstore/detail/forcecom-logins/ldjbglicecgnpkpdhpbogkednmmbebec?hl=en&quot; target=&quot;_blank&quot;&gt;Force.com Logins&lt;/a&gt;&amp;nbsp;extension for plenty of feedback about that.&lt;br /&gt;
&lt;br /&gt;
The rest of this blog post will be to demonstrate how to:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;1) &amp;nbsp;Set up a new KeePass Database&lt;/div&gt;&lt;div&gt;2) &amp;nbsp;Add a &amp;nbsp;Group&lt;br /&gt;
3) &amp;nbsp;Add an Entry&lt;br /&gt;
4) &amp;nbsp;Include a custom Token field&lt;br /&gt;
5) &amp;nbsp;Set up KeePass Trigger Buttons&lt;br /&gt;
6) &amp;nbsp;Create/Assign KeePass Trigger Actions to open creds in the browser and mode of your choice.&lt;/div&gt;&lt;div&gt;&lt;h2&gt;Set Up a New KeePass Database&lt;/h2&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;1) &amp;nbsp;The first thing you&#39;ll want to do is install the program from &lt;a href=&quot;http://keepass.info/&quot; target=&quot;_blank&quot;&gt;KeePass&lt;/a&gt; and open it up.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;2) &amp;nbsp;Click on File --&amp;gt; New... to create a new database. &amp;nbsp;Give it a name and save it in a location of your choice. &amp;nbsp;This is where I save my file to my synced Dropbox folder. &amp;nbsp;Once you save it, you always have the ability to rename and move the file.&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3cCPAAVYfEUzn1imY6iNEn4s1NSnrcOjmKcho4hqyorevpjgcXmCsudcH0nzDO-jVWiubvi6MEdhFj9oO_FT2Ms5vvd6T4ztnCxnP3uZ8aGtiivpG7bedW9cSPPvQwKjOHyVh8tNrzEA/s1600/00_Setup_01.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3cCPAAVYfEUzn1imY6iNEn4s1NSnrcOjmKcho4hqyorevpjgcXmCsudcH0nzDO-jVWiubvi6MEdhFj9oO_FT2Ms5vvd6T4ztnCxnP3uZ8aGtiivpG7bedW9cSPPvQwKjOHyVh8tNrzEA/s1600/00_Setup_01.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;3) &amp;nbsp;Next, you&#39;ll create a master key. &amp;nbsp;Pick a strong phrase that you won&#39;t forget. &amp;nbsp;At this point, you can also create an additional key file to store separately (maybe on a USB), that you&#39;ll need to provide in addition to you database and master key for some extra security.&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhczZQoYZc0VhBXW5h3QEcU2RC4jTJ5l56wyi7unj5qLv8ITbJ3rE8ReCECeRogd0vufS2VonccPCRrU3L0m7a3T10rGwgAs09Ozmm118Knw4ip2UxxO8yP5sedXVitzyKXQ1fjJ7lAzrg/s1600/00_Setup_02.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhczZQoYZc0VhBXW5h3QEcU2RC4jTJ5l56wyi7unj5qLv8ITbJ3rE8ReCECeRogd0vufS2VonccPCRrU3L0m7a3T10rGwgAs09Ozmm118Knw4ip2UxxO8yP5sedXVitzyKXQ1fjJ7lAzrg/s1600/00_Setup_02.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&amp;nbsp;4) &amp;nbsp;Within the Database Settings screen, you can provide a name and description for your credential database. &amp;nbsp;Check out the other tabs for more security and a few other storage related settings.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRRQFpW21j5dZA9RyVmeSfJIqWUIZhFh5eInztc3OjYr-BxmDdlVGr3A1PypUJMFQz6XENdfIKqMqdaBheORCBujzVZ-RQDdA_TasdlfNqDISp45i3ESGz_i8-bjoHGz1M34yq5I2H-cM/s1600/00_Setup_03.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRRQFpW21j5dZA9RyVmeSfJIqWUIZhFh5eInztc3OjYr-BxmDdlVGr3A1PypUJMFQz6XENdfIKqMqdaBheORCBujzVZ-RQDdA_TasdlfNqDISp45i3ESGz_i8-bjoHGz1M34yq5I2H-cM/s1600/00_Setup_03.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;h2 style=&quot;clear: both; text-align: left;&quot;&gt;Add a Group&lt;/h2&gt;1) &amp;nbsp;Now that you&#39;re database is created, you can start structuring your credential folders to stay organize. &amp;nbsp;You can create a top-level &quot;Salesforce&quot; folder and then create sub-folders for clients, projects, etc. &amp;nbsp;Do this by going to Edit --&amp;gt; Add Group.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-XpBz2xYwXaKeFPI-uig6Ak6UpxuBO7dA4WfSX7iNYBf6u-pBgdpMD0I6GQ8Zzm4XvbdNphhXcevgiUGksbAm9aKK3fWdEPk0F4PNHU23V4AFEp9TxLUlT5in4VXpc9oHftPjZzaEMhQ/s1600/00_Setup_04.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-XpBz2xYwXaKeFPI-uig6Ak6UpxuBO7dA4WfSX7iNYBf6u-pBgdpMD0I6GQ8Zzm4XvbdNphhXcevgiUGksbAm9aKK3fWdEPk0F4PNHU23V4AFEp9TxLUlT5in4VXpc9oHftPjZzaEMhQ/s1600/00_Setup_04.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;h2 style=&quot;clear: both; text-align: left;&quot;&gt;Add an Entry&lt;/h2&gt;1) &amp;nbsp;Now you can start populating your entries. &amp;nbsp;Click on Edit --&amp;gt; Add Entry... and provide details about your credentials. &amp;nbsp;Here I provide a quick Title (label) for the cred, usually something along the lines of &quot;Testing: &amp;nbsp;Feature X&quot; or &quot;Development Org: &amp;nbsp;Feature X.&quot; &amp;nbsp;To take advantage of the browser abilities we&#39;ll be using later, be sure to provide either the login or test.salesforce.com URL in the appropriate field. &amp;nbsp;There&#39;s a few different ways to skin-this cat, but using the URL field will also allow you to auto-fill/suggest credentials if you use one of the various KeePass related browser add-ons.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLy5iI2kzpaYmcyIu4jQxjnVsFEVZLG50JDnoqyOz2BL0eE7otFPihcCx2P_X5ZgXmW-C-T5LBfA3_P9LRn-4Kmyg6BaSRmfHwnZbOn42os9ZOfPn1VX9OXFdpKi2KEaxcfP-k0lonebk/s1600/00_Setup_05.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLy5iI2kzpaYmcyIu4jQxjnVsFEVZLG50JDnoqyOz2BL0eE7otFPihcCx2P_X5ZgXmW-C-T5LBfA3_P9LRn-4Kmyg6BaSRmfHwnZbOn42os9ZOfPn1VX9OXFdpKi2KEaxcfP-k0lonebk/s1600/00_Setup_05.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&amp;nbsp;2) &amp;nbsp;Click on the &quot;Advanced&quot; Tab, followed by the &quot;Add&quot; button to add a new custom string field.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjb-24apULXulWff6yT-pwiXZJrfP04_sNyRv65ITNW3IDkqNUuGhp9EP4g1Rs-vFETriqSAVikoucDnRZSiqFcpbmpH6G2fYstM7zZfiyC-Wf2XMnJt25gmnDcdWxonLC6t4_h9nBkoJg/s1600/00_Setup_06.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjb-24apULXulWff6yT-pwiXZJrfP04_sNyRv65ITNW3IDkqNUuGhp9EP4g1Rs-vFETriqSAVikoucDnRZSiqFcpbmpH6G2fYstM7zZfiyC-Wf2XMnJt25gmnDcdWxonLC6t4_h9nBkoJg/s1600/00_Setup_06.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;3) &amp;nbsp;Give it the name &quot;Token&quot; (be consistent about this) and then paste your security token in the &quot;Value&quot; box.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigBrgBgCCkrHLwOKmpxBdvIAe_vuqFSNwR6bGOf8PFGnc7lWqZkWzBAYeM3oPpbdJ5mY8oJ5gxMXOgtup7ANSkvKZIskRaOEDUDsL7vG3UNzkQKmasRo9utx9MSIWDT16NjyRSMes_TW0/s1600/00_Setup_07.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigBrgBgCCkrHLwOKmpxBdvIAe_vuqFSNwR6bGOf8PFGnc7lWqZkWzBAYeM3oPpbdJ5mY8oJ5gxMXOgtup7ANSkvKZIskRaOEDUDsL7vG3UNzkQKmasRo9utx9MSIWDT16NjyRSMes_TW0/s1600/00_Setup_07.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;h2 style=&quot;clear: both; text-align: left;&quot;&gt;KeePass Triggers&lt;/h2&gt;&lt;h3&gt;Overview&lt;/h3&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Nope, not Apex Triggers, KeePass triggers. &amp;nbsp;KeePass triggers are a way that you can create your own custom features within KeePass, without any development. &amp;nbsp;We&#39;ll be creating two triggers, one a button, and one an action for when the button is clicked. &amp;nbsp;That functionality will be opening the browser of your choice, in standard or private mode, and logging into Salesforce with the credentials you have highlighted.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;If you configure all the browsers, this is what you&#39;ll end up with these triggers:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmO0cwBwdqydCcafXBb39zmL5HxwW_n4asJ4CbN0klZxr6vJfJsR_8jRzD8Gvg6s0sv1_iudHa89AT3JS8OpZk8M8Lx823omRr2AtMQYJubUT4wN3ik2r7RSxuwhe_qHuWV97c7mgYk4M/s1600/01.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmO0cwBwdqydCcafXBb39zmL5HxwW_n4asJ4CbN0klZxr6vJfJsR_8jRzD8Gvg6s0sv1_iudHa89AT3JS8OpZk8M8Lx823omRr2AtMQYJubUT4wN3ik2r7RSxuwhe_qHuWV97c7mgYk4M/s1600/01.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Which will result in these custom buttons within the tool:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_ac_l__CTJOE-SQ-SyFvnQtxF-LotvzDkYUNjygAvbBhGzxKFu8m1JwYyC7h7H8_b5LXvFoVYtgckCsnR2trlU9-35mPCtEglEmAgt7fROcYDGbKFEjtIogw0kgS2MMvnCoIdP7NCCpw/s1600/Buttons.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;56&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_ac_l__CTJOE-SQ-SyFvnQtxF-LotvzDkYUNjygAvbBhGzxKFu8m1JwYyC7h7H8_b5LXvFoVYtgckCsnR2trlU9-35mPCtEglEmAgt7fROcYDGbKFEjtIogw0kgS2MMvnCoIdP7NCCpw/s1600/Buttons.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;h3 style=&quot;clear: both; text-align: left;&quot;&gt;Creating the Buttons&lt;/h3&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;1) &amp;nbsp;Go to Tools --&amp;gt; Triggers...&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;2) &amp;nbsp;Provide a name for this trigger. &amp;nbsp;I prefix mine with &quot;Button: &amp;nbsp;&quot; just to keep them straight in the list.&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPCMKfuAnAiRn5SHwT8jJlvAMMWmSFqPayGxcnKbHcGZnU3iThzFXbRaXkMPJDTcyDpFYJ0j1qGjMLQJHHNAy_HkEn0fsnRxvj4kXH58ilMewQAU-DAK1F-qRGDElcTsLVlljUCOGkCRI/s1600/02_ChromeButton_01.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPCMKfuAnAiRn5SHwT8jJlvAMMWmSFqPayGxcnKbHcGZnU3iThzFXbRaXkMPJDTcyDpFYJ0j1qGjMLQJHHNAy_HkEn0fsnRxvj4kXH58ilMewQAU-DAK1F-qRGDElcTsLVlljUCOGkCRI/s1600/02_ChromeButton_01.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;3) &amp;nbsp;Go to the &quot;Events&quot; tab, click on the &quot;Add...&quot; button&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQpS4BmhtCRzHMlarDyj6D7DeXzRvzu1wWc6XQGssMS8soB3J0V7I55rDGTylyrQ4TqLLY4m9rhA7cNOQs8hQjv1GFp12_Zhu4U-A7-zmXlQC02LcwmGY8ETEV-vgNb2O11EwNqNIAGTg/s1600/02_ChromeButton_02.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQpS4BmhtCRzHMlarDyj6D7DeXzRvzu1wWc6XQGssMS8soB3J0V7I55rDGTylyrQ4TqLLY4m9rhA7cNOQs8hQjv1GFp12_Zhu4U-A7-zmXlQC02LcwmGY8ETEV-vgNb2O11EwNqNIAGTg/s1600/02_ChromeButton_02.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;4) &amp;nbsp;Choose the &quot;Application started and ready&quot; option.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqrFyqxjtLD6Jcvc027pwszcmUsP7JOpwrmeqO7w_rrHEiGtzEC_RCzZu1X1bVUVyHt2xFM3kWsUsTJm_6Moixk280ARt8lno3FEm-vCNTmIfB_zR6pTIMbhIPCalCIt38iV21TxO_EKM/s1600/02_ChromeButton_02a.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqrFyqxjtLD6Jcvc027pwszcmUsP7JOpwrmeqO7w_rrHEiGtzEC_RCzZu1X1bVUVyHt2xFM3kWsUsTJm_6Moixk280ARt8lno3FEm-vCNTmIfB_zR6pTIMbhIPCalCIt38iV21TxO_EKM/s1600/02_ChromeButton_02a.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;5) &amp;nbsp;Leave the &quot;Conditions&quot; Tab blank.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4OmkWbCsq2j4jpz_kBjGM_O42GCoJSujyp7qKXwBJi043V_tuL-cI_n7_lSMl9anNOKDVanDK8w_AM4DSY2abhAFnuksK-NrItQInEO2T5cw5XHB_hgRsjSC_AMaJcG00T5cUlanuJJI/s1600/02_ChromeButton_03.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4OmkWbCsq2j4jpz_kBjGM_O42GCoJSujyp7qKXwBJi043V_tuL-cI_n7_lSMl9anNOKDVanDK8w_AM4DSY2abhAFnuksK-NrItQInEO2T5cw5XHB_hgRsjSC_AMaJcG00T5cUlanuJJI/s1600/02_ChromeButton_03.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;6) &amp;nbsp;On the &quot;Actions&quot; Tab, click on the &quot;Add...&quot; button.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjl7KwRaHFy7FllfJ1PoKswog-H8sjg2WBR1clKTYxI8og7cTctA_f_Dv9atP0Yciqb-WUNOo-df_yhwnorks3A8HH75dx7VoaBE81Yt4reqS7-cslBbMo3XsICiMetkdC-oc-PE_A3EAg/s1600/02_ChromeButton_04.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjl7KwRaHFy7FllfJ1PoKswog-H8sjg2WBR1clKTYxI8og7cTctA_f_Dv9atP0Yciqb-WUNOo-df_yhwnorks3A8HH75dx7VoaBE81Yt4reqS7-cslBbMo3XsICiMetkdC-oc-PE_A3EAg/s1600/02_ChromeButton_04.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;7) &amp;nbsp;Within the &quot;Action:&quot; dropdown, choose &quot;Add custom toolbar button. &amp;nbsp;Then provide an ID, Name, and Description for this new button. &amp;nbsp;The Id is important as this will be referenced by the next trigger you create.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPzog_FCvWLlChVqKqwZMm91aMFSsl85CQ20lZ7HED76zXjvh2jmycA7WIZItHjr1KB0yjZhSL1RcaoMwtn1WeXSA2MClOdrNosnw-ppuKygIYIreS79h0pBuwNwOIIl5qkHaEU959KiQ/s1600/02_ChromeButton_04b.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPzog_FCvWLlChVqKqwZMm91aMFSsl85CQ20lZ7HED76zXjvh2jmycA7WIZItHjr1KB0yjZhSL1RcaoMwtn1WeXSA2MClOdrNosnw-ppuKygIYIreS79h0pBuwNwOIIl5qkHaEU959KiQ/s1600/02_ChromeButton_04b.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;h3 style=&quot;clear: both; text-align: left;&quot;&gt;Assigning an Action to a Custom Button&lt;/h3&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;1) &amp;nbsp;Create another trigger, providing a name for it on the &quot;Properties&quot; tab. &amp;nbsp;This time, I prefix the name with &quot;Action: &amp;nbsp;&quot;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3G8Bed_5Zcj16k0PsXmDFKKHKO5KiXZ98q_eGLT5kYrdJmUAbGiCj2oTW1kZZ8zMD1p6NIYfSQZI4j9TzypE7NMHlytDB7gnrMHUL1ENRQqWjX53UccUSQd1o6wNqlVXh13ArlmnvsvY/s1600/03_ChromeAction_01.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3G8Bed_5Zcj16k0PsXmDFKKHKO5KiXZ98q_eGLT5kYrdJmUAbGiCj2oTW1kZZ8zMD1p6NIYfSQZI4j9TzypE7NMHlytDB7gnrMHUL1ENRQqWjX53UccUSQd1o6wNqlVXh13ArlmnvsvY/s1600/03_ChromeAction_01.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&amp;nbsp;2) &amp;nbsp;On the &quot;Events&quot; tab, click on the &quot;Add...&quot; button&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDyZxgGxaWVOBNxD1IHQ7feNb12HguwU4mIYCB3_YiM4T-DykKT-DddqIvzHLOUXmJZKqD0u93AMxGFkLOvd9kyYQ1ynIcE0in4hhLEPjm4WsQt1ZHHSbGF5f3PdA1awjIIxx3YANzgkQ/s1600/03_ChromeAction_02.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDyZxgGxaWVOBNxD1IHQ7feNb12HguwU4mIYCB3_YiM4T-DykKT-DddqIvzHLOUXmJZKqD0u93AMxGFkLOvd9kyYQ1ynIcE0in4hhLEPjm4WsQt1ZHHSbGF5f3PdA1awjIIxx3YANzgkQ/s1600/03_ChromeAction_02.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
3) &amp;nbsp;From the &quot;Event:&quot; dropdown, choose &quot;Custom toolbar button clicked&quot; and next to &quot;ID&quot; provide the ID of the button to be clicked (you defined this in the above step 7).&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwvbQYAPFHWtUDZ_sQbaS_-QChhhhfYnDvOmQbX9YA894P6HQAMYj70A5-bkH4D4JvVDOGPbw-M5MjYT7K-qxC1B9ref9_hVJ0kJO55aVnqF1bH5xj7P4XP6738OJyjN-JQpIMcu5dttU/s1600/03_ChromeAction_02b.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwvbQYAPFHWtUDZ_sQbaS_-QChhhhfYnDvOmQbX9YA894P6HQAMYj70A5-bkH4D4JvVDOGPbw-M5MjYT7K-qxC1B9ref9_hVJ0kJO55aVnqF1bH5xj7P4XP6738OJyjN-JQpIMcu5dttU/s1600/03_ChromeAction_02b.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&amp;nbsp;4) &amp;nbsp;Again, leave the &quot;Conditions&quot; tab empty.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLckCD54OLB0ft3n0e6Ny6FeS4iqpAMUdhzWAboes_LKlgccfH1zTRzVwXm-9Lw8OB9y2T3a7U21k59CYgDxR1Gbcp6Z7aPRDPSIyOkfXT1b6cpcKHlW8IGr2pz76qHHLJpU9rK_eho7k/s1600/03_ChromeAction_03.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLckCD54OLB0ft3n0e6Ny6FeS4iqpAMUdhzWAboes_LKlgccfH1zTRzVwXm-9Lw8OB9y2T3a7U21k59CYgDxR1Gbcp6Z7aPRDPSIyOkfXT1b6cpcKHlW8IGr2pz76qHHLJpU9rK_eho7k/s1600/03_ChromeAction_03.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&amp;nbsp;5) &amp;nbsp;On the &quot;Actions&quot; tab, click on the &quot;Add...&quot; button.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh97ymFdrQ0aoHXELs1Gkc9PmnDlXpXprcaGwlEmhE9p-g70SYn6CdNx4XbGWNziLharcHf6ruG-UfMRWe5T7ZPcXT4Z7nLjB3QHVYTGOuSxntUox0RrXcheHJ_wEK5XNurhGJ3fC_r9Ew/s1600/03_ChromeAction_04.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh97ymFdrQ0aoHXELs1Gkc9PmnDlXpXprcaGwlEmhE9p-g70SYn6CdNx4XbGWNziLharcHf6ruG-UfMRWe5T7ZPcXT4Z7nLjB3QHVYTGOuSxntUox0RrXcheHJ_wEK5XNurhGJ3fC_r9Ew/s1600/03_ChromeAction_04.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&amp;nbsp;6) &amp;nbsp;From the &quot;Action:&quot; dropdown, click on the &quot;Execute command line / URL&quot; option. &amp;nbsp;Provide the following as parameters for the &quot;File/URL&quot; and &quot;Arguments&quot; options. &amp;nbsp;Here we&#39;re using the equivalent of Salesforce merge fields to populate the setting with a value from the credential.&lt;br /&gt;
&lt;br /&gt;
File/URL: &amp;nbsp;{GOOGLECHROME}&lt;br /&gt;
Arguments: &amp;nbsp;{URL}?un={USERNAME}&amp;amp;pw={PASSWORD}&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjrM30c_3g4M7U2iTBoHTmFzm7q8PNvpJiRGgQQhLNaZssjSE-FFJtixSyBeHTOO2W2DT4fMvLnSNkmzWbDa9VA4RkZOyv2115CkWvvMf7TQRHNdjGzdsytvyE80-fkyuWxSrggw5HcgM/s1600/03_ChromeAction_04b.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjrM30c_3g4M7U2iTBoHTmFzm7q8PNvpJiRGgQQhLNaZssjSE-FFJtixSyBeHTOO2W2DT4fMvLnSNkmzWbDa9VA4RkZOyv2115CkWvvMf7TQRHNdjGzdsytvyE80-fkyuWxSrggw5HcgM/s1600/03_ChromeAction_04b.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Now when you open KeePass, you&#39;ll have a few additional buttons within the programs toolbar for you to use.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;1) &amp;nbsp;Highlight the credential you want to use&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;2) &amp;nbsp;Click on the appropriate custom toolbar button to get logged into Salesforce&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;h3 style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
Update #1 - 1/22/2015&lt;/h3&gt;&lt;div&gt;About a week into using this over the Force.com Plugins extension and I&#39;ve adapted well. &amp;nbsp;The extension is gone and my habit to click there is gone.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The process is easy:&lt;/div&gt;&lt;div&gt;Ctrl + Alt + K opens KeePass&lt;/div&gt;&lt;div&gt;Ctrl&amp;nbsp;+ F opens the search prompt&lt;/div&gt;&lt;div&gt;And I&#39;m off!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Here are the URLs and the arguments that I used for my six buttons; two for each browser (Chrome, Firefox, and Internet Explorer). &amp;nbsp;One for normal browsing and one for that browser&#39;s private mode.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;b&gt;Google Chrome - Standard&lt;/b&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;File/URL: &amp;nbsp;{GOOGLECHROME}&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;Arguments: &amp;nbsp;{URL}?un={T-CONV:/{USERNAME}/Uri/}&amp;amp;pw={T-CONV:/{PASSWORD}/Uri/}&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;b&gt;Google Chrome - Incognito&lt;/b&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;File/URL: &amp;nbsp;{GOOGLECHROME}&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;Arguments: &amp;nbsp;-incognito {URL}?un={T-CONV:/{USERNAME}/Uri/}&amp;amp;pw={T-CONV:/{PASSWORD}/Uri/}&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;b&gt;Firefox - Standard&lt;/b&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;File/URL: &amp;nbsp;{FIREFOX}&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;Arguments: &amp;nbsp;{URL}?un={T-CONV:/{USERNAME}/Uri/}&amp;amp;pw={T-CONV:/{PASSWORD}/Uri/}&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;b&gt;Firefox - Private Mode&lt;/b&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;File/URL: &amp;nbsp;{FIREFOX}&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;Arguments: &amp;nbsp;{URL}?un={T-CONV:/{USERNAME}/Uri/}&amp;amp;pw={T-CONV:/{PASSWORD}/Uri/} -private-window&amp;nbsp;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;b&gt;Internet Explorer - Standard&lt;/b&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;File/URL: &amp;nbsp;{INTERNETEXPLORER}&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;Arguments: &amp;nbsp;{URL}?un={T-CONV:/{USERNAME}/Uri/}&amp;amp;pw={T-CONV:/{PASSWORD}/Uri/}&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;b&gt;Internet Explorer - Private Mode&lt;/b&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;File/URL: &amp;nbsp;{INTERNETEXPLORER}&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;Arguments: &amp;nbsp;{URL}?un={T-CONV:/{USERNAME}/Uri/}&amp;amp;pw={T-CONV:/{PASSWORD}/Uri/} -private&amp;nbsp;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;Update #2 - 6/27/2015&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;I&#39;ve modified the scripts to work a little bit better with things like special characters; previously if a username/password contained things like &quot;+&quot; symbols (who doesn&#39;t use the &lt;a href=&quot;https://support.google.com/mail/answer/12096?hl=en&quot; target=&quot;_blank&quot;&gt;Gmail &lt;/a&gt;alias trick?) the buttons would not work as desired.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;The work around is to modify the above snippets to take advantage of the KeePass &lt;a href=&quot;http://keepass.info/help/base/placeholders.html#texttrf&quot; target=&quot;_blank&quot;&gt;text transformation&amp;nbsp;{T-CONV}&lt;/a&gt;. &amp;nbsp;each argument has been updated above.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;Looking to save some time setting these up? &amp;nbsp;Copy the following gist to your clipboard and then navigate to Tools --&amp;gt; Triggers... &quot;Tools&quot; button in the lower-left --&amp;gt; and then click on the option to &quot;Paste Triggers from Clipboard.&quot; &amp;nbsp;Then restart KeePass.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;script src=&quot;https://gist.github.com/KirkSteffke/a29d29eef458881bab3d.js&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;</description><link>http://blog.crmscience.com/2015/01/managing-credentials-with-keepass.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoYnsFArJxUns_9NqfU8HbYE2bBHk4kdHONg1j_ZBpk1-esU-q4WXfKhtJrfPrIHauqoYD9Sz-scig_xP78-Urvc6M8xdOAK-h40o5lNGbhDFnxqRpWU-tqZQ2ZsHAu3-f8jZ43yupRtM/s72-c/KeePass.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-5200343476502122705</guid><pubDate>Mon, 22 Dec 2014 15:03:00 +0000</pubDate><atom:updated>2020-02-21T18:08:18.496-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">API</category><category domain="http://www.blogger.com/atom/ns#">Callout</category><category domain="http://www.blogger.com/atom/ns#">HttpCalloutMock</category><category domain="http://www.blogger.com/atom/ns#">httprequest</category><category domain="http://www.blogger.com/atom/ns#">httpresponse</category><category domain="http://www.blogger.com/atom/ns#">MultiStaticResourceCalloutock</category><category domain="http://www.blogger.com/atom/ns#">rest</category><category domain="http://www.blogger.com/atom/ns#">StaticResourceCalloutMock</category><category domain="http://www.blogger.com/atom/ns#">test</category><title>Test Coverage Pattern for Multi-Callout Methods</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://www.crmscience.com/lab-coat-lessons&quot;&gt;&lt;img alt=&quot;Visit our website&quot; border=&quot;0&quot; data-original-height=&quot;300&quot; data-original-width=&quot;1600&quot; height=&quot;120&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiMZW2AjEu-qQrMD6QIOtSX7VLLGnSBv1oUIKukZ3XG2IZCIGwQuUzsAWtVvOyjbRO54lS16uF_NwS0-yJ_MebVQqM_fEqWcqYdFp_-7urHs0pS0I5BPl35Hg5A3F_RI-_seyFupLSSTo/s640/Blogger-Banner-01.png&quot; title=&quot;&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
When you&#39;re developing Apex code for integrations with external systems, an issue you always need to overcome is the creation of test coverage to cover your various methods responsible for making callouts to one or more endpoints.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Existing Resources&lt;/h3&gt;
Salesforce provides a few different ways for you to achieve this:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#CSHID=apex_classes_restful_http_testing_httpcalloutmock.htm|StartTopic=Content%2Fapex_classes_restful_http_testing_httpcalloutmock.htm|SkinName=webhelp&quot; target=&quot;_blank&quot;&gt;HttpCalloutMock Interface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#CSHID=apex_classes_restful_http_testing_httpcalloutmock.htm|StartTopic=Content%2Fapex_classes_restful_http_testing_httpcalloutmock.htm|SkinName=webhelp&quot; target=&quot;_blank&quot;&gt;StaticResourceCalloutMock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#CSHID=apex_classes_restful_http_testing_httpcalloutmock.htm|StartTopic=Content%2Fapex_classes_restful_http_testing_httpcalloutmock.htm|SkinName=webhelp&quot; target=&quot;_blank&quot;&gt;MultiStaticResourceCalloutMock&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
&lt;br /&gt;
&lt;/h3&gt;
&lt;h3&gt;
Problem&lt;/h3&gt;
&lt;div&gt;
However, all three have a similar shortcoming when additional complexity is needed. &amp;nbsp;With systems integrations, it&#39;s not uncommon to require multiple callouts within the same execution. &amp;nbsp;The three examples from Salesforce can handle that just fine... as long as you don&#39;t need to use the same endpoint more than once AND expect different results.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Before we take a look at a solution, here are some details on the existing testing mechanisms and sample usages from the Salesforce documentation.&lt;/div&gt;
&lt;h3&gt;
&lt;br /&gt;
&lt;/h3&gt;
&lt;h3&gt;
HttpCalloutMock Interface&lt;/h3&gt;
The HttpCalloutMock Interface allows you to create a respond() method in a test utility class where a response is constructed. &amp;nbsp;Within the test coverage class, you tell your test to use the mock utility with a test.setMock() method.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
TestUtility (&lt;a href=&quot;https://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#CSHID=apex_classes_restful_http_testing_httpcalloutmock.htm|StartTopic=Content%2Fapex_classes_restful_http_testing_httpcalloutmock.htm|SkinName=webhelp&quot; target=&quot;_blank&quot;&gt;from documentation&lt;/a&gt;)&lt;/h4&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
@isTest                        
global class MockHttpResponseGenerator implements HttpCalloutMock {
    // Implement this interface method
    global HTTPResponse respond(HTTPRequest req) {
        // Optionally, only send a mock response for a specific endpoint
        // and method.
        System.assertEquals(&#39;http://api.salesforce.com/foo/bar&#39;, req.getEndpoint());
        System.assertEquals(&#39;GET&#39;, req.getMethod());
        
        // Create a fake response
        HttpResponse res = new HttpResponse();
        res.setHeader(&#39;Content-Type&#39;, &#39;application/json&#39;);
        res.setBody(&#39;{&quot;foo&quot;:&quot;bar&quot;}&#39;);
        res.setStatusCode(200);
        return res;
    }
}
]]&lt;/script&gt;
&lt;/div&gt;
In that code snippet, note the &quot;implements HttpCalloutMock&quot; interface declaration. &amp;nbsp;HttpCalloutMock requires a respond() method, which accepts an HttpRequest parameter. &amp;nbsp;Within this method, an HttpResponse is constructed.

&lt;br /&gt;
&lt;h4&gt;
Test Method Usage (&lt;a href=&quot;https://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#CSHID=apex_classes_restful_http_testing_httpcalloutmock.htm|StartTopic=Content%2Fapex_classes_restful_http_testing_httpcalloutmock.htm|SkinName=webhelp&quot; target=&quot;_blank&quot;&gt;from documentation&lt;/a&gt;)&lt;/h4&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
@isTest
private class CalloutClassTest {
     @isTest static void testCallout() {
        // Set mock callout class 
        Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator());
        
        // Call method to test.
        // This causes a fake response to be sent
        // from the class that implements HttpCalloutMock. 
        HttpResponse res = CalloutClass.getInfoFromExternalService();
        
        // Verify response received contains fake values
        String contentType = res.getHeader(&#39;Content-Type&#39;);
        System.assert(contentType == &#39;application/json&#39;);
        String actualValue = res.getBody();
        String expectedValue = &#39;{&quot;foo&quot;:&quot;bar&quot;}&#39;;
        System.assertEquals(actualValue, expectedValue);
        System.assertEquals(200, res.getStatusCode());
    }
}
]]&lt;/script&gt;

If you look at their comments within the respond() method, you could intelligently create an HttpResponse based on the request - however, for that endpoint, you&#39;ll always receive the same response. &amp;nbsp;That&#39;s not ideal if you&#39;re making multiple calls within an execution context and need different results. &amp;nbsp;Just a few examples might include testing paging (&quot;next_page&quot;:2), date/time stamp requirements (if date/time &amp;gt; last received date/time), record count calculations (count # increase after POST), and so on.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
StaticResourceCalloutMock and MultipleStaticResourceCalloutMock&amp;nbsp;&lt;/h3&gt;
Using these methods, you can leverage Static Resources to maintain you response bodies, which can help keep your Apex code nice and tidy. 

Rather than implement an HttpCalloutMock interface, you can declare everything within your test coverage. &amp;nbsp;Here are usage examples of both the single StaticResourceCalloutMock and the MultipleStaticResourceCalloutMock

&lt;br /&gt;
&lt;h4&gt;
Test Method Usage of Static ResourceCalloutMock (&lt;a href=&quot;https://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#CSHID=apex_classes_restful_http_testing_httpcalloutmock.htm|StartTopic=Content%2Fapex_classes_restful_http_testing_httpcalloutmock.htm|SkinName=webhelp&quot; target=&quot;_blank&quot;&gt;from documentation&lt;/a&gt;)&lt;/h4&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
StaticResourceCalloutMock mock = new StaticResourceCalloutMock();
mock.setStaticResource(&#39;myStaticResourceName&#39;);
mock.setStatusCode(200);
mock.setHeader(&#39;Content-Type&#39;, &#39;application/json&#39;);

Test.setMock(HttpCalloutMock.class, mock);
]]&lt;/script&gt;

&lt;br /&gt;
&lt;h4&gt;
Test Method Usage of MultipleStaticResourceCalloutMock (&lt;a href=&quot;https://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#CSHID=apex_classes_restful_http_testing_httpcalloutmock.htm|StartTopic=Content%2Fapex_classes_restful_http_testing_httpcalloutmock.htm|SkinName=webhelp&quot; target=&quot;_blank&quot;&gt;from documentation&lt;/a&gt;)&lt;/h4&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
MultiStaticResourceCalloutMock multimock = new MultiStaticResourceCalloutMock();
multimock.setStaticResource(&#39;http://api.salesforce.com/foo/bar&#39;, &#39;mockResponse&#39;);
multimock.setStaticResource(&#39;http://api.salesforce.com/foo/sfdc&#39;, &#39;mockResponse2&#39;);
multimock.setStatusCode(200);
multimock.setHeader(&#39;Content-Type&#39;, &#39;application/json&#39;);

Test.setMock(HttpCalloutMock.class, multimock);
]]&lt;/script&gt;

&lt;br /&gt;
&lt;h3&gt;
Solution&lt;/h3&gt;
So how do we go about setting up a mechanism to achieve test coverage in a method that requires multiple callouts, including multiple callouts to the same resources where different resutlts are expected? &amp;nbsp;We&#39;ll leverage and extend the first solution, the HttpMockCallout interface. &amp;nbsp;We&#39;ll define a constructor that accepts a map of callout methods to callout endpoints to a list of response details. &amp;nbsp;We&#39;ll also accept a boolean to control whether or not the responses should be re-used or thrown away so a different response can be provided next time.

Let&#39;s start with a sample call we&#39;ll be covering:

&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
public with sharing class Callout {

    //  Method to do callout1 twice, callout2 once, and return their combined response bodies
    public static string doCallouts() {
        string resp1Str = doCallout1().getBody();
        string resp2Str = doCallout1().getBody();
        string resp3Str = doCallout2().getBody();
    
        return resp1Str + &#39;:&#39; + resp2Str + &#39;:&#39; + resp3Str;
    }
    
    //  Callout 1 - used twice
    public static HttpResponse doCallout1() {
        HttpRequest req = new HttpRequest();
        req.setEndpoint(&#39;http://yourEndpoint.com/resources/example1&#39;);
        req.setMethod(&#39;GET&#39;);
        Http h = new Http();
        HttpResponse res = h.send(req);
        system.debug(res);
        return res;
    }
    
    //  Callout 2 - used once
    public static HttpResponse doCallout2() {
        HttpRequest req = new HttpRequest();
        req.setEndpoint(&#39;http://yourEndpoint.com/resources/example2&#39;);
        req.setMethod(&#39;GET&#39;);
        Http h = new Http();
        HttpResponse res = h.send(req);
        system.debug(res);
        return res;
    }
}
]]&lt;/script&gt;

Here we have two methods (doCallout1 and doCallout2) that make a GET callout to two different endpoints (/resources/example1 and /resources/example2). &amp;nbsp;We also have a doCallouts() method that uses those callout methods; it calls Callout1 twice and Callout2 once. &amp;nbsp;It then returns a concatenated string of each callout&#39;s response body.

If we test without any customizations, using the standard mock interface, here&#39;s what it would look like:

&lt;br /&gt;
&lt;h4&gt;
Test Utility&lt;/h4&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
@isTest                     
global class testResponseGenerator implements HttpCalloutMock {
    //  Default Constructor
    global testResponseGenerator() {}
  
    //  Handle responses for two callouts
    global HTTPResponse respond(HTTPRequest req) {
        // Create a fake response
        HttpResponse res = new HttpResponse();
      
        res.setHeader(&#39;Content-Type&#39;, &#39;application/json&#39;);
        res.setStatusCode(200);

        //  Set the response body, based on endpoint. - What if your method calls example1 twice and you need a different response?
        if (req.getEndpoint() == &#39;http://yourEndpoint.com/resources/example1&#39;)
            res.setBody(&#39;{&quot;example&quot;:&quot;response1&quot;}&#39;);
        else if (req.getEndpoint() == &#39;http://yourEndpoint.com/resources/example2&#39;)
            res.setBody(&#39;{&quot;example&quot;:&quot;response2&quot;}&#39;);

        return res;
    }
}
]]&lt;/script&gt;

&lt;br /&gt;
&lt;h4&gt;
Test Class&lt;/h4&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
@isTest
private class testCallout {
    
    @isTest static void testWithoutPattern() {
        Test.setMock(HttpCalloutMock.class, new testResponseGenerator());
        string str = Callout.doCallouts();
        system.debug(&#39;str:  &#39; + str);
    }
}
]]&lt;/script&gt;

&lt;b&gt;Our output would be:&lt;/b&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
{&quot;example&quot;:&quot;response1&quot;}:{&quot;example&quot;:&quot;&lt;span style=&quot;background-color: #ffd966;&quot;&gt;response1&lt;/span&gt;&quot;}:{&quot;example&quot;:&quot;response2&quot;}&lt;/blockquote&gt;
&lt;b&gt;Instead of:&lt;/b&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
{&quot;example&quot;:&quot;response1&quot;}:{&quot;example&quot;:&quot;&lt;span style=&quot;background-color: #ffd966;&quot;&gt;response1b&lt;/span&gt;&quot;}:{&quot;example&quot;:&quot;response2&quot;}&lt;/blockquote&gt;
If we modify the Test Utility, can can get the expected results...

&lt;br /&gt;
&lt;h4&gt;
Test Utility&lt;/h4&gt;
&lt;div&gt;
While we maintain the use of the HttpCalloutMock interface, we extend it&#39;s functionality by providing a new object called &quot;Resp&quot; that will hold individual response bodies, statuses, status codes, and a boolean called &quot;Discard.&quot; &amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
A nested map, called ResponseMap, will be used to pair callout methods to endpoints and the endpoints to a list of these &quot;Resp&quot; records.&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
Method --&amp;gt; Endpoint --&amp;gt; LIST&amp;lt;Resp&amp;gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
Within the respond() method of the interface, we&#39;ll get a list of Resp&#39;s/responses from the map using the provided HttpRequests (from the respond() signature&#39;s HttpRequest param), and use the Resp at the top of the list to populate a newly instantiated HttpResponse&#39;s details (set its body, result, and result code).&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
To help with our original problem of being able to provide different responses to calls, using the same endpoints, the &quot;discard&quot; boolean will be used to remove a resp, once moved, from the list, so in subsequent calls, another resp is used to populate the HttpResponse.&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[@isTest                     
global class testResponseGenerator implements HttpCalloutMock {
  
    //  Default constructor
    global testResponseGenerator() {}

    //  Property and getter (semi-init&#39;d) to pair method --&gt; endpoint --&gt; list of string responses (obj)
    private static map&lt;string, map&lt;string, list&lt;resp&gt;&gt;&gt;; ResponseMap;
    public static map&lt;string, map&lt;string, list&lt;resp&gt;&gt;&gt;; getResponseMap() {
        if (ResponseMap == null) {
            ResponseMap = new map&gt;string, map&lt;string, list&lt;resp&gt;&gt;&gt;{
                &#39;GET&#39; =&gt; new map&lt;string, list&lt;resp&gt;&gt;(),
                &#39;PUT&#39; =&gt; new map&lt;string, list&lt;resp&gt;&gt;(),
                &#39;POST&#39; =&gt; new map&lt;string, list&lt;resp&gt;&gt;()
            };
        }
        return ResponseMap;
    }

    //  Object to hold details of a callout for test methods where callouts are performed
    global class Resp {
        public string Body { get; set; }
        public string Status { get; set; }
        public integer StatusCode { get; set; }
        public boolean Discard { get; set; }
        public Resp(string body, string status, integer statusCode, boolean discard) {
            this.Body = body;
            this.Status = status;
            this.StatusCode = statusCode;
            this.Discard = discard;
        }
    }

    //  Required respond() method for HTTPCalloutMock
    global HTTPResponse respond(HTTPRequest req) {

        //  Property for returned response
        HttpResponse res = new HttpResponse();

        //  Ensure HttpRequest is valid and the Response map contains the req&#39;s method and endpoint
        if (req != null &amp;amp;&amp;amp; req.getMethod() != null &amp;amp;&amp;amp; req.getEndpoint() != null) {
            if (getResponseMap().containsKey(req.getMethod()) &amp;amp;&amp;amp; getResponseMap().get(req.getMethod()).containsKey(req.getEndpoint())) {
              
                //  Instantiate a list of the method/endpoint&#39;s response bodies
                list&lt;resp&gt; respList = getResponseMap().get(req.getMethod()).get(req.getEndpoint());
              
                //  If there&#39;s at least one, use it - otherwise output an error
                if (!respList.isEmpty()) {

                    //  Use the first in the list - might be called again or cleared
                    Resp r = respList[0];

                    //  Set up the response details
                    res.setBody(r.Body);
                    res.setStatus(r.Status);
                    res.setStatusCode(r.StatusCode);

                    //  Unless provided true by test, remove the response so it isn&#39;t used again (multiple-callout method tests)
                    if (r.discard)
                        respList.remove(0);
                } else {
                    system.debug(&#39;No responses for this method/endpoint&#39;);
                }
            } else {
                system.debug(&#39;There was a problem with the prepared response map&#39;);
            }
        } else {
            system.debug(&#39;There was a problem with the Test Request:  &#39; + req);
        }

        //  Return the response to the caller
        return res;
    }
}
&lt;/resp&gt;
]]&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Test Method&lt;/h4&gt;
&lt;div&gt;
The test method is only slightly different. &amp;nbsp;Before using the test.setMock() method, we have to load up the ResponseMap with the responses that are required for the testing in that method. &amp;nbsp;Now, within our test method, we can set up everything that&#39;s needed, from multiple methods, endpoints, with varying response bodies and results, as needed.&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[@isTest
private class testCallout {
    
    @isTest static void testWithPattern() {
        
        //  Add valid responses for the 1st endpoint
        testResponseGenerator.getResponseMap().get(&#39;GET&#39;).put(
            &#39;http://yourEndpoint.com/resources/example1&#39;, 
            new list&lt;testresponsegenerator .resp=&quot;&quot;&gt;{
                
                //  Add as many unique responses as are necessary - Response Body, success, success code, discard
                new testResponseGenerator.Resp(&#39;{&quot;example&quot;:&quot;response1&quot;}&#39;,&#39;success&#39;, 200, true),
                new testResponseGenerator.Resp(&#39;{&quot;example&quot;:&quot;response1b&quot;}&#39;,&#39;success&#39;, 200, false)
            }
        );
        //  Add valid responses for the 2nd endpoint
        testResponseGenerator.getResponseMap().get(&#39;GET&#39;).put(
            &#39;http://yourEndpoint.com/resources/example2&#39;, 
            new list&lt;testresponsegenerator .resp=&quot;&quot;&gt;{
                new testResponseGenerator.Resp(&#39;{&quot;example&quot;:&quot;response2&quot;}&#39;,&#39;success&#39;, 200, false)
            }
        );
        //  Enable mock response
        Test.setMock(HttpCalloutMock.class, new testResponseGenerator());
        //  Invoke the callout method
        string str = Callout.doCallouts();
        system.debug(&#39;str:  &#39; + str);
        //  Do rest of test coverage...
    }
}
&lt;/testresponsegenerator&gt;&lt;/testresponsegenerator&gt;
]]&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
Now you can run the test class and get the expected results:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
{&quot;example&quot;:&quot;response1&quot;}:{&quot;example&quot;:&quot;&lt;span style=&quot;background-color: #ffd966;&quot;&gt;response1b&lt;/span&gt;&quot;}:{&quot;example&quot;:&quot;response2&quot;}&lt;/blockquote&gt;
&lt;br /&gt;&lt;/div&gt;
</description><link>http://blog.crmscience.com/2014/12/test-coverage-pattern-for-multi-callout.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiMZW2AjEu-qQrMD6QIOtSX7VLLGnSBv1oUIKukZ3XG2IZCIGwQuUzsAWtVvOyjbRO54lS16uF_NwS0-yJ_MebVQqM_fEqWcqYdFp_-7urHs0pS0I5BPl35Hg5A3F_RI-_seyFupLSSTo/s72-c/Blogger-Banner-01.png" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-4089725749093897875</guid><pubDate>Sun, 14 Dec 2014 19:15:00 +0000</pubDate><atom:updated>2015-06-10T10:06:33.739-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">exercise</category><category domain="http://www.blogger.com/atom/ns#">left</category><category domain="http://www.blogger.com/atom/ns#">mid</category><category domain="http://www.blogger.com/atom/ns#">now</category><category domain="http://www.blogger.com/atom/ns#">right</category><category domain="http://www.blogger.com/atom/ns#">Visualforce; actionPoller; functions</category><title>What Color Is It?</title><description>While swiping away at my tablet, like a madman with my morning cup-o-joe, I came across this novelty of a site: &amp;nbsp;&lt;a href=&quot;http://whatcolourisit.scn9a.org/&quot;&gt;http://whatcolourisit.scn9a.org/&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiKZVkbxcBTRxblsuZhDpJq6upLlySqw5g2T7D-xbg9bEMg68ZP3NgM_wimsLk6DmU2VSofTbmq0Spqn6ZPV1ifB2CvgUBmi8nRqu5whwlZ3mce_fayiPBcoWiA7qtgB3MCmkfltWVmHI/s1600/WhatTimeIsIt.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiKZVkbxcBTRxblsuZhDpJq6upLlySqw5g2T7D-xbg9bEMg68ZP3NgM_wimsLk6DmU2VSofTbmq0Spqn6ZPV1ifB2CvgUBmi8nRqu5whwlZ3mce_fayiPBcoWiA7qtgB3MCmkfltWVmHI/s1600/WhatTimeIsIt.PNG&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;The idea is simple... take the hour, minute, and second of the current time and use those values combined as the page background&#39;s hex color (#hhmmss).&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Admittedly, there&#39;s not a lot of business purpose here, but it can be a good development exercise to use as an introduction to re-rendering page components using&amp;nbsp;&lt;a href=&quot;https://www.salesforce.com/us/developer/docs/pages/Content/pages_compref_actionPoller.htm&quot; target=&quot;_blank&quot;&gt;actionPollers&lt;/a&gt;&amp;nbsp;and a few various &lt;a href=&quot;https://www.salesforce.com/us/developer/docs/pages/Content/pages_variables_functions.htm&quot; target=&quot;_blank&quot;&gt;Visualforce functions&lt;/a&gt;.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Can it be done? &amp;nbsp;With the exception of the minimal polling time being 5 seconds, you know it!&amp;nbsp;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Here&#39;s the end result:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioOwOAEK3X3T-EQrHEyEptcnh2A9vGD1-8pLOGzZCZlIhHsd5pXEWA-Tmq3Ow8KBOK57TwqBbHYx0vwsuXLUzKb8cx0Ost8YfBqCz7V4W-SPZEt1PknEu1E1gx0pG5R5R_ulSUE95Ae3Q/s1600/output_Xz3v9r.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;310&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioOwOAEK3X3T-EQrHEyEptcnh2A9vGD1-8pLOGzZCZlIhHsd5pXEWA-Tmq3Ow8KBOK57TwqBbHYx0vwsuXLUzKb8cx0Ost8YfBqCz7V4W-SPZEt1PknEu1E1gx0pG5R5R_ulSUE95Ae3Q/s1600/output_Xz3v9r.gif&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Here&#39;s the Visualforce page:&lt;/div&gt;&lt;br /&gt;
&lt;script class=&quot;brush: js&quot; type=&quot;syntaxhighlighter&quot;&gt;&lt;![CDATA[
&lt;apex:page showHeader=&quot;true&quot; sidebar=&quot;true&quot;&gt;
 &lt;apex:sectionHeader title=&quot;What Color Is It?&quot; /&gt;
 &lt;apex:form&gt;
  &lt;apex:pageBlock&gt;
   &lt;apex:pageBlockSection columns=&quot;1&quot;&gt;
    &lt;apex:actionPoller interval=&quot;5&quot; reRender=&quot;timeBlock&quot; /&gt;
    
    &lt;apex:outputPanel id=&quot;timeBlock&quot; layout=&quot;block&quot; style=&quot;overflow:auto;width:100%;height:600px;background-color:#{!MID(TEXT(NOW()),12,2) + MID(TEXT(NOW()),15,2) + MID(TEXT(NOW()),18,2)}; color:#FFFFFF; text-align:center;&quot; &gt;
     
     &lt;apex:outputPanel &gt; 
      &lt;apex:image value=&quot;{!URLFOR($Resource.ColorClock)}&quot; /&gt;
     &lt;/apex:outputPanel&gt;

     &lt;apex:outputPanel layout=&quot;block&quot; style=&quot;font-size:100px&quot;&gt; 
      &lt;apex:outputText style=&quot;color:#0E0E0E;&quot; value=&quot;#&quot; /&gt;
      &lt;apex:outputText style=&quot;color:#FFFFFF;&quot; value=&quot;{!MID(TEXT(NOW()),12,8)}&quot;/&gt;
     &lt;/apex:outputPanel&gt;

    &lt;/apex:outputPanel&gt; 
   &lt;/apex:pageBlockSection&gt;
  &lt;/apex:pageBlock&gt;
 &lt;/apex:form&gt;
&lt;/apex:page&gt;

]]&gt;&lt;/script&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:card&quot; content=&quot;summary_large_image&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:site&quot; content=&quot;@crmscience&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:creator&quot; content=&quot;@kirkevonphilly&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:title&quot; content=&quot;What Color is It?&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:description&quot; content=&quot;The idea is simple... take the hour, minute, and second of the current time and use those values combined as the page background&#39;s hex color (#hhmmss).&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:image&quot; content=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioOwOAEK3X3T-EQrHEyEptcnh2A9vGD1-8pLOGzZCZlIhHsd5pXEWA-Tmq3Ow8KBOK57TwqBbHYx0vwsuXLUzKb8cx0Ost8YfBqCz7V4W-SPZEt1PknEu1E1gx0pG5R5R_ulSUE95Ae3Q/s1600/output_Xz3v9r.gif&quot;&gt;&lt;br /&gt;
</description><link>http://blog.crmscience.com/2014/12/what-color-is-it.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiKZVkbxcBTRxblsuZhDpJq6upLlySqw5g2T7D-xbg9bEMg68ZP3NgM_wimsLk6DmU2VSofTbmq0Spqn6ZPV1ifB2CvgUBmi8nRqu5whwlZ3mce_fayiPBcoWiA7qtgB3MCmkfltWVmHI/s72-c/WhatTimeIsIt.PNG" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-7582110795155845662</guid><pubDate>Fri, 10 Oct 2014 16:26:00 +0000</pubDate><atom:updated>2014-10-10T12:48:33.462-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">df14</category><category domain="http://www.blogger.com/atom/ns#">Dreamforce</category><category domain="http://www.blogger.com/atom/ns#">Visualforce</category><title>From Admin to Developer: Learning to Code on Force.com Resources</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://res.cloudinary.com/hy4kyit2a/image/upload/sd_social300x300_1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;200&quot; src=&quot;https://res.cloudinary.com/hy4kyit2a/image/upload/sd_social300x300_1.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;b&gt;From Admin to Developer: Learning to Code on Force.com&lt;/b&gt;&lt;br /&gt;
&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;span style=&quot;background-color: white; font-size: 17px; line-height: 24.285715103149414px;&quot;&gt;Are you an Administrator interested in learning more about how and when to use the programmatic tools in Salesforce? Join us for an introduction to Apex and Visualforce that is geared towards Salesforce Administrators. This session will include best practices, real life experiences with using code in Salesforce, and useful resources. You will leave this session with a foundation to start learning how to code in Salesforce and develop on the Force.com platform.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;span style=&quot;background-color: white; font-size: 17px; line-height: 24.285715103149414px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;span style=&quot;background-color: white; font-size: 17px; line-height: 24.285715103149414px;&quot;&gt;Use the links below to get started on your path to become a Developer!&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;span style=&quot;background-color: white; font-size: 17px; line-height: 24.285715103149414px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;span style=&quot;background-color: white; font-size: 17px; line-height: 24.285715103149414px;&quot;&gt;&lt;b&gt;Apex&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;span style=&quot;font-size: 17px; line-height: 24.285715103149414px;&quot;&gt;Guided Do-It-Yourself&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;span style=&quot;font-size: 17px; line-height: 24.285715103149414px;&quot;&gt;&lt;a href=&quot;http://www.salesforce.com/us/developer/docs/workbook/&quot; target=&quot;_blank&quot;&gt;Force.com Workbook &lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;a href=&quot;http://www.salesforce.com/us/developer/docs/apex_workbook/&quot; target=&quot;_blank&quot;&gt;Apex Workbook&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;span style=&quot;font-size: 17px; line-height: 24.285715103149414px;&quot;&gt;Follow Along&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: ProximaNovaRegular;&quot;&gt;&lt;span style=&quot;color: blue; font-size: 17px; line-height: 24.285715103149414px;&quot;&gt;&lt;a href=&quot;http://www.sfdc99.com/&quot; target=&quot;_blank&quot;&gt;sfdc99.com&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: blue; font-family: ProximaNovaRegular;&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=J4yX17_yxbI&quot; target=&quot;_blank&quot;&gt;Intro to Apex Code Webinar&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=LwDwmU0IkYk&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;color: blue;&quot;&gt;Introduction to Apex Triggers&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Azb31kE31ZA&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;color: blue;&quot;&gt;Hands-on Training: Get Started with Apex Code for Admins&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=n9amswhOxJw&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;color: blue;&quot;&gt;Hands-on Training: Write Apex Tests Using Best Practices&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;span style=&quot;font-size: 17px; line-height: 24.285715103149414px;&quot;&gt;Reading Documentation&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;span style=&quot;font-size: 17px; line-height: 24.285715103149414px;&quot;&gt;&lt;a href=&quot;https://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm&quot; target=&quot;_blank&quot;&gt;Force.com Apex Code Developer&#39;s Guide&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;a href=&quot;http://www.headfirstlabs.com/books/hfjava/&quot; target=&quot;_blank&quot;&gt;Head First Java by Kathy Sierra &amp;amp; Bert Bates 2nd edition&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=Development+with+the+Force.com+Platform+by+Jason+Ouellette&amp;amp;rlz=1C1CHFX_enUS586US586&amp;amp;oq=Development+with+the+Force.com+Platform+by+Jason+Ouellette&amp;amp;aqs=chrome..69i57.9927j0j4&amp;amp;sourceid=chrome&amp;amp;es_sm=0&amp;amp;ie=UTF-8&quot; target=&quot;_blank&quot;&gt;Development with the Force.com Platform by Jason Ouellette&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://advancedapex.com/&quot; target=&quot;_blank&quot;&gt;Advanced Apex Programming for Salesforce and Force.com by Dan Appleman&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://na1.salesforce.com/help/pdfs/en/salesforce_apex_developer_cheatsheet.pdf&quot; target=&quot;_blank&quot;&gt;Apex Code Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;span style=&quot;font-size: 17px; line-height: 24.285715103149414px;&quot;&gt;Independent Practice&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;span style=&quot;font-size: 17px; line-height: 24.285715103149414px;&quot;&gt;&lt;a href=&quot;https://developer.salesforce.com/signup&quot; target=&quot;_blank&quot;&gt;Developer Edition&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;span style=&quot;font-size: 17px; line-height: 24.285715103149414px;&quot;&gt;Advanced Learning&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;span style=&quot;font-size: 17px; line-height: 24.285715103149414px;&quot;&gt;&lt;a href=&quot;http://www.salesforce.com/us/developer/docs/dev_lifecycle/&quot; target=&quot;_blank&quot;&gt;Development Lifecycle Guide&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: ProximaNovaRegular;&quot;&gt;&lt;a href=&quot;http://developer.force.com/cookbook&quot; target=&quot;_blank&quot;&gt;Force.com Cookbook&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;a href=&quot;https://developer.salesforce.com/page/Apex&quot; target=&quot;_blank&quot;&gt;Apex Code Technical Library&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Visualforce&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;Guided Do-It-Yourself&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.salesforce.com/us/developer/docs/workbook/&quot; target=&quot;_blank&quot;&gt;Force.com Workbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.salesforce.com/us/developer/docs/workbook_vf/&quot; target=&quot;_blank&quot;&gt;Visualforce Workbook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Follow Allong&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.salesforce.com/page/Webinar:_Intro_to_Visualforce_(2012-Nov)&quot; target=&quot;_blank&quot;&gt;Webinar: Intro to Visualforce&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=1W_mDfDM2Ak&quot; target=&quot;_blank&quot;&gt;Hands-on Training: Get Started with Visualforce for Admins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=mgFjVBR5fNU&quot; target=&quot;_blank&quot;&gt;Introduction to Visualforce&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=fHeRlUO8UOo&quot; target=&quot;_blank&quot;&gt;7 Habits of Highly Efficient Visualforce Pages&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Reading Documentation&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.salesforce.com/page/An_Introduction_to_Visualforce&quot; target=&quot;_blank&quot;&gt;An Introduction to Visualforce&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.salesforce.com/us/developer/docs/pages/index.htm&quot; target=&quot;_blank&quot;&gt;Visualforce Developer&#39;s Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.developerforce.com/guides/Visualforce_in_Practice.pdf&quot; target=&quot;_blank&quot;&gt;Visualforce in Practice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.salesforce.com/docs/en/cce/salesforce_visualforce_best_practices/salesforce_visualforce_best_practices.pdf&quot; target=&quot;_blank&quot;&gt;Visualforce Performance: Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://na1.salesforce.com/help/pdfs/en/salesforce_visualforce_developer_cheatsheet.pdf&quot; target=&quot;_blank&quot;&gt;Visualforce Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Independent Practice&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.salesforce.com/signup&quot; style=&quot;font-family: ProximaNovaRegular; font-size: 17px; line-height: 24.285715103149414px;&quot; target=&quot;_blank&quot;&gt;Developer Edition&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Advanced Learning&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.salesforce.com/page/Webinar:_Advanced_Visualforce_(2012-Dec)&quot; target=&quot;_blank&quot;&gt;Webinar: Advanced Visualforce&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;a href=&quot;https://developer.salesforce.com/page/User_Interface&quot; target=&quot;_blank&quot;&gt;Visualforce Technical Library&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Community&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://success.salesforce.com/userGroups&quot; target=&quot;_blank&quot;&gt;User Groups&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.salesforce.com/dugs?title=page/Force.com_User_Groups&quot; target=&quot;_blank&quot;&gt;Salesforce Developer User Groups&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.salesforce.com/forums/#!/feedtype=RECENT&amp;amp;dc=Apex_Code_Development&amp;amp;criteria=ALLQUESTIONS&quot; target=&quot;_blank&quot;&gt;Apex Code Development Forum&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.salesforce.com/forums/#!/feedtype=RECENT&amp;amp;dc=Visualforce_Development&amp;amp;criteria=ALLQUESTIONS&quot; target=&quot;_blank&quot;&gt;Visualforce Development Forum&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.salesforce.com/events/webinars/forcedotcomfridayreg?d=70130000000lcfr&quot; target=&quot;_blank&quot;&gt;Force.com Friday&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/SalesforceDevs&quot; target=&quot;_blank&quot;&gt;@SalesforceDevs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Best of luck on your journey! &amp;nbsp;Let us know how it is going&amp;nbsp;&lt;complete id=&quot;goog_434598804&quot;&gt;@mgsherms @Scott_VS&lt;/complete&gt;&lt;br /&gt;
&lt;complete&gt;&lt;br /&gt;&lt;/complete&gt;&lt;/div&gt;
&lt;/div&gt;
</description><link>http://blog.crmscience.com/2014/10/from-admin-to-developer-resources.html</link><author>noreply@blogger.com (Anonymous)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-1452219635738389111</guid><pubDate>Fri, 10 Oct 2014 00:25:00 +0000</pubDate><atom:updated>2014-10-10T03:23:57.622-04:00</atom:updated><title>Integrating Salesforce to the Carvoyant API </title><description>The Internet of Things. IoT. The connected world. A paradigm shift known by many different names. While how exactly it will look may be unclear, it is quite clear that the technological world as we know it is undergoing a rapid and dynamic change. Pick a vertical, and we see the evolution. For instance, consider transportation, or more specifically cars. 
We&#39;ve come a long way from the horseless carriages of yore; every modern car has a computer in it that controls it&#39;s oprations called the Electronic Control Module (ECM). Not only does this control many of the car&#39;s functions, but it also digitizes these actions. While the ECM is specific to a particular manufacturer or vehicle, there is an interface called the &#39;On Board Diagnostic&#39; (OBD) connector that serves as a universal gateway to the digitized data of a car&#39;s inner workings.&lt;br /&gt;
&lt;br /&gt;
Taking advantage of this interface are devices such as Carvoyant&#39;s connector, which plugs in to the OBD device and collects your car&#39;s data for your use through their API. This allows you to retrieve details such as your cars movements and position, fuel usage, maintenance needs, and much more. For companies whose businesses revolve around many or a fleet of cars, the prospect of accessing their data on-demand and/or near real-time can be very attractive.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&amp;nbsp;Setting up Carvoyant&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;
&lt;b&gt;1. &lt;/b&gt;Refer to Carvoyant&#39;s getting started and documentation here:&amp;nbsp;&lt;a href=&quot;http://confluence.carvoyant.com/display/PUBDEV/Getting+Started&quot;&gt;http://confluence.carvoyant.com/display/PUBDEV/Getting+Started&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;2. &lt;/b&gt;Go to &lt;a href=&quot;http://developer.carvoyant.com/&quot;&gt;http://developer.carvoyant.com&lt;/a&gt; and register for a &lt;b&gt;user &lt;/b&gt;account.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;3. &lt;/b&gt;You will fill out some information for the application you create. The &quot;Register Callback URL&quot; field is very important -- this must be the page on which your web app performing the OAuth2 authentication is located and process the authorization code to exchange for the access token.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;4. &lt;/b&gt;Now that you have an account, we need some data. go to&amp;nbsp;&lt;a href=&quot;https://sandbox-driver.carvoyant.com/&quot;&gt;https://sandbox-driver.carvoyant.com/&lt;/a&gt; . Here you must register for a &lt;b&gt;driver &lt;/b&gt;account (different from the user account you set up earlier).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;5&lt;/b&gt;. Create a few cars. Either use your own cars&#39; VIN numbers or search the web for some of your favorite cars and use those. Don&#39;t tell them I sent you.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;6&lt;/b&gt;. Now let&#39;s make some trip data. Go to&amp;nbsp;&lt;a href=&quot;https://sandbox-simulator.carvoyant.com/&quot;&gt;https://sandbox-simulator.carvoyant.com/&lt;/a&gt; and login once again using your &lt;b&gt;driver &lt;/b&gt;account. Click on two points on the map and a series of waypoints will be created between them. You can add more color to your data with the properties to the left, such as fuel usage and engine temperature.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;7. &lt;/b&gt;That&#39;s it! We now have some data that we can use in Salesforce once we perform our integration.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&amp;nbsp;Salesforce Development&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;The API uses the standard server side OAuth2 authorization flow. This involves passing an application key and client secret to the API, getting back an authorization code, and exchanging this code for a token from the API. Authentication is complete and this token is then stored and used for subsequent callouts to the API.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;Let&#39;s do a simple callout to the API to get our vehicles and their positions. We will then store them as records in Salesforce and map their position on a Visualforce page with Google Maps. This is what we will end up with (or something similar for the data you create): 
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://1.bp.blogspot.com/-SmqfY8pCbDs/VDeGh31icAI/AAAAAAAAACk/6F9atquaDz8/s1600/dudewheresmycar2.tiff&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-SmqfY8pCbDs/VDeGh31icAI/AAAAAAAAACk/6F9atquaDz8/s1600/dudewheresmycar2.tiff&quot; height=&quot;192&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
The code below consists of a few components. We performed our authentication and saved our token and credentials in a custom setting. The class &quot;CarvoyantIntegration&quot; builds our HTTP request for us by using the results from authentication, the target API endpoint (https://sandbox-api.carvoyant.com/sandbox/api), and the resource/HTTP method passed in from our loadVehicles method. We deserialize the response from the Carvoyant API using the Vehicles/Vehicle inner classes, and thereby have the properties of the vehicle for our use later in the processVehicles method, where we take their values and create records in Salesforce.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&lt;script class=&quot;brush: java&quot; type=&quot;syntaxhighlighter&quot;&gt;
public class VehiclesLoader{

     public VehiclesLoader(){
        
        if(carvoyant == null){
        
        //Initialize the integration
        carvoyant = new CarvoyantIntegration();
        
        }
    }
    
    public class Vehicles {
    
        public list&lt;vehicle&gt; vehicle;
    }
    
    public class Vehicle {
        
        public string name;
        public string label;
        public string vehicleId;
        public string vin;
        public decimal mileage;
        public Coord lastWaypoint;
        public string year;
        public string make;
        public string model;
        
    }
    
    public class Coord{
        public decimal latitude;
        public decimal longitude;
    }
    
    public CarvoyantIntegration carvoyant;
    
    public string vehiclesResponseBody {get;set;}
    public CarvoyantIntegration.Response vehiclesResponse;
    
    public Vehicles vehiclesList;
    public list&lt;vehicle&gt; theVehicles;
    
    public void loadVehicles(){
    
        string resource = &#39;/vehicle&#39;;
        string method = &#39;GET&#39;;

        try {
            // call the integration to get the vehicles
            vehiclesResponse = carvoyant.Callout(resource, method);
        
            if (vehiclesResponse.success) {
                           
                // deserialize the json response
                vehiclesList = (vehicles)JSON.deserialize(vehiclesResponse.body, vehicles.class);
                theVehicles = vehiclesList.vehicle;

               //create records from the response data
               processVehicles(vehicles);
               
            } else {
                // callout failed - Log the bad response
            }
        } catch (exception e) {
            // callout failed - Log the bad response
        }  
    
    }
    
    public void processVehicles(list&lt;vehicle&gt; vs){
        
        list&lt;vehicle__c&gt; vehicles = new list&lt;vehicle__c&gt;();    
        for(Vehicle each : vs){
            Vehicle__c v = new Vehicle__c(name = each.label,
                                          vehicle_id__c = each.vehicleId, 
                                          mileage__c = each.mileage, 
                                          last_waypoint__longitude__s = each.lastWaypoint.longitude,
                                          last_waypoint__latitude__s = each.lastWaypoint.latitude,
                                          vin__c = each.vin, 
                                          year__c = each.year, 
                                          make__c = each.make,
                                          model__c = each.model);
            vehicles.add(v);
        }
        upsert vehicles vehicle_id__c;
    }
}
&lt;/script&gt;The class below contains a getter that merely fetches the vehicle data created from our callouts for use in our visualforce page.&lt;br /&gt;
&lt;br /&gt;
We will use some of the properties in our table of vehicle information, and use the last waypoint latitude/longitude to map the last known location of the vehicles.

&lt;script class=&quot;brush: java&quot; type=&quot;syntaxhighlighter&quot;&gt;
public class vehiclesPage {

    public vehiclesPage(VehiclesLoader controller){}
    public list&lt;vehicle__c&gt; getVehicles(){
    
        list&lt;vehicle__c&gt; vehicles = [SELECT id,name,vin__c, last_waypoint__latitude__s, 
                                            last_waypoint__longitude__s, mileage__c, 
                                            year__c, make__c, model__c FROM vehicle__c];
        
    
        return vehicles;
    }

}
&lt;/script&gt;

The page has code for displaying vehicle record information as well as creating markers for the vehicles we queried for inthe controller above. Check out&amp;nbsp;&lt;a href=&quot;http://blog.crmscience.com/2014/09/lab-coat-lesson-google-maps-api.html&quot;&gt;http://blog.crmscience.com/2014/09/lab-coat-lesson-google-maps-api.html&lt;/a&gt; for more detailed information about the Google Maps Javascript API.&lt;script class=&quot;brush: xml&quot; type=&quot;syntaxhighlighter&quot;&gt;
&lt;apex:page controller=&quot;VehiclesLoader&quot; extensions=&quot;VehiclesPage&quot;&gt;
   &lt;apex:form &gt;
     &lt;apex:commandButton action=&quot;{!loadVehicles}&quot; rerender=&quot;vehiclesPanel&quot; value=&quot;Load&quot;/&gt;
     &lt;apex:outputPanel id=&quot;vehiclesPanel&quot;&gt;
     &lt;apex:sectionHeader title=&quot;Carvoyant&quot; subtitle=&quot;My Cars&quot;/&gt;
     &lt;apex:pageBlock &gt;
         &lt;apex:pageBlockSection columns=&quot;2&quot;&gt;
         &lt;apex:pageBlockTable value=&quot;{!vehicles}&quot; var=&quot;v&quot; &gt;
             &lt;apex:column &gt;
                 &lt;apex:commandButton value=&quot;Load Routes&quot; rerender=&quot;null&quot;/&gt;
             &lt;/apex:column&gt;
             &lt;apex:column headerValue=&quot;Name&quot; &gt;
                 {!v.name}
             &lt;/apex:column&gt;
             &lt;apex:column headerValue=&quot;Year&quot;&gt;
                 {!v.Year__c}
             &lt;/apex:column&gt;
             &lt;apex:column headerValue=&quot;Make&quot;&gt;
                 {!v.Make__c}
             &lt;/apex:column&gt;
             &lt;apex:column headerValue=&quot;Model&quot;&gt;
                 {!v.Model__c}
             &lt;/apex:column&gt;
             &lt;apex:column headerValue=&quot;Mileage&quot;&gt;
                 {!v.Mileage__c}
             &lt;/apex:column&gt;
         &lt;/apex:pageblockTable&gt;
         &lt;apex:outputPanel &gt;
         
           &lt;div style=&quot;width:600px;height:400px;&quot;&gt;
              &lt;div id=&quot;map-canvas&quot; style=&quot;width: 100%; height: 100%&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/apex:outputPanel&gt;
         &lt;/apex:pageBlockSection&gt;
    &lt;/apex:pageBlock&gt;
   
   
   &amp;lt;script type=&quot;text/javascript&quot; src=&quot;https://maps.googleapis.com/maps/api/js?sensor=false&quot;&amp;gt;&amp;lt;/script&amp;gt;
  
  
  &amp;lt;script type=&quot;text/javascript&quot;&amp;gt;
     var map;
    
      function initialize() {
      var mapOptions = {
        zoom: 8,
        center: new google.maps.LatLng({!Vehicles[0].last_waypoint__latitude__s}, {!Vehicles[0].last_waypoint__longitude__s})
      };

       map = new google.maps.Map(document.getElementById(&#39;map-canvas&#39;),
          mapOptions);
     
    
     &lt;apex:repeat value=&quot;{!vehicles}&quot; var=&quot;v&quot;&gt;
         
         var latLng = new google.maps.LatLng({!v.Last_Waypoint__Latitude__s},{!v.Last_Waypoint__Longitude__s});
         var marker = new google.maps.Marker({
             position : latLng,
             title:&quot;{!v.name}&quot;
         });
         marker.setMap(map);
         
           var infowindow = new google.maps.InfoWindow({
                  content: &#39;{!v.name}&#39;
                  });
                  
         google.maps.event.addListener(marker, &#39;click&#39;, function() {
            infowindow.open(map,marker);
          });
          
        
     &lt;/apex:repeat&gt;
      
    }
    
    window.onload = initialize;
  
  &amp;lt;/script&amp;gt;

   
   
  &lt;/apex:outputPanel&gt;
   &lt;/apex:form&gt;  
&lt;/apex:page&gt;
&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
What&#39;s next? Maybe you want to go in the direction of getting data for your vehicles when there is a change. You can use Carvoyant&#39;s subscription service and the Salesforce Streaming API as they have described here to do that &lt;a href=&quot;http://confluence.carvoyant.com/display/PUBDEV/Force.com&quot;&gt;http://confluence.carvoyant.com/display/PUBDEV/Force.com&lt;/a&gt; 
Perhaps you want to send emails when something goes wrong with a car, or better yet perform some preventative actions when a car hits certain threshold data points during their usage, such as mileage and engine temperatures. Or maybe you want to be able to know when certain cars enter certain areas you demarcate known as Geofences. 
&lt;br /&gt;
&lt;br /&gt;
While we are only beginning our journey into the connected world, steps like these will prove to be instrumental in guiding that course and our expectations of it. Do we want cars to communicate with eachother? Perhaps leading to more efficient routing and a final end to traffic jams? Can we optimize our infrastructure through analysis of this data? Will this sort of thing help us keep an eye out on our autonomous cars? Control them even? There is a plethora of ideas in this realm that are waiting to be implemented. And what&#39;s next... you decide. 
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
</description><link>http://blog.crmscience.com/2014/10/integrating-salesforce-to-carvoyant-api.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-SmqfY8pCbDs/VDeGh31icAI/AAAAAAAAACk/6F9atquaDz8/s72-c/dudewheresmycar2.tiff" height="72" width="72"/></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-6873754788148632858</guid><pubDate>Sun, 05 Oct 2014 23:23:00 +0000</pubDate><atom:updated>2015-09-30T22:24:32.874-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">arduino</category><category domain="http://www.blogger.com/atom/ns#">Callout</category><category domain="http://www.blogger.com/atom/ns#">iot</category><category domain="http://www.blogger.com/atom/ns#">webservice</category><title>Lab Coat Lesson:  Salesforce Arduino Gateway</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsV29zI_PvagW76iGhpZhWtMkO-oTuwR_YprIldwMowSQyFUIdFjZNlUreukSX5N1wZMOY5gHsIDBImcibYqlkgMOAOSttw2BVq45h-O1jC6EjuY1FfQ6cLSvgw_GvZUNj6LVEh0IfYZM/s1600/labcoat_header.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsV29zI_PvagW76iGhpZhWtMkO-oTuwR_YprIldwMowSQyFUIdFjZNlUreukSX5N1wZMOY5gHsIDBImcibYqlkgMOAOSttw2BVq45h-O1jC6EjuY1FfQ6cLSvgw_GvZUNj6LVEh0IfYZM/s1600/labcoat_header.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
The maker movement is alive, well, and has been very much reinvigorated over the last few years. Makers and tinkerers have been creating amazing projects and supporting each other in a large online community, not all too different from our own Salesforce community. The tail end of 2013 and 2014 brought a wave of &quot;smart&quot; wearable tech - 2015 will be no different (check out some of the ideas on &lt;a href=&quot;http://www.kickstarter.com/&quot; target=&quot;_blank&quot;&gt;Kickstarter&lt;/a&gt;).&lt;br /&gt;
&lt;br /&gt;
The contributions to hobby electronics made by companies like &lt;a href=&quot;http://www.arduino.com/&quot; target=&quot;_blank&quot;&gt;Arduino&lt;/a&gt;, &lt;a href=&quot;http://www.adafruit.com/&quot; target=&quot;_blank&quot;&gt;Adafruit&lt;/a&gt;, and &lt;a href=&quot;http://www.sparkfun.com/&quot; target=&quot;_blank&quot;&gt;Sparkfun&lt;/a&gt; make it possible for anyone (yes, anyone - including you) to create a physical working version of something you thought would be a great idea. &amp;nbsp;Think web controlled pet bowls, smart fishtanks, web-enabled weather logging stations, sun tracking window blinds...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Adafruit created the &lt;a href=&quot;https://www.adafruit.com/products/1469&quot; target=&quot;_blank&quot;&gt;CC3000&lt;/a&gt;, a Wi-Fi enabled breakout board (also, available as a shield), featuring a Texas Instrument chips that allowed you to add Wi-Fi capabilities to your projects. &amp;nbsp;You could now send web requests to servers or even treat your device as a basic web server to receive requests. &amp;nbsp; &amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Then along came the &lt;a href=&quot;http://arduino.cc/en/Main/ArduinoBoardYun?from=Main.ArduinoYUN#.Uwj1vpBDt5Q&quot; target=&quot;_blank&quot;&gt;Arduino&amp;nbsp;Yún&lt;/a&gt; (Chinese for &quot;cloud&quot;, by the way) board - the best of the Arduino you may already know and love with a bridge over to an embedded linux chip. &amp;nbsp;Now you&#39;ve got more flexibility in you data processing and web handling. &amp;nbsp;You could easily a Raspberry Pi (fairly inexpensive embedded linux board) for the project in this post, but then you lose out on the fun of working with the new Yún. &amp;nbsp;If it were up to me, I&#39;d be saying in my best Oprah voice, &quot;You get a Yún!...&amp;nbsp;and you get a Yún!...&amp;nbsp;and you get a Yún!...) while living in a house made of Yúns - big fan &lt;a href=&quot;http://www.massimobanzi.com/&quot; target=&quot;_blank&quot;&gt;Massimo Banzi&lt;/a&gt;, big fan.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;So what are we going to build? &amp;nbsp; &lt;strike&gt;How about a little switch box to help quickly destroy all the evidence?&lt;/strike&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMGSq4tH1yVJzKLR72rF-qIOitrRYbB30cz4zBl24l71Q3sal88MyD76E5hkSCpWWqME3gdBjCRxpo-dqN4Kh9j7gIGBLUp1YgXDI5u68TegztqHWTKbDgU-LANPZA9dsAgNcBy5DBuHo/s1600/_20140222_140208.JPG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMGSq4tH1yVJzKLR72rF-qIOitrRYbB30cz4zBl24l71Q3sal88MyD76E5hkSCpWWqME3gdBjCRxpo-dqN4Kh9j7gIGBLUp1YgXDI5u68TegztqHWTKbDgU-LANPZA9dsAgNcBy5DBuHo/s1600/_20140222_140208.JPG&quot; height=&quot;404&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Alright - let&#39;s not be destructive, so let&#39;s create a few test records via the push of a button. &lt;br /&gt;
&lt;br /&gt;
Sure, you could always execute the same script anonymously, but let&#39;s be honest, this seems like more fun!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;How&#39;s this going to work? &amp;nbsp;We&#39;ll wire together an Arduino&amp;nbsp;Yún and connect to it an LCD and a rotary knob. &amp;nbsp;Users will twist the rotary knob clockwise or couter-clockwise to select an object (Account, Contact, Lead, Opportunity, or Case). &amp;nbsp;The user will then push the knob (hooray, built in switch!) which will send a request across the Yún&#39;s bridge to the linux side to kick off a Python script. &amp;nbsp;This script will callout to your Salesforce Org, which will be using an Apex Rest class to &lt;strike&gt;kick off the destruction&lt;/strike&gt;&amp;nbsp;create copious amounts of test data and send back a response to the board.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiapl9X217qHc30Yfrk9NjEFAEu_2uBL7yop-W3Aqv-5ToOEjehe_AzrcbAiCdw2yDoTwErF88F093JAHB5oRtnG5JD3mW9JS8sguSGnx9IBXyk3WVUYk0VLxtJak2up5lVSq2tPzY4JbE/s1600/IMG_20141006_093911_a.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiapl9X217qHc30Yfrk9NjEFAEu_2uBL7yop-W3Aqv-5ToOEjehe_AzrcbAiCdw2yDoTwErF88F093JAHB5oRtnG5JD3mW9JS8sguSGnx9IBXyk3WVUYk0VLxtJak2up5lVSq2tPzY4JbE/s1600/IMG_20141006_093911_a.jpg&quot; height=&quot;330&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Not so pretty.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div&gt;&lt;h3&gt;What You&#39;ll Need:&lt;/h3&gt;&lt;/div&gt;&lt;h4&gt;Hardware&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;http://www.adafruit.com/products/1498&quot; target=&quot;_blank&quot;&gt;Arduino&amp;nbsp;Yún&lt;/a&gt;&amp;nbsp;(1)&lt;/li&gt;
&lt;li&gt;&lt;u&gt;&lt;a href=&quot;http://www.adafruit.com/products/377&quot; target=&quot;_blank&quot;&gt;Rotary Encoder Switch&lt;/a&gt;&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.adafruit.com/product/782&quot; target=&quot;_blank&quot;&gt;LCD w/ Serial Backpack&lt;/a&gt; (backpack allows for LCD use with only 5V, ground, and one data lead instead of the normal rats nest)&lt;/li&gt;
&lt;/ol&gt;&lt;h4&gt;Software&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;http://developer.force.com/&quot; target=&quot;_blank&quot;&gt;A Dev Org&lt;/a&gt;&amp;nbsp;(or sandbox, but definitely not production)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://arduino.cc/en/Main/Software&quot; target=&quot;_blank&quot;&gt;Arduino 1.5.5&amp;nbsp;&lt;/a&gt;(beta or later - support for Yún necessary)&lt;/li&gt;
&lt;/ol&gt;&lt;h3&gt;Wiring&lt;/h3&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVz3CMjIwniIn1Y13Z4Nrt_FW4T-Cq6f0fQ5Gm6on4SNV1-mr5VV1jhuTodgTzmvhhz093Xpa0YXxHAczZLHECdH9sRUp_tixV4lszBCRLMIZTkC-4FX5erXNMP-GN9BRSDOMEPP8vGoY/s1600/ArduinoGateway.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVz3CMjIwniIn1Y13Z4Nrt_FW4T-Cq6f0fQ5Gm6on4SNV1-mr5VV1jhuTodgTzmvhhz093Xpa0YXxHAczZLHECdH9sRUp_tixV4lszBCRLMIZTkC-4FX5erXNMP-GN9BRSDOMEPP8vGoY/s1600/ArduinoGateway.png&quot; height=&quot;392&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Note: &amp;nbsp;I&#39;m using the LCD Backpack (linked above) that uses 3 wires. &amp;nbsp;The above locations on the LCD are not correct and don&#39;t represent the use of the backpack.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;h3&gt;Apex Class: &amp;nbsp;ArduinoGateway&lt;/h3&gt;&lt;/div&gt;&lt;div&gt;&lt;script class=&quot;brush: java&quot; type=&quot;syntaxhighlighter&quot;&gt;
&lt;![CDATA[
@RestResource(urlMapping=&#39;/ArduinoGateway/*&#39;)
global class ArduinoGateway {
 public static RestRequest req;
    public static RestResponse res;
    public class ReqException extends Exception {}
    public class ArduinoRequest {
        public string objType { get; set; }
        public integer num { get; set; }
        
        public ArduinoRequest(string objType, integer num){
            this.objType = objType;
            this.num = num;
        }
    }
    
    @HttpPost
    global static void doPost() {
        //  Populate the req and res vars from the request
        req = RestContext.request;
        res = RestContext.response;
        
        system.debug(&#39;req:  &#39; + req.requestBody.toString());
        system.debug(&#39;body:  &#39; + (ArduinoRequest)JSON.deserialize(req.requestBody.toString(), ArduinoRequest.class));
        //  Set up an initial status - worst case
        string status = &#39;error&#39;;
        integer recCount = 0;
        
        //  Handle Request
        try {
            
            ArduinoRequest ar = (ArduinoRequest)JSON.deserialize(req.requestBody.toString(), ArduinoRequest.class);

            list&lt;sobject&gt; objects = new list&lt;sobject&gt;();
            for (integer i = 0; i &lt; ar.num; i++) {
                if (ar.objType == &#39;Account&#39;)
                    objects.add(new Account(Name = &#39;Test Account: &#39; + i));
                else if (ar.objType == &#39;Lead&#39;)
                    objects.add(new Lead(Company = &#39;Test Company&#39;, FirstName = &#39;Test&#39;, LastName = &#39;Lead:  &#39; + i));
                
                // ... handle the other object types - don&#39;t forget required fields
            }
            
            //  Commit any new sObjects
            if (!objects.isEmpty()) {
             insert objects;
            }
   
            //  Create success response for caller
            res.responseBody = prepResponse(&#39;success&#39;, &#39;Records created successfully&#39;);
         system.debug(&#39;Response:  &#39; + res);
        } catch (exception ex) {
             //  Create error response for caller
            res.responseBody = prepResponse(&#39;error&#39;, &#39;Error creating records:  &#39; + ex.getMessage());
        }
    }
    
    public static blob prepResponse(string status, string details) {
        //  New JSONGenerator obect for crafting a response;
        JSONGenerator gen = JSON.createGenerator(true);
        gen.writeStartObject();
        gen.writeStringField(&#39;status&#39;, &#39;success&#39;);
        gen.writeStringField(&#39;details&#39;, &#39;Records created successfully&#39;);
        gen.writeEndObject();
        return blob.valueOf(gen.getAsString());
    }
}
]]&gt;
&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRx8WCieyLJgDKnyER8h3qU3_kVv6BQupJWmS_7tOWNTckEyyU7fwF9mNuIQmJeeRCZvwSIEfxOw7lbzQWj5jkIppIQ36aKlm6zj_WWS22R7EkYgBAcLRIImYICmatwRsXMdqgqXMhma0/s1600/DebugLog.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRx8WCieyLJgDKnyER8h3qU3_kVv6BQupJWmS_7tOWNTckEyyU7fwF9mNuIQmJeeRCZvwSIEfxOw7lbzQWj5jkIppIQ36aKlm6zj_WWS22R7EkYgBAcLRIImYICmatwRsXMdqgqXMhma0/s1600/DebugLog.png&quot; height=&quot;116&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Debug Log Output&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;h3&gt;&lt;/h3&gt;&lt;h3&gt;Connected App&lt;/h3&gt;&lt;/div&gt;&lt;div&gt;We&#39;ll use a Connected App to provide us with an endpoint to authenticate against so we can securely use our custom Apex Rest classes.&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Setup --&amp;gt; Build --&amp;gt; Create --&amp;gt; Apps&lt;/li&gt;
&lt;li&gt;Scroll down to the &quot;Connected Apps&quot; section&lt;/li&gt;
&lt;li&gt;Click on the &quot;New&quot; button&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhki6tHDX_zWFK3oFXBR2AfizsJ96M7ITvy3z681Aj756JHM-Moa2PGGSCGNWuejelgG0SaccJS8qOZyPB1soIhI2WfHoQZmPd3Knt12iRYdzwhPdCgXCdbHJ1bV2wMBZlyG2Mve_8ZGyo/s1600/Selection_011.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhki6tHDX_zWFK3oFXBR2AfizsJ96M7ITvy3z681Aj756JHM-Moa2PGGSCGNWuejelgG0SaccJS8qOZyPB1soIhI2WfHoQZmPd3Knt12iRYdzwhPdCgXCdbHJ1bV2wMBZlyG2Mve_8ZGyo/s1600/Selection_011.png&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Populate the &quot;Connected App&quot; details&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigDRCS3B4TLtrjX3WJluV6Ci8qdrFj3puQvPBHaStKJ6wh9sbHbqzuwMc9IOMobTjJ00uJfB4F7-aS5hic96o4C3UxhEPm_CM4GGbn7yI_vFkDZzzKGOqmPfBzCpvsToMZVk1Ca74j58c/s1600/Blog_A.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigDRCS3B4TLtrjX3WJluV6Ci8qdrFj3puQvPBHaStKJ6wh9sbHbqzuwMc9IOMobTjJ00uJfB4F7-aS5hic96o4C3UxhEPm_CM4GGbn7yI_vFkDZzzKGOqmPfBzCpvsToMZVk1Ca74j58c/s1600/Blog_A.PNG&quot; height=&quot;282&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Check the &quot;Enable OAuth Settings&quot; checkbox and provide the following details:&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-M0ierbX7yUTC4k5LY_tlP3-zTZ30SG_v0wzwXzMqbW9sJGI8Yi8H4KbfHFp4ra0KcfRsvGpV6uvuImfYO-1tfNkmAY535x9Eubvi09R_g2aV0zRwa6b9SHuZKM4BfC2rsm0ymv7gy5M/s1600/Blog_B.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-M0ierbX7yUTC4k5LY_tlP3-zTZ30SG_v0wzwXzMqbW9sJGI8Yi8H4KbfHFp4ra0KcfRsvGpV6uvuImfYO-1tfNkmAY535x9Eubvi09R_g2aV0zRwa6b9SHuZKM4BfC2rsm0ymv7gy5M/s1600/Blog_B.PNG&quot; height=&quot;104&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Click on the &quot;Save&quot; button&lt;/li&gt;
&lt;li&gt;Copy the Consumer Key and the Consumer Secret - you&#39;ll need these for the Python script below&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoDLKIZZ8idIPCPbiEbgeWUlf92eXPz5C282nEOeKMEXc32wfqQhpju2sfsZCoGXhShRt3_StZuOhLe0gQqURCIzg3ZdedwaDXne_A1mBfX8j4jDQGLNu1Ub0iJ485Ylx7WlKhDhAqkso/s1600/Selection_014.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoDLKIZZ8idIPCPbiEbgeWUlf92eXPz5C282nEOeKMEXc32wfqQhpju2sfsZCoGXhShRt3_StZuOhLe0gQqURCIzg3ZdedwaDXne_A1mBfX8j4jDQGLNu1Ub0iJ485Ylx7WlKhDhAqkso/s1600/Selection_014.png&quot; height=&quot;168&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3&gt;&lt;/h3&gt;&lt;h3&gt;Arduino Sketch: &amp;nbsp;ArduinoGateway.ino&lt;br /&gt;
&lt;span style=&quot;font-weight: normal;&quot;&gt;Overview: &amp;nbsp;Our sketch is very simple - in a nutshell, when we flipping our final switch runs a Python script. &amp;nbsp;More verbosely, after the&amp;nbsp;Yún board boots, it will be listening for a signal on the switchPin (13). &amp;nbsp;The switchPin will be hot after our final safety toggle is flipped (and illuminated!). &amp;nbsp;At that moment, we&#39;ll use the&amp;nbsp;Yún&#39;s&amp;nbsp;bridge from the Arduino side to the linux side to kick off a new Python process to run our script to call out to our Salesforce endpoint.&lt;/span&gt;&lt;/h3&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;script class=&quot;brush: java&quot; type=&quot;syntaxhighlighter&quot;&gt;
//  Libraries to include
#include &lt;Console.h&gt;
#include &lt;ClickEncoder.h&gt;
#include &lt;TimerOne.h&gt;
#include &lt;SoftwareSerial.h&gt;

//  Properties for later use
SoftwareSerial lcd = SoftwareSerial(0,2);
ClickEncoder *encoder;
int16_t last, value;
uint8_t red, green, blue;

//  Standard setup() method
void setup() {
  //  Set up serial for debugging
  Serial.begin(9600);

  //  Set up the Yun&#39;s bridge/console
  Bridge.begin();
  Console.begin();
  while(!Console) {;}

  //  Initalize an encode so we can twist/click the knob
  encoder = new ClickEncoder(A1, A0, A2);

  //  Initalize a timer to be used by encoder
  Timer1.initialize(1000);
  Timer1.attachInterrupt(timerIsr);

  last = -1;

  setupLCD();
}

//  Standard loop method
void loop() {
  value += encoder-&gt;getValue();
  if (value != last) {
    if (value == 20)
     value = 0;
    else if (value == -20)
      value = -0;
   
    last = value;

    //  Output to serial the current value and corresponding selection
    Serial.print(&quot;Encoder Value: &quot;);
    Serial.println(value);
    Serial.print(&quot;Object Value:  &quot;);
    Serial.println(getObjType(value));
  }

  ClickEncoder::Button b = encoder-&gt;getButton();
  if (b != ClickEncoder::Open) {
    Serial.print(&quot;Button: &quot;);
    #define VERBOSECASE(label) case label: Serial.println(#label); break;
    switch (b) {
      case ClickEncoder::Clicked:
        Serial.println(&quot;ClickEncoder::Clicked&quot;);
        updateLCD(&quot;Calling Out!&quot;,getObjType(value));
        CallSFDC(getObjType(value));
        updateLCD(&quot;Calling Out!&quot;,getObjType(value));
        break;
    }
  }
  delay(2000);
}

//  Required for rotary encoder knob functionality
void timerIsr() {
  encoder-&gt;service();
}

//  Initialize the LCD
void setupLCD() {
  lcd.begin(9600);

  // Specify your LCD size (16x2 in our example)
  lcd.write(0xFE);
  lcd.write(0xD1);
  lcd.write(16);  // 16 columns
  lcd.write(2);   // 2 rows
  delay(10);    

  //  Hide the LCD cursor
  lcd.write(0xFE);
  lcd.write(0x4B);
  lcd.write(0xFE);
  lcd.write(0x54);

  //  Contrast (0 - min, 255, max)
  lcd.write(0xFE);
  lcd.write(0x50);
  lcd.write(255);
  delay(10);    

  //  Brightness (0 - min, 255, max)
  lcd.write(0xFE);
  lcd.write(0x99);
  lcd.write(255);
  delay(10);    
}

//  Write top/bottom strings to LCD
void updateLCD(String a, String b){
  //  Clear what&#39;s on the screen
  lcd.write(0xFE);
  lcd.write(0x58);
  delay(10);

  //  Go to the home position
  lcd.write(0xFE);
  lcd.write(0x48);
  delay(10);

  //  Populate top/bottom lines
  lcd.print(a);
  lcd.println(b);
  delay(100);
}

//  Every +/- 4 rotary &quot;clicks&quot; is another sObject
String getObjType(int16_t i) {
  if (i == 0) {
    updateLCD(&quot;Lead&quot;,&quot;&quot;);
    return &quot;Lead&quot;;
  }
  else if ((i &gt; 0 &amp;&amp; i &lt;= 4) || (i &lt; -12 &amp;&amp; i &gt;= -16)) {
    updateLCD(&quot;Contact&quot;,&quot;&quot;);
    return &quot;Contact&quot;;
  }
  else if ((i &gt; 4 &amp;&amp; i &lt;= 8) || (i &lt; -8 &amp;&amp; i &gt;= -12)) {
    updateLCD(&quot;Account&quot;,&quot;&quot;);
    return &quot;Account&quot;;
  }
  else if ((i &gt; 8 &amp;&amp; i &lt;= 12) || (i &lt; -4 &amp;&amp; i &gt;= -8)) {
    updateLCD(&quot;Opportunity&quot;,&quot;&quot;);
    return &quot;Opportunity&quot;;
  }
  else if ((i &gt; 12 &amp;&amp; i &lt;= 16) || (i &lt; 0 &amp;&amp; i &gt;= -4)) {
    updateLCD(&quot;Case&quot;,&quot;&quot;);
    return &quot;Case&quot;;
  }
  else {
    return &quot;true&quot;;
  }
  delay(1000);
}

/*  Portion of sketch that uses linux side of Yun to initial
    a Python script to callout to SF
*/
void CallSFDC(String objType) {
  Process p;
  p.begin(&quot;python&quot;);
  p.addParameter(&quot;/home/root/ArduinoGateway/CallSalesforce.py&quot;);

  //  Specify the sObject type to create
  p.addParameter(&quot;-o&quot;);
  p.addParameter(objType);

  //  Specify how many sObject records to create
  p.addParameter(&quot;-n&quot;);
  p.addParameter(&quot;1&quot;);

  //  Kick-off the Python script
  Serial.println(p.run());

  //  Introduce delay to before
  delay(10000);
}
&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;After you&#39;ve uploaded the Arduino sketch to the Yun, using the Arduino IDE, you&#39;ll need to create the Python script. &amp;nbsp;Here are the general steps to do so:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;ssh &amp;lt;username&amp;gt;@&amp;lt;yun_ip_address&amp;gt; (IE: &amp;nbsp;root@192.168.1.8)&lt;/li&gt;
&lt;li&gt;If prompted, enter your password (Default: &amp;nbsp;arduino)&lt;/li&gt;
&lt;li&gt;&quot;Yes&quot; if prompted to add RSA key to list of known hosts&lt;/li&gt;
&lt;li&gt;cd /&lt;/li&gt;
&lt;li&gt;ls&lt;/li&gt;
&lt;li&gt;mkdir -p /home/root/ArduinoGateway/&lt;/li&gt;
&lt;li&gt;vi /home/root/ArduinoGateway/CallSalesforce.py&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;h3&gt;Python Script: &amp;nbsp;CallSalesforce.py &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/h3&gt;&lt;/div&gt;&lt;div&gt;&lt;script class=&quot;brush: java&quot; type=&quot;syntaxhighlighter&quot;&gt;
import os                                                                                                                        
import urllib                                                                                                                    
import urllib2                                                                                                                  
import json                                                                                                                      
import pprint                                                                                                                    
                                                                                                                                 
import sys, getopt                                                                                                              
                                                                                                                                 
def main(argv):                                                                                                                  
                                                                                                                                 
# Grab credentials from the environment                                                                                          
        consumer_key = &#39;&lt;consumer_key&gt;&#39;;                
        consumer_secret = &#39;&lt;consumer_secret&#39;;                                                                          
        username = &#39;&lt;username&gt;&#39;;                                                                                
        password = &#39;&lt;password&gt;&#39;;                                                                
        login_server = &#39;https://login.salesforce.com&#39;;                                                                          
                                                                                                                                 
        # Do OAuth username/password                                                                                            
        token_url = login_server+&#39;/services/oauth2/token&#39;                                                                        
                                                                                                                                 
        objectType = &#39;&#39;                                                                                                          
        num = 0                                                                                                                  
                                                                                                                                 
        try:                                                                                                                    
                opts, args = getopt.getopt(argv,&quot;ho:n:&quot;,[&quot;object=&quot;, &quot;number=&quot;])                                                  
        except getopt.GetoptError:                                                                                              
                print &#39;ArduinoGateway.py -o &lt;object type&gt; -n &lt;number of records&gt;&#39;                                                
                sys.exit(2)                                                                                                      
        for opt, arg in opts:                                                                                                    
                if opt == &#39;-h&#39;:                                                                                                  
                        print &#39;ArduinoGateway.py -o &lt;object type&gt; -n &lt;number of records&gt;&#39;                                        
                elif opt in (&quot;-o&quot;, &quot;--object&quot;):                                                                                  
                        objectType = arg                                                                                        
                elif opt in (&quot;-n&quot;, &quot;--number&quot;):                                                                                  
                        num = arg                                                                                                
                                                                                                                                 
        print &#39;object:  &#39;, objectType                                                                                            
        print &#39;num:  &#39;, num                                                                                                      
                                                                                                                                 
                params = urllib.urlencode({                                                                                              
                &#39;grant_type&#39;: &#39;password&#39;,                                                                                        
                &#39;client_id&#39;: consumer_key,                                                                                      
                &#39;client_secret&#39;: consumer_secret,                                                                                
                &#39;username&#39;: username,                                                                                            
                &#39;password&#39;: password                                                                                            
                })                                                                                                              
                                                                                                                                 
        try:                                                                                                                    
                data = urllib2.urlopen(token_url,params).read()                                                                  
                print &#39;Response Header:  &quot;%s&quot;&#39; % data                                                                            
                oauth = json.loads(data)                                                                                        
                pprint.pprint(oauth)                                                                                            
                                                                                                                                 
                                                                                                                                 
                query_url = oauth[&#39;instance_url&#39;]+&#39;/services/apexrest/ArduinoGateway&#39;;                                          
                headers = {                                                                                                      
                        &#39;Authorization&#39;: &#39;OAuth &#39;+oauth[&#39;access_token&#39;],                                                        
                        &#39;Content-Type&#39;: &#39;application/json&#39;                                                                      
                }                                                                                                                
                body = {&quot;objType&quot;:objectType,&quot;num&quot;:num}                                                                          
                req = urllib2.Request(query_url, json.dumps(body), headers)                                                      
                data = urllib2.urlopen(req).read()                                                                              
                result = json.loads(data)                                                                                        
                pprint.pprint(result)                                                                                            
                                                                                                                                 
        except IOError, e:                                                                                                      
                if hasattr(e, &#39;code&#39;): # HTTPError                                                                              
                        print &#39;http error code: &#39;, e.code                                                                        
                elif hasattr(e, &#39;reason&#39;): # URLError                                                                            
                        print &quot;can&#39;t connect, reason: &quot;, e.reason                                                                
                else:                                                                                                            
                        raise
if __name__ == &quot;__main__&quot;:                                                                                                      
        main(sys.argv[1:])
&lt;/script&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;So there you have it - with all those pieces in place, you should be able to twist the knob and cycle through the various sObject types. &amp;nbsp;Within the Apex Class above, we only handle Lead and Account scenarios - but you can just as freely modify all of the code to kick off any Apex code via the webservice class. &amp;nbsp;Likewise, within the Python script, you&#39;ll see that it&#39;s currently configured to take two parameters, one for the object type and one for the number of records to create. &amp;nbsp;The Arduino sketch can be modified to allow for the selection of an sObject type, then the number of records to create, before sending the request to the web service.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Have fun and please share any projects you have in mind or have done!&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;meta name=&quot;twitter:card&quot; content=&quot;summary_large_image&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:site&quot; content=&quot;@crmscience&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:creator&quot; content=&quot;@kirkevonphilly&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:title&quot; content=&quot;Lab Coat Lesson:  Salesforce Arduino Gateway&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:description&quot; content=&quot;A simple Apex REST class can open a world of Salesforce connectivity for your IoT gadgets!&quot;&gt;&lt;br /&gt;
&lt;meta name=&quot;twitter:image&quot; content=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiapl9X217qHc30Yfrk9NjEFAEu_2uBL7yop-W3Aqv-5ToOEjehe_AzrcbAiCdw2yDoTwErF88F093JAHB5oRtnG5JD3mW9JS8sguSGnx9IBXyk3WVUYk0VLxtJak2up5lVSq2tPzY4JbE/s1600/IMG_20141006_093911_a.jpg&quot;&gt;&lt;br /&gt;
</description><link>http://blog.crmscience.com/2014/10/salesforce-arduino-gateway.html</link><author>noreply@blogger.com (Anonymous)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsV29zI_PvagW76iGhpZhWtMkO-oTuwR_YprIldwMowSQyFUIdFjZNlUreukSX5N1wZMOY5gHsIDBImcibYqlkgMOAOSttw2BVq45h-O1jC6EjuY1FfQ6cLSvgw_GvZUNj6LVEh0IfYZM/s72-c/labcoat_header.png" height="72" width="72"/></item></channel></rss>