Skip to content

UAG 2010 Custom Portal

Hello everyone. In the next couple posts I’ll talk a bit about making changes to the UAG Portal and UAG Logon pages. Most customer deployments require complete rebranding of these two user interfaces and as I found there is not whole a lot of information available on how to do this. I just did a project where customer wanted to have a completely different look from the default UAG branding. Changing text strings in Language file was not enough for them, and unfortunately UAG help does not go into much more detail on how to do other changes to Portal or Logon pages. Also, while customer wanted to have their own unique look and feel, they wanted to make sure we do not modify UAG code and keep it default as much as possible.

I’m not going to discuss how to modify UI for mobile phones or other type of clients. This post discusses how to modify UAG Portal UI for normal browsers only.

First I’ll talk about rebranding the Portal UI. I know it is not what user sees first, but I just feel like talking about it first.

Before we go into the changes let’s compare the default UAG Portal UI and what we want it to look like.

This is what you are most familiar with:

clip_image002

This is what we are going to make it look after a few changes:

clip_image004

They do look very different isn’t it? In the following diagram I’m going to identify specific zones and elements on the original UI that we are going to change:

clip_image005

As you can see I identified seven general areas that must be modified. Each of the areas actually have different elements that controlled via its own configuration files.

Let’s take a look at each area and identify what must be changed:

  1. Area 1. This is the logo in the left top corner and it must be replaced with our own custom logo.
  2. Area 2. In this area we need to remove the “Application and Network Access Portal” words out and replace the background with our own custom background.
  3. Area 3. Here we need to replace all image buttons with text, remove some of these buttons and replace background with our own custom background.
  4. Area 4. Need to replace it with our custom background graphic.
  5. Area 5. The left side folder area must be removed.
  6. Area 6. In main application area we will replace the background color and modify the text shown with each published application.
  7. Area 7. In footer area we need to replace the text and provide our own background color.

Some of the above areas have other elements as well, like borders for example which we need to either remove or replace with more suitable colors.

All custom changes in UAG are recommended to be done via supported CustomUpdate folder mechanism. Basically, you take the file that you want to modify and copy it in the corresponding CustomUpdate folder. Then you will modify this file and UAG will automagically pick them up and use these settings for displaying UI. It is not recommended or supported to modify files in their default locations.

The Portal UI is controlled by code located in PortlalHomePage folder. There are a lot of folders there, but the two main that we are going to work with are the following:

  • App_Themes
  • Data

Most of the visible text strings that we see in UI are controlled via languages configuration files. There is one for each supported language. I’m going to work with English only. The default files are located under Data\Languages folder. To customize text strings we’ll copy EN-US.XML file to Data\Languages\CustomUpdate folder and make some changes to it. If you look at this file you’ll see a few hundred IDs with corresponding text. It is called from the application code and all we need to do is to identify proper IDs and modify text to our own liking.

Let’s see what we need to modify in each area.

  • Area 1. There is no text there. No changes to EN-US.XML file.
  • Area 2. The default UI has the following text: “Application and Network Access Portal” which is not present in our final custom UI. We need to remove this text from EN-US.XML file. This text string is controlled by ID #12. Remove it, so it looks like this: <String id=”12” _locID=”12”></String>
  • Area 3. It does not contain text that we need to change via Languages file.
  • Area 4. It does not contain text that we need to change via Languages file.
  • Area 5. It does not contain text that we need to change via Languages file.
  • Area 6. It does not contain text that we need to change via Languages file.
  • Area 7. The default UI has the following text: “Contact us | Microsoft Corporation. All rights reserved. Terms and Conditions”. This string is actually controlled via different configuration files:

Contact us” is controlled via ID 182. If we remove it from languages file, it will still take the space in the footer and the rest of the footer will not be properly aligned. Also, the vertical separator “|” is not controlled via Languages file. Both of this values will be removed from UI by modifying Data\Sitemap\Footer\LeftFooter.sitemap file. Comment out the first two sections, so it looks like this and then copy this file to Data\Sitemap\Footer\CustomUpdate\ folder:

 

<?xml version=”1.0″ encoding=”utf-8″ ?>
<siteMap xmlns=”http://schemas.microsoft.com/AspNet/SiteMap-File-1.0&#8243; enableLocalization=”true”>
<siteMapNode url=”” title=”” description=””>
<!– <siteMapNode url=”mailto:”
title=”$Resources:Resource, 182″
description=”$Resources:Resource, 182″
imageUrl=””
displayMode=”OnlyText”
target=”_blank” /> –>

<!– <siteMapNode url=””
title=”|”
description=””
imageUrl=””
displayMode=”OnlyText”
target=”” /> –>

<siteMapNode url=””
title=”$Resources:Resource,1″
description=””
imageUrl=””
displayMode=”OnlyText”
target=””
selectable=”false”  />

</siteMapNode>
</siteMap>

Microsoft Corporation. All rights reserved. Terms and Conditions” text is controlled via Languages file using <String id=”1” _locID=”1”>. For our custom portal we will replace it with the following text so it looks like this:

  • <String id=”1″ _locID=”1″><!– _locID_CDATA=”HTM” –><![CDATA[<a href=’https://portal.contoso.com’>Home</a&gt; | Contoso Inc | UAG CustomPortal | CloudIdentityBlog.com]]></String>
  • Site Title for UAG portal is controlled via String id =11. Modify it to whatever title is required, in our case: <String id=”11″ _locID=”11″>Executive Office for Immigration Review – Portal</String>

After making changes to the EN-US.XML file, copy it to the Data\Languages\CustomUpdate folder. Activate UAG and we see the following UI:

clip_image007

Area three contains a lot of action buttons. Most of these buttons were removed from our UI and all of them were converted to text only presentation.

To modify “Log Off” button and remove little door from UI modify Data\Sitemap\Toolbar\Logout.Sitemap from this:

<?xml version=”1.0″ encoding=”utf-8″ ?>
<siteMap xmlns=”http://schemas.microsoft.com/AspNet/SiteMap-File-1.0&#8243; enableLocalization=”true” >
<siteMapNode url=”” title=”” description=””>
<siteMapNode url=””
title=”&lt;span id=’timer’&gt;&lt;/span&gt;”
description=””
imageUrl=””
DisplayMode=”OnlyText”
target=””
selectable=”false”></siteMapNode>
<siteMapNode url=”javascript:logoff();”

title=”$Resources:Resource, 112″
description=””
imageUrl=”~/images/Toolbar/logout.gif”
displayMode=”ImageAndText”
target=”” />

</siteMapNode>
</siteMap>

To this:

<?xml version=”1.0″ encoding=”utf-8″ ?>
<siteMap xmlns=”http://schemas.microsoft.com/AspNet/SiteMap-File-1.0&#8243; enableLocalization=”true” >
<siteMapNode url=”” title=”” description=””>

<siteMapNode url=””
title=”&lt;span id=’timer’&gt;&lt;/span&gt;”
description=””
imageUrl=””
DisplayMode=”OnlyText”
target=””
selectable=”false”></siteMapNode>
<siteMapNode url=”javascript:logoff();”
title=”$Resources:Resource, 112″
description=””
imageUrl=”~/images/Toolbar/logout.gif”
displayMode=”OnlyText”
target=”” />

</siteMapNode>
</siteMap>

And copy it to the Data\Sitemap\Toolbar\CustomUpdate folder.

Refresh UAG Portal on the client and you’ll have this UI:

clip_image009

All other buttons are controlled via the Data\Sitemap\Toolbar\Web.Sitemap file. Modify it to look like this, commenting out all buttons and graphic:

<?xml version=”1.0″ encoding=”utf-8″?>
<siteMap xmlns=”http://schemas.microsoft.com/AspNet/SiteMap-File-1.0&#8243; enableLocalization=”true”>

<siteMapNode url=”Default.aspx” title=”Home” description=”Home page” imageUrl=””>
<!– <siteMapNode url=”javascript:BrowseInitialApplication()”
title=”$Resources:Resource,102″
description=”$Resources:Resource, 102″
imageUrl=”~/images/ToolBar/home.gif”
target=”_self”
selectable=”true”
value=”root/” /> –>

<!– <siteMapNode url=””
title=””
description=””
imageUrl=”~/images/ToolBar/seperator.gif”
displayMode=”OnlyImage”
target=””
selectable=”false”
/> –>

<siteMapNode url=”javascript:openCredentialsWin(‘/internalsite/credentialssettings.asp’)”
title=”$Resources:Resource, 103″
description=”$Resources:Resource, 103″
imageUrl=”~/images/ToolBar/credentialsSettings.gif”
visibleConditionMethod=”IsCredentialsManagementSupported”
target=”_self” />

<siteMapNode url=””
title=””
description=””
imageUrl=”~/images/ToolBar/seperator.gif”
displayMode=”OnlyImage”
visibleConditionMethod=”IsCredentialsManagementSupported”
target=””
selectable=”false” />

<siteMapNode provider=”ApplicationListSiteMapProvider” />

<siteMapNode url=””
title=””
description=””
imageUrl=”~/images/ToolBar/seperator.gif”
displayMode=”OnlyImage”
target=””
selectable=”false” />

<siteMapNode url=”javascript:openBrowseAdditional();”
title=”$Resources:Resource, 106″
description=”$Resources:Resource, 106″
imageUrl=”~/images/ToolBar/browse.gif”
displayMode=”OnlyImage”
target=””
visible=”false”/>

<siteMapNode url=””
title=””
description=””
imageUrl=”~/images/ToolBar/seperator.gif”
displayMode=”OnlyImage”
target=””
selectable=”false”
visible=”false” />

<!– <siteMapNode url=”javascript:openSystemInformation();”
title=”$Resources:Resource, 107″
description=”$Resources:Resource, 107″
imageUrl=”~/images/ToolBar/systemInformation.gif”
displayMode=”OnlyImage”
target=”” /> –>

<!– <siteMapNode url=””
title=””
description=””
imageUrl=”~/images/ToolBar/seperator.gif”
displayMode=”OnlyImage”
target=””
selectable=”false”  /> –>

<!– <siteMapNode url=”javascript:openHelp();”
title=”$Resources:Resource, 300″
description=”$Resources:Resource, 300″
imageUrl=”~/images/ToolBar/help.gif”
displayMode=”OnlyImage”
target=”” /> –>

<!– <siteMapNode url=””
title=””
description=””
imageUrl=”~/images/ToolBar/seperator.gif”
displayMode=”OnlyImage”
target=””
selectable=”false”  /> –>

<!– <siteMapNode url=”javascript:showPortalActivity();”
title=”$Resources:Resource, 108″
description=”$Resources:Resource, 109″
imageUrl=”~/images/ToolBar/activity.gif” 
DisplayMode=”ImageAndText”
target=”” /> –>

<!– <siteMapNode url=””
title=””
description=””
imageUrl=”~/images/ToolBar/seperator.gif”
displayMode=”OnlyImage”
target=””
selectable=”false”  /> –>

<!– <siteMapNode url=”mailto:admin@domain.com” 
title=”$Resources:Resource, 113″
description=”$Resources:Resource, 113″ 
imageUrl=”~/images/ToolBar/mailAdmin.gif”
DisplayMode=”OnlyImage”
target=”_blank” /> –>

<!– Copy the file to the CustomUpdate folder and uncomment the next siteMapNode to add a button to the toolbar for the Forefront UAG client components Installer. –>

<!–<siteMapNode url=”~/OfflineInstaller.msi?type=Basic” 
title=”$Resources:Resource, 114″ 
description=”$Resources:Resource, 114″ 
imageUrl=”~/images/ToolBar/offlineInstallation.gif” 
DisplayMode=”OnlyImage” 
target=”_blank” /> –>

</siteMapNode>
</siteMap>

And copy it to the Data\Sitemap\Toolbar\CustomUpdate folder.

Refresh UAG Portal on the client and you’ll have this UI:

clip_image011

The rest of the UI will be modified via Cascading Style Sheets in PortalHomePage\App_Themes folder and new graphic files.

To change search results font color to black and to make application tiles text black make the following changes to TilesViewAppList.css file:

.TilesView_SearchResultsTitle

{
font-size: 10pt;
color: #000000;
font-family: Tahoma;
text-decoration: none;
font-weight: bold;  /* New value */
}

.TilesView_AppItemLink

{
font-size: 9pt;
font-weight: bold;
color: #000000;  /* Change from 0560a6 */
font-family: Tahoma;
text-decoration: underline; 
}

Save this file and copy to the PortalHomePage\App_Themes\CustomUpdate\Office folder.

Refresh UAG Portal on the client and you’ll have this UI:

clip_image013

To modify how text appears in toolbar modify Toolbar.css file to look like this:

#timer

{
font-family: Arial;
font-size: 10pt;
color: #000000;
text-decoration: none;
font-weight: Bold;
}

.StaticMenu

{
font-family: Tahoma;
font-size: 10pt;
color: #2770d6;
width: 36px;
height: 36px;
}

.StaticMenuItem

{
white-space: nowrap;
padding-left: 2px;
padding-right: 2px;
font-family: Tahoma;
font-size: 8pt;
color: #000000;  /* Change from 002c97 */
height: 32px;
margin-right: 1px;
font-weight: Bold;  /* New value */ 
}

.StaticMenuItem tr td a img

{
padding-right: 3px;
height: 32px;
vertical-align: middle;
}

.OverStaticMenuItem

{
background-image: url(Layout/Toolbar_Over_middle.gif);
background-repeat: repeat-x;
padding-left: 2px;
padding-right: 2px;
font-family: Tahoma;
font-size: 8pt;
color: #000000;  /* Change from 002c97 */
width: 30px;
height: 30px;
}

.OverStaticMenuItem tr td img

{
padding-right: 0px;
vertical-align: middle;
}

.OverStaticMenuItem a

{
background:none;
}

.DynamicMenu

{
font-family: Tahoma;
font-size: 8pt;
color: #002c97;
background-color: #f4f8fe;
border: #c9c9c9 1px solid;
width: 200px;
}

.DynamicMenuItem

{
font-family: Tahoma;
font-size: 8pt;
color: #000000; /* Change from 002c97 */
padding-top: 3px;
padding-bottom: 3px;
background-color: #f4f8fe;
border: #f4f8fe 1px solid;
width: 200px;
}

.DynamicMenuItem a

{
width: 150px;
overflow: hidden;
text-overflow: ellipsis;
-moz-text-overflow: ellipsis;
display: block;
font-family: Tahoma;
font-size: 8pt;
color: #000000; /* Change from 002c97 */
padding-right: 3px;
}

.DynamicMenuItem img

{
padding-left: 3px;
padding-right: 6px;
width: 16px;
height: 16px;
}

.DynamicHoverStyle

{
background-image: url(Layout/Toolbar_Over_middle.gif);
background-repeat: repeat-x;
font-family: Tahoma;
font-size: 8pt;
color: #002c97;
padding-top: 3px;
padding-bottom: 3px;
width: 200px;
}

.DynamicHoverStyle a

{
width: 195px;
overflow: hidden;
text-overflow: ellipsis;
display: block;
font-family: Tahoma;
font-size: 8pt;
color: #002c97;
padding-right: 3px;
}

Save this file and copy to the PortalHomePage\App_Themes\CustomUpdate\Office folder.

Refresh UAG Portal on the client and you’ll have this UI:

clip_image015

The final changes will be done via Office.css file and new graphic files.

Modify Office.css to look like this:

/*Office.css*/

body

{
background-color: #ffffff; /* Change from a5c3ee */
background-image: url(Layout/portalbackground2.gif); /* Change from default image */
background-repeat: repeat-x;
}

div#topStrip

{
position: fixed;
top: 0;
left: 0;
height: 152px; /* Change from 53px to match the height of our custom top logo image */
width: 100%;
min-width: 799px;
overflow: hidden;
}

.leftSideBarTable

{
width: 100%;
height: 100%;
table-layout: fixed;
}

.TilesViewTable

{
background-color: #ffffff;
background-image: url(Layout/portalbackground.gif); /* New value for background in app table with custom graphic file */
background-repeat: repeat-x; /* new value */
}

div#toolbar

{
position: absolute;
top:152px; /* Change from 45px to move toolbar below the top logo */
left: 0;
height: 40px;
width: 100%;
min-width: 799px;
z-index: 1000;
}

.topStripLeftCell

{
background-image: url(Layout/Header_logo.gif);
background-repeat: no-repeat;
width:290px; /* Change from 60px to accommodate new top left logo graphic */
}

.topStripLeftCell div

{
width: 290px; /* Change from 60px to accommodate new top left logo graphic */
}

.portalTitleCell

{
background-image: url(Layout/Header_middle.gif);
width: auto;
min-width: 240px;
background-repeat: repeat-x;
}

.topStripWhiteSpacerCell

{
background-image: url(Layout/Header_middle.gif);
background-repeat: repeat-x;
}

.topStripPattern

{
background-image: url(Layout/Header_middle.gif);
background-repeat: repeat-x;
}

.topStripOrangeSpacerCell

{
background-image: url(Layout/Header_middle.gif);
background-repeat: repeat-x;
}

.topStripRightCell

{
background-image: url(Layout/Header_right.gif);
width: 907px;
background-repeat: no-repeat;
}

.toolbarLeftCell

{
background-image: url(Layout/bar1.gif);
background-repeat: repeat-x;
width: 23px;
}

.toolbarMidCell

{
background-image: url(Layout/bar1.gif);
background-repeat: repeat-x;
}

.toolbarRightCell

{
background-image: url(Layout/bar1.gif);
width: 23px;
background-repeat: repeat-x;
}

.leftPanel

{
width: 70%;
float: left;
margin-left: 5px;
margin-bottom: 2px;
}

.rightPanel

{
float: right;
margin-right: 5px;
margin-bottom: 2px;
}

div#content

{
margin-top: 10px;
position: fixed;
top: 194px; /* Change from 85px */
left: 0;
bottom: 79px;
width: 100%;
height: 100%;
min-width: 799px;
}

.contentLeftMargin

{
width: 10px;
height: 100%;
vertical-align: top;
}

.topLeftMarginGradient

{
width: 10px;
height: 86px;
}

.topRightMarginGradient

{
width: 10px;
height: 86px;
}

.bottomLeftMarginGradient

{
width: 10px;
height: 271px;
vertical-align: absbottom;
}

.bottomRightMarginGradient

{
width: 10px;
height: 271px;
vertical-align: absbottom;
}

.contentRightMargin

{
width: 10px;
height: 100%;
vertical-align: top;
}

.contentLeftSideBarCell

{
display:none; /* New value. Remove all other values from this section. This will hide the left side bar tree in the portal UI */
}

.hiddenSideBar

{
border-left: #333333 2px solid; /* Change from 82aeeb */
border-right: #333333 2px solid; /* Change from 82aeeb */
border-bottom: #333333 2px solid; /* Change from 82aeeb */
background-color: #f7faff;
}

.mainContentCell

{
vertical-align: top;
text-align: left;
height: 300px;
width: 100%;
overflow: auto;
}

.leftTopSideBarCell

{
background-image: url(Layout/Panel_header_left.gif);
background-repeat: no-repeat;
width: 7px;
height: 43px;
border-bottom: #c6c6c6 1px solid;
border-left: #333333 2px solid; /* New entry to complete the border */
}

.midTopSideBarCell

{
background-image: url(Layout/Panel_Header_middle.gif);
height: 43px;
width: 199px;
padding-left: 5px;
overflow: hidden;
background-repeat: repeat-x;
border-bottom: #c6c6c6 1px solid;
}

.rightTopSideBarCell

{
background-image: url(Layout/Panel_header_right.gif);
background-repeat: no-repeat;
width: 7px;
height: 43px;
border-bottom: #c6c6c6 1px solid;
border-right: #333333 2px solid; /* Change from 82aeeb */
}

.leftSideBarMargin

{
border-left: #333333 2px solid; /* Change from 82aeeb */
}

.appTreeContainerPanel

{
vertical-align: top;
overflow:auto;
width:100%;
height:100%;
}

.sideBarContent

{
height: 95%;
width: 160px;
overflow: hidden;
vertical-align: top;
border-left: #333333 2px solid; /* Change from 82aeeb */
border-right: #333333 2px solid; /* Change from 82aeeb */
}

.sideBarContent > div

{
height: 100%;
vertical-align: top;
overflow: hidden;
}

.sideBarContent img

{
max-width: 16px;
max-height: 16px;
}

.sideBarContentPanel

{
padding-top: 5px;
height: 100%;
}

.rightSideBarMargin

{
border-right: #333333 2px solid; /* Change from 82aeeb */
height: 100%;
}

.sideBarTitle

{
color: #ffffff; /* Change from 6690ce */
font-family: Tahoma;
font-weight: bold;
font-size: 10pt;
}

.labelTitle

{
color: #000000;
font-family: Tahoma;
font-size: 10pt;
}

div#footer

{
position: fixed;
bottom: 0px;
left: 0px;
clear: both;
width: 100%;
height: 26px;
min-width: 799px;
background-color: #333333; /* Change from white*/
color: #ffffff; /* New value */
}

div#footer table

{
height: 26px;
color: #e6e3e3; /* New value */
font-weight: normal; /* New value */
font-family: George; /* New value */
}

div#footer A

{
color: #e6e3e3; /* New value to provide color for hyperlink in footer */
}

.footerLeftCell

{
background-image: url(Layout/Footer_middle.gif);
background-repeat: repeat-x;
width: 23px;
}

.footerMidCell

{
background-image: url(Layout/Footer_middle.gif);
background-repeat: repeat-x;
}

.footerMidCell div

{
float: left; /* Change from Right */
}

.footerRightCell

{
background-image: url(Layout/Footer_middle.gif);
background-repeat: repeat-x;
width: 23px;
}

.BigTitle

{
font-size: 14pt;
color: gray;
font-family: Tahoma;
text-decoration: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

.main_iframe

{
vertical-align: top;
width: 100%;
height:300px;
overflow: auto;
}

.AjaxLoadingPanel

{
width: 130px;
height: 60px;
text-align: center;
background-color: #ffffff;
border: gray 1px solid;
padding: 10px 10px 10px 10px;
}

.AjaxLoadingImage

{
width: 30px;
height: 30px;
}

.AjaxLoadingLabel

{
font-family: Tahoma;
font-size: 10pt;
color: #000000;
font-weight: bold;
padding-top: 10px;
}

.AjaxLoadingModal

{
background-color:Gray;
filter:alpha(opacity=70);
opacity:0.7;
}

.treeContentSpacerCell

{
width: 10px;
font-size: 6pt;
}

Save this file and copy to the PortalHomePage\App_Themes\CustomUpdate\Office folder.

And in the final step we need to move custom graphic into the PortalHomePage\App_Themes\CustomUpdate\Office\Layout folder. We are replacing the following default images with our custom images:

  1. Toolbar_middle.gif /* Control background of tool bar with all command buttons */
  2. Footer_middle.gif /* Control the footer background */
  3. Header_logo.gif /* Control the left of the top logo area */
  4. Header_middle.gif /* Control the middle of the top logo area */
  5. Header_right.gif /* Control the right side of the top logo area */
  6. Panel_header_left.gif /* Control the left corner of the bar next to Home */
  7. Panel_header_middle.gif /* Control the tool bar from Home to Name */
  8. Panel_header_right.gif /* Control the right corner of the bar next to Name */
  9. Portalbackground.gif /* Control the background inside the main application window */
  10. Portalbackground2.gif /* Control the background around the main application window */

UAG Portal Image map:

clip_image017

Just copy them to the target folder and then refresh UAG Portal on the client computer and we have the winner:

clip_image019

In next post we will discuss how to modify UAG Logon and Logoff UI pages.

7 Comments
  1. Awesome post, didn’t have a clue how to do this. Language files is as far as I’d got.

    Looking forward to the Logon/Logoff pages.

    Like

  2. Brandon S. permalink

    When I do Step: “All other buttons are controlled via the Data\Sitemap\Toolbar\Web.Sitemap file. Modify it to look like this, commenting out all buttons and graphic:” I get an error. I followed it exactly how it is typed out and even copied and pasted it and it still gives an error once I refresh the UAG.

    Like

    • when you comment those buttons out make sure to use double – – , here in UI on the page it was converted to single –

      Like

  3. Roy Driessen permalink

    Do you expect problems with future updates when the new UI is implemented?

    Like

    • it depends on what they do with new UI and code behind it, if it is using the same mechanism to build UI then should have minimal impact, if they change the underlying code then it could be substantial. test it first in the lab!!!

      Like

  4. Chelsea permalink

    How do I get to Portlalhomepage folder? The App_Themes and Data folders? Thanks much

    Like

    • You will find this folders under UAG installation folder, somewhere under c:\Program Files\…

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: