# OZサーバーバインディング

## 前提条件 <a href="#prerequisites" id="prerequisites"></a>

### OZサーバライセンス <a href="#oz-server-license" id="oz-server-license"></a>

下記のような権限を持つOZサーバライセンスファイル (`WEB-INF/license/ozlicense.xml`) が必要です。　

```
USE-SERVERBIND="TRUE"
```

OZサーバは、OZサーババインディングを使用するために以下のような4つのファイル&#x3092;*`WEB-INF/lib/`*&#x914D;下に配置する必要があります。&#x20;

<div align="left"><img src="https://gblobscdn.gitbook.com/assets%2F-M0LRvAG2w89F7pN5LX0%2F-M0LS-5iLuHl7xvC2A8d%2F-M0LYQKe5CEdYNI2362W%2Ftech-server-binding.png?alt=media&#x26;token=7e42d878-dfd4-4cfe-b133-ef55daf53dce" alt=""></div>

### 設定 <a href="#settings" id="settings"></a>

設定ファイル `WEB-INF/conf/spmgr.properties` を開き、下記のように必要な権限を設定します。

```bash
allow_exportbind_service=true # uncomment 1 and set to true
exportbind_sessionkey= # uncomment
```

## OZRエクスポート <a href="#exporting-ozr-with-inputjson" id="exporting-ozr-with-inputjson"></a>

1. クライアント側(html)で入力値をサーバに伝送します。
2. サーバ側のjspプログラムはOZサーバに要請します。 program requests the OZ server to bind the input data with OZR and export it to OZD.

{% hint style="info" %}
OZD (OZデータファイル)は、OZRとその入力値を含んでいます。
{% endhint %}

### export-inputjson.html <a href="#export-inputjson-html" id="export-inputjson-html"></a>

1. OZRを開き、ユーザーから入力値を取得します。
2. 下記のような関数でOZビューアから入力値を取得します。

   `OZViewer.GetInformation("INPUT_JSON_ALL");`
3. server-binding-inputjson.jspに入力値をパラメータで伝送します。

### export-inputjson.jsp <a href="#export-inputjson-jsp" id="export-inputjson-jsp"></a>

1. パラメータで入力値を受け取ります。
2. 下記のようなビューアオプションを使用します。

   OZRフォームを開く ( connection.reportname )

   OZRにinputjsonを事前バインディングする ( connection.inputjson )

   OZDでエクスポートする ( export.format )
3. OZサーバにバインディングとエクスポートを要請します。

   `request.setAttribute("OZViewerExportParam", param);`

   `getRequestDispatcher("/server");`

   `dispatcher.include(request, response);`
4. OZサーバから結果を取得します。

   `request.getAttribute("OZViewerExportResult");`

{% tabs %}
{% tab title="export-inputjson.html" %}

```markup
<!DOCTYPE html>
<html>
<html style="height:100%">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" type="text/css"/>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link rel="stylesheet" href="/oz/HTML5viewer/ui.dynatree.css" type="text/css"/>
<script type="text/javascript" src="/oz/HTML5viewer/jquery.dynatree.js" charset="utf-8"></script>
<script type="text/javascript" src="/oz/HTML5viewer/OZJSViewer.js" charset="utf-8"></script>
</head>

<script>
function sendForm() {
	var input_data = OZViewer.GetInformation("INPUT_JSON_ALL");
	document.form.input.value = input_data;
}
</script>

<form name="form" method="POST" action="export-inputjson.jsp">
  <input type="hidden" name="input" value="">
  <input type="submit" value="Export to OZD on Server" onclick="sendForm()">
</form> 

<body style="width:98%;height:98%">
<div id="OZViewer" style="width:98%;height:98%"></div>
<script type="text/javascript" >
	var serverUrl = "https://" + location.host;
	function SetOZParamters_OZViewer(){
		var oz = document.getElementById("OZViewer");
		oz.sendToActionScript("information.debug", "true");
		oz.sendToActionScript("connection.servlet",serverUrl + "/oz/server");
		oz.sendToActionScript("connection.reportname","guide/server-binding/export.ozr");
		oz.sendToActionScript("global.language", "en_US");
		return true;
	}
	start_ozjs("OZViewer", serverUrl + "/oz/HTML5viewer/");
</script>
</body>
</html>
```

{% endtab %}

{% tab title="export-inputjson.jsp" %}

```javascript
<%@ page contentType="charset=UTF-8" autoFlush="true"%>
<%@ page import="java.util.*,java.io.*"%><%!

	public String getParameter(HttpServletRequest req, String key) {
		String value = req.getParameter(key);
		return value;
	}	
	   
	public boolean writefile(byte[] b, String path)
	{
		BufferedOutputStream fout = null;
		boolean result = false;
		try{
			fout = new BufferedOutputStream(new FileOutputStream(path));
			fout.write(b);
			fout.flush();
			fout.close();
			fout = null;
			result = true;
		}catch(Exception e){
			result = false; 
		}finally{
			if(fout!=null) try{fout.close();}catch(Exception e){}
		}
		return result;
	}
%><%
try {
		String input = getParameter(request,"input");
		String jsondata = input.replaceAll("\"","\\\"");
		out.println("inputjson=<br>" + input);

		String sourceFile = "guide\\server-binding\\export.ozr";
		String targetType = "attachment"; // : to save the target file as a file. 
						 // "inline": to open the target file with browser
		String targetFormat = "ozd"; 
		String targetFile = "export." + targetFormat;
		String targetFolder = "C:\\Program Files\\Apache Software Foundation\\Tomcat 8.5\\webapps\\oz\\guide\\server-binding\\";
		File tf = new File(targetFolder);
		if (!tf.exists()) { new File(targetFolder).mkdir(); }
      	String targetPath = targetFolder + targetFile;	

		// delete if pdf exists
		File pdffile = new File(targetFile);
        if(pdffile.delete()){}else{} 

		// OZ parameters 	
		Hashtable param = new Hashtable();	
		param.put("information.debug", "true");  // enable viewer console
		param.put("export.mode", "silent");
		param.put("export.confirmsave", "flase"); // no confirm = silent
		param.put("export.saveonefile", "true"); 
		param.put("export.format", targetFormat);
		param.put("export.path", targetFolder);
		param.put("export.filename", targetFile);	
		param.put("connection.inputjson", jsondata); // fill values into components
		param.put("connection.reportname", sourceFile);
		param.put("pdf.fontembedding", "true"); // embed the font used in the OZR into the target pdf
		param.put("ozd.allowreplaceformparam", "true"); // allow to pass form parameter

		// request OZ server to bind and export
		request.setAttribute("OZViewerExportParam", param);
		RequestDispatcher dispatcher = pageContext.getServletContext().getRequestDispatcher("/server");		
		dispatcher.include(request, response);

		// get result from OZ server 
		boolean isSaved = false;
		Object o = request.getAttribute("OZViewerExportResult");
		if (o == null) { // Server Error
			Throwable t = (Throwable) request.getAttribute("OZViewerExportError");
			if(t != null) {
				throw t;
			} else {
				throw new Exception("No result from OZ Server.");
			}
		} else { // save as file in target format
			Hashtable t = (Hashtable) o;
			byte[] b = (byte[]) t.get(targetPath);
			if (b != null) {				
				isSaved = writefile(b, targetPath);
			} else {
				throw new Exception("targetPath is required: " + targetPath);
			}			
			response.setContentType("text/html");
			if (isSaved) {   
				out.println("<br><br>Successfully exported. <a href=\"https://demo.ozeform.io/oz/guide/server-binding/export.ozd\">Download OZD</a>");
			} 
		}
	} catch (Throwable e) {
		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);
		e.printStackTrace(pw);
		response.sendError(500, sw.getBuffer().toString());
	} finally {
	}
%>
```

{% endtab %}
{% endtabs %}

### pdfのフォント埋め込み <a href="#embedding-fonts-in-pdf" id="embedding-fonts-in-pdf"></a>

pdfエクスポートする際、OZRで使用するフォントをPDFファイルの埋め込むためには、サーバにフォントをインストールした後、下記のようなパラメータオプションを使用します。

```
param.put("pdf.fontembedding", "true"); // embedd all fonts
param.put("pdf.fontembedding_subset", "true"); // embedd only selected fonts
```

## メモリーストリームとしてエクスポート <a href="#exporting-ozr-to-memory-stream" id="exporting-ozr-to-memory-stream"></a>

1. クライアント (html)は、OZRフォームとそのデータをOZDタイプでメモリーストリームエクスポートを行なった後、サーバに伝送します。.
2. サーバ側のjspプログラムはOZDメモリーストリームを受け取り、OZDファイルで保存します。.

### export-memorystream.html <a href="#export-memorystream-html" id="export-memorystream-html"></a>

1. OZRフォームを開き、ユーザーから入力値を取得します。
2. 下記のようなスクリプトを利用し、現在のビューアからデータと共にOZRをOZDメモリーストリームとしてエクスポートします。

   `ScriptEx("save_memorystream", "export.format=ozd;");`

   `OZCommand_ozviewer(cmd, msg){};`

   `OZExportMemoryStreamCallBack_ozviewer(outputdata){}`
3. 当該ファイルストリームがBASE64でインコーディングされ、出力データ`outputdata` としてリターンされます。
4. サーバにファイルストリームを伝送します。

### export-memorystream.jsp <a href="#export-memorystream-jsp" id="export-memorystream-jsp"></a>

1. ファイルストリームを取得します。
2. ファイルストリームをデコードします。
3. OZDファイルとして保存します。

{% tabs %}
{% tab title="export-stream.html" %}

```markup
<!DOCTYPE html>
<html style="height:100%">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" type="text/css"/>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link rel="stylesheet" href="/oz/HTML5viewer/ui.dynatree.css" type="text/css"/>
<script type="text/javascript" src="/oz/HTML5viewer/jquery.dynatree.js" charset="utf-8"></script>
<script type="text/javascript" src="/oz/HTML5viewer/OZJSViewer.js" charset="utf-8"></script>
</head>
<body topmargin="0" leftmargin="0" style="width:98%;height:98%;webkit-text-size-adjust:none;">

<div> 
	<form>
		<input type="button" value="Export to OZD stream" onclick="Save_MemoryStream()">
		<input type="hidden" id="strOZD"	name="strOZD">
	</form>
	
</div>

<div id="ozviewer" style="width:98;height:90%"></div>

<script type="text/javascript" >

	function Save_MemoryStream() {
		ozviewer.ScriptEx("save_memorystream", "export.format=ozd; ozd.saveall=true; ozd.allowreplaceformparam=true; export.path=C:\\TEMP;export.mode=silent;export.filename=temp;export.confirmsave=false",";");	
		// export.path=C:\\TEMP -> "C:\\TEM" is just a dummy value, no meaning, but the option is required.
	}
	function OZCommand_ozviewer(cmd, msg) {
		// Do not remove this function. This is required for "save_memorystream" option to work correctly.
	}
	function OZExportMemoryStreamCallBack_ozviewer(outputdata) {			   
		if(outputdata == "{}") {
		  alert("Export failed.");
		}else {
			var obj = eval('(' + outputdata + ')');
			var value = null;
			for(var key in obj) value = obj[key];

			$('#strOZD').val(value);
			var param = $('form').serialize();	
 			var url = "./export-stream.jsp";

			$.ajax({
				type : "POST",
				url : url,
				data : param,
				async : false,
				success : sucessCallback,
				error : function(request, status, error) {
					if (request.status != '0') {
						alert("code : " + request.status + "\r\nmessage : "	+ request.reponseText + "\r\nerror : " + error);
					}
				}
			});
		}	   
    }
	var sucessCallback = function(data){
		document.write("Export complete. <a href=\"https://demo.ozeform.io/oz/guide/server-binding/export.ozd\">Download OZD</a>");
	};

    function SetOZParamters_ozviewer()	{
		var serverUrl = "https://" + location.host;
        var oz = document.getElementById("ozviewer");
		oz.sendToActionScript("information.debug", "true");
		oz.sendToActionScript("connection.servlet", serverUrl + "/oz/server");
		oz.sendToActionScript("connection.reportname","guide/server-binding/export.ozr");
		oz.sendToActionScript("global.language", "en_US");
        return true;
    }
    start_ozjs("ozviewer", "/oz/HTML5viewer/");

</script>
</body>
</html>
```

{% endtab %}

{% tab title="export-stream.jsp" %}

```javascript
<%@ page language="java" import="java.io.*,sun.misc.*,org.xml.sax.InputSource,org.w3c.dom.*, javax.xml.parsers.*, java.util.*, java.text.*" contentType="text/html; charset=UTF-8" autoFlush="true"%><%!
	public String encoder(String key) {
		return new BASE64Encoder().encode(key.getBytes());
	}
	public byte[] decoder(String cipher) throws IOException {
		return new BASE64Decoder().decodeBuffer(cipher);
	} 
%><%
try {
	String _PATH = "C:/Program Files/Apache Software Foundation/Tomcat 8.5/webapps/oz/guide/server-binding/"; 
	String _FILE	= "export";
	String _FILE_PATH = _PATH +_FILE + ".ozd";
	
	request.setCharacterEncoding("utf-8");
	String base64Str =  request.getParameter("strOZD");
	//System.out.println(base64Str);
	byte[] decodedBytes = new BASE64Decoder().decodeBuffer(base64Str.substring(base64Str.indexOf(",")+1));
	try {	
		FileOutputStream fout = new FileOutputStream(_FILE_PATH);
	    fout.write(decodedBytes, 0, decodedBytes.length);
	    fout.close();
        System.out.println("OZD saved.");
		out.println(_FILE_PATH);
	} catch (IOException e) {
		e.printStackTrace();
	} 
}
catch(Exception e) {
	out.print(e.getMessage());
} finally {
}
%>
```

{% endtab %}
{% endtabs %}

## サーバ側へのpdfエクスポート(OZD) <a href="#exporting-ozd-to-pdf-at-server-side" id="exporting-ozd-to-pdf-at-server-side"></a>

サーバ側のjspプログラムはconnection.reportnameの代わりにconnection.openfileのオプションを利用し、OZDファイルを開きます。

```bash
String sourceFile = "file://C:\\Program Files\\Apache Software Foundation\\Tomcat 8.5\\webapps\\oz\\guide\\server-binding\\export.ozd";
param.put("connection.openfile", sourceFile); // open ozd
```

{% hint style="warning" %}
ozd.allowreplaceformparamオプションの値をtrueに設定したOZDのみ、OZフォームパラメータを使用することが可能です。上記の例示にも下記のようなコードを含んでいます。

`param.put("ozd.allowreplaceformparam", "true"); ozviewer.ScriptEx(ozd.allowreplaceformparam=true;)`
{% endhint %}

inputjsonを渡して入力項目の入力値を事前入力することも可能ですが、このサンプルではコメントアウト処理されています。

{% tabs %}
{% tab title="export-ozd2pdf.jsp" %}

```javascript

<%@ page contentType="charset=UTF-8" autoFlush="true"%>
<%@ page import="java.util.*,java.io.*"%><%!
	   
	public boolean writefile(byte[] b, String path)
	{
		BufferedOutputStream fout = null;
		boolean result = false;
		try{
			fout = new BufferedOutputStream(new FileOutputStream(path));
			fout.write(b);
			fout.flush();
			fout.close();
			fout = null;
			result = true;
		}catch(Exception e){
			result = false; 
		}finally{
			if(fout!=null) try{fout.close();}catch(Exception e){}
		}
		return result;
	}
%><%
try {
    // add inputjson
		// String input = "{\"no\":\"1200\",\"name\":\"John Kim\",\"email\":\"john.kim@forcs.com\",\"title\":\"Consultant\"}";
		// String jsondata = input.replaceAll("\"","\\\"");
		// out.println(jsondata);

		// source and target	
		String sourceFile = "file://C:\\Program Files\\Apache Software Foundation\\Tomcat 8.5\\webapps\\oz\\guide\\server-binding\\export.ozd";
		//String sourceFile = "http://localhost/oz/guide/server-binding/export.ozd";
		
		String targetType = "attachment"; // : to save the target file as a file. 
		String targetFormat = "pdf"; // target document format
		String targetFile = "export.pdf";
		String targetFolder = "C:\\Program Files\\Apache Software Foundation\\Tomcat 8.5\\webapps\\oz\\guide\\server-binding\\";

		// target path
		File tf = new File(targetFolder);
		if (!tf.exists()) { new File(targetFolder).mkdir(); }
      	String targetPath = targetFolder + targetFile;	

		// prepare OZ parameters 
		java.util.Date date=new java.util.Date();  	
		Hashtable param = new Hashtable(); 
		param.put("connection.openfile", sourceFile); // open ozd
		param.put("connection.pcount", "1");
		param.put("connection.args1", "date="+date);
		param.put("export.format", targetFormat);
		param.put("export.path", targetFolder);
		param.put("export.filename", targetFile);	
		param.put("pdf.fontembedding", "true");
		param.put("html.charset", "unicode");
		param.put("tiff.savemultipage", "true");
		param.put("export.saveonefile", "true");
		param.put("viewer.useractioncommand", "true");	
	  // memo options	
		param.put("pdf.savecomment", "true");
		param.put("memo.exportoption","nothing");
		
		// replace values of components using inputjson
		//param.put("connection.inputjson", jsondata); 

	  // pass inputjson to replace component values
		request.setAttribute("OZViewerExportParam", param);
		String OZserver = "/server"; // OZ Server path
		RequestDispatcher dispatcher = pageContext.getServletContext().getRequestDispatcher(OZserver);		
		dispatcher.include(request, response);

		// get result from OZ server 
		boolean isSaved = false;
		Object o = request.getAttribute("OZViewerExportResult");
		if (o == null) {
			// Server Error
			Throwable t = (Throwable) request.getAttribute("OZViewerExportError");
			if(t != null) {
				throw t;
			} else {
				throw new Exception("No result from OZ Server.");
			}
		} else {
			// save as file in target format
			Hashtable t = (Hashtable) o;

			byte[] b = (byte[]) t.get(targetPath);
			if (b != null) {				
				isSaved = writefile(b, targetPath);
			} else {
				throw new Exception("targetPath is required: " + targetPath);
			}
			
			response.setContentType("text/html");

			if (isSaved)
			{   
				out.println("<br><br>Successfully exported. <a href=\"https://demo.ozeform.io/oz/guide/server-binding/export.pdf\">open PDF</a>");
			} 
		}

	} catch (Throwable e) {
		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);
		e.printStackTrace(pw);
		response.sendError(500, sw.getBuffer().toString());
	} finally {
	}
%>
```

{% endtab %}
{% endtabs %}

## Consolidation with Empty Viewer <a href="#consolidation-with-empty-viewer" id="consolidation-with-empty-viewer"></a>

今回は空ビューアを開き、OZRとOZDを開くことが可能なボタンを提供します。ユーザーがSubmitボタンを利用して入力値を提出すると、OZRまたはOZDがOZDファイルとしてサーバに伝送されます。OZDファイルをエクスポートする際、以前の例題のように生成されたOZDがフォームパラメータを許可するようにする必要があります。ユーザーはOZDファイルを開いてアップデートし、OZDとして再びエクスポートをすることが可能できます。PDFエクスポートボタンは、サーバでexport-ozd2pdf.jspを実行し、PDFを生成します。

{% tabs %}
{% tab title="export-form2ozd.html" %}

```markup
<!DOCTYPE html>
<html style="height:100%">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" type="text/css"/>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link rel="stylesheet" href="/oz/HTML5viewer/ui.dynatree.css" type="text/css"/>
<script type="text/javascript" src="/oz/HTML5viewer/jquery.dynatree.js" charset="utf-8"></script>
<script type="text/javascript" src="/oz/HTML5viewer/OZJSViewer.js" charset="utf-8"></script>

<script type="text/javascript" src="/oz/HTML5viewer/pdf_js/web/compatibility.js"></script>  
<script type="text/javascript" src="/oz/HTML5viewer/pdf_js/build/pdf.js"></script>
</head>
<body topmargin="0" leftmargin="0" style="width:98%;height:98%;webkit-text-size-adjust:none;">

Form File: <input type="text" id="file" size="100" value="">

<div> 
	<form>
		<input type="hidden" id="strOZD"	name="strOZD">
		<input type="button" value="open OZR" onClick="openOZR()">
		<input type="button" value="SUBMIT" onclick="Save_MemoryStream()">		
		<input type="button" value="open OZD" onClick="openOZD()">	
		<a href="https://demo.ozeform.io/oz/guide/server-binding/export-ozd2pdf.jsp">Export to PDF</a>
	</form>
</div>

<div id="ozviewer" style="width:98;height:90%"></div>

<script type="text/javascript" >

	function Save_MemoryStream() {
		ozviewer.ScriptEx("save_memorystream", "export.format=ozd; ozd.saveall=true; ozd.allowreplaceformparam=true; export.path=C:\\TEMP;export.mode=silent;export.filename=temp;export.confirmsave=false",";");	
		// export.path=C:\\TEMP -> "C:\\TEM" is just a dummy value, no meaning, but the option is required.
	}
	function OZCommand_ozviewer(cmd, msg) {
		// Do not remove this function. This is required for "save_memorystream" option to work correctly.
	}
	function OZExportMemoryStreamCallBack_ozviewer(outputdata) {			   
		if(outputdata == "{}") {
		  alert("Export failed.");
		}else {
			var obj = eval('(' + outputdata + ')');
			var value = null;
			for(var key in obj) value = obj[key];

			$('#strOZD').val(value);
			var param = $('form').serialize();	
 			var url = "./export-stream.jsp";

			$.ajax({
				type : "POST",
				url : url,
				data : param,
				async : false,
				success : sucessCallback,
				error : function(request, status, error) {
					if (request.status != '0') {
						alert("code : " + request.status + "\r\nmessage : "	+ request.reponseText + "\r\nerror : " + error);
					}
				}
			});
		}	   
    }
	var sucessCallback = function(data){
		alert("Export complete.");
	};
	
	function openOZR(){	
		var form = "connection.reportname=guide/server-binding/export.ozr; ";
		document.getElementById("file").value = form;
		var param = form + "connection.servlet=/oz/server; viewer.pagedisplay=singlepagecontinuous; comment.all=true; comment.selectedpen=highlightpen;";
		ozviewer.Script("closeall");
		ozviewer.CreateReportEx(param, ";");
    }

	function openOZD(){
	var date = new Date();
		var form = "connection.openfile=https://demo.ozeform.io/oz/guide/server-binding/export.ozd; ";
		document.getElementById("file").value = form;
		var formparam = "connection.pcount=1; connection.args1=date=" + date.toISOString() + ";";
		var param = form + formparam + "connection.servlet=/oz/server; viewer.pagedisplay=singlepagecontinuous; comment.all=true; comment.selectedpen=highlightpen;";
		alert(param);
		ozviewer.Script("closeall");
		ozviewer.CreateReportEx(param, ";");
    }

    function SetOZParamters_ozviewer()	{	
        var oz = document.getElementById("ozviewer");
		oz.sendToActionScript("viewer.emptyframe", "true");
        return true;
    }
    start_ozjs("ozviewer", "/oz/HTML5viewer/");

</script>
</body>
</html>
```

{% endtab %}
{% endtabs %}

​[Run sample](http://oz.ozeform.io/oz/guide/server-binding/server-binding.html)

{% file src="/files/-MJa8Xe2dmJKOINCZ724" %}
guiide-server-binding.zip
{% endfile %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jp.ozeform.io/bjonbakkuappu/oz-server-binding.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
