Category: Developer


One month ago, I get a requirement from customer, they need receive email and stored to corresponding document library to SharePoint intranet. Then I thought about incoming email configuration and tried to set it up.

I found an article from Microsoft about step by step guideline to enable incoming email and sync out email to SharePoint with a dedicated email account http://technet.microsoft.com/en-us/library/cc287879(v=office.14).aspx

But when I go throught this articles, I recognized that it’s not easy as I guess and require that you need a power domain permission to implement some steps such as Setup SMTP Server and connect Directory Management Service….

Actually, I got 2 times at least about the question “How can I sync my email to SharePoint library?” from my buddy and colleagues. So I would like write an addins for Microsoft Outlook 2010 to adapt with the customer requirement and share this setup package + source code so that some body find and may be helpfull for you.

The setup package allow install a new tab in Oulook ribbon to configure and sycn selected email to SharePoint 2010 server document library

Before install this add-ins, you need 2 SharePoint list.

– 1 Document Library to store all the Microsoft original basically message files (*.msg). In this article, I named it as “Email Library” so that all selected email from Outlook will be synced to SharePoint and stored in this document library.

– 1 Custom list (which I named “ReviewEmail” in this post), this library was hard coded some neccessary columns with corresponding data type as below

0.ReviewEmailList

  • Subject: Use to stored email subject. This is Multiple line of plain text field, it shouldn’t be single line of text because email subject can be longer than 225 characters
  • ReceiveDate: Date and Time
  • SentDate: Date and Time
  • FromEmail: Single line of text, used to store from email address
  • ToEmail: Since “To Email” may have multiple email addresses, so that I set it to multiple line of plain text field
  • EmailContent: Enhanced rich text (Rich text with pictures, tables, and hyperlinks)
  • FileUrl: Hyperlink. You can download original msg file from here.

1. Run the setup Outlook synchronize to Sharepoint add-ins wizard

0.1 Setup

2. After setup completed, you will see a new Ribbon tab from your outlook and allow you setup SharePoint connection

1.Configure

3. Setup synchronization SharePoint connection from Outlook

You will be asked for

  • SharePoint site url to corresponding SharePoint site/subsite where Email library and Review Email library belongs to
  • Username and Password to login SharePoint server
  • Email library: the library mentioned above
  • Review Email List: the custom list mentioned above to review email data.

2.SetupInfo

  • Then Click Connect button, it will try to connect and save your configuration data for next use.

2.1.SetupSuccess

4. Select with emails you to to sync to SharePoint and click Sync to Server ribbon button, in functionality, the add-ins will read your selected message to save to “Review Email” custom list and upload msg files to “Email Library

3.SelectMutipleEmail - And - SyncToServer

It will show you a simple text if successful, otherwise, an error message will be showed up.

4.SyncSuccess

5. Verify result

  • Selected email were uploaded to Email Library and named with a GUID

5.EmailLibrarySuccess

  • Message’s data was extracted to ReviewEmail custom list with a hyperlink to download msg file

6.ReviewEmailSuccess

See detail of Email was synced to SharePoint from Microsoft Outlook

7.ReviewEmailDetail

I have uploaded setup file and sourcecode to my dirve.

– Installation package https://drive.google.com/file/d/0B55FfAMp1BXddmp2b2NHSC1WdU0

– Source code https://drive.google.com/file/d/0B55FfAMp1BXdVGg0RjEtZnRON1U

Enjoy and hope it help.

Hoang Nhut Nguyen
Email: nhutcmos@gmail.com
Skype: hoangnhut.nguyen

As a SharePoint developer, almost of time you will work with SharePoint object model. Some time you realize that your customize solution make SharePoint performance slow down. It is very important time to think about memory

it is very important to consider for the memory used by your code via these SharePoint objects which was implemented IDisposable interface. It means these types of objects must be disposed right after finish you request for accessing data as soon as possible.

From 2009, Microsoft introduced some guidelines for coding and working with SharePoint object module and SPDisposeCheck is a great utility for checking the disposal patterns for your SharePoint solution, it’s also a helpful utility when you need to review a large of source code from your team.

The latest version of SPDisposeCheck tool has support as Add-in for Visual studio 2008/2010. So you can run SPDisposeCheck when building your Visual Studio project.

You can visit here to get for latest version: http://archive.msdn.microsoft.com/SPDisposeCheck

You can check Roger Lamb’s blog for SPDisposeCheck development team http://blogs.msdn.com/b/rogerla/

There are also couple of White Papers by Scott Harris’s on MSDN for more details:
Best Practices: Using Disposable Windows SharePoint Services Objects
Best Practices: Common Coding Issues When Using the SharePoint Object Model.

Most usually we forgot in our code dispose SPWeb or SPSite object after the new operator

//for SPSite
void CreatingSPSiteLeak()
{
    SPSite siteCollection = new SPSite("http://moss");
    // siteCollection leaked
}

//for Open SPWeb
void OpenWebLeak()
{
    using (SPWeb web = new SPSite(SPContext.Current.Web.Url).OpenWeb())
    {
      // SPSite leaked !
    }
}

//for AllWeb
void AllWebsIndexerLeak()
{
    using (SPSite siteCollection = new SPSite("http://moss"))
    {
        SPWeb web = siteCollection.AllWebs[0];
        // SPWeb web leaked
    }
}

//for Add SPWeb
void AllWebsAddLeak()
{
    using (SPSite siteCollection = new SPSite("http://moss"))
    {
        SPWeb web = siteCollection.AllWebs.Add("site-relative URL");
        // SPWeb web Leaked
    }
}
//And many others scene...

Manually configure run SPDisposeCheck as external tool

Implement as below configure

Manually configure run at compile time

Find all projects under the solution that reference the Microsoft.SharePoint namespace and select properties on the project file. Select the Build Events tab and enter the commands below into the Post-build events text box for On Successful Build:

cd $(ProjectDir)

“..\SharePoint Dispose Check\SPDisposeCheck” “$(TargetPath)” > “$(ProjectName)”.SPDisposeCheck.log

findstr /C:”Total Found:” “$(ProjectName)”.SPDisposeCheck.log


More information about the proper disposal of SharePoint objects, see this article

Hoang Nhut Nguyen
Email: nhutcmos@gmail.com
Skype: hoangnhut.nguyen

Last week, I setup my SharePoint Server 2010 on my laptop for development environment.
After finished all installation, I realized that I need test send mail functions. As you may know, I need to configure outgoing e-mail settings from SharePoint Central Administration with existed mail server, or I have to setup a mail server such as Microsoft Exchange or MDaemon,… but these installations required some technical knowledge about IT and not easy to complete it. More than that, it may required for licenses and make slow performance on my laptop for mail services.

The solution I used my Gmail account to send and receive email from my local SharePoint server via hMailServer, it is a free e-mail server for Microsoft Windows. It’s used by Internet service providers, companies, governments, schools and enthusiasts in all parts of the world.

It supports the common e-mail protocols (IMAP, SMTP and POP3) and can easily be integrated with many existing web mail systems. It has flexible score-based spam protection and can attach to your virus scanner to scan all incoming and outgoing email.

The benefits are:
– There is all free and not required for licenses fee
– Fast and and easy to setup
– Gmail is available and have good performance and security

In this post, I just introduce SMTP to send mail and let you try on POP3 and IMAP 😉
OK, Here we go

Firstly, we can download hMailServer from website, I also uploaded current lasted version to Mediafire

After finished download, run hMailServer-5.3.3.exe file, click Next to continue the installation wizard

If your local machine has database instant, click Next to continue the installation wizard, or you can use SQL Compact if don’t have database engine installation.

Click Next on next screen.

On next screen, select Create a new hMailServer database for the first installation

Select your database server type

Input your database server connection information as below

On next screen, select database service to ensure database service is running before hMailServer service is started

Click Close to finish the wizard

After finished the wizard, it prompts for password to be able manage hMailServer configuraiton

Check Run hMailServer Administrator and click Finish to continue configuration

On Conect screen, check on Automatically connect on start-up and click Connect

From left menu, navigate to SMTP, fill your host name to Local host name textbox and SMTP Relayer information. In this step, you have to provide your email account and password to login to Gmail

On RFC compliance, check  as below

Navigate Auto-ban and uncheck Enabled if you don’t use Auto-ban feature

Navigate to My computer under IP ranges, fill your local IP address or keep 127.0.0.1 in Lower IP and Upper IP. Make sure all check box as below

And same to Internet range

Finally, you should disable Firewall service to make sure you have no problems with connection issues

Next step, Login your SharePoint Central Administration. Go to System Settings and select Configure outgoing e-mail settings under E-Mail and Text Messages (SMS) section

Fill Mail settings with your hMailServer information and email address use to send email

To test send mail function, you can open any your web application and go to Site Permissions. Try to add a user and check on Send welcome e-mai to the new users as below

Finally, open mail box of this user and check result

It’s cool!!!

Hoang Nhut Nguyen
Email: nhutcmos@gmail.com
Skype: hoangnhut.nguyen

ULS Logs vs Windows event logs

If you are SharePoint developer or SharePoint administrator, one of important thing for your job is that face with problems of SharePoint system and give the feedback to your team or correct it as soon as possible.

As you may know, SharePoint provides 2 ways to find the reason of the problems are Windows event logs and ULS Logs.

What is ULS Logs

ULS logs is SharePoint log file which is stored in 12 hiv folder (SharePoint 2007) or 14 hiv folder(SharePoint 2010). These file can be configure to generate logs file from SharePoint Central Administration

Formerly ,I usually use Windows event log to see the reason and debugging, because it’s clear enought to get error message and searching for solution

But now, ULS logs is the first place I need to look for debugging problems. These logs normally contain the bulk of the logging information provided by SharePoint and it’s really difficult to see by text editor but you can use ULS Log Viewer to view, keep it on update and monitor these files. ULS Log Viewer is a free tool, and available now for downloading at http://archive.msdn.microsoft.com/ULSViewer. This tool allow open a log file, monitor SharePoint ULS Logs folder or open from Clipboard.

The benefit of ULS logs is that you can get more details information related to your SharePoint server than Windows event log and only SharePoint information are recorded in these files. So that you can easy to filter by status, categories, operatio, data of time range…

More than that, If you are a developer, SharePoint API allow your solution use this loggin model to through your message to both of ULS log files and Windows event logs via SharePoint Diagnostics Service. Simply, you can trace what you want like log4net library.

 SharePoint Diagnostics Service

Simply, I write the LogToULS method using SPDiagnosticsService to write the logging message as below.

private void LogToULS(string message)
{
    SPDiagnosticsService diagnosticsService = SPDiagnosticsService.Local;
    SPDiagnosticsCategory category = diagnosticsService.Areas["SharePoint Foundation"].Categories["General"];
    diagnosticsService.WriteTrace(99, category, TraceSeverity.High, message, null);
}

As you see, WriteTrace method have some input parameters:

  • The first one is an ID, you can put any number for this parameter
  • The second one is the category we retrieved from the second line
  • The third one is the severity of this log entry message and it’s defined by  TraceSeverity enumeration
  • And your message need to be logged
Hope it’s help!
Hoang Nhut Nguyen
Email: nhutcmos@gmail.com
Skype: hoangnhut.nguyen

Just release from last month, Office 365 is opening a new opportunity for your professionals and small businesses Collaboration to everyone. License price is easy to calculate with $6 per person per month, Office 365 is not expensive to bring your business on Cloud and  help you build solutions that leverage SharePoint Online, Exchange Online and Lync Online, Office Web App (Excel, Word, PowerPoint and OneNote)

And a very new release from Microsoft,  Office 365 Developer Training Kit – June 2011 allow you learn how to build collaborative and communication focused cloud solutions that run in Office 365 using Visual Studio 2010 and the .NET Framework

In this post, I would like to introduce my experience to build a solution with Visual Studio 2010 and deploy in Office 365 SharePoint site.

1. First of all, you need to install Visual Studio 2010 SharePoint Power Tools, this extension allow Visual Studio create SharePoint Visual web parts that can be deployed in a sandboxed solution and displays build errors on compile time

2. Create an empty SharePoint 2010 project and provide your local SharePoint 2010 for debugging

3. Add an Visual Webpart for Sandboxed Solution with several asp controls as below

<p>
All Lists of this site:
<asp:DropDownList ID=”ddlLists” runat=”server”></asp:DropDownList>
</p>
<asp:Button ID=”btnPopularDetails” runat=”server” Text=”Show Details” OnClick=”btnPopularDetails_Click” />
<p>
<asp:GridView ID=”gridListsDetails” runat=”server”></asp:GridView></p>

4. Add following code to get all existed list except document library on page load and show details info of selected list to Gridview when clicked on “Show Details” button

 public partial class VisualWebPart1 : System.Web.UI.WebControls.WebParts.WebPart
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
InitializeControl();
}protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
SPWeb web = SPContext.Current.Web;
var listNames = from SPList list in web.Lists
where list.BaseTemplate != SPListTemplateType.DocumentLibrary
select list.Title;
ddlLists.DataSource = listNames;
ddlLists.DataBind();
}
}protected void btnPopularDetails_Click(object sender, EventArgs e)
{
SPList sourceList = SPContext.Current.Web.Lists.TryGetList(ddlLists.SelectedValue);
SPQuery qry = new SPQuery();
qry.ViewFieldsOnly = true;
qry.ViewFields = “<FieldRef Name = ‘Title’ /><FieldRef Name = ‘Author’ />”;
qry.RowLimit = 20;
gridListsDetails.DataSource = sourceList.GetItems(qry).GetDataTable();
gridListsDetails.EmptyDataText = string.Format(“List {0} have no data”, ddlLists.SelectedValue);
gridListsDetails.DataBind();
}
}

5. Build project and find Office365.wsp under Debug/Bin folder

6. Login to Office 365 with your account

7. Open  Site Setting and navigate to Solution Galleries

And then, Upload your Solution to this gallery, after that click on Active button to active your solution

8. Finally, Create a new page and insert your webpart to see the result

Related Video resources:

Hoang Nhut Nguyen
Email: nhutcmos@gmail.com
Skype: hoangnhut.nguyen

In previous post, I have a post to tell how Configure Forefront Unified Access Gateway for Office Mobile

Last week, I need to find a easier way to allow Iphone Application access SharePoint web service and get the data via http://hostname/_vti_bin/Lists.asmx web service.

As you know, SharePoint isn’t allowing access to their web services without authentication event if it’s configured allow anonymously access. So that, what Iphone/WindowsPhone need to implement sent username and password to SharePoint server for authenticatio in order connect to the web services.

Splendid,  a very simple way allow us to do that, all one needs to do is format the URL properly. The URL should be follow below format

http://user:password@hostname:port/_vti_bin/ServiceName.asmx.

For example, if you have an user “administrator” and the password is “123456” and access Lists.asmx as above request  and SharePoint site is running on host sptest.com via port 123. All that we need to logging this webservice via URL and it would be:

http://administrator:123456@sptest.com:123/_vti_bin/Lists.asmx

I’ve managed to set up external access to Sharepoint from WP7 office hub. I’ve set up separate IIS sites for windows authentication and FBA authentication by extending my web application. The post that helped me enormously to correctly set up FBA is this one:

http://blogs.msdn.com/b/sridhara/archive/2010/01/07/setting-up-fba-claims-in-sharepoint-2010-with-active-directory-membership-provider.aspx

If you’re using SharePoint 2010, for Windows Phone, you can try to use Microsoft SharePoint Workspace Mobile to access SharePoint Server 2010 very easy and simple http://www.microsoft.com/windowsphone/en-us/howto/wp7/office/use-office-sharepoint-workspace-mobile.aspx

Hoang Nhut Nguyen
Email: nhutcmos@gmail.com
Skype: hoangnhut.nguyen

As you know, SharePoint allow to define Search scope and condition to create full text search indexes. This is really one of greatest features SharePoint bring to you.

All search scopes will be managed by Share Services Provider (SSP). It’s easy to create a custom search scopes with friendly user interface.

You can see more details here:

For SharePoint 2007: http://dattard.blogspot.com/2007/04/sharepoint-2007-creating-custom-search.html

For SharePoint 2010: http://technet.microsoft.com/en-us/library/ff453895.aspx

In this post, I would like to focus in Developer side, SharePoint not only provide a powerful feature with ability to index many content, break down the content into different scopes, dynamic and friendly search for end user, but also Developer can query in each existed scopes like a Table  from SQL. It’s awesome!!!

See image below, I created some search scope: All Sites, Poeple, Document Libraries

From now, we can query on each scope as well as example code below

– Query to People Search Scope

DataTable resultDataTable = new DataTable();string SQLQueryString = “SELECT PersonalTitle, Firstname, Lastname, AccountName, Department, workemail”+
“FROM SCOPE() “+
“WHERE \”scope\”=’People’ ORDER BY Write DESC”;using (FullTextSqlQuery searchQuery = new FullTextSqlQuery(ServerContext.Current))
{
SPSite contextSite = SPControl.GetContextSite(HttpContext.Current);

searchQuery.SiteContext = new Uri(contextSite.Url);
searchQuery.StartRow = 1;

if (rowLimit > 0)
{
searchQuery.RowLimit = 500;
}

searchQuery.EnableStemming = true;
searchQuery.KeywordInclusion = KeywordInclusion.AllKeywords;
searchQuery.ResultTypes = ResultType.RelevantResults;
searchQuery.TrimDuplicates = true;
searchQuery.QueryText = SQLQueryString;

ResultTableCollection searchResultTableCollection = searchQuery.Execute();
if ((int)ResultType.RelevantResults != 0)
{
searchResultTable = searchResultTableCollection[ResultType.RelevantResults];
}
}

– Or more simple to query to All Sites Search Scope

var query = new FullTextSqlQuery(SPContext.Current.Site)
{
QueryText = “SELECT Title FROM SCOPE() WHERE \”scope\” = ‘All Sites’ AND  CONTAINS(Title, ‘Example’)”,
ResultTypes = ResultType.RelevantResults
};
var queryResults = query.Execute();
var queryResultsTable = queryResults[ResultType.RelevantResults];
var results = new DataTable();
results.Load(queryResultsTable, LoadOption.OverwriteChanges);

That’s all, You can manually control search result and freely customize SharePoint search with available powerful full text search. So cool!

Related article:

Hoang Nhut Nguyen
Email: nhutcmos@gmail.com
Skype: hoangnhut.nguyen

In last post Working with SharePoint Large List – Part 1, I just showed to you about how to get SharePoint data list by many ways:

– By Object Module with For/Each loop

– By SPQuery

– By DataTable

– By Web Services

– By Portal SiteMap Provider

And in this post, we will review the performance of each via tested result in the charts. It’s also compare Add and Delete Items between Indexed fields, No Indexed Fields and By ID field.

1. Add Item

2. Delete Item

3. Data Retrieval

Data Retrieval with under 1500 Items

*

Data Retreival around 100,000 Items

*

Retrieval Data with Indexed Column vs No Index

*

Data Retrieval By ID vs By Indexed Column

Related Article:
Hoang Nhut Nguyen
Email: nhutcmos@gmail.com
Skype: hoangnhut.nguyen

Microsoft performed performance testing against Microsoft® SharePoint® Server 2007 and 2010to determine the performance characteristics of large SharePoint lists under different loads and modes of operation.

The same is true for calendars, contacts, and other interfaces. They are all just customized versions of the basic SharePoint list, also referred to as an SPList. The individual items in the list are referred to as list items generally, or an SPListItem in an SPListItemCollection from the Office SharePoint Server 2007 object model.

Each test consisted of retrieving a subset of data from the list using one of a number of different data access methods.
The code samples included in the following sections are intended to show the process used to conduct tests. The code may not com

1. By For/Each loop

Object model (OM) was used to retrieve the list into an SPList object. Each item in the list was then enumerated with a For/Each loop until items were found that matched the search criteria.

//get the site 

SPSite curSite = New SPSite(http://myPortal&#8221;) ;

//get the web

SPWeb curWeb = curSite.OpenWeb();

//get our list

SPList curList = curWeb.Lists(New Guid(“myListGUID”));

//get the collection of items in the list

SPListItemCollection curItems = curList.Items;

//enumerate the items in the list

foreach(SPListItemcurItem in curItems )

/////do some comparison in here to see if it’s an item we need

 


2. By SPQuery

The OM was used to create an SPQuery object that contained the query criteria. That object was then used to against an instance of the list in a SPList object. The results of the query were returned by calling the GetItems method on the SPList object.

//get the site 

SPSite curSite = New SPSite(http://myPortal&#8221;);

//get the web

SPWeb curWeb = curSite.OpenWeb();

//create our query

SPQuery curQry = New SPQuery();

//configure the query

curQry.Query = “<Where><Eq><FieldRef Name=’Expense_x0020_Category’/><Value Type=’Text’>

Hotel</Value></Eq></Where>”;

curQry.RowLimit = 100;

//get our list

SPList curList = curWeb.Lists(New Guid(“myListGUID”));

//get the collection of items in the list

SPListItemCollection curItems = curList.GetItems(curQry);

//enumerate the items in the list

foreach (curItem SPListItem in curItems)

/////do something with each match

 


3. By DataTable

This is one of two methods that test using a Microsoft ADO.NET DataTable to work with the data. In this case an instance of the list is obtained with an SPList object. The data from it is then retrieved into a DataTable by calling the GetDataTable() method on the Items property —for example, SPList.Items.GetDataTable(). The DataTable’s DefaultView has a property called RowFilter that was then set to find the items. To keep the methodology between data access methods consistent.

//get the siteSPSite curSite = New SPSite(http://myPortal&#8221;);

//get the web

SPWeb curWeb = curSite.OpenWeb();

//get our list

SPList curList = curWeb.Lists(New Guid(“myListGUID”));

//get the item in a datatable

DataTable dt = curList.Items.GetDataTable();

//get a dataview for filtering

DataView dv = dt.DefaultView;

dv.RowFilter = “Expense_x0020_Category=’Hotel'”;

//enumerate matches

for (int rowNum = 0; i<=dv.Count – 1; i ++)

////do something with each match

 


4. By Web Service

The Lists Web service was used to retrieve the data. A Collaborative Application Markup Language (CAML) query was created and submitted along with the list identifier, and an XML result set was returned from the Lists Web service

//create a new xml doc we can use to create query nodesXmlDocument xDoc = New XmlDocument();

//create our query node

XmlNode xQry = xDoc.CreateNode(XmlNodeType.Element, “Query”, “”) ;

//set the query constraints

xQry.InnerXml = “<Where><Eq><FieldRef Name=’Expense_x0020_Category’/><Value Type=’Text’>Hotel</Value></Eq></Where>”;

//create the Web service proxy that is mapped to Lists.asmx

using (ws = wsLists.Lists())

{

//configure it

ws.Credentials = System.Net.CredentialCache.DefaultCredentials;

ws.Url = http://myPortal/_vti_bin/lists.asmx&#8221;;

//create the optional elements

XmlNode xView = xDoc.CreateNode(XmlNodeType.Element, “ViewFields”, “”);

XmlNode xQryOpt = xDoc.CreateNode(XmlNodeType.Element, “QueryOptions”, “”);

//query the server

XmlNode xNode = ws.GetListItems(“myListID”, “”, xQry, xView, “”, xQryOpt, “”);

//enumerate returned items

for ( int nodeCount = 0; i<=xNode.ChildNodes.Count – 1; i++)

/////do something with each match

}

 


4. By Portal SiteMap Provider

One approach to retrieving list data in Office SharePoint Server 2007 that’s not very well known is the use of the PortalSiteMapProvider class. It was originally created to help cache content for navigation. However, it also provides a nice automatic caching infrastructure for retrieving list data. The class includes a method called GetCachedListItemsByQuery that was used in this test. This method first retrieves data from a list based on an SPQuery object that is provided as a parameter to the method call. The method then looks in its cache to see if the items already exist. If they do, the method returns the cached results, and if not, it queries the list, stores the results in cache and returns them from the method call.
The following sample code was used for this method. Note that it is different from all of the previous examples in that you cannot use the PortalSiteMapProvider class in Windows forms applications.

//get the current webSPWeb curWeb = SPControl.GetContextWeb(HttpContext.Current)

//create the query

Dim curQry AsNew SPQuery()

curQry.Query = “<Where><Eq><FieldRef Name=’Expense_x0020_Category’/><Value Type=’Text’>Hotel</Value></Eq></Where>”;

//get the portal map provider stuff

PortalSiteMapProvider ps = PortalSiteMapProvider.WebSiteMapProvider

PortalWebSiteMapNode pNode = TryCast(ps.FindSiteMapNode(curWeb.ServerRelativeUrl), PortalWebSiteMapNode);

//get the items

pItems = ps.GetCachedListItemsByQuery(pNode, “myListName_NotID”, curQry, curWeb);

//enumerate all matches

foreach (PortalListItemSiteMapNodepItem in pItems)

/////do something with each match

 


Related Article:
Hoang Nhut Nguyen
Email: nhutcmos@gmail.com
Skype: hoangnhut.nguyen
%d bloggers like this: