472,793 Members | 2,275 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,793 software developers and data experts.

Creating user in active directory

Friends,

Can anybody help me out by sending a piece of C# code showing how to add an
active directory user to a particular user group? If the group does not
exist, then create it.

Thanks in advance
-Hari
Nov 16 '05 #1
2 6540
hi Hari
Here you are code to create user

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.DirectoryServices;
using System.Reflection;

namespace PowerAD
{
public class createUserForm : System.Windows.Forms.Form
{
//Declaration des variables.
private System.Windows.Forms.TextBox firstNameBox;
private System.Windows.Forms.TextBox lastNameBox;
private System.Windows.Forms.TextBox aliasBox;
private System.Windows.Forms.Label instructionLabel;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Button createButton;
private System.Windows.Forms.Button cancelButton;
private System.ComponentModel.Container components = null;
public navForm currentForm;

// CONSTRUCTEUR DU FORM

public createUserForm(navForm remoteForm)
{
InitializeComponent();
//<CG ADD> DTE:16/10/2003
this.Text = App.ResourceM.GetString("createuser_title");
this.cancelButton.Text = App.ResourceM.GetString("gen_cancel");
this.createButton.Text = App.ResourceM.GetString("gen_create");
this.label3.Text = App.ResourceM.GetString("createuser_detailname");
this.label2.Text = App.ResourceM.GetString("createuser_lastname");
this.label1.Text = App.ResourceM.GetString("createuser_firstname");
this.instructionLabel.Text = App.ResourceM.GetString("createuser_lbl");
//</CG>
createButton.Enabled = false;
currentForm = remoteForm;
}

protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Méthode requise pour la prise en charge du concepteur - ne modifiez
pas
/// le contenu de cette méthode avec l'éditeur de code.
/// </summary>
private void InitializeComponent()
{
System.Resources.ResourceManager resources = new
System.Resources.ResourceManager(typeof(createUser Form));
this.firstNameBox = new System.Windows.Forms.TextBox();
this.lastNameBox = new System.Windows.Forms.TextBox();
this.aliasBox = new System.Windows.Forms.TextBox();
this.instructionLabel = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.createButton = new System.Windows.Forms.Button();
this.cancelButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// firstNameBox
//
this.firstNameBox.Location = new System.Drawing.Point(152, 40);
this.firstNameBox.Name = "firstNameBox";
this.firstNameBox.Size = new System.Drawing.Size(152, 20);
this.firstNameBox.TabIndex = 0;
this.firstNameBox.Text = "";
//
// lastNameBox
//
this.lastNameBox.Location = new System.Drawing.Point(152, 72);
this.lastNameBox.Name = "lastNameBox";
this.lastNameBox.Size = new System.Drawing.Size(152, 20);
this.lastNameBox.TabIndex = 1;
this.lastNameBox.Text = "";
//
// aliasBox
//
this.aliasBox.Location = new System.Drawing.Point(152, 104);
this.aliasBox.Name = "aliasBox";
this.aliasBox.Size = new System.Drawing.Size(152, 20);
this.aliasBox.TabIndex = 2;
this.aliasBox.Text = "";
this.aliasBox.TextChanged += new System.EventHandler(this.checkBoxes);
//
// instructionLabel
//
this.instructionLabel.Location = new System.Drawing.Point(16, 12);
this.instructionLabel.Name = "instructionLabel";
this.instructionLabel.Size = new System.Drawing.Size(232, 16);
this.instructionLabel.TabIndex = 5;
//
// label1
//
this.label1.Location = new System.Drawing.Point(8, 44);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(140, 16);
this.label1.TabIndex = 6;
//
// label2
//
this.label2.Location = new System.Drawing.Point(8, 76);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(140, 16);
this.label2.TabIndex = 7;
//
// label3
//
this.label3.Location = new System.Drawing.Point(8, 108);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(140, 16);
this.label3.TabIndex = 8;
//
// createButton
//
// this.createButton.BackgroundImage =
(System.Drawing.Image)App.ResourceG.GetObject("But tonImg");
this.createButton.Location = new System.Drawing.Point(48, 148);
this.createButton.Name = "createButton";
this.createButton.Size = new System.Drawing.Size(96, 24);
this.createButton.TabIndex = 11;
this.createButton.Click += new
System.EventHandler(this.createButton_Click);
//
// cancelButton
//
// this.cancelButton.BackgroundImage =
(System.Drawing.Image)App.ResourceG.GetObject("But tonImg");
this.cancelButton.DialogResult =
System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Location = new System.Drawing.Point(160, 148);
this.cancelButton.Name = "cancelButton";
this.cancelButton.Size = new System.Drawing.Size(104, 24);
this.cancelButton.TabIndex = 12;
this.cancelButton.Click += new
System.EventHandler(this.cancelButton_Click);
//
// createUserForm
//
this.AcceptButton = this.createButton;
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.CancelButton = this.cancelButton;
this.ClientSize = new System.Drawing.Size(316, 194);
this.Controls.Add(this.cancelButton);
this.Controls.Add(this.createButton);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.instructionLabel);
this.Controls.Add(this.aliasBox);
this.Controls.Add(this.lastNameBox);
this.Controls.Add(this.firstNameBox);
this.FormBorderStyle =
System.Windows.Forms.FormBorderStyle.FixedToolWind ow;
this.Name = "createUserForm";
this.Load += new System.EventHandler(this.createUserForm_Load);
this.ResumeLayout(false);

}
#endregion

// Cette fonction active ou desactive le bouton create en fonction qu'il y
ait du texte ou non dans
// la textbox du nom.

private void checkBoxes(object sender, System.EventArgs e)
{
if (aliasBox.Text.ToString().Length > 0)
createButton.Enabled = true;
else
createButton.Enabled = false;
}

// Cette fonction cree l'utilisateur, raffraichiet l'affichage du
container, puis lance le dialogue
// de creation du mot de passe.

private void createButton_Click(object sender, System.EventArgs e)
{
try
{
DirectoryEntry user =
currentForm.currentObjectInView.Children.Add("cn=" + aliasBox.Text, "user");
user.Properties["sAMAccountName"].Add(aliasBox.Text);
if (firstNameBox.Text.ToString().Length != 0)
user.Properties["givenName"].Add(firstNameBox.Text);
if (lastNameBox.Text.ToString().Length != 0)
user.Properties["sn"].Add(lastNameBox.Text);
user.CommitChanges();
currentForm.ShowView(currentForm.currentObjectInVi ew);
setPasswordForm setPassword = new setPasswordForm(user);
setPassword.ShowDialog();
this.Close();
}
catch (Exception ex)
{
if (ex.InnerException != null)
MessageBox.Show(ex.InnerException.ToString().Split (':')[1]);
else
MessageBox.Show(ex.Message.ToString());
}
}

private void cancelButton_Click(object sender, System.EventArgs e)
{
this.Close();
}

private void createUserForm_Load(object sender, System.EventArgs e)
{

}
}
}

And here you are code to create group

sing System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.DirectoryServices;

namespace PowerAD
{
public class createGroupForm : System.Windows.Forms.Form
{
//Creation des variables
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox groupNameTextBox;
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.Button cancelButton;
private System.ComponentModel.Container components = null;
private System.Windows.Forms.GroupBox typeGroup;
private System.Windows.Forms.RadioButton distributionRadioBox;
private System.Windows.Forms.RadioButton securityRadioBox;
private System.Windows.Forms.GroupBox etendueGroup;
private System.Windows.Forms.RadioButton universalRadioBox;
private System.Windows.Forms.RadioButton globalRadioBox;
private System.Windows.Forms.RadioButton localRadioBox;
private navForm currentForm;

//Creation des flags
private const uint ADS_GROUP_TYPE_GLOBAL_GROUP = 0x00000002;
private const uint ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP = 0x00000004;
private const uint ADS_GROUP_TYPE_LOCAL_GROUP = 0x00000004;
private const uint ADS_GROUP_TYPE_UNIVERSAL_GROUP = 0x00000008;
private const uint ADS_GROUP_TYPE_SECURITY_ENABLED = 0x80000000;

// CONSTRUCTEUR DU FORM

// Dans le constructeur on initialise les checkboxes avec les valeurs par
defaut.

public createGroupForm(navForm remoteForm)
{
InitializeComponent();
Trad();
globalRadioBox.Checked = true;
securityRadioBox.Checked = true;
currentForm = remoteForm;
}

protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Méthode requise pour la prise en charge du concepteur - ne modifiez
pas
/// le contenu de cette méthode avec l'éditeur de code.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.groupNameTextBox = new System.Windows.Forms.TextBox();
this.okButton = new System.Windows.Forms.Button();
this.cancelButton = new System.Windows.Forms.Button();
this.typeGroup = new System.Windows.Forms.GroupBox();
this.distributionRadioBox = new System.Windows.Forms.RadioButton();
this.securityRadioBox = new System.Windows.Forms.RadioButton();
this.etendueGroup = new System.Windows.Forms.GroupBox();
this.universalRadioBox = new System.Windows.Forms.RadioButton();
this.globalRadioBox = new System.Windows.Forms.RadioButton();
this.localRadioBox = new System.Windows.Forms.RadioButton();
this.typeGroup.SuspendLayout();
this.etendueGroup.SuspendLayout();
this.SuspendLayout();
//
// label1
//
this.label1.Location = new System.Drawing.Point(16, 16);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(184, 16);
this.label1.TabIndex = 0;
//<CG DEL> DTE:16/10/2003 RAISON : MOVED TO CONSTRUCTOR
//this.label1.Text = "Entrez le nom du groupe :";
//</CG>
//
// groupNameTextBox
//
this.groupNameTextBox.Location = new System.Drawing.Point(8, 40);
this.groupNameTextBox.Name = "groupNameTextBox";
this.groupNameTextBox.Size = new System.Drawing.Size(272, 20);
this.groupNameTextBox.TabIndex = 1;
this.groupNameTextBox.Text = "";
this.groupNameTextBox.TextChanged += new
System.EventHandler(this.groupNameTextBox_TextChan ged);
//
// okButton
//
// this.okButton.BackgroundImage =
(System.Drawing.Image)App.ResourceG.GetObject("But tonImg");
this.okButton.Enabled = false;
this.okButton.Location = new System.Drawing.Point(104, 200);
this.okButton.Name = "okButton";
this.okButton.Size = new System.Drawing.Size(80, 24);
this.okButton.TabIndex = 2;
//<CG DEL> DTE:16/10/2003 RAISON : MOVED TO CONSTRUCTOR
//this.okButton.Text = "Creer";
//</CG>
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// cancelButton
//
// this.cancelButton.BackgroundImage =
(System.Drawing.Image)App.ResourceG.GetObject("But tonImg");
this.cancelButton.DialogResult =
System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Location = new System.Drawing.Point(200, 200);
this.cancelButton.Name = "cancelButton";
this.cancelButton.Size = new System.Drawing.Size(72, 24);
this.cancelButton.TabIndex = 3;
//<CG DEL> DTE:16/10/2003 RAISON : MOVED TO CONSTRUCTOR
//this.cancelButton.Text = "Annuler";
//</CG>
//
// typeGroup
//
this.typeGroup.Controls.AddRange(new System.Windows.Forms.Control[] {
this.distributionRadioBox,
this.securityRadioBox});
this.typeGroup.Location = new System.Drawing.Point(152, 81);
this.typeGroup.Name = "typeGroup";
this.typeGroup.Size = new System.Drawing.Size(128, 80);
this.typeGroup.TabIndex = 6;
this.typeGroup.TabStop = false;
//<CG DEL> DTE:16/10/2003 RAISON : MOVED TO CONSTRUCTOR
//this.typeGroup.Text = "Type de groupe";
//</CG>
//
// distributionRadioBox
//
this.distributionRadioBox.Location = new System.Drawing.Point(12, 48);
this.distributionRadioBox.Name = "distributionRadioBox";
this.distributionRadioBox.TabIndex = 1;
//<CG DEL> DTE:16/10/2003 RAISON : MOVED TO CONSTRUCTOR
//this.distributionRadioBox.Text = "Distribution";
//</CG>
//
// securityRadioBox
//
this.securityRadioBox.Location = new System.Drawing.Point(12, 20);
this.securityRadioBox.Name = "securityRadioBox";
this.securityRadioBox.TabIndex = 0;
//<CG DEL> DTE:16/10/2003 RAISON : MOVED TO CONSTRUCTOR
//this.securityRadioBox.Text = "Sécurité";
//</CG>
//
// etendueGroup
//
this.etendueGroup.Controls.AddRange(new System.Windows.Forms.Control[] {
this.universalRadioBox,
this.globalRadioBox,
this.localRadioBox});
this.etendueGroup.Location = new System.Drawing.Point(8, 81);
this.etendueGroup.Name = "etendueGroup";
this.etendueGroup.Size = new System.Drawing.Size(128, 104);
this.etendueGroup.TabIndex = 5;
this.etendueGroup.TabStop = false;
//<CG DEL> DTE:16/10/2003 RAISON : MOVED TO CONSTRUCTOR
//this.etendueGroup.Text = "Etendue du groupe";
//</CG>
//
// universalRadioBox
//
this.universalRadioBox.Location = new System.Drawing.Point(12, 68);
this.universalRadioBox.Name = "universalRadioBox";
this.universalRadioBox.TabIndex = 2;
//<CG DEL> DTE:16/10/2003 RAISON : MOVED TO CONSTRUCTOR
//this.universalRadioBox.Text = "Universelle";
//</CG>
//
// globalRadioBox
//
this.globalRadioBox.Location = new System.Drawing.Point(12, 44);
this.globalRadioBox.Name = "globalRadioBox";
this.globalRadioBox.TabIndex = 1;
//<CG DEL> DTE:16/10/2003 RAISON : MOVED TO CONSTRUCTOR
//this.globalRadioBox.Text = "Globale";
//</CG>
//
// localRadioBox
//
this.localRadioBox.Location = new System.Drawing.Point(12, 20);
this.localRadioBox.Name = "localRadioBox";
this.localRadioBox.TabIndex = 0;
//<CG DEL> DTE:16/10/2003 RAISON : MOVED TO CONSTRUCTOR
//this.localRadioBox.Text = "Domaine Local";
//</CG>
//
// createGroupForm
//
this.AcceptButton = this.okButton;
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.CancelButton = this.cancelButton;
this.ClientSize = new System.Drawing.Size(290, 242);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.typeGroup,
this.etendueGroup,
this.cancelButton,
this.okButton,
this.groupNameTextBox,
this.label1});
this.FormBorderStyle =
System.Windows.Forms.FormBorderStyle.FixedToolWind ow;
this.Name = "createGroupForm";
//<CG DEL> DTE:16/10/2003 RAISON : MOVED TO CONSTRUCTOR
//this.Text = "Nouveau Groupe";
//</CG>
this.typeGroup.ResumeLayout(false);
this.etendueGroup.ResumeLayout(false);
this.ResumeLayout(false);

}
#endregion

// Cette fonction active ou desactive le bouton OK si il y a du texte ou
pas dans la textbox
// du nom de groupe.

private void groupNameTextBox_TextChanged(object sender, System.EventArgs
e)
{
if (groupNameTextBox.Text.ToString().Length != 0)
okButton.Enabled = true;
else
okButton.Enabled = false;
}

// Cette fonction cree le groupe dans le container courant, verifie de
quel type est le groupe, puis
// raffraichit l'affichage du form principal.

private void okButton_Click(object sender, System.EventArgs e)
{
try
{
DirectoryEntry group =
currentForm.currentObjectInView.Children.Add("CN=" + groupNameTextBox.Text,
"group");
group.Properties["sAMAccountName"].Add(groupNameTextBox.Text);
group.CommitChanges();
checkGroupType(group);
currentForm.ShowView(currentForm.currentObjectInVi ew);
this.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

// Cette fonction verifie le type de groupe par un systeme de flags et en
fonction des radiobox checkees.

private void checkGroupType(DirectoryEntry group)
{
if (localRadioBox.Checked)
{
setGroupType(ADS_GROUP_TYPE_UNIVERSAL_GROUP, group);
setGroupType(ADS_GROUP_TYPE_LOCAL_GROUP, group);
}
else if (globalRadioBox.Checked)
setGroupType(ADS_GROUP_TYPE_GLOBAL_GROUP, group);
else if (universalRadioBox.Checked)
setGroupType(ADS_GROUP_TYPE_UNIVERSAL_GROUP, group);
if (securityRadioBox.Checked)
setSecurityGroup(group);
else
unSetSecurityGroup(group);
}

// Cette fonction passe le groupe en groupe de securite si l'option est
checkee.

private void setSecurityGroup(DirectoryEntry group)
{
try
{
int groupType = (int)group.Properties["groupType"][0];
group.Properties["groupType"][0] = (int)(groupType +
ADS_GROUP_TYPE_SECURITY_ENABLED);
group.CommitChanges();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}

// Cette fonction enleve le groupe du type securite si l'option est
decochee.

private void unSetSecurityGroup(DirectoryEntry group)
{
try
{
int groupType = (int)group.Properties["groupType"][0];
group.Properties["groupType"][0] = (int)(groupType +
ADS_GROUP_TYPE_SECURITY_ENABLED);
group.CommitChanges();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}

private void setGroupType(uint newType, DirectoryEntry group)
{
try
{
group.Properties["groupType"][0] = (int)newType;
group.CommitChanges();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
private void Trad()
{
this.Text = App.ResourceM.GetString("creategroup_title");
this.localRadioBox.Text = App.ResourceM.GetString("creategroup_area_o1");
this.globalRadioBox.Text =
App.ResourceM.GetString("creategroup_area_o2");
this.universalRadioBox.Text =
App.ResourceM.GetString("creategroup_area_o3");
this.etendueGroup.Text =
App.ResourceM.GetString("creategroup_area_title");
this.securityRadioBox.Text =
App.ResourceM.GetString("creategroup_type_o1");
this.distributionRadioBox.Text =
App.ResourceM.GetString("creategroup_type_o2");
this.typeGroup.Text = App.ResourceM.GetString("creategroup_type_title");
this.cancelButton.Text = App.ResourceM.GetString("gen_cancel");
this.okButton.Text = App.ResourceM.GetString("gen_create");
this.label1.Text = App.ResourceM.GetString("creategroup_lbl");

}

}
}
hope this helps

Mohamed Mahfouz
MEA Developer Support Center
ITworx on behalf of Microsoft EMEA GTSC

Nov 16 '05 #2
Great, OP has to search 600 lines of code looking for something that could
be answered with only 20 lines of code text.

Willy.

"Mohamoss" <mo************@egdsc.microsoft.com> wrote in message
news:1v**************@cpmsftngxa06.phx.gbl...
Nov 16 '05 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Eugene Burtsev | last post by:
Yes folks, I finally lost it. I need to make a php script cable of creating/editing users in windows active directory. To make it even harder php is installed as a module on Apache running on...
1
by: Mario Rodriguez | last post by:
Hi, I'm creating active directory users programatically and everything works fine, but I could notice that the UserLogonName on the microsoft Active directory Console is not set. Does anybody...
1
by: anonymous | last post by:
Hi all, I've been searching the way to achieve the following task. But no luck so far. I have a web site(main site), which requires authentication. This authentication is set at Windows...
0
by: Kumar | last post by:
Hi Folks, I am trying to do the following functionality. Add employee ID in OtherHomePhone field in that user Active directory profile. I created DirectoryEntry object. While assiging the...
1
by: Andrew | last post by:
Hey all, Working on revamping our Intranet here and making use of the LDPA, Active Directory, Directory Services, etc. that .Net provides. I am still fairly new on this subject, so the problem...
5
by: J'son | last post by:
<REPOSTED> Guys, I need to build a web intranet application that can automatically create a user account when a new user registers on the site. The user account will be on the web server,...
6
by: Leo_Surf | last post by:
Hello, I need your help adding user in Active Directory from ASP.net website. Could any one provide me the complete code for the html page. As this is my curriculam project and I dont have any...
9
by: Patrick | last post by:
I have an ASP.NET page that searches for someone in the corporate Active Directory. It had been working fine until recently when I changed from Basic Authentication on IIS6 back to Integrated...
3
by: Gentian Hila | last post by:
Hello there, I was wondering if any one knows some good source, book, or even MSDN resurce (I found something there, but seems to be very little) that instructs how to create in VB.NET programs...
3
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 2 August 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM) The start time is equivalent to 19:00 (7PM) in Central...
0
linyimin
by: linyimin | last post by:
Spring Startup Analyzer generates an interactive Spring application startup report that lets you understand what contributes to the application startup time and helps to optimize it. Support for...
0
by: erikbower65 | last post by:
Here's a concise step-by-step guide for manually installing IntelliJ IDEA: 1. Download: Visit the official JetBrains website and download the IntelliJ IDEA Community or Ultimate edition based on...
0
by: kcodez | last post by:
As a H5 game development enthusiast, I recently wrote a very interesting little game - Toy Claw ((http://claw.kjeek.com/))。Here I will summarize and share the development experience here, and hope it...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Sept 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM) The start time is equivalent to 19:00 (7PM) in Central...
14
DJRhino1175
by: DJRhino1175 | last post by:
When I run this code I get an error, its Run-time error# 424 Object required...This is my first attempt at doing something like this. I test the entire code and it worked until I added this - If...
0
by: Rina0 | last post by:
I am looking for a Python code to find the longest common subsequence of two strings. I found this blog post that describes the length of longest common subsequence problem and provides a solution in...
0
by: lllomh | last post by:
Define the method first this.state = { buttonBackgroundColor: 'green', isBlinking: false, // A new status is added to identify whether the button is blinking or not } autoStart=()=>{
0
by: Mushico | last post by:
How to calculate date of retirement from date of birth

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.