github.com/schmorrison/Zoho@v1.1.4/recruit/candidates.go (about)

     1  package recruit
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	zoho "github.com/schmorrison/Zoho"
     8  )
     9  
    10  // https://www.zoho.eu/recruit/developer-guide/apiv2/insert-records.html
    11  func (c *API) InsertCandidates(
    12  	request InsertCandidateRequest,
    13  ) (data InsertCandidateResponse, err error) {
    14  	endpoint := zoho.Endpoint{
    15  		Name: "InsertCandidates",
    16  		URL: fmt.Sprintf(
    17  			"https://recruit.zoho.%s/recruit/v2/%s",
    18  			c.ZohoTLD,
    19  			CandidatesModule,
    20  		),
    21  		Method:       zoho.HTTPPost,
    22  		ResponseData: &InsertCandidateResponse{},
    23  		RequestBody:  request,
    24  	}
    25  
    26  	err = c.Zoho.HTTPRequest(&endpoint)
    27  	if err != nil {
    28  		return InsertCandidateResponse{}, fmt.Errorf(
    29  			"failed to insert Candidate(s): %s",
    30  			err.Error(),
    31  		)
    32  	}
    33  
    34  	if v, ok := endpoint.ResponseData.(*InsertCandidateResponse); ok {
    35  		for _, resp := range v.Data {
    36  			if resp.Code != "SUCCESS" {
    37  				return InsertCandidateResponse{}, fmt.Errorf(
    38  					"failed to insert Candidate(s): %s: %s",
    39  					resp.Code,
    40  					resp.Details,
    41  				)
    42  			}
    43  		}
    44  		return *v, nil
    45  	}
    46  
    47  	return InsertCandidateResponse{}, fmt.Errorf("no 'InsertCandidateResponse' returned")
    48  }
    49  
    50  type CandidateRequestData struct {
    51  	CandidateId       string `json:"CandidateId,omitempty"`
    52  	ApplicationDate   string `json:"ApplicationDate,omitempty"`
    53  	FirstName         string `json:"First_Name,omitempty"`
    54  	LastName          string `json:"Last_Name,omitempty"`
    55  	City              string `json:"City,omitempty"`
    56  	Email             string `json:"Email,omitempty"`
    57  	Mobile            string `json:"Mobile,omitempty"`
    58  	Street            string `json:"Street,omitempty"`
    59  	CurrentEmployer   string `json:"Current_Employer,omitempty"`
    60  	CurrentJobTitle   string `json:"Current_Job_Title,omitempty"`
    61  	ExpectedSalary    string `json:"Expected_Salary,omitempty"`
    62  	CurrencySymbol    string `json:"$currency_symbol,omitempty"`
    63  	ExperienceInYears string `json:"Experience_in_Years,omitempty"`
    64  	CandidateStatus   string `json:"Candidate_Status,omitempty"`
    65  	Source            string `json:"Source,omitempty"`
    66  }
    67  
    68  type InsertCandidateRequest struct {
    69  	Data    []CandidateRequestData `json:"data"`
    70  	Trigger []string               `json:"trigger"`
    71  }
    72  
    73  type InsertCandidateResponse struct {
    74  	Data []struct {
    75  		Code    string `json:"code"`
    76  		Details struct {
    77  			ModifiedTime time.Time `json:"Modified_Time"`
    78  			ModifiedBy   struct {
    79  				Name string `json:"name"`
    80  				ID   string `json:"id"`
    81  			} `json:"Modified_By"`
    82  			CreatedTime time.Time `json:"Created_Time"`
    83  			ID          string    `json:"id"`
    84  			CreatedBy   struct {
    85  				Name string `json:"name"`
    86  				ID   string `json:"id"`
    87  			} `json:"Created_By"`
    88  		} `json:"details"`
    89  		Message string `json:"message"`
    90  		Status  string `json:"status"`
    91  	} `json:"data"`
    92  }
    93  
    94  // Upsert = Insert or Update
    95  // https://www.zoho.com/recruit/developer-guide/apiv2/upsert-records.html
    96  func (c *API) UpsertCandidates(
    97  	request UpsertCandidateRequest,
    98  ) (data UpsertCandidateResponse, err error) {
    99  	endpoint := zoho.Endpoint{
   100  		Name: "UpsertCandidates",
   101  		URL: fmt.Sprintf(
   102  			"https://recruit.zoho.%s/recruit/v2/%s/upsert",
   103  			c.ZohoTLD,
   104  			CandidatesModule,
   105  		),
   106  		Method:       zoho.HTTPPost,
   107  		ResponseData: &UpsertCandidateResponse{},
   108  		RequestBody:  request,
   109  	}
   110  
   111  	err = c.Zoho.HTTPRequest(&endpoint)
   112  	if err != nil {
   113  		return UpsertCandidateResponse{}, fmt.Errorf("failed to upsert Candidate(s): %s", err)
   114  	}
   115  
   116  	if v, ok := endpoint.ResponseData.(*UpsertCandidateResponse); ok {
   117  		return *v, nil
   118  	}
   119  
   120  	return UpsertCandidateResponse{}, fmt.Errorf("no 'UpsertCandidateResponse' returned")
   121  }
   122  
   123  type UpsertCandidateRequest struct {
   124  	Data                 []CandidateRequestData `json:"data"`
   125  	DuplicateCheckFields []string               `json:"duplicate_check_fields"`
   126  	Trigger              []string               `json:"trigger"`
   127  }
   128  type UpsertCandidateResponse struct {
   129  	Data []struct {
   130  		Code           string `json:"code"`
   131  		DuplicateField string `json:"duplicate_field"`
   132  		Action         string `json:"action"`
   133  		Details        struct {
   134  			ModifiedTime time.Time `json:"Modified_Time"`
   135  			ModifiedBy   struct {
   136  				Name string `json:"name"`
   137  				ID   string `json:"id"`
   138  			} `json:"Modified_By"`
   139  			CreatedTime time.Time `json:"Created_Time"`
   140  			ID          string    `json:"id"`
   141  			CreatedBy   struct {
   142  				Name string `json:"name"`
   143  				ID   string `json:"id"`
   144  			} `json:"Created_By"`
   145  		} `json:"details"`
   146  		Message string `json:"message"`
   147  		Status  string `json:"status"`
   148  	} `json:"data"`
   149  }
   150  
   151  // https://www.zoho.com/recruit/developer-guide/apiv2/get-records.html
   152  func (c *API) GetCandidates(params map[string]zoho.Parameter) (data CandidatesResponse, err error) {
   153  	endpoint := zoho.Endpoint{
   154  		Name: "GetCandidates",
   155  		URL: fmt.Sprintf(
   156  			"https://recruit.zoho.%s/recruit/v2/%s",
   157  			c.ZohoTLD,
   158  			CandidatesModule,
   159  		),
   160  		Method:       zoho.HTTPGet,
   161  		ResponseData: &CandidatesResponse{},
   162  		URLParameters: map[string]zoho.Parameter{
   163  			"fields":        "",
   164  			"sort_order":    "",
   165  			"sort_by":       "",
   166  			"converted":     "false",
   167  			"approved":      "true",
   168  			"page":          "1",
   169  			"per_page":      "200",
   170  			"cvid":          "",
   171  			"territory_id":  "",
   172  			"include_child": "",
   173  		},
   174  	}
   175  
   176  	if len(params) > 0 {
   177  		for k, v := range params {
   178  			endpoint.URLParameters[k] = v
   179  		}
   180  	}
   181  
   182  	err = c.Zoho.HTTPRequest(&endpoint)
   183  	if err != nil {
   184  		return CandidatesResponse{}, fmt.Errorf("failed to retrieve Candidates: %s", err)
   185  	}
   186  
   187  	if v, ok := endpoint.ResponseData.(*CandidatesResponse); ok {
   188  		return *v, nil
   189  	}
   190  
   191  	return CandidatesResponse{}, fmt.Errorf("no 'CandidatesResponse' returned")
   192  }
   193  
   194  // https://www.zoho.com/recruit/developer-guide/apiv2/get-records.html
   195  func (c *API) GetCandidateById(id string) (data CandidatesResponse, err error) {
   196  	endpoint := zoho.Endpoint{
   197  		Name: "GetCandidateById",
   198  		URL: fmt.Sprintf(
   199  			"https://recruit.zoho.%s/recruit/v2/%s/%s",
   200  			c.ZohoTLD,
   201  			CandidatesModule,
   202  			id,
   203  		),
   204  		Method:       zoho.HTTPGet,
   205  		ResponseData: &CandidatesResponse{},
   206  	}
   207  
   208  	err = c.Zoho.HTTPRequest(&endpoint)
   209  	if err != nil {
   210  		return CandidatesResponse{}, fmt.Errorf("failed to retrieve Candidate with id: %s", err)
   211  	}
   212  
   213  	if v, ok := endpoint.ResponseData.(*CandidatesResponse); ok {
   214  		return *v, nil
   215  	}
   216  
   217  	return CandidatesResponse{}, fmt.Errorf("no 'CandidatesResponse' returned")
   218  }
   219  
   220  type CandidatesResponse struct {
   221  	Data []struct {
   222  		Origin                   string `json:"Origin,omitempty"`
   223  		Email                    string `json:"Email,omitempty"`
   224  		CurrencySymbol           string `json:"$currency_symbol,omitempty"`
   225  		Last_Activity_Time       Time   `json:"Last_Activity_Time,omitempty"`
   226  		HighestQualificationHeld string `json:"Highest_Qualification_Held,omitempty"`
   227  		SkillSet                 string `json:"Skill_Set,omitempty"`
   228  		Converted                bool   `json:"$converted,omitempty"`
   229  		ProcessFlow              bool   `json:"$process_flow,omitempty"`
   230  		Updated_On               Time   `json:"Updated_On,omitempty"`
   231  		CurrentEmployer          string `json:"Current_Employer,omitempty"`
   232  		Street                   string `json:"Street,omitempty"`
   233  		ZipCode                  string `json:"Zip_Code,omitempty"`
   234  		ID                       string `json:"id,omitempty"`
   235  		ExperienceInYears        int    `json:"Experience_in_Years,omitempty"`
   236  		Approved                 bool   `json:"$approved,omitempty"`
   237  		Approval                 struct {
   238  			Delegate bool `json:"delegate,omitempty"`
   239  			Approve  bool `json:"approve,omitempty"`
   240  			Reject   bool `json:"reject,omitempty"`
   241  			Resubmit bool `json:"resubmit,omitempty"`
   242  		} `json:"$approval,omitempty"`
   243  		CandidateStatus string `json:"Candidate_Status,omitempty"`
   244  		CandidateID     string `json:"Candidate_ID,omitempty"`
   245  		LastMailedTime  Time   `json:"Last_Mailed_Time,omitempty"`
   246  		CreatedTime     string `json:"Created_Time,omitempty"`
   247  		Followed        string `json:"followed,omitempty"`
   248  		CandidateOwner  struct {
   249  			Name string `json:"name,omitempty"`
   250  			ID   string `json:"id,omitempty"`
   251  		} `json:"Candidate_Owner,omitempty"`
   252  		Editable       bool       `json:"$editable,omitempty"`
   253  		IsLocked       bool       `json:"Is_Locked,omitempty"`
   254  		City           string     `json:"City,omitempty"`
   255  		IsUnqualified  bool       `json:"Is_Unqualified,omitempty"`
   256  		AssociatedTags []struct{} `json:"Associated_Tags,omitempty"`
   257  		AdditionalInfo string     `json:"Additional_Info,omitempty"`
   258  		State          string     `json:"State,omitempty"`
   259  		Country        string     `json:"Country,omitempty"`
   260  		CreatedBy      struct {
   261  			Name string `json:"name,omitempty"`
   262  			ID   string `json:"id,omitempty"`
   263  		} `json:"Created_By,omitempty"`
   264  		SecondaryEmail      string `json:"Secondary_Email,omitempty"`
   265  		IsAttachmentPresent bool   `json:"Is_Attachment_Present,omitempty"`
   266  		Rating              int    `json:"Rating,omitempty"`
   267  		AppliedWithLinkedin string `json:"$applied_with_linkedin,omitempty"`
   268  		Website             string `json:"Website,omitempty"`
   269  		Twitter             string `json:"Twitter,omitempty"`
   270  		CurrentJobTitle     string `json:"Current_Job_Title,omitempty"`
   271  		Salutation          string `json:"Salutation,omitempty"`
   272  		Source              string `json:"Source,omitempty"`
   273  		FirstName           string `json:"First_Name,omitempty"`
   274  		FullName            string `json:"Full_Name,omitempty"`
   275  		ModifiedBy          struct {
   276  			Name string `json:"name,omitempty"`
   277  			ID   string `json:"id,omitempty"`
   278  		} `json:"Modified_By,omitempty"`
   279  		SkypeID                     string   `json:"Skype_ID,omitempty"`
   280  		Phone                       string   `json:"Phone,omitempty"`
   281  		Email_Opt_Out               bool     `json:"Email_Opt_Out,omitempty"`
   282  		IsStatusSplitDone           bool     `json:"isStatusSplitDone,omitempty"`
   283  		ConvertedDetail             struct{} `json:"#converted_detail,omitempty"`
   284  		CareerPageInviteStatus      string   `json:"Career_Page_Invite_Status,omitempty"`
   285  		Mobile                      string   `json:"Mobile,omitempty"`
   286  		LastName                    string   `json:"Last_Name,omitempty"`
   287  		CurrentSalary               string   `json:"Current_Salary,omitempty"`
   288  		AssociatedAnySocialProfiles bool     `json:"Associated_any_Social_Profiles,omitempty"`
   289  		Fax                         string   `json:"Fax,omitempty"`
   290  		ExpectedSalary              string   `json:"Expected_Salary,omitempty"`
   291  	} `json:"data,omitempty"`
   292  	Info PageInfo `json:"info,omitempty"`
   293  }
   294  
   295  // https://www.zoho.com/recruit/developer-guide/apiv2/get-related-records.html
   296  func (c *API) GetCandidateRelatedRecords(
   297  	params map[string]zoho.Parameter,
   298  	candidateId string,
   299  	record RelatedRecord,
   300  ) (data CandidateRelatedRecordsResponse, err error) {
   301  	endpoint := zoho.Endpoint{
   302  		Name: "GetCandidateRelatedRecords",
   303  		URL: fmt.Sprintf(
   304  			"https://recruit.zoho.%s/recruit/v2/%s/%s/%s",
   305  			c.ZohoTLD,
   306  			CandidatesModule,
   307  			candidateId,
   308  			record,
   309  		),
   310  		Method:       zoho.HTTPGet,
   311  		ResponseData: &CandidateRelatedRecordsResponse{},
   312  		URLParameters: map[string]zoho.Parameter{
   313  			"ids":        "",
   314  			"sort_order": "",
   315  			"sort_by":    "",
   316  			"page":       "1",
   317  			"per_page":   "200",
   318  			"fields":     "",
   319  		},
   320  	}
   321  
   322  	if len(params) > 0 {
   323  		for k, v := range params {
   324  			endpoint.URLParameters[k] = v
   325  		}
   326  	}
   327  
   328  	err = c.Zoho.HTTPRequest(&endpoint)
   329  	if err != nil {
   330  		return CandidateRelatedRecordsResponse{}, fmt.Errorf(
   331  			"failed to retrieve Candidates: %s",
   332  			err,
   333  		)
   334  	}
   335  
   336  	if v, ok := endpoint.ResponseData.(*CandidateRelatedRecordsResponse); ok {
   337  		return *v, nil
   338  	}
   339  
   340  	return CandidateRelatedRecordsResponse{}, fmt.Errorf(
   341  		"no 'CandidateRelatedRecordsResponse' returned",
   342  	)
   343  }
   344  
   345  type CandidateRelatedRecordsResponse struct {
   346  	Data []struct {
   347  		AttachType struct {
   348  			Name string `json:"name"`
   349  			ID   string `json:"id"`
   350  		} `json:"$attach_type"`
   351  		ModifiedTime    time.Time `json:"Modified_Time"`
   352  		FileName        string    `json:"File_Name"`
   353  		Size            string    `json:"Size"`
   354  		CreatedTime     time.Time `json:"Created_Time"`
   355  		LinkDocs        int       `json:"$link_docs"`
   356  		ParentID        string    `json:"Parent_Id"`
   357  		Editable        bool      `json:"$editable"`
   358  		AttachmentOwner struct {
   359  			Name string `json:"name"`
   360  			ID   string `json:"id"`
   361  		} `json:"Attachment_Owner"`
   362  		FileID     string `json:"$file_id"`
   363  		Type       string `json:"$type"`
   364  		SeModule   string `json:"$se_module"`
   365  		ModifiedBy struct {
   366  			Name string `json:"name"`
   367  			ID   string `json:"id"`
   368  		} `json:"Modified_By"`
   369  		ID        string `json:"id"`
   370  		CreatedBy struct {
   371  			Name string `json:"name"`
   372  			ID   string `json:"id"`
   373  		} `json:"Created_By"`
   374  		LinkURL interface{} `json:"$link_url"`
   375  	} `json:"data"`
   376  	Info PageInfo `json:"info,omitempty"`
   377  }
   378  
   379  // https://www.zoho.com/recruit/developer-guide/apiv2/delete-records.html
   380  func (c *API) DeleteCandidateById(ID string) (data DeleteCandidateResponse, err error) {
   381  	endpoint := zoho.Endpoint{
   382  		Name: "DeleteCandidateById",
   383  		URL: fmt.Sprintf(
   384  			"https://recruit.zoho.%s/recruit/v2/%s/%s",
   385  			c.ZohoTLD,
   386  			CandidatesModule,
   387  			ID,
   388  		),
   389  		Method:       zoho.HTTPDelete,
   390  		ResponseData: &DeleteCandidateResponse{},
   391  	}
   392  
   393  	err = c.Zoho.HTTPRequest(&endpoint)
   394  	if err != nil {
   395  		return DeleteCandidateResponse{}, fmt.Errorf("failed to delete Candidate: %s", err)
   396  	}
   397  
   398  	if v, ok := endpoint.ResponseData.(*DeleteCandidateResponse); ok {
   399  		return *v, nil
   400  	}
   401  
   402  	return DeleteCandidateResponse{}, fmt.Errorf("no 'DeleteCandidateResponse' returned")
   403  }
   404  
   405  // https://www.zoho.com/recruit/developer-guide/apiv2/delete-records.html
   406  func (c *API) DeleteCandidatesByIds(IDs ...string) (data DeleteCandidateResponse, err error) {
   407  	if len(IDs) == 0 {
   408  		return DeleteCandidateResponse{}, fmt.Errorf(
   409  			"failed to delete Candidates, must provide at least 1 ID",
   410  		)
   411  	}
   412  
   413  	idStr := ""
   414  	for i, a := range IDs {
   415  		idStr += a
   416  		if i < len(IDs)-1 {
   417  			idStr += ","
   418  		}
   419  	}
   420  
   421  	endpoint := zoho.Endpoint{
   422  		Name: "DeleteCandidatesByIds",
   423  		URL: fmt.Sprintf(
   424  			"https://recruit.zoho.%s/recruit/v2/%s",
   425  			c.ZohoTLD,
   426  			CandidatesModule,
   427  		),
   428  		Method:       zoho.HTTPDelete,
   429  		ResponseData: &DeleteCandidateResponse{},
   430  		URLParameters: map[string]zoho.Parameter{
   431  			"ids": zoho.Parameter(idStr),
   432  		},
   433  	}
   434  
   435  	err = c.Zoho.HTTPRequest(&endpoint)
   436  	if err != nil {
   437  		return DeleteCandidateResponse{}, fmt.Errorf("failed to delete Candidate(s): %s", err)
   438  	}
   439  
   440  	if v, ok := endpoint.ResponseData.(*DeleteCandidateResponse); ok {
   441  		return *v, nil
   442  	}
   443  
   444  	return DeleteCandidateResponse{}, fmt.Errorf("no 'DeleteCandidateResponse' returned")
   445  }
   446  
   447  type DeleteCandidateResponse struct {
   448  	Data []struct {
   449  		Code    string `json:"code"`
   450  		Details struct {
   451  			ID string `json:"id"`
   452  		} `json:"details"`
   453  		Message string `json:"message"`
   454  		Status  string `json:"status"`
   455  	} `json:"data"`
   456  }
   457  
   458  // https://www.zoho.com/recruit/developer-guide/apiv2/get-deleted-records.html
   459  func (c *API) ListDeletedCandidates(
   460  	params map[string]zoho.Parameter,
   461  ) (data DeletedCandidatesResponse, err error) {
   462  	endpoint := zoho.Endpoint{
   463  		Name: "ListDeletedCandidates",
   464  		URL: fmt.Sprintf(
   465  			"https://recruit.zoho.%s/recruit/v2/%s/deleted",
   466  			c.ZohoTLD,
   467  			CandidatesModule,
   468  		),
   469  		Method:       zoho.HTTPGet,
   470  		ResponseData: &DeletedCandidatesResponse{},
   471  		URLParameters: map[string]zoho.Parameter{
   472  			"type":     "",
   473  			"page":     "1",
   474  			"per_page": "200",
   475  		},
   476  	}
   477  
   478  	if len(params) > 0 {
   479  		for k, v := range params {
   480  			endpoint.URLParameters[k] = v
   481  		}
   482  	}
   483  
   484  	err = c.Zoho.HTTPRequest(&endpoint)
   485  	if err != nil {
   486  		return DeletedCandidatesResponse{}, fmt.Errorf(
   487  			"failed to retrieve Deleted Candidates: %s",
   488  			err,
   489  		)
   490  	}
   491  
   492  	if v, ok := endpoint.ResponseData.(*DeletedCandidatesResponse); ok {
   493  		return *v, nil
   494  	}
   495  
   496  	return DeletedCandidatesResponse{}, fmt.Errorf("no 'DeletedCandidatesResponse' returned")
   497  }
   498  
   499  type DeletedCandidatesResponse struct {
   500  	Data []struct {
   501  		DeletedBy struct {
   502  			Name string `json:"id,omitempty"`
   503  			ID   string `json:"id2,omitempty"`
   504  		} `json:"deleted_by,omitempty"`
   505  		ID          string `json:"id,omitempty"`
   506  		DisplayName string `json:"display_name,omitempty"`
   507  		Type        string `json:"type,omitempty"`
   508  		CreatedBy   struct {
   509  			Name string `json:"name,omitempty"`
   510  			ID   string `json:"id,omitempty"`
   511  		} `json:"created_by,omitempty"`
   512  		DeletedTime Time `json:"deleted_time,omitempty"`
   513  	} `json:"data,omitempty"`
   514  	Info PageInfo `json:"info,omitempty"`
   515  }
   516  
   517  // https://www.zoho.com/recruit/developer-guide/apiv2/associate-candidate.html
   518  func (c *API) AssociateCandidates(
   519  	request AssociateCandidatesRequest,
   520  ) (data AssociateCandidatesResponse, err error) {
   521  	endpoint := zoho.Endpoint{
   522  		Name: "AssociateCandidates",
   523  		URL: fmt.Sprintf(
   524  			"https://recruit.zoho.%s/recruit/v2/%s/actions/associate",
   525  			c.ZohoTLD,
   526  			CandidatesModule,
   527  		),
   528  		Method:       zoho.HTTPPut,
   529  		ResponseData: &AssociateCandidatesResponse{},
   530  		RequestBody:  request,
   531  	}
   532  
   533  	err = c.Zoho.HTTPRequest(&endpoint)
   534  	if err != nil {
   535  		return AssociateCandidatesResponse{}, fmt.Errorf("failed to associate candidate: %s", err)
   536  	}
   537  
   538  	if v, ok := endpoint.ResponseData.(*AssociateCandidatesResponse); ok {
   539  		return *v, nil
   540  	}
   541  
   542  	return AssociateCandidatesResponse{}, fmt.Errorf("no 'AssociateCandidatesResponse' returned")
   543  }
   544  
   545  type AssociateCandidatesResponseData struct {
   546  	Jobids   []string `json:"jobids"`
   547  	Ids      []string `json:"ids"`
   548  	Comments string   `json:"comments"`
   549  }
   550  type AssociateCandidatesRequest struct {
   551  	Data []AssociateCandidatesResponseData `json:"data"`
   552  }
   553  type AssociateCandidatesResponse struct {
   554  	Data []struct {
   555  		Code    string `json:"code"`
   556  		Details struct {
   557  			Jobid string `json:"jobid"`
   558  			Ids   string `json:"ids"`
   559  			Error []struct {
   560  				Code    string `json:"code"`
   561  				Details struct {
   562  					ID string `json:"id"`
   563  				} `json:"details"`
   564  				Message string `json:"message"`
   565  				Status  string `json:"status"`
   566  			} `json:"error"`
   567  		} `json:"details"`
   568  		Message string `json:"message"`
   569  		Status  string `json:"status"`
   570  	} `json:"data"`
   571  }