Repository: yorkie-team/yorkie
Pull request #471 (2023-02-18 12:45:19)

Change ClientDeactivateThreshold Type to String
**What this PR does / why we need it**:

Change `ClientDeactivateThreshold` type to string.

This change is applied to remove unnecessary type conversion in server, and also ease client to see and update `ClientDeactivateThreshold` in time duration string format (ex: `1h30m`). Previous `ClientDeactivateThreshold` field was `time.Duration` type of with internal `int64` nanoseconds, which made client hard to see and update field.

**Which issue(s) this PR fixes**:

No issue is related.

**Special notes for your reviewer**:

None.

**Does this PR introduce a user-facing change?**:

```release-note
Add `--client-deactivate-threshold` parameter in project update CLI 
Add `ClientDeactivateThreshold` field in project update in Dashboard
```

**Additional documentation**:

```docs

```

**Checklist**:
- [x] Added relevant tests or not required
- [x] Didn't break anything


codecov[bot]: # [Codecov](https://codecov.io/gh/yorkie-team/yorkie/pull/471?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=yorkie-team) Report
> Merging [#471](https://codecov.io/gh/yorkie-team/yorkie/pull/471?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=yorkie-team) (20a41ce) into [main](https://codecov.io/gh/yorkie-team/yorkie/commit/c5b9a908577b911c1598496a6f0e83c94563cbe2?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=yorkie-team) (c5b9a90) will **decrease** coverage by `0.06%`.
> The diff coverage is `0.00%`.

```diff
@@            Coverage Diff             @@
##             main     #471      +/-   ##
==========================================
- Coverage   46.65%   46.59%   -0.06%     
==========================================
  Files          69       69              
  Lines        5749     5756       +7     
==========================================
  Hits         2682     2682              
- Misses       2763     2770       +7     
  Partials      304      304              
```


| [Impacted Files](https://codecov.io/gh/yorkie-team/yorkie/pull/471?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=yorkie-team) | Coverage Δ | |
|---|---|---|
| [api/converter/from\_pb.go](https://codecov.io/gh/yorkie-team/yorkie/pull/471?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=yorkie-team#diff-YXBpL2NvbnZlcnRlci9mcm9tX3BiLmdv) | `53.79% <0.00%> (-0.76%)` | :arrow_down: |
| [api/converter/to\_pb.go](https://codecov.io/gh/yorkie-team/yorkie/pull/471?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=yorkie-team#diff-YXBpL2NvbnZlcnRlci90b19wYi5nbw==) | `63.48% <0.00%> (-0.21%)` | :arrow_down: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=yorkie-team). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=yorkie-team)

krapie: With CLI added, I also added `ClientDeactivateThreshold` update field in dashboard's project settings.
Follow this PR: https://github.com/yorkie-team/dashboard/pull/107

Patch:
diff --git a/api/converter/from_pb.go b/api/converter/from_pb.go
index 13fe4b9b..b21d6361 100644
--- a/api/converter/from_pb.go
+++ b/api/converter/from_pb.go
@@ -18,7 +18,6 @@ package converter
 
 import (
 	"fmt"
-	gotime "time"
 
 	protoTypes "github.com/gogo/protobuf/types"
 
@@ -69,12 +68,13 @@ func FromProject(pbProject *api.Project) (*types.Project, error) {
 	if err != nil {
 		return nil, fmt.Errorf("convert updatedAt to timestamp: %w", err)
 	}
+
 	return &types.Project{
 		ID:                        types.ID(pbProject.Id),
 		Name:                      pbProject.Name,
 		AuthWebhookURL:            pbProject.AuthWebhookUrl,
 		AuthWebhookMethods:        pbProject.AuthWebhookMethods,
-		ClientDeactivateThreshold: gotime.Duration(pbProject.ClientDeactivateThreshold),
+		ClientDeactivateThreshold: pbProject.ClientDeactivateThreshold,
 		PublicKey:                 pbProject.PublicKey,
 		SecretKey:                 pbProject.SecretKey,
 		CreatedAt:                 createdAt,
@@ -665,8 +665,8 @@ func FromUpdatableProjectFields(pbProjectFields *api.UpdatableProjectFields) (*t
 	if pbProjectFields.AuthWebhookMethods != nil {
 		updatableProjectFields.AuthWebhookMethods = &pbProjectFields.AuthWebhookMethods.Methods
 	}
-	if pbProjectFields.ClientDeactivateThreshold != 0 {
-		updatableProjectFields.ClientDeactivateThreshold = gotime.Duration(pbProjectFields.ClientDeactivateThreshold)
+	if pbProjectFields.ClientDeactivateThreshold != nil {
+		updatableProjectFields.ClientDeactivateThreshold = &pbProjectFields.ClientDeactivateThreshold.Value
 	}
 
 	return updatableProjectFields, nil
diff --git a/api/converter/to_pb.go b/api/converter/to_pb.go
index 32390473..9f621f9b 100644
--- a/api/converter/to_pb.go
+++ b/api/converter/to_pb.go
@@ -76,7 +76,7 @@ func ToProject(project *types.Project) (*api.Project, error) {
 		Name:                      project.Name,
 		AuthWebhookUrl:            project.AuthWebhookURL,
 		AuthWebhookMethods:        project.AuthWebhookMethods,
-		ClientDeactivateThreshold: int64(project.ClientDeactivateThreshold),
+		ClientDeactivateThreshold: project.ClientDeactivateThreshold,
 		PublicKey:                 project.PublicKey,
 		SecretKey:                 project.SecretKey,
 		CreatedAt:                 pbCreatedAt,
@@ -515,8 +515,10 @@ func ToUpdatableProjectFields(fields *types.UpdatableProjectFields) (*api.Updata
 	} else {
 		pbUpdatableProjectFields.AuthWebhookMethods = nil
 	}
-	if fields.ClientDeactivateThreshold != 0 {
-		pbUpdatableProjectFields.ClientDeactivateThreshold = int64(fields.ClientDeactivateThreshold)
+	if fields.ClientDeactivateThreshold != nil {
+		pbUpdatableProjectFields.ClientDeactivateThreshold = &protoTypes.StringValue{
+			Value: *fields.ClientDeactivateThreshold,
+		}
 	}
 	return pbUpdatableProjectFields, nil
 }
diff --git a/api/types/fields_validation.go b/api/types/fields_validation.go
index 00dd8e40..153fd8e4 100644
--- a/api/types/fields_validation.go
+++ b/api/types/fields_validation.go
@@ -32,6 +32,7 @@ const (
 	containNumberRegexString          = `[0-9]`
 	containSpecialCharRegexString     = `[\{\}\[\]\/?.,;:|\)*~!^\-_+<>@\#$%&\\\=\(\'\"\x60]`
 	alphaNumberSpecialCharRegexString = `^[a-zA-Z0-9\{\}\[\]\/?.,;:|\)*~!^\-_+<>@\#$%&\\\=\(\'\"\x60]+$`
+	timeDurationFormatRegexString     = `^(\d{1,2}h\s?)?(\d{1,2}m\s?)?(\d{1,2}s)?$`
 )
 
 var (
@@ -44,6 +45,7 @@ var (
 	containNumberRegex          = regexp.MustCompile(containNumberRegexString)
 	containSpecialCharRegex     = regexp.MustCompile(containSpecialCharRegexString)
 	alphaNumberSpecialCharRegex = regexp.MustCompile(alphaNumberSpecialCharRegexString)
+	timeDurationFormatRegex     = regexp.MustCompile(timeDurationFormatRegexString)
 )
 
 func isReservedProjectName(name string) bool {
@@ -74,6 +76,10 @@ func hasAlphaNumSpecial(str string) bool {
 	return isValid
 }
 
+func isValidTimeDurationStringFormat(str string) bool {
+	return timeDurationFormatRegex.MatchString(str)
+}
+
 func init() {
 	registerValidation("slug", func(level validator.FieldLevel) bool {
 		val := level.Field().String()
@@ -109,4 +115,10 @@ func init() {
 		return val == ""
 	})
 	registerTranslation("url|emptystring", "{0} must be a valid URL")
+
+	registerValidation("duration", func(level validator.FieldLevel) bool {
+		val := level.Field().String()
+		return isValidTimeDurationStringFormat(val)
+	})
+	registerTranslation("duration", "{0} must be a valid time duration string format")
 }
diff --git a/api/types/project.go b/api/types/project.go
index 4975fbc0..1edd4ed2 100644
--- a/api/types/project.go
+++ b/api/types/project.go
@@ -39,7 +39,7 @@ type Project struct {
 
 	// ClientDeactivateThreshold is the time after which clients in
 	// specific project are considered deactivate for housekeeping.
-	ClientDeactivateThreshold time.Duration `bson:"client_deactivate_threshold"`
+	ClientDeactivateThreshold string `bson:"client_deactivate_threshold"`
 
 	// PublicKey is the API key of this project.
 	PublicKey string `json:"public_key"`
diff --git a/api/types/updatable_project_fields.go b/api/types/updatable_project_fields.go
index e11eebed..45e75fcc 100644
--- a/api/types/updatable_project_fields.go
+++ b/api/types/updatable_project_fields.go
@@ -19,7 +19,6 @@ package types
 
 import (
 	"errors"
-	"time"
 
 	"github.com/go-playground/validator/v10"
 )
@@ -39,12 +38,12 @@ type UpdatableProjectFields struct {
 	AuthWebhookMethods *[]string `bson:"auth_webhook_methods,omitempty" validate:"omitempty,invalid_webhook_method"`
 
 	// ClientDeactivateThreshold is the time after which clients in specific project are considered deactivate.
-	ClientDeactivateThreshold time.Duration `bson:"client_deactivate_threshold,omitempty" validate:"omitempty"`
+	ClientDeactivateThreshold *string `bson:"client_deactivate_threshold,omitempty" validate:"omitempty,min=2,duration"`
 }
 
 // Validate validates the UpdatableProjectFields.
 func (i *UpdatableProjectFields) Validate() error {
-	if i.Name == nil && i.AuthWebhookURL == nil && i.AuthWebhookMethods == nil && i.ClientDeactivateThreshold == 0 {
+	if i.Name == nil && i.AuthWebhookURL == nil && i.AuthWebhookMethods == nil && i.ClientDeactivateThreshold == nil {
 		return ErrEmptyProjectFields
 	}
 
diff --git a/api/yorkie/v1/resources.pb.go b/api/yorkie/v1/resources.pb.go
index 12581b59..147192f2 100644
--- a/api/yorkie/v1/resources.pb.go
+++ b/api/yorkie/v1/resources.pb.go
@@ -2023,7 +2023,7 @@ type Project struct {
 	SecretKey                 string           `protobuf:"bytes,4,opt,name=secret_key,json=secretKey,proto3" json:"secret_key,omitempty"`
 	AuthWebhookUrl            string           `protobuf:"bytes,5,opt,name=auth_webhook_url,json=authWebhookUrl,proto3" json:"auth_webhook_url,omitempty"`
 	AuthWebhookMethods        []string         `protobuf:"bytes,6,rep,name=auth_webhook_methods,json=authWebhookMethods,proto3" json:"auth_webhook_methods,omitempty"`
-	ClientDeactivateThreshold int64            `protobuf:"varint,7,opt,name=client_deactivate_threshold,json=clientDeactivateThreshold,proto3" json:"client_deactivate_threshold,omitempty"`
+	ClientDeactivateThreshold string           `protobuf:"bytes,7,opt,name=client_deactivate_threshold,json=clientDeactivateThreshold,proto3" json:"client_deactivate_threshold,omitempty"`
 	CreatedAt                 *types.Timestamp `protobuf:"bytes,8,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
 	UpdatedAt                 *types.Timestamp `protobuf:"bytes,9,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
 	XXX_NoUnkeyedLiteral      struct{}         `json:"-"`
@@ -2106,11 +2106,11 @@ func (m *Project) GetAuthWebhookMethods() []string {
 	return nil
 }
 
-func (m *Project) GetClientDeactivateThreshold() int64 {
+func (m *Project) GetClientDeactivateThreshold() string {
 	if m != nil {
 		return m.ClientDeactivateThreshold
 	}
-	return 0
+	return ""
 }
 
 func (m *Project) GetCreatedAt() *types.Timestamp {
@@ -2131,7 +2131,7 @@ type UpdatableProjectFields struct {
 	Name                      *types.StringValue                         `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
 	AuthWebhookUrl            *types.StringValue                         `protobuf:"bytes,2,opt,name=auth_webhook_url,json=authWebhookUrl,proto3" json:"auth_webhook_url,omitempty"`
 	AuthWebhookMethods        *UpdatableProjectFields_AuthWebhookMethods `protobuf:"bytes,3,opt,name=auth_webhook_methods,json=authWebhookMethods,proto3" json:"auth_webhook_methods,omitempty"`
-	ClientDeactivateThreshold int64                                      `protobuf:"varint,4,opt,name=client_deactivate_threshold,json=clientDeactivateThreshold,proto3" json:"client_deactivate_threshold,omitempty"`
+	ClientDeactivateThreshold *types.StringValue                         `protobuf:"bytes,4,opt,name=client_deactivate_threshold,json=clientDeactivateThreshold,proto3" json:"client_deactivate_threshold,omitempty"`
 	XXX_NoUnkeyedLiteral      struct{}                                   `json:"-"`
 	XXX_unrecognized          []byte                                     `json:"-"`
 	XXX_sizecache             int32                                      `json:"-"`
@@ -2191,11 +2191,11 @@ func (m *UpdatableProjectFields) GetAuthWebhookMethods() *UpdatableProjectFields
 	return nil
 }
 
-func (m *UpdatableProjectFields) GetClientDeactivateThreshold() int64 {
+func (m *UpdatableProjectFields) GetClientDeactivateThreshold() *types.StringValue {
 	if m != nil {
 		return m.ClientDeactivateThreshold
 	}
-	return 0
+	return nil
 }
 
 type UpdatableProjectFields_AuthWebhookMethods struct {
@@ -2786,146 +2786,146 @@ func init() {
 func init() { proto.RegisterFile("yorkie/v1/resources.proto", fileDescriptor_36361b2f5d0f0896) }
 
 var fileDescriptor_36361b2f5d0f0896 = []byte{
-	// 2214 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x59, 0xdd, 0x8f, 0xdb, 0x58,
-	0x15, 0x8f, 0x1d, 0xe7, 0xc3, 0x27, 0xb3, 0x9d, 0xf4, 0x4e, 0x3f, 0xd2, 0xb4, 0x9d, 0x9d, 0xa6,
-	0x50, 0x66, 0x5b, 0xc8, 0xb4, 0x43, 0xbb, 0xc0, 0x56, 0x8b, 0xf0, 0x24, 0xde, 0x66, 0xba, 0xd3,
-	0xcc, 0xc8, 0xc9, 0x74, 0x69, 0x25, 0x64, 0x79, 0xec, 0xdb, 0x8e, 0x77, 0x12, 0xdb, 0x6b, 0x3b,
-	0xd9, 0xe6, 0x81, 0x17, 0x04, 0x6f, 0xf0, 0xce, 0x1f, 0x80, 0xc4, 0xdf, 0xb0, 0x4f, 0x48, 0x3c,
-	0x20, 0xde, 0x00, 0x81, 0xc4, 0x2b, 0x74, 0x1f, 0x10, 0xbc, 0x01, 0x12, 0x6f, 0x48, 0xe8, 0xde,
-	0x6b, 0x3b, 0x8e, 0xe3, 0xa4, 0x69, 0x18, 0xa1, 0x2e, 0x6f, 0xbe, 0xf7, 0xfe, 0xce, 0xb9, 0xe7,
-	0xf3, 0x9e, 0xe3, 0x7b, 0xe1, 0xd2, 0xc8, 0x76, 0x4f, 0x4c, 0xbc, 0x35, 0xbc, 0xb3, 0xe5, 0x62,
-	0xcf, 0x1e, 0xb8, 0x3a, 0xf6, 0xea, 0x8e, 0x6b, 0xfb, 0x36, 0x12, 0xd9, 0x52, 0x7d, 0x78, 0xa7,
-	0xfa, 0xf6, 0x73, 0xdb, 0x7e, 0xde, 0xc3, 0x5b, 0x74, 0xe1, 0x68, 0xf0, 0x6c, 0xcb, 0x37, 0xfb,
-	0xd8, 0xf3, 0xb5, 0xbe, 0xc3, 0xb0, 0xd5, 0xf5, 0x24, 0xe0, 0x53, 0x57, 0x73, 0x1c, 0xec, 0x06,
-	0xbc, 0x6a, 0xff, 0xe0, 0x00, 0x1a, 0xc7, 0x9a, 0xf5, 0x1c, 0x1f, 0x68, 0xfa, 0x09, 0xba, 0x06,
-	0x2b, 0x86, 0xad, 0x0f, 0xfa, 0xd8, 0xf2, 0xd5, 0x13, 0x3c, 0xaa, 0x70, 0x1b, 0xdc, 0xa6, 0xa8,
-	0x94, 0xc2, 0xb9, 0x0f, 0xf1, 0x08, 0xdd, 0x03, 0xd0, 0x8f, 0xb1, 0x7e, 0xe2, 0xd8, 0xa6, 0xe5,
-	0x57, 0xf8, 0x0d, 0x6e, 0xb3, 0xb4, 0x7d, 0xbe, 0x1e, 0x89, 0x54, 0x6f, 0x44, 0x8b, 0x4a, 0x0c,
-	0x88, 0xaa, 0x50, 0xf4, 0x2c, 0xcd, 0xf1, 0x8e, 0x6d, 0xbf, 0x92, 0xdd, 0xe0, 0x36, 0x57, 0x94,
-	0x68, 0x8c, 0x6e, 0x41, 0x41, 0xa7, 0x32, 0x78, 0x15, 0x61, 0x23, 0xbb, 0x59, 0xda, 0x3e, 0x3b,
-	0xc1, 0x8f, 0xac, 0x28, 0x21, 0x02, 0x49, 0x70, 0xb6, 0x6f, 0x5a, 0xaa, 0x37, 0xb2, 0x74, 0x6c,
-	0xa8, 0xbe, 0xa9, 0x9f, 0x60, 0xbf, 0x92, 0x9b, 0x12, 0xa3, 0x6b, 0xf6, 0x71, 0x97, 0x2e, 0x2a,
-	0xab, 0x7d, 0xd3, 0xea, 0x50, 0x38, 0x9b, 0xa8, 0x7d, 0x1f, 0xf2, 0x8c, 0x2b, 0xba, 0x0e, 0xbc,
-	0x69, 0x50, 0x2d, 0x4b, 0xdb, 0x6b, 0x53, 0x9b, 0xee, 0x36, 0x15, 0xde, 0x34, 0x50, 0x05, 0x0a,
-	0x7d, 0xec, 0x79, 0xda, 0x73, 0x4c, 0xd5, 0x15, 0x95, 0x70, 0x88, 0xee, 0x02, 0xd8, 0x0e, 0x76,
-	0x35, 0xdf, 0xb4, 0x2d, 0xaf, 0x92, 0xa5, 0xb2, 0x9f, 0x8b, 0xb1, 0xd9, 0x0f, 0x17, 0x95, 0x18,
-	0xae, 0xf6, 0x23, 0x0e, 0x8a, 0xe1, 0x06, 0xe8, 0x2a, 0x80, 0xde, 0x33, 0x89, 0xbd, 0x3d, 0xfc,
-	0x09, 0x95, 0xe4, 0x2d, 0x45, 0x64, 0x33, 0x1d, 0xfc, 0x09, 0xba, 0x06, 0xe0, 0x61, 0x77, 0x88,
-	0x5d, 0xba, 0x4c, 0xb6, 0xcf, 0xee, 0xf0, 0xb7, 0x39, 0x45, 0x64, 0xb3, 0x04, 0x72, 0x05, 0x0a,
-	0x3d, 0xad, 0xef, 0xd8, 0x2e, 0x33, 0x2c, 0x5b, 0x0f, 0xa7, 0xd0, 0x25, 0x28, 0x6a, 0xba, 0x6f,
-	0xbb, 0xaa, 0x69, 0x54, 0x04, 0x6a, 0xf7, 0x02, 0x1d, 0xef, 0x1a, 0xb5, 0xcf, 0xcf, 0x81, 0x18,
-	0x49, 0x88, 0xbe, 0x0a, 0x59, 0x0f, 0xfb, 0x81, 0x2d, 0x2a, 0x69, 0x4a, 0xd4, 0x3b, 0xd8, 0x6f,
-	0x65, 0x14, 0x02, 0x23, 0x68, 0xcd, 0x30, 0x02, 0xf7, 0xa7, 0xa3, 0x25, 0xc3, 0x20, 0x68, 0xcd,
-	0x30, 0xd0, 0x16, 0x08, 0x7d, 0x7b, 0x88, 0xa9, 0x7c, 0xa5, 0xed, 0x4b, 0xa9, 0xf0, 0x47, 0xf6,
-	0x10, 0xb7, 0x32, 0x0a, 0x05, 0xa2, 0x7b, 0x90, 0x77, 0x31, 0x25, 0x11, 0x28, 0xc9, 0xe5, 0x54,
-	0x12, 0x85, 0x42, 0x5a, 0x19, 0x25, 0x00, 0x93, 0x7d, 0xb0, 0x61, 0x86, 0xe1, 0x90, 0xbe, 0x8f,
-	0x6c, 0x98, 0x44, 0x0b, 0x0a, 0x24, 0xfb, 0x78, 0xb8, 0x87, 0x75, 0xbf, 0x92, 0x9f, 0xb3, 0x4f,
-	0x87, 0x42, 0xc8, 0x3e, 0x0c, 0x8c, 0xb6, 0x21, 0xe7, 0xf9, 0xa3, 0x1e, 0xae, 0x14, 0x28, 0x55,
-	0x35, 0x9d, 0x8a, 0x20, 0x5a, 0x19, 0x85, 0x41, 0xd1, 0x7d, 0x28, 0x9a, 0x96, 0xee, 0x62, 0xcd,
-	0xc3, 0x95, 0x22, 0x25, 0xbb, 0x9a, 0x4a, 0xb6, 0x1b, 0x80, 0x5a, 0x19, 0x25, 0x22, 0xa8, 0xfe,
-	0x8a, 0x83, 0x6c, 0x07, 0xfb, 0x24, 0xf8, 0x1d, 0xcd, 0x25, 0xd1, 0x42, 0x16, 0x7c, 0x6c, 0xa8,
-	0x5a, 0xe8, 0xb2, 0x59, 0xc1, 0xcf, 0xf0, 0x0d, 0x06, 0x97, 0x7c, 0x54, 0x86, 0x2c, 0xc9, 0x6c,
-	0x16, 0xc9, 0xe4, 0x93, 0x68, 0x33, 0xd4, 0x7a, 0x83, 0xd0, 0x3d, 0x57, 0x62, 0x8c, 0x1e, 0x76,
-	0xf6, 0xdb, 0x72, 0x0f, 0x93, 0xdc, 0xef, 0x98, 0x7d, 0xa7, 0x87, 0x15, 0x06, 0x45, 0xef, 0x42,
-	0x09, 0xbf, 0xc0, 0xfa, 0x20, 0x10, 0x41, 0x98, 0x27, 0x02, 0x84, 0x48, 0xc9, 0xaf, 0xfe, 0x93,
-	0x83, 0xac, 0x64, 0x18, 0xa7, 0xa1, 0xc8, 0xfb, 0xb0, 0xea, 0xb8, 0x78, 0x18, 0x67, 0xc0, 0xcf,
-	0x63, 0xf0, 0x16, 0x41, 0x8f, 0xc9, 0xff, 0x97, 0x5a, 0xff, 0x8b, 0x03, 0x81, 0xc4, 0xf7, 0x1b,
-	0xa0, 0xf6, 0x5d, 0x80, 0x18, 0x65, 0x76, 0x1e, 0xa5, 0xa8, 0x47, 0x54, 0xcb, 0x2a, 0xfe, 0x19,
-	0x07, 0x79, 0x96, 0xa5, 0xa7, 0xa1, 0xfa, 0xa4, 0xec, 0xfc, 0x72, 0xb2, 0x67, 0x17, 0x95, 0xfd,
-	0x97, 0x02, 0x08, 0xe4, 0xb0, 0x38, 0x0d, 0xc9, 0x6f, 0x82, 0xf0, 0xcc, 0xb5, 0xfb, 0x81, 0xcc,
-	0x17, 0xe2, 0x54, 0xf8, 0x85, 0xdf, 0xb6, 0x0d, 0x7c, 0x60, 0x7b, 0x0a, 0xc5, 0xa0, 0x1b, 0xc0,
-	0xfb, 0x76, 0x20, 0xe6, 0x2c, 0x24, 0xef, 0xdb, 0xe8, 0x18, 0x2e, 0x8e, 0xe5, 0x51, 0xfb, 0x9a,
-	0xa3, 0x1e, 0x8d, 0x54, 0x7a, 0xb6, 0x07, 0x55, 0x74, 0x7b, 0xe6, 0xf9, 0x57, 0x8f, 0x24, 0x7b,
-	0xa4, 0x39, 0x3b, 0x23, 0x89, 0x10, 0xc9, 0x96, 0xef, 0x8e, 0x94, 0x35, 0x7d, 0x7a, 0x85, 0x14,
-	0x40, 0xdd, 0xb6, 0x7c, 0x6c, 0xb1, 0x93, 0x55, 0x54, 0xc2, 0x61, 0xd2, 0xb6, 0xf9, 0x05, 0x6d,
-	0x8b, 0x76, 0x01, 0x34, 0xdf, 0x77, 0xcd, 0xa3, 0x81, 0x8f, 0xbd, 0x4a, 0x81, 0x8a, 0xfb, 0xce,
-	0x6c, 0x71, 0xa5, 0x08, 0xcb, 0xa4, 0x8c, 0x11, 0x57, 0xbf, 0x07, 0x95, 0x59, 0xda, 0x84, 0x67,
-	0x1d, 0x37, 0x3e, 0xeb, 0x6e, 0x85, 0x59, 0x3f, 0x37, 0x7a, 0x18, 0xe6, 0x3d, 0xfe, 0x9b, 0x5c,
-	0xf5, 0x7d, 0x58, 0x4d, 0xec, 0x9e, 0xc2, 0xf5, 0x5c, 0x9c, 0xab, 0x18, 0x27, 0xff, 0x23, 0x07,
-	0x79, 0x56, 0x3e, 0xde, 0xd4, 0x30, 0x5a, 0x36, 0xb5, 0xff, 0xcc, 0x43, 0x8e, 0x96, 0xb8, 0x37,
-	0x55, 0xb1, 0x87, 0x13, 0x31, 0xc6, 0x52, 0xe2, 0xe6, 0xec, 0x4a, 0x3d, 0x2f, 0xc8, 0x92, 0x46,
-	0xca, 0x2d, 0x6a, 0xa4, 0xff, 0x32, 0x7a, 0x3e, 0xe3, 0xa0, 0x18, 0xf6, 0x03, 0xa7, 0x61, 0xe6,
-	0xed, 0xc9, 0xe8, 0x5f, 0xa6, 0xe6, 0x2d, 0x7a, 0x7c, 0xee, 0xe4, 0x41, 0x38, 0xb2, 0x8d, 0x51,
-	0xed, 0xef, 0x1c, 0x9c, 0x9d, 0x62, 0x9e, 0x38, 0xca, 0xb9, 0x05, 0x8f, 0xf2, 0xdb, 0x50, 0x24,
-	0xb5, 0xe4, 0xd5, 0xc7, 0x7f, 0x81, 0xc2, 0x58, 0xc9, 0x60, 0xbd, 0xe1, 0x02, 0xe5, 0x2e, 0x00,
-	0x4a, 0x3e, 0xda, 0x04, 0xc1, 0x1f, 0x39, 0xac, 0xf9, 0x3c, 0x33, 0xd1, 0xd1, 0x3f, 0x26, 0x36,
-	0xe9, 0x8e, 0x1c, 0xac, 0x50, 0xc4, 0xd8, 0x77, 0x39, 0xda, 0x5b, 0xb3, 0x41, 0xed, 0x67, 0x25,
-	0x28, 0xc5, 0x74, 0x46, 0x4d, 0x28, 0x7d, 0xec, 0xd9, 0x96, 0x6a, 0x1f, 0x7d, 0x4c, 0x7a, 0x4d,
-	0xa6, 0xee, 0xb5, 0x74, 0xeb, 0xd3, 0xef, 0x7d, 0x0a, 0x6c, 0x65, 0x14, 0x20, 0x74, 0x6c, 0x84,
-	0x24, 0xa0, 0x23, 0x55, 0x73, 0x5d, 0x6d, 0x14, 0xe8, 0xbf, 0x31, 0x87, 0x89, 0x44, 0x70, 0xad,
-	0x8c, 0x22, 0x12, 0x2a, 0x3a, 0x40, 0xdf, 0x01, 0xd1, 0x71, 0xcd, 0xbe, 0xe9, 0x9b, 0x51, 0x37,
-	0x3e, 0x8b, 0xc3, 0x41, 0x88, 0x23, 0x1c, 0x22, 0x22, 0x74, 0x07, 0x04, 0x1f, 0xbf, 0x08, 0x53,
-	0xe0, 0xf2, 0x0c, 0x62, 0x92, 0x8b, 0xa4, 0xc9, 0x26, 0x50, 0xf4, 0x1e, 0x29, 0x1f, 0x03, 0xcb,
-	0xc7, 0x6e, 0x50, 0x20, 0xd6, 0x67, 0x50, 0x35, 0x18, 0xaa, 0x95, 0x51, 0x42, 0x82, 0xea, 0x1f,
-	0x38, 0x80, 0xb1, 0x41, 0xd0, 0x26, 0xe4, 0x2c, 0xdb, 0xc0, 0x5e, 0x85, 0xa3, 0xe9, 0x8c, 0x62,
-	0x8c, 0x94, 0x56, 0x97, 0x64, 0xbf, 0xc2, 0x00, 0x4b, 0xf6, 0x0a, 0xf1, 0x00, 0xcb, 0x2e, 0x11,
-	0x60, 0xc2, 0x62, 0x01, 0x56, 0xfd, 0x3d, 0x07, 0x62, 0xe4, 0xa2, 0xb9, 0x5a, 0x3d, 0x90, 0xbe,
-	0x38, 0x5a, 0xfd, 0x95, 0x03, 0x31, 0x0a, 0x9b, 0x28, 0x89, 0xb8, 0xc5, 0x93, 0x88, 0x8f, 0x25,
-	0xd1, 0x92, 0x9d, 0x6a, 0x5c, 0x57, 0x61, 0x09, 0x5d, 0x73, 0x0b, 0xea, 0xfa, 0x1b, 0x0e, 0x04,
-	0x12, 0xe5, 0xe8, 0x9d, 0x49, 0xe7, 0xad, 0xa5, 0x54, 0xa4, 0x2f, 0x86, 0xf7, 0xfe, 0xc2, 0x41,
-	0x21, 0xc8, 0xc0, 0xff, 0x6f, 0xdf, 0x45, 0xa5, 0xe9, 0x11, 0x14, 0x82, 0x53, 0x23, 0xa5, 0x2a,
-	0xdf, 0x86, 0x02, 0x66, 0xe7, 0x52, 0x4a, 0x57, 0x12, 0x3b, 0xb5, 0x94, 0x10, 0x56, 0xd3, 0xa1,
-	0x10, 0xa4, 0x2b, 0xba, 0x01, 0x82, 0x45, 0x4e, 0x49, 0x76, 0xd2, 0xa7, 0x25, 0x34, 0x5d, 0x5f,
-	0x62, 0x93, 0xa7, 0xb0, 0x12, 0x86, 0x15, 0xe9, 0x2c, 0xc6, 0xf6, 0xe7, 0x62, 0xcd, 0x03, 0xb1,
-	0xcb, 0xc0, 0x31, 0x16, 0x8b, 0xb4, 0x00, 0x28, 0xf9, 0xb5, 0xdf, 0xf1, 0x50, 0x0c, 0x99, 0xa3,
-	0x2f, 0xc7, 0xae, 0xc6, 0xce, 0xa7, 0x04, 0x75, 0x70, 0x39, 0x96, 0xda, 0xbc, 0x2c, 0x59, 0x76,
-	0xef, 0x41, 0xc9, 0xb4, 0x3c, 0x95, 0xfe, 0xde, 0x06, 0xd7, 0x55, 0x33, 0xf7, 0x16, 0x4d, 0xcb,
-	0x3b, 0x70, 0xf1, 0x70, 0xd7, 0x40, 0x8d, 0x89, 0x46, 0x2f, 0x47, 0xd3, 0xf0, 0x7a, 0x0a, 0xd5,
-	0xdc, 0xdf, 0x88, 0xc7, 0x8b, 0x74, 0x6a, 0x5f, 0x9b, 0xec, 0x9f, 0x2e, 0xa6, 0x6c, 0x42, 0x98,
-	0xc4, 0x5a, 0xb8, 0xda, 0x53, 0x80, 0xb1, 0xd4, 0x4b, 0xb6, 0x3d, 0x17, 0x20, 0x6f, 0x3f, 0x7b,
-	0xe6, 0x61, 0xe6, 0xc9, 0x9c, 0x12, 0x8c, 0x6a, 0x7d, 0x10, 0x0e, 0x3d, 0xec, 0xa2, 0x33, 0x91,
-	0xab, 0x44, 0xea, 0x93, 0x2a, 0x14, 0x07, 0x1e, 0x76, 0x2d, 0xad, 0x1f, 0xba, 0x25, 0x1a, 0xa3,
-	0x6f, 0xa5, 0x64, 0x66, 0xb5, 0xce, 0x6e, 0x89, 0xeb, 0xe1, 0x2d, 0x31, 0x95, 0x83, 0x5e, 0x23,
-	0xc7, 0xc4, 0xa8, 0xfd, 0x9b, 0x87, 0xc2, 0x81, 0x6b, 0xd3, 0x42, 0x9c, 0xdc, 0x12, 0x81, 0x10,
-	0xdb, 0x8e, 0x7e, 0xa3, 0xab, 0x00, 0xce, 0xe0, 0xa8, 0x67, 0xea, 0xf4, 0x2a, 0x39, 0x4b, 0x57,
-	0x44, 0x36, 0xf3, 0x21, 0x1e, 0x91, 0x65, 0x0f, 0xeb, 0x2e, 0x66, 0x37, 0xcd, 0x02, 0x5b, 0x66,
-	0x33, 0x64, 0x79, 0x13, 0xca, 0xda, 0xc0, 0x3f, 0x56, 0x3f, 0xc5, 0x47, 0xc7, 0xb6, 0x7d, 0xa2,
-	0x0e, 0xdc, 0x5e, 0xf0, 0xf7, 0x79, 0x86, 0xcc, 0x7f, 0xc4, 0xa6, 0x0f, 0xdd, 0x1e, 0xba, 0x0d,
-	0xe7, 0x26, 0x90, 0x7d, 0xec, 0x1f, 0xdb, 0x86, 0x57, 0xc9, 0x6f, 0x64, 0x37, 0x45, 0x05, 0xc5,
-	0xd0, 0x8f, 0xd8, 0x0a, 0xfa, 0x36, 0x5c, 0x0e, 0x2e, 0x5d, 0x0d, 0xac, 0xe9, 0xbe, 0x39, 0xd4,
-	0x7c, 0xac, 0xfa, 0xc7, 0x2e, 0xf6, 0x8e, 0xed, 0x9e, 0x41, 0x6f, 0xf5, 0xb2, 0xca, 0x25, 0x06,
-	0x69, 0x46, 0x88, 0x6e, 0x08, 0x48, 0x18, 0xb1, 0xf8, 0x1a, 0x46, 0x24, 0xa4, 0xb1, 0xcc, 0x14,
-	0x5f, 0x4d, 0x3a, 0x4e, 0xcf, 0xbf, 0xf1, 0x70, 0xe1, 0x90, 0x8c, 0xb4, 0xa3, 0x1e, 0x0e, 0x1c,
-	0xf1, 0x81, 0x89, 0x7b, 0x86, 0x87, 0x6e, 0x07, 0xe6, 0xe7, 0x82, 0xbe, 0x3e, 0xc9, 0xaf, 0xe3,
-	0xbb, 0xa6, 0xf5, 0x9c, 0x9e, 0xdd, 0x81, 0x73, 0x3e, 0x48, 0x31, 0x2f, 0xbf, 0x00, 0x75, 0xd2,
-	0xf8, 0xcf, 0x66, 0x18, 0x9f, 0x45, 0xd6, 0xdd, 0x58, 0x6c, 0xa7, 0x8b, 0x5e, 0x97, 0xa6, 0xdc,
-	0xb3, 0x8c, 0xcb, 0x84, 0x57, 0xb8, 0xac, 0x5a, 0x07, 0x34, 0xbd, 0x13, 0xbb, 0xda, 0x67, 0x02,
-	0x73, 0x34, 0x5a, 0xc2, 0x61, 0xed, 0x07, 0x3c, 0xac, 0x36, 0x83, 0x67, 0x8f, 0xce, 0xa0, 0xdf,
-	0xd7, 0xdc, 0xd1, 0x54, 0xd0, 0x4f, 0x5f, 0xa5, 0x26, 0x5f, 0x39, 0xc4, 0xd8, 0x2b, 0xc7, 0x64,
-	0xd0, 0x08, 0xaf, 0x13, 0x34, 0xf7, 0xa1, 0xa4, 0xe9, 0x3a, 0xf6, 0xbc, 0x78, 0x9d, 0x9b, 0x47,
-	0x0b, 0x21, 0x7c, 0x2a, 0xe2, 0xf2, 0xaf, 0x13, 0x71, 0x3f, 0xe6, 0xa0, 0x78, 0xe0, 0x62, 0x0f,
-	0x5b, 0x3a, 0xad, 0xf4, 0x7a, 0xcf, 0xd6, 0x4f, 0xa8, 0x01, 0x72, 0x0a, 0x1b, 0x90, 0xff, 0x01,
-	0xe2, 0xd6, 0x0a, 0x4f, 0x8f, 0xdd, 0xf8, 0x95, 0x76, 0x48, 0x58, 0x6f, 0x6a, 0xbe, 0xc6, 0x0e,
-	0x5c, 0x0a, 0xad, 0x7e, 0x03, 0xc4, 0x68, 0xea, 0x75, 0x7e, 0x87, 0x6b, 0xbb, 0x90, 0x6f, 0x50,
-	0x07, 0xc7, 0x3c, 0xb1, 0x42, 0x3d, 0xb1, 0x05, 0x45, 0x27, 0xd8, 0x2e, 0x88, 0xe2, 0xb5, 0x14,
-	0x49, 0x94, 0x08, 0x54, 0x7b, 0x17, 0x0a, 0x8c, 0x95, 0x47, 0x5f, 0x9f, 0xd8, 0x67, 0xd0, 0xc2,
-	0x4d, 0xbc, 0x3e, 0xd1, 0x15, 0x25, 0x44, 0xd4, 0xda, 0x00, 0xe3, 0x07, 0xae, 0xc4, 0xeb, 0x0c,
-	0x97, 0xf6, 0x3a, 0x33, 0xf9, 0xbe, 0xc3, 0x27, 0xde, 0x77, 0x6a, 0x3f, 0xe4, 0xa0, 0x14, 0xbb,
-	0xb8, 0x38, 0xdd, 0x02, 0x81, 0xbe, 0x02, 0xab, 0x2e, 0xee, 0x69, 0xa4, 0x1d, 0x57, 0x03, 0x40,
-	0x96, 0x02, 0xce, 0x84, 0xd3, 0xfb, 0xac, 0x92, 0xe8, 0x00, 0x63, 0xce, 0xf1, 0x17, 0x25, 0x6e,
-	0xfa, 0x45, 0xe9, 0x0a, 0x88, 0x06, 0xee, 0x91, 0x2e, 0x1f, 0xbb, 0xa1, 0x42, 0xd1, 0xc4, 0xc4,
-	0x7b, 0x53, 0x76, 0xf2, 0xbd, 0xe9, 0x27, 0x1c, 0x14, 0x9b, 0xb6, 0x2e, 0x0f, 0x89, 0x07, 0x6f,
-	0x4d, 0x74, 0x98, 0xf1, 0x4a, 0x1a, 0x42, 0x62, 0x4d, 0xe6, 0x16, 0xb0, 0xba, 0xe1, 0x1d, 0x07,
-	0x5b, 0xa6, 0x3a, 0x69, 0x8c, 0x41, 0xd7, 0xe1, 0xad, 0xf8, 0x3b, 0x26, 0x7b, 0x9b, 0x13, 0x95,
-	0x95, 0xd8, 0x43, 0xa6, 0x77, 0xf3, 0x17, 0x3c, 0x88, 0x51, 0x3b, 0x8b, 0xd6, 0x60, 0xf5, 0xb1,
-	0xb4, 0x77, 0x28, 0xab, 0xdd, 0x27, 0x07, 0xb2, 0xda, 0x3e, 0xdc, 0xdb, 0x2b, 0x67, 0xd0, 0x05,
-	0x40, 0xb1, 0xc9, 0x9d, 0xfd, 0xfd, 0x3d, 0x59, 0x6a, 0x97, 0xb9, 0xc4, 0xfc, 0x6e, 0xbb, 0x2b,
-	0x3f, 0x90, 0x95, 0x32, 0x9f, 0x60, 0xb2, 0xb7, 0xdf, 0x7e, 0x50, 0xce, 0xa2, 0xf3, 0x70, 0x36,
-	0x36, 0xd9, 0xdc, 0x3f, 0xdc, 0xd9, 0x93, 0xcb, 0x42, 0x62, 0xba, 0xd3, 0x55, 0x76, 0xdb, 0x0f,
-	0xca, 0x39, 0x74, 0x0e, 0xca, 0xf1, 0x2d, 0x9f, 0x74, 0xe5, 0x4e, 0x39, 0x9f, 0x60, 0xdc, 0x94,
-	0xba, 0x72, 0xb9, 0x80, 0xaa, 0x70, 0x21, 0x36, 0x49, 0xda, 0x45, 0x75, 0x7f, 0xe7, 0xa1, 0xdc,
-	0xe8, 0x96, 0x8b, 0xe8, 0x12, 0x9c, 0x4f, 0xae, 0x49, 0x8a, 0x22, 0x3d, 0x29, 0x8b, 0x09, 0x5e,
-	0x5d, 0xf9, 0xbb, 0xdd, 0x32, 0x24, 0x78, 0x05, 0x1a, 0xa9, 0x8d, 0x76, 0xb7, 0x5c, 0x42, 0x17,
-	0x61, 0x2d, 0xa1, 0x15, 0x5d, 0x58, 0xb9, 0xf9, 0x73, 0x0e, 0x56, 0xe2, 0xee, 0x42, 0x5f, 0x82,
-	0x8d, 0xe6, 0x7e, 0x43, 0x95, 0x1f, 0xcb, 0xed, 0x6e, 0xa8, 0x6e, 0xe3, 0xf0, 0x91, 0xdc, 0xee,
-	0x76, 0xd4, 0x46, 0x4b, 0x6a, 0x3f, 0x90, 0x9b, 0xe5, 0xcc, 0x5c, 0xd4, 0x47, 0x52, 0xb7, 0xd1,
-	0x92, 0x9b, 0x65, 0x0e, 0xdd, 0x80, 0xda, 0x4c, 0xd4, 0x61, 0x3b, 0xc4, 0xf1, 0xe8, 0x3a, 0xbc,
-	0x9d, 0xc0, 0x1d, 0x28, 0x72, 0x47, 0x6e, 0x37, 0xe4, 0x68, 0xcb, 0xec, 0xce, 0xad, 0x5f, 0xbf,
-	0x5c, 0xe7, 0x7e, 0xfb, 0x72, 0x9d, 0xfb, 0xd3, 0xcb, 0x75, 0xee, 0xa7, 0x9f, 0xaf, 0x67, 0xe0,
-	0xac, 0x81, 0x87, 0x61, 0x0c, 0x69, 0x8e, 0x59, 0x1f, 0xde, 0x39, 0xe0, 0x9e, 0x0a, 0xf5, 0xfb,
-	0xc3, 0x3b, 0x47, 0x79, 0x7a, 0x2a, 0x7e, 0xfd, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x58, 0xfb,
-	0xda, 0x75, 0x84, 0x1f, 0x00, 0x00,
+	// 2222 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x59, 0xdf, 0x8f, 0xdb, 0x58,
+	0xf5, 0x8f, 0x1d, 0xe7, 0x87, 0x4f, 0xa6, 0x9d, 0xf4, 0x4e, 0x7f, 0xa4, 0x69, 0x3b, 0x3b, 0x4d,
+	0xbf, 0xdf, 0x32, 0xdb, 0x42, 0xa6, 0x1d, 0xda, 0x05, 0xb6, 0x5a, 0x84, 0x27, 0xf1, 0x36, 0xd3,
+	0x9d, 0x66, 0x46, 0x4e, 0xa6, 0x4b, 0x2b, 0x90, 0xe5, 0xb1, 0x6f, 0x3b, 0xde, 0x49, 0x6c, 0xaf,
+	0xed, 0x64, 0x9b, 0x07, 0x5e, 0x10, 0x48, 0x3c, 0xc0, 0x3b, 0x7f, 0x00, 0x12, 0x7f, 0xc3, 0x3e,
+	0x21, 0xf1, 0x80, 0x78, 0x03, 0x04, 0x12, 0xaf, 0xd0, 0x7d, 0x40, 0x3c, 0x02, 0x12, 0x6f, 0x48,
+	0xe8, 0xde, 0x6b, 0x3b, 0x8e, 0xe3, 0x64, 0xd3, 0x30, 0x42, 0x5d, 0xde, 0x7c, 0xef, 0xfd, 0x9c,
+	0x73, 0xcf, 0xcf, 0x7b, 0x8e, 0xef, 0x85, 0xcb, 0x23, 0xdb, 0x3d, 0x31, 0xf1, 0xd6, 0xf0, 0xee,
+	0x96, 0x8b, 0x3d, 0x7b, 0xe0, 0xea, 0xd8, 0xab, 0x3b, 0xae, 0xed, 0xdb, 0x48, 0x64, 0x4b, 0xf5,
+	0xe1, 0xdd, 0xea, 0x5b, 0x2f, 0x6c, 0xfb, 0x45, 0x0f, 0x6f, 0xd1, 0x85, 0xa3, 0xc1, 0xf3, 0x2d,
+	0xdf, 0xec, 0x63, 0xcf, 0xd7, 0xfa, 0x0e, 0xc3, 0x56, 0xd7, 0x93, 0x80, 0x4f, 0x5c, 0xcd, 0x71,
+	0xb0, 0x1b, 0xf0, 0xaa, 0xfd, 0x9d, 0x03, 0x68, 0x1c, 0x6b, 0xd6, 0x0b, 0x7c, 0xa0, 0xe9, 0x27,
+	0xe8, 0x3a, 0xac, 0x18, 0xb6, 0x3e, 0xe8, 0x63, 0xcb, 0x57, 0x4f, 0xf0, 0xa8, 0xc2, 0x6d, 0x70,
+	0x9b, 0xa2, 0x52, 0x0a, 0xe7, 0x3e, 0xc0, 0x23, 0x74, 0x1f, 0x40, 0x3f, 0xc6, 0xfa, 0x89, 0x63,
+	0x9b, 0x96, 0x5f, 0xe1, 0x37, 0xb8, 0xcd, 0xd2, 0xf6, 0x85, 0x7a, 0x24, 0x52, 0xbd, 0x11, 0x2d,
+	0x2a, 0x31, 0x20, 0xaa, 0x42, 0xd1, 0xb3, 0x34, 0xc7, 0x3b, 0xb6, 0xfd, 0x4a, 0x76, 0x83, 0xdb,
+	0x5c, 0x51, 0xa2, 0x31, 0xba, 0x0d, 0x05, 0x9d, 0xca, 0xe0, 0x55, 0x84, 0x8d, 0xec, 0x66, 0x69,
+	0xfb, 0xdc, 0x04, 0x3f, 0xb2, 0xa2, 0x84, 0x08, 0x24, 0xc1, 0xb9, 0xbe, 0x69, 0xa9, 0xde, 0xc8,
+	0xd2, 0xb1, 0xa1, 0xfa, 0xa6, 0x7e, 0x82, 0xfd, 0x4a, 0x6e, 0x4a, 0x8c, 0xae, 0xd9, 0xc7, 0x5d,
+	0xba, 0xa8, 0xac, 0xf6, 0x4d, 0xab, 0x43, 0xe1, 0x6c, 0xa2, 0xf6, 0x3d, 0xc8, 0x33, 0xae, 0xe8,
+	0x06, 0xf0, 0xa6, 0x41, 0xb5, 0x2c, 0x6d, 0xaf, 0x4d, 0x6d, 0xba, 0xdb, 0x54, 0x78, 0xd3, 0x40,
+	0x15, 0x28, 0xf4, 0xb1, 0xe7, 0x69, 0x2f, 0x30, 0x55, 0x57, 0x54, 0xc2, 0x21, 0xba, 0x07, 0x60,
+	0x3b, 0xd8, 0xd5, 0x7c, 0xd3, 0xb6, 0xbc, 0x4a, 0x96, 0xca, 0x7e, 0x3e, 0xc6, 0x66, 0x3f, 0x5c,
+	0x54, 0x62, 0xb8, 0xda, 0x0f, 0x39, 0x28, 0x86, 0x1b, 0xa0, 0x6b, 0x00, 0x7a, 0xcf, 0x24, 0xf6,
+	0xf6, 0xf0, 0xc7, 0x54, 0x92, 0x33, 0x8a, 0xc8, 0x66, 0x3a, 0xf8, 0x63, 0x74, 0x1d, 0xc0, 0xc3,
+	0xee, 0x10, 0xbb, 0x74, 0x99, 0x6c, 0x9f, 0xdd, 0xe1, 0xef, 0x70, 0x8a, 0xc8, 0x66, 0x09, 0xe4,
+	0x2a, 0x14, 0x7a, 0x5a, 0xdf, 0xb1, 0x5d, 0x66, 0x58, 0xb6, 0x1e, 0x4e, 0xa1, 0xcb, 0x50, 0xd4,
+	0x74, 0xdf, 0x76, 0x55, 0xd3, 0xa8, 0x08, 0xd4, 0xee, 0x05, 0x3a, 0xde, 0x35, 0x6a, 0x9f, 0x9d,
+	0x07, 0x31, 0x92, 0x10, 0x7d, 0x19, 0xb2, 0x1e, 0xf6, 0x03, 0x5b, 0x54, 0xd2, 0x94, 0xa8, 0x77,
+	0xb0, 0xdf, 0xca, 0x28, 0x04, 0x46, 0xd0, 0x9a, 0x61, 0x04, 0xee, 0x4f, 0x47, 0x4b, 0x86, 0x41,
+	0xd0, 0x9a, 0x61, 0xa0, 0x2d, 0x10, 0xfa, 0xf6, 0x10, 0x53, 0xf9, 0x4a, 0xdb, 0x97, 0x53, 0xe1,
+	0x8f, 0xed, 0x21, 0x6e, 0x65, 0x14, 0x0a, 0x44, 0xf7, 0x21, 0xef, 0x62, 0x4a, 0x22, 0x50, 0x92,
+	0x2b, 0xa9, 0x24, 0x0a, 0x85, 0xb4, 0x32, 0x4a, 0x00, 0x26, 0xfb, 0x60, 0xc3, 0x0c, 0xc3, 0x21,
+	0x7d, 0x1f, 0xd9, 0x30, 0x89, 0x16, 0x14, 0x48, 0xf6, 0xf1, 0x70, 0x0f, 0xeb, 0x7e, 0x25, 0x3f,
+	0x67, 0x9f, 0x0e, 0x85, 0x90, 0x7d, 0x18, 0x18, 0x6d, 0x43, 0xce, 0xf3, 0x47, 0x3d, 0x5c, 0x29,
+	0x50, 0xaa, 0x6a, 0x3a, 0x15, 0x41, 0xb4, 0x32, 0x0a, 0x83, 0xa2, 0x07, 0x50, 0x34, 0x2d, 0xdd,
+	0xc5, 0x9a, 0x87, 0x2b, 0x45, 0x4a, 0x76, 0x2d, 0x95, 0x6c, 0x37, 0x00, 0xb5, 0x32, 0x4a, 0x44,
+	0x50, 0xfd, 0x15, 0x07, 0xd9, 0x0e, 0xf6, 0x49, 0xf0, 0x3b, 0x9a, 0x4b, 0xa2, 0x85, 0x2c, 0xf8,
+	0xd8, 0x50, 0xb5, 0xd0, 0x65, 0xb3, 0x82, 0x9f, 0xe1, 0x1b, 0x0c, 0x2e, 0xf9, 0xa8, 0x0c, 0x59,
+	0x92, 0xd9, 0x2c, 0x92, 0xc9, 0x27, 0xd1, 0x66, 0xa8, 0xf5, 0x06, 0xa1, 0x7b, 0xae, 0xc6, 0x18,
+	0x3d, 0xea, 0xec, 0xb7, 0xe5, 0x1e, 0x26, 0xb9, 0xdf, 0x31, 0xfb, 0x4e, 0x0f, 0x2b, 0x0c, 0x8a,
+	0xde, 0x81, 0x12, 0x7e, 0x89, 0xf5, 0x41, 0x20, 0x82, 0x30, 0x4f, 0x04, 0x08, 0x91, 0x92, 0x5f,
+	0xfd, 0x07, 0x07, 0x59, 0xc9, 0x30, 0x4e, 0x43, 0x91, 0xf7, 0x60, 0xd5, 0x71, 0xf1, 0x30, 0xce,
+	0x80, 0x9f, 0xc7, 0xe0, 0x0c, 0x41, 0x8f, 0xc9, 0xff, 0x9b, 0x5a, 0xff, 0x93, 0x03, 0x81, 0xc4,
+	0xf7, 0x1b, 0xa0, 0xf6, 0x3d, 0x80, 0x18, 0x65, 0x76, 0x1e, 0xa5, 0xa8, 0x47, 0x54, 0xcb, 0x2a,
+	0xfe, 0x29, 0x07, 0x79, 0x96, 0xa5, 0xa7, 0xa1, 0xfa, 0xa4, 0xec, 0xfc, 0x72, 0xb2, 0x67, 0x17,
+	0x95, 0xfd, 0x97, 0x02, 0x08, 0xe4, 0xb0, 0x38, 0x0d, 0xc9, 0x6f, 0x81, 0xf0, 0xdc, 0xb5, 0xfb,
+	0x81, 0xcc, 0x17, 0xe3, 0x54, 0xf8, 0xa5, 0xdf, 0xb6, 0x0d, 0x7c, 0x60, 0x7b, 0x0a, 0xc5, 0xa0,
+	0x9b, 0xc0, 0xfb, 0x76, 0x20, 0xe6, 0x2c, 0x24, 0xef, 0xdb, 0xe8, 0x18, 0x2e, 0x8d, 0xe5, 0x51,
+	0xfb, 0x9a, 0xa3, 0x1e, 0x8d, 0x54, 0x7a, 0xb6, 0x07, 0x55, 0x74, 0x7b, 0xe6, 0xf9, 0x57, 0x8f,
+	0x24, 0x7b, 0xac, 0x39, 0x3b, 0x23, 0x89, 0x10, 0xc9, 0x96, 0xef, 0x8e, 0x94, 0x35, 0x7d, 0x7a,
+	0x85, 0x14, 0x40, 0xdd, 0xb6, 0x7c, 0x6c, 0xb1, 0x93, 0x55, 0x54, 0xc2, 0x61, 0xd2, 0xb6, 0xf9,
+	0x05, 0x6d, 0x8b, 0x76, 0x01, 0x34, 0xdf, 0x77, 0xcd, 0xa3, 0x81, 0x8f, 0xbd, 0x4a, 0x81, 0x8a,
+	0xfb, 0xf6, 0x6c, 0x71, 0xa5, 0x08, 0xcb, 0xa4, 0x8c, 0x11, 0x57, 0xbf, 0x0b, 0x95, 0x59, 0xda,
+	0x84, 0x67, 0x1d, 0x37, 0x3e, 0xeb, 0x6e, 0x87, 0x59, 0x3f, 0x37, 0x7a, 0x18, 0xe6, 0x5d, 0xfe,
+	0xeb, 0x5c, 0xf5, 0x3d, 0x58, 0x4d, 0xec, 0x9e, 0xc2, 0xf5, 0x7c, 0x9c, 0xab, 0x18, 0x27, 0xff,
+	0x23, 0x07, 0x79, 0x56, 0x3e, 0xde, 0xd4, 0x30, 0x5a, 0x36, 0xb5, 0xff, 0xcc, 0x43, 0x8e, 0x96,
+	0xb8, 0x37, 0x55, 0xb1, 0x47, 0x13, 0x31, 0xc6, 0x52, 0xe2, 0xd6, 0xec, 0x4a, 0x3d, 0x2f, 0xc8,
+	0x92, 0x46, 0xca, 0x2d, 0x6a, 0xa4, 0xff, 0x30, 0x7a, 0x3e, 0xe5, 0xa0, 0x18, 0xf6, 0x03, 0xa7,
+	0x61, 0xe6, 0xed, 0xc9, 0xe8, 0x5f, 0xa6, 0xe6, 0x2d, 0x7a, 0x7c, 0xee, 0xe4, 0x41, 0x38, 0xb2,
+	0x8d, 0x51, 0xed, 0x6f, 0x1c, 0x9c, 0x9b, 0x62, 0x9e, 0x38, 0xca, 0xb9, 0x05, 0x8f, 0xf2, 0x3b,
+	0x50, 0x24, 0xb5, 0xe4, 0xf3, 0x8f, 0xff, 0x02, 0x85, 0xb1, 0x92, 0xc1, 0x7a, 0xc3, 0x05, 0xca,
+	0x5d, 0x00, 0x94, 0x7c, 0xb4, 0x09, 0x82, 0x3f, 0x72, 0x58, 0xf3, 0x79, 0x76, 0xa2, 0xa3, 0x7f,
+	0x42, 0x6c, 0xd2, 0x1d, 0x39, 0x58, 0xa1, 0x88, 0xb1, 0xef, 0x72, 0xb4, 0xb7, 0x66, 0x83, 0xda,
+	0xcf, 0x4a, 0x50, 0x8a, 0xe9, 0x8c, 0x9a, 0x50, 0xfa, 0xc8, 0xb3, 0x2d, 0xd5, 0x3e, 0xfa, 0x88,
+	0xf4, 0x9a, 0x4c, 0xdd, 0xeb, 0xe9, 0xd6, 0xa7, 0xdf, 0xfb, 0x14, 0xd8, 0xca, 0x28, 0x40, 0xe8,
+	0xd8, 0x08, 0x49, 0x40, 0x47, 0xaa, 0xe6, 0xba, 0xda, 0x28, 0xd0, 0x7f, 0x63, 0x0e, 0x13, 0x89,
+	0xe0, 0x5a, 0x19, 0x45, 0x24, 0x54, 0x74, 0x80, 0xbe, 0x05, 0xa2, 0xe3, 0x9a, 0x7d, 0xd3, 0x37,
+	0xa3, 0x6e, 0x7c, 0x16, 0x87, 0x83, 0x10, 0x47, 0x38, 0x44, 0x44, 0xe8, 0x2e, 0x08, 0x3e, 0x7e,
+	0x19, 0xa6, 0xc0, 0x95, 0x19, 0xc4, 0x24, 0x17, 0x49, 0x93, 0x4d, 0xa0, 0xe8, 0x5d, 0x52, 0x3e,
+	0x06, 0x96, 0x8f, 0xdd, 0xa0, 0x40, 0xac, 0xcf, 0xa0, 0x6a, 0x30, 0x54, 0x2b, 0xa3, 0x84, 0x04,
+	0xd5, 0x3f, 0x70, 0x00, 0x63, 0x83, 0xa0, 0x4d, 0xc8, 0x59, 0xb6, 0x81, 0xbd, 0x0a, 0x47, 0xd3,
+	0x19, 0xc5, 0x18, 0x29, 0xad, 0x2e, 0xc9, 0x7e, 0x85, 0x01, 0x96, 0xec, 0x15, 0xe2, 0x01, 0x96,
+	0x5d, 0x22, 0xc0, 0x84, 0xc5, 0x02, 0xac, 0xfa, 0x7b, 0x0e, 0xc4, 0xc8, 0x45, 0x73, 0xb5, 0x7a,
+	0x28, 0x7d, 0x71, 0xb4, 0xfa, 0x2b, 0x07, 0x62, 0x14, 0x36, 0x51, 0x12, 0x71, 0x8b, 0x27, 0x11,
+	0x1f, 0x4b, 0xa2, 0x25, 0x3b, 0xd5, 0xb8, 0xae, 0xc2, 0x12, 0xba, 0xe6, 0x16, 0xd4, 0xf5, 0x37,
+	0x1c, 0x08, 0x24, 0xca, 0xd1, 0xdb, 0x93, 0xce, 0x5b, 0x4b, 0xa9, 0x48, 0x5f, 0x0c, 0xef, 0xfd,
+	0x85, 0x83, 0x42, 0x90, 0x81, 0xff, 0xdb, 0xbe, 0x8b, 0x4a, 0xd3, 0x63, 0x28, 0x04, 0xa7, 0x46,
+	0x4a, 0x55, 0xbe, 0x03, 0x05, 0xcc, 0xce, 0xa5, 0x94, 0xae, 0x24, 0x76, 0x6a, 0x29, 0x21, 0xac,
+	0xa6, 0x43, 0x21, 0x48, 0x57, 0x74, 0x13, 0x04, 0x8b, 0x9c, 0x92, 0xec, 0xa4, 0x4f, 0x4b, 0x68,
+	0xba, 0xbe, 0xc4, 0x26, 0xcf, 0x60, 0x25, 0x0c, 0x2b, 0xd2, 0x59, 0x8c, 0xed, 0xcf, 0xc5, 0x9a,
+	0x07, 0x62, 0x97, 0x81, 0x63, 0x2c, 0x16, 0x69, 0x01, 0x50, 0xf2, 0x6b, 0xbf, 0xe3, 0xa1, 0x18,
+	0x32, 0x47, 0xff, 0x1f, 0xbb, 0x1a, 0xbb, 0x90, 0x12, 0xd4, 0xc1, 0xe5, 0x58, 0x6a, 0xf3, 0xb2,
+	0x64, 0xd9, 0xbd, 0x0f, 0x25, 0xd3, 0xf2, 0x54, 0xfa, 0x7b, 0x1b, 0x5c, 0x57, 0xcd, 0xdc, 0x5b,
+	0x34, 0x2d, 0xef, 0xc0, 0xc5, 0xc3, 0x5d, 0x03, 0x35, 0x26, 0x1a, 0xbd, 0x1c, 0x4d, 0xc3, 0x1b,
+	0x29, 0x54, 0x73, 0x7f, 0x23, 0x9e, 0x2c, 0xd2, 0xa9, 0x7d, 0x65, 0xb2, 0x7f, 0xba, 0x94, 0xb2,
+	0x09, 0x61, 0x12, 0x6b, 0xe1, 0x6a, 0xcf, 0x00, 0xc6, 0x52, 0x2f, 0xd9, 0xf6, 0x5c, 0x84, 0xbc,
+	0xfd, 0xfc, 0xb9, 0x87, 0x99, 0x27, 0x73, 0x4a, 0x30, 0xaa, 0xf5, 0x41, 0x38, 0xf4, 0xb0, 0x8b,
+	0xce, 0x46, 0xae, 0x12, 0xa9, 0x4f, 0xaa, 0x50, 0x1c, 0x78, 0xd8, 0xb5, 0xb4, 0x7e, 0xe8, 0x96,
+	0x68, 0x8c, 0xbe, 0x91, 0x92, 0x99, 0xd5, 0x3a, 0xbb, 0x25, 0xae, 0x87, 0xb7, 0xc4, 0x54, 0x0e,
+	0x7a, 0x8d, 0x1c, 0x13, 0xa3, 0xf6, 0x2f, 0x1e, 0x0a, 0x07, 0xae, 0x4d, 0x0b, 0x71, 0x72, 0x4b,
+	0x04, 0x42, 0x6c, 0x3b, 0xfa, 0x8d, 0xae, 0x01, 0x38, 0x83, 0xa3, 0x9e, 0xa9, 0xd3, 0xab, 0xe4,
+	0x2c, 0x5d, 0x11, 0xd9, 0xcc, 0x07, 0x78, 0x44, 0x96, 0x3d, 0xac, 0xbb, 0x98, 0xdd, 0x34, 0x0b,
+	0x6c, 0x99, 0xcd, 0x90, 0xe5, 0x4d, 0x28, 0x6b, 0x03, 0xff, 0x58, 0xfd, 0x04, 0x1f, 0x1d, 0xdb,
+	0xf6, 0x89, 0x3a, 0x70, 0x7b, 0xc1, 0xdf, 0xe7, 0x59, 0x32, 0xff, 0x21, 0x9b, 0x3e, 0x74, 0x7b,
+	0xe8, 0x0e, 0x9c, 0x9f, 0x40, 0xf6, 0xb1, 0x7f, 0x6c, 0x1b, 0x5e, 0x25, 0xbf, 0x91, 0xdd, 0x14,
+	0x15, 0x14, 0x43, 0x3f, 0x66, 0x2b, 0xe8, 0x9b, 0x70, 0x25, 0xb8, 0x74, 0x35, 0xb0, 0xa6, 0xfb,
+	0xe6, 0x50, 0xf3, 0xb1, 0xea, 0x1f, 0xbb, 0xd8, 0x3b, 0xb6, 0x7b, 0x06, 0xbd, 0xd5, 0x13, 0x95,
+	0xcb, 0x0c, 0xd2, 0x8c, 0x10, 0xdd, 0x10, 0x90, 0x30, 0x62, 0xf1, 0x35, 0x8c, 0x48, 0x48, 0x63,
+	0x99, 0x29, 0x7e, 0x3e, 0xe9, 0x38, 0x3d, 0x7f, 0x94, 0x85, 0x8b, 0x87, 0x64, 0xa4, 0x1d, 0xf5,
+	0x70, 0xe0, 0x88, 0xf7, 0x4d, 0xdc, 0x33, 0x3c, 0x74, 0x27, 0x30, 0x3f, 0x17, 0xf4, 0xf5, 0x49,
+	0x7e, 0x1d, 0xdf, 0x35, 0xad, 0x17, 0xf4, 0xec, 0x0e, 0x9c, 0xf3, 0x7e, 0x8a, 0x79, 0xf9, 0x05,
+	0xa8, 0x93, 0xc6, 0x7f, 0x3e, 0xc3, 0xf8, 0x2c, 0xb2, 0xee, 0xc5, 0x62, 0x3b, 0x5d, 0xf4, 0xba,
+	0x34, 0xe5, 0x9e, 0x54, 0x97, 0x7d, 0x67, 0xbe, 0xcb, 0x84, 0x05, 0x44, 0x9f, 0xed, 0xd0, 0x6a,
+	0x1d, 0xd0, 0xb4, 0x1c, 0xec, 0xe2, 0x9f, 0xa9, 0xc3, 0xd1, 0x58, 0x0a, 0x87, 0xb5, 0xef, 0xf3,
+	0xb0, 0xda, 0x0c, 0x1e, 0x45, 0x3a, 0x83, 0x7e, 0x5f, 0x73, 0x47, 0x53, 0x29, 0x31, 0x7d, 0xd1,
+	0x9a, 0x7c, 0x03, 0x11, 0x63, 0x6f, 0x20, 0x93, 0x21, 0x25, 0xbc, 0x4e, 0x48, 0x3d, 0x80, 0x92,
+	0xa6, 0xeb, 0xd8, 0xf3, 0xe2, 0x55, 0x70, 0x1e, 0x2d, 0x84, 0xf0, 0xa9, 0x78, 0xcc, 0xbf, 0x4e,
+	0x3c, 0xfe, 0x98, 0x83, 0xe2, 0x81, 0x8b, 0x3d, 0x6c, 0xe9, 0xb4, 0x0f, 0xd0, 0x7b, 0xb6, 0x7e,
+	0x42, 0x0d, 0x90, 0x53, 0xd8, 0x80, 0xfc, 0x2d, 0x10, 0xa7, 0x57, 0x78, 0x7a, 0x28, 0xc7, 0x2f,
+	0xbc, 0x43, 0xc2, 0x7a, 0x53, 0xf3, 0x35, 0x76, 0x1c, 0x53, 0x68, 0xf5, 0x6b, 0x20, 0x46, 0x53,
+	0xaf, 0xf3, 0xb3, 0x5c, 0xdb, 0x85, 0x7c, 0x83, 0x3a, 0x38, 0xe6, 0x89, 0x15, 0xea, 0x89, 0x2d,
+	0x28, 0x3a, 0xc1, 0x76, 0x41, 0x8c, 0xaf, 0xa5, 0x48, 0xa2, 0x44, 0xa0, 0xda, 0x3b, 0x50, 0x60,
+	0xac, 0x3c, 0xfa, 0x36, 0xc5, 0x3e, 0x83, 0x06, 0x6f, 0xe2, 0x6d, 0x8a, 0xae, 0x28, 0x21, 0xa2,
+	0xd6, 0x06, 0x18, 0x3f, 0x7f, 0x25, 0xde, 0x6e, 0xb8, 0xb4, 0xb7, 0x9b, 0xc9, 0xd7, 0x1f, 0x3e,
+	0xf1, 0xfa, 0x53, 0xfb, 0x01, 0x07, 0xa5, 0xd8, 0xb5, 0xc6, 0xe9, 0x96, 0x0f, 0xf4, 0x25, 0x58,
+	0x75, 0x71, 0x4f, 0x23, 0xcd, 0xba, 0x1a, 0x00, 0xb2, 0x14, 0x70, 0x36, 0x9c, 0xde, 0x67, 0x75,
+	0x46, 0x07, 0x18, 0x73, 0x8e, 0xbf, 0x37, 0x71, 0xd3, 0xef, 0x4d, 0x57, 0x41, 0x34, 0x70, 0x8f,
+	0xfc, 0x03, 0x60, 0x37, 0x54, 0x28, 0x9a, 0x98, 0x78, 0x8d, 0xca, 0x4e, 0xbe, 0x46, 0xfd, 0x84,
+	0x83, 0x62, 0xd3, 0xd6, 0xe5, 0x21, 0xf1, 0xe0, 0xed, 0x89, 0xfe, 0x33, 0x5e, 0x67, 0x43, 0x48,
+	0xac, 0x05, 0xdd, 0x02, 0x56, 0x55, 0xbc, 0xe3, 0x60, 0xcb, 0x54, 0x27, 0x8d, 0x31, 0xe8, 0x06,
+	0x9c, 0x89, 0xbf, 0x72, 0xb2, 0x97, 0x3b, 0x51, 0x59, 0x89, 0x3d, 0x73, 0x7a, 0xb7, 0x7e, 0xc1,
+	0x83, 0x18, 0x35, 0xbb, 0x68, 0x0d, 0x56, 0x9f, 0x48, 0x7b, 0x87, 0xb2, 0xda, 0x7d, 0x7a, 0x20,
+	0xab, 0xed, 0xc3, 0xbd, 0xbd, 0x72, 0x06, 0x5d, 0x04, 0x14, 0x9b, 0xdc, 0xd9, 0xdf, 0xdf, 0x93,
+	0xa5, 0x76, 0x99, 0x4b, 0xcc, 0xef, 0xb6, 0xbb, 0xf2, 0x43, 0x59, 0x29, 0xf3, 0x09, 0x26, 0x7b,
+	0xfb, 0xed, 0x87, 0xe5, 0x2c, 0xba, 0x00, 0xe7, 0x62, 0x93, 0xcd, 0xfd, 0xc3, 0x9d, 0x3d, 0xb9,
+	0x2c, 0x24, 0xa6, 0x3b, 0x5d, 0x65, 0xb7, 0xfd, 0xb0, 0x9c, 0x43, 0xe7, 0xa1, 0x1c, 0xdf, 0xf2,
+	0x69, 0x57, 0xee, 0x94, 0xf3, 0x09, 0xc6, 0x4d, 0xa9, 0x2b, 0x97, 0x0b, 0xa8, 0x0a, 0x17, 0x63,
+	0x93, 0xa4, 0x99, 0x54, 0xf7, 0x77, 0x1e, 0xc9, 0x8d, 0x6e, 0xb9, 0x88, 0x2e, 0xc3, 0x85, 0xe4,
+	0x9a, 0xa4, 0x28, 0xd2, 0xd3, 0xb2, 0x98, 0xe0, 0xd5, 0x95, 0xbf, 0xdd, 0x2d, 0x43, 0x82, 0x57,
+	0xa0, 0x91, 0xda, 0x68, 0x77, 0xcb, 0x25, 0x74, 0x09, 0xd6, 0x12, 0x5a, 0xd1, 0x85, 0x95, 0x5b,
+	0x3f, 0xe7, 0x60, 0x25, 0xee, 0x2e, 0xf4, 0x7f, 0xb0, 0xd1, 0xdc, 0x6f, 0xa8, 0xf2, 0x13, 0xb9,
+	0xdd, 0x0d, 0xd5, 0x6d, 0x1c, 0x3e, 0x96, 0xdb, 0xdd, 0x8e, 0xda, 0x68, 0x49, 0xed, 0x87, 0x72,
+	0xb3, 0x9c, 0x99, 0x8b, 0xfa, 0x50, 0xea, 0x36, 0x5a, 0x72, 0xb3, 0xcc, 0xa1, 0x9b, 0x50, 0x9b,
+	0x89, 0x3a, 0x6c, 0x87, 0x38, 0x1e, 0xdd, 0x80, 0xb7, 0x12, 0xb8, 0x03, 0x45, 0xee, 0xc8, 0xed,
+	0x86, 0x1c, 0x6d, 0x99, 0xdd, 0xb9, 0xfd, 0xeb, 0x57, 0xeb, 0xdc, 0x6f, 0x5f, 0xad, 0x73, 0x7f,
+	0x7a, 0xb5, 0xce, 0xfd, 0xf4, 0xb3, 0xf5, 0x0c, 0x9c, 0x33, 0xf0, 0x30, 0x8c, 0x21, 0xcd, 0x31,
+	0xeb, 0xc3, 0xbb, 0x07, 0xdc, 0x33, 0xa1, 0xfe, 0x60, 0x78, 0xf7, 0x28, 0x4f, 0x4f, 0xc5, 0xaf,
+	0xfe, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x77, 0x83, 0x5a, 0x5a, 0xa2, 0x1f, 0x00, 0x00,
 }
 
 func (m *ChangePack) Marshal() (dAtA []byte, err error) {
@@ -4943,10 +4943,12 @@ func (m *Project) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 		i--
 		dAtA[i] = 0x42
 	}
-	if m.ClientDeactivateThreshold != 0 {
-		i = encodeVarintResources(dAtA, i, uint64(m.ClientDeactivateThreshold))
+	if len(m.ClientDeactivateThreshold) > 0 {
+		i -= len(m.ClientDeactivateThreshold)
+		copy(dAtA[i:], m.ClientDeactivateThreshold)
+		i = encodeVarintResources(dAtA, i, uint64(len(m.ClientDeactivateThreshold)))
 		i--
-		dAtA[i] = 0x38
+		dAtA[i] = 0x3a
 	}
 	if len(m.AuthWebhookMethods) > 0 {
 		for iNdEx := len(m.AuthWebhookMethods) - 1; iNdEx >= 0; iNdEx-- {
@@ -5019,10 +5021,17 @@ func (m *UpdatableProjectFields) MarshalToSizedBuffer(dAtA []byte) (int, error)
 		i -= len(m.XXX_unrecognized)
 		copy(dAtA[i:], m.XXX_unrecognized)
 	}
-	if m.ClientDeactivateThreshold != 0 {
-		i = encodeVarintResources(dAtA, i, uint64(m.ClientDeactivateThreshold))
+	if m.ClientDeactivateThreshold != nil {
+		{
+			size, err := m.ClientDeactivateThreshold.MarshalToSizedBuffer(dAtA[:i])
+			if err != nil {
+				return 0, err
+			}
+			i -= size
+			i = encodeVarintResources(dAtA, i, uint64(size))
+		}
 		i--
-		dAtA[i] = 0x20
+		dAtA[i] = 0x22
 	}
 	if m.AuthWebhookMethods != nil {
 		{
@@ -6394,8 +6403,9 @@ func (m *Project) Size() (n int) {
 			n += 1 + l + sovResources(uint64(l))
 		}
 	}
-	if m.ClientDeactivateThreshold != 0 {
-		n += 1 + sovResources(uint64(m.ClientDeactivateThreshold))
+	l = len(m.ClientDeactivateThreshold)
+	if l > 0 {
+		n += 1 + l + sovResources(uint64(l))
 	}
 	if m.CreatedAt != nil {
 		l = m.CreatedAt.Size()
@@ -6429,8 +6439,9 @@ func (m *UpdatableProjectFields) Size() (n int) {
 		l = m.AuthWebhookMethods.Size()
 		n += 1 + l + sovResources(uint64(l))
 	}
-	if m.ClientDeactivateThreshold != 0 {
-		n += 1 + sovResources(uint64(m.ClientDeactivateThreshold))
+	if m.ClientDeactivateThreshold != nil {
+		l = m.ClientDeactivateThreshold.Size()
+		n += 1 + l + sovResources(uint64(l))
 	}
 	if m.XXX_unrecognized != nil {
 		n += len(m.XXX_unrecognized)
@@ -11995,10 +12006,10 @@ func (m *Project) Unmarshal(dAtA []byte) error {
 			m.AuthWebhookMethods = append(m.AuthWebhookMethods, string(dAtA[iNdEx:postIndex]))
 			iNdEx = postIndex
 		case 7:
-			if wireType != 0 {
+			if wireType != 2 {
 				return fmt.Errorf("proto: wrong wireType = %d for field ClientDeactivateThreshold", wireType)
 			}
-			m.ClientDeactivateThreshold = 0
+			var stringLen uint64
 			for shift := uint(0); ; shift += 7 {
 				if shift >= 64 {
 					return ErrIntOverflowResources
@@ -12008,11 +12019,24 @@ func (m *Project) Unmarshal(dAtA []byte) error {
 				}
 				b := dAtA[iNdEx]
 				iNdEx++
-				m.ClientDeactivateThreshold |= int64(b&0x7F) << shift
+				stringLen |= uint64(b&0x7F) << shift
 				if b < 0x80 {
 					break
 				}
 			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthResources
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthResources
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.ClientDeactivateThreshold = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
 		case 8:
 			if wireType != 2 {
 				return fmt.Errorf("proto: wrong wireType = %d for field CreatedAt", wireType)
@@ -12245,10 +12269,10 @@ func (m *UpdatableProjectFields) Unmarshal(dAtA []byte) error {
 			}
 			iNdEx = postIndex
 		case 4:
-			if wireType != 0 {
+			if wireType != 2 {
 				return fmt.Errorf("proto: wrong wireType = %d for field ClientDeactivateThreshold", wireType)
 			}
-			m.ClientDeactivateThreshold = 0
+			var msglen int
 			for shift := uint(0); ; shift += 7 {
 				if shift >= 64 {
 					return ErrIntOverflowResources
@@ -12258,11 +12282,28 @@ func (m *UpdatableProjectFields) Unmarshal(dAtA []byte) error {
 				}
 				b := dAtA[iNdEx]
 				iNdEx++
-				m.ClientDeactivateThreshold |= int64(b&0x7F) << shift
+				msglen |= int(b&0x7F) << shift
 				if b < 0x80 {
 					break
 				}
 			}
+			if msglen < 0 {
+				return ErrInvalidLengthResources
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthResources
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.ClientDeactivateThreshold == nil {
+				m.ClientDeactivateThreshold = &types.StringValue{}
+			}
+			if err := m.ClientDeactivateThreshold.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipResources(dAtA[iNdEx:])
diff --git a/api/yorkie/v1/resources.proto b/api/yorkie/v1/resources.proto
index f9c71b9a..a4786e2e 100644
--- a/api/yorkie/v1/resources.proto
+++ b/api/yorkie/v1/resources.proto
@@ -214,7 +214,7 @@ message Project {
   string secret_key = 4;
   string auth_webhook_url = 5;
   repeated string auth_webhook_methods = 6;
-  int64 client_deactivate_threshold = 7;
+  string client_deactivate_threshold = 7;
   google.protobuf.Timestamp created_at = 8;
   google.protobuf.Timestamp updated_at = 9;
 }
@@ -227,7 +227,7 @@ message UpdatableProjectFields {
   google.protobuf.StringValue name = 1;
   google.protobuf.StringValue auth_webhook_url = 2;
   AuthWebhookMethods auth_webhook_methods = 3;
-  int64 client_deactivate_threshold = 4;
+  google.protobuf.StringValue client_deactivate_threshold = 4;
 }
 
 message DocumentSummary {
diff --git a/cmd/yorkie/project/update.go b/cmd/yorkie/project/update.go
index 41fd230c..39ba14c6 100644
--- a/cmd/yorkie/project/update.go
+++ b/cmd/yorkie/project/update.go
@@ -32,8 +32,9 @@ import (
 )
 
 var (
-	flagAuthWebhookURL string
-	flagName           string
+	flagAuthWebhookURL            string
+	flagName                      string
+	flagClientDeactivateThreshold string
 )
 
 func newUpdateCommand() *cobra.Command {
@@ -78,9 +79,15 @@ func newUpdateCommand() *cobra.Command {
 				newAuthWebhookURL = flagAuthWebhookURL
 			}
 
+			newClientDeactivateThreshold := project.ClientDeactivateThreshold
+			if flagClientDeactivateThreshold != "" {
+				newClientDeactivateThreshold = flagClientDeactivateThreshold
+			}
+
 			updatableProjectFields := &types.UpdatableProjectFields{
-				Name:           &newName,
-				AuthWebhookURL: &newAuthWebhookURL,
+				Name:                      &newName,
+				AuthWebhookURL:            &newAuthWebhookURL,
+				ClientDeactivateThreshold: &newClientDeactivateThreshold,
 			}
 
 			updated, err := cli.UpdateProject(ctx, id, updatableProjectFields)
@@ -125,5 +132,11 @@ func init() {
 		"",
 		"authorization-webhook update url",
 	)
+	cmd.Flags().StringVar(
+		&flagClientDeactivateThreshold,
+		"client-deactivate-threshold",
+		"",
+		"client deactivate threshold for housekeeping",
+	)
 	SubCmd.AddCommand(cmd)
 }
diff --git a/cmd/yorkie/server.go b/cmd/yorkie/server.go
index fa3ffe6e..f89dfdb6 100644
--- a/cmd/yorkie/server.go
+++ b/cmd/yorkie/server.go
@@ -41,7 +41,7 @@ var (
 
 	adminTokenDuration        time.Duration
 	housekeepingInterval      time.Duration
-	clientDeactivateThreshold time.Duration
+	clientDeactivateThreshold string
 
 	mongoConnectionURI     string
 	mongoConnectionTimeout time.Duration
@@ -68,7 +68,7 @@ func newServerCmd() *cobra.Command {
 		RunE: func(cmd *cobra.Command, args []string) error {
 			conf.Backend.AdminTokenDuration = adminTokenDuration.String()
 
-			conf.Backend.ClientDeactivateThreshold = clientDeactivateThreshold.String()
+			conf.Backend.ClientDeactivateThreshold = clientDeactivateThreshold
 
 			conf.Backend.AuthWebhookMaxWaitInterval = authWebhookMaxWaitInterval.String()
 			conf.Backend.AuthWebhookCacheAuthTTL = authWebhookCacheAuthTTL.String()
@@ -317,7 +317,7 @@ func init() {
 		"Whether to use the default project. Even if public key is not provided from the client, "+
 			"the default project will be used for the request.",
 	)
-	cmd.Flags().DurationVar(
+	cmd.Flags().StringVar(
 		&clientDeactivateThreshold,
 		"client-deactivate-threshold",
 		server.DefaultClientDeactivateThreshold,
diff --git a/server/backend/backend.go b/server/backend/backend.go
index c49dc226..ba4ca06e 100644
--- a/server/backend/backend.go
+++ b/server/backend/backend.go
@@ -137,7 +137,7 @@ func New(
 		context.Background(),
 		conf.AdminUser,
 		conf.AdminPassword,
-		conf.ParseClientDeactivateThreshold(),
+		conf.ClientDeactivateThreshold,
 	)
 	if err != nil {
 		return nil, err
diff --git a/server/backend/config.go b/server/backend/config.go
index c436c7d2..30bc8ea3 100644
--- a/server/backend/config.go
+++ b/server/backend/config.go
@@ -107,16 +107,6 @@ func (c *Config) Validate() error {
 	return nil
 }
 
-// ParseClientDeactivateThreshold returns client deactivate threshold.
-func (c *Config) ParseClientDeactivateThreshold() time.Duration {
-	result, err := time.ParseDuration(c.ClientDeactivateThreshold)
-	if err != nil {
-		panic(err)
-	}
-
-	return result
-}
-
 // ParseAdminTokenDuration returns admin token duration.
 func (c *Config) ParseAdminTokenDuration() time.Duration {
 	result, err := time.ParseDuration(c.AdminTokenDuration)
diff --git a/server/backend/database/database.go b/server/backend/database/database.go
index 54327649..a7496ef9 100644
--- a/server/backend/database/database.go
+++ b/server/backend/database/database.go
@@ -20,7 +20,6 @@ package database
 import (
 	"context"
 	"errors"
-	gotime "time"
 
 	"github.com/yorkie-team/yorkie/api/types"
 	"github.com/yorkie-team/yorkie/pkg/document"
@@ -84,7 +83,7 @@ type Database interface {
 		ctx context.Context,
 		username,
 		password string,
-		clientDeactivateThreshold gotime.Duration,
+		clientDeactivateThreshold string,
 	) (*UserInfo, *ProjectInfo, error)
 
 	// CreateProjectInfo creates a new project.
@@ -92,7 +91,7 @@ type Database interface {
 		ctx context.Context,
 		name string,
 		owner types.ID,
-		clientDeactivateThreshold gotime.Duration,
+		clientDeactivateThreshold string,
 	) (*ProjectInfo, error)
 
 	// ListProjectInfos returns all project infos owned by owner.
diff --git a/server/backend/database/memory/database.go b/server/backend/database/memory/database.go
index 034b5568..f5b26e0d 100644
--- a/server/backend/database/memory/database.go
+++ b/server/backend/database/memory/database.go
@@ -117,7 +117,7 @@ func (d *DB) EnsureDefaultUserAndProject(
 	ctx context.Context,
 	username,
 	password string,
-	clientDeactivateThreshold gotime.Duration,
+	clientDeactivateThreshold string,
 ) (*database.UserInfo, *database.ProjectInfo, error) {
 	user, err := d.ensureDefaultUserInfo(ctx, username, password)
 	if err != nil {
@@ -169,7 +169,7 @@ func (d *DB) ensureDefaultUserInfo(
 func (d *DB) ensureDefaultProjectInfo(
 	ctx context.Context,
 	defaultUserID types.ID,
-	defaultClientDeactivateThreshold gotime.Duration,
+	defaultClientDeactivateThreshold string,
 ) (*database.ProjectInfo, error) {
 	txn := d.db.Txn(true)
 	defer txn.Abort()
@@ -199,7 +199,7 @@ func (d *DB) CreateProjectInfo(
 	ctx context.Context,
 	name string,
 	owner types.ID,
-	clientDeactivateThreshold gotime.Duration,
+	clientDeactivateThreshold string,
 ) (*database.ProjectInfo, error) {
 	txn := d.db.Txn(true)
 	defer txn.Abort()
@@ -563,7 +563,12 @@ func (d *DB) findDeactivateCandidatesPerProject(
 	txn := d.db.Txn(false)
 	defer txn.Abort()
 
-	offset := gotime.Now().Add(-project.ClientDeactivateThreshold)
+	clientDeactivateThreshold, err := project.ClientDeactivateThresholdAsTimeDuration()
+	if err != nil {
+		return nil, err
+	}
+
+	offset := gotime.Now().Add(-clientDeactivateThreshold)
 
 	var infos []*database.ClientInfo
 	iterator, err := txn.ReverseLowerBound(
diff --git a/server/backend/database/mongo/client.go b/server/backend/database/mongo/client.go
index 095b19da..b26e17f1 100644
--- a/server/backend/database/mongo/client.go
+++ b/server/backend/database/mongo/client.go
@@ -95,7 +95,7 @@ func (c *Client) EnsureDefaultUserAndProject(
 	ctx context.Context,
 	username,
 	password string,
-	clientDeactivateThreshold gotime.Duration,
+	clientDeactivateThreshold string,
 ) (*database.UserInfo, *database.ProjectInfo, error) {
 	userInfo, err := c.ensureDefaultUserInfo(ctx, username, password)
 	if err != nil {
@@ -158,7 +158,7 @@ func (c *Client) ensureDefaultUserInfo(
 func (c *Client) ensureDefaultProjectInfo(
 	ctx context.Context,
 	defaultUserID types.ID,
-	defaultClientDeactivateThreshold gotime.Duration,
+	defaultClientDeactivateThreshold string,
 ) (*database.ProjectInfo, error) {
 	candidate := database.NewProjectInfo(database.DefaultProjectName, defaultUserID, defaultClientDeactivateThreshold)
 	candidate.ID = database.DefaultProjectID
@@ -207,7 +207,7 @@ func (c *Client) CreateProjectInfo(
 	ctx context.Context,
 	name string,
 	owner types.ID,
-	clientDeactivateThreshold gotime.Duration,
+	clientDeactivateThreshold string,
 ) (*database.ProjectInfo, error) {
 	encodedOwner, err := encodeID(owner)
 	if err != nil {
@@ -622,11 +622,21 @@ func (c *Client) findDeactivateCandidatesPerProject(
 	project *database.ProjectInfo,
 	candidatesLimit int,
 ) ([]*database.ClientInfo, error) {
+	encodedProjectID, err := encodeID(project.ID)
+	if err != nil {
+		return nil, err
+	}
+
+	clientDeactivateThreshold, err := project.ClientDeactivateThresholdAsTimeDuration()
+	if err != nil {
+		return nil, err
+	}
+
 	cursor, err := c.collection(colClients).Find(ctx, bson.M{
-		"project_id": project.ID,
+		"project_id": encodedProjectID,
 		"status":     database.ClientActivated,
 		"updated_at": bson.M{
-			"$lte": gotime.Now().Add(-project.ClientDeactivateThreshold),
+			"$lte": gotime.Now().Add(-clientDeactivateThreshold),
 		},
 	}, options.Find().SetLimit(int64(candidatesLimit)))
 
diff --git a/server/backend/database/mongo/indexes.go b/server/backend/database/mongo/indexes.go
index 10a46c3f..1734d4da 100644
--- a/server/backend/database/mongo/indexes.go
+++ b/server/backend/database/mongo/indexes.go
@@ -75,6 +75,7 @@ var collectionInfos = []collectionInfo{
 			Options: options.Index().SetUnique(true),
 		}, {
 			Keys: bsonx.Doc{
+				{Key: "project_id", Value: bsonx.Int32(1)},
 				{Key: "status", Value: bsonx.Int32(1)},
 				{Key: "updated_at", Value: bsonx.Int32(1)},
 			},
diff --git a/server/backend/database/project_info.go b/server/backend/database/project_info.go
index 1bc9efae..2be73d0d 100644
--- a/server/backend/database/project_info.go
+++ b/server/backend/database/project_info.go
@@ -17,6 +17,7 @@
 package database
 
 import (
+	"errors"
 	"time"
 
 	"github.com/rs/xid"
@@ -24,6 +25,9 @@ import (
 	"github.com/yorkie-team/yorkie/api/types"
 )
 
+// ErrInvalidTimeDurationString is returned when the given time duration string is not in valid format.
+var ErrInvalidTimeDurationString = errors.New("invalid time duration string format")
+
 // DefaultProjectID is the default project ID.
 var DefaultProjectID = types.ID("000000000000000000000000")
 
@@ -55,7 +59,7 @@ type ProjectInfo struct {
 
 	// ClientDeactivateThreshold is the time after which clients in
 	// specific project are considered deactivate for housekeeping.
-	ClientDeactivateThreshold time.Duration `bson:"client_deactivate_threshold"`
+	ClientDeactivateThreshold string `bson:"client_deactivate_threshold"`
 
 	// CreatedAt is the time when the project was created.
 	CreatedAt time.Time `bson:"created_at"`
@@ -65,7 +69,7 @@ type ProjectInfo struct {
 }
 
 // NewProjectInfo creates a new ProjectInfo of the given name.
-func NewProjectInfo(name string, owner types.ID, clientDeactivateThreshold time.Duration) *ProjectInfo {
+func NewProjectInfo(name string, owner types.ID, clientDeactivateThreshold string) *ProjectInfo {
 	return &ProjectInfo{
 		Name:                      name,
 		Owner:                     owner,
@@ -124,8 +128,8 @@ func (i *ProjectInfo) UpdateFields(fields *types.UpdatableProjectFields) {
 	if fields.AuthWebhookMethods != nil {
 		i.AuthWebhookMethods = *fields.AuthWebhookMethods
 	}
-	if fields.ClientDeactivateThreshold != 0 {
-		i.ClientDeactivateThreshold = time.Duration(fields.ClientDeactivateThreshold)
+	if fields.ClientDeactivateThreshold != nil {
+		i.ClientDeactivateThreshold = *fields.ClientDeactivateThreshold
 	}
 }
 
@@ -144,3 +148,13 @@ func (i *ProjectInfo) ToProject() *types.Project {
 		UpdatedAt:                 i.UpdatedAt,
 	}
 }
+
+// ClientDeactivateThresholdAsTimeDuration converts ClientDeactivateThreshold string to time.Duration.
+func (i *ProjectInfo) ClientDeactivateThresholdAsTimeDuration() (time.Duration, error) {
+	clientDeactivateThreshold, err := time.ParseDuration(i.ClientDeactivateThreshold)
+	if err != nil {
+		return 0, ErrInvalidTimeDurationString
+	}
+
+	return clientDeactivateThreshold, nil
+}
diff --git a/server/config.go b/server/config.go
index 6a2ccf21..c5c38a59 100644
--- a/server/config.go
+++ b/server/config.go
@@ -42,7 +42,7 @@ const (
 
 	DefaultAdminPort = 11103
 
-	DefaultHousekeepingInterval                  = time.Minute
+	DefaultHousekeepingInterval                  = 30 * time.Second
 	DefaultHousekeepingCandidatesLimitPerProject = 500
 
 	DefaultMongoConnectionURI     = "mongodb://localhost:27017"
@@ -55,7 +55,7 @@ const (
 	DefaultSecretKey                  = "yorkie-secret"
 	DefaultAdminTokenDuration         = 7 * 24 * time.Hour
 	DefaultUseDefaultProject          = true
-	DefaultClientDeactivateThreshold  = 24 * time.Hour
+	DefaultClientDeactivateThreshold  = "24h"
 	DefaultSnapshotThreshold          = 500
 	DefaultSnapshotInterval           = 1000
 	DefaultSnapshotWithPurgingChanges = false
@@ -180,7 +180,7 @@ func (c *Config) ensureDefaultValue() {
 	}
 
 	if c.Backend.ClientDeactivateThreshold == "" {
-		c.Backend.ClientDeactivateThreshold = DefaultClientDeactivateThreshold.String()
+		c.Backend.ClientDeactivateThreshold = DefaultClientDeactivateThreshold
 	}
 
 	if c.Backend.SnapshotThreshold == 0 {
@@ -256,7 +256,7 @@ func newConfig(port int, profilingPort int) *Config {
 			CandidatesLimitPerProject: DefaultHousekeepingCandidatesLimitPerProject,
 		},
 		Backend: &backend.Config{
-			ClientDeactivateThreshold:  DefaultClientDeactivateThreshold.String(),
+			ClientDeactivateThreshold:  DefaultClientDeactivateThreshold,
 			SnapshotThreshold:          DefaultSnapshotThreshold,
 			SnapshotInterval:           DefaultSnapshotInterval,
 			SnapshotWithPurgingChanges: DefaultSnapshotWithPurgingChanges,
diff --git a/server/grpchelper/status.go b/server/grpchelper/status.go
index 84d9e0d0..31798d87 100644
--- a/server/grpchelper/status.go
+++ b/server/grpchelper/status.go
@@ -37,14 +37,15 @@ import (
 // errorToCode maps an error to gRPC status code.
 var errorToCode = map[error]codes.Code{
 	// InvalidArgument means the request is malformed.
-	converter.ErrPackRequired:       codes.InvalidArgument,
-	converter.ErrCheckpointRequired: codes.InvalidArgument,
-	time.ErrInvalidHexString:        codes.InvalidArgument,
-	time.ErrInvalidActorID:          codes.InvalidArgument,
-	types.ErrInvalidID:              codes.InvalidArgument,
-	clients.ErrInvalidClientID:      codes.InvalidArgument,
-	clients.ErrInvalidClientKey:     codes.InvalidArgument,
-	types.ErrEmptyProjectFields:     codes.InvalidArgument,
+	converter.ErrPackRequired:             codes.InvalidArgument,
+	converter.ErrCheckpointRequired:       codes.InvalidArgument,
+	database.ErrInvalidTimeDurationString: codes.InvalidArgument,
+	time.ErrInvalidHexString:              codes.InvalidArgument,
+	time.ErrInvalidActorID:                codes.InvalidArgument,
+	types.ErrInvalidID:                    codes.InvalidArgument,
+	clients.ErrInvalidClientID:            codes.InvalidArgument,
+	clients.ErrInvalidClientKey:           codes.InvalidArgument,
+	types.ErrEmptyProjectFields:           codes.InvalidArgument,
 
 	// NotFound means the requested resource does not exist.
 	database.ErrProjectNotFound:  codes.NotFound,
diff --git a/server/projects/projects.go b/server/projects/projects.go
index 33d129ea..ab9ee237 100644
--- a/server/projects/projects.go
+++ b/server/projects/projects.go
@@ -32,7 +32,7 @@ func CreateProject(
 	owner types.ID,
 	name string,
 ) (*types.Project, error) {
-	info, err := be.DB.CreateProjectInfo(ctx, name, owner, be.Config.ParseClientDeactivateThreshold())
+	info, err := be.DB.CreateProjectInfo(ctx, name, owner, be.Config.ClientDeactivateThreshold)
 	if err != nil {
 		return nil, err
 	}


Test patch:
diff --git a/api/types/updatable_project_fields_test.go b/api/types/updatable_project_fields_test.go
index b4896674..948e0113 100644
--- a/api/types/updatable_project_fields_test.go
+++ b/api/types/updatable_project_fields_test.go
@@ -18,7 +18,6 @@ package types_test
 
 import (
 	"testing"
-	"time"
 
 	"github.com/stretchr/testify/assert"
 
@@ -34,12 +33,12 @@ func TestUpdatableProjectFields(t *testing.T) {
 			string(types.AttachDocument),
 			string(types.WatchDocuments),
 		}
-		newClientDeactivateThreshold := 1 * time.Hour
+		newClientDeactivateThreshold := "1h"
 		fields := &types.UpdatableProjectFields{
 			Name:                      &newName,
 			AuthWebhookURL:            &newAuthWebhookURL,
 			AuthWebhookMethods:        &newAuthWebhookMethods,
-			ClientDeactivateThreshold: newClientDeactivateThreshold,
+			ClientDeactivateThreshold: &newClientDeactivateThreshold,
 		}
 		assert.NoError(t, fields.Validate())
 
@@ -54,7 +53,7 @@ func TestUpdatableProjectFields(t *testing.T) {
 		fields = &types.UpdatableProjectFields{
 			Name:                      &newName,
 			AuthWebhookURL:            &newAuthWebhookURL,
-			ClientDeactivateThreshold: newClientDeactivateThreshold,
+			ClientDeactivateThreshold: &newClientDeactivateThreshold,
 		}
 		assert.NoError(t, fields.Validate())
 
@@ -66,7 +65,7 @@ func TestUpdatableProjectFields(t *testing.T) {
 			Name:                      &newName,
 			AuthWebhookURL:            &newAuthWebhookURL,
 			AuthWebhookMethods:        &newAuthWebhookMethods,
-			ClientDeactivateThreshold: newClientDeactivateThreshold,
+			ClientDeactivateThreshold: &newClientDeactivateThreshold,
 		}
 		assert.ErrorAs(t, fields.Validate(), &invalidFieldsError)
 	})
diff --git a/server/backend/config_test.go b/server/backend/config_test.go
index 63830a98..cbe44745 100644
--- a/server/backend/config_test.go
+++ b/server/backend/config_test.go
@@ -35,7 +35,7 @@ func TestConfig(t *testing.T) {
 		assert.NoError(t, validConf.Validate())
 
 		conf1 := validConf
-		conf1.ClientDeactivateThreshold = "5"
+		conf1.ClientDeactivateThreshold = "1 hour"
 		assert.Error(t, conf1.Validate())
 
 		conf2 := validConf
diff --git a/server/backend/database/memory/database_test.go b/server/backend/database/memory/database_test.go
index 6467155d..970976ab 100644
--- a/server/backend/database/memory/database_test.go
+++ b/server/backend/database/memory/database_test.go
@@ -20,7 +20,6 @@ import (
 	"context"
 	"fmt"
 	"testing"
-	gotime "time"
 
 	"github.com/stretchr/testify/assert"
 
@@ -43,7 +42,7 @@ func TestDB(t *testing.T) {
 	dummyOwnerID := types.ID("000000000000000000000000")
 	otherOwnerID := types.ID("000000000000000000000001")
 	notExistsID := types.ID("000000000000000000000000")
-	clientDeactivateThreshold := 1 * gotime.Hour
+	clientDeactivateThreshold := "1h"
 
 	t.Run("activate/deactivate client test", func(t *testing.T) {
 		// try to deactivate the client with not exists ID.
@@ -365,7 +364,7 @@ func TestDB(t *testing.T) {
 			string(types.AttachDocument),
 			string(types.WatchDocuments),
 		}
-		newClientDeactivateThreshold := 1 * gotime.Hour
+		newClientDeactivateThreshold := "1h"
 
 		info, err := db.CreateProjectInfo(ctx, t.Name(), dummyOwnerID, clientDeactivateThreshold)
 		assert.NoError(t, err)
@@ -379,7 +378,7 @@ func TestDB(t *testing.T) {
 			Name:                      &newName,
 			AuthWebhookURL:            &newAuthWebhookURL,
 			AuthWebhookMethods:        &newAuthWebhookMethods,
-			ClientDeactivateThreshold: newClientDeactivateThreshold,
+			ClientDeactivateThreshold: &newClientDeactivateThreshold,
 		}
 		assert.NoError(t, fields.Validate())
 		res, err := db.UpdateProjectInfo(ctx, dummyOwnerID, id, fields)
@@ -424,9 +423,9 @@ func TestDB(t *testing.T) {
 		assert.Equal(t, newClientDeactivateThreshold, updateInfo.ClientDeactivateThreshold)
 
 		// 04. Update clientDeactivateThreshold test
-		clientDeactivateThreshold2 := clientDeactivateThreshold + 1*gotime.Hour
+		clientDeactivateThreshold2 := "2h"
 		fields = &types.UpdatableProjectFields{
-			ClientDeactivateThreshold: clientDeactivateThreshold2,
+			ClientDeactivateThreshold: &clientDeactivateThreshold2,
 		}
 		assert.NoError(t, fields.Validate())
 		res, err = db.UpdateProjectInfo(ctx, dummyOwnerID, id, fields)
diff --git a/server/backend/database/memory/housekeeping_test.go b/server/backend/database/memory/housekeeping_test.go
index 178543f6..f71a9194 100644
--- a/server/backend/database/memory/housekeeping_test.go
+++ b/server/backend/database/memory/housekeeping_test.go
@@ -38,7 +38,7 @@ func TestHousekeeping(t *testing.T) {
 	t.Run("housekeeping test", func(t *testing.T) {
 		ctx := context.Background()
 
-		clientDeactivateThreshold := 23 * gotime.Hour
+		clientDeactivateThreshold := "23h"
 		_, project, err := memdb.EnsureDefaultUserAndProject(ctx, "test", "test", clientDeactivateThreshold)
 		assert.NoError(t, err)
 
diff --git a/server/backend/database/mongo/client_test.go b/server/backend/database/mongo/client_test.go
index fd37fda1..dbf837dd 100644
--- a/server/backend/database/mongo/client_test.go
+++ b/server/backend/database/mongo/client_test.go
@@ -19,7 +19,6 @@ package mongo_test
 import (
 	"context"
 	"testing"
-	"time"
 
 	"github.com/stretchr/testify/assert"
 
@@ -44,7 +43,7 @@ func TestClient(t *testing.T) {
 
 	dummyOwnerID := types.ID("000000000000000000000000")
 	otherOwnerID := types.ID("000000000000000000000001")
-	clientDeactivateThreshold := 1 * time.Hour
+	clientDeactivateThreshold := "1h"
 
 	t.Run("UpdateProjectInfo test", func(t *testing.T) {
 		info, err := cli.CreateProjectInfo(ctx, t.Name(), dummyOwnerID, clientDeactivateThreshold)
@@ -60,14 +59,14 @@ func TestClient(t *testing.T) {
 			string(types.AttachDocument),
 			string(types.WatchDocuments),
 		}
-		newClientDeactivateThreshold := 2 * time.Hour
+		newClientDeactivateThreshold := "2h"
 
 		// update total project_field
 		fields := &types.UpdatableProjectFields{
 			Name:                      &newName,
 			AuthWebhookURL:            &newAuthWebhookURL,
 			AuthWebhookMethods:        &newAuthWebhookMethods,
-			ClientDeactivateThreshold: newClientDeactivateThreshold,
+			ClientDeactivateThreshold: &newClientDeactivateThreshold,
 		}
 
 		err = fields.Validate()
diff --git a/server/backend/database/project_info_test.go b/server/backend/database/project_info_test.go
index 8178cab3..658e2bf3 100644
--- a/server/backend/database/project_info_test.go
+++ b/server/backend/database/project_info_test.go
@@ -18,7 +18,6 @@ package database_test
 
 import (
 	"testing"
-	"time"
 
 	"github.com/stretchr/testify/assert"
 
@@ -29,13 +28,13 @@ import (
 func TestProjectInfo(t *testing.T) {
 	t.Run("update fields test", func(t *testing.T) {
 		dummyOwnerID := types.ID("000000000000000000000000")
-		clientDeactivateThreshold := 1 * time.Hour
+		clientDeactivateThreshold := "1h"
 		project := database.NewProjectInfo(t.Name(), dummyOwnerID, clientDeactivateThreshold)
 
 		testName := "testName"
 		testURL := "testUrl"
 		testMethods := []string{"testMethod"}
-		testClientDeactivateThreshold := 2 * time.Hour
+		testClientDeactivateThreshold := "2h"
 
 		project.UpdateFields(&types.UpdatableProjectFields{Name: &testName})
 		assert.Equal(t, testName, project.Name)
@@ -48,7 +47,7 @@ func TestProjectInfo(t *testing.T) {
 		assert.Equal(t, dummyOwnerID, project.Owner)
 
 		project.UpdateFields(&types.UpdatableProjectFields{
-			ClientDeactivateThreshold: testClientDeactivateThreshold,
+			ClientDeactivateThreshold: &testClientDeactivateThreshold,
 		})
 		assert.Equal(t, testClientDeactivateThreshold, project.ClientDeactivateThreshold)
 	})
diff --git a/server/config_test.go b/server/config_test.go
index e11c9888..d01e20c1 100644
--- a/server/config_test.go
+++ b/server/config_test.go
@@ -65,7 +65,7 @@ func TestNewConfigFromFile(t *testing.T) {
 		assert.Equal(t, conf.Backend.SnapshotInterval, int64(server.DefaultSnapshotInterval))
 		assert.Equal(t, conf.Backend.AuthWebhookMaxRetries, uint64(server.DefaultAuthWebhookMaxRetries))
 
-		ClientDeactivateThreshold, err := time.ParseDuration(conf.Backend.ClientDeactivateThreshold)
+		ClientDeactivateThreshold := conf.Backend.ClientDeactivateThreshold
 		assert.NoError(t, err)
 		assert.Equal(t, ClientDeactivateThreshold, server.DefaultClientDeactivateThreshold)
 
diff --git a/server/rpc/server_test.go b/server/rpc/server_test.go
index b5f20157..05e36ff7 100644
--- a/server/rpc/server_test.go
+++ b/server/rpc/server_test.go
@@ -67,7 +67,7 @@ func TestMain(m *testing.M) {
 	be, err := backend.New(&backend.Config{
 		AdminUser:                 helper.AdminUser,
 		AdminPassword:             helper.AdminPassword,
-		ClientDeactivateThreshold: helper.ClientDeactivateThreshold.String(),
+		ClientDeactivateThreshold: helper.ClientDeactivateThreshold,
 		SnapshotThreshold:         helper.SnapshotThreshold,
 		AuthWebhookCacheSize:      helper.AuthWebhookSize,
 	}, &mongo.Config{
diff --git a/test/bench/grpc_bench_test.go b/test/bench/grpc_bench_test.go
index ea760fdd..8259940e 100644
--- a/test/bench/grpc_bench_test.go
+++ b/test/bench/grpc_bench_test.go
@@ -25,7 +25,6 @@ import (
 	"strings"
 	"sync"
 	"testing"
-	"time"
 
 	"github.com/stretchr/testify/assert"
 
@@ -109,7 +108,7 @@ func benchmarkUpdateProject(ctx context.Context, b *testing.B, cnt int, adminCli
 		for _, m := range types.AuthMethods() {
 			authWebhookMethods = append(authWebhookMethods, string(m))
 		}
-		clientDeactivateThreshold := 1 * time.Hour
+		clientDeactivateThreshold := "1h"
 
 		_, err := adminCli.UpdateProject(
 			ctx,
@@ -118,7 +117,7 @@ func benchmarkUpdateProject(ctx context.Context, b *testing.B, cnt int, adminCli
 				Name:                      &name,
 				AuthWebhookURL:            &authWebhookURL,
 				AuthWebhookMethods:        &authWebhookMethods,
-				ClientDeactivateThreshold: clientDeactivateThreshold,
+				ClientDeactivateThreshold: &clientDeactivateThreshold,
 			},
 		)
 		assert.NoError(b, err)
diff --git a/test/helper/helper.go b/test/helper/helper.go
index 32f31d0f..aa7ac707 100644
--- a/test/helper/helper.go
+++ b/test/helper/helper.go
@@ -55,7 +55,7 @@ var (
 	HousekeepingInterval                  = 1 * gotime.Second
 	HousekeepingCandidatesLimitPerProject = 10
 
-	ClientDeactivateThreshold  = 10 * gotime.Second
+	ClientDeactivateThreshold  = "10s"
 	SnapshotThreshold          = int64(10)
 	SnapshotWithPurgingChanges = false
 	AuthWebhookMaxWaitInterval = 3 * gotime.Millisecond
@@ -134,7 +134,7 @@ func TestConfig() *server.Config {
 			SecretKey:                  server.DefaultSecretKey,
 			AdminTokenDuration:         server.DefaultAdminTokenDuration.String(),
 			UseDefaultProject:          true,
-			ClientDeactivateThreshold:  server.DefaultClientDeactivateThreshold.String(),
+			ClientDeactivateThreshold:  server.DefaultClientDeactivateThreshold,
 			SnapshotThreshold:          SnapshotThreshold,
 			SnapshotWithPurgingChanges: SnapshotWithPurgingChanges,
 			AuthWebhookMaxWaitInterval: AuthWebhookMaxWaitInterval.String(),