tag:blogger.com,1999:blog-88808487359381550142024-02-21T23:08:02.442-08:00Andy Uzick's Sitecore BlogAndy Uzick has been working with the Sitecore platform for over 15 years, having developed the first large scale Sitecore site in North America as Sitecore’s first North American partner. He has been a Sitecore MVP since the award was started in 2008. As V.P. of Martech Innovation at Arke Systems, he advances technologies in and around the Sitecore ecosystem, and helps clients realize value from marketing technology through “disruptive consulting”.Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.comBlogger22125tag:blogger.com,1999:blog-8880848735938155014.post-79262699525097351282019-07-26T11:36:00.000-07:002019-07-30T11:52:21.154-07:00Yet another Sitecore 9.2 Install Blog<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWTiJjPAzgQS8suWJn5rm3XvY1sp5yA4JLeg3DFxB6Yo6r0DJ6CdPTOTTHaWUquP9BC6Tn9T6n6Dp6Uu7gFVDV5PDo0Df1HjP6iQv3Er83VB5lzBqqj41xOLDPCA3alAlFhyphenhyphenK93fPohKDQ/s1600/9.2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="240" data-original-width="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWTiJjPAzgQS8suWJn5rm3XvY1sp5yA4JLeg3DFxB6Yo6r0DJ6CdPTOTTHaWUquP9BC6Tn9T6n6Dp6Uu7gFVDV5PDo0Df1HjP6iQv3Er83VB5lzBqqj41xOLDPCA3alAlFhyphenhyphenK93fPohKDQ/s1600/9.2.png" /></a></div>
<br />
Setting up a developer VM got much easier with 9.2. I'm sure lots of these "how to" posts are going up; here's mine (as much for my own reference as anything else).<br />
<br />
I'm assuming you're using a "bare" Azure VM with Server 2016, but the steps shouldn't be much different for other hosting scenarios. I use a DS4 v3. I take liberties with security best practices, since this is a dev box.<br />
<br />
<h3>
Installing SQL</h3>
<h4>
Install <i>en_sql_server_2017_standard_x64_dvd_11294407.iso.</i></h4>
<ul>
<li>Instance ID: MSSQLSERVER</li>
<li>Mixed Mode authentication</li>
<ul>
<li>Assign a SA password</li>
<li>Add your machine account as an admin.</li>
</ul>
</ul>
<h4>
Install management tools 8.1</h4>
<div>
<ul>
<li>Installer: <a href="https://docs.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms?view=sql-server-2017">https://docs.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms?view=sql-server-2017</a> </li>
</ul>
<h4>
Create a service account</h4>
</div>
<div>
<ul>
<li>sitecore/sitecore </li>
<li>Enforce password policy off </li>
<li>Server Roles > sysadmin </li>
</ul>
<h4>
Enable "contained database authentication"</h4>
</div>
<div>
<ul>
<li>Run the SQL script: <span style="font-family: "courier new" , "courier" , monospace;">EXEC sp_configure 'contained', 1; RECONFIGURE;</span></li>
</ul>
<h3>
<span style="font-family: inherit;"><br /></span></h3>
<h3>
<span style="font-family: inherit;">Install Solr 7.5</span></h3>
</div>
<div>
<div>
<ul>
<li>Install JRE using <a href="https://download.oracle.com/otn/java/jdk/8u171-b11/512cd62ec5174c3487ac17c61aaa89e8/jdk-8u171-windows-x64.exe">https://download.oracle.com/otn/java/jdk/8u171-b11/512cd62ec5174c3487ac17c61aaa89e8/jdk-8u171-windows-x64.exe </a> </li>
</ul>
</div>
<div>
<ul>
<li>There's lots of good Solr installation scripts. I used this one: <a href="https://github.com/Sitecore/Sitecore.HabitatHome.Utilities/blob/master/XP/install/Solr/install-solr.ps1%20to%20C:/Setup/solr/">https://github.com/Sitecore/Sitecore.HabitatHome.Utilities/blob/master/XP/install/Solr/install-solr.ps1 to C:\Setup\solr\</a></li>
<li>Setup the variables at the top as desired: </li>
</ul>
</div>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">[string]$solrVersion = "7.5.0", </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[string]$installFolder = "C:\solr",</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[string]$solrPort = "8983", </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[string]$solrHost = "solr750.local", </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[bool]$solrSSL = $TRUE, </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[string]$nssmVersion = "2.24", </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[string]$keystoreSecret = "secret", </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[string]$KeystoreFile = 'solr-ssl.keystore.jks', </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[string]$SolrDomain = 'solr750.local', </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[switch]$Clobber </span></blockquote>
<div>
<ul>
<li>Run powershell as admin in <span style="font-family: "courier new" , "courier" , monospace;">C:\Setup\Solr</span> </li>
<li><span style="font-family: "courier new" , "courier" , monospace;">.\Install-Solr.ps1</span> </li>
<li>Test <a href="https://solr750.local:8983/solr/#/">https://solr750.local:8983/solr/#/ </a></li>
</ul>
<h4>
IIS</h4>
<div>
<div>
<ul>
<li>IIS 10, using Server Manager > Roles and Features > Tasks > Add Roles and Features > Web Server </li>
<li>.NET Core 2.1.7 Windows Hosting Module <a href="https://dotnet.microsoft.com/download/thank-you/dotnet-runtime-2.1.7-windows-hosting-bundle-installer">https://dotnet.microsoft.com/download/thank-you/dotnet-runtime-2.1.7-windows-hosting-bundle-installer </a> </li>
</ul>
</div>
</div>
<h3>
</h3>
<h3>
Sitecore</h3>
<div>
<h4>
Install SIF </h4>
<div>
<ul>
<li><span style="font-family: "courier new" , "courier" , monospace;">Register-PSRepository -Name SitecoreGallery -SourceLocation https://sitecore.myget.org/F/sc-powershell/api/v2 </span></li>
<li><span style="font-family: "courier new" , "courier" , monospace;">Update-Module SitecoreInstallFramework</span> </li>
<li>Validate: <span style="font-family: "courier new" , "courier" , monospace;">Get-Module SitecoreInstallFramework –ListAvailable </span></li>
</ul>
</div>
<h4>
Install Sitecore </h4>
<div>
<ul>
<li>Use “Graphical setup package for XP Single” <a href="https://dev.sitecore.net/~/media/1C1D7C4CBC934A6AA36825974A18A72E.ashx">https://dev.sitecore.net/~/media/1C1D7C4CBC934A6AA36825974A18A72E.ashx</a> </li>
</ul>
</div>
<h4>
SXA</h4>
<a href="https://dev.sitecore.net/Downloads/Sitecore_Experience_Accelerator/19/Sitecore_Experience_Accelerator_190.aspx">https://dev.sitecore.net/Downloads/Sitecore_Experience_Accelerator/19/Sitecore_Experience_Accelerator_190.aspx </a><br />
<div>
<ul>
<li><span style="color: red;">[Correction 7/29/18] <b>SXA 1.9 requires Sitecore Powershell Extensions 5.1.</b> As of this writing, that version is not available on the Marketplace. You can download SPE 5.1 from <a href="https://github.com/SitecorePowerShell/Console/releases/tag/5.1">https://github.com/SitecorePowerShell/Console/releases/tag/5.1</a>.</span><br /><strike>Install Sitecore Powershell Extensions 5.0 full from <a href="https://marketplace.sitecore.net/Modules/Sitecore_PowerShell_console.aspx">https://marketplace.sitecore.net/Modules/Sitecore_PowerShell_console.aspx</a> </strike></li>
</ul>
</div>
<div>
<ul>
<li>Download “Sitecore Experience Accelerator for 9.2” from <a href="https://dev.sitecore.net/~/media/FB62D25D54C945999FE05C0E22B29622.ashx">https://dev.sitecore.net/~/media/FB62D25D54C945999FE05C0E22B29622.ashx</a> </li>
</ul>
</div>
<div>
<ul>
<li>Follow instructions in the Installation Guide <a href="https://dev.sitecore.net/~/media/870D6095010241668E83E16C8DB2C850.ashx">https://dev.sitecore.net/~/media/870D6095010241668E83E16C8DB2C850.ashx</a><br />(be sure to create and populate cores, rebuild indexes) </li>
</ul>
</div>
<div>
<br /></div>
<h4>
JSS</h4>
<div>
<a href="https://dev.sitecore.net/Downloads/Sitecore_JavaScript_Services/120/Sitecore_JavaScript_Services_1200.aspx">https://dev.sitecore.net/Downloads/Sitecore_JavaScript_Services/120/Sitecore_JavaScript_Services_1200.aspx </a></div>
<div>
<ul>
<li>Install the latest Node.js <a href="https://nodejs.org/en/">https://nodejs.org/en/ </a></li>
<li>Download server components <a href="https://dev.sitecore.net/~/media/21E55AD5AEA145C2903E1FB3A25B079E.ashx">https://dev.sitecore.net/~/media/21E55AD5AEA145C2903E1FB3A25B079E.ashx</a> </li>
<li>Install package <b>Sitecore JavaScript Services Server for Sitecore 9.2 XP</b> </li>
</ul>
</div>
</div>
<div>
<br /></div>
</div>
</div>
Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.com0tag:blogger.com,1999:blog-8880848735938155014.post-40708530874663291122019-03-27T07:53:00.002-07:002019-03-27T07:53:26.377-07:00Understanding Sitecore SXA: Why SXA?<div class="MsoNormal" style="text-align: right;">
<br /></div>
<div class="MsoNormal">
Traditional Sitecore implementations have always been a
“custom build” proposition. And with each custom build often comes a different
approach and methodology. How can organizations overcome the cost, time and
stress involved with a fully custom build?</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Once regarded as a “small site” tool, SXA has evolved into
an enterprise-class framework. </div>
<div class="MsoNormal">
Organizations can embark on projects large and
small, secure in the knowledge that best practices are already baked into the
solution.</div>
<div class="MsoNormal">
<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
When leveraged to its fullest, SXA allows organizations to
redefine the process for building and maintaining sites, in a way that shortens
timelines, reduces reliance on development, and promotes team collaboration.
Projects are accelerated by utilizing a toolbox of pre-built components, and by
embracing a compressed project cadence that promotes collaboration and brings
the work of many teams into a more parallel arrangement.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<h3>
Your New Development Process</h3>
<div class="MsoNormal">
With SXA, Sitecore itself becomes central to solution
development as well as content development, bringing together the visual and UX
designers, content creators, back-end and front-end developers.<o:p></o:p></div>
<div class="MsoNormal">
Serving as the wireframing tool, SXA allows content creators
to develop content and construct pages in a wireframe mode, as designers and
front-end developers style the site in parallel. These “themes” are applied
iteratively to content being created in flight.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<h3>
Improved Time-To-Value</h3>
<div class="MsoNormal">
With development and content being developed in parallel,
project timelines are shortened. Unexpected conflicts are uncovered as design
meets real world content, allowing adjustments to be made sooner, with a less
regressive remediation cycle.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
In a multi-site environment, content and presentation can be
shared across sites, streamlining development as additional sites are added.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<h3>
Lower TCO</h3>
<div class="MsoNormal">
<o:p></o:p></div>
<div class="MsoNormal">
Much of the classic development cost for a typical site can
be avoided, by leveraging the impressive set of components that ship with SXA.
Many tasks once relegated to developers and requiring code deployments are now
accomplished in the Sitecore UI and simply published.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Page editors have more control over the styling and
composition of common presentation components, freeing developers to focus on
domain-specific custom features.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
SXA’s framework, with strong separation of presentation from
design, promotes multi-site development with heavy re-use of components,
further lowering development cost.<o:p></o:p></div>
<div class="MsoNormal">
Reduced Organizational Stress<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
SXA allows organizations to start with a strong foundation,
using a fully supported and tested framework that makes the entire process more
reliable and reduces rework. Solution structure is consistent across sites,
making development more predictable and allowing developers to switch between
projects with less ramp-up time.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Developers are relieved from mundane tasks, allowing them to
focus on more interesting challenges, while content creators are freed from
reliance on development to achieve commonplace requirements. Having fewer code
deployments reduces friction and removes barriers to content publishing.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Upgrades become more approachable, because less coding means
fewer regression issues to remediate.<o:p></o:p></div>
<div class="MsoNormal">
<br />
<br /></div>
<div class="MsoNormal">
<i>Next: <a href="https://andyuzick.arke.com/2019/03/what-is-sitecore-sxa.html">What is SXA?</a></i></div>
<span style="font-style: italic;">Home: </span><a href="https://andyuzick.arke.com/2019/03/understanding-sitecore-sxa.html" style="font-style: italic;">Understanding Sitecore SXA</a><br />
<br />Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.comtag:blogger.com,1999:blog-8880848735938155014.post-8966580449329608332019-03-27T07:53:00.001-07:002019-03-27T07:53:15.078-07:00Understanding Sitecore SXA: What is SXA?<i>Previous: <a href="https://andyuzick.arke.com/2019/03/what-is-sitecore-sxa.html">What is SXA?</a></i><br />
<br />
Marketers and technologists often struggle with complex implementations. Faced with a dazzling array of new technologies, organizations everywhere are trying to develop a roadmap that fits the right technologies with their business objectives. But as many have learned, the road to success is often bumpier than expected.
<br />
<br />
SXA delivers key features out-of-the-box, shifts development away from coding and into UI, and provides a reliable framework for execution.
<br />
<br />
Projects can now start with a fully-baked scaffolding, that puts mobile first, separates presentation from content, and already contains a host of presentation components. In addition, key features like url management and search are already incorporated, and the execution methodology is clear and well understood.
<br />
<br />
<br />
<h2>
For Marketers</h2>
<ul>
<li><b>Best practices (“Helix”) baked in</b><br />Consistent structure of content reduces guesswork. Start with a stable solution that is poised to grow as needed.</li>
<li><b>Extensive component suite</b><br />Most of the commonly needed components are ready to go, right out of the box.</li>
<li><b>Search</b><br />No need to invest in a separate search technology for many common search requirements.</li>
<li><b>Multi tenant and site</b>Host multiple sites in a single infrastructure, with selectively shared content and cross-site link management.</li>
<li><b>Layout and rendering flexibility</b><br />Content editors have more control of layout and appearance. Renderings can be tweaked, extended or created without having to wait for development.</li>
<li><b>Parallel development and content load</b><br />Content pages can be developed in a wireframe mode, and style can be applied is it becomes available.</li>
</ul>
<br />
<h2>
For Technologists</h2>
<ul>
<li><b>Best practices (“Habitat”) baked in</b>Avoid costly strategic errors in new projects. Coders are immediately familiar with existing projects.</li>
<li><b>Extensive component suite</b>No need to develop commonly used components. All pre-built components can be styled, extended or replaced as needed.</li>
<li><b>Search</b><br />Fewer technologies to maintain, fewer integration points to fail.</li>
<li><b>Multi tenant and site</b><br />Less infrastructure to maintain, better re-use of code, and consistent deployment strategy.</li>
<li><b>Layout and rendering flexibility</b><br />Developers focus on new features and capabilities, rather than tweaks to existing artifacts. Fewer regression bugs.</li>
<li><b>Parallel development and content load</b><br />Front end developers can see real-world instances of their design by switching completed pages into their custom theme.</li>
</ul>
<div>
<br /></div>
<div>
<div class="MsoNormal">
<i>Next: <a href="https://andyuzick.arke.com/2019/03/sitecore-sxa-rapid-start-smooth-execution.html">Rapid Start, Smooth Execution</a></i><br />
<div>
<span style="font-style: italic;">Home: </span><a href="https://andyuzick.arke.com/2019/03/understanding-sitecore-sxa.html" style="font-style: italic;">Understanding Sitecore SXA</a><br />
<br /></div>
</div>
</div>
Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.comtag:blogger.com,1999:blog-8880848735938155014.post-5179480456484345612019-03-27T07:53:00.000-07:002019-03-27T07:53:07.000-07:00Understanding Sitecore SXA: Which Way to Go?<i>Previous: <a href="https://andyuzick.arke.com/2019/03/understanding-sxa-changes-to-roles-and-processes.html">Changes to Roles and Processes</a></i><br />
<br />
<div class="MsoNormal">
When is SXA the right course for a project, and when is a conventional build the right way to go? The answer is, “it depends”.</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
For smaller projects, where a conventional Sitecore build was too large an undertaking, SXA changes the equation by reducing the build time and technical burden. Customers building smaller sites can now reap the benefits of Sitecore’s engagement and marketing automation capabilities, instead of limiting themselves to a less capable CMS tool.</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
For large enterprises that face a range of challenges, the choice between SXA and a conventional build becomes more nuanced. In a development-lead culture, or where heavy functional functionality is required, a conventional build may be best. But SXA is a viable, even desirable, choice for organizations experiencing a digital transformation and orienting to a marketing- and business-forward approach.</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Organizations with a large amount of web presence can use SXA to “pace layer” their solutions into more manageable groupings that develop at different rates and have different orientations. SXA reduces the friction for building smaller, more nimble projects. An enterprise might have a classic build for portal or corporate sites, and an SXA model for brand sites, location sites, and campaign sites. This allows nimble execution for time-critical marketing demands, alongside a more rigorous model for times when fidelity and precision are crucial.</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
For battle-scarred managers who have survived painful and expensive builds, SXA is a welcome relief. Those who’ve survived those rocky projects in the past would gladly embrace a more prescriptive process that starts with “best practices”.</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<br /></div>
<span style="font-style: italic;">Read the full series on SXA: </span><a href="https://andyuzick.arke.com/2019/03/understanding-sitecore-sxa.html" style="font-style: italic;">Understanding Sitecore SXA</a><br />
<br />
<br />Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.comtag:blogger.com,1999:blog-8880848735938155014.post-28053152332601219282019-03-27T07:52:00.001-07:002019-03-27T07:52:31.777-07:00Understanding Sitecore SXA: Changes to Roles and Processes<i>Previous: <a href="https://andyuzick.arke.com/2019/03/understanding-sxa-prescriptive-yet-flexible.html">Prescriptive, Yet Flexible</a></i><br />
<br />
<br />
Two of SXA’s key benefits are improved project cadence and less reliance on development. Achieving these goals often means changes in roles and responsibilities.<br />
<br />
<h3>
Development doesn’t necessarily mean coding</h3>
With SXA, some of the implementation work that would otherwise be done in back-end code is now done in the Sitecore UI. That doesn’t mean that code is written in a Sitecore UI, but it does mean that some things that would have otherwise required code are now either done in, or supplemented by, activities in the Sitecore UI.<br />
<br />
Once upon a time, the Sitecore UI largely insulated the person in the chair from technical “stuff”. Now, quite a bit of that technical stuff is managed in UI. Structuring components was once done entirely in code, now this is done largely in Sitecore. You’ll find yourself declaring element tags and CSS classes, creating data queries and using substitution tokens, and structuring things akin to models and markup. But just because it’s managed in UI doesn’t mean it doesn’t require a technical thinker.<br />
<br />
Although much of the methodology shifts from code to configuration, developing functionality in SXA is conceptually more akin to development than content management. Just like in coding, an understanding of what can be done and how things work, leads to effective solutioning. Your technical staff is going to change where and how they do a lot of this work, and the big benefit is that many things that would otherwise have required a code deployment now just require a publish.<br />
<br />
This will require a shift in thinking for both I.T. and Marketing. In the early days of CMS it was often hard for I.T. to accept that content management was now a production activity; now they must accept that more things that have been traditionally subjected to development protocols are now becoming production activities as well.<br />
<br />
<h3>
Front-End in the loop</h3>
The role of the front end developer isn’t just coding, and it isn’t just design. It’s some of both and other things besides. Since SXA is a framework that manages the methodology for developing both structure and style, the front-end developer’s work becomes part of the SXA flow.<br />
<br />
Changes to HTML structure are done directly in SXA (or at times, in back-end code). This may be driven by the need for new renderings, or by imperatives the styling process. As wireframes and content are developed, the entire site (or portions of it) are exported to a ZIP file, where designers and front-end developers extend CSS and JavaScript and apply styling using their preferred tools. Sitecore’s Creative Exchange re-imports this zip file, detects changes to styling, and applies them to the system. The styling methodology is constrained by how the SXA framework operates (for example HTML structure and content can’t be modified, and existing class cannot be removed), and SXA injects comments into the HTML to direct developers as appropriate.<br />
<br />
If desired, teams can use “Creative Exchange Live” to fully automate the export/import loop. Creative Exchange can be triggered by a Continuous Integration server, integrating code changes into the main branch, and to test changes early and often.<br />
<div>
<br /></div>
<br />
<br />
<i>Next: <a href="https://andyuzick.arke.com/2019/03/understanding-sxa-which-way-to-go.html">Which Way to Go?</a></i><br />
<span style="font-style: italic;">Home: </span><a href="https://andyuzick.arke.com/2019/03/understanding-sitecore-sxa.html" style="font-style: italic;">Understanding Sitecore SXA</a><br />
<br />
<br />Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.comtag:blogger.com,1999:blog-8880848735938155014.post-23199726922414662822019-03-27T07:52:00.000-07:002019-03-27T07:52:06.523-07:00Understanding Sitecore SXA: Prescriptive, Yet Flexible<a href="https://andyuzick.arke.com/2019/03/sitecore-sxa-improved-project-cadence.html"><i>Previous: Improved Project Cadence</i></a><br />
<br />
Many marketers and technologists have found that their perspective on a large project can change rapidly, as the level of effort and learning curve become increasingly clear. The envisioned scope, schedule and budget are all threatened, as the imagined methodology and cadence meet reality.<br />
<br />
SXA tackles this dilemma by providing a proven structure, framework, and methodology. The aim is to simplify processes, increase collaboration, shorten timelines, and smooth the path to success. Naturally, the maximum benefit is gained by a comprehensive adoption, but SXA can be used in an opt-in fashion, utilizing some of its features and replacing others with more conventional approaches.<br />
<br />
By embracing all of SXA, organizations achieve the maximum benefit that they seek from a prescriptive, out-of-the-box framework. For many organizations, however, there are aspects to the architecture or build process that need a more custom approach.<br />
<br />
<h3>
Going All In</h3>
Adopting SXA to its fullest doesn’t mean giving up customization. Design customization is an essential part of an SXA build. Customizing CSS, building multiple themes, and extending the client-side structure are all common activities in an SXA build.<br />
<br />
Page structure are actually more flexible with SXA than a typical conventional build. Content editors are able to drag-and-drop renderings, choose from more focused data sources, and adjust column widths. Also common is the use of Rendering Variants, to change the structure and appearance of components — without requiring code deployments!<br />
<br />
SXA’s preferred project cadence solves a common pitfall. When design collides with content, it often becomes necessary to adjust, when styling designed for best casecontent collides with real world content. In the SXA model, these collisions are detected earlier, and remediated faster than with a conventional build.<br />
<br />
In an all-out SXA implementation, the design/style/construct process is shortened, but changes from conventional expectations.<br />
<br />
Wireframes are developed directly in Sitecore. They are exported as packages with HTML, CSS and script, organized in an orderly layered stack based on themes. Designers and front-end developers then style these wireframes, by extending and modifying the CSS and script (for the most part, without changing the HTML). Their work is imported back into Sitecore, where their theme(s) are applied to the site(s) that have already begun to take on content and structure.<br />
<br />
This process can be iterative and branched. The export/style/import process can iterate, without necessitating radical changes to the existing work. In fact, Sitecore SXA provides “Creative Exchange Live”, that uses the gulp toolkit to bring design into a dev-ops model for continuous integration. Content editors continue to develop content and construct pages while the styling process iterates, shortening the project timeline and providing more real-world content to help refine the styling.<br />
<br />
Multiple themes can be developed within or across sites, allowing the same components and structures to be presented differently simply by selecting from the different themes. The compounded power of reusable components with customizable themes and development-free customization, creates a force multiplier that can dramatically improves time-to-value.<br />
<br />
<h3>
Deep customization when needed</h3>
SXA ships with an impressive set of components that cover most of what the core of any site will need, and through the use of “rendering variants”, new renderings can be created without requiring coding.<br />
<br />
Using these components out-of-the-box means (for the most part) working with the HTML as provided and styling entirely with CSS and script. An implementation can replace the HTML of all or some of these components and add new ones, but this requires requires a back-end development process more akin to a conventional build. Custom HTML is cut up and used as prototypes for c# developers to create new views, which replace default views or are registered in SXA as new components. Changes to the HTML require code deployments after a round trip through this back-end development process, which can slow concurrent content development.<br />
<br />
<br />
<br />
<i>Next: <a href="https://andyuzick.arke.com/2019/03/understanding-sxa-changes-to-roles-and-processes.html">Changes to Roles and Processes</a></i><br />
<div>
<span style="font-style: italic;">Home: </span><a href="https://andyuzick.arke.com/2019/03/understanding-sitecore-sxa.html" style="font-style: italic;">Understanding Sitecore SXA</a><br />
<br /></div>
Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.comtag:blogger.com,1999:blog-8880848735938155014.post-36256061507041630222019-03-27T07:51:00.001-07:002019-03-27T07:51:32.332-07:00Understanding Sitecore SXA: Rapid Start, Smooth Execution<i>Previous: <a href="https://andyuzick.arke.com/2019/03/what-is-sitecore-sxa.html">What is SXA?</a></i><br />
<div>
<br /></div>
<div>
<div class="MsoNormal">
Today’s marketing technology landscape has become a “field of dreams,” offering a dizzying array of platforms, technologies, and strategies. Marketers are eager to make their own dreams a reality, utilizing these tools to achieve the promise of true customer engagement.</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Two things become quickly apparent.</div>
<div class="MsoNormal">
</div>
<ul>
<li>Actually living that dream means changing business as usual.</li>
<li>Understanding how to execute is the difference between a dream and a nightmare.</li>
</ul>
<br />
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Adopting a powerful technology like Sitecore can be overwhelming. A knowledgeable partner knows the landscape can guide a successful implementation, but a complex implementation can be a long and trying process.</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
By combining a suite of pre-built components and user-friendly tools that smooth the learning curve, SXA gets projects off to the right start and streamlines execution.</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Throughout and beyond the initial project build, much of the work of modifying layout and even building new features is shifted to the Sitecore administrative interface, meaning many things that have historically relied on cumbersome code deployment processes can not be achieved with a mere publish.</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Time-to-value is reduced, and concurrent team collaboration becomes a force multiplier rather than a series of tactical waves.</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<i>Next: <a href="https://andyuzick.arke.com/2019/03/sitecore-sxa-improved-project-cadence.html">Improved Project Cadence</a></i></div>
<div>
<i>Home: <a href="https://andyuzick.arke.com/2019/03/understanding-sitecore-sxa.html">Understanding Sitecore SXA</a></i></div>
Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.comtag:blogger.com,1999:blog-8880848735938155014.post-34383229044427900862019-03-27T07:51:00.000-07:002019-03-27T07:51:27.783-07:00Understanding Sitecore SXA: Improved Project Cadence<br />
<i>Previous: <a href="https://andyuzick.arke.com/2019/03/sitecore-sxa-rapid-start-smooth-execution.html">Rapid Start, Smooth Execution</a></i><br />
<br />
Battle-scarred professionals know the stress and cost that can go with a fully bespoke implementation. Sitecore is an outstanding platform for creating truly exceptional experiences. But implementations can be drawn out, owing to the highly linear nature if a conventional build. Nervous stakeholders don’t see progress, and the seeming vacuum created by the isolated development process begs to be filled with new ideas and changes.<br />
<br />
A classic linear build relies on handoffs of phases of the project: from user experience to information architecture to wireframing to front-end development to back-end development to content load to UAT. Changes and fixes require looking back farther and farther in the chain, leading to regression problems and costly rework.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbFu1F8F5RJh_64m27XzRlb4xItsN5o9FTIbKk07eFb4HBakhsdBDN23ikCLRdxah8yFDcsavvGvmcfNkOZpz39V2QIvGee_2-kilE-3Saz4-ZgJqq3G16VDAOWzvYAHr8RG9AqbQnZvZi/s1600/old+cadence.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="254" data-original-width="982" height="103" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbFu1F8F5RJh_64m27XzRlb4xItsN5o9FTIbKk07eFb4HBakhsdBDN23ikCLRdxah8yFDcsavvGvmcfNkOZpz39V2QIvGee_2-kilE-3Saz4-ZgJqq3G16VDAOWzvYAHr8RG9AqbQnZvZi/s400/old+cadence.png" width="400" /></a></div>
<br />
<br />
SXA makes the process more parallel, and allows for continual adjustment and improvement that reduces the need for gated, painstakingly detailed requirements.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicq_FbBI5qIixFm2gY6QPh5kLh8_F9aD1gIRJlhgpYysWRzE0XVMGSpP4yn4-mS30-ibp2iMPOXqqgF9-r6aWHrBLpu0D-1S66-gEeOxJOy3UbrRTHm9xQPW1RpDp2jFbuNOUrcf5n-yrY/s1600/new+cadence.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="266" data-original-width="982" height="107" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicq_FbBI5qIixFm2gY6QPh5kLh8_F9aD1gIRJlhgpYysWRzE0XVMGSpP4yn4-mS30-ibp2iMPOXqqgF9-r6aWHrBLpu0D-1S66-gEeOxJOy3UbrRTHm9xQPW1RpDp2jFbuNOUrcf5n-yrY/s400/new+cadence.png" width="400" /></a></div>
<br />
<br />
After primary envisioning, Sitecore itself becomes the hub around which the project revolves. Ongoing UX and content load begins immediately, using Sitecore’s wireframe tool. As visual design progresses, front-end developers develop themes that can be applied to already-loaded content in the wireframes, which become the publishable pages. Back-end developers build new components as needed, which are available in the toolbox immediately. Most bespoke component requirements can actually be created entirely within Sitecore and styled by back-end coders, all without requiring a code deployment.<br />
<br />
Over the life of the project, stakeholders see ongoing progress, participants stay more engaged and collaborate better, issues are identified sooner, with less regressive remediation, and best practices lead to a deliverable that can be maintained and extended by anybody familiar with the framework.<br />
<div>
<br />
<br /></div>
<i>Next: <a href="https://andyuzick.arke.com/2019/03/understanding-sxa-prescriptive-yet-flexible.html">Prescriptive, Yet Flexible</a></i><br />
<span style="font-style: italic;">Home: </span><a href="https://andyuzick.arke.com/2019/03/understanding-sitecore-sxa.html" style="font-style: italic;">Understanding Sitecore SXA</a><br />
<br />Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.comtag:blogger.com,1999:blog-8880848735938155014.post-36176764101119944052019-03-26T13:07:00.000-07:002019-03-26T13:57:53.287-07:00Understanding Sitecore SXASitecore Experience Accelerator (SXA) can be an absolute game-changer for how projects are envisioned, executed and maintained. Understanding how SXA will affect the design/build/maintain journey is key to knowing when to adopt. Just like in an auto race, knowing when to hit the accelerator can make the difference between success and disaster.<br />
<br />
This seven-part series will examine the what-and-why of SXA, and uncover the impact SXA can have on marketing effectiveness.<br />
<br />
<h3>
<a href="https://andyuzick.arke.com/2019/03/why-sitecore-sxa.html">Why SXA?</a></h3>
If you’re facing a new implementation for the first time, or you’ve been battle-scarred from a past rocky implementations, there’s a certain allure to an out-of-the-box solution, built on best practices, containing a swath of pre-built capabilities, with a prescriptive implementation process.<br />
Learn about SXA’s promise and what it could mean for you.<br />
<i><a href="https://andyuzick.arke.com/2019/03/why-sitecore-sxa.html">Read more...</a></i><br />
<br />
<h3>
<a href="https://andyuzick.arke.com/2019/03/what-is-sitecore-sxa.html">What is SXA?</a></h3>
SXA is a Sitecore-supported framework, toolbox and methodology that helps projects get started faster, develop more smoothly, and deliver results reliably. Learn more about how SXA helps overcome many of the conventional hurdles faced by Sitecore project implementers.<br />
<i><a href="https://andyuzick.arke.com/2019/03/what-is-sitecore-sxa.html">Read more</a>...</i><br />
<br />
<h3>
<a href="https://andyuzick.arke.com/2019/03/sitecore-sxa-rapid-start-smooth-execution.html">Rapid start, smooth execution</a></h3>
Adopting a powerful technology like Sitecore can be overwhelming. Implementations are rocky, solutions become unmaintainable, and the high-return “phase 2” features never come to pass. Learn how SXA’s prescriptive, best-practice methodology and user-friendly tools can smooth the learning curve, get projects off to the right start, and streamline execution.<br />
<i><a href="https://andyuzick.arke.com/2019/03/sitecore-sxa-rapid-start-smooth-execution.html">Read more...</a></i><br />
<br />
<br />
<h3>
<a href="https://andyuzick.arke.com/2019/03/sitecore-sxa-improved-project-cadence.html">Flatter, faster cadence</a></h3>
Every Sitecore project is unique. Some large, some smaller. Some stand-alone, some multisite. Some complex, some straightforward. Languages, search, media, seo, visual design — any of these can raise the complexity bar. Learn how SXA can lower the barrier to entry, speed time to value, and enable continuous improvement.<br />
<i><a href="https://andyuzick.arke.com/2019/03/sitecore-sxa-improved-project-cadence.html">Read more</a>...</i><br />
<br />
<br />
<h3>
<a href="https://andyuzick.arke.com/2019/03/understanding-sxa-prescriptive-yet-flexible.html">Prescriptive, but flexible</a></h3>
Digital marketers and technologists that have lived through (or are facing up to) a complex project, the unknowns of proper execution loom large. Faced with unknown complexity, the idea of a highly prescriptive methodology can be a welcome relief. That may feel confining, but SXA allows a mix-and-march approach that allows a given project to adopt all or just some of SXA’s processes. Learn how SXA allows the hard things to be hard, while keeping the simple things simple … and makes some of those hard things simpler than you thought.<br />
<i><a href="https://andyuzick.arke.com/2019/03/understanding-sxa-prescriptive-yet-flexible.html">Read more</a>...</i><br />
<br />
<br />
<h3>
<a href="https://andyuzick.arke.com/2019/03/understanding-sxa-changes-to-roles-and-processes.html">Nuances in process and responsibilities</a></h3>
When moving into an SXA mindset, in addition to changes in methodology and process, be prepared for roles to be redefined or at least shift a bit. Learn more about how disciplines and processes may shift when adopting SXA as an implementation framework.<br />
<i><a href="https://andyuzick.arke.com/2019/03/understanding-sxa-changes-to-roles-and-processes.html">Read more</a>...</i><br />
<br />
<br />
<h3>
<a href="https://andyuzick.arke.com/2019/03/understanding-sxa-which-way-to-go.html">Choosing a path</a></h3>
Conventional build or SXA? Marketers and technologists preparing for a new site build in Sitecore have more choices than ever before. SXA offers a real alternative to the classic build approach, bringing with it both advantages and challenges.<br />
<i><a href="https://andyuzick.arke.com/2019/03/understanding-sxa-which-way-to-go.html">Read more</a>...</i><br />
<div>
<br /></div>
Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.comtag:blogger.com,1999:blog-8880848735938155014.post-55108802028228185092016-06-05T14:25:00.003-07:002016-06-05T14:54:52.393-07:00Zip code data in Sitecore<div class="separator" style="clear: both; text-align: center;">
</div>
<hr />
<div style="text-align: center;">
<i>The <a href="https://github.com/auzick/ZipInfo">source code</a> and <a href="https://github.com/auzick/ZipInfo/blob/master/README.md">documentation</a> </i><i>for this solution </i><i>are available on GitHub. </i><a aria-label="Download auzick/ZipInfo on GitHub" class="github-button" data-icon="octicon-cloud-download" data-style="mega" href="https://github.com/auzick/ZipInfo/archive/master.zip"><i>Download</i></a></div>
<hr />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjg__Ri3gUM2r1MJK-1w_Y6qJeGQGa0O1IPy_6f3uXjYQB2_BM8MWhNBxwMBiv_Ta21YvgZp-ipHBSAGyBkcGLqCiUEjFyn7STadUEJfduOz7pBhUI0VCH-OlOKyRktBzQXHPnLvF2Zvnje/s1600/Mr._ZIP1.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjg__Ri3gUM2r1MJK-1w_Y6qJeGQGa0O1IPy_6f3uXjYQB2_BM8MWhNBxwMBiv_Ta21YvgZp-ipHBSAGyBkcGLqCiUEjFyn7STadUEJfduOz7pBhUI0VCH-OlOKyRktBzQXHPnLvF2Zvnje/s1600/Mr._ZIP1.png" /></a><br />
Good old postal Zip Codes. Not a very exciting subject, but it seems like every year or two, I run into a solution that requires access to a zip code database.<br />
<br />
There are several commercial services that provide extensive zip code data, but there is at least one free database available (<a href="https://boutell.com/zipcodes/">https://boutell.com/zipcodes/</a>) that includes a decent amount of data, including coordinates, city and state, and time zone.<br />
<br />
Latitude and longitude can be useful if for example you needed to put an "approximate" pin in a map.<br />
<br />
We recently ran into a situation where we needed to know the visitor's time zone. Sitecore GeoIP data includes zip codes, but not time zones. All I need is to wire that up to a zip code database, and I'm all set. (And before you quibble over the accuracy, don't. I know it's not perfect; I think of this as a "good enough" solution).<br />
<br />
So I set up a solution to provide Sitecore with an API for looking up zip codes. I started with a few goals:<br />
<br />
<ul>
<li>I want to be able to use this in any Sitecore solution.,</li>
<li>I don't want to use SQL. It's always administrative and deployment hassle to use custom SQL tables.</li>
<li>I don't want to impose a schema on every application that uses this. Sure, that free zip database is fine for what I need now, but others may have more detailed data they'd like to use.</li>
<li>I want to use a swappable provider so other applications can change how the data is imported, where it is stored, and/or how it is queried.</li>
<li>For my default provider, I want it to "just work". I drop the file into a folder, and my Sitecore app has access to the data (well, I did end up also needing to add a mongo connection string to the connectionstrings.config file).</li>
</ul>
<div>
<br /></div>
<div>
I decided to use MongoDB to store the data. Once I have a connection string, I can create collections and add data with any schema I want, without bugging the SQL admins. I also added to add a caching layer. I'm probably going to access this data from rules and such, and I want it to be zippy-quick.</div>
<div>
<br /></div>
<div>
The data flow looks like this:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCIalWzeQTgzFDvTkd07rJSJfe9HDq5u11R72D0-_jaKbMI10YUNJVj6QyudMbH3-lXMDEcDZCbaDhZ02PQvUH9lkhDjURu3oajJ2JNwWlrEZjjcPXI_q5NQqoYlSB7rKALi2F3UYNtjF1/s1600/Zip+Code+data+flow.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCIalWzeQTgzFDvTkd07rJSJfe9HDq5u11R72D0-_jaKbMI10YUNJVj6QyudMbH3-lXMDEcDZCbaDhZ02PQvUH9lkhDjURu3oajJ2JNwWlrEZjjcPXI_q5NQqoYlSB7rKALi2F3UYNtjF1/s1600/Zip+Code+data+flow.png" /></a></div>
<div>
<br /></div>
<div>
The idea is, the operational data stored in MongoDB, and accessed through a caching layer at runtime. At application start (and via an administrative interface), the data file date is compared to the last time the data was imported, and if the file is newer, it is re-imported.<br />
<br />
<h3>
Installing the module</h3>
Install the update package in your Sitecore application. When Sitecore starts, it will populate a MongoDB database with data from a provided zip code document located in App_Data. This file is sourced from https://boutell.com/zipcodes/.<br />
<br />
Whenever this file is updated, it will be reloaded the next time Sitecore starts.<br />
<br />
Add a connection string to your <span style="font-family: "courier new" , "courier" , monospace;">ConnectionStrings.config</span> file with the name you'd like to use for your Mongo database. For example<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><add name="zipinfo" connectionString="mongodb://localhost:27017/zipinfo" /></span><br />
<br />
If you want to use a separate mongo database for each Sitecore instance sharing a common Mongo server, change the connectionString e.g.<br />
<span style="font-family: "courier new" , "courier" , monospace;">connectionString="mongodb://localhost:27017/myapp_zipinfo"</span><br />
<br />
The update package will place a copy of the data file in your <span style="font-family: "courier new" , "courier" , monospace;">App_Data </span>folder. You can relocate this to the Sitecore data folder if you desire.<br />
<br />
<h3>
Using the module</h3>
</div>
<div>
The module exposes a "manager" static class (<span style="font-family: "courier new" , "courier" , monospace;">ZipInfo.ZipInfoManager</span>) with static methods like <span style="font-family: "courier new" , "courier" , monospace;">Get(int zipCode)</span> to access the data. I won't get into all the methods here (see the <a href="https://github.com/auzick/ZipInfo/blob/master/README.md">documentation</a>), but there are methods for both retrieve/update and cache management operations.<br />
<br />
The update package will also install a utility at /sitecore/admin/zipinfo.aspx that'll allow you to query the database, manage the cache, and re-import the data.<br />
<br />
The module exposes a provider class that can be swapped out with your own provider. If you have more detailed data in a a csv file, you can simply inherit from the default provider, create your own POCO class, and override the <span style="font-family: "courier new" , "courier" , monospace;">LoadRecord </span>method that maps fields on the csv line to the POCO. If you need a different method for loading the data rather than reading it from a csv file, override the <span style="font-family: "courier new" , "courier" , monospace;">Load</span> method. If you don;t want to use mongo, you can replace the entire provider by creating a class that implements <span style="font-family: "courier new" , "courier" , monospace;">IZipInfoProvider</span>. More information about the provider is available in the docs.<br />
<br /></div>
<hr />
<div style="text-align: center;">
<i>The <a href="https://github.com/auzick/ZipInfo">source code</a> and <a href="https://github.com/auzick/ZipInfo/blob/master/README.md">documentation</a> </i><i>for this solution </i><i>are available on GitHub. </i><a aria-label="Download auzick/ZipInfo on GitHub" class="github-button" data-icon="octicon-cloud-download" data-style="mega" href="https://github.com/auzick/ZipInfo/archive/master.zip"><i>Download</i></a></div>
<hr />
<br />
<br />
<br />
<br />
<!-- Place this tag in your head or just before your close body tag. -->
<script async="" defer="" src="https://buttons.github.io/buttons.js"></script>Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.com0tag:blogger.com,1999:blog-8880848735938155014.post-71191739871880082392016-06-01T09:16:00.000-07:002016-10-19T09:26:07.933-07:00Content Indexing vs Site Search<div class="separator" style="clear: both; text-align: center;">
<img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9ZnUrPc4vzDM6zAYxQwamXnoD2P26opCmp1Nbb6ZazZw1-hSzvn6oFc95CYhP87M0EFC6poFoMW1gGkWw2k09wRWUACP0p8SCafFn9TCeWyxeevLJGVgsoqf25weR0aFdW4yksGyNbe2e/s320/AppleOrange.jpg" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;" width="320" /></div>
I've had this conversation so many times, I thought I'd capture it here once and for all.<br />
<br />
<div class="MsoNormal">
<o:p></o:p></div>
There is a vast difference between content indexing and site
search. The following discusses these differences. This is not exhaustive;
there are finer nuances that I’ll skip over in order to keep focused on the key
concepts.<br />
<br />
<h3>
Content Indexing</h3>
Content indexing is the act of storing selected fields of Sitecore content items into a separate index, so that content items can be retrieved rapidly by code. Examples of this are the search box Sitecore uses for item buckets, or a custom rendering that “facets” content e.g. outputs links to every item where “Georgia” is selected in a “Home state” field.<br />
<br />
<ul>
<li>Indexes are created by copying raw <i>item data </i>into the index, typically when the item is saved or published.</li>
<li>Content indexing is a “data-oriented” operation e.g. a lookup in an index finds an match of content in a field. </li>
<li>A content index has no concept of <i>pages</i>, and does not have any ability to rank on such things as link frequency. </li>
<li>Content Indexing is absolutely required for Sitecore to function. </li>
<li>Sitecore implements content indexing “out of the box”, using Lucene by default, with configurable support for Solr in scaled enterprise environments. </li>
</ul>
<br />
<h3>
Site Search</h3>
Site search is the act of indexing the content of entire viewable <i><u>pages</u></i>, so that whole pages can be found using “free text” search. An example of this is a site visitor entering a few words in a search box and getting back a page of ranked results, akin to a Google search.<br />
<br />
<ul>
<li>Indexes are created by “crawling” the site e.g. code uses http requests to pull every page of the site, storing the content in its index, and examining the links on in the page to find more pages to crawl.</li>
<li>Site search is a “free text” operation, e.g. a lookup considers all of the visible content of a page.</li>
<li>A good site search tool ranks results based on things like semantics e.g. content in <h1> tags will rank higher than body text, or linking e.g. pages with more inbound links will rank higher.</li>
<li>A site search solution is only necessary if you want visitors to be able to “free text” search the site e.g. the site has a “search box”. </li>
<li><b><i>Sitecore does not implement free-text page search “out of the box”.</i></b></li>
</ul>
<br />
<h3>
Why the distinction is important</h3>
Any given page of a Sitecore site may have visible page content derived from many content items. Therefore, out-of-the-box content indexing is not an appropriate solution for site search.<br />
<br />
Moreover, a good “free text” search experience requires that the results be well ranked. Consider when you do a Google search. Google isn’t simply returning a flat list of every page that contains your search terms, instead, it is using highly sophisticated ranking algorithms to present the results you are most likely to want first. If you’re familiar with SEO principles, you know that there are many factors that influence rank far beyond the simple content of the page. <br />
<br />
Of course there is some overlap. A good site search tool can also include "hard data" in the form of metadata, so that search results can be "faceted". This allows the visitor to "filter" results based on date, geography, product line, or any other "field oriented" data that you include in the page metadata.<br />
<br />
<h3>
We've already deployed Solr. Why can't we use that for site search?</h3>
In theory, there is a way to leverage a Solr index to do free text search. This is not a simple matter of “configuration”, but rather, requires extensive coding. The general idea is you build a scheduled processor that programmatically loads every page of the site (via an http request) so it can get the entirety of the content on a given page. It puts that content into a “computed field” of a Solr index. Then, custom “search box” code can search that “computed field” for occurrences of that content. There are a drawbacks to this approach:<br />
<br />
<ul>
<li>It is not implemented out of the box.</li>
<li>The ranking of search is either non-existent, or at least far short of the ranking quality of a true crawler.</li>
</ul>
<i>[edited to correct my error about Coveo]</i><br />
<br />
There are “off the shelf” tools that combine the concepts of content indexing and site search.<br />
<br />
<ul>
<li>Coveo is an excellent commercial product that uses a proprietary indexing mechanism, with conventional "content indexing" and also crawling. It can index both entire pages and content items. It comes with value-added tools for rapid deployment of faceted search features, and also adds some ranking capabilities, including the ability to manually tweak search ranking. It comes in on-premises, cloud, and a hobbled “free” version. It is arguably the “least effort” solution to implement, since it is very "Sitecore aware" out of the box.</li>
<li>There are lots of free and commercial solutions. For example, Arke’s SDK includes a “computed search” module. uses configured field and template types to inject page content into a Solr index. </li>
</ul>
<br />
There are other “off the shelf” solutions that provide excellent free text search experiences that do not rely on Solr. Most of these have evolved to cloud-hosted rather than on-premises solutions. Google site search and Amazon cloud search are leaders in this space, and Coveo had a cloud edition, but there are many services available. Using one of these services would still require coding, but it would be pure “integration” coding, not an attempt to build a full blown crawler.<br />
<br />
In the absence of an “off the shelf” solution, you could build a home-grown Solr-based crawler. It’d require significant time and effort, only to yield a pretty poor user experience due to the lack of any sophisticated ranking.<br />
<br />
<div>
<br /></div>
Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.com0tag:blogger.com,1999:blog-8880848735938155014.post-44459927315981407912016-04-14T13:15:00.001-07:002016-04-14T13:47:57.417-07:00Using ARR to enable FXM<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-mHKwkq_lwMLYwMXU_-qe1G_5OEIKP-7LsH6I50O12qphPeDtmSP8wYfZq5L7m2cMA6GoVoB6cVfX1TcethyphenhyphenlyGdxjt34758hFOPorU3kBLJGrVd4GYSO3yJX_PPzfdo83CQhLNxsFb3H/s1600/AdobeStock_16207300.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="160" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-mHKwkq_lwMLYwMXU_-qe1G_5OEIKP-7LsH6I50O12qphPeDtmSP8wYfZq5L7m2cMA6GoVoB6cVfX1TcethyphenhyphenlyGdxjt34758hFOPorU3kBLJGrVd4GYSO3yJX_PPzfdo83CQhLNxsFb3H/s400/AdobeStock_16207300.jpeg" width="400" /></a></div>
<br />
Ever used Sitecore's <a href="http://www.sitecore.net/platform/channels/federated-experience.aspx" target="_blank">Federated Experience Manager</a> (FXM)? Effectively, it lets you use Sitecore to content manage, track, personalize and test external sites which are not hosted in Sitecore.<br />
<br />
The motivations I often hear for using FXM are...<br />
<br />
<ul>
<li>We've bought a license and plan to migrate to Sitecore later, but we want to start personalizing and gathering analytics on our site now.</li>
<li>We're moving our main site to Sitecore, but we have some related sites we just don't have time and budget to move now.</li>
<li>We want to do a demo or POC using content from a non-Sitecore site, but don’t want to re-create the content in Sitecore.</li>
</ul>
<br />
With FXM you can do that. All you need is to place a small bit of script on the external sites. Sadly, that's often not possible. Sometimes the old site is literally on a server that nobody knows how to access. Sometimes you're just doing a POC and nobody wants to edit the old site for that.<br />
<br />
<h3>
IIS's <a href="http://www.iis.net/downloads/microsoft/application-request-routing" target="_blank">Application Request Routing (ARR)</a> to the rescue.</h3>
<br />
IIS has features called <a href="http://www.iis.net/downloads/microsoft/application-request-routing" target="_blank">ARR</a> and the <a href="http://www.iis.net/downloads/microsoft/url-rewrite" target="_blank">URL Rewrite module</a> that amount to a reverse proxy that allows you have a “man in the middle” that can manipulate the HTML before it is returned to the browser.<br />
<br />
We set up a IIS instance with ARR with a public-facing URL (in this example, “demo.mysite.com”), and configure ARR to do the following<br />
<br />
<ol>
<li>Take the path from the inbound request, and form a URL using the Sitecore server’s host name.</li>
<li>Fetch the HTML from the Sitecore host.</li>
<li>Inject the FXM beacon script into the HTML</li>
<li>Change the URLS within the HTML for such things as images, scripts, CSS, iframes, etc, so that they will be requested from the ARR and not the Sitecore site.</li>
<li>Strip out the “X-Frame-Settings” header (if it exists), which can interfere with FXM Experience Editor.</li>
</ol>
<br />
This results in a topology like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPNQBxnKNl8uB7DyptmIP4OcgZ9Z_V1j9f6Ry0ibgNuUONfCnfybEVLSy-pm3PogPrEElz2uCae67Y4eXyZ230_Bj-CfvFSM_o1Yeuyry5yReJIJpvy-Sr102AXE1-4uUo38N3_cAW0WpW/s1600/ARR+sample+topology3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPNQBxnKNl8uB7DyptmIP4OcgZ9Z_V1j9f6Ry0ibgNuUONfCnfybEVLSy-pm3PogPrEElz2uCae67Y4eXyZ230_Bj-CfvFSM_o1Yeuyry5yReJIJpvy-Sr102AXE1-4uUo38N3_cAW0WpW/s1600/ARR+sample+topology3.png" /></a></div>
<br />
<br />
The URL structure in this example would give us a demo/POC website (“demo.mysite.com”) where we can show how a site can be tracked and manipulated with FXM. This could in theory be used for a live site by changing DNS to point www.mysite.com to the ARR, and change the hostname of the Sitecore server to something like Sitecore.mysite.com.<br />
<br />
<h3>
Setting up the Reverse Proxy</h3>
From an infrastructure perspective, setting up the proxy server is pretty simple. Install the <a href="http://www.iis.net/downloads/microsoft/application-request-routing" target="_blank">ARR </a>and <a href="http://www.iis.net/downloads/microsoft/application-request-routing" target="_blank">URL Rewrite</a> extensions, and create a new site in IIS. Set the binding up so it answers requests from the desired host (in the example above, “demo.mysite.com”). The site folder doesn’t need much; a default.htm page, and an empty web config.<br />
<br />
The magic all happens in web.config. The URL Rewrite module is governed by rules. There are two sets, one just called “rules” which are used to route requests to the Sitecore server, and another called “outbound rules” which are used to manipulate the responses from Sitecore before they are returned to the browser. Outbound rules also allow you to define “preconditions” that allow you to restrict when an outbound rule will apply.<br />
<br />
The IIS management console provides an interface for building up all the XML in the config file for all of this. I find that when I’m working with it, I flip between IIS and Notepad++ until I get everything just right.<br />
<br />
The referenced articles provide good guidance for how to use the URL Rewrite module and set up rules. This example web.config could be used to implement our example.<br />
<div>
<br /></div>
<div>
<br /></div>
<pre style="background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-family: "arial"; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> <?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
</system.web>
<system.webServer>
<rewrite>
<rules>
<!--
This rule routes requests everything to the external site.
The use of "HTTP_ACCEPT_ENCODING" ensures that external servers
will send responses in the clear (not zipped or otherwise encoded)
-->
<rule name="Route to external site" stopProcessing="true">
<match url="(.*)" />
<action type="Rewrite" url="http://www.mysite.com/{R:1}" />
<serverVariables>
<set name="HTTP_ACCEPT_ENCODING" value="" />
</serverVariables>
</rule>
</rules>
<outboundRules>
<!--
This rule converts proxied pages' urls to relative urls (so they'll be requested through the ARR server and avoid cross-domain issues)
-->
<rule name="Rewrite External Absolute Paths" preCondition="Request is for html">
<match filterByTags="A, Area, Base, Form, Frame, Head, IFrame, Img, Input, Link, Script" pattern="^http(s)?://www.mysite.com/(.*)" />
<action type="Rewrite" value="/{R:2}" />
</rule>
<!--
This rule removes the X_Frame_Options header, which can prevent the Experience editor from working.
-->
<rule name="Strip x-frame-options" preCondition="Request is for html" patternSyntax="ECMAScript">
<match serverVariable="RESPONSE_X_Frame_Options" pattern="(.+)" />
<action type="Rewrite" value="" />
</rule>
<!--
This rule removes adds "(via proxy)" to the Server header, to aid troubleshooting.
-->
<rule name="Change Server Header">
<match serverVariable="RESPONSE_Server" pattern="(.+)" />
<action type="Rewrite" value="{R:0} (via proxy)" />
</rule>
<!--
This rule injects the FXM script into the HTML from the external site.
-->
<rule name="Add FXM script to tb" preCondition="Request is for html" patternSyntax="ExactMatch">
<match filterByTags="None" pattern="&lt;/head>" />
<action type="Rewrite" value="&lt;script src=&quot;//sitecore.mysite.com/bundle/beacon&quot;>&lt;/script>&quot;/head>" />
</rule>
<preConditions>
<!--
This precondition allows the outbound rules to only act on html responses.
-->
<preCondition name="Request is for html">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="text/html" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
</system.webServer>
</configuration>
</code></pre>
Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.com0tag:blogger.com,1999:blog-8880848735938155014.post-59791382900292178872016-02-02T07:46:00.000-08:002016-02-02T07:48:17.475-08:00Dear John...<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAHolsHBuctI7Z3alS8bBG5MwMccsmmpZKPeKU7h0RUpIHTqL5UjQP6CoaYg9xnuEX9Vxbq1FGPIMyG5hlULETR-nOTIO4BXmS2Nn3mPWFhhNKFYmhXjep-gNwsL5_5xS_-rZNdf6jvGjT/s1600/GoWest.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img alt="We all go West" border="0" height="198" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAHolsHBuctI7Z3alS8bBG5MwMccsmmpZKPeKU7h0RUpIHTqL5UjQP6CoaYg9xnuEX9Vxbq1FGPIMyG5hlULETR-nOTIO4BXmS2Nn3mPWFhhNKFYmhXjep-gNwsL5_5xS_-rZNdf6jvGjT/s320/GoWest.jpeg" title="" width="320" /></a></div>
No I’m not writing to say I’ve left you for another CMS. But John West’s<a href="http://www.sitecore.net/learn/blogs/technical-blogs/john-west-sitecore-blog/posts/2016/02/sitecorejohn-bids-farewell.aspx" target="_blank"> announcement today</a> leaves me wanting to take a short detour down Memory Lane. If you came here looking for technical tidbits, I’ll be hangin’ a right back down Architecture Avenue shortly.<br />
<br />
I had the great good fortune to work directly with John on my very first Sitecore project. It was one of the first projects to be done at scale in North America, and it was my first foray into a true enterprise-level .net CMS. When Lars Nielsen flew out to conduct our first training, John was there, both to learn and to advise. He remained tightly connected throughout the project, providing strategic advice and technical leadership (and answers to my incessant questions). John’s enthusiasm for Sitecore was infectious. His spirit of adventure set the tone for that project, and indeed for my entire Sitecore career.<br />
<br />
John’s thought leadership has been at the bedrock of Sitecore’s growth. His quiet, unassuming tone underlies a deep passion for Sitecore. Owing to John’s example, today’s Sitecore ecosystem is infused with a sense of excitement, wonder, and a craving to learn, create and explore. His blog is a hallmark of his motivational style. John provides the signposts leading to the new and evolving capabilities of the product, while never asserting his knowledge is definitive, never assuming his observations are comprehensive, and never insisting his conclusions are absolute. Being the good teacher he is, he leaves application as an exercise for the student. And exercise we do! Many talented Sitecore professionals share valuable learnings from their Sitecore journeys. But those journeys began with John’s unspoken challenge to “Go West, young man!” (Yes, I went there.)<br />
<br />
Over the years, as John as gone from teacher to mentor to friend, I’ve felt immense pride to be part of this dynamic community that John was so instrumental in creating. Though we have gone from speaking almost every day to interacting only sporadically, every time we see each other it seems we are picking up in mid-sentence. There has never been a “goodbye” with him, and there is not one now. Talk to you soon, friend!<br />
<br />
(And goodbye forever, XSLT!)<br />
<div>
<br /></div>
Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.com2tag:blogger.com,1999:blog-8880848735938155014.post-34275410954376067392015-08-04T08:52:00.000-07:002015-08-04T09:22:29.431-07:00Organizing the Language Menu's Tower of Babel<div style="clear: right; float: right; margin-bottom: 8px; margin-left: 8px; text-align: center;">
<img border="0" height="272" src="https://googledrive.com/host/0B5f9-r16NLrpYUtuaU9iN28yVUk/LanguageTagCloud400x272.jpg" width="400" /></div>
If you have a site with lots of languages, you've no doubt run into some challenges. A small -- but annoying -- one, is the ordering of the language menus. This is particularly problematic when the site has a large number of configured languages, but any given conten item may only have versions in one or two. It can be a chore slogging through the menu looking for ones that have versions.<br />
<br />
This little tidbit allows you to re-order the language menu so that languages that actually have versions will float up to the top of that Tower of Babel.<br />
<br />
<h3>
Finding the pressure point</h3>
When I'm making changes to Sitecore's "internals" I try to be as minimally invasive as possible. Unfortunately, this solution is more like a tourniquet than a pressure point. I want to replace the code-beside for one of Sitecore's XML controls (the control that Sitecore uses for drop-down language menus in the content editor). The only way I know to do that is to replace the XML file and change the <span style="font-family: Courier New, Courier, monospace;"><CodeBeside></span> element. <i>Anyone know a good trick to change the code-beside without replacing this file?</i><br />
<br />
Worse, the decompiled code-beside doesn't seem to lend itself to a surgical strike that just changes one little part. Often, you'll find that Sitecore anticipates your need by doing things like having an overridable class fetch an object that does most of the work. You can just inherit from their class and change that one method to suit your needs.Not the case here. We're going to have to implement the whole class just to change one line of code. Such is life.<br />
<br />
The control for this menu is located at<br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">/Sitecore/Shell/Applications/Content Manager</span><span style="font-family: 'Courier New', Courier, monospace;">/Galleries/Languages/Gallery Languages.xml</span></blockquote>
What we really want to do is make a small change to the associated code-beside. First, we need to change this XML file to use our code-beside instead of Sitecore's:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivT26bbOgTEhRrDRmJ5g9dz2S6SrTC89WWTtkjW68kQGZ1uw4QG7cZgUKee176c3AJMvYZWkMp-SzFieqGgOTTCIdCap0YDPe8t8DQ7c3N-53Ic1qcfDhZRQhMlvCQ7_ZWHU0Luo8fGwss/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> <!--<CodeBeside Type="Sitecore.Shell.Applications.ContentManager.Galleries.Languages.GalleryLanguagesForm,Sitecore.Client"/>-->
<CodeBeside Type="MySolution.Shell.Applications.ContentManager.Galleries.GalleryLanguagesForm,sb1"/>
</code></pre>
<br />
For the code-beside file, we need to copy the entire decompiled Sitecore class, although we're really just changing one line of code. So use your favorite decompiler to snag the Sitecore class (or copy the code from the end of this article), and clean up the references.<br />
<br />
I'm going to change that one pesky line to call a new method, just to isolate the change and make it more tweakable in the future.<br />
<br />
To fetch the list of languages to put in the menu, Sitecore just does a <span style="font-family: Courier New, Courier, monospace;">GetLanguages(currentItem)</span>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://googledrive.com/host/0B5f9-r16NLrpYUtuaU9iN28yVUk/LanguageMenuBadOrder.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://googledrive.com/host/0B5f9-r16NLrpYUtuaU9iN28yVUk/LanguageMenuBadOrder.jpg" /></a></div>
<br />
That works, but I want to take the languages for which there are actually versions, and float them to the top.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://googledrive.com/host/0B5f9-r16NLrpYUtuaU9iN28yVUk/LanguageMenuGoodOrder.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://googledrive.com/host/0B5f9-r16NLrpYUtuaU9iN28yVUk/LanguageMenuGoodOrder.jpg" /></a></div>
<br />
So I change their code to call my method instead of <span style="font-family: Courier New, Courier, monospace;">GetLanguages</span>:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivT26bbOgTEhRrDRmJ5g9dz2S6SrTC89WWTtkjW68kQGZ1uw4QG7cZgUKee176c3AJMvYZWkMp-SzFieqGgOTTCIdCap0YDPe8t8DQ7c3N-53Ic1qcfDhZRQhMlvCQ7_ZWHU0Luo8fGwss/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> foreach (Language language in GetLanguages(currentItem)) //currentItem.Languages)
</code></pre>
<br />
... and then I add the <span style="font-family: Courier New, Courier, monospace;">GetLanguages()</span> method that lets me be a it more finessed about ordering:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivT26bbOgTEhRrDRmJ5g9dz2S6SrTC89WWTtkjW68kQGZ1uw4QG7cZgUKee176c3AJMvYZWkMp-SzFieqGgOTTCIdCap0YDPe8t8DQ7c3N-53Ic1qcfDhZRQhMlvCQ7_ZWHU0Luo8fGwss/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> protected IEnumerable<Language> GetLanguages(Item {
return currentItem.Languages.Where(l => ItemManager.GetVersions(currentItem, l).Count > 0)
.Union(currentItem.Languages.Where(l => ItemManager.GetVersions(currentItem, l).Count == 0));
}
</code></pre>
<br />
And now the languages that are actually <i>used </i>for this item will float to the top. This might be a handy place to do other manipulation you might need for your solution, depending on the business rules for language management.<br />
<br />
Here's the full code for the XML control and the code-beside:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivT26bbOgTEhRrDRmJ5g9dz2S6SrTC89WWTtkjW68kQGZ1uw4QG7cZgUKee176c3AJMvYZWkMp-SzFieqGgOTTCIdCap0YDPe8t8DQ7c3N-53Ic1qcfDhZRQhMlvCQ7_ZWHU0Luo8fGwss/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: 400px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Sitecore;
using Sitecore.Configuration;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.Data.Managers;
using Sitecore.Diagnostics;
using Sitecore.Globalization;
using Sitecore.Shell;
using Sitecore.Web;
using Sitecore.Web.UI.HtmlControls;
using Sitecore.Web.UI.Sheer;
using Sitecore.Web.UI.XmlControls;
using Control = System.Web.UI.Control;
namespace MySolution.Shell.Applications.ContentManager.Galleries
{
public class GalleryLanguagesForm : Sitecore.Shell.Applications.ContentManager.Galleries.GalleryForm
{
protected GalleryMenu Options;
protected Scrollbox Languages;
public GalleryLanguagesForm() : base()
{
}
public override void HandleMessage(Message message)
{
Assert.ArgumentNotNull((object)message, "message");
if (message.Name == "event:click")
return;
this.Invoke(message, true);
}
protected override void OnLoad(EventArgs e)
{
Assert.ArgumentNotNull((object)e, "e");
base.OnLoad(e);
if (Context.ClientPage.IsEvent)
return;
Item currentItem = GetCurrentItem();
if (currentItem == null)
return;
using (new ThreadCultureSwitcher(Context.Language.CultureInfo))
{
foreach (Language language in GetLanguages(currentItem)) //currentItem.Languages)
{
ID languageItemId = LanguageManager.GetLanguageItemId(language, currentItem.Database);
if (!ItemUtil.IsNull(languageItemId))
{
Item obj = currentItem.Database.GetItem(languageItemId);
if (obj == null || !obj.Access.CanRead() || obj.Appearance.Hidden && !UserOptions.View.ShowHiddenItems)
continue;
}
XmlControl xmlControl = ControlFactory.GetControl("Gallery.Languages.Option") as XmlControl;
Assert.IsNotNull((object)xmlControl, typeof(XmlControl));
Context.ClientPage.AddControl((Control)this.Languages, (Control)xmlControl);
Item obj1 = currentItem.Database.GetItem(currentItem.ID, language);
if (obj1 != null)
{
int length = obj1.Versions.GetVersionNumbers(false).Length;
string str1;
if (length != 1)
str1 = Translate.Text("{0} versions.", (object)length.ToString());
else
str1 = Translate.Text("1 version.");
string str2 = str1;
CultureInfo cultureInfo = language.CultureInfo;
xmlControl["Header"] = (object)(cultureInfo.DisplayName + " : " + cultureInfo.NativeName);
xmlControl["Description"] = (object)str2;
xmlControl["Click"] = (object)string.Format("item:load(id={0},language={1},version=0)", (object)currentItem.ID, (object)language);
xmlControl["ClassName"] = !language.Name.Equals(WebUtil.GetQueryString("la"), StringComparison.OrdinalIgnoreCase) ? (object)"scMenuPanelItem" : (object)"scMenuPanelItemSelected";
}
}
}
Item obj2 = Sitecore.Client.CoreDatabase.GetItem("/sitecore/content/Applications/Content Editor/Menues/Languages");
if (obj2 == null)
return;
this.Options.AddFromDataSource(obj2, string.Empty);
}
protected IEnumerable<Language> GetLanguages(Item currentItem)
{
return currentItem.Languages.Where(l => ItemManager.GetVersions(currentItem, l).Count > 0)
.Union(currentItem.Languages.Where(l => ItemManager.GetVersions(currentItem, l).Count == 0));
}
private static Item GetCurrentItem()
{
string queryString1 = WebUtil.GetQueryString("db");
string queryString2 = WebUtil.GetQueryString("id");
Language language = Language.Parse(WebUtil.GetQueryString("la"));
Sitecore.Data.Version version = Sitecore.Data.Version.Parse(WebUtil.GetQueryString("vs"));
Database database = Factory.GetDatabase(queryString1);
Assert.IsNotNull((object)database, queryString1);
return database.GetItem(queryString2, language, version);
}
}
}
</code></pre>
<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivT26bbOgTEhRrDRmJ5g9dz2S6SrTC89WWTtkjW68kQGZ1uw4QG7cZgUKee176c3AJMvYZWkMp-SzFieqGgOTTCIdCap0YDPe8t8DQ7c3N-53Ic1qcfDhZRQhMlvCQ7_ZWHU0Luo8fGwss/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: 400px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> <?xml version="1.0" encoding="utf-8" ?>
<control xmlns:def="Definition" xmlns="http://schemas.sitecore.net/Visual-Studio-Intellisense" xmlns:shell="http://www.sitecore.net/shell">
<Gallery.Languages>
<Gallery>
<!--<CodeBeside Type="Sitecore.Shell.Applications.ContentManager.Galleries.Languages.GalleryLanguagesForm,Sitecore.Client"/>-->
<CodeBeside Type="sb1.Shell.Applications.ContentManager.Galleries.GalleryLanguagesForm,sb1"/>
<Script>
window.onload = function() {
var activeLanguage = document.querySelector('.scMenuPanelItemSelected');
activeLanguage.scrollIntoView(false);
}
</Script>
<Stylesheet Key="GalleryLanguages">
.scMenuPanelItem, .scMenuPanelItem_Hover, .scMenuPanelItemSelected_Hover, .scMenuPanelItemSelected {
padding-left: 0;
padding-right: 0;
padding-top: 8px;
padding-bottom: 8px;
}
.scGalleryGrip {
position: absolute;
bottom: 1px;
left: 1px;
right: 1px;
height: 10px;
}
.scLanguagesGalleryMenu {
overflow: hidden;
vertical-align: top;
border-bottom: 12px solid transparent;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 100%;
height: 100%;
border-collapse: separate;
}
div#Languages img {
display: none;
}
</Stylesheet>
<Border Width="100%" Height="100%">
<GalleryMenu ID="Options" Class="scLanguagesGalleryMenu">
<MenuPanel Height="100%">
<Scrollbox ID="Languages" Class="scScrollbox scFixSize scFixWidthInsideGallery" style="padding-top:0 !important;" Height="100%" Width="100%" />
</MenuPanel>
</GalleryMenu>
<Gallery.Grip />
</Border>
</Gallery>
</Gallery.Languages>
</control>
</code></pre>
<br />
<br />Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.com0tag:blogger.com,1999:blog-8880848735938155014.post-25444741773611495262014-05-28T07:07:00.002-07:002014-06-23T06:57:10.860-07:00Size Doesn’t Matter: Suppressing Size Attributes in Image Tags<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ8_SH1Pr5eTP2Kw524u7ZA025wt-4MOENmFoNG3Cd3T-BSXdXvLUEFbFD_SXVl9FqLZyanGclIaObGvVW7_gaDKZO5yS_GUxHH5o3kXe4wCchU_xa8mHVEwUyFuHdNTOKlOVHM6cm2sM7/s1600/measure.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ8_SH1Pr5eTP2Kw524u7ZA025wt-4MOENmFoNG3Cd3T-BSXdXvLUEFbFD_SXVl9FqLZyanGclIaObGvVW7_gaDKZO5yS_GUxHH5o3kXe4wCchU_xa8mHVEwUyFuHdNTOKlOVHM6cm2sM7/s1600/measure.png" style="-goog-ms-box-shadow: none; -moz-box-shadow: none; -webkit-box-shadow: none; border-style: none; box-shadow: none;" /></a><br />
<br />
On a recent, massively-responsive project, our front-end developer asked us to (well, he actually threatened to hold his breath until he turned blue unless we would) remove the height and width attributes from the image tags in our Sitecore site. He’s one of the best front-end guys I've ever worked with, so instead of just dismissing this as “front-end guys will be front-end guys”, I decided to see if we could indulge him.<br />
<br />
It makes sense, actually. Client-side code can deal manipulating height and width easily enough when rendering on different devices. But it you want the thrill of waving around the resize handle and watching all that responsiveness a’responding, then it’d be better if the height and width attributes weren't there in the first place.<br />
<br />
By and large, there are two ways an image tag finds its way into a page generated by Sitecore. It may come from an image field, or from an embedded image in an HTML field. So we should be able to tackle this in the <span style="font-family: Courier New, Courier, monospace;">renderField </span>pipeline, assuming we've been good boys and girls and used field renderers everywhere (and if you haven’t, then go to your room and think about what you've done).<br />
<br />
The two cases (image fields and html fields) pose different challenges, so let’s look at them separately. Or if you don’t want to dig in, then you can stop reading now, download the module <a href="http://googledrive.com/host/0B5f9-r16NLrpcEl3OEtlblZDSkk/DimensionlessImages-1.0.zip">package</a> or source code (<a href="http://googledrive.com/host/0B5f9-r16NLrpcEl3OEtlblZDSkk/DimensionlessImages-Source.zip">zip file</a>, <a href="https://github.com/auzick/DimensionlessImages" target="_blank">GitHub</a>, or <a href="https://marketplace.sitecore.net/en/Modules/Dimensionless_Images.aspx" target="_blank">Sitecore Marketplace</a>) and have at it.<br />
<br />
<h2>
Image Fields</h2>
We've got images in image fields, and we’re using field renderers to generate image tags at runtime. Sitecore uses <span style="font-family: Courier New, Courier, monospace;">Sitecore.Pipelines.RenderField.GetImageFieldValue</span> to do this. When we take a look under the hood, we see it in turn is using a <span style="font-family: Courier New, Courier, monospace;">Sitecore.Xml.Xsl.ImageRenderer</span>. Luckily, <span style="font-family: Courier New, Courier, monospace;">GetImageFieldValue </span>uses a virtual method <span style="font-family: Courier New, Courier, monospace;">CreateRenderer</span>, so we can shim in our own class that inherits from <span style="font-family: Courier New, Courier, monospace;">GetImageFieldValue </span>and override <span style="font-family: Courier New, Courier, monospace;">CreateRenderer </span>to substitute our own handy-dandy <span style="font-family: Courier New, Courier, monospace;">ImageRenderer </span>class.<br />
<br />
Now, Sitecore's <span style="font-family: Courier New, Courier, monospace;">ImageRenderer </span>class is pretty bulky, and it has more stuff that deals with dimensions than a cartographer’s workshop. I’d like to just inherit from theirs and find a good pressure point to slap down those size attributes. Taking a good look at the Render method in Sitecore’s <span style="font-family: Courier New, Courier, monospace;">ImageRenderer</span>, it looks like someone anticipated our need. The last thing it does to determine the size is to call a virtual method called <span style="font-family: Courier New, Courier, monospace;">AdjustImageSize</span>. All we need to do is override that and set the height and width properties to zero. The existing Sitecore code is already set up to suppress the height and width attributes if these properties are zero.<br />
<br />
So we need two pretty lightweight classes and an override in a config file. First, the config file. We need to tell Sitecore to replace its <span style="font-family: Courier New, Courier, monospace;">GetImageFieldValue </span>processor with ours.<br />
<div>
<br /></div>
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<renderField>
<processor
type="DimensionlessImages.Pipelines.RenderField.GetImageFieldValue,
DimensionlessImages"
patch:instead="*[@type='Sitecore.Pipelines.RenderField.GetImageFieldValue,
Sitecore.Kernel']"
/>
</code></pre>
<div>
<br />
Then, there’s our own GetImageFieldValue processor, which inherits from Sitecore’s and overrides the CreateReplacer method.<br />
<br /></div>
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> namespace DimensionlessImages.Pipelines.RenderField
{
using Sitecore.Xml.Xsl;
public class GetImageFieldValue : Sitecore.Pipelines.RenderField.GetImageFieldValue
{
protected override ImageRenderer CreateRenderer()
{
return new DimensionlessImages.ImageRenderer();
}
}
}
</code></pre>
<div>
<br />
And lastly, there’s our own <span style="font-family: Courier New, Courier, monospace;">ImageRenderer</span>, which overrides the <span style="font-family: Courier New, Courier, monospace;">AdjustImageSize </span>method.<br />
<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> namespace DimensionlessImages
{
using Sitecore.Data.Fields;
public class ImageRenderer : Sitecore.Xml.Xsl.ImageRenderer
{
protected override void AdjustImageSize(ImageField imageField, float imageScale, int imageMaxWidth, int imageMaxHeight, ref int w, ref int h)
{
w = 0;
h = 0;
}
}
}
</code></pre>
<br />
Piece of cake, that.<br />
<br />
<h2>
HTML Fields</h2>
HTML fields are a different animal. We've got a hunk of existing html, not just some data we’ll use to form HTML at runtime.<br />
<br />
When a media library image is inserted in the rich text editor, Sitecore adds the height and width attributes to the img tag. So between that, and the possibility that content people might edit HTML manually (bless their little programmer-wannabe hearts), we’re going to have lots of height and width attributes in our HTML fields.<br />
<br />
We can use the HtmlAgilityPack to strip these attributes off the <span style="font-family: Courier New, Courier, monospace;">img </span>tags in in the <span style="font-family: Courier New, Courier, monospace;">renderField </span>pipeline. Although the HtmlAgilityPack is wicked fast, we could start to see a performance hit of there are lots of HTML fields on complex pages. It’d better to do it in a save handler or a <span style="font-family: Courier New, Courier, monospace;">publishItem </span>processor, but that could present problems with the page editor or if there is already a lot of existing content. I’m seeing times of less than 0.1ms per HTML field to strip the tags at runtime, so to make this code more bullet-proof (well, ok, to let me be lazy) I’m going to do it in <span style="font-family: Courier New, Courier, monospace;">renderField</span>. If your solution permits, by all means move this processing to a save handler.<br />
<br />
Like before, we’ll start with the config changes…<br />
<div>
<br /></div>
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<renderField>
<processor type="DimensionlessImages.Pipelines.RenderField.GetFieldValue, DimensionlessImages"
patch:instead="*[@type='Sitecore.Pipelines.RenderField.GetFieldValue, Sitecore.Kernel']"
/>
</code></pre>
<br />
We’ll use a custom <span style="font-family: Courier New, Courier, monospace;">GetFieldValue </span>processor. It is actually simpler than the image field case, because all we have to do is catch “rich text” fields and strip the height and width attributes.<br />
<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> namespace DimensionlessImages.Pipelines.RenderField
{
using Sitecore.Pipelines.RenderField;
public class GetFieldValue : Sitecore.Pipelines.RenderField.GetFieldValue
{
public new void Process(RenderFieldArgs args)
{
base.Process(args);
if (args.FieldTypeKey == "rich text")
{
Sitecore.Diagnostics.Profiler.StartOperation("Stripping image tags from field: " + args.FieldName);
args.Result.FirstPart = HtmlUtil.StripDimensions(args.Result.FirstPart);
Sitecore.Diagnostics.Profiler.EndOperation();
}
}
}
}
</code></pre>
<br />
Finally, we need a helper method uses the HtmlAgilityPack to strip the dimension attributes…<br />
<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> namespace DimensionlessImages
{
using System;
using HtmlAgilityPack;
public class HtmlUtil
{
public static string StripDimensions(string text)
{
if (string.IsNullOrWhiteSpace(text))
{
return text;
}
string outText = text;
try
{
var doc = new HtmlDocument();
doc.LoadHtml(outText);
StripAttribute(doc, "width");
StripAttribute(doc, "height");
outText = doc.DocumentNode.WriteContentTo();
}
catch (Exception)
{}
return outText;
}
private static void StripAttribute(HtmlDocument doc, string attribute)
{
// For reasons surpassing all understanding, HtmeAgilityPack returns null instead of an empty collection
// when the query finds no results.
HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes(String.Format("//img[@{0}]", attribute));
if (nodes == null || nodes.Count.Equals(0))
{
return;
}
foreach (HtmlNode node in nodes)
{
node.Attributes[attribute].Remove();
}
}
}
}
</code></pre>
<br />
<div class="MsoNormal">
- - -<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
This code addresses the most likely cases that emit image
tags to the browser. A given solution may have other cases, like stuff being
generated by custom code or copied from static files. For cases like that,
we've provided the static method that custom code can use to “play ball” with
the rest of this code.<o:p></o:p><br />
<br />
<div style="border: 1px solid black; padding: 8px;">
<b><i>Download:</i> <a href="http://googledrive.com/host/0B5f9-r16NLrpcEl3OEtlblZDSkk/DimensionlessImages-1.0.zip" target="_blank">Module (package only)</a> or source code (<a href="http://googledrive.com/host/0B5f9-r16NLrpcEl3OEtlblZDSkk/DimensionlessImages-Source.zip">zip file</a>, <a href="https://github.com/auzick/DimensionlessImages" target="_blank">GitHub</a>, or <a href="https://marketplace.sitecore.net/en/Modules/Dimensionless_Images.aspx" target="_blank">Sitecore Marketplace</a>).</b>
</div>
</div>
<br />
<div class="MsoNormal">
<br /></div>
<br />
<br />
<br />
<br /></div>
Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.com0tag:blogger.com,1999:blog-8880848735938155014.post-54745697230840649862013-11-29T15:28:00.001-08:002014-02-12T06:55:23.116-08:00Sitecore Profiling and Tracing<div>
It's been a while since I've posted. I have a couple of bigger subjects on the spike, but for now here's a quick word about Sitecore profiling and tracing.
</div>
<div>
<br /></div>
Have you ever had to debug a problem with a Sitecore page and you wind up slogging through the log, trying to find the related error? Or have you ever wondered which of your renderings or sublayouts might be causing performance issues? Or maybe you have custom logic in a pipeline processor, and you wish there was an easy way to emit debugging or performance information?<br />
<div>
<br /></div>
<div>
There are a couple of underutilized features in Sitecore that can be a real time saver in situations like this: <span style="font-family: Courier New, Courier, monospace;">Sitecore.Diagnostics.Tracer</span> and <span style="font-family: Courier New, Courier, monospace;">Sitecore.Diagnostics.Profiler</span>. These classes are sitting right next to the much-used <span style="font-family: Courier New, Courier, monospace;">Sitecore.Diagnostics.Log</span> class, but are often overlooked. Both of these classes allow you to emit information directly to the page when in debug mode. This is a far more convenient and useful way to do debugging than writing to the Sitecore log.
</div>
<div>
<br /></div>
<div>
The <span style="font-family: 'Courier New', Courier, monospace;">Profiler</span> class is useful for tracking the progress of the page rendering cycle, and for gathering performance data about the components and code being executed. It has the usual <span style="font-family: Courier New, Courier, monospace;">Info</span>, <span style="font-family: Courier New, Courier, monospace;">Warning</span> and <span style="font-family: Courier New, Courier, monospace;">Error</span> static methods you are probably familiar with from the <span style="font-family: Courier New, Courier, monospace;">Log</span> class, but the real gems here are the <span style="font-family: Courier New, Courier, monospace;">StartOperation </span>and <span style="font-family: Courier New, Courier, monospace;">EndOperation</span> methods. With them, you can gather valuable performance data about parts of the rendering process, including both large chunks of a process and nested inner pieces of the process. For example, the <a href="http://marketplace.sitecore.net/en/Modules/MetaTag_Manager.aspx" target="_blank">Arke MetaTag Manager</a> module emits quite a bit of information about it's internal workings to the debugger.
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjiONl56t7ScXpmBrQLNHJSsjfg4vhcioXQWyBF0xaSyKOIv-vRb38bqEMTRLyYDcgf_i6COdrzAbqpYtcHANIAIme2ZwgbYSPkp6n1lAotjItbeseQGQHiTcwVzUqNmnXS4WZGK8Cp1qR/s1600/11-29-2013+1-11-35+PM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;">
<img alt="" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjiONl56t7ScXpmBrQLNHJSsjfg4vhcioXQWyBF0xaSyKOIv-vRb38bqEMTRLyYDcgf_i6COdrzAbqpYtcHANIAIme2ZwgbYSPkp6n1lAotjItbeseQGQHiTcwVzUqNmnXS4WZGK8Cp1qR/s640/11-29-2013+1-11-35+PM.png" height="336" title="" width="640" /></a>
</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div>
The information provided not only helps us understand the performance impact of this process, but also helps us troubleshoot when we suspect that a tag is not being gathered properly.
</div>
<div>
<br /></div>
<div>
To output this information, it's a simple matter of adding a two lines of code. For example, this is the <span style="font-family: Courier New, Courier, monospace;">Process </span>method used for the <span style="font-family: Courier New, Courier, monospace;">CustomTag </span>pipeline processor:
</div>
<div>
<br /></div>
<div>
<div>
<div>
<!-- begin code -->
<br />
<div style="background-color: #e8e8e8; padding: 4px 4px 4px 4px;">
<code>
<span style="font-family: Courier New, Courier, monospace;">public void Process(InjectMetaTagsPipelineArgs args)</span>
</code><br />
<div>
<code><span style="font-family: Courier New, Courier, monospace;">{</span>
</code></div>
<code>
</code><br />
<div>
<code><span style="background-color: yellow; font-family: Courier New, Courier, monospace;"> Sitecore.Diagnostics.Profiler.StartOperation(</span>
</code></div>
<code>
</code>
<div>
<code><span style="background-color: yellow; font-family: Courier New, Courier, monospace;"> "Adding custom tag '" + GetSignatureName() + "'"</span>
</code></div>
<code>
<div>
<span style="background-color: yellow; font-family: Courier New, Courier, monospace;"> );</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;">
<br />
</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> try</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> {</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> Assert.ArgumentNotNullOrEmpty(</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> TypeSignature, </span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> "Class not supplied"</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> );</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> args.MetaTags.Add(ReflectionUtil.GetCustomTag(TypeSignature));</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> catch (Exception ex)</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> {</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> Sitecore.Diagnostics.Tracer.Error(</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> "CustomTag failed.", </span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> ex</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> );</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> Sitecore.Diagnostics.Log.Error(</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> "CustomTag failed.", </span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> ex, </span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> "CustomTag"</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> );</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> finally</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> {</span>
</div>
<div>
<span style="background-color: yellow; font-family: Courier New, Courier, monospace;"> Sitecore.Diagnostics.Profiler.EndOperation();</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;">}</span>
</div>
</code>
</div>
</div>
</div>
</div>
<!-- end code -->
<br />
<div>
<div>
<br /></div>
</div>
<div>
Sitecore will nest sets of profiling blocks, which makes it easy to trace through a process to see where a problem or performance hit may be.
</div>
<div>
<br /></div>
<div>
The other handy class for "in-page" debugging is the <span style="font-family: Courier New, Courier, monospace;">Tracer</span> class. Again , this class has the familiar <span style="font-family: Courier New, Courier, monospace;">Info</span>, <span style="font-family: Courier New, Courier, monospace;">Warning</span> and <span style="font-family: Courier New, Courier, monospace;">Error</span> static methods, but the output from these methods is written to the "Trace" section of the page debugger. I use these methods for writing out error or info strings much the way I would to the Sitecore Log, but they're written to the page itself, where troubleshooting is much easier. It's always nice to just be able to turn on the debugger to see this info instead of having to search through the log file.
</div>
<div>
<br /></div>
<div>
Again, looking at the sample code above, note that the "catch" statements include a line of code to write the error to the tracer, which would yield this:
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwmpXXkFgFASsHBwWMJAidjv2rFLV25W4TUiNv_uaPzoSeJdbFYdrtX61cx0yq_AfSMeKAuFJrp6CaTzhgyZNQjBkYbcDymRTblHnZZneZH6gqa3vV9eZ171LeFR1kH7n482GdOuAZyIHI/s1600/11-29-2013+5-05-18+PM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;">
<img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwmpXXkFgFASsHBwWMJAidjv2rFLV25W4TUiNv_uaPzoSeJdbFYdrtX61cx0yq_AfSMeKAuFJrp6CaTzhgyZNQjBkYbcDymRTblHnZZneZH6gqa3vV9eZ171LeFR1kH7n482GdOuAZyIHI/s640/11-29-2013+5-05-18+PM.png" height="209" width="640" /></a>
</div>
<div>
That beats searching for the error on the log file ... or worse, throwing a "yellow screen".
</div>
<div>
<br /></div>
<div>
Happy tracing!
</div>
<div>
<br /></div>
<div>
<br /></div>
Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.com0tag:blogger.com,1999:blog-8880848735938155014.post-58405240423074603772013-07-03T13:15:00.000-07:002013-07-04T14:24:49.904-07:00Hiding fields in the Content Editor<img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMEJeXSIJrvo4fycOL4IXVPMf77dCkYw0t0orG1oSDP6ojSf9gF1cMTmOOarl9rbXGbX7iz6H0D5ZB8GetiEgd0zLTBKK_GEAGiuQU_BiIa2-A8Xbf2T-TVe2yW8Qg0i1_iEA2L-WCpptI/s1600/Hiding-fields.jpg" style="-moz-box-shadow: 0px 0px 0px transparent !important; -webkit-box-shadow: 0px 0px 0px transparent !important; background: none !important; border: none !important; box-shadow: 0px 0px 0px transparent !important; padding: none !important;" />
<br />
<div>
</div>
<br />
<div style="background-color: #e8e8e8; float: right; margin: 0px 8px 8px 32px; padding: 8px 8px 8px 8px; width: 200px;">
<i>The source code, package and documentation for this module are available from the <a href="http://marketplace.sitecore.net/en/Modules/Hide_Field_Template_Extension.aspx" target="_blank">Sitecore Marketplace</a>.</i></div>
Anyone who has worked much with the Sitecore Content Editor knows that there are a bunch of "standard" fields that Sitecore usually keeps hidden. These fields are either system-managed, or are rarely used and typically only changed by developers or administrators. With proper permissions, you can see these fields (<span style="font-family: Courier New, Courier, monospace;">View > Standard Fields</span>), but they are usually turned off to reduce clutter.<br />
<br />
Sometimes I want to hide some of the fields that are created as part of my solutions. This may include:<br />
<ul>
<li>Fields that are intended only for administration. To avoid clutter, these fields should be hidden unless the content editor is showing standard (system) fields.</li>
<li>Fields that are populated by handlers. This could include fields that are populated by a save handler and should not be edited.</li>
<li>Fields that are populated by a publishing processor, to aggregate information or provide hints or shortcuts to the CD, to improve performance or to pass along other data.</li>
<li>Fields that are populated or reconciled by a data importer, which should not be edited.</li>
</ul>
<br />
I've created a module (available from the <a href="http://marketplace.sitecore.net/en/Modules/Hide_Field_Template_Extension.aspx" target="_blank">Sitecore Marketplace</a>) to do just that.<br />
<br />
This module extends Sitecore to allow developers to designate when a field should be hidden from the content editor. The options are to (1) always show the field, (2) always hide the field, or (3) only show the field when the content editor is showing standard (system) fields.<br />
<br />
The module extends the “<span style="font-family: Courier New, Courier, monospace;">GetContentEditorFields</span>” pipeline and also extends the <span style="font-family: Courier New, Courier, monospace;">Template field</span> template that Sitecore uses for managing template fields in the content editor. A description of the techniques underlying this are included a bit farther down.<br />
<br />
<h2>
</h2>
<h2>
Installing the module</h2>
There are three key pieces required for this module: the assembly, the config file and Sitecore content items. These are all included in the package <span style="font-family: Courier New, Courier, monospace;">Arke.Templates.zip</span>. To install this module, simply upload this package to Sitecore and install it normally.<br />
<br />
If security prevents the package installer from deploying the assembly (<span style="font-family: Courier New, Courier, monospace;">.dll</span>) file or the <span style="font-family: Courier New, Courier, monospace;">Arke.Templates.config</span> file, these can be extracted from the zip file and deployed manually.
<br />
<br />
<br />
<h2>
Using the module</h2>
Once the module is installed, you can manage the visibility of any field by changing the “Show In Content Editor” setting on any field item. The options are…<br />
<ul>
<li><b>Always</b>: Always show this field.</li>
<li><b>Never</b>: Never show this field.</li>
<li><b>When showing standard fields</b>: Show this field when <span style="font-family: Courier New, Courier, monospace;">Standard Fields</span> is turned on in the ribbon (under <span style="font-family: Courier New, Courier, monospace;">View</span>).</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-T1npWasifG8n1x5OFLE7e9GcbgpAp_aDGHDX4UvZkD7ytK62mbrrKdSgAgxF7rNS0xP9sNxJFD6pf-5a9PKbjBQjoKe5sfhyFvKUgJoeGIR2Eqz0Yy2XKTu5NlUhG1yJLY9d-_sTBbuK/s996/image001.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="168" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-T1npWasifG8n1x5OFLE7e9GcbgpAp_aDGHDX4UvZkD7ytK62mbrrKdSgAgxF7rNS0xP9sNxJFD6pf-5a9PKbjBQjoKe5sfhyFvKUgJoeGIR2Eqz0Yy2XKTu5NlUhG1yJLY9d-_sTBbuK/s400/image001.png" style="-moz-box-shadow: 0px 0px 0px transparent !important; -webkit-box-shadow: 0px 0px 0px transparent !important; background: none !important; border: none !important; box-shadow: 0px 0px 0px transparent !important; padding: none !important;" width="400" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<h2>
</h2>
<h2>
Configuration options</h2>
The <span style="font-family: Courier New, Courier, monospace;">Arke.Templates.Config</span> file allows the system administrator to set how the module behaves. “<span style="font-family: Courier New, Courier, monospace;">HideEmptySections</span>” governs how to handle content editor sections when all of the fields within that section have been hidden:<br />
<br />
<div style="background-color: #e8e8e8; padding: 4px 4px 4px 4px;">
<code><span class="Apple-tab-span" style="white-space: pre;"> </span><!-- Hide empty sections<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>Should the template section be hidden entirely if all of the fields<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>within it are hidden<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>--><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><setting name="Arke.Templates.HideEmptySections" value="true" /><br />
</code>
</div>
<br />
<br />
<h2>
</h2>
<h2>
How the module works</h2>
The module works by extending the <span style="font-family: Courier New, Courier, monospace;">GetContentEditorFields</span> pipeline.<br />
<br />
Like many other Sitecore pipelines, <span style="font-family: 'Courier New', Courier, monospace;">GetContentEditorFields</span> maintains a collection in its <span style="font-family: Courier New, Courier, monospace;">PipelineArgs</span> class that is populated by a series of processor items. When Sitecore is rendering the content panel, it uses this pipeline to gather all of the fields and sections that it needs to display. As each processor runs, it adds fields and sections to a collection, which Sitecore uses at the end of the pipeline to form the editing panel.<br />
<br />
When developing a pipeline processor in a situation like this, it is tempting to replace Sitecore’s processor with your own, in order to control what data is being added to the <span style="font-family: Courier New, Courier, monospace;">args</span> object. However, this often requires extensive duplication of Sitecore’s code, as many of the classes in the Sitecore namespace are not public or not static, and so must be replicated in the custom processor. It also means the custom processor is less “future-proof”. If a future Sitecore release changes the processor you replaced, you will have to re-create your custom processor to reflect Sitecore’s changes.<br />
<br />
The architecture of this module leaves Sitecore’s <span style="font-family: Courier New, Courier, monospace;">GetContentEditorFields </span>pipeline processors intact, and adds a new custom processor to the end of the pipeline (the namespaces below have been truncated for readability):<br />
<br />
<div style="background-color: #e8e8e8; padding: 4px 4px 4px 4px;">
<code>
<pipelines><br />
<getContentEditorFields><br />
<processor<br />
type="Arke…TrimHiddenFields, Arke.SharedSource.Templates"<br />
patch:after="processor[@type='Sitecore...GetExplicitFields, Sitecore.Client']<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
/><br />
</getContentEditorFields><br />
</pipelines><br />
</code>
</div>
<br />
When the default processors have completed, the args class contains all of the fields and sections gathered by the standard processors. The <span style="font-family: Courier New, Courier, monospace;">TrimHiddenFields</span> processor then iterates over all of the content sections, examining all the fields to see if their “hide” box is checked, and removing them as appropriate. It them removes the section if it no longer has visible fields.<br />
<br />
<div style="background-color: #e8e8e8; padding: 4px 4px 4px 4px;">
<code>
public void Process(GetContentEditorFieldsArgs args)<br />
{<br />
Assert.ArgumentNotNull(args, "args");<br />
if (args.Sections == null || args.Sections.Count == 0)<br />
{<br />
return;<br />
}<br />
if (Settings.HidingCheckedFields == HideCheckedField.Never)<br />
{ <br />
return;<br />
}<br />
this.args = args;<br />
for (int sectionIndex = 0; sectionIndex < args.Sections.Count; sectionIndex++)<br />
{<br />
Editor.Section section = args.Sections[sectionIndex];<br />
TrimFields(section); <br />
if (Settings.HidingEmptySections && section.Fields.Count == 0)<br />
{<br />
args.Sections.RemoveAt(sectionIndex);<br />
sectionIndex--;<br />
}<br />
}<br />
}</code><br />
<code><br />
private void TrimFields(Editor.Section section)<br />
{<br />
for (int fieldIndex = 0; fieldIndex < section.Fields.Count; fieldIndex++)<br />
{<br />
if (FieldIsHidden(section.Fields[fieldIndex]))<br />
{<br />
section.Fields.RemoveAt(fieldIndex);<br />
fieldIndex--;<br />
}<br />
}<br />
}</code><br />
<code><br />
private bool FieldIsHidden(Editor.Field field)<br />
{<br />
try<br />
{<br />
Item templateFieldItem = GetTemplateFieldItem(field, args.Item.Database);<br />
if (templateFieldItem == null)<br />
{<br />
return false;<br />
}<br />
bool isHiddenChecked = false;<br />
try<br />
{<br />
CheckboxField fld =<br />
(CheckboxField)templateFieldItem.Fields[Settings.HideCheckboxFieldName];<br />
isHiddenChecked = fld.Checked;<br />
}<br />
catch { }<br />
switch (Settings.HidingCheckedFields)<br />
{<br />
case HideCheckedField.Never:<br />
return false;<br />
break;<br />
case HideCheckedField.Always:<br />
return isHiddenChecked;<br />
break;<br />
case HideCheckedField.WhenHidingStandardFields:<br />
return isHiddenChecked && (!UserOptions.ContentEditor.ShowSystemFields);<br />
break;<br />
}<br />
}<br />
catch { }<br />
return false;<br />
}<br />
<br />
private Item GetTemplateFieldItem(Editor.Field field, Database database)<br />
{<br />
try<br />
{<br />
return database.GetItem(field.TemplateField.ID);<br />
}<br />
catch { }<br />
return null;<br />
}<br />
</code>
</div>
<br />
<code><br /></code>
It may seem wasteful to “undo” some of the work down by previous processors. However, the CPU overhead for this is pretty light, and any item data the custom processor needs (like field definition items) will have already been read (and presumably cached) by previous steps. This slight extra overhead is a small price to pay to keep this additional functionality self-contained, and to avoid replacing any of Sitecore’s default processors. Also bear in mind that this activity only happens in the content management server, where I regard performance as somewhat less critical than the content delivery instance.<br />
<br />
<h4>
More resources...</h4>
<ul>
<li>John West has a different approach to a similar need: <i><a href="http://www.sitecore.net/france/Community/Technical-Blogs/John-West-Sitecore-Blog/Posts/2013/02/Render-Content-Editor-Fields-Read-Only-in-the-Sitecore-ASPNET-CMS.aspx" target="_blank">Render Content Editor Fields Read-Only in the Sitecore ASP.NET CMS</a></i></li>
<li><a href="http://sdn.sitecore.net/Reference/Sitecore%206/Client%20Configuration%20Cookbook.aspx" target="_blank"><i>Sitecore Client Configuration Cookbook</i></a></li>
</ul>
<br />
<br />
<br />Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.com2tag:blogger.com,1999:blog-8880848735938155014.post-20684373684940178282013-03-12T15:16:00.001-07:002013-03-27T11:09:37.208-07:00The Heart of the Meta<h4 style="border-bottom: solid 1px #DDDDDD; border-top: solid 1px #DDDDDD;" target="_blank">
<span style="font-weight: normal;"><i>
This article describes Arke System's <a href="http://marketplace.sitecore.net/en/Modules/MetaTag_Manager.aspx" target="_blank">Meta Tag Manager</a>
shared source module, available for free download from the <a href="http://marketplace.sitecore.net/en/Modules/MetaTag_Manager.aspx" target="_blank">Sitecore Marketplace</a>.</i></span></h4>
<div style="clear: both;">
</div>
<br />
<div class="separator" style="clear: both; text-align: left;">
<img border="0" margin="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGWrAWnOXSJZsVpFTbHBwp7ze-4W_66pEm8SOAc6KzHroaXRDIv3Lny-s9ayIZH41AdvFJE8JD5jKUkTlODAcHKFRM_LN8Mgh5aS__EB_U2TsYlraDy9SOfn5klmMznggx0yfroiUv2Nu4/s1600/meta-570.gif" style="-moz-box-shadow: 0px 0px 0px transparent !important; -webkit-box-shadow: 0px 0px 0px transparent !important; background: none !important; border: none !important; box-shadow: 0px 0px 0px transparent !important; margin: 0px 0px 0px 0px !important; padding: none !important;" /></div>
<div style="clear: both; text-align: center;">
</div>
<br />
<br />
<blockquote class="tr_bq">
<span style="font-size: x-small; font-weight: normal;"><i>Update 27-March-2013: Several changes have been made to this module, including adding new tag types (properties), adding support for all tag types in the pipeline, and creating "Custom Tags" to replace the less intuitive "Dynamic Processors"). See the documentation file in the Sitecore Marketplace for details.</i></span></blockquote>
It's almost inevitable that at some point in a solution's lifespan, there comes a need to add various types of meta tags to the head of your pages. Sometimes it's site-wide tags like turning off the silly IE image toolbar (thankfully a legacy issue now). Sometimes it's something you may need at the page level, like instructing robots not to crawl the page. Sometimes the tag values are static, like a robot directive Sometimes they're dynamic, like page type (template), GUID or other info needed by crawlers or page script. Sometimes the need is simple, sometimes there are very complex tagging requirements for analytics or search crawling.<br />
<br />
I've found that over time, solutions wind up with meta tags being handled in dozens of ways ... sometimes in markup, sometimes in code-behind, sometimes in base layouts, sometimes in renderings, sometimes in handlers. Discovering the providence of a tag you find in the final HTML can be challenging. <br />
<br />
Recently, a client was concerned about the S.E.O. ramifications of having identical pages at more than one URL on their Sitecore site (for example, with and without "/en" in the path). Having pages like this (or worse, internal links formed differently) can decrease search ranking. If the same page is at two URLs, and there are links to both, the "link juice" is diluted across those pages.<br />
<br />
One way to overcome this is to issue a "canonical URL" meta tag. If you emit a meta tag with the same canonical URL on both pages, it informs the search engine which URL is "authoritative" for that page. The search engine will (theoretically) award all of the link juice to the canonical URL.<br />
<br />
If you are using a common base layout class, the simplest thing to do would be to have the code-behind of that class hang the canonical meta tag in the page header. But in this case, the client did not have a common base layout.<br />
<br />
This kind of thing has come up often enough that I was motivated to create a MetaTag management module. Different chunks of code need to create meta tags, and it’s not always convenient or even possible to limit the timing of meta tag generation to the layout.<br />
<br />
This article only covers some highlight from the module. For more detail, see the full documentation at the <a href="http://marketplace.sitecore.net/en/Modules/MetaTag_Manager.aspx" target="_blank">Sitecore Marketplace</a>.<br />
<br />
<h3>
Overview</h3>
<div>
<br /></div>
<br />
Tags can be added four ways:<br />
<br />
<ol>
<li>By adding processors to the InjectMetaTags pipeline.</li>
<li>In the content editor, by adding tag definitions to a GlobalTags folder (these tags appear site-wide).</li>
<li>In the content editor, by selecting pre-defined tags in a field that can be added to any template (these tags appear on individual pages)</li>
<li>In code, at any point in the page lifecycle. This allows code in layouts, sublayouts and renderings to add meta tags “ad hoc”.</li>
</ol>
<br />
<div>
<br /></div>
<br />
<ol>
</ol>
Several tag "types" are support to simplify creation of tags in code or configuration:<br />
<br />
<br />
<ol>
<li>Static tags: Tags where both the name and value are static, such a “robots noindex”.</li>
<li>Custom tags: Tags where either the name, value or both are generated by custom logic.</li>
<li>Method tags: Tags where the name is static, and the value is derived from an existing static method.</li>
<li>Property tags: Tags where the name is static, and the value is derived from an existing static property.</li>
</ol>
<br />
<div>
Method and Property tags allow creation of dynamic tags entirely in configuration, with no coding. These tags derive their values at runttime from existing methods or properties.</div>
<br />
<br />
There seems to be two subspecies of meta tag markup, those that use a “property” attribute and those that use “name”. Both are still effectively name/value pairs. The “name” style tag seems to be more common, but notable sets of commonly-used tags (like OpenGraph tags) use the “property” structure. This module allows both styles.<br />
<div>
<br /></div>
<div>
<h3>
Architecture</h3>
<div>
<br /></div>
<div>
The module uses a collection of tag description objects (not markup) that persist through the page lifecycle. Tags are added to this collection in various ways, and are flushed to the head section of the page after pre-render. To flush the tags to the page, each is formed into a custom <span style="font-family: Courier New, Courier, monospace;">MetaTag </span>control. </div>
<div>
<br /></div>
<div>
No modifications to the solution’s code or markup are required; all of the artifacts and event hooks are created using pipeline processors added to the <span style="font-family: Courier New, Courier, monospace;">httpRequestBegin </span>and <span style="font-family: Courier New, Courier, monospace;">insertRenderings </span>pipelines.<br />
<br />
<h4>
Adding Tags From Code</h4>
</div>
<div>
<br /></div>
<div>
Coders can add tags to the page in any point in the page lifecycle, using provided convenience methods.<br />
<br />
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><pre style="background-position: initial initial; background-repeat: initial initial; font-family: Consolas;"> <span style="color: #2b91af;">PageTags</span>.AddTag(<span style="color: #2b91af;">MetaTagType</span>.name, <span style="color: #a31515;">"MyTag"</span>, <span style="color: #a31515;">"This is my tag."</span>);</pre>
</pre>
</div>
<div>
<h4>
Managing Tags in the Content Editor</h4>
<br /></div>
<div>
Site administrators can create site-wide tags by adding "StaticMetaTag" and "DynamicMetaTag" items to the appropriate folder in the Modules section of the content tree. Items added to the "GlobalTags" folder are emitted on every page; items added to the "OptionalTags" folder are available for content authors to use selectively in their pages (see below).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqsRR95L1HyBcmmj5CKTE78vAEU2YbocRVFcN4i5Uy8oTPib0noJRqIjEKaeCvFsyEwh1zZKH2QoniUhMx89GKE7ZeIGX7KYvuWCWcA0k98GWCdsYgLPpdQsw7Ic5H-k9WSRse9TYEKZJG/s1600/DefinedTags.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqsRR95L1HyBcmmj5CKTE78vAEU2YbocRVFcN4i5Uy8oTPib0noJRqIjEKaeCvFsyEwh1zZKH2QoniUhMx89GKE7ZeIGX7KYvuWCWcA0k98GWCdsYgLPpdQsw7Ic5H-k9WSRse9TYEKZJG/s1600/DefinedTags.png" /></a></div>
</div>
<div>
<br /></div>
<div>
The definition of a StaticMeta tag is simple; just specify the tag type ("name" or "property"), and the key and value.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRTlFu8ZkBLMcxn-1ZuCfl0204vM5XVYZ6SKmyOCE17pT0E5Qp1dpSqnD94muBVZ1kbL6YXGLQaPvYl1QaGDXIcMEE-fY4JH2fBcZkGfyu05MUyEjdbVQK23RuiUb0uc6TfvRZC5QTo3Za/s1600/StaticTagDef.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRTlFu8ZkBLMcxn-1ZuCfl0204vM5XVYZ6SKmyOCE17pT0E5Qp1dpSqnD94muBVZ1kbL6YXGLQaPvYl1QaGDXIcMEE-fY4JH2fBcZkGfyu05MUyEjdbVQK23RuiUb0uc6TfvRZC5QTo3Za/s320/StaticTagDef.png" width="320" /></a></div>
<br /></div>
<div>
To define a dynamic tag, you must first create a simple "Dynamic Processor" class that exposes properties for TagType, Key and Value. Sample Dynamic Processors are provided that emit tags for the Item ID, Template Key and Machine Name. Once this class is defined, you can add it by creating a DynamicMetaTag item and supplying the class signature for the dynamic processor.<br />
<br />
<br />
<div class="codechunk">
<pre style="background: white; margin-left: .5in;"><pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><span style="color: blue;">namespace</span> Arke.SharedSource.MetaTags.DynamicProcessors
{
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">ItemID</span> : <span style="color: #2b91af;">IDynamicProcessor</span>
{
<span style="color: blue;">public</span> <span style="color: #2b91af;">MetaTagType</span> TagType { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
<span style="color: blue;">public</span> <span style="color: blue;">string</span> Key { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
<span style="color: blue;">public</span> <span style="color: blue;">string</span> Value { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
<span style="color: blue;">public</span> ItemID()
{
TagType = <span style="color: #2b91af;">MetaTagType</span>.name;
Key = <span style="color: #a31515;">"ItemID"</span>;
Value = Sitecore.<span style="color: #2b91af;">Context</span>.Item.ID.ToString();
}
}
}</pre>
</pre>
</div>
</div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0SpZCWrKM2Fube-HEyM-NP7hMPEtUHJzcjrYnxz_bhCGbh2iGWpDDYWtrT4Pdg46V4B0OIN2z3ayuxRcdps-mr6OAHUsTN7ffSGVgbZut77ozcWjSKaT23EE2_fPm0ZDJ_WjrsLvGuClX/s1600/DynamicTagDef.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="92" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0SpZCWrKM2Fube-HEyM-NP7hMPEtUHJzcjrYnxz_bhCGbh2iGWpDDYWtrT4Pdg46V4B0OIN2z3ayuxRcdps-mr6OAHUsTN7ffSGVgbZut77ozcWjSKaT23EE2_fPm0ZDJ_WjrsLvGuClX/s400/DynamicTagDef.png" width="400" /></a></div>
<br /></div>
<div>
A base template is provided, which can be added to the base templates of any site template. This gives the content author an opportunity to include the pre-defined tags (those defined n the OptionalTags folder) in any given page.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7JtPecf8Uh5NKHdD9xEKh5ZK-Bj0EKSBTXKRoNKX0M9j0mP8iNVWyltL-SAlFZUHmE-wa83PzR_mkOZe6A5cU-crJf-9KQ4vyJQz0GC3hZx4mGYCplCVlsqmxYa-cU_cIOFiza9AFFHsf/s1600/PageTagField.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7JtPecf8Uh5NKHdD9xEKh5ZK-Bj0EKSBTXKRoNKX0M9j0mP8iNVWyltL-SAlFZUHmE-wa83PzR_mkOZe6A5cU-crJf-9KQ4vyJQz0GC3hZx4mGYCplCVlsqmxYa-cU_cIOFiza9AFFHsf/s1600/PageTagField.png" /></a></div>
<br /></div>
<div>
<br />
<h4>
Managing Tags in the <span style="font-family: Courier New, Courier, monospace;">InjectMetaTags</span> Pipeline</h4>
<br /></div>
<div>
The process for gathering, forming and injecting tags is itself managed with a custom pipeline. Developers can add custom tags by inserting processors into this pipeline. They can also change the behavior of the process by replacing existing processors.</div>
</div>
<div style="background-color: #dddddd; clear: right; float: right; margin-bottom: 10px; margin-left: 18px; margin-top: 10px; padding: 6px 6px 6px 6px; text-align: left; width: 35%;">
<b><i>For more information on how to manage processes in your solutions by creating custom pipelines, see "<a href="http://andyuzick.arke.com/2013/03/put-that-in-your-pipe-and-process-it.html" target="_blank">Put That in Your Pipe and Process It</a>"</i></b></div>
<div>
<br /></div>
<div>
In addition to the processors that gather the meta tags defined in content (global and page-scoped), there are other "demonstrator" processor included in the module. One shows how to implement a fully custom meta tag processor, using the "canonical" meta tag as an example.</div>
<div>
<br /></div>
<div>
There are also processors that allow you to leverage your "Dynamic Processors" or any static method (including any Sitecore static method) to add a global meta, entirely in configuration, without writing a single line of code. This is accomplished by adding processor nodes that have child nodes the define class signatures and names of the processor or static method to be used. </div>
<div>
<br /></div>
<div>
Here's and example of a meta tag pipeline in config (I've shortened the type names for readability):</div>
<div>
<br /></div>
<div class="codechunk">
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><pre style="background-position: initial initial; background-repeat: initial initial; font-family: Consolas;"><span style="color: blue;"><</span><span style="color: #a31515;">Arke.MetaTags.InjectMetaTags</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">processor</span><span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Arke...CheckContextItem, Arke.SharedSource.MetaTags</span>"<span style="color: blue;"> /></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">processor</span><span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Arke...CheckHeader, Arke.SharedSource.MetaTags</span>"<span style="color: blue;"> /></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">processor</span><span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Arke...CanonialUrl, Arke.SharedSource.MetaTags</span>"<span style="color: blue;"> /></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">processor</span><span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Arke...MethodTag, Arke.SharedSource.MetaTags</span>"<span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">TypeSignature</span><span style="color: blue;">></span>Sitecore.Context, Sitecore.Kernel<span style="color: blue;"></</span><span style="color: #a31515;">TypeSignature</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">MethodName</span><span style="color: blue;">></span>GetSiteName<span style="color: blue;"></</span><span style="color: #a31515;">MethodName</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">TagName</span><span style="color: blue;">></span>sc_site<span style="color: blue;"></</span><span style="color: #a31515;">TagName</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">TagType</span><span style="color: blue;">></span>name<span style="color: blue;"></</span><span style="color: #a31515;">TagType</span><span style="color: blue;">></span>
<span style="color: blue;"> </</span><span style="color: #a31515;">processor</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">processor</span><span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Arke...GlobalTags, Arke.SharedSource.MetaTags</span>"<span style="color: blue;"> /></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">processor</span><span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Arke...ItemTags, Arke.SharedSource.MetaTags</span>"<span style="color: blue;"> /></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">processor</span><span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Arke...FlushMetaTags, Arke.SharedSource.MetaTags</span>"<span style="color: blue;"> /></span>
<span style="color: blue;"></</span><span style="color: #a31515;">Arke.MetaTags.InjectMetaTags</span><span style="color: blue;">></span></pre>
</pre>
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"></pre>
</div>
<br />
<br />
<br />
<br />
<hr />
<div>
The source code for this module is available at the <a href="http://marketplace.sitecore.net/en/Modules/MetaTag_Manager.aspx" target="_blank">Sitecore Marketplace</a>. You can also <a href="http://marketplace.sitecore.net/services/~/media/Marketplace/Modules/M/MetaTag%20Manager/Documents/ArkeSharedSourceMetatags.ashx" target="_blank">download the documentation file</a>.<br />
<br /></div>
Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.com0tag:blogger.com,1999:blog-8880848735938155014.post-63003314092904249952013-03-09T12:38:00.001-08:002013-03-11T13:53:32.693-07:00Put That in Your Pipe and Process It<div style="clear: right; float: right; margin-bottom: 10px; margin-left: 10px;">
<img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_MiD_WvBRcdcD3AHGXRAWNAj3WIliy95MH_KCpPz_BX_zdh9Fo4j0atIivfiottY0u8WFQW3o15EeX9g8wLs-lGpDu39WLW9xbq1AQSegPRalDl4dBWxKyXt42VjLpKv91gCmGSn6JZcN/s320/Pipeline.jpg" width="320" />
</div>
A teacher once told me "When faced with a problem you don't understand, solve any part of it that you <em>do</em> understand, and then step back and look at the problem again." It was supposed to be advice about math, but it is a good advice for troubleshooting <em>any</em> problem. It also taught me that complex problems and processes are best handled in small, discreet pieces.<br />
<br />
If you read my <a href="http://andyuzick.arke.com/2013/01/render-unto-c_25.html" target="_blank">blog about renderings</a>, you've heard me lecture on the importance of granularity. When coding our solutions, we often implement complex processes, sequential processes. Sitecore gives us a great tool for making these processes granular and extensible with <i>pipelines</i>.<br />
<br />
A <i>pipeline </i>is a framework for defining a process in a series of steps that are handled by individual <i>processors</i>. Developers implement the steps in code following a specified pattern, and define the ordering of these steps in a config file. The pipeline execution engine manages this functionality and exposes a number of supporting methods and properties.<br />
<br />
Sitecore exposes many of its internal processes via pipelines, allowing us to do all kinds of magic by adding and modifying processors. Lots of cool enhancements to Sitecore have been shared around the community that leverage these open pipelines.Why don't we open our solutions up to future developers (and our future selves) by using this same technique?<br />
<br />
Just like Sitecore has done with many of its processes, we can take our solution's processes, break them down into a series of steps, and implement them with a pipeline. This will allow us to extend or modify the process later (perhaps even using classes in a different assembly) through configuration. This makes our solutions more transparent and more flexible. It leaves an open architecture that allows future developers to change the behavior of the process without changing the original code.<br />
<br />
<div style="background-color: #dddddd; clear: right; float: right; margin-bottom: 10px; margin-left: 10px; margin-top: 10px; padding: 6px 6px 6px 6px; text-align: left; width: 35%;">
<i><b>The example code in this article is taken from the <a href="http://marketplace.sitecore.net/en/Modules/MetaTag_Manager.aspx" target="_blank">MetaTag Manager Module</a> available from the <a href="http://marketplace.sitecore.net/en/Modules/MetaTag_Manager.aspx" target="_blank">Sitecore Marketplace</a></b></i></div>
The solution I'll use as an example is designed to manage Meta Tag Manager open source module. There are a number of "common" circumstances that influence the insertion of meta tags in that module: managed content items, logic for specialty tags, and a context object that code can use to insert meta tags. These each require their own set of code to manage. Knowing this, and knowing that in the future I might want to implement additional meta tag logic in the future, I used a pipeline to manage this task.<br />
<h3>
</h3>
<h3>
</h3>
<h3>
When to Use a Pipeline</h3>
<br />
Pipelines are a useful tools when you are creating sequential processes that represent significant functionality in your application. This might be something like a data consumer that periodically imports data (via a scheduled task) from an external system, or a process for generating markup as part of your page construction (as in the example pipeline in this article), or a process associated with application start-up, publishing, or any other part of your solution.<br />
<br />
Sitecore uses pipelines for most of the processes needed to render every page; this tells me that they should be reasonably efficient. Custom pipelines are most useful for complex processes that may need to be extended or modified later, with the convenience if not having to modify the original code. <br />
<h3>
</h3>
<h3>
</h3>
<h3>
Anatomy of a Pipeline</h3>
<br />
The Sitecore pipeline architecture exists to allow you to define a series of steps in a config file that, when executed in order, implement a process within the solution. The pipeline can be invoked from anywhere in your code where you might otherwise call one or more methods to achieve the same purpose. <br />
<br />
The pieces of a pipeline are...<br />
<br />
<ul>
<li>The pipeline definition. This is declared in a config file.</li>
<li>One or more pipeline processors. These represent the steps that could be used in the pipeline, and are implemented in code.</li>
<li><i>(Optional)</i> A PipelineArgs class, which is implemented in code and is used to allow the steps in the pipeline pass data down the line.</li>
<li>The Sitecore.Pipelines.<span style="color: #2b91af;">CorePipeline</span> namespace, which contains all of the API needed to develop and invoke pipelines and pipeline processors.</li>
</ul>
<br />
<br />
In a pipeline, each step is defined using a class signature in the <span style="font-family: "Courier New", Courier, monospace;">config</span> file. The when the pipeline is run, Sitecore uses reflection to instantiate n instance of each processor class, and calls the <span style="font-family: "Courier New", Courier, monospace;">Process</span> method of that class.<br />
<h3>
</h3>
<h3>
</h3>
<h3>
Pipeline Args</h3>
<br />
It is usually helpful to be able to maintain some context during the execution of the pipeline, so that processors can pass data to each other. Sitecore instantiates a <span style="font-family: "Courier New", Courier, monospace;">PipelineArgs</span> class (or a custom class that inherits from <span style="font-family: "Courier New", Courier, monospace;">PipelineArgs</span>) when a pipeline is run. This instance is passed to each processor's <span style="font-family: "Courier New", Courier, monospace;">Process</span> method, allowing each step access to the <span style="font-family: "Courier New", Courier, monospace;">PipelineArgs</span>. <br />
<br />
This <span style="font-family: "Courier New", Courier, monospace;">PipelineArgs</span> class exposes some useful methods to each processor. One important one is the <span style="font-family: "Courier New", Courier, monospace;">AbortPipeline</span> method. If a processor step detects that the pipeline should be terminated without calling the subsequent steps, it can call this method.<br />
<br />
The <span style="font-family: "Courier New", Courier, monospace;">PipelineArgs</span> class also contains a <span style="font-family: "Courier New", Courier, monospace;">SafeDictionary</span> property called <span style="font-family: "Courier New", Courier, monospace;">CustomData</span>. Pipeline processors can add objects to this dictionary in order to pass information down the line as subsequent processors are invoked.<br />
<br />
Rather than use the <span style="font-family: "Courier New", Courier, monospace;">CustomData</span> dictionary, I prefer to create a custom "args" class that inherits from Sitecore's <span style="font-family: "Courier New", Courier, monospace;">PipelineArgs</span>. I can then define properties that do not require casting to be used by pipeline steps. This is also a convenient place to put convenience or utility methods for the processor steps.<br />
<br />
<br />
<div class="codechunk">
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><span style="color: blue;">namespace</span> Arke.SharedSource.MetaTags
{
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">InjectMetaTagsPipelineArgs</span> : <span style="color: #2b91af;">PipelineArgs</span>
{
<span style="color: blue;">public</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">MetaTagItem</span>> MetaTags;
<span style="color: blue;">public</span> InjectMetaTagsPipelineArgs()
{
<span style="color: blue;">this</span>.MetaTags = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">MetaTagItem</span>>();
}
}
}</pre>
</div>
<br />
<br />
When using a custom <span style="font-family: "Courier New", Courier, monospace;">PipelineArgs</span> class, it is a good idea to create an Interface that our pipeline processors will implement. This ensures that each step is casting the args class properly.<br />
<br />
<div class="codechunk">
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><span style="color: blue;">namespace</span> Arke.SharedSource.MetaTags.Pipelines
{
<span style="color: blue;">public</span> <span style="color: blue;">interface</span> <span style="color: #2b91af;">IInjectMetaTagsPipelineProcessor</span>
{
<span style="color: blue;">void</span> Process(<span style="color: #2b91af;">InjectMetaTagsPipelineArgs</span> args);
}
}
</pre>
</div>
<h3>
</h3>
<h3>
</h3>
<h3>
Pipeline Processors</h3>
<br />
The steps in your pipeline are implemented with pipeline processors, representing the steps in the process that the pipeline implements. Each is implemented with a class that implements a <span style="font-family: "Courier New", Courier, monospace;">Process</span> method, which accepts a <span style="font-family: "Courier New", Courier, monospace;">PipelineArgs</span> argument. The pipeline runner instantiates these classes in turn, and calls the <span style="font-family: "Courier New", Courier, monospace;">Process</span> method, passing in the <span style="font-family: "Courier New", Courier, monospace;">PipelineArgs</span> object.<br />
<br />
This is where you implement the logic for that step of the process. The processor may read from and.or write to the <span style="font-family: "Courier New", Courier, monospace;">PipelineArgs</span> object. It can abort the remainder of the pipeline with the <span style="font-family: "Courier New", Courier, monospace;">AbortPipeline</span> method.<br />
<br />
For example, this processor runs early in the pipeline to make sure there is a context item, and aborts the pipeline if necessary:<br />
<br />
<div class="codechunk">
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><span style="color: blue;">namespace</span> Arke.SharedSource.MetaTags.Pipelines.InjectMetaTags
{
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">CheckContextItem</span> : <span style="color: #2b91af;">IInjectMetaTagsPipelineProcessor</span>
{
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Process(<span style="color: #2b91af;">InjectMetaTagsPipelineArgs</span> args)
{
<span style="color: blue;">if</span> (Sitecore.<span style="color: #2b91af;">Context</span>.Item == <span style="color: blue;">null</span>)
{
<span style="color: #2b91af;">Tracer</span>.Warning(<span style="color: blue;">string</span>.Concat(<span style="color: #a31515;">"Not injecting meta tags; no context item"</span>));
args.AbortPipeline();
}
}
}
}
</pre>
</div>
<div>
<br />
This processor adds a "canonical" meta tag:<br />
<br />
<div class="codechunk">
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><span style="color: blue;">namespace</span> Arke.SharedSource.MetaTags.Pipelines.InjectMetaTags
{
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">CanonialUrl</span> : <span style="color: #2b91af;">IInjectMetaTagsPipelineProcessor</span>
{
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Process(<span style="color: #2b91af;">InjectMetaTagsPipelineArgs</span> args)
{
<span style="color: #2b91af;">Tracer</span>.Info(<span style="color: blue;">string</span>.Concat(<span style="color: #a31515;">"Adding Canonical URL"</span>));
args.MetaTags.Add(<span style="color: blue;">new</span> <span style="color: #2b91af;">MetaTagItem</span>(<span style="color: #2b91af;">MetaTagType</span>.name, <span style="color: #a31515;">"canonical"</span>, <span style="color: #2b91af;">Settings</span>.GetAuthorativeUrl()));
}
}
}
</pre>
</div>
<h3>
</h3>
</div>
<h3>
</h3>
<h3>
</h3>
<h3>
Architecting the Steps in a Pipeline</h3>
<br />
What pipeline steps you create, and what they do, is up to you. Remember that pipelines typically define a process in your solution. Sitecore has pipelines that define the processes for things like <span style="font-family: "Courier New", Courier, monospace;">insertRenderings</span> and <span style="font-family: "Courier New", Courier, monospace;">publishItem</span>. These steps in these pipelines do thing like detecting if the process is appropriate for the current item or context, building up or transforming data, moving data from one place to another, generating markup, cleaning up, logging messages and saving performance data. <br />
<br />
When I'm building a process to be handled by a pipeline, I tend to think about <a href="http://en.wikipedia.org/wiki/The_Seven_Habits_of_Highly_Effective_People" target="_blank">Stephen Covey's</a> advice about analysis and synthesis. To <em>analyze</em> means to break apart, to <i>synthesize</i> means to put together. A pipeline process often begins by analyzing (checking and transforming the input data, context and environment), and then ends with synthesizing the desired output.<br />
<br />
What steps your pipeline should take depends on the nature of the task at hand. It is common to have the initial steps determine if the process should execute depending on the context or availability of data or objects, and to instantiate objects and data that will be needed by subsequent steps. The next steps actually perform the process in discreet steps, and the last steps clean up or do some logging.<br />
<br />
Try to break the pipeline into very discreet steps. If you find that one of your steps is becoming "spaghetti," break it into multiple steps. Take logic that makes decisions and move them to separate steps. If there is data to be gathered that is used by subsequent steps, put the data gatherers into separate steps. This allows future developers to modify or extend the data-gathering, decision-making and output-producing steps, or to insert their own steps in between.<br />
<br />
The pipeline in the example solution starts by checking if meta tags can be injected into the page (by validating the existence of a context item and a head section in the page). It then has a step for every group of tags that might be injected (depending on the nature of the tags), adding them to a collection stored in the <span style="font-family: "Courier New", Courier, monospace;">PipelineArgs</span>. Finally, it flushes the tags to the page.<br />
<br />
By separating the sets of tags to be included, the application administrator can decide to exclude steps, say for example, the canonical URL tag, by removing them from the config. A developer can add logic to include a different set of tags by adding a step to this pipeline, which might call a class in an entirely separate assembly.<br />
<h3>
</h3>
<h3>
</h3>
<h3>
The Config File</h3>
<br />
The pipeline steps are defined in <span style="font-family: Courier New, Courier, monospace;">.config</span>. This might be directly in <span style="font-family: Courier New, Courier, monospace;">web.config</span>, or in an external <span style="font-family: Courier New, Courier, monospace;">config </span>file. I'd recommend an external config file ... see <a href="http://andyuzick.blogspot.com/2013/01/sitecore-solution-custom-configuration.html" target="_blank">this blog post</a>.<br />
<br />
Each step in the pipeline is defined with a <span style="font-family: Courier New, Courier, monospace;">processor </span>node, which simply declares the type signature for that step of the pipeline.<br />
<br />
A pipeline <span style="font-family: Courier New, Courier, monospace;">processor </span>node can also have child nodes. The tag name in these nodes must map to property names on the class for that processor. Sitecore will inject the value (the text) of each node into the corresponding property in the class. This allows you to create more "general purpose" processor steps and hand properties to them at runtime.<br />
<br />
<div class="codechunk">
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><pre style="background-position: initial initial; background-repeat: initial initial; font-family: Consolas;"><span style="color: blue;"><</span><span style="color: #a31515;">MetaTags.InjectMetaTags</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">processor</span><span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Arke.SharedSource.MetaTags.Pipelines.InjectMetaTags.CheckContextItem, Arke.SharedSource.MetaTags</span>"<span style="color: blue;"> /></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">processor</span><span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Arke.SharedSource.MetaTags.Pipelines.InjectMetaTags.CheckHeader, Arke.SharedSource.MetaTags</span>"<span style="color: blue;"> /></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">processor</span><span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Arke.SharedSource.MetaTags.Pipelines.InjectMetaTags.CanonialUrl, Arke.SharedSource.MetaTags</span>"<span style="color: blue;"> /></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">processor</span><span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Arke.SharedSource.MetaTags.Pipelines.InjectMetaTags.MethodTag, Arke.SharedSource.MetaTags</span>"<span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">TypeSignature</span><span style="color: blue;">></span>Sitecore.Context, Sitecore.Kernel<span style="color: blue;"></</span><span style="color: #a31515;">TypeSignature</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">MethodName</span><span style="color: blue;">></span>GetSiteName<span style="color: blue;"></</span><span style="color: #a31515;">MethodName</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">TagName</span><span style="color: blue;">></span>sc_site<span style="color: blue;"></</span><span style="color: #a31515;">TagName</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">TagType</span><span style="color: blue;">></span>name<span style="color: blue;"></</span><span style="color: #a31515;">TagType</span><span style="color: blue;">></span>
<span style="color: blue;"> </</span><span style="color: #a31515;">processor</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">processor</span><span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Arke.SharedSource.MetaTags.Pipelines.InjectMetaTags.GlobalTags, Arke.SharedSource.MetaTags</span>"<span style="color: blue;"> /></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">processor</span><span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Arke.SharedSource.MetaTags.Pipelines.InjectMetaTags.FlushMetaTags, Arke.SharedSource.MetaTags</span>"<span style="color: blue;"> /></span></pre>
</pre>
</div>
<h3>
</h3>
<h3>
</h3>
<h3>
Invoking the Pipeline</h3>
<div>
<br />
It's really very simple to invoke a pipeline. You simply call <span style="font-family: Courier New, Courier, monospace;">Sitecore.Pipelines.CorePipeline.Run("MyPipelineName", args)</span>, where <span style="font-family: Courier New, Courier, monospace;">MyPipelineName </span>is the name of the pipeline in the config file, and <span style="font-family: Courier New, Courier, monospace;">args </span>is an instance of <span style="font-family: Courier New, Courier, monospace;">PipelineArgs </span>(or a custom class derived from it).</div>
<div>
<br /></div>
<div>
<div class="codechunk">
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><pre style="background-position: initial initial; background-repeat: initial initial; font-family: Consolas;"> <span style="color: #2b91af;">InjectMetaTagsPipelineArgs</span> args = <span style="color: blue;">new</span> <span style="color: #2b91af;">InjectMetaTagsPipelineArgs</span>();
Sitecore.Pipelines.<span style="color: #2b91af;">CorePipeline</span>.Run(<span style="color: #2b91af;">Settings</span>.PIPELINE_NAME, args);</pre>
</pre>
</div>
</div>
<div>
<br /></div>
<div>
<i>Where </i>to invoke the pipeline depends on what the pipeline does. Sometimes it needs to be invoked from a timed task, sometimes from another pipeline, sometimes from other places. If I have a situation where I need to extend an existing Sitecore pipeline with a complex task, I'll create my own pipeline and invoke it from Sitecore's pipeline. That makes maintenance much easier, because I can define it all in another config file and don't need to patch Sitecore's pipeline more than once.<br />
<br />
First, we wire up the the appropriate existing pipeline:</div>
<div>
<br /></div>
<div class="codechunk">
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><span style="color: blue;"> <</span><span style="color: #a31515;">pipelines</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">insertRenderings</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">processor</span>
<span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Arke.SharedSource.MetaTags.Pipelines.InsertRenderings.InjectMetaTags,</span><span style="color: blue;"> Arke.SharedSource.MetaTags</span>"</pre>
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><span style="color: blue;"> </span><span style="color: red;">patch:after</span><span style="color: blue;">=</span>"<span style="color: blue;">processor[@type='Sitecore.Pipelines.InsertRenderings.Processors.AddRenderings, Sitecore.Kernel']</span>"
<span style="color: blue;"> /></span>
<span style="color: blue;"> </</span><span style="color: #a31515;">insertRenderings</span><span style="color: blue;">></span>
</pre>
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><pre style="background-position: initial initial; background-repeat: initial initial; font-family: Consolas;"><span style="color: blue;"> </</span><span style="color: #a31515;">pipelines</span><span style="color: blue;">></span></pre>
</pre>
</div>
<div>
<br />
<div>
The method we're wiring exists only to fire our custom pipeline:</div>
<div>
<br /></div>
<div class="codechunk">
<br />
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><pre style="background-position: initial initial; background-repeat: initial initial; font-family: Consolas;"> <span style="color: blue;">public</span> <span style="color: blue;">void</span> Process(<span style="color: #2b91af;">InsertRenderingsArgs</span> args)
{
<span style="color: #2b91af;">Assert</span>.ArgumentNotNull(args, <span style="color: #a31515;">"args"</span>);
<span style="color: green;">// Don't wire this up when in the sitecore shell</span>
<span style="color: blue;">if</span> (Sitecore.<span style="color: #2b91af;">Context</span>.Site.Name.Equals(<span style="color: #a31515;">"shell"</span>, <span style="color: #2b91af;">StringComparison</span>.InvariantCultureIgnoreCase))
{
<span style="color: #2b91af;">Tracer</span>.Warning(<span style="color: #a31515;">"Meta tags not emitted in the shell site."</span>);
<span style="color: blue;">return</span>;
}
<span style="color: green;">// We'll wire up a handler for after prerender is complete, so any meta tags added</span>
<span style="color: green;">// by controls (via Arke.SharedSource.MetaTags.PageTags) will be available.</span>
Sitecore.<span style="color: #2b91af;">Context</span>.Page.Page.PreRenderComplete += <span style="color: blue;">new</span> <span style="color: #2b91af;">EventHandler</span>(RunPipeline);
}</pre>
<pre style="background-position: initial initial; background-repeat: initial initial; font-family: Consolas;"></pre>
<pre style="background-position: initial initial; background-repeat: initial initial; font-family: Consolas;"><pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"> <span style="color: blue;">void</span> RunPipeline(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">EventArgs</span> e)
{
<span style="color: #2b91af;">Profiler</span>.StartOperation(<span style="color: #a31515;">"Adding Global MetaTags."</span>);
<span style="color: blue;">try</span>
{
<span style="color: #2b91af;">InjectMetaTagsPipelineArgs</span> args = <span style="color: blue;">new</span> <span style="color: #2b91af;">InjectMetaTagsPipelineArgs</span>();
Sitecore.Pipelines.<span style="color: #2b91af;">CorePipeline</span>.Run(<span style="color: #2b91af;">Settings</span>.PIPELINE_NAME, args);
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> ex)
{
Sitecore.Diagnostics.<span style="color: #2b91af;">Log</span>.Error(<span style="color: #a31515;">"InjectMetaTags failed"</span>, ex, <span style="color: #a31515;">"InjectMetaTags"</span>);
}
<span style="color: #2b91af;">Profiler</span>.EndOperation();
}
</pre>
</pre>
</pre>
</div>
</div>
<div>
<div>
<br />
Our pipeline in turn declares the steps that would otherwise have to be patched into Sitecore's pipeline, as shown in the config example shown before.</div>
<div>
<br />
<br />
<br /></div>
</div>
<div>
Next time you're building a process for your solution, consider using Sitecore's built-in tools for pipeline management. It may take a little more time now, but it'll make life easier later, when new requirements come down the pipe.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
References:</div>
<div>
<ul>
<li><i><a href="http://www.sitecore.net/Community/Technical-Blogs/John-West-Sitecore-Blog/Posts/2011/05/All-About-Pipelines-in-the-Sitecore-ASPNET-CMS.aspx" target="_blank">John West: All About Pipelines in the Sitecore ASP.NET CMS</a></i></li>
<li><i>Andy Uzick (Arke Systems): <a href="http://marketplace.sitecore.net/en/Modules/MetaTag_Manager.aspx" target="_blank">MetaTag Manager Module</a> available from the <a href="http://marketplace.sitecore.net/en/Modules/MetaTag_Manager.aspx" target="_blank">Sitecore Marketplace</a></i></li>
</ul>
</div>
<div>
<br /></div>
Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.com1tag:blogger.com,1999:blog-8880848735938155014.post-83422980893889681762013-02-12T09:44:00.000-08:002013-02-25T09:10:13.052-08:00Tag, You're it: Tracking Tag Management in SitecoreAs web marketers, a great deal of our strategy relies on <i>hunting </i>(we'll leave <i>farming </i>tactics, like social media, nurturing and personalization, for another day). Most of our hunting activities rely heavily on <i>tracking</i>. The <a href="http://en.wikipedia.org/wiki/Tracking_(hunting)">wiki definition of tracking</a> (in the hunting context) fits this quite well:<br />
<blockquote class="tr_bq">
<b style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.1875px;">Tracking</b><span style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.1875px;"> in </span><a href="http://en.wikipedia.org/wiki/Hunting" style="background-color: white; background-image: none; color: #0b0080; font-family: sans-serif; font-size: 13px; line-height: 19.1875px; text-decoration: initial;" title="Hunting">hunting</a><span style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.1875px;"> and </span><a href="http://en.wikipedia.org/wiki/Ecology" style="background-color: white; background-image: none; color: #0b0080; font-family: sans-serif; font-size: 13px; line-height: 19.1875px; text-decoration: initial;" title="Ecology">ecology</a><span style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.1875px;"> is the science and art of observing animal </span><a href="http://en.wikipedia.org/wiki/Animal_tracks" style="background-color: white; background-image: none; color: #0b0080; font-family: sans-serif; font-size: 13px; line-height: 19.1875px; text-decoration: initial;" title="Animal tracks">tracks</a><span style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.1875px;"> and other signs, with the goal of gaining understanding of the landscape and the animal being tracked (quarry).</span></blockquote>
For web marketers, hunting requires an understanding of the web ecosystem and the behavior of our "quarry" within it, so tracking is very important to us. There has been an explosion in tracking technologies of late, most of which are based on injecting <i>tracking tags</i> into our pages. Our pages have more tags hanging off them than the discount rack at Macy's --- so much so that <i>tracking tag management</i> has become a hot service offering. Just Google <i><a href="http://www.google.com/webhp?q=tracking+tag+management">tracking tag management</a></i> and you'll find more tools than you can count.<br />
<br />
These tools can be appealing. After all, we have so much tag content that we need to manage on our site.<br />
<br />
Wait a minute ... "content" ... "manage" ... hmmm --- aren't we already working in a content management environment?<br />
<br />
There's no doubt that we could build a superb tracking tag management system into Sitecore. When we do a deep dive into these tagging technologies, we find that the formation and injection of tags into our pages can become quite complicated, but Sitecore is the best system around for building complex content management architectures.<br />
<h3>
<br />Simple tracking tag management in Sitecore</h3>
<br />
But let's start off simple. When you first get into tagging, you find that at its simplest, all you have to do is copy a tag snippet (typically some javascript) into your pages. You find new tracking service you want to use, you paste their snippet into your pages, and you're off.<br />
<br />
Simple as that sounds, our marketers can't just do that themselves. They need the developers to deploy the tags to the production servers, typically within layouts. But marketeers want things done <i>now </i>... so why don't we simplify this process by creating support for simple tag injection?<br />
<br />
The solution I'll describe here is pretty rudimentary. It assumes that you are tagging every page on your site with every tag you have. That's fine for a start; over time, we'll examine ways to create dynamic tags and associate tags with content more robustly.<br />
<br />
We'll create templates to allow the tag markup to be managed as Sitecore content. Since we want the tags on every page, we'll use a pipeline processor to inject them into every page (rather than relying on layouts).<br />
<br />
You can download the source and package for this solution from the <a href="http://marketplace.sitecore.net/en/Modules/Simple_Tracking_Tags.aspx" target="_blank">Sitecore Marketplace</a>.<br />
<h3>
<br />The templates</h3>
<br />
First, a couple of templates. We will create other tag types over time, but for now we'll just create a template for "Html Tracking Tag" that just holds some static tag markup. We'll also create a folder template to hold all of our tag items. This just a template with no fields, but with Standard Values set with insert options for our tag template.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGYA8_gQ82DCaPlN8ixvnPZJibODqXzLA7_-CspddeMXsIMCx49cuf4jigr_V6bnQcSr0dYapymepO8shxuvIGri0qjJN_NID-bifqg8SLj9Q7QNc8MP30CvDa8H0qNVOrl9x5BqIh9IiN/s1600/Templates.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGYA8_gQ82DCaPlN8ixvnPZJibODqXzLA7_-CspddeMXsIMCx49cuf4jigr_V6bnQcSr0dYapymepO8shxuvIGri0qjJN_NID-bifqg8SLj9Q7QNc8MP30CvDa8H0qNVOrl9x5BqIh9IiN/s1600/Templates.gif" /></a></div>
<br />
The HtmlTrackingTag template is simple; it just contains a memo field to hold the tag markup.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSEKAGR1gCx8j32mXfpng9hbN6mnLZMkCw5sGLKbcZufml6CKc1XSwOivtl0XQoX5m3VVA9M_-PshYxAlCrIydzBl6dTyoWm0XRQNFx2uuQUQunKxXznmBn7sGFojfFnVZDTelz6vXpM8X/s1600/HtmlTrackingTagTemplate.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSEKAGR1gCx8j32mXfpng9hbN6mnLZMkCw5sGLKbcZufml6CKc1XSwOivtl0XQoX5m3VVA9M_-PshYxAlCrIydzBl6dTyoWm0XRQNFx2uuQUQunKxXznmBn7sGFojfFnVZDTelz6vXpM8X/s1600/HtmlTrackingTagTemplate.gif" /></a></div>
<br />
We'll create a TrackingTagFolder in our content, wherever we manage "globals".<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOwzrtOaiSkKcnhBntGOPnMvf9tpe68hmEehmG4F9f7h4li59kyA1slJXnCXaQJYBL_qKuge0h25K0tYnHwCnApB3SHDkIzKQl5IxeJTvLUhSqdKKnGUTVcIwzhnBKLxnZNPcptvL6k7vu/s1600/TagContent.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOwzrtOaiSkKcnhBntGOPnMvf9tpe68hmEehmG4F9f7h4li59kyA1slJXnCXaQJYBL_qKuge0h25K0tYnHwCnApB3SHDkIzKQl5IxeJTvLUhSqdKKnGUTVcIwzhnBKLxnZNPcptvL6k7vu/s1600/TagContent.gif" /></a></div>
<br />
I've added a couple of tag items, which contain simple tag markup copied from that service's site.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVoG-jJ-mdThCEZkDf4QeebObYuss7b_zXOYRgIpmTPPJhv2ALjW4zpLRpZDWsMwIAhHcpYmZfm1H0bwNyoQgmz-0xk0yICzFhIelxWTiFoci8byGP3Pu3Ezg_lWIo1lHgY9sKcovYqR7h/s1600/GaTag.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVoG-jJ-mdThCEZkDf4QeebObYuss7b_zXOYRgIpmTPPJhv2ALjW4zpLRpZDWsMwIAhHcpYmZfm1H0bwNyoQgmz-0xk0yICzFhIelxWTiFoci8byGP3Pu3Ezg_lWIo1lHgY9sKcovYqR7h/s1600/GaTag.gif" /></a></div>
<br />
<h3>
<br />
The code</h3>
<br />
First, we'll need a configuration file to register up our pipeline and manage our settings:<br />
<br />
<div class="codechunk">
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><span style="color: blue;"><?</span><span style="color: #a31515;">xml</span><span style="color: blue;"> </span><span style="color: red;">version</span><span style="color: blue;">=</span>"<span style="color: blue;">1.0</span>"<span style="color: blue;">?></span>
<span style="color: blue;"><</span><span style="color: #a31515;">configuration</span><span style="color: blue;"> </span><span style="color: red;">xmlns:patch</span><span style="color: blue;">=</span>"<span style="color: blue;">http://www.sitecore.net/xmlconfig/</span>"<span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">sitecore</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">settings</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">setting</span><span style="color: blue;"> </span><span style="color: red;">name</span><span style="color: blue;">=</span>"<span style="color: blue;">TrackingTags.GlobalTagFolder</span>"<span style="color: blue;"> </span><span style="color: red;">value</span><span style="color: blue;">=</span>"<span style="color: blue;">/sitecore/content/Global/TrackingTags</span>"<span style="color: blue;"> /></span>
<span style="color: blue;"> </</span><span style="color: #a31515;">settings</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">pipelines</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">insertRenderings</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">processor</span>
<span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Arke.SharedSource.TrackingTags.Pipelines.InsertRenderings.InsertTrackingTags, Arke.SharedSource.TrackingTags</span>"
<span style="color: blue;"> </span><span style="color: red;">patch:after</span><span style="color: blue;">=</span>"<span style="color: blue;">processor[@type='Sitecore.Pipelines.InsertRenderings.Processors.AddRenderings, Sitecore.Kernel']</span>"
<span style="color: blue;"> /></span>
<span style="color: blue;"> </</span><span style="color: #a31515;">insertRenderings</span><span style="color: blue;">></span>
<span style="color: blue;"> </</span><span style="color: #a31515;">pipelines</span><span style="color: blue;">></span>
<span style="color: blue;"> </</span><span style="color: #a31515;">sitecore</span><span style="color: blue;">></span>
<span style="color: blue;"></</span><span style="color: #a31515;">configuration</span><span style="color: blue;">></span></pre>
</div>
<br />
And we'll create an associated settings class to make it simpler to access our settings (we only have one for now, but it's good practice).<br />
<br />
<div class="codechunk">
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><span style="color: blue;">namespace</span> Arke.SharedSource.TrackingTags
{
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">Settings</span>
{
<span style="color: blue;">public</span> <span style="color: blue;">const</span> <span style="color: blue;">string</span> DEFAULT_GLOBAL_TAG_FOLDER = <span style="color: #a31515;">"/sitecore/content/Global/TrackingTags"</span>;
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">string</span> GlobalTagFolder
{
<span style="color: blue;">get</span>
{
<span style="color: blue;">return</span> Sitecore.Configuration.<span style="color: #2b91af;">Settings</span>.GetSetting(<span style="color: #a31515;">"TrackingTags.GlobalTagFolder"</span>, DEFAULT_GLOBAL_TAG_FOLDER);
}
}
}
}</pre>
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"></pre>
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"></pre>
</div>
<br />
To render the tags to the page, we'll create a simple web control that grabs the markup from the tag definition item and spits it to the page.<br />
<br />
<div class="codechunk">
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><span style="color: blue;">namespace</span> Arke.SharedSource.TrackingTags
{
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">HtmlTrackingTag</span> : Sitecore.Web.UI.<span style="color: #2b91af;">WebControl</span>
{
System.Web.UI.WebControls.<span style="color: #2b91af;">Literal</span> container;
<span style="color: blue;">public</span> <span style="color: blue;">string</span> TagItem { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> OnInit(<span style="color: #2b91af;">EventArgs</span> e)
{
<span style="color: blue;">base</span>.OnInit(e);
container = <span style="color: blue;">new</span> System.Web.UI.WebControls.<span style="color: #2b91af;">Literal</span>();
}
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> CreateChildControls()
{
<span style="color: #2b91af;">Assert</span>.IsNotNullOrEmpty(TagItem, <span style="color: #a31515;">"tag item"</span>);
<span style="color: #2b91af;">Item</span> item = Sitecore.<span style="color: #2b91af;">Context</span>.Database.GetItem(TagItem);
<span style="color: #2b91af;">Assert</span>.IsNotNull(item.Fields[<span style="color: #a31515;">"Markup"</span>], <span style="color: #a31515;">"Markup"</span>);
<span style="color: blue;">string</span> markup = item.Fields[<span style="color: #a31515;">"Markup"</span>].Value;
container.Text = markup;
}
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> DoRender(<span style="color: #2b91af;">HtmlTextWriter</span> output)
{
EnsureChildControls();
container.RenderControl(output);
}
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">string</span> GetCachingID()
{
<span style="color: blue;">return</span> <span style="color: blue;">this</span>.GetType().FullName;
}
}
}
</pre>
</div>
<br />
Finally, we'll use a pipeline processor to iterate over the global tags and inject a <span style="color: #2b91af; font-family: Consolas; font-size: 13px;">HtmlTrackingTag</span> control into the page for each.<br />
<br />
<div class="codechunk">
<pre style="background-color: white; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 13px;"><span style="color: blue;">namespace</span> Arke.SharedSource.TrackingTags.Pipelines.InsertRenderings
{
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">InsertTrackingTags</span>
{
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Process(<span style="color: #2b91af;">InsertRenderingsArgs</span> args)
{
<span style="color: #2b91af;">Assert</span>.ArgumentNotNull(args, <span style="color: #a31515;">"args"</span>);
<span style="color: blue;">if</span> (Sitecore.<span style="color: #2b91af;">Context</span>.Site.Name == <span style="color: #a31515;">"shell"</span>)
{
<span style="color: blue;">return</span>;
}
<span style="color: #2b91af;">Item</span> globalTagFolder = Sitecore.<span style="color: #2b91af;">Context</span>.Database.GetItem(<span style="color: #2b91af;">Settings</span>.GlobalTagFolder);
<span style="color: #2b91af;">Profiler</span>.StartOperation(<span style="color: #a31515;">"Adding Tracking Tags."</span>);
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">Item</span> globalTagItem <span style="color: blue;">in</span> globalTagFolder.Children)
{
Arke.SharedSource.TrackingTags.<span style="color: #2b91af;">HtmlTrackingTag</span> control =
<span style="color: blue;">new</span> Arke.SharedSource.TrackingTags.<span style="color: #2b91af;">HtmlTrackingTag</span>();
<span style="color: blue;">if</span> (control != <span style="color: blue;">null</span>)
{
control.TagItem = globalTagItem.ID.ToGuid().ToString();
control.Cacheable = <span style="color: blue;">true</span>;
control.VaryByData = <span style="color: blue;">true</span>;
<span style="color: #2b91af;">RenderingReference</span> reference = <span style="color: blue;">new</span> <span style="color: #2b91af;">RenderingReference</span>(control);
reference.AddToFormIfUnused = <span style="color: blue;">true</span>;
args.Renderings.Add(reference);
<span style="color: #2b91af;">Tracer</span>.Info(<span style="color: blue;">string</span>.Concat(<span style="color: #a31515;">"Added tracking tag '"</span>, globalTagItem.Name, <span style="color: #a31515;">"'"</span>));
}
}
<span style="color: #2b91af;">Profiler</span>.EndOperation();
}
}
}
</pre>
</div>
<br />
Note from the config file that we're putting our processor before Sitecore's <span style="background-color: white; color: blue; font-family: Consolas; font-size: 13px;">AddRenderings</span> processor.This puts our renderings at the top of the body part of the page.<br />
<br />
If you look at the page in debug mode, you can see the script tag renderings.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuE115Syfp3zFLM25HAjyBFLkIMjl4n6sDjmRJ2bP00qweBUk1td38EF2dxkm6UHTcfv2FQ9KFcKID8pt0qykllM8cOZ4uvt84NTDT4KGHZUm1rw1YlihIXINw8iFio7gzMrsX1x3L91H1/s1600/RenderingsInDebugger.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuE115Syfp3zFLM25HAjyBFLkIMjl4n6sDjmRJ2bP00qweBUk1td38EF2dxkm6UHTcfv2FQ9KFcKID8pt0qykllM8cOZ4uvt84NTDT4KGHZUm1rw1YlihIXINw8iFio7gzMrsX1x3L91H1/s1600/RenderingsInDebugger.gif" /></a></div>
<br />
<br />
<h3>
<br />
Shortcomings of this solution</h3>
<brf>
Of course, this is a bit of a dangerous solution. We've enabled content managers to manually inject script into the page. Either by accident or intent, a content owner could wreak havoc on the site. The tag definitions in globals should have good security to limit access only to trusted power users.<br />
<br />
As I said before, this is a pretty simple solution. The obvious next step is to create a place to store "ad hoc" tags, and a rendering parameter template for the HtmlTrackingTag control. This would allow content manager to insert specific tag into specific pages.<br />
<br />
Beyond this, a much more robust solution would include templates for the well-known tags so they could be managed more easily (by pasting in specific parameters into specific fields, rather than the entire tag). Dynamic tags that modify their behavior depending on context, template or rendering parameters could be built as well.<br />
<br />
This solution allows the easy things to be easy, and the hard things will just have to wait till later. At least now, when we identify a new tracking service we want to implement, its as simple as "tag, you're it".</brf><br />
<brf><br /></brf>
<brf><br /></brf>
<brf><br />
<br /><i><b>The source code and package for this solution are available at the <a href="http://marketplace.sitecore.net/en/Modules/Simple_Tracking_Tags.aspx" target="_blank">Sitecore Marketplace</a>.</b></i>
</brf><br />
<brf><i><b><br /></b></i></brf>Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.com0tag:blogger.com,1999:blog-8880848735938155014.post-2089686197888549962013-01-25T08:57:00.000-08:002013-01-25T08:59:07.521-08:00Render Unto c#<br />
When it comes to CMS development (among other things in life) I’m a big fan of granularity and reusability. I believe that in a good solution architecture, both content and code are managed in discreet, granular pieces, which promotes both consistency and reusability.<br />
<br />
That’s why it bothers me that so many Sitecore professionals react to the word “rendering” the same way a horse would. To my mind, a good solution has a geometric ratio of layouts to sublayouts, and sublayouts to renderings. Yet I see projects that are extremely sublayout-centric, with content IA and logic governing page layout.<br />
<br />
Sitecore’s arsenal of presentation management tools, such as layout details, placeholder settings and rendering parameters, allows us as developers to truly empower our content owners. When implemented well, these features give the content authors what I like to call “controlled control” over their pages.<br />
<br />
Unfortunately, we often see solutions where sublayouts are the dominant presentation component. Sublayouts are far less efficient than renderings, both in terms of performance and management. With sublayouts, there are all the ascx files to manage and deploy. And using sublayouts to present content seems to promote having a single component (sublayout) present multiple fields. This can dramatically reduce the solution’s flexibility – or worse, lead to having multiple components that are slight variations on each other, or have cumbersome logic (often wired to “control” fields in the content) to suppress content or change the presentation behavior.<br />
<br />
Worse, some solutions rely almost entirely on the content tree to govern layout, such as by having fields in page templates that change the behavior of the layout, and/or by having sets of child items that code “bubbles up” into the page when they are present.<br />
<br />
So why are renderings so often left out of solution architecture? I suspect that the problem lies in Sitecore training. Although Sitecore trainers do point out the different ways that renderings can be created, they tend to use XSL as the example technology in class (probably because it’s quicker to demonstrate --the trainer can show changes to an XSL rendering immediately, without compiling). Regrettably, this leaves many with a linkage in their minds between renderings as a Sitecore artifact and XSL as a technology. The oft-maligned rendering can be implemented using multiple technologies, yet many, many developers believe that renderings can only be developed using XSL.<br />
<br />
I’m not going to wade into the great XSL debate here. I personally like XSL, but I rarely use it in Sitecore projects, for a number of reasons that I’ll get into that in a separate post. Suffice it to say that many developers, even if they know XSL, want to avoid it if for no other reason than to make their projects sustainable. XSL is a far more rare skill than c#, so it makes sense to ensure that future developers will be able to extend and maintain the project. And since there’s this misconception that “renderings = XSL”, the “baby” of a rendering-based architecture gets thrown out with the “bathwater” of XSL. And that’s a shame.<br />
<br />
So let’s set the record straight. Renderings can and should be developed in c#. Actually, <a href="http://www.sitecore.net/Community/Technical-Blogs/John-West-Sitecore-Blog.aspx">John West</a> points out in his book “<a href="http://www.amazon.com/Professional-Sitecore-Development-John-West/dp/047093901X">Professional Sitecore Development</a>,” there are four types of renderings:<br />
<ol>
<li>XSL renderings </li>
<li>Method renderings </li>
<li>URL renderings </li>
<li>Web Controls </li>
</ol>
Of these, Web Control renderings – controls that are implemented entirely in code and deployed in assemblies – are the least used yet most useful presentation component available. (In my next post, I’ll delve into the anatomy of a web control rendering.)<br />
<br />
As a simple example, consider a page with a “core content” (“body”) area consisting of a title, a main image, and some body text. These three fields are defined in the page’s template. One way of handling this is to create a sublayout that renders these fields to the output (hopefully, at least, using field renderers). But what happens when the author does not want a title on a particular page (this is a simple example, so let’s not quibble over usability or SEO). Sure, the sublayout’s code-behind could suppress the <h1> when the field is empty or null. Or we could have a checkbox in the template to suppress the title.<br />
<br />
What if the content author wants something other than a main image, like a flash or a video? What if they need to insert something between the image and the body? And after the body, they might need set of “spots” to point to other content?<br />
<br />
So we might resort to having different sublayouts with variations on the content. This can lead to an unmanageable mess, creating confusion as to which sublayout does what. It also leads to redundant code, which makes ongoing maintenance and modification to the site much more challenging.<br />
<br />
Another solution would be to put fields in the template to suppress content, or add content, or modify the presentation of content. Or we might create templates for child items that, when present, are bubbled up into the page. This puts management of presentation into the data. Sitecore is so well architected to give us excellent separation of content and presentation, so why fight that and force content to manage presentation?<br />
<br />
I much prefer solutions that have very “light” layouts and sublayouts, with lots of renderings bound to placeholders. For the simple example, I would have a separate rendering each for title, main image, and body text, which I would bind to a placeholder in the sublayout for the core content area. Standard values in the item’s template would bind them by default, but the content owner would have the freedom to change the presentation as required. We can use features like thumbnails, rendering parameters, placeholder settings and compatible renderings both to assist them in the layout process, and to enforce brand or visual design requirements.<br />
<br />
Most of my layouts and sublayouts are little more than div’s and placeholders. They exist to manage the geometry of the page or of regions of the page, not to present the actual content. Renderings bound to placeholders actually emit the content. Rendering parameter templates allow the editor to influence the source and behavior of the content in the page. Now, control over presentation and layout are managed in the presentation layer, and content is managed in the content layer. The design of the IA can break the content down into more manageable chunks, promoting reusability and avoiding redundancy.<br />
<br />
To be fair, there are times when sublayouts are a better choice than renderings. For example, for forms or other situations where postback is required, I refer to use sublayouts (ascx) controls.. Also, in cases where the parts of the page structure are immutable, it is more efficient to statically bind renderings into sublayouts (by including them in the sublayout markup). This is fine for cases like fixed headers and footers, or when the site design requires an element (like a title) to always be present. There are also rare occasions when I allow a folder of child items to bubble up into a page, but even then, I usually use a placeholder-bound rendering to do the bubbling.<br />
<br />
A highly granular architecture, which maintains separation of content from presentation, is hugely empowering to both developers and content editors. It promotes reusability of both code and content, shifts much of the responsibility for page assembly from code to configuration, and empowers editors with more control over the layout of their pages.Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.com0tag:blogger.com,1999:blog-8880848735938155014.post-48247193629503948532013-01-17T06:00:00.002-08:002013-02-25T09:10:41.091-08:00Sitecore Solution Custom Configuration<span style="font-family: Calibri;">No matter how many times I look at a Sitecore
web.config<span style="mso-spacerun: yes;"> </span>I inevitably find something
I’ve never seen before, or had forgotten about, or never really understood.
There’s such an abundance of settings, pipelines, hooks, events --- all kinds
of ways to modify and extend the application.</span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Good solution architecture should follow that same approach.
As much as is practical, functional components should expose custom configuration
settings, which allow the solution to be tweaked and extended without the need
to deploy code. This includes such thing as connection strings, service URLs
and communication parameters, pick list options, content locations, task
behaviors, UI factors … anything that code or users need to make decisions
about how the application should work.</span></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">There are four key places where configuration options can be
created and managed:</span></div>
<ol>
<li><div class="MsoListParagraphCxSpFirst" style="margin: 0in 0in 0pt 0.5in; mso-list: l2 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: "Courier New";">Web.config</span></div>
</li>
<li><div class="MsoListParagraphCxSpMiddle" style="margin: 0in 0in 0pt 0.5in; mso-list: l2 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Calibri;">Config files in the </span><span style="font-family: "Courier New";">/App_Config/Include</span><span style="font-family: Calibri;"> folder</span></div>
</li>
<li><div class="MsoListParagraphCxSpMiddle" style="margin: 0in 0in 0pt 0.5in; mso-list: l2 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Calibri;">Sitecore content items (typically in a global “</span><span style="font-family: "Courier New";">MetaData</span><span style="font-family: Calibri;">” or “</span><span style="font-family: "Courier New";">Settings</span><span style="font-family: Calibri;">” node)</span></div>
</li>
<li><div class="MsoListParagraphCxSpLast" style="margin: 0in 0in 10pt 0.5in; mso-list: l2 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Calibri;">Static code classes, exposed as enums, constants, properties or methods<o:p></o:p></span></div>
</li>
</ol>
<span style="font-family: Calibri;">There are other, more obscure methods as well. For example,
an application initialization event could create application-scoped objects, or
even modify the running config. Cool as all that may be, these techniques are
only useful in unusual circumstances, and can complicate analysis and
troubleshooting.</span><br />
<br />
<span style="font-family: Calibri;">There is no single right way for configuration management in
a solution; rather, any given configuration setting should be managed in the location
that makes the most sense for that function.</span><br />
<h1 style="margin: 24pt 0in 0pt;">
<span style="font-size: large;"><span style="color: #365f91;"><span style="font-family: Cambria;">Using web.config<o:p></o:p></span></span></span></h1>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">It is best to avoid using web.config to store custom application
settings. Generally speaking, only Sitecore platform specific configuration
should be handled here. Settings embedded within web.config can be a nightmare when
deploying and reconciling across environments. <o:p></o:p></span></div>
<span style="font-family: Calibri;">All configuration within the Sitecore section of the web
config can be extended and modified within .config files (below). Rather than
placing settings in web.config, it is better to group related configuration
items within .config files, making management, deployment and troubleshooting
much easier.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Content owners cannot make changes to web.config, and
developers might not be able to easily make changes here is some landscapes. <o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Web.config should be used only for very stable,
solution-wide settings, and that, rarely (.config files can accomplish the same
thing and are more manageable). Ideally, only Sitecore platform specific
configuration – things that are part of the Sitecore release --- should be managed
in web.config.</span></div>
<h1 style="margin: 24pt 0in 0pt;">
<span style="font-size: large;"><span style="color: #365f91;"><span style="font-family: Cambria;">Using .config files<o:p></o:p></span></span></span></h1>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Sitecore allows any number of .config files to be created in
the<span style="mso-spacerun: yes;"> </span></span><span style="font-family: "Courier New";">/App_Config/Include</span><span style="font-family: Calibri;">
folder. These config files require a specific XML structure, and are reconciled
with web.config when Sitecore initializes, to create a “running config”. This
running config represents what the web.config file would look like if all
configuration were managed in one file. <o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Remember that Sitecore reconciles all of the .config files
against web.config at application initialization. It is possible for two config
files to modify the same configuration item, and it is difficult to predict
what order the .config files will be applied.<span style="mso-spacerun: yes;">
</span>Sitecore provides a utility </span><span style="font-family: "Courier New";">at
/sitecore/admin/showconfig.aspx</span><span style="font-family: Calibri;"> to view the running config, which can be
very helpful when troubleshooting.<o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Well organized .config files are a very powerful way to
handle configuration, as related configuration item can be aggregated into a
single file. Configuration for settings, pipeline processors, events, etc<span style="mso-spacerun: yes;"> </span>can be added to the “running config” here,
which has the same effect as modifying web.config, but in a more manageable
way. Modifying existing web config entries in external .config files allows the
solution to have ‘default” behavior defined in web.config while making server,
landscape or application specific changes to be made in separate file in
separate environments.<o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">This is the ideal place to manage config in the following
circumstances:<o:p></o:p></span></div>
<ol>
<li>
<span style="font-family: Calibri;">The configuration modifies or extends an existing setting, event or pipeline in web.config.<o:p></o:p></span></li>
<li><span style="font-family: Calibri;">This configuration might need to have different values in different environments.<o:p></o:p></span></li>
<li><span style="font-family: Calibri;">The configuration related to a module or package that needs to be distributable.<o:p></o:p></span></li>
<li><span style="font-family: Calibri;">Only developers or administrators should be allowed to change the configuration.<o:p></o:p></span></li>
</ol>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Settings in these files should follow the Sitecore setting
syntax.<o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="background: rgb(242, 242, 242); line-height: normal; margin: 0in 0in 0pt 0.5in; mso-background-themecolor: background1; mso-background-themeshade: 242; mso-layout-grid-align: none;">
<span style="color: blue; font-family: Consolas; font-size: 9.5pt;"><</span><span style="color: #a31515; font-family: Consolas; font-size: 9.5pt;">configuration</span><span style="color: blue; font-family: Consolas; font-size: 9.5pt;"> </span><span style="color: red; font-family: Consolas; font-size: 9.5pt;">xmlns:patch</span><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">=</span><span style="font-family: Consolas; font-size: 9.5pt;">"<span style="color: blue;">http://www.sitecore.net/xmlconfig/</span>"<span style="color: blue;">></span></span></div>
<div class="MsoNormal" style="background: rgb(242, 242, 242); line-height: normal; margin: 0in 0in 0pt 0.5in; mso-background-themecolor: background1; mso-background-themeshade: 242; mso-layout-grid-align: none;">
<span style="color: blue; font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><</span><span style="color: #a31515; font-family: Consolas; font-size: 9.5pt;">sitecore</span><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">></span></div>
<div class="MsoNormal" style="background: rgb(242, 242, 242); line-height: normal; margin: 0in 0in 0pt 0.5in; mso-background-themecolor: background1; mso-background-themeshade: 242; mso-layout-grid-align: none;">
<span style="color: blue; font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><</span><span style="color: #a31515; font-family: Consolas; font-size: 9.5pt;">settings</span><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">></span></div>
<div class="MsoNormal" style="background: rgb(242, 242, 242); line-height: normal; margin: 0in 0in 0pt 0.5in; mso-background-themecolor: background1; mso-background-themeshade: 242; mso-layout-grid-align: none;">
<span style="color: blue; font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><!—</span><span style="color: green; font-family: Consolas; font-size: 9.5pt;">Items to fetch per
connection </span><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">--></span></div>
<div class="MsoNormal" style="background: rgb(242, 242, 242); line-height: normal; margin: 0in 0in 0pt 0.5in; mso-background-themecolor: background1; mso-background-themeshade: 242; mso-layout-grid-align: none;">
<span style="color: blue; font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><</span><span style="color: #a31515; font-family: Consolas; font-size: 9.5pt;">setting</span><span style="color: blue; font-family: Consolas; font-size: 9.5pt;"> </span><span style="color: red; font-family: Consolas; font-size: 9.5pt;">name</span><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">=</span><span style="font-family: Consolas; font-size: 9.5pt;">"<span style="color: blue;">MyDataConsumer.ItemsToFetchPerConnection</span>"<span style="color: blue;"> </span><span style="color: red;">value</span><span style="color: blue;">=</span>"<span style="color: blue;">10</span>"<span style="color: blue;"> /></span><o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
</div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Note the naming convention for the name of the </span><span style="font-family: "Courier New";">setting</span><span style="font-family: Calibri;"> node. Using the dotted
notation (</span><span style="font-family: "Courier New";">MySettingGroup.MySettingItem</span><span style="font-family: Calibri;">)
creates a pseudo-namespace that prevents name collisions. Remember that all
settings in config files are merged together into a single running config when
Sitecore initializes. Every setting needs to have a unique name when the
configs are merged.<o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;"><span style="mso-spacerun: yes;"> </span>It is a good practice
to create an associated class that exposes these settings through properties or
static methods.<o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="background: rgb(242, 242, 242); line-height: normal; margin: 0in 0in 0pt 0.5in; mso-background-themecolor: background1; mso-background-themeshade: 242; mso-layout-grid-align: none;">
<span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">static</span> <span style="color: blue;">int</span> <span style="color: blue;">ItemsToFetchPerConnection</span></span></div>
<div class="MsoNormal" style="background: rgb(242, 242, 242); line-height: normal; margin: 0in 0in 0pt 0.5in; mso-background-themecolor: background1; mso-background-themeshade: 242; mso-layout-grid-align: none;">
<span style="font-family: Consolas; font-size: 9.5pt;">{</span></div>
<div class="MsoNormal" style="background: rgb(242, 242, 242); line-height: normal; margin: 0in 0in 0pt 0.5in; mso-background-themecolor: background1; mso-background-themeshade: 242; mso-layout-grid-align: none;">
<span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-tab-count: 1;"> </span><span style="color: blue;">get</span></span></div>
<div class="MsoNormal" style="background: rgb(242, 242, 242); line-height: normal; margin: 0in 0in 0pt 0.5in; mso-background-themecolor: background1; mso-background-themeshade: 242; mso-layout-grid-align: none;">
<span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-tab-count: 1;"> </span>{</span></div>
<div class="MsoNormal" style="background: rgb(242, 242, 242); line-height: normal; margin: 0in 0in 0pt 0.5in; mso-background-themecolor: background1; mso-background-themeshade: 242; mso-layout-grid-align: none;">
<span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-tab-count: 2;"> </span><span style="color: blue;">return</span>
Sitecore.Configuration.<span style="color: #2b91af;">Settings</span>.GetIntSetting(</span></div>
<div class="MsoNormal" style="background: rgb(242, 242, 242); line-height: normal; margin: 0in 0in 0pt 0.5in; mso-background-themecolor: background1; mso-background-themeshade: 242; mso-layout-grid-align: none;">
<span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-tab-count: 3;"> </span><span style="color: blue;">MyDataConsumer.ItemsToFetchPerConnection</span><span style="color: #a31515;">"</span>, 0);</span></div>
<div class="MsoNormal" style="background: rgb(242, 242, 242); line-height: normal; margin: 0in 0in 0pt 0.5in; mso-background-themecolor: background1; mso-background-themeshade: 242; mso-layout-grid-align: none;">
<span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-tab-count: 1;"> </span>}</span></div>
<div class="MsoNormal" style="background: rgb(242, 242, 242); line-height: normal; margin: 0in 0in 0pt 0.5in; mso-background-themecolor: background1; mso-background-themeshade: 242; mso-layout-grid-align: none;">
<span style="font-family: Consolas; font-size: 9.5pt;">}<o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
</div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Not only can .config files extend Sitecore configuration,
but they can even change Sitecore configuration by using a </span><span style="font-family: "Courier New";">patch</span><span style="font-family: Calibri;"> attribute.<span style="mso-spacerun: yes;"> </span></span><a href="http://www.sitecore.net/Community/Technical-Blogs/John-West-Sitecore-Blog/Author.aspx"><span style="color: blue; font-family: Calibri;">John
West’</span></a><span style="font-family: Calibri;">s blog post, </span><a href="http://www.sitecore.net/Community/Technical-Blogs/John-West-Sitecore-Blog/Posts/2011/05/All-About-web-config-Include-Files-with-the-Sitecore-ASPNET-CMS.aspx"><span style="color: blue; font-family: Calibri;">“All
About web.config Include Files with the Sitecore ASP.NET CMS</span></a><span style="font-family: Calibri;">” discusses
config patching, and includes links to more in-depth reading.<o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">In most cases, developers can create and deploy config
files, at least within the developer and QA environments. Of course, content
authors generally can’t touch config files.</span></div>
<h1 style="margin: 24pt 0in 0pt;">
<span style="font-size: large;"><span style="color: #365f91;"><span style="font-family: Cambria;">Using content items<o:p></o:p></span></span></span></h1>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">It is common practice to have a global settings section of
the content tree, usually (not below) the home node. This node is usually
called something like “</span><span style="font-family: "Courier New";">MetaData</span><span style="font-family: Calibri;">”
or “</span><span style="font-family: "Courier New";">Settings</span><span style="font-family: Calibri;">”.<o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">This is a great place to manage configuration in these
circumstances:<o:p></o:p></span></div>
<ol>
<li>
<span style="font-family: Calibri;">The setting is always the same across all landscapes and environments.<o:p></o:p></span></li>
<li><span style="font-family: Calibri;">Content authors, editors or power users should be able to manage the setting.<o:p></o:p></span></li>
<li><span style="font-family: Calibri;">The setting relates to interface elements, like the items to be included in a pick list in a data template or rendering parameter template.<o:p></o:p></span></li>
</ol>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Settings stored here are very easy to manage, but there is
also some risk. Whenever a setting can affect the stability of the application,
there should be tighter control over who can change it. Using security can help
protect these settings while allowing them to be managed in the Sitecore UI, but
moving them to .config or static classes protects them from UI users
altogether.<o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Rather than creating a template that contains all of the
fields needed for a particular “set” of settings, I generally create a several
generic “settings” templates, and use them to create items in grouped folders
under a “settings” item at the root of the content tree. Some useful templates include:
<i style="mso-bidi-font-style: normal;">General</i> (text), <i style="mso-bidi-font-style: normal;">Link</i> (for references to content items), <i style="mso-bidi-font-style: normal;">WebService</i> (with fields for the URL and credential info), and <i style="mso-bidi-font-style: normal;">File</i> (for media library file items).<o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Settings managed in content cannot have different values for
CM and CD (unless you use two different items). <o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">The nature of the setting also comes into play. When the
setting represents a list of allowable values in a pick list in the content UI,
this is really the only place to manage it (because the items in these lists
are defined as data sources for the field). The danger is that these values
often govern the behavior of code, and unexpected values can cause the code to
throw errors. Again, security can help prevent unintended changes to these
settings.</span></div>
<h1 style="margin: 24pt 0in 0pt;">
<span style="font-size: large;"><span style="color: #365f91;"><span style="font-family: Cambria;">Using static classes<o:p></o:p></span></span></span></h1>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">Settings in static classes (constants, properties or enums)
is the best scenario from a performance perspective, but is also the least
manageable method. Changes to these settings can only be accomplished with a
code deployment.<o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">This is a good approach for things that should only be
changed when code is changing anyway, or only affect code. Static code
configuration should also be considered when performance is a concern. For example,
there are cases where a known predictable content item must be referenced
frequently in code. Storing the GUID of this item in a static class makes the
code much more efficient when accessing the item. If the GUID is unlikely to
ever change, this is an excellent approach. Note that Sitecore exposes the </span><span style="font-family: "Courier New";">Sitecore.FieldIDs</span><span style="font-family: Calibri;"> and </span><span style="font-family: "Courier New";">Sitecore.ItemIDs</span><span style="font-family: Calibri;"> classes where the
GUIDS of well-known items are stored. <o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;">In fact, this is a good way to “bootstrap” settings that are
managed in the Sitecore content tree. Create a property in code with the GUID
of the folder that contains the settings. This avoids hard-coding the location
of the settings, and allows the settings to be accessed even if the location of
the settings folder changes.</span></div>
<h1 style="margin: 24pt 0in 0pt;">
<span style="font-size: large;"><span style="color: #365f91;"><span style="font-family: Cambria;">Settings location guidelines<o:p></o:p></span></span></span></h1>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<o:p><span style="font-family: Calibri;"> <span style="font-family: Times New Roman;">
</span></span></o:p><span style="font-family: Calibri;"><span style="font-family: Times New Roman;"></span></span></div>
<span style="font-family: Calibri;"><span style="font-family: Times New Roman;"></span></span><br />
<span style="font-family: Calibri;"><span style="font-family: Times New Roman;"><table border="1" cellpadding="0" cellspacing="0" class="MsoTableMediumList2" style="border-collapse: collapse; border: currentColor; mso-border-alt: solid black 1.0pt; mso-border-themecolor: text1; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184; width: 667px;">
<tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: -1;">
<td style="background: white; border-color: rgb(0, 0, 0) rgb(0, 0, 0) black; border-style: none none solid; border-width: 0px 0px 3pt; mso-background-themecolor: background1; mso-border-bottom-themecolor: text1; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 517; page-break-after: avoid;">
</div>
</td>
<td style="background: white; border-color: rgb(0, 0, 0) rgb(0, 0, 0) black; border-style: none none solid; border-width: 0px 0px 3pt; mso-background-themecolor: background1; mso-border-bottom-themecolor: text1; padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 1; page-break-after: avoid; text-align: center;">
<b style="mso-bidi-font-weight: normal;"><span style="color: black; font-family: "Cambria","serif"; font-size: 12pt; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">web.config<o:p></o:p></span></b></div>
</td>
<td style="background: white; border-color: rgb(0, 0, 0) rgb(0, 0, 0) black; border-style: none none solid; border-width: 0px 0px 3pt; mso-background-themecolor: background1; mso-border-bottom-themecolor: text1; padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 1; page-break-after: avoid; text-align: center;">
<b style="mso-bidi-font-weight: normal;"><span style="color: black; font-family: "Cambria","serif"; font-size: 12pt; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Config file<o:p></o:p></span></b></div>
</td>
<td style="background: white; border-color: rgb(0, 0, 0) rgb(0, 0, 0) black; border-style: none none solid; border-width: 0px 0px 3pt; mso-background-themecolor: background1; mso-border-bottom-themecolor: text1; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 1; page-break-after: avoid; text-align: center;">
<b style="mso-bidi-font-weight: normal;"><span style="color: black; font-family: "Cambria","serif"; font-size: 12pt; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Content item<o:p></o:p></span></b></div>
</td>
<td style="background: white; border-color: rgb(0, 0, 0) rgb(0, 0, 0) black; border-style: none none solid; border-width: 0px 0px 3pt; mso-background-themecolor: background1; mso-border-bottom-themecolor: text1; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 1; page-break-after: avoid; text-align: center;">
<b style="mso-bidi-font-weight: normal;"><span style="color: black; font-family: "Cambria","serif"; font-size: 12pt; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Static class<o:p></o:p></span></b></div>
</td>
</tr>
<tr style="mso-yfti-irow: 0;">
<td colspan="5" style="background: rgb(13, 13, 13); border-color: rgb(0, 0, 0) black windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-background-themecolor: text1; mso-background-themetint: 242; mso-border-bottom-alt: solid windowtext .5pt; mso-border-right-alt: solid black 1.0pt; mso-border-right-themecolor: text1; mso-border-top-alt: solid black 3.0pt; mso-border-top-themecolor: text1; padding: 0in 5.4pt; width: 6.95in;" valign="top" width="667"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 68; page-break-after: avoid;">
<b style="mso-bidi-font-weight: normal;"><span style="color: white; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: background1;">Types</span></b><span style="color: white; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: background1;"> (what
does this setting affect?)<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 1;">
<td style="background: white; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: background1; mso-border-right-themecolor: text1; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 4; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Part of the Sitecore platform<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-border-right-themecolor: text1; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 2;">
<td style="background: white; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: background1; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 68; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Related to code<o:p></o:p></span></div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background: silver; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 3;">
<td style="background: white; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: background1; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 4; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Related to infrastructure<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
</div>
</td>
</tr>
<tr style="mso-yfti-irow: 4;">
<td style="background: white; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: background1; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 68; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Related to content<o:p></o:p></span></div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background: silver; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
</tr>
<tr style="mso-yfti-irow: 5;">
<td colspan="5" style="background: rgb(13, 13, 13); border-color: rgb(0, 0, 0) black windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-background-themecolor: text1; mso-background-themetint: 242; mso-border-bottom-alt: solid windowtext .5pt; mso-border-right-alt: solid black 1.0pt; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 6.95in;" valign="top" width="667"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 4; page-break-after: avoid;">
<b style="mso-bidi-font-weight: normal;"><span style="color: white; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: background1;">Roles</span></b><span style="color: white; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: background1;"> (who
manages this setting?)<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 6;">
<td style="background: white; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: background1; mso-border-right-themecolor: text1; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 68; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Developer<o:p></o:p></span></div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background: silver; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-right-themecolor: text1; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 7;">
<td style="background: white; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: background1; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 4; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">System administrator<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
</div>
</td>
</tr>
<tr style="mso-yfti-irow: 8;">
<td style="background: white; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: background1; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 68; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Site architect<o:p></o:p></span></div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background: silver; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 9;">
<td style="background: white; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: background1; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 4; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Business owner<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
</div>
</td>
</tr>
<tr style="mso-yfti-irow: 10;">
<td colspan="5" style="background: rgb(13, 13, 13); border-color: rgb(0, 0, 0) black windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-background-themecolor: text1; mso-background-themetint: 242; mso-border-bottom-alt: solid windowtext .5pt; mso-border-right-alt: solid black 1.0pt; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 6.95in;" valign="top" width="667"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 68; page-break-after: avoid;">
<b style="mso-bidi-font-weight: normal;"><span style="color: white; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: background1;">Environments
</span></b><span style="color: white; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: background1;">(CM vs
CD)<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 11;">
<td style="background: white; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: background1; mso-border-right-themecolor: text1; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 4; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Same on all environments<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-border-right-themecolor: text1; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
</tr>
<tr style="height: 4pt; mso-yfti-irow: 12;">
<td style="background: white; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; height: 4pt; mso-background-themecolor: background1; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 68; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Different in each environment<o:p></o:p></span></div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); height: 4pt; mso-background-themecolor: text1; mso-background-themetint: 63; padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); height: 4pt; mso-background-themecolor: text1; mso-background-themetint: 63; padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); height: 4pt; mso-background-themecolor: text1; mso-background-themetint: 63; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background: silver; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; height: 4pt; mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
</tr>
<tr style="mso-yfti-irow: 13;">
<td colspan="5" style="background: rgb(13, 13, 13); border-color: rgb(0, 0, 0) black windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-background-themecolor: text1; mso-background-themetint: 242; mso-border-bottom-alt: solid windowtext .5pt; mso-border-right-alt: solid black 1.0pt; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 6.95in;" valign="top" width="667"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 4; page-break-after: avoid;">
<b style="mso-bidi-font-weight: normal;"><span style="color: white; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: background1;">Volatility</span></b><span style="color: white; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: background1;"> (how
often does it change?)<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 14;">
<td style="background: white; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: background1; mso-border-right-themecolor: text1; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 68; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Frequently<o:p></o:p></span></div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background: silver; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-right-themecolor: text1; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
</tr>
<tr style="mso-yfti-irow: 15;">
<td style="background: white; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: background1; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 4; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Infrequently<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 16;">
<td colspan="5" style="background: rgb(13, 13, 13); border-color: rgb(0, 0, 0) black windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-background-themecolor: text1; mso-background-themetint: 242; mso-border-bottom-alt: solid windowtext .5pt; mso-border-right-alt: solid black 1.0pt; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 6.95in;" valign="top" width="667"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 68; page-break-after: avoid;">
<b style="mso-bidi-font-weight: normal;"><span style="color: white; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: background1;">Risk</span></b><span style="color: white; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: background1;">
(impact of a mistake)<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 17;">
<td style="background: white; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: background1; mso-border-right-themecolor: text1; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 4; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Changes affect entire application<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-border-right-themecolor: text1; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 18;">
<td style="background: white; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: background1; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 68; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Changes affect part of the application<o:p></o:p></span></div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background: silver; border: 0px rgb(0, 0, 0); mso-background-themecolor: text1; mso-background-themetint: 63; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background: silver; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
</tr>
<tr style="mso-yfti-irow: 19;">
<td style="background: white; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-background-themecolor: background1; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 4; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Changes affect availability of data<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border: 0px rgb(0, 0, 0); padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) black rgb(0, 0, 0) rgb(0, 0, 0); border-style: none solid none none; border-width: 0px 1pt 0px 0px; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; page-break-after: avoid; text-align: center;">
</div>
</td>
</tr>
<tr style="mso-yfti-irow: 20; mso-yfti-lastrow: yes;">
<td style="background: white; border-color: rgb(0, 0, 0) black windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-background-themecolor: background1; mso-border-bottom-alt: solid windowtext .5pt; mso-border-right-alt: solid black 1.0pt; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 201.7pt;" valign="top" width="269"><div class="Indentedtableitem" style="margin: 0in 0in 0pt 0.15in; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 68; page-break-after: avoid;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">Changes are cosmetic or content only<o:p></o:p></span></div>
</td>
<td style="background: silver; border-color: rgb(0, 0, 0) rgb(0, 0, 0) windowtext; border-style: none none solid; border-width: 0px 0px 1pt; mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-bottom-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 70.3pt;" valign="top" width="94"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
<td style="background: silver; border-color: rgb(0, 0, 0) rgb(0, 0, 0) windowtext; border-style: none none solid; border-width: 0px 0px 1pt; mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-bottom-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 70.9pt;" valign="top" width="95"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background: silver; border-color: rgb(0, 0, 0) rgb(0, 0, 0) windowtext; border-style: none none solid; border-width: 0px 0px 1pt; mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-bottom-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
<span style="color: black; font-family: "Cambria","serif"; mso-ascii-theme-font: major-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: major-bidi; mso-fareast-font-family: "Times New Roman"; mso-fareast-theme-font: major-fareast; mso-hansi-theme-font: major-latin; mso-themecolor: text1;">•<o:p></o:p></span></div>
</td>
<td style="background: silver; border-color: rgb(0, 0, 0) black windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-background-themecolor: text1; mso-background-themetint: 63; mso-border-bottom-alt: solid windowtext .5pt; mso-border-right-alt: solid black 1.0pt; mso-border-right-themecolor: text1; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-pagination: widow-orphan lines-together; mso-yfti-cnfc: 64; page-break-after: avoid; text-align: center;">
</div>
</td>
</tr>
</tbody></table>
</span></span><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
</div>
<span style="font-family: Calibri;"><span style="font-family: Times New Roman;">
</span></span>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-family: Calibri;"><br /></span></div>
<span style="font-family: Calibri;">
</span>
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<br />
<h4>
<span style="color: #365f91; font-family: Cambria; font-size: large;">More reading...</span></h4>
</div>
<div>
<i><a href="http://www.sitecore.net/Community/Technical-Blogs/John-West-Sitecore-Blog/Author.aspx">John West</a>: </i>"<a href="http://www.sitecore.net/Community/Technical-Blogs/John-West-Sitecore-Blog/Posts/2011/05/All-About-web-config-Include-Files-with-the-Sitecore-ASPNET-CMS.aspx"><b>All About web.config Include Files with the Sitecore ASP.NET CMS</b></a>"<br />
<i><a href="http://www.sitecore.net/Community/Technical-Blogs/John-West-Sitecore-Blog/Author.aspx">John West</a>: </i>"<a href="http://www.sitecore.net/Community/Technical-Blogs/John-West-Sitecore-Blog/Posts/2011/02/The-Sitecore-ASPNET-CMS-Configuration-Factory.aspx"><b>The Sitecore ASP.NET CMS Configuration Factory</b></a>"<br />
<br />
<br /></div>
Andy Uzickhttp://www.blogger.com/profile/02076585774001842004noreply@blogger.com0