Is it possible to create a wrapper for uploading to CloudApp? Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Is it possible to create a wrapper for uploading to CloudApp?

09 Jan 2019, 18:49

I've never dealt with html scraping, and I really don't want to go down that path if I don't have to, but is it possible to create something that can upload to CloudApp, hopefully without using a browser?

I found this, but I don't know how to use that language.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Is it possible to create a wrapper for uploading to CloudApp?

12 Jan 2019, 13:19

Just wrote one :)

CloudApp.ahk

Code: Select all

/*
	Requires:
		CreateFormData.ahk - https://gist.github.com/tmplinshi/8428a280bba58d25ef0b
		BinArr.ahk         - https://gist.github.com/tmplinshi/a97d9a99b9aa5a65fd20
		Jxon.ahk (by Coco) - https://www.autohotkey.com/boards/viewtopic.php?t=627

	Supported methods:
		CreateBookmark(name, url)
		ListItems(paramters := "page=1&per_page=5")
		DeleteItem(url)
		ViewItem(url)
		uploadFile(FilePath)

	Example:
		api := New CloudApp("your email", "your password")
		objResult := api.uploadFile("D:\Desktop\1.jpg")
		MsgBox % Jxon_Dump(objResult)
*/


; CloudApp API Document: https://github.com/cloudapp/api/blob/master/README.md

class CloudApp
{
	whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")

	__New(email, password) {
		this.http("GET", "https://my.cl.ly/account")
		auth := DigestAuth.Build(email, password, "GET", "/account", this.whr.getResponseHeader("WWW-Authenticate"))

		oHeaders := {"Authorization": auth}
		this.http("GET", "https://my.cl.ly/account",, oHeaders)
		this.getCookie()

		if (this.whr.Status != 200)
			throw "Login failed"
	}

	CreateBookmark(name, url) {
		body := {item: {name: name, redirect_url: url}}
		return this.http("POST", "https://my.cl.ly/items", body)
	}

	/*
		Optional paramters:
			page=1 : Page number starting at 1.
			per_page=5 : Number of items per page.
			type=image : Filter items by type (image, bookmark, text, archive, audio, video, or unknown).
			deleted=true : Show trashed items.
			source=MyApp : Filter items by all or part of the User-Agent.
	*/
	ListItems(paramters := "page=1&per_page=5") {
		return this.http("GET", "https://my.cl.ly/items?" paramters)
	}

	DeleteItem(url) {
		return this.http("DELETE", url)
	}

	ViewItem(url) {
		return this.http("GET", url)
	}

	uploadFile(FilePath) {
		ret := this.http("GET", "https://my.cl.ly/items/new")

		objParam := ret.params
		objParam.file := [FilePath]
		CreateFormData(body, vContentType, objParam)

		oHeaders := {"Content-Type": vContentType}
		return this.http("POST", ret.url, body, oHeaders, 600)
	}

	http(method, url, body := "", oHeaders := "", timeoutSeconds := 30) {
		whr := this.whr
		whr.Open(method, url, true)

		whr.SetRequestHeader("Accept", "application/json")
		if !oHeaders.HasKey("Content-Type") {
			whr.SetRequestHeader("Content-Type", "application/json")
		}
		if this.cookie {
			whr.SetRequestHeader("Cookie", this.cookie)
		}
		for k, v in oHeaders
			whr.SetRequestHeader(k, v)

		try {
			if IsObject(body)
				body := Jxon_Dump(body)
		}

		If (timeoutSeconds > 30)
			whr.SetTimeouts(0, 60000, 30000, timeoutSeconds * 1000)

		whr.Send(body)
		whr.WaitForResponse()

		if InStr(whr.getResponseHeader("Content-Type"), "application/json")
			return Jxon_Load(whr.responseText)
	}

	getCookie() {
		hdrs := this.whr.getAllResponseHeaders()

		pos := 1
		while pos := RegExMatch(hdrs, "`am)^Set-Cookie: \K[^;]+", m, pos+StrLen(m))
			this.cookie .= (A_Index>1 ? "; " : "") . m
	}
}

; https://en.wikipedia.org/wiki/Digest_access_authentication
class DigestAuth
{
	Build(username, password, method, uri, ByRef WWWAuthenticate) {
		Loop, Parse, % "realm|qop|algorithm|nonce|opaque", |
			RegExMatch(WWWAuthenticate, A_LoopField "=""?\K[^,""]+", %A_LoopField%)

		cnonce := this.create_cnonce()
		nonceCount := "00000001"

		ha1 := this.StrMD5(username ":" realm ":" password)
		ha2 := this.StrMD5(method ":" uri)
		response := this.StrMD5(ha1 ":" nonce ":" nonceCount ":" cnonce ":" qop ":" ha2)

		return "
		(Join, LTrim
			Digest username=""" username """
			realm=""" realm """
			nonce=""" nonce """
			uri=""" uri """
			algorithm=""" algorithm """
			cnonce=""" cnonce """
			nc=" nonceCount "
			qop=""" qop """
			response=""" response """
			opaque=""" opaque """
		)"
	}

	StrMD5( V ) { ; www.autohotkey.com/forum/viewtopic.php?p=376840#376840
		VarSetCapacity( MD5_CTX,104,0 ), DllCall( "advapi32\MD5Init", UInt,&MD5_CTX ) 
		DllCall( "advapi32\MD5Update", UInt,&MD5_CTX, A_IsUnicode ? "AStr" : "Str",V 
		, UInt,StrLen(V) ), DllCall( "advapi32\MD5Final", UInt,&MD5_CTX ) 
		Loop % StrLen( Hex:="123456789abcdef0" ) 
			N := NumGet( MD5_CTX,87+A_Index,"Char"), MD5 .= SubStr(Hex,N>>4,1) . SubStr(Hex,N&15,1)
		Return MD5 
	}

	CreateGUID() { ; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=4732
		VarSetCapacity(pguid, 16, 0)
		if !(DllCall("ole32.dll\CoCreateGuid", "ptr", &pguid)) {
			size := VarSetCapacity(sguid, (38 << !!A_IsUnicode) + 1, 0)
			if (DllCall("ole32.dll\StringFromGUID2", "ptr", &pguid, "ptr", &sguid, "int", size))
				return StrGet(&sguid)
		}
		return ""
	}

	create_cnonce() {
		guid := this.CreateGUID()
		StringLower, guid, guid
		return RegExReplace(guid, "[{}-]")
	}
}
Example:

Code: Select all

; Register your account at https://www.getcloudapp.com/

#Include CloudApp.ahk

; Login
api := New CloudApp("your email", "your password")

; Upload File
objResult := api.uploadFile("D:\Desktop\1.jpg")
MsgBox % Jxon_Dump(objResult)
Download: https://github.com/tmplinshi/CloudApp.ahk
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Re: Is it possible to create a wrapper for uploading to CloudApp?  Topic is solved

12 Jan 2019, 19:36

tmplinshi wrote:
12 Jan 2019, 13:19
Just wrote one :)

CloudApp.ahk

Code: Select all

/*
	Requires:
		CreateFormData.ahk - https://gist.github.com/tmplinshi/8428a280bba58d25ef0b
		BinArr.ahk         - https://gist.github.com/tmplinshi/a97d9a99b9aa5a65fd20
		Jxon.ahk (by Coco) - https://www.autohotkey.com/boards/viewtopic.php?t=627

	Supported methods:
		CreateBookmark(name, url)
		ListItems(paramters := "page=1&per_page=5")
		DeleteItem(url)
		ViewItem(url)
		uploadFile(FilePath)

	Example:
		api := New CloudApp("your email", "your password")
		objResult := api.uploadFile("D:\Desktop\1.jpg")
		MsgBox % Jxon_Dump(objResult)
*/


; CloudApp API Document: https://github.com/cloudapp/api/blob/master/README.md

class CloudApp
{
	whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")

	__New(email, password) {
		this.http("GET", "https://my.cl.ly/account")
		auth := DigestAuth.Build(email, password, "GET", "/account", this.whr.getResponseHeader("WWW-Authenticate"))

		oHeaders := {"Authorization": auth}
		this.http("GET", "https://my.cl.ly/account",, oHeaders)
		this.getCookie()

		if (this.whr.Status != 200)
			throw "Login failed"
	}

	CreateBookmark(name, url) {
		body := {item: {name: name, redirect_url: url}}
		return this.http("POST", "https://my.cl.ly/items", body)
	}

	/*
		Optional paramters:
			page=1 : Page number starting at 1.
			per_page=5 : Number of items per page.
			type=image : Filter items by type (image, bookmark, text, archive, audio, video, or unknown).
			deleted=true : Show trashed items.
			source=MyApp : Filter items by all or part of the User-Agent.
	*/
	ListItems(paramters := "page=1&per_page=5") {
		return this.http("GET", "https://my.cl.ly/items?" paramters)
	}

	DeleteItem(url) {
		return this.http("DELETE", url)
	}

	ViewItem(url) {
		return this.http("GET", url)
	}

	uploadFile(FilePath) {
		ret := this.http("GET", "https://my.cl.ly/items/new")

		objParam := ret.params
		objParam.file := [FilePath]
		CreateFormData(body, vContentType, objParam)

		oHeaders := {"Content-Type": vContentType}
		return this.http("POST", ret.url, body, oHeaders, 600)
	}

	http(method, url, body := "", oHeaders := "", timeoutSeconds := 30) {
		whr := this.whr
		whr.Open(method, url, true)

		whr.SetRequestHeader("Accept", "application/json")
		if !oHeaders.HasKey("Content-Type") {
			whr.SetRequestHeader("Content-Type", "application/json")
		}
		if this.cookie {
			whr.SetRequestHeader("Cookie", this.cookie)
		}
		for k, v in oHeaders
			whr.SetRequestHeader(k, v)

		try {
			if IsObject(body)
				body := Jxon_Dump(body)
		}

		If (timeoutSeconds > 30)
			whr.SetTimeouts(0, 60000, 30000, timeoutSeconds * 1000)

		whr.Send(body)
		whr.WaitForResponse()

		if InStr(whr.getResponseHeader("Content-Type"), "application/json")
			return Jxon_Load(whr.responseText)
	}

	getCookie() {
		hdrs := this.whr.getAllResponseHeaders()

		pos := 1
		while pos := RegExMatch(hdrs, "`am)^Set-Cookie: \K[^;]+", m, pos+StrLen(m))
			this.cookie .= (A_Index>1 ? "; " : "") . m
	}
}

; https://en.wikipedia.org/wiki/Digest_access_authentication
class DigestAuth
{
	Build(username, password, method, uri, ByRef WWWAuthenticate) {
		Loop, Parse, % "realm|qop|algorithm|nonce|opaque", |
			RegExMatch(WWWAuthenticate, A_LoopField "=""?\K[^,""]+", %A_LoopField%)

		cnonce := this.create_cnonce()
		nonceCount := "00000001"

		ha1 := this.StrMD5(username ":" realm ":" password)
		ha2 := this.StrMD5(method ":" uri)
		response := this.StrMD5(ha1 ":" nonce ":" nonceCount ":" cnonce ":" qop ":" ha2)

		return "
		(Join, LTrim
			Digest username=""" username """
			realm=""" realm """
			nonce=""" nonce """
			uri=""" uri """
			algorithm=""" algorithm """
			cnonce=""" cnonce """
			nc=" nonceCount "
			qop=""" qop """
			response=""" response """
			opaque=""" opaque """
		)"
	}

	StrMD5( V ) { ; www.autohotkey.com/forum/viewtopic.php?p=376840#376840
		VarSetCapacity( MD5_CTX,104,0 ), DllCall( "advapi32\MD5Init", UInt,&MD5_CTX ) 
		DllCall( "advapi32\MD5Update", UInt,&MD5_CTX, A_IsUnicode ? "AStr" : "Str",V 
		, UInt,StrLen(V) ), DllCall( "advapi32\MD5Final", UInt,&MD5_CTX ) 
		Loop % StrLen( Hex:="123456789abcdef0" ) 
			N := NumGet( MD5_CTX,87+A_Index,"Char"), MD5 .= SubStr(Hex,N>>4,1) . SubStr(Hex,N&15,1)
		Return MD5 
	}

	CreateGUID() { ; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=4732
		VarSetCapacity(pguid, 16, 0)
		if !(DllCall("ole32.dll\CoCreateGuid", "ptr", &pguid)) {
			size := VarSetCapacity(sguid, (38 << !!A_IsUnicode) + 1, 0)
			if (DllCall("ole32.dll\StringFromGUID2", "ptr", &pguid, "ptr", &sguid, "int", size))
				return StrGet(&sguid)
		}
		return ""
	}

	create_cnonce() {
		guid := this.CreateGUID()
		StringLower, guid, guid
		return RegExReplace(guid, "[{}-]")
	}
}
Example:

Code: Select all

; Register your account at https://www.getcloudapp.com/

#Include CloudApp.ahk

; Login
api := New CloudApp("your email", "your password")

; Upload File
objResult := api.uploadFile("D:\Desktop\1.jpg")
MsgBox % Jxon_Dump(objResult)
Download: https://github.com/tmplinshi/CloudApp.ahk

Getting an error on Line 36 of CloudApp.ahk when launched from Test.CloudApp.ahk. I'm guessing that throw requires a catch?? I've never used it before. Changing throw to MsgBox clears the error and displays "Login Failed".

I've not seen some of the code you provided... very interesting and I will have to spend some time going through it line by line to understand it.

Question:
Do I need to provide the credentials enclosed in quotes when setting the API?
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Is it possible to create a wrapper for uploading to CloudApp?

12 Jan 2019, 22:07

TXShooter wrote:
12 Jan 2019, 19:36
Do I need to provide the credentials enclosed in quotes when setting the API?
Yes.
api := New CloudApp("your email", "your password")
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Re: Is it possible to create a wrapper for uploading to CloudApp?

22 Jan 2019, 08:27

I finally had a chance to implement this code into my script. The first several times everything went as planned, but the last two garnered an error, "Show Something". I couldn't track down what caused it, and I didn't grab a screen shot.

Any idea what may have thrown that flag?
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Is it possible to create a wrapper for uploading to CloudApp?

22 Jan 2019, 11:27

It might be timeout, or big files. I tried uploading a 916MB file, and got an error from "ADODB.Stream":

Code: Select all

Error in #include file "D:\code\AutoHotkey\Lib\BinArr.ahk":
     0x8007000E - Not enough memory resources are available to complete this operation.
Source:		Provider
Description:	Not enough memory resources are available to complete this operation.
HelpFile:		(null)
HelpContext:	1240640

Specifically: Read

	Line#
	015: Return,oADO.Read, oADO.Close
	016: }
	018: {
	019: oADO := ComObjCreate("ADODB.Stream")
	021: oADO.Type := 1  
	022: oADO.Open  
	023: oADO.LoadFromFile(FileName)  
--->	024: Return,oADO.Read, oADO.Close
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Is it possible to create a wrapper for uploading to CloudApp?

22 Jan 2019, 13:52

@malcev Because I haven't encountered any error for my scripts using the ADO object, and I'm too lazy to take the time learning the memory approach.. It's on my to-do list though.
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Re: Is it possible to create a wrapper for uploading to CloudApp?

23 Jan 2019, 07:25

tmplinshi wrote:
22 Jan 2019, 11:27
It might be timeout, or big files. I tried uploading a 916MB file, and got an error from "ADODB.Stream":
I had received that once before on the session prior to my latest post. I didn't understand it, so I restarted my app and got the "Show Something" error the second and third times. My files are less than 20MB.

How can I go about making this more stable? I'm unfamiliar with ADO coding. Truth be told, a LOT of the code you provided is way over my head. I wouldn't even know where to start to learn.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Is it possible to create a wrapper for uploading to CloudApp?

23 Jan 2019, 12:08

TXShooter wrote:
23 Jan 2019, 07:25
How can I go about making this more stable?
Why not just sit back and relax :) , till the next time you encountered the error, and then remember to post the error messages to the forum, so that others know where to help.
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Re: Is it possible to create a wrapper for uploading to CloudApp?

24 Jan 2019, 06:49

tmplinshi wrote:
23 Jan 2019, 12:08
TXShooter wrote:
23 Jan 2019, 07:25
How can I go about making this more stable?
Why not just sit back and relax :) , till the next time you encountered the error, and then remember to post the error messages to the forum, so that others know where to help.
Here it is:

Code: Select all

---------------------------
RDIEmailer.exe
---------------------------
Error:  SOMEthing failed

	Line#
	010: {
	011: this.http("GET", "https://my.cl.ly/account")  
	012: auth := DigestAuth.Build(email, password, "GET", "/account", this.whr.getResponseHeader("WWW-Authenticate"))
	013: oHeaders := {"Authorization": auth}
	014: this.http("GET", "https://my.cl.ly/account",, oHeaders)  
	015: this.getCookie()  
	016: if (this.whr.Status != 200)  
--->	017: Throw,"SOMEthing failed"
	018: }
	019: {
	020: body := {item: {name: name, redirect_url: url}}
	021: Return,this.http("POST", "https://my.cl.ly/items", body)
	022: }
	023: {
	024: Return,this.http("GET", "https://my.cl.ly/items?" paramters)

The current thread will exit.
---------------------------
OK   
---------------------------

This worked flawlessly one time, then this and the ADO error has popped up. I have McAfee Internet Security running. Do I need to make an exception in it for this to clear? If so, what program / port / whatever do I add?
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Is it possible to create a wrapper for uploading to CloudApp?

24 Jan 2019, 07:58

That's a "login failed" error. Maybe you typed an incorrect username/password?
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Re: Is it possible to create a wrapper for uploading to CloudApp?

24 Jan 2019, 19:23

tmplinshi wrote:
24 Jan 2019, 07:58
That's a "login failed" error. Maybe you typed an incorrect username/password?
Apparently the username is case sensitive. I have corrected my credentials.

Thank you. :)
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Re: Is it possible to create a wrapper for uploading to CloudApp?

26 Jan 2019, 11:35

Not relating to the CloudApp Wrapper, but still in the same script... can anyone help me to identify the error here?
---------------------------
RDIEmailer.exe
---------------------------
Error: The following variable name contains an illegal character:
"Stewardship Conf"

Line#
536: if !(IsOpen)
536: {
537: oWorkBook.Close()
538: }
540: months := ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Aug","Sep","Oct","Nov","Dec"]
541: if (CellSeries_Num <> "")
541: {
---> 542: FileSeries := %CellSeries_Title% . " " . %CellSeries_Num% . " - "
543: }
543: Else
543: {
544: FileSeries := ""
545: }
546: SplitPath,Attachment,,Folder
547: FileDate := StrSplit(CellDate, "/")

The current thread will exit.
---------------------------
OK
---------------------------
FileSeries is a local variable being defined on line 542/544. The value of CellSeries_Title is Stewardship Conf, and the value of CellSeries_Num is Message 1. What went wrong here?
gregster
Posts: 9029
Joined: 30 Sep 2013, 06:48

Re: Is it possible to create a wrapper for uploading to CloudApp?

26 Jan 2019, 12:51

The := means you are in expression mode. That means, variables should (usually) be used without %s.

Using the %'s here causes a double deref, that means, SteStewardship Conf is seen as a variable name (but the space is obv not allowed) instead of variable content, which is not your intention, I assume:
Error: The following variable name contains an illegal character:
"Stewardship Conf"
Try

Code: Select all

FileSeries := CellSeries_Title . " " . CellSeries_Num . " - "
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Re: Is it possible to create a wrapper for uploading to CloudApp?

26 Jan 2019, 14:05

gregster wrote:
26 Jan 2019, 12:51
The := means you are in expression mode. That means, variables should (usually) be used without %s.

Using the %'s here causes a double deref, that means, SteStewardship Conf is seen as a variable name (but the space is obv not allowed) instead of variable content, which is not your intention, I assume:
Error: The following variable name contains an illegal character:
"Stewardship Conf"
Try

Code: Select all

FileSeries := CellSeries_Title . " " . CellSeries_Num . " - "
AHHHHhhhhhh.... so the illegal character was the space!! Now it makes sense. I kept looking at it over and over and just could not place what the error was all about.

Thank you.
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Re: Is it possible to create a wrapper for uploading to CloudApp?

27 Jan 2019, 14:15

Here are the two ADO errors I got today. Is there something that I'm doing wrong that is causing this?
---------------------------
RDIEmailer.exe
---------------------------
Error: 0x800A0BBA -
Source: ADODB.Stream
Description: File could not be opened.
HelpFile: C:\Windows\HELP\ADO270.CHM
HelpContext: 1240642

Specifically: LoadFromFile

Line#
126: oADO.Position := 3
127: Return,oADO.Read, oADO.Close
128: }
129: {
130: oADO := ComObjCreate("ADODB.Stream")
131: oADO.Type := 1
132: oADO.Open
---> 133: oADO.LoadFromFile(FileName)
134: Return,oADO.Read, oADO.Close
135: }
136: {
137: oADO := ComObjCreate("ADODB.Stream")
138: oADO.Type := 1
139: oADO.Mode := 3
140: oADO.Open

Continue running the script?
---------------------------
Yes No
---------------------------

---------------------------
RDIEmailer.exe
---------------------------
Error: 0x800A0BB9 -
Source: ADODB.Stream
Description: Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.
HelpFile: C:\Windows\HELP\ADO270.CHM
HelpContext: 1240641

Specifically: Write

Line#
135: }
136: {
137: oADO := ComObjCreate("ADODB.Stream")
138: oADO.Type := 1
139: oADO.Mode := 3
140: oADO.Open
141: For i,arr in Arrays
---> 142: oADO.Write(arr)
143: oADO.Position := 0
144: Return,oADO.Read, oADO.Close
145: }
146: {
147: oADO := ComObjCreate("ADODB.Stream")
148: oADO.Type := 1
149: oADO.Mode := 3

Continue running the script?
---------------------------
Yes No
---------------------------
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Is it possible to create a wrapper for uploading to CloudApp?

29 Jan 2019, 03:17

TXShooter wrote:
27 Jan 2019, 14:15
---------------------------
RDIEmailer.exe
---------------------------
Error: 0x800A0BBA -
Source: ADODB.Stream
Description: File could not be opened.
HelpFile: C:\Windows\HELP\ADO270.CHM
HelpContext: 1240642

Specifically: LoadFromFile
Maybe the file path is wrong, or the file is being opened and locked by another program. I have tesed a .xlsx file that is opened by excel, and got the same error.
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Re: Is it possible to create a wrapper for uploading to CloudApp?

29 Jan 2019, 17:55

tmplinshi wrote:
29 Jan 2019, 03:17
TXShooter wrote:
27 Jan 2019, 14:15
---------------------------
RDIEmailer.exe
---------------------------
Error: 0x800A0BBA -
Source: ADODB.Stream
Description: File could not be opened.
HelpFile: C:\Windows\HELP\ADO270.CHM
HelpContext: 1240642

Specifically: LoadFromFile
Maybe the file path is wrong, or the file is being opened and locked by another program. I have tesed a .xlsx file that is opened by excel, and got the same error.
Since that help file does not exist on any of my machines, that might be it. However, what's trying to call for it, and why? How do I get that file or work around this issue?

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: No registered users and 74 guests