How to make a connection to a database using DropDownList - c#

So I want to have a DDL (SELECT name FROM sys.databases (nolock)) that returns a value once selected (displayed in gridview possibly).
The problem that I have is that the query needs to make a connection to different databases depending on what the user selects from the DDL and return a value that is displayed in gridview. I want something like the below query:
How could I accomplish this?
use ([name]=#name) select sum(t.table1.column1) as Total from database inner join database2 on db1.table1.id= ([name]=#name).table2.id where([appname]=#appname) and Date <= GetDate()AND YEAR(Date) = year(GetDate())
I got this so far (not sure if this is the best method.) This is my code behind, how do I display the result using gridview that is dependent on DDL?
protected void DropDownList2_SelectedIndexChanged(object sender, EventArgs e)
{
{
if (DropDownList2.SelectedValue == "test1")
{
SqlDataSource3.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["test1ConnectionString"].ConnectionString;
{
SqlDataSource3.SelectCommandType = SqlDataSourceCommandType.Text;
SqlDataSource3.SelectCommand = "select top 10 * from table1 (nolock)";
}
}
else if (DropDownList2.SelectedValue == "test2")
{
SqlDataSource4.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["test2ConnectionString"].ConnectionString;
{
SqlDataSource4.SelectCommandType = SqlDataSourceCommandType.Text;
SqlDataSource4.SelectCommand = "select top 1 * from table1 (nolock)";
}
}
And below is my aspx code for the DDL.
<asp:DropDownList ID="DropDownList2" runat="server" AutoPostBack="True" OnSelectedIndexChanged="DropDownList2_SelectedIndexChanged">
<asp:ListItem>test1</asp:ListItem>
<asp:ListItem>test2</asp:ListItem>
</asp:DropDownList>

From what I understand you want to run different SQL when a user selects an item from the DropDownList. Anyway, you should put your code in the SelectedIndexChanged event of the control. As an example, your markup might look something like this:
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True"
onselectedindexchanged="DropDownList1_SelectedIndexChanged">
</asp:DropDownList>
And in your code-behind:
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
// call your sql
}
Edit
I've included a links to get your started. They show some code with the SelectedIndexChanged event.
http://www.devasp.net/net/articles/display/1294.html
http://www.c-sharpcorner.com/UploadFile/092589/working-with-dropdownlist-slectedindexchanged-event/

Related

dealing with GridView and Custom Validation, both client and serverside

I'm not quite sure how to solve this problem.
What I'm trying to do:
Go through a gridview with multiple rows, and force the user to enter in specific values if certain textboxes or drop down lists are left on the default value.
What I tried:
Tried client side requirements, by use of the focusout event in javascript. Focus goes onto these fields depending on the previous selections users make, that part works. My code:
var row = $(this).closest('tr');
var text = $(row).find("input[name*='txtCurriculum']").val('enter lesson/unit name here');
var ddl = $(row).find("select[name*='ddlCurrAdditions']");
$(ddl).focusout(function () {
if (ddl.val == "-select curriculum name-") {
$(ddl).focus();
alert("select a curriculum name before moving on");
}
});
$(text).focusout(function () {
if (text.val == 'enter lesson/unit name here') {
$(text).focus();
alert('enter in a lesson or unit name before moving on');
}
});
It never fired properly. the ddl focusout would fire, but wouldn't stop firing until I exited and went back to the page. the text focusout would never fire.
Tried server side validation, with the custom validation feature.
protected void cv1_ServerValidate(object source, ServerValidateEventArgs args)
{
CustomValidator cv = ((CustomValidator)(source));
GridViewRow gvr;
//if (FormCGrid.Rows)
foreach (GridViewRow row in FormCGrid.Rows)
{
//string ddl = ((DropDownList)row.FindControl("ddlCurrAdditions")).SelectedItem.Text;
string txtC = ((TextBox)row.FindControl("txtCurriculum")).Text;
bool ddl = ((DropDownList)row.FindControl("ddlCurrAdditions")).Visible;
if (txtC == "enter lesson/unit name here")
{
args.IsValid = false;
cv.ErrorMessage = string.Format("Please enter the Additional program name on row {0}", row.RowIndex);
}
else if (ddl == true)
{
cv.ErrorMessage = string.Format("Enter your lesson or unit for the curriculum selected on row {0}", row.RowIndex);
args.IsValid = false;
}
}
}
I tried to loop through the rows of the gridview here, checking the named dropdown for visibility (hidden until another dropdownlist reveals it, dependent on the value chosen there) and the textbox for the default value, yet this did not work either. It never fired at all. Any suggestions welcome.
I am generally ok with most programming/coding issues, but I find that working with the asp.net gridview, all of my techniques get thrown out the window.
Ok, there are two ways to do this, and you can use js quite easy here. However, lets go with a 100% server side code. I think sticking to server side code is easier.
Next up? I actually STONG suggest to use a listview in place of a gridview WHEN you plan to edit data. The reason is simple - the ListView does not require those "irratating" "item template" over and over for each asp.net control you want to drop/have in that grid display. Now to be fair, say 2-3 controls - then grid view is ok, but for more, then I really find that the listview starts to win here big time (no need for the item template).
The "trick" with listview is of course to setup a datasoruce on the web page, let it generate the markup, and then blow out (delete) all templates except for the item template. And then delete the datasourc1 item on the page, and remove the datasource1 setting from the list view.
However, lets go with the grid view - this will thus be some what "more messy"
So, we going to fill out the grid - and say we want a city combo box - MUST be selected. And lets toss in a basic check for say LastName also must be entered.
So, we have a city combo box (database driven). And say lets toss in a drop down for a hotel rating (1-5) - but that's only 5 choices - so we have that dropdown with the list in mark-up. (so two combo examples to show how this works).
So, say we have a grid like this, and we hit save, we get this result:
Now, of course we would fancy up that message box area. And in fact, we could VERY easy drop in jQuery.UI and make that cute div on the right appear in a dialog box (and we can trigger that box + jQuery.UI dialog display even from our server side code behind - but lets try and keep this short - but I would fancy up that error message area).
Ok, first the markup:
Just a simple grid, but "a bit messy" due to those "item Templates - (if you not figured this out, I really dislike those template things!!! - and with listview you don't need them!! - just drop in pure clean asp.net controls for the grid). Anyway:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID">
<Columns>
<asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
<asp:TemplateField HeaderText="HotelName" >
<ItemTemplate><asp:TextBox id="HotelName" runat="server" Text='<%# Eval("HotelName") %>' /></ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="FirstName" >
<ItemTemplate><asp:TextBox id="FirstName" runat="server" Text='<%# Eval("FirstName") %>' /></ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="LastName" >
<ItemTemplate><asp:TextBox id="LastName" runat="server" Text='<%# Eval("LastName") %>' /></ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="City">
<ItemTemplate>
<asp:DropDownList ID="cboCity" runat="server" DataTextField="City"
DataValueField = "City" Width="110px">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Active">
<ItemTemplate><asp:CheckBox id="Active" runat="server" Checked = '<%# Eval("Active") %>' /></ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Rating">
<ItemTemplate>
<asp:DropDownList ID="cboRating" runat="server" SelectedValue = '<%# Eval("Rating") %>' >
<asp:ListItem Value="1">Poor</asp:ListItem>
<asp:ListItem Value="2">Just Ok</asp:ListItem>
<asp:ListItem Value="3">Ok</asp:ListItem>
<asp:ListItem Value="4">Good</asp:ListItem>
<asp:ListItem Value="5">Excellent</asp:ListItem>
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
<div id="ErrorDialog" style="display:normal;float:left;padding-left:30px;width:20%" runat="server">
<asp:TextBox ID="txtErrors" runat="server" TextMode="MultiLine" Style="width:100%" Rows="20" ></asp:TextBox>
</div>
<div style="clear:both;padding-top:20px">
<asp:Button ID="cmdSave" runat="server" Text="Save" />
<asp:Button ID="cmdUnDo" runat="server" Text="UnDo" Style="margin-left:20px"/>
</div>
Ok, now on SO? Gee, that is about the total max markup I would post in one shot - beyond above, we approach the "not very nice" post territory.
Ok, so lets look at the code to load up this grid. We have this code:
public class EditHotelsG : System.Web.UI.Page
{
private DataTable rstTable = new DataTable();
private DataTable rstCity = new DataTable();
protected void Page_Load(object sender, System.EventArgs e)
{
if (System.Web.UI.Page.IsPostBack == false)
{
ErrorDialog.Visible = false;
LoadGrid();
ViewState["rstTable"] = rstTable;
ViewState["rstCity"] = rstCity;
}
else
{
rstTable = ViewState["rstTable"];
rstCity = ViewState["rstCity"];
}
}
public void LoadGrid()
{
// load up our drop down list from database (city)
string strSQL;
strSQL = "SELECT City from tblCity Order by City";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, new SqlConnection(My.Settings.TEST3)))
{
cmdSQL.Connection.Open();
rstCity.Load(cmdSQL.ExecuteReader);
// now load up main grid view
strSQL = "SELECT ID, FirstName, LastName, HotelName, City, Active, Rating from tblHotels ORDER BY HotelName";
cmdSQL.CommandText = strSQL;
rstTable.Load(cmdSQL.ExecuteReader);
GridView1.DataSource = rstTable;
GridView1.DataBind();
}
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
// set combo box data source
if (e.Row.RowType == DataControlRowType.DataRow)
{
// setup city drop down list
DropDownList cboDrop = e.Row.FindControl("cboCity");
cboDrop.DataSource = rstCity;
cboDrop.DataBind();
cboDrop.Items.Insert(0, new ListItem(string.Empty)); // add blank row
cboDrop.Text = rstTable.Rows(e.Row.RowIndex).Item("City").ToString;
}
}
}
Ok, now that is not all that much code. And a good part was setting up that combo box. Since the cbo box (dropdown list) was database driven, then we have to bind + setup for each row. So, that cost us a good chunk of our coding time.
Note however how we persist the database soruce (table). We do that, since we want to with A LOT LESS code, update the whole database behind in ONE shot. By peristing that table, then we
Transfer data from Grid to table
Save the table to database in one shot
So, this reduces our coding efforts by a truckload.
The code to save our data, thus becomes this gem:
(and note how we ALSO put in our validation code).
protected void cmdSave_Click(object sender, EventArgs e)
{
// pull gride rows back to table.
bool bolDataOk = true;
txtErrors.Text = "";
foreach (GridViewRow rRow in GridView1.Rows)
{
int RecordPtr = rRow.RowIndex;
DataRow OneDataRow;
OneDataRow = rstTable.Rows(RecordPtr);
OneDataRow.Item("HotelName") = rRow.FindControl("HotelName") as TextBox.Text;
OneDataRow.Item("FirstName") = rRow.FindControl("FirstName") as TextBox.Text;
OneDataRow.Item("LastName") = rRow.FindControl("LastName") as TextBox.Text;
OneDataRow.Item("City") = rRow.FindControl("cboCity") as DropDownList.Text;
OneDataRow.Item("Active") = rRow.FindControl("Active") as CheckBox.Checked;
OneDataRow.Item("Rating") = rRow.FindControl("cboRating") as DropDownList.SelectedValue;
// check for missing City, or LastName
if (IsDBNull(OneDataRow("City")) | OneDataRow("City") == "")
{
bolDataOk = false;
if (txtErrors.Text != "")
txtErrors.Text += Constants.vbCrLf;
txtErrors.Text += "Missing City on row = " + (rRow.RowIndex + 1).ToString;
}
if (IsDBNull(OneDataRow("LastName")) | OneDataRow("LastName") == "")
{
bolDataOk = false;
if (txtErrors.Text != "")
txtErrors.Text += Constants.vbCrLf;
txtErrors.Text += "Missing lastName on row = " + (rRow.RowIndex + 1).ToString;
}
}
ErrorDialog.Visible = !(bolDataOk);
// now send table back to database with updates
if (bolDataOk)
{
string strSQL = "SELECT ID, FirstName, LastName, City, HotelName, Active, Rating from tblHotels WHERE ID = 0";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, new SqlConnection(My.Settings.TEST3)))
{
cmdSQL.Connection.Open();
SqlDataAdapter daupdate = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder cmdBuild = new SqlCommandBuilder(daupdate);
daupdate.Update(rstTable);
}
}
}
Now, once again, that above code snip is a wee bit long - and is aobut the max size of a code snip for SO. I would perhaps consider breaking out that above last code into 2 or even 3 routines.
but, all in all, the above shows quite a few tricks, and approaches here.
As noted, I was going to post how you can/could verify using client side code, ,but the OVER ALL idea of saving back the whole grid with one database update? Well, I would use that trick with a listview, gridview, and even if I was doing client side js verification? I will still use the bulk of the above design pattern.
And the un-do button? Well, I never finished that part - but it would just call the same code as the first page load (postback - false, and you would simply re-bind the grid from the database source for the un-do button.

Reverting ASP SQL DataSource Select statement

If the Select statement has been specified on the .aspx page, and then later altered in the code-behind, based on some event-driven logic, is there a way to revert the select statement to what is originally on the .aspx page?
The ASP code:
<asp:SqlDataSource ID="ds_Users" runat="server" ConnectionString="<%$ ConnectionStrings:DefaultConnection %>"
SelectCommand="SELECT * FROM [Users]" >
</asp:SqlDataSource>
In the codebehind:
ds_Users.SelectStatement += " WHERE [UserType] LIKE '" + LocalVariable + "'";
Let's assume the above event was bound to a filter combobox that has the UserTypes as items.
If there's a "View All" option included in that list, how would I revert the SelectStatement to the original query without storing the Select statement (SELECT * FROM [Users]) as another string in the code-behind. Is that even possible?
You have to always fix the SQL Select Command, on every page load, or on post back. You do bind ones, and then again only if you click on a button that change the SQL command.
Here is an example, please note gvMyLista is the GridView that use the data.
protected void Page_Load(object sender, EventArgs e)
{
FixTheSelectCommand();
}
void FixTheSelectCommand()
{
// this is an example - make your test here to know if there is a valid variable
if(LocalVariable != null)
ds_Users.SelectCommand = "SELECT * FROM [Users] WHERE [UserType] LIKE '" + LocalVariable + "'";
else
ds_Users.SelectCommand = "SELECT * FROM [Users]";
if (!IsPostBack)
gvMyLista.DataBind();
}
// when a search button clicked that change the search text
protected void btnSearchFor_Click(object sender, System.EventArgs e)
{
gvMyLista.DataBind();
}

Add "Please Select" to Drop-down list that retrieves values from Data base

I have a drop-down list and uses the SQL data source for it where I am retrieving the product names from SQL server. Now, I want to add "Please Select a product" Option to the drop-down list.
As far as my knowledge, I add options to drop-down list by using
<asp:ListItem Selected ="true" Value = "1">1</asp:ListItem>
Since, I am not adding the values but retrieving the values from DB, how to achieve this Option additionally and add to it as first position to my drop-down list?
I tried the below code, but not able to do get at first position.Also, each time I am getting extra "please select" option whenever I am selecting other values.
protected void NameDropDownList_SelectedIndexChanged(object sender, EventArgs e)
{
NameDropDownList.Items.Insert(0, new ListItem("Please Select a product", "Please Select a product");
SqlCommand cmd = new SqlCommand("SELECT ProductID, Price, Description, Rating FROM Product_Info Where Name = '" + NameDropDownList.Text + "'", conn);
SqlDataReader myReader;
conn.Open();
myReader = cmd.ExecuteReader();
while (myReader.Read()) {
//Logic
}
conn.Close();
myReader.Close();
Here is my code behind where I bind the data:
<tr>
<td class="style2">Name</td>
<td>
<asp:DropDownList ID="NameDropDownList" runat="server" Height="16px"
Width="130px" AutoPostBack="True" DataSourceID="NameSqlDataSource"
DataTextField="Name" DataValueField="Name"
onselectedindexchanged="NameDropDownList_SelectedIndexChanged">
</asp:DropDownList>
<asp:SqlDataSource ID="NameSqlDataSource" runat="server"
ConnectionString="<%$ ConnectionStrings:ProductsConnectionString %>"
SelectCommand="SELECT [Name] FROM [Product_Info]"></asp:SqlDataSource>
</td>
</tr>
I also enables the Auto post back to true.Thanks in advance
Thanks for your responses. I figured out the actual problem and able to done it in simple step.
First, I make the AppendDataBoundItems behavior of my drop-down list To TRUE and kept the following code and it works perfectly.
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
NameDropDownList.Items.Insert(0, new ListItem("Please Select a Product", "Please Select a Product"));
}
}
Move this line NameDropDownList.Items.Insert(0, new ListItem("Please Select a product", "Please Select a product");
t osomewhere after you bind your data, what is happening is that you insert this, then you bind over the top of it.
The problem here is that you're using asp:SqlDataSource. You need to query and bind your data from the code because you want to manipulate it.
Here is the sample logic.
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
// 1- Query into a list
// 2- Add your custom item at the 1st position
// 3- Set the DataSource of your list
// 4- Make sure you bind your fields (text and value)
}
}
I'll let you try the different steps above, but let me know if you have any trouble.

Is it possible to programmatically input values in TextBox control before UpdateCommand runs

(C# asp.net 3.5) I have successfully pre-populated CheckBoxList3 in RowDataBound event. In edit mode, user may then make other checkbox selections. I have successfully captured the new values, creating a new comma-delimited string that updates SQL in _RowUpdating event after Update link is clicked. The problem is my update is being overriden by the GridView1s update. *The new string is not physically input by user in the TextBox2 control.
It seems I have two choices:
Pass the comma-delimited string built from checkboxlist3 selections
to TextBox2 control programmatically before UpdateCommand is run. P*Is this possible?* I've
googled everywhere with no clearcut solutions. I've also tried this code in RowUpdating and it makes to difference:
TextBox tb2 = (TextBox)GridView1.Rows[e.RowIndex].Cells[1].FindControl("TextBox2");
tb2.Text = strCheckBoxList3.Substring(0, strCheckBoxList3.Length - 2);
Update sql manually like I'm doing only place Sql call AFTER the "natural" update (for lack of
better words). If this is an option, what method to run the update in because placing it in RowUpdating always gets reversed.
HTML:
<asp:TemplateField HeaderText="Endorsements" SortExpression="Endorsements">
<ItemTemplate>
<asp:Label ID="Label2" runat="server" Text='<%# Bind("Endorsements") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="TextBox2" runat="server" Text='<%# Bind("Endorsements") %>'></asp:TextBox>
<asp:CheckBoxList ID="CheckBoxList3" runat="server" Font-Size="Small" RepeatDirection="Horizontal" onselectedindexchanged="CheckBoxList3_SelectedIndexChanged"
AutoPostBack="True" >
<asp:ListItem Value="H">H</asp:ListItem>
<asp:ListItem Value="I">I</asp:ListItem>
<asp:ListItem Value="K">K</asp:ListItem>
<asp:ListItem Value="N">N</asp:ListItem>
<asp:ListItem Value="T">T</asp:ListItem>
<asp:ListItem Value="X">X</asp:ListItem>
</asp:CheckBoxList>
</EditItemTemplate>
</asp:TemplateField>
C#
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
//endorsements string
string strCheckBoxList3 = String.Empty;
//find endorsements checkboxlist in gridview.
CheckBoxList cbl3 = (CheckBoxList)GridView1.Rows[e.RowIndex].Cells[1].FindControl("CheckBoxList3");
try
{
// Build Endorsements string
if (cbl3 != null)
{
// determine which checkboxes have been checked
foreach (ListItem item in cbl3.Items)
{
// is item checked?
if (item.Selected == true)
{
// build string
strCheckBoxList3 += (item.Value + ", ");
}//end of if
}// end of foreach
// Save the value in ViewState object before the PostBack
ViewState["vsEndorsementsString"] = strCheckBoxList3;
}// end of if
}// end of endorsements try
catch (ArgumentOutOfRangeException ez)
{
System.Diagnostics.Debug.WriteLine(ez.Message + "; " + ez.Source + "; " + ez.TargetSite);
}
//Note: routine to update SQL was removed here
}
// New: pass strings to sql Update Command Parameters for two checkboxlist columns in gridview
protected void sdsMySqlDataSource_Updating(object sender, SqlDataSourceCommandEventArgs e)
{
string getViewStateEndorsementsString = ViewState["vsEndorsementsString"].ToString();
string getViewStateRestrictionsString = ViewState["vsRestrictionsString"].ToString();
foreach (System.Data.Common.DbParameter p in e.Command.Parameters)
{
if (p.ParameterName == "#Endorsements" && p.Value != null)
{
//Assign #Endorsements parameter
e.Command.Parameters["#Endorsements"].Value = getViewStateEndorsementsString.ToString();
}//if
if (p.ParameterName == "#Restrictions" && p.Value != null)
{
//Assign #Restrictions parameter
e.Command.Parameters["#Restrictions"].Value = getViewStateRestrictionsString.ToString();
}//if
}
}
The solution is to pass new values to Update Command Parameters in SqlDataSource _Updating event. Relevent updated code provided above.
I removed the SQL update routine that I had in _RowUpdating event entirely - it isn't needed. Then I saved the newly created comma-delimited string to ViewState object which I retrieve in SqlDataSource _Updating event.
Credit for me coming to this conclusion goes to leoinlios because of his post here: changing textbox value in code behind does not post back new value Plus I did a lot of reading about View State and found this to be the most useful article: TRULY Understanding ViewState

Databound FormView with DropDownList Questions

I am trying to achieve the following:
Eliminate the FormView’s default edit link button.
Display the FormView in edit mode on Page_Load with current data and additional DDL data selections.
Currently I have the following to bind the DDL to the current database value based upon id = x etc:
<asp:DropDownList ID="DropDownList1" runat="server"
SelectedValue='<%# Bind("xxx") %>'
DataSourceID="xxx"
DataTextField="xxx"
DataValueField="xxx"
ondatabound="DropDownList1_DataBound">
Via C# code I do this to add additional DDL list items for selection: (which is a waste of my energy because the data is already in the database!)
protected void DropDownList1 _DataBound(object sender, EventArgs e)
{
DropDownList DropDownList1 = (DropDownList)FormView1.FindControl("DropDownList1");
DropDownList1.Items.Insert(1, new ListItem("0 - 1 km/h", "0"));
DropDownList1.Items.Insert(2, new ListItem("2 - 5 km/h", "1"));
DropDownList1.Items.Insert(3, new ListItem("6 - 11 km/h", "2"));
DropDownList1.Items.Insert(4, new ListItem("12 - 19 km/h", "3"));
DropDownList1.Items.Insert(5, new ListItem("20 - 28 km/h", "4"));
}
There has got to be a better way!
Dont know exactly how you are connecting to the database but if you are using datacontext linq to sql is a good way to do it. Your 'ddl' will have an onLoad event and you can use a query in the code behind. For example:
<asp:DropDownList ID="DropDownList1" runat="server"
onLoad="DropDownList1_Load"
AutoPostBack="true" />
And then in the code behind:
protected void DropDownList1_Load(object sender, EventARgs e)
{
YourDataContext db = new YourDataContext();
var qry = from a in db.table1
select a;
foreach(var itm in qry)
{
DropDownList1.Items.Add(new ListItem(itm.speedRange.ToString(), itm.id.ToString()));
db.Dispose();
}

Categories

Resources