המדיניות SanitizeUserPrompt

מדיניות ניתנת להרחבה

הדף הזה רלוונטי ל-Apigee ול-Apigee Hybrid.

לצפייה במאמרי העזרה של Apigee Edge.

המדיניות SanitizeUserPrompt מגינה על אפליקציות AI מפני תוכן פוגעני על ידי הסרת תוכן זדוני או רגיש מהנחיות של משתמשים שנשלחות למודלים של AI גנרטיבי. המדיניות משתמשת בהגנה מוגברת על המודל כדי להעריך אם הנחיות של משתמשים מכילות תוכן פוגעני, וכך מאפשרת הגנה מובנית על עומסי עבודה של AI באמצעות Apigee. ‫Model Armor הוא Google Cloud שירות שמציע אמצעי אבטחה ובטיחות ל-AI כדי לצמצם את הסיכונים שקשורים למודלים גדולים של שפה (LLM).

המדיניות הזו פועלת בשילוב עם המדיניות SanitizeModelResponse.

המדיניות הזו היא מדיניות ניתנת להרחבה, והשימוש בה עשוי להשפיע על העלות או על הניצול, בהתאם לרישיון שלכם ב-Apigee. למידע על סוגי המדיניות וההשלכות של השימוש בהם, קראו את המאמר סוגי מדיניות.

לפני שמתחילים

לפני שמשתמשים במדיניות SanitizeUserPrompt, צריך לבצע את המשימות הבאות:

  • יוצרים תבנית של Model Armor. צריך להשלים את השלב הזה לפני שיוצרים מדיניות SanitizeUserPrompt.
  • מגדירים את נקודת הקצה ל-API של שירות Model Armor.
  • יוצרים מדיניות SanitizeModelResponse. צריך להשלים את המשימה הזו לפני שפורסים את המדיניות SanitizeUserPrompt.

התפקידים הנדרשים

כדי לקבל את ההרשאות שדרושות בשביל להחיל את המדיניות SanitizeUserPrompt ולהשתמש בה, אתם צריכים לבקש מהאדמין לתת לכם את התפקידים הבאים ב-IAM בחשבון השירות שמשמש לפריסת שרתי proxy של Apigee:

להסבר על מתן תפקידים, ראו איך מנהלים את הגישה ברמת הפרויקט, התיקייה והארגון.

יכול להיות שאפשר לקבל את ההרשאות הנדרשות גם באמצעות תפקידים בהתאמה אישית או תפקידים מוגדרים מראש.

הפעלת ממשקי ה-API

מפעילים את Model Armor API, אם הוא עדיין לא מופעל.

התפקידים שנדרשים כדי להפעיל ממשקי API

כדי להפעיל ממשקי API, צריך את ההרשאה serviceusage.services.enable. אם יצרתם את הפרויקט, סביר להניח שכבר יש לכם את ההרשאה הזו דרך התפקיד "בעלים" (roles/owner). אחרת, תוכלו לקבל את ההרשאה הזו דרך התפקיד "אדמין בממשק 'שימוש בשירות'" (roles/serviceusage.serviceUsageAdmin). איך מקצים תפקידים

להפעלת ה-API

רכיב <SanitizeUserPrompt>

מגדירה מדיניות SanitizeUserPrompt.

ערך ברירת המחדל מידע נוסף מופיע בקטע הכרטיסייה "מדיניות ברירת המחדל" שבהמשך.
חובה? חובה
סוג אובייקט מורכב
רכיב הורה לא רלוונטי
רכיבי צאצא <DisplayName>
<IgnoreUnresolvedVariables>
<ModelArmor>
<UserPromptSource>
<FunctionResponseSource>

הרכיב <SanitizeUserPrompt> משתמש בתחביר הבא:

תחביר

<SanitizeUserPrompt async="false" continueOnError="false" enabled="true" name="sanitize-text">
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <DisplayName>Sanitize-Text-sample</DisplayName>
  <ModelArmor>
    <TemplateName>projects/{project}/locations/{location}/templates/{template-name}</TemplateName>
  </ModelArmor>
  <UserPromptSource>{jsonPath('$.contents[-1].parts[-1].text',request.content)}</UserPromptSource>
  <FunctionResponseSource>{jsonPath('$.contents[-1].parts[-1].functionResponse.response',request.content)}</FunctionResponseSource>
</SanitizeUserPrompt>

מדיניות ברירת המחדל

בדוגמה הבאה מוצגות הגדרות ברירת המחדל כשמוסיפים מדיניות SanitizeUserPrompt לתהליך הבקשה בממשק המשתמש של Apigee:

<SanitizeUserPrompt async="false" continueOnError="false" enabled="true" name="sanitize-text">
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <DisplayName>Sanitize-Text-sample</DisplayName>
  <ModelArmor>
    <TemplateName>projects/{project}/locations/{location}/templates/{template-name}</TemplateName>
  </ModelArmor>
  <UserPromptSource>{jsonPath('$.contents[-1].parts[-1].text',request.content)}</UserPromptSource>
  <FunctionResponseSource>{jsonPath('$.contents[-1].parts[-1].functionResponse.response',request.content)}</FunctionResponseSource>
</SanitizeUserPrompt>

כשמוסיפים מדיניות חדשה של SanitizeUserPrompt באמצעות ממשק המשתמש של Apigee, התבנית מכילה קטעי קוד לכל הפעולות האפשריות. בהמשך מופיע מידע על הרכיבים הנדרשים.

לרכיב הזה יש את המאפיינים הבאים שמשותפים לכל המדיניות:

מאפיין ברירת מחדל חובה? תיאור
name לא רלוונטי חובה

השם הפנימי של המדיניות. הערך של מאפיין name יכול להכיל אותיות, מספרים, רווחים, מקפים, קווים תחתונים ונקודות. הערך הזה לא יכול להיות ארוך מ-255 תווים.

אפשר להשתמש ברכיב <DisplayName> כדי לתת למדיניות תווית בשם אחר בשפה טבעית בכלי לעריכת פרוקסי בממשק המשתמש לניהול.

continueOnError FALSE אופציונלי מגדירים את הערך false כדי להחזיר שגיאה אם המדיניות נכשלת. זו התנהגות צפויה ברוב המקרים. הגדרה ל-true מאפשרת להמשיך את הביצוע של התהליך גם אחרי שמדיניות נכשלת. מאמרים קשורים:
enabled TRUE אופציונלי מגדירים את הערך true כדי לאכוף את המדיניות, או את הערך false כדי להשבית את המדיניות. המדיניות לא נאכפת גם אם היא עדיין משויכת לזרימה.
async   FALSE הוצא משימוש המאפיין הזה הוצא משימוש.

בטבלה הבאה מופיע תיאור כללי של רכיבי המשנה של <SanitizeUserPrompt>:

רכיב צאצא חובה? תיאור
<DisplayName> אופציונלי שם המדיניות.

<IgnoreUnresolvedVariables> אופציונלי המדיניות הזו קובעת אם העיבוד ייפסק אם המשתנה שמשמש לשם התבנית או למטען הייעודי (payload) של Model Armor לא נפתר.
<ModelArmor> חובה מכיל את המידע הנדרש כדי לציין את התבנית של Model Armor.
<UserPromptSource> אופציונלי המיקום של המטען הייעודי (payload) של טקסט ההנחיה של המשתמש שצריך לחלץ. אפשר להשתמש רק בערכי טקסט של מחרוזות.

השדה הזה תומך בתחביר של תבנית ההודעה של Apigee, כולל שימוש ב משתנים או בפונקציות של נתיב JSON.

לדוגמה:

{jsonpath('$.input.prompt.text',request.content,false)}

<FunctionResponseSource> אופציונלי המיקום של נתוני התגובה של הפונקציה או הכלי שרוצים לחלץ. המדיניות משתמשת ברכיב הזה כגיבוי כש-<UserPromptSource> מחזיר ערך ריק בתורות של קריאה להפעלת פונקציות.

ברירת המחדל: {jsonPath('$.contents[-1].parts[-1].functionResponse.response',request.content)}

דוגמה

בקטע הזה מופיעה דוגמה לשימוש ב-<SanitizeUserPrompt>.

בדוגמה הזו נעשה שימוש בכל ערכי ברירת המחדל לזיהוי מודלים ולחילוץ הנחיות:

<SanitizeUserPrompt async="false" continueOnError="false" enabled="true" name="sanitize-text">
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <DisplayName>Sanitize-Text-sample</DisplayName>
  <ModelArmor>
    <TemplateName>projects/{project}/locations/{location}/templates/{template-name}</TemplateName>
  </ModelArmor>
</SanitizeUserPrompt>

הפניה לרכיב צאצא

בקטע הזה מתוארים רכיבי הצאצא של <SanitizeUserPrompt>.

<DisplayName>

אפשר להשתמש במאפיין הזה בנוסף למאפיין name כדי לתת למדיניות שם אחר, שנשמע יותר טבעי, ב-UI של עורך ה-proxy לניהול.

הרכיב <DisplayName> משותף לכל סוגי המדיניות.

ערך ברירת המחדל לא רלוונטי
חובה? זה שינוי אופציונלי. אם לא מציינים את <DisplayName>, המערכת משתמשת בערך של מאפיין name של המדיניות.
סוג String
רכיב אב <PolicyElement>
רכיבי צאצא ללא

רכיב <DisplayName> משתמש בתחביר הבא:

תחביר

<PolicyElement>
  <DisplayName>POLICY_DISPLAY_NAME</DisplayName>
  ...
</PolicyElement>

דוגמה

<PolicyElement>
  <DisplayName>My Validation Policy</DisplayName>
</PolicyElement>

לרכיב <DisplayName> אין מאפיינים או רכיבי צאצא.

<IgnoreUnresolvedVariables>

קובעת אם העיבוד ייפסק כשמשתנה לא נפתר. מגדירים את הערך true כדי להתעלם ממשתנים לא פתורים ולהמשיך בעיבוד.

ערך ברירת המחדל לא נכון
חובה? אופציונלי
סוג בוליאני
רכיב הורה <SanitizeUserPrompt>
רכיבי צאצא ללא

<ModelArmor>

מכיל את המידע הנדרש כדי לציין את התבנית של Model Armor.

ערך ברירת המחדל לא רלוונטי
חובה? חובה
סוג String
רכיב הורה
רכיבי צאצא <TemplateName>

הרכיב <ModelArmor> משתמש בתחביר הבא:

תחביר

<ModelArmor>
  <TemplateName>projects/{project}/locations/{location}/templates/{template-name}</TemplateName>
</ModelArmor>

דוגמה

בדוגמה הזו נעשה שימוש במשתני זרימה של Apigee כדי לאכלס את המידע הנדרש.

<ModelArmor>
  <TemplateName>projects/{organization.name}/locations/{system.region.name}/templates/{id}</TemplateName>
</ModelArmor>

בטבלה הבאה מופיע תיאור כללי של רכיבי המשנה של <ModelArmor>.

רכיב צאצא חובה? תיאור
<TemplateName> חובה String

התבנית של Model Armor שמשמשת להסרת תוכן זדוני או רגיש מההנחיה של המשתמש.

אפשר להשתמש בתבנית לערך הזה באמצעות משתני הזרימה הבאים של Apigee:

projects/{organization.name}/locations/{system.region.name}/templates/{id}

<UserPromptSource>

המיקום של המטען הייעודי (payload) של טקסט ההנחיה של המשתמש שצריך לחלץ. השדה הזה תומך בתחביר של תבנית ההודעה של Apigee, כולל שימוש ב משתנים או בפונקציות של נתיב JSON. לדוגמה:

{jsonpath('$.input.prompt.text',request.content,false)}
ערך ברירת המחדל {jsonPath('$.contents[-1].parts[-1].text',request.content)}
חובה? אופציונלי
סוג String
רכיב הורה <SanitizeUserPrompt>
רכיבי צאצא ללא

<FunctionResponseSource>

המיקום של נתוני התגובה של הפונקציה או הכלי שצריך לחלץ מהבקשה. המדיניות משתמשת ברכיב הזה כחלופה כש-<UserPromptSource> מחזיר ערך ריק, וזה קורה בסבבים של קריאה להפעלת פונקציות שבהם רשומת התוכן האחרונה מכילה תשובה של פונקציה במקום טקסט. חשוב לנקות את נתוני התגובה של הפונקציה כי הם מכילים נתונים חיצוניים לא מהימנים מממשקי API וממסדי נתונים.

השדה הזה תומך בתחביר של תבניות הודעות, כולל פונקציות של נתיב JSON.

ערך ברירת המחדל {jsonPath('$.contents[-1].parts[-1].functionResponse.response',request.content)}
חובה? אופציונלי
סוג String
רכיב הורה <SanitizeUserPrompt>
רכיבי צאצא ללא

משתני זרימה

משתני זרימה מגדירים התנהגות דינמית בזמן ריצה של כללי מדיניות וזרימות, על סמך כותרות HTTP או תוכן ההודעה, או ההקשר שזמין בזרימה. מידע נוסף על משתני זרימה זמין במאמר חומר עזר בנושא משתני זרימה.

המדיניות הזו מספקת את קבוצת משתני הזרימה הבאה לקריאה בלבד במהלך ההפעלה. אתם יכולים להשתמש במשתני הזרימה האלה עם מדיניות DataCapture כדי ליצור דוחות ניתוח בהתאמה אישית. מידע נוסף זמין במאמר איסוף נתוני לקוחות בהתאם למדיניות בנושא תיעוד נתונים.

שם המשתנה תיאור
SanitizeUserPrompt.POLICY_NAME.templateUsed מציינת באיזו תבנית של Model Armor משתמשים. לדוגמה: projects/myproject/locations/us-west1/templates/mytemplate
SanitizeUserPrompt.POLICY_NAME.userPrompt מציין את תוכן הפרומפט שמשמש לקריאה ל-Model Armor כדי להסיר תוכן זדוני או רגיש מהתוכן.
SanitizeUserPrompt.POLICY_NAME.modelResponse מציין את תוכן התשובה של ה-LLM שמשמש לקריאה ל-Model Armor כדי להסיר תוכן זדוני או רגיש.
SanitizeUserPrompt.POLICY_NAME.responseFromModelArmor מציין את תגובת ה-JSON מ-Model Armor.
SanitizeUserPrompt.POLICY_NAME.filterMatchState מציין אם המסנן תואם. הערכים התקינים כוללים את MATCH_FOUND ו-NO_MATCH_FOUND.
SanitizeUserPrompt.POLICY_NAME.invocationResult שדה שמציין את תוצאת ההפעלה, בלי קשר לסטטוס ההתאמה. הוא יכול לכלול את הפרטים הבאים:
  • הצלחה: כל המסננים הופעלו בהצלחה.
  • חלקית: המערכת דילגה על חלק מהמסננים או שההפעלה שלהם נכשלה.
  • נכשל: כל המסננים דולגו או שההפעלה שלהם נכשלה.
SanitizeUserPrompt.POLICY_NAME.raiFilterResult.executionState תוצאת ההפעלה של מסנן ה-RAI. הערכים התקינים כוללים את EXECUTION_SUCCESS ו-EXECUTION_SKIPPED.
SanitizeUserPrompt.POLICY_NAME.raiFilterResult.matchState מצב ההתאמה של מסנן ה-RAI. הערכים התקינים כוללים את MATCH_FOUND ו-NO_MATCH_FOUND.
SanitizeUserPrompt.POLICY_NAME.sdpFilterResult.inspectResult.executionState מצב ההפעלה של תוצאת הבדיקה של מסנן ה-SDP. הערכים התקינים כוללים את EXECUTION_SUCCESS ו-EXECUTION_SKIPPED.
SanitizeUserPrompt.POLICY_NAME.sdpFilterResult.inspectResult.matchState מצב ההתאמה של תוצאת הבדיקה של מסנן ה-SDP. הערכים התקינים כוללים את MATCH_FOUND ו-NO_MATCH_FOUND.
SanitizeUserPrompt.POLICY_NAME.sdpFilterResult.deidentifyResult.executionState מצב הביצוע של תוצאת הסרת פרטי הזיהוי של מסנן SDP. הערכים התקינים כוללים את EXECUTION_SUCCESS ו-EXECUTION_SKIPPED.
SanitizeUserPrompt.POLICY_NAME.sdpFilterResult.deidentifyResult.matchState מצב ההתאמה של תוצאת הסרת פרטי הזיהוי של מסנן SDP. הערכים התקינים כוללים את MATCH_FOUND ו-NO_MATCH_FOUND.
SanitizeUserPrompt.POLICY_NAME.piAndJailbreakFilterResult.executionState מצב הביצוע של תוצאות הסינון של החדרת פרומפטים ו-Jailbreak. הערכים התקינים כוללים את EXECUTION_SUCCESS ו-EXECUTION_SKIPPED.
SanitizeUserPrompt.POLICY_NAME.piAndJailbreakFilterResult.matchState מצב התאמה של תוצאות הסינון של החדרת פרומפטים ו-Jailbreak. הערכים התקינים כוללים את MATCH_FOUND ו-NO_MATCH_FOUND.
SanitizeUserPrompt.POLICY_NAME.csamFilterFilterResult.executionState מצב ההפעלה של מסנן ה-CSAM. הערכים התקינים כוללים את EXECUTION_SUCCESS ו-EXECUTION_SKIPPED.
SanitizeUserPrompt.POLICY_NAME.csamFilterFilterResult.matchState מצב ההתאמה של מסנן ה-CSAM. הערכים התקינים כוללים את MATCH_FOUND ו-NO_MATCH_FOUND.
SanitizeUserPrompt.POLICY_NAME.maliciousUriFilterResult.executionState מצב ההפעלה של מסנן ה-URI הזדוני. הערכים התקינים כוללים את EXECUTION_SUCCESS ו-EXECUTION_SKIPPED.
SanitizeUserPrompt.POLICY_NAME.maliciousUriFilterResult.matchState מצב ההתאמה של מסנן ה-URI הזדוני. הערכים התקינים כוללים את MATCH_FOUND ו-NO_MATCH_FOUND.
SanitizeUserPrompt.POLICY_NAME.sanitizationMetadata.errorCode קוד שגיאה מותאם אישית שמוחלף אם הוא קיים בתגובה של Model Armor.
SanitizeUserPrompt.POLICY_NAME.sanitizationMetadata.errorMessage קוד שגיאה מותאם אישית שמוחלף אם הוא קיים בתגובה של Model Armor.
SanitizeUserPrompt.POLICY_NAME.csamFilterMatched ערך בוליאני שמציין אם מסנן ה-CSAM תאם.
SanitizeUserPrompt.POLICY_NAME.maliciousURIs רשימה מצורפת של מזהי URI זדוניים שזוהו על ידי מסנן ה-URI הזדוניים.
SanitizeUserPrompt.POLICY_NAME.maliciousURIsDetected ערך בוליאני שמציין אם הייתה התאמה למסנן של כתובות ה-URI הזדוניות.
SanitizeUserPrompt.POLICY_NAME.matchesFound ערך בוליאני שמציין אם אחד מהמסננים תואם.
SanitizeUserPrompt.POLICY_NAME.promptInjectionDetected ערך בוליאני שמציין אם מסנן החדרת הפרומפטים תאם.
SanitizeUserPrompt.POLICY_NAME.promptInjectionConfidence רמת הסמך של גלאי החדרת פרומפטים.
SanitizeUserPrompt.POLICY_NAME.raiMatchesFound ערך בוליאני שמציין אם מסנן ה-RAI תאם.
SanitizeUserPrompt.POLICY_NAME.requestSentToModelArmor ערך בוליאני שמציין אם נשלחה בקשה ל-Model Armor.
SanitizeUserPrompt.POLICY_NAME.sanitizeOperation מציין את הפעולה שהמדיניות מבצעת. הערכים התקינים כוללים את SANITIZE_USER_PROMPT ו-SANITIZE_MODEL_RESPONSE.

הפניה לשגיאה

בקטע הזה מתוארים קודי השגיאה והודעות השגיאה שמוחזרים על ידי Apigee, ומשתני השגיאה שמוגדרים על ידי Apigee למדיניות SanitizeUserPrompt. חשוב לדעת את המידע הזה אם אתם מפתחים כללי תקלות לטיפול בתקלות. למידע נוסף, קראו את המאמרים מה שצריך לדעת על שגיאות במדיניות וטיפול בתקלות.

שגיאות זמן ריצה

השגיאות האלה יכולות להתרחש כשהמדיניות מופעלת.

קוד השגיאה סטטוס HTTP מטרה
steps.sanitize.user.prompt.response.FilterMatched 400 השגיאה הזו מתרחשת אם ההנחיה של המשתמש לא עוברת את בדיקת התבנית של Model Armor.
steps.sanitize.user.prompt.SanitizationResponseParsingFailed 500 השגיאה הזו מתרחשת אם אי אפשר לנתח את התגובה של Model Armor.
steps.sanitize.user.prompt.FailedToExtractUserPrompt 500 השגיאה הזו מתרחשת אם החילוץ האוטומטי של הנחיית המשתמש לערך ברירת המחדל נכשל.
steps.sanitize.user.prompt.InternalError 500 השגיאה הזו מתרחשת אם יש שגיאת שרת פנימית.
steps.sanitize.modelarmor.ModelArmorTemplateNameExtractionFailed 500 השגיאה הזו קורית אם אי אפשר לפתור את שם התבנית.
steps.sanitize.modelarmor.AuthenticationFailure 500 השגיאה הזו מתרחשת אם לחשבון השירות אין הרשאה לשלוח קריאה ל-Model Armor API.
steps.sanitize.modelarmor.ModelArmorAPIFailed 500 השגיאה הזו מתרחשת אם Model Armor API מחזיר שגיאה.
steps.sanitize.modelarmor.ModelArmorCalloutError 500 השגיאה הזו מתרחשת אם הקריאה ל-Model Armor API נכשלת.
steps.sanitize.modelarmor.ServiceUnavailable 500 השגיאה הזו מתרחשת אם שירות Model Armor לא זמין.

שגיאות בפריסה

השגיאות האלה יכולות להתרחש כשפורסים שרת proxy שמכיל את המדיניות הזו.

שם השגיאה מטרה
The ModelArmor/TemplateName element is required. השגיאה הזו מתרחשת אם הרכיב <TemplateName> לא נמצא ב-<ModelArmor>.
The TemplateName element value is required. השגיאה הזו מתרחשת אם הערך של <TemplateName> ריק.

משתני תקלות

המדיניות הזו מגדירה את המשתנים האלה כשהיא מפעילה שגיאה בזמן הריצה. למידע נוסף, קראו את המאמר מה שצריך לדעת על שגיאות שקשורות למדיניות.

משתנים כאשר: דוגמה
fault.name="FAULT_NAME" ‫FAULT_NAME הוא שם התקלה, כמו שמופיע בטבלה שגיאות זמן ריצה שלמעלה. שם התקלה הוא החלק האחרון של קוד השגיאה. fault.name Matches "UnresolvedVariable"
SanitizeUserPrompt.POLICY_NAME.failed ‫POLICY_NAME הוא השם שהמשתמש נתן למדיניות שגרמה לשגיאה. SanitizeUserPrompt.sanitize-prompt.failed = true

דוגמה לתגובת שגיאה

{
  "fault": {
    "faultstring": "SanitizeUserPrompt[sanitize-prompt]: unable to resolve variable [variable_name]",
    "detail": {
      "errorcode": "steps.sanitizeuserprompt.UnresolvedVariable"
    }
  }
}

דוגמה לכלל שגיאה

<FaultRule name="SanitizeUserPrompt Faults">
    <Step>
        <Name>SUP-CustomSetVariableErrorResponse</Name>
        <Condition>(fault.name = "SetVariableFailed")</Condition>
    </Step>
    <Condition>(sanitizeuserprompt.failed = true)</Condition>
</FaultRule>

קודי שגיאה והודעות שגיאה בתבניות של "הגנה מוגברת על המודל"

התבנית של Model Armor תומכת בשינוי קודי השגיאה והודעות השגיאה שמופיעות בבקשות ה-API של המדיניות SanitizeUserPrompt. אם המשתמש מגדיר את השינויים, קודי השגיאה והודעות השגיאה של Model Armor מאכלסים את משתני הזרימה.

לדוגמה, תגובה עם קודי שגיאה והודעות של Model Armor יכולה להיראות כך:

{
  "sanitizationResult": {
    "filterMatchState": "MATCH_FOUND",
    "filterResults": {...},
    "sanitizationMetadata": {
      "errorCode": "890",
      "errorMessage": "get out"
      },
    "invocationResult": "SUCCESS"
  }
}

סכימות

כל סוג מדיניות מוגדר על ידי סכימת XML‏ (.xsd). לעיון, סכימות המדיניות זמינות ב-GitHub.