DataFlex Requires Chilkat v11.7.0+
DataFlex
Box: Upload a Large File in Parts and Commit the Session
See more Box Examples
Run the reusable setup once per HttpCurl object, then select names and execute the operation. The setup is repeated here only to make this published example independently runnable. Resolve documents by name, then perform the explicit chunked-upload session, part, and commit loop. Supports 20 MB through 2 GB using int. Saves recovery information and honors bounded commit Retry-After.
See the Box API guide for setup and the complete workflow.
Chilkat DataFlex Downloads
Use ChilkatAx-win32.pkg
Procedure Test
Boolean iSuccess
Handle hoCurl
Handle hoSetupCommand
Integer iSetupReplacements
String sParentName
String sFolderName
Handle hoAuthorizedCommand1
Integer iHeaderReplacement1
String sLocalPath
Handle hoFile
String sSizeString
Handle hoSizeText
Variant vSizeMatch
Handle hoSizeMatch
Integer iFileSize
Handle hoHttp
Variant vResponse
Handle hoResponse
Variant vRequest
Handle hoRequest
Handle hoSession
Integer iPartSize
String sUploadUrl
String sCommitUrl
Handle hoHash
String sFileDigest
Variant vCommit
Handle hoCommit
Handle hoPartResponse
Variant vChunk
Handle hoChunk
Handle hoRange
Handle hoDigestHeader
Integer iOffset
Integer iPartIndex
Integer iPartLength
Integer iLastByte
String sPartDigest
Integer iAttempts
Integer iWaitSeconds
Handle hoRetryHeader
Variant vRetryMatch
Handle hoRetryMatch
Boolean iCompleted
String sTemp1
Integer iTemp1
Boolean bTemp1
Move False To iSuccess
// Requires Chilkat 11.7.0 or later and a previously unlocked Chilkat bundle.
// See Global Unlock Sample.
// Guide: Box API Guide.
Move False To iSuccess
// BEGIN ONE-TIME SETUP
// This block is repeated so each published example can run on its own.
// In an application, run the setup example once and pass the SAME curl object
// to operation code below. Do not recreate it for every operation.
// See Reusable Box HttpCurl Setup.
Get Create (RefClass(cComChilkatHttpCurl)) To hoCurl
If (Not(IsComObjectCreated(hoCurl))) Begin
Send CreateComObject of hoCurl
End
Send ComSetVar To hoCurl "access_token" "BOX_ACCESS_TOKEN"
Send ComSetVar To hoCurl "parent_name" "/"
// Box's fixed root ID is an implementation detail; callers supply names.
Send ComSetVar To hoCurl "parent_id" "0"
Get Create (RefClass(cComChilkatStringBuilder)) To hoSetupCommand
If (Not(IsComObjectCreated(hoSetupCommand))) Begin
Send CreateComObject of hoSetupCommand
End
// Register findParent; registration sends no request.
Get ComSetString Of hoSetupCommand 'curl -X GET "https://api.box.com/2.0/folders/0/items?limit=1000&fields=id,type,name" -H "Authorization: Bearer ACCESS_TOKEN"' To iSuccess
Get ComGetVar Of hoCurl "access_token" To sTemp1
Get ComReplace Of hoSetupCommand "ACCESS_TOKEN" sTemp1 To iSetupReplacements
Get ComGetAsString Of hoSetupCommand To sTemp1
Get ComAddFunction Of hoCurl "findParent" sTemp1 To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoCurl To sTemp1
Showln sTemp1
Procedure_Return
End
// Register findFolder; registration sends no request.
Get ComSetString Of hoSetupCommand 'curl -X GET "https://api.box.com/2.0/folders/{{parent_id}}/items?limit=1000&fields=id,type,name" -H "Authorization: Bearer ACCESS_TOKEN"' To iSuccess
Get ComGetVar Of hoCurl "access_token" To sTemp1
Get ComReplace Of hoSetupCommand "ACCESS_TOKEN" sTemp1 To iSetupReplacements
Get ComGetAsString Of hoSetupCommand To sTemp1
Get ComAddFunction Of hoCurl "findFolder" sTemp1 To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoCurl To sTemp1
Showln sTemp1
Procedure_Return
End
// Register findFile; registration sends no request.
Get ComSetString Of hoSetupCommand 'curl -X GET "https://api.box.com/2.0/folders/{{folder_id}}/items?limit=1000&fields=id,type,name" -H "Authorization: Bearer ACCESS_TOKEN"' To iSuccess
Get ComGetVar Of hoCurl "access_token" To sTemp1
Get ComReplace Of hoSetupCommand "ACCESS_TOKEN" sTemp1 To iSetupReplacements
Get ComGetAsString Of hoSetupCommand To sTemp1
Get ComAddFunction Of hoCurl "findFile" sTemp1 To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoCurl To sTemp1
Showln sTemp1
Procedure_Return
End
// Register findDestination; registration sends no request.
Get ComSetString Of hoSetupCommand 'curl -X GET "https://api.box.com/2.0/folders/0/items?limit=1000&fields=id,type,name" -H "Authorization: Bearer ACCESS_TOKEN"' To iSuccess
Get ComGetVar Of hoCurl "access_token" To sTemp1
Get ComReplace Of hoSetupCommand "ACCESS_TOKEN" sTemp1 To iSetupReplacements
Get ComGetAsString Of hoSetupCommand To sTemp1
Get ComAddFunction Of hoCurl "findDestination" sTemp1 To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoCurl To sTemp1
Showln sTemp1
Procedure_Return
End
// Register getFileDetails; registration sends no request.
Get ComSetString Of hoSetupCommand 'curl -X GET "https://api.box.com/2.0/files/{{file_id}}?fields=id,sha1,file_version" -H "Authorization: Bearer ACCESS_TOKEN"' To iSuccess
Get ComGetVar Of hoCurl "access_token" To sTemp1
Get ComReplace Of hoSetupCommand "ACCESS_TOKEN" sTemp1 To iSetupReplacements
Get ComGetAsString Of hoSetupCommand To sTemp1
Get ComAddFunction Of hoCurl "getFileDetails" sTemp1 To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoCurl To sTemp1
Showln sTemp1
Procedure_Return
End
// Register getEnterprise; registration sends no request.
Get ComSetString Of hoSetupCommand 'curl -X GET "https://api.box.com/2.0/users/me?fields=enterprise" -H "Authorization: Bearer ACCESS_TOKEN"' To iSuccess
Get ComGetVar Of hoCurl "access_token" To sTemp1
Get ComReplace Of hoSetupCommand "ACCESS_TOKEN" sTemp1 To iSetupReplacements
Get ComGetAsString Of hoSetupCommand To sTemp1
Get ComAddFunction Of hoCurl "getEnterprise" sTemp1 To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoCurl To sTemp1
Showln sTemp1
Procedure_Return
End
// Register output rules once. Chilkat 11.7.0 evaluates {{name}} variables
// when extracting each output, using the current value at that time.
Get ComAddOutput2 Of hoCurl "findParent" "entries" "name" "{{parent_name}}" True "id" "parent_id" To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoCurl To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComAddOutput2 Of hoCurl "findFolder" "entries" "name" "{{folder_name}}" True "id" "folder_id" To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoCurl To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComAddOutput2 Of hoCurl "findFile" "entries" "name" "{{file_name}}" True "id" "file_id" To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoCurl To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComAddOutput2 Of hoCurl "findDestination" "entries" "name" "{{destination_name}}" True "id" "destination_id" To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoCurl To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComAddOutput Of hoCurl "getFileDetails" "file_version.id" "file_version_id" To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoCurl To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComAddOutput Of hoCurl "getFileDetails" "sha1" "file_sha1" To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoCurl To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComAddOutput Of hoCurl "getEnterprise" "enterprise.id" "enterprise_id" To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoCurl To sTemp1
Showln sTemp1
Procedure_Return
End
// END ONE-TIME SETUP
// The name lookups below assume each listing fits in one page (1000 items).
// Parent and destination names select root children; folder_name selects a child
// of parent_name. "/" selects the root parent. These are not arbitrary paths.
// BEGIN OPERATION -- keep the configured object when reusing it.
// Inputs are names. Retain cached IDs when the selected names have not changed.
Move "/" To sParentName
Move "documents" To sFolderName
Get ComGetVar Of hoCurl "parent_name" To sTemp1
Get ComVarDefined Of hoCurl "parent_id" To bTemp1
If ((sTemp1 <> sParentName) Or ((sParentName = "/") And (bTemp1 = False))) Begin
Send ComSetVar To hoCurl "parent_name" sParentName
Send ComClearVar To hoCurl "parent_id"
Send ComClearVar To hoCurl "folder_id"
Send ComClearVar To hoCurl "file_id"
Send ComClearVar To hoCurl "file_version_id"
Send ComClearVar To hoCurl "file_sha1"
If (sParentName = "/") Begin
Send ComSetVar To hoCurl "parent_id" "0"
End
End
Get ComGetVar Of hoCurl "folder_name" To sTemp1
If (sTemp1 <> sFolderName) Begin
Send ComSetVar To hoCurl "folder_name" sFolderName
Send ComClearVar To hoCurl "folder_id"
Send ComClearVar To hoCurl "file_id"
Send ComClearVar To hoCurl "file_version_id"
Send ComClearVar To hoCurl "file_sha1"
End
// Resolve the named destination first. HttpCurl does not expand variables
// inside multipart -F attributes in the tested build, so this upload is two phases.
Send ComClearTargetOutput To hoCurl "*"
Get Create (RefClass(cComChilkatStringBuilder)) To hoAuthorizedCommand1
If (Not(IsComObjectCreated(hoAuthorizedCommand1))) Begin
Send CreateComObject of hoAuthorizedCommand1
End
Get ComSetString Of hoAuthorizedCommand1 'curl -X GET "https://api.box.com/2.0/folders/{{folder_id}}?fields=id" -H "Authorization: Bearer {{access_token}}"' To iSuccess
Get ComGetVar Of hoCurl "access_token" To sTemp1
Get ComReplace Of hoAuthorizedCommand1 "{{access_token}}" sTemp1 To iHeaderReplacement1
Get ComGetAsString Of hoAuthorizedCommand1 To sTemp1
Get ComDoYourThing Of hoCurl sTemp1 To iSuccess
Get ComStatusCode Of hoCurl To iTemp1
If ((iSuccess <> True) Or (iTemp1 <> 200)) Begin
Get ComStatusCode Of hoCurl To iTemp1
Showln "Box request failed. HTTP status: " iTemp1
Get ComFailReason Of hoCurl To iTemp1
Showln "Failure reason: " iTemp1
Get ComResponseBodyStr Of hoCurl To sTemp1
Showln sTemp1
Procedure_Return
End
// This example limits size to 2 GB so offsets fit all generated languages' integers.
// The source must not change during hashing or upload. Create qa_output first.
Move "qa_data/large-document.zip" To sLocalPath
Get Create (RefClass(cComCkFileAccess)) To hoFile
If (Not(IsComObjectCreated(hoFile))) Begin
Send CreateComObject of hoFile
End
// Check the decimal size before converting so an oversized file cannot overflow int.
Get ComFileSizeStr Of hoFile sLocalPath To sSizeString
Get ComLastMethodSuccess Of hoFile To bTemp1
If (bTemp1 <> True) Begin
Get ComLastErrorText Of hoFile To sTemp1
Showln sTemp1
Procedure_Return
End
Get Create (RefClass(cComChilkatStringBuilder)) To hoSizeText
If (Not(IsComObjectCreated(hoSizeText))) Begin
Send CreateComObject of hoSizeText
End
Get ComSetString Of hoSizeText sSizeString To iSuccess
Get Create (RefClass(cComChilkatJsonObject)) To hoSizeMatch
If (Not(IsComObjectCreated(hoSizeMatch))) Begin
Send CreateComObject of hoSizeMatch
End
Get ComRegexMatch Of hoSizeText "^([0-9]{1,9}|1[0-9]{9}|2000000000)$" Get pvComObject of hoSizeMatch to vSizeMatch
vSizeMatch 100 To iTemp1
If (iTemp1 <> 1) Begin
Showln "Choose an input between 20 MB and 2 GB for this example."
Procedure_Return
End
Move (sSizeString) To iFileSize
If (iFileSize < 20971520) Begin
Showln "Choose an input between 20 MB and 2 GB for this example."
Procedure_Return
End
Get Create (RefClass(cComChilkatHttp)) To hoHttp
If (Not(IsComObjectCreated(hoHttp))) Begin
Send CreateComObject of hoHttp
End
Get ComGetVar Of hoCurl "access_token" To sTemp1
Set ComAuthToken Of hoHttp To sTemp1
Get Create (RefClass(cComChilkatHttpResponse)) To hoResponse
If (Not(IsComObjectCreated(hoResponse))) Begin
Send CreateComObject of hoResponse
End
Get Create (RefClass(cComChilkatJsonObject)) To hoRequest
If (Not(IsComObjectCreated(hoRequest))) Begin
Send CreateComObject of hoRequest
End
Get ComGetVar Of hoCurl "folder_id" To sTemp1
Get ComUpdateString Of hoRequest "folder_id" sTemp1 To iSuccess
Get ComUpdateString Of hoRequest "file_name" "large-document.zip" To iSuccess
Get ComUpdateInt Of hoRequest "file_size" iFileSize To iSuccess
Get pvComObject of hoRequest to vRequest
Get pvComObject of hoResponse to vResponse
Get ComHttpJson Of hoHttp "POST" "https://upload.box.com/api/2.0/files/upload_sessions" vRequest "application/json" vResponse To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoHttp To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComStatusCode Of hoResponse To iTemp1
If (iTemp1 <> 201) Begin
Get ComBodyStr Of hoResponse To sTemp1
Showln sTemp1
Procedure_Return
End
Get Create (RefClass(cComChilkatJsonObject)) To hoSession
If (Not(IsComObjectCreated(hoSession))) Begin
Send CreateComObject of hoSession
End
Get ComBodyStr Of hoResponse To sTemp1
Get ComLoad Of hoSession sTemp1 To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoSession To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComWriteFile Of hoSession "qa_output/box_upload_session.json" To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoSession To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComIntOf Of hoSession "part_size" To iPartSize
Get ComStringOf Of hoSession "session_endpoints.upload_part" To sUploadUrl
Get ComStringOf Of hoSession "session_endpoints.commit" To sCommitUrl
If ((iPartSize <= 0) Or (sUploadUrl = "") Or (sCommitUrl = "")) Begin
Showln "Invalid session response."
Procedure_Return
End
Get Create (RefClass(cComChilkatCrypt2)) To hoHash
If (Not(IsComObjectCreated(hoHash))) Begin
Send CreateComObject of hoHash
End
Set ComHashAlgorithm Of hoHash To "sha1"
Set ComEncodingMode Of hoHash To "base64"
Get ComHashFileENC Of hoHash sLocalPath To sFileDigest
Get ComLastMethodSuccess Of hoHash To bTemp1
If (bTemp1 <> True) Begin
Get ComLastErrorText Of hoHash To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComFileOpen Of hoFile sLocalPath 2147483648 1 3 0 To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoFile To sTemp1
Showln sTemp1
Procedure_Return
End
Get Create (RefClass(cComChilkatJsonObject)) To hoCommit
If (Not(IsComObjectCreated(hoCommit))) Begin
Send CreateComObject of hoCommit
End
Get Create (RefClass(cComChilkatJsonObject)) To hoPartResponse
If (Not(IsComObjectCreated(hoPartResponse))) Begin
Send CreateComObject of hoPartResponse
End
Get Create (RefClass(cComChilkatBinData)) To hoChunk
If (Not(IsComObjectCreated(hoChunk))) Begin
Send CreateComObject of hoChunk
End
Get Create (RefClass(cComChilkatStringBuilder)) To hoRange
If (Not(IsComObjectCreated(hoRange))) Begin
Send CreateComObject of hoRange
End
Get Create (RefClass(cComChilkatStringBuilder)) To hoDigestHeader
If (Not(IsComObjectCreated(hoDigestHeader))) Begin
Send CreateComObject of hoDigestHeader
End
Move 0 To iOffset
Move 0 To iPartIndex
While (iOffset < iFileSize)
Get ComClear Of hoChunk To iSuccess
Get pvComObject of hoChunk to vChunk
Get ComFileReadBd Of hoFile iPartSize vChunk To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoFile To sTemp1
Showln sTemp1
Send ComFileClose To hoFile
Procedure_Return
End
Get ComNumBytes Of hoChunk To iPartLength
If (iPartLength <= 0) Begin
Showln "Unexpected end of file."
Send ComFileClose To hoFile
Procedure_Return
End
Move (iOffset + (iPartLength - 1)) To iLastByte
Send ComClear To hoRange
Get ComAppend Of hoRange "bytes " To iSuccess
Get ComAppendInt Of hoRange iOffset To iSuccess
Get ComAppend Of hoRange "-" To iSuccess
Get ComAppendInt Of hoRange iLastByte To iSuccess
Get ComAppend Of hoRange "/" To iSuccess
Get ComAppendInt Of hoRange iFileSize To iSuccess
Get pvComObject of hoChunk to vChunk
Get ComHashBdENC Of hoHash vChunk To sPartDigest
Get ComLastMethodSuccess Of hoHash To bTemp1
If (bTemp1 <> True) Begin
Get ComLastErrorText Of hoHash To sTemp1
Showln sTemp1
Send ComFileClose To hoFile
Procedure_Return
End
Get ComSetString Of hoDigestHeader "sha=" To iSuccess
Get ComAppend Of hoDigestHeader sPartDigest To iSuccess
Get ComGetAsString Of hoDigestHeader To sTemp1
Send ComSetRequestHeader To hoHttp "Digest" sTemp1
Get ComGetAsString Of hoRange To sTemp1
Send ComSetRequestHeader To hoHttp "Content-Range" sTemp1
Get pvComObject of hoChunk to vChunk
Get pvComObject of hoResponse to vResponse
Get ComHttpBd Of hoHttp "PUT" sUploadUrl vChunk "application/octet-stream" vResponse To iSuccess
Get ComStatusCode Of hoResponse To iTemp1
If ((iSuccess <> True) Or (iTemp1 <> 200)) Begin
Get ComStatusCode Of hoResponse To iTemp1
Showln "Part failed. HTTP status: " iTemp1
Get ComBodyStr Of hoResponse To sTemp1
Showln sTemp1
Showln "Inspect the saved session and server list_parts before retrying this part."
Send ComFileClose To hoFile
Procedure_Return
End
Get ComBodyStr Of hoResponse To sTemp1
Get ComLoad Of hoPartResponse sTemp1 To iSuccess
If (iSuccess <> True) Begin
Send ComFileClose To hoFile
Procedure_Return
End
Set ComI Of hoCommit To iPartIndex
// Copy the server's acknowledged part fields into the commit manifest.
Get ComStringOf Of hoPartResponse "part.part_id" To sTemp1
Get ComUpdateString Of hoCommit "parts[i].part_id" sTemp1 To iSuccess
Get ComIntOf Of hoPartResponse "part.offset" To iTemp1
Get ComUpdateInt Of hoCommit "parts[i].offset" iTemp1 To iSuccess
Get ComIntOf Of hoPartResponse "part.size" To iTemp1
Get ComUpdateInt Of hoCommit "parts[i].size" iTemp1 To iSuccess
Get ComStringOf Of hoPartResponse "part.sha1" To sTemp1
Get ComUpdateString Of hoCommit "parts[i].sha1" sTemp1 To iSuccess
Get ComWriteFile Of hoCommit "qa_output/box_upload_parts.json" To iSuccess
If (iSuccess <> True) Begin
Get ComLastErrorText Of hoCommit To sTemp1
Showln sTemp1
Send ComFileClose To hoFile
Procedure_Return
End
Move (iOffset + iPartLength) To iOffset
Move (iPartIndex + 1) To iPartIndex
Loop
Send ComFileClose To hoFile
Send ComRemoveRequestHeader To hoHttp "Content-Range"
Get ComSetString Of hoDigestHeader "sha=" To iSuccess
Get ComAppend Of hoDigestHeader sFileDigest To iSuccess
Get ComGetAsString Of hoDigestHeader To sTemp1
Send ComSetRequestHeader To hoHttp "Digest" sTemp1
Move 0 To iAttempts
Get Create (RefClass(cComChilkatStringBuilder)) To hoRetryHeader
If (Not(IsComObjectCreated(hoRetryHeader))) Begin
Send CreateComObject of hoRetryHeader
End
Get Create (RefClass(cComChilkatJsonObject)) To hoRetryMatch
If (Not(IsComObjectCreated(hoRetryMatch))) Begin
Send CreateComObject of hoRetryMatch
End
Move False To iCompleted
While ((iAttempts < 10) And (iCompleted = False))
Get pvComObject of hoCommit to vCommit
Get pvComObject of hoResponse to vResponse
Get ComHttpJson Of hoHttp "POST" sCommitUrl vCommit "application/json" vResponse To iSuccess
If (iSuccess <> True) Begin
Get ComStatusCode Of hoResponse To iTemp1
Showln "Commit failed: " iTemp1
Get ComBodyStr Of hoResponse To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComStatusCode Of hoResponse To iTemp1
If (iTemp1 = 201) Begin
Move True To iCompleted
End
Else Begin
Get ComStatusCode Of hoResponse To iTemp1
If (iTemp1 <> 202) Begin
Get ComStatusCode Of hoResponse To iTemp1
Showln "Unexpected commit status: " iTemp1
Procedure_Return
End
// Box's asynchronous commit response supplies Retry-After in seconds.
Get ComGetHeaderField Of hoResponse "Retry-After" To sTemp1
Get ComSetString Of hoRetryHeader sTemp1 To iSuccess
Get ComRegexMatch Of hoRetryHeader "^[0-9]{1,2}$" Get pvComObject of hoRetryMatch to vRetryMatch
vRetryMatch 100 To iTemp1
If (iTemp1 <> 1) Begin
Get ComGetAsString Of hoRetryHeader To sTemp1
Showln "Commit pending. Preserve the session and inspect Retry-After before resuming: " sTemp1
Procedure_Return
End
Get ComGetAsString Of hoRetryHeader To sTemp1
Move (sTemp1) To iWaitSeconds
If ((iWaitSeconds < 1) Or (iWaitSeconds > 60)) Begin
Get ComGetHeaderField Of hoResponse "Retry-After" To sTemp1
Showln "Commit pending. Resume commit after Retry-After: " sTemp1
Procedure_Return
End
Send ComSleepMs To hoHttp (iWaitSeconds * 1000)
End
Move (iAttempts + 1) To iAttempts
Loop
If (iCompleted = False) Begin
Showln "Commit still pending; retain session and part manifests to resume commit later."
Procedure_Return
End
Get ComBodyStr Of hoResponse To sTemp1
Showln "Upload committed: " sTemp1
End_Procedure