VBA Call TI

Post Reply
Darkhorse
Posts: 141
Joined: Wed Mar 09, 2011 1:25 pm
OLAP Product: TM1
Version: 10.2.2
Excel Version: 2003 2007 2010 2013

VBA Call TI

Post by Darkhorse »

Hi all

I tried using the following found in another thread:

Code: Select all

 v 1.0 23 August 2010
' Written by Martin Ryan based on code from Mike Cowie in the TM1 Forum
' http://forums.olapforums.com/viewtopic.php?f=3&p=4468#p4468

Declare Function TM1_API2HAN Lib "tm1.xll" () As Long

code]' #### SAMPLE CALL ####
Sub sampleTICall()
    Dim tm1ServerName As String, procName As String
    Dim p1, p2, p3, p4, p5, p6, p7 As String
   
    '--- Update this section as required
    tm1ServerName = "tm1_library" ' the name of the TM1 server
    procName = "DataExport_AnyDimension" ' the name of the process being called
    p1 = "ID" ' The first parameter
    p2 = "No" ' The second parameter
    '--- end updates section
   
    MsgBox RunTIProcess(tm1ServerName, procName, p1, p2)
End Sub
' #### END SAMPLE CALL ####

'HELPER FUNCTION TO GET TM1 API SESSION HANDLE
'  This allows you to leverage TM1 Excel Client's active connection to your TM1 Server
Public Function GetExcelSessionHandle() As Long
    GetExcelSessionHandle = Application.Run("TM1_API2HAN")
End Function

'EXECUTE PROCESS FUNCTION
Public Function RunTIProcess(ByVal ServerName As String, ByVal ProcessName As String, ParamArray ProcessParameters()) As String
  Dim SessionHandle As Long, ValPoolHandle As Long
  Dim ServerHandle As Long, ProcessHandle As Long
  Dim TotParams As Long, i As Long, RawParameterArray() As Variant, ArrOffset As Byte
  Dim InitParamArray() As Long, ParamArrayHandle As Long
  Dim ExecuteResult As Long, numResults As Integer, k As Integer, myMsg As String
  Dim iType As Integer, errStr As String * 75, tempVal As Long, returnStr As String * 75

  'Get handles
  SessionHandle = GetExcelSessionHandle()
  If SessionHandle = 0 Then
    RunTIProcess = "ERROR: Cannot communicate with TM1 API."
    Exit Function
  End If

  ValPoolHandle = TM1ValPoolCreate(SessionHandle)
  On Error GoTo Cleanup_API
   
  'Get handle to server; check if connected
  ServerHandle = TM1SystemServerHandle(SessionHandle, ServerName)
  If ServerHandle = 0 Then
    RunTIProcess = "ERROR: Not connected to server " & ServerName & "."
    GoTo Cleanup_API
  End If

  'Get handle to process; check if valid
  ProcessHandle = TM1ObjectListHandleByNameGet(ValPoolHandle, ServerHandle, TM1ServerProcesses, TM1ValString(ValPoolHandle, ProcessName, 0))
  If TM1ValType(SessionHandle, ProcessHandle) <> TM1ValTypeObject Then
    RunTIProcess = "ERROR: Unable to access process " & ProcessName & "."
    GoTo Cleanup_API
  End If

  If TM1ValObjectCanRead(SessionHandle, ProcessHandle) = 0 Then
     RunTIProcess = "ERROR: No permissions to execute process " & ProcessName & "."
    GoTo Cleanup_API
  End If

  ' Get parameters, build array of param & type
  TotParams = UBound(ProcessParameters)
  If TotParams < 0 Then 'No parameters passed
    ReDim InitParamArray(1)
    InitParamArray(1) = TM1ValString(ValPoolHandle, "", 1)
    ParamArrayHandle = TM1ValArray(ValPoolHandle, InitParamArray, 0)
  Else
    ReDim RawParameterArray(TotParams, 1)
   
    'Collect the params, get their type
    For i = 0 To TotParams
      RawParameterArray(i, 0) = ProcessParameters(i)
      If VarType(ProcessParameters(i)) = vbString Then
        RawParameterArray(i, 1) = "S"
      Else
        RawParameterArray(i, 1) = "N"
      End If
    Next i
   
    'Now array of handles to params for process
    ReDim InitParamArray(TotParams)
    For i = 0 To TotParams
      If RawParameterArray(i, 1) = "S" Then
        InitParamArray(i) = TM1ValString(ValPoolHandle, CStr(RawParameterArray(i, 0)), 0)
      Else
        InitParamArray(i) = TM1ValReal(ValPoolHandle, CDbl(RawParameterArray(i, 0)))
      End If
    Next i
       
    'Set the parameters in TM1 array
    ParamArrayHandle = TM1ValArray(ValPoolHandle, InitParamArray, TotParams + 1)
    For i = 0 To TotParams
      TM1ValArraySet ParamArrayHandle, InitParamArray(i), i + 1
    Next i
  End If

  'Execute process
  ExecuteResult = TM1ProcessExecuteEx(ValPoolHandle, ProcessHandle, ParamArrayHandle)
  'ExecuteResult is an array containing information about the error type (minor, ProcessQuit, etc) and a reference to the error log location
  iType = TM1ValType(SessionHandle, ExecuteResult)

    If iType = CInt(TM1ValTypeIndex) Then
        RunTIProcess = "Process executed successfully"
    ElseIf iType = CInt(TM1ValTypeArray) Then
        'Retrieve the error
        TM1ValErrorString_VB SessionHandle, TM1ValArrayGet(SessionHandle, ExecuteResult, CDbl(1)), errStr, 75
        'Retrieve the error log file
        TM1ValStringGet_VB SessionHandle, TM1ValArrayGet(SessionHandle, ExecuteResult, CDbl(2)), returnStr, 75
        showProcessError errStr, returnStr
        RunTIProcess = "Errors occurred during process execution"
    ElseIf iType = CInt(TM1ValTypeError) Then
        RunTIProcess = "Returned an error value.  The process was not run for some reason"
    ElseIf iType = CInt(TM1ValTypeBool) Then
        RunTIProcess = "Returned a boolean value.  This should not happen."
    ElseIf iType = CInt(TM1ValTypeObject) Then
        RunTIProcess = "Returned an object.  This should not happen."
    ElseIf iType = CInt(TM1ValTypeReal) Then
        RunTIProcess = "Returned a real number.  This should not happen."
    ElseIf iType = CInt(TM1ValTypeString) Then
        RunTIProcess = "Returned a string.  This should not happen."
    Else
        RunTIProcess = "Unknown return value: " & iType
    End If

Cleanup_API:
  TM1ValPoolDestroy ValPoolHandle
End Function

Sub showProcessError(reason As String, fileName As String)
Dim myMsg As String, filePath As String, logPath As String, fso

On Error GoTo errorHandler

Set fso = CreateObject("Scripting.FileSystemObject")
' Retrieve the log path that the user set in the options dialog box.
logPath = GetSetting(gSC_APP_NAME, gSC_REG_SECT_OPTS, gSC_REGKEY_LOGDIR, "") & "\"
filePath = logPath & fileName

' Check they've specified a log path
If logPath = "\" Then
    myMsg = "There was an error when running your process.  Specify a logging directory " & _
    "in the TM1 Tools options dialog box to be able to view the error log from this workbook.  The error message was " & reason
    MsgBox myMsg, vbOKOnly, "An error occurred"
' Check they've specified a valid log path
ElseIf Not fso.FolderExists(logPath) Then
    myMsg = "There was an error when running your process, but I can't find the error directory.  Check you have specified it " & _
    "correctly in the TM1 Tools options dialog box and that you have access privileges.  The error message was " & reason
    MsgBox myMsg, vbOKOnly, "An error occurred"
' If we can find the error file then give them the option of opening it
ElseIf fso.FileExists(filePath) Then
    myMsg = "There was an error when running your process.  Do you wish to view the error log?  The error message was " & reason
    If MsgBox(myMsg, vbYesNo, "View error log?") = vbYes Then
        If Dir(filePath) = "" Then
            MsgBox "I was unable to open the file.  The path is " & filePath
        Else
            Workbooks.Open filePath
        End If
    End If
Else
    ' Incorrect parameters (either how many of them, or incorrect numeric/string type) sticks a '$' on the end of the error
    ' log and is locked by TM1 so we can't open it.  There may be other reasons too.
    myMsg = "An error occurred but I cannot find the error log.  This may something is wrong with " & _
     "the parameters, or that the error log folder you have specified is incorrect. " & _
     Chr(13) & Chr(13) & "The error message was: " & reason
     MsgBox myMsg, vbOKOnly, "An error occurred"
End If
Exit Sub 'avoid error handler
errorHandler:
    MsgBox "An unknown error occured in the showProcessError sub of the bas_TurboIntegrator module in the TM1_Tools addin"
End Sub ellissj3 
  
Posts: 40
Joined: Tue Jun 15, 2010 1:43 pm 
OLAP Product: Cognos TM1 
Version: 9.4.1 FP3 and 9.5.1 
Excel Version: 2007 
Private messageE-mail ellissj3AIM 
But i just keep getting back "Variable not Declared" which is annoying as hell, i tried adding all variables but found most were actually functions which i needed to assign properly... this began to become a laborius task.

once i had declared all functions it still did not work. Can anyone please point out what im doing wrong?

i am simply trying to run a TI from a userform with 1 or 2 parameters passed That is all!!! why is this so difficult? can i create an action button on a userfrom if so how?

i would prefer the VB in truth but if theres a more efficient work around im all ears!!

thanks guys for reading
Wim Gielis
MVP
Posts: 3241
Joined: Mon Dec 29, 2008 6:26 pm
OLAP Product: TM1, Jedox
Version: PAL 2.1.5
Excel Version: Microsoft 365
Location: Brussels, Belgium
Contact:

Re: VBA Call TI

Post by Wim Gielis »

Take out "Option Explicit" and test again please.
Best regards,

Wim Gielis

IBM Champion 2024-2025
Excel Most Valuable Professional, 2011-2014
https://www.wimgielis.com ==> 121 TM1 articles and a lot of custom code
Newest blog article: Deleting elements quickly
Darkhorse
Posts: 141
Joined: Wed Mar 09, 2011 1:25 pm
OLAP Product: TM1
Version: 10.2.2
Excel Version: 2003 2007 2010 2013

Re: VBA Call TI

Post by Darkhorse »

that didnt work i found all the extra items anyway

Code: Select all

Declare Function TM1_API2HAN Lib "tm1.xll" () As Long
Declare Function TM1ObjectListHandleByNameGet Lib "tm1api.dll" (ByVal hPool As Long, ByVal hObject As Long, ByVal iPropertyList As Long, ByVal sName As Long) As Long
Declare Function TM1ProcessExecute Lib "tm1api.dll" (ByVal hPool As Long, ByVal hProcess As Long, ByVal hParametersArray As Long) As Long
Declare Function TM1ProcessExecuteEx Lib "tm1api.dll" (ByVal hPool As Long, ByVal hProcess As Long, ByVal hParametersArray As Long) As Long
Declare Function TM1ProcessVariableNameIsValid Lib "tm1api.dll" (ByVal hPool As Long, ByVal hProcess As Long, ByValhVariableName As Long) As Long
Declare Function TM1SystemOpen Lib "tm1api.dll" () As Long
Declare Function TM1SystemServerHandle Lib "tm1api.dll" (ByVal huser As Long, ByVal name As String) As Long
Declare Function TM1ValPoolCreate Lib "tm1api.dll" (ByVal huser As Long) As Long
Declare Function TM1ValString Lib "tm1api.dll" (ByVal hPool As Long, ByVal InitString As String, ByVal MaxSize As Long) As Long
Declare Function TM1ValType Lib "tm1api.dll" (ByVal huser As Long, ByVal Value As Long) As Integer
Declare Function TM1ValReal Lib "tm1api.dll" (ByVal hPool As Long, ByVal InitReal As Double) As Long
Declare Function TM1ValObjectCanRead Lib "tm1api.dll" (ByVal huser As Long, ByVal vObject As Long) As Integer
Declare Sub TM1ValArraySetSize Lib "tm1api.dll" (ByVal vArray As Long, ByVal Size As Long)
Declare Sub TM1ValPoolDestroy Lib "tm1api.dll" (ByVal hPool As Long)
Declare Sub TM1ValArraySet Lib "tm1api.dll" (ByVal vArray As Long, ByVal val As Long, ByVal index As Long)

But now i have a seperate issue

this is my code

Code: Select all

Public Function RunTIProcess(ByVal ServerName As String, ByVal ProcessName As String, ByVal user As String, ParamArray ProcessParameters())
  Dim SessionHandle As Long, ValPoolHandle As Long, hPool As Long
  Dim ServerHandle As Long, ProcessHandle As Long
  Dim TotParams As Long, i As Long, RawParameterArray() As Variant, ArrOffset As Byte
  Dim InitParamArray() As Variant, ParamArrayHandle As Variant
  Dim ExecuteResult As Long, TM1ServerProcesses As Long, TM1ValTypeObject As Long
  Dim TM1ValArray As Variant, TM1ValTypeError As Variant
  
  'Get handles
  SessionHandle = GetExcelSessionHandle()
  If SessionHandle = 0 Then
    RunTIProcess = "ERROR: Cannot communicate with TM1 API."
    Exit Function
  End If
  
  ValPoolHandle = TM1ValPoolCreate(SessionHandle)
  On Error GoTo Cleanup_API
    
  'Get handle to server; check if connected
  ServerHandle = TM1SystemServerHandle(SessionHandle, ServerName)
  If ServerHandle = 0 Then
    RunTIProcess = "ERROR: Not connected to server " & ServerName & "."
    GoTo Cleanup_API
  End If

ProcessHandle = TM1ObjectListHandleByNameGet(ValPoolHandle, ServerHandle, TM1ServerProcesses, TM1ValString(ValPoolHandle, ProcessName, 0))

  TotParams = UBound(ProcessParameters)
  If TotParams < 0 Then 'No parameters passed
    ReDim InitParamArray(1)
    InitParamArray(1) = TM1ValString(ValPoolHandle, "", 1)
    ParamArrayHandle = TM1ValArray(ValPoolHandle, InitParamArray, 0)
  Else
    ReDim RawParameterArray(TotParams, 1)
    
    'Collect the params, get their type
    For i = 0 To TotParams
      RawParameterArray(i, 0) = ProcessParameters(i)
      If VarType(ProcessParameters(i)) = vbString Then
        RawParameterArray(i, 1) = "S"
      Else
        RawParameterArray(i, 1) = "N"
      End If
    Next i
    
    'Now array of handles to params for process
    ReDim InitParamArray(TotParams)
    For i = 0 To TotParams
        InitParamArray(i) = TM1ValString(ValPoolHandle, CStr(RawParameterArray(i, 0)), 0)
    Next i
        
    'Set the parameters in TM1 array
    ParamArrayHandle = TM1ValArray(ValPoolHandle, InitParamArray, TotParams + 1)
    For i = 0 To TotParams
      TM1ValArraySet ParamArrayHandle, InitParamArray(i), i + 1
    Next i
  End If
  
  'Execute process
  ExecuteResult = TM1ProcessExecuteEx(ValPoolHandle, ProcessHandle, ParamArrayHandle)
  
 
Cleanup_API:
  TM1ValPoolDestroy ValPoolHandle
End Function
The problem is i get to this line:
ParamArrayHandle = TM1ValArray(ValPoolHandle, InitParamArray, TotParams + 1)

it keeps failing and the message is type missmatch i have tried changing the variables around to all variants (as thats the most flexible tpe of variable still miss match)


any help really welcome
Darkhorse
Posts: 141
Joined: Wed Mar 09, 2011 1:25 pm
OLAP Product: TM1
Version: 10.2.2
Excel Version: 2003 2007 2010 2013

please Help API TI from VB

Post by Darkhorse »

OK got this to finally work to the point of
1) No errors!
2) No requests for Declare Variables.

BUT!!!

It passes the check to see if im logged into the server, but it wont find the TI i chose manually
i know this name is in because i copied the eact name from the Ti list can anone point out my mistakes?

Code: Select all

Declare Function TM1_API2HAN Lib "tm1.xll" () As Long
Declare Function TM1ObjectListHandleByNameGet Lib "tm1api.dll" (ByVal hPool As Long, ByVal hObject As Long, ByVal iPropertyList As Long, ByVal sName As Long) As Long
Declare Function TM1ProcessExecute Lib "tm1api.dll" (ByVal hPool As Long, ByVal hProcess As Long, ByVal hParametersArray As Long) As Long
Declare Function TM1ProcessExecuteEx Lib "tm1api.dll" (ByVal hPool As Long, ByVal hProcess As Long, ByVal hParametersArray As Long) As Long
Declare Function TM1ProcessVariableNameIsValid Lib "tm1api.dll" (ByVal hPool As Long, ByVal hProcess As Long, ByValhVariableName As Long) As Long
Declare Function TM1SystemOpen Lib "tm1api.dll" () As Long
Declare Function TM1SystemServerHandle Lib "tm1api.dll" (ByVal hUser As Long, ByVal name As String) As Long
Declare Function TM1ValPoolCreate Lib "tm1api.dll" (ByVal hUser As Long) As Long
Declare Function TM1ValString Lib "tm1api.dll" (ByVal hPool As Long, ByVal InitString As String, ByVal MaxSize As Long) As Long
Declare Function TM1ValType Lib "tm1api.dll" (ByVal hUser As Long, ByVal Value As Long) As Integer
Declare Function TM1ValArray Lib "tm1api.dll" (ByVal hPool As Long, ByRef sArray() As Long, ByVal MaxSize As Long) As Long
Declare Function TM1ValReal Lib "tm1api.dll" (ByVal hPool As Long, ByVal InitReal As Double) As Long
Declare Function TM1ValObjectCanRead Lib "tm1api.dll" (ByVal hUser As Long, ByVal vObject As Long) As Integer
Declare Sub TM1ValArraySetSize Lib "tm1api.dll" (ByVal vArray As Long, ByVal Size As Long)
Declare Sub TM1ValPoolDestroy Lib "tm1api.dll" (ByVal hPool As Long)
Declare Sub TM1ValArraySet Lib "tm1api.dll" (ByVal vArray As Long, ByVal val As Long, ByVal index As Long)
Declare Sub TM1ValErrorString_VB Lib "tm1api.dll" (ByVal hUser As Long, ByVal vValue As Long, ByVal Str As String, ByVal Max As Integer)
Declare Function TM1ValArrayGet Lib "tm1api.dll" (ByVal hUser As Long, ByVal vArray As Long, ByVal index As Long) As Long
Declare Sub TM1ValStringGet_VB Lib "tm1api.dll" (ByVal hUser As Long, ByVal sValue As Long, ByVal Retval As String, ByVal Max As Integer)


Public Function GetExcelSessionHandle() As Long
   GetExcelSessionHandle = Application.Run("TM1_API2HAN")
End Function

Sub callProcess()
    Dim tm1ServerName As String, procName As String
    Dim p1, p2, p3, p4, p5, p6, p7, user As String

    tm1ServerName = "tm1_GMS" ' the name of the TM1 server
    procName = "User - Add User" ' the name of the process being called
    p1 = "Testuser3" ' The first parameter
    p2 = "2124" ' The second parameter
    '--- end updates section
   
    MsgBox RunTIProcess(tm1ServerName, procName, user, p1, p2)
End Sub

'EXECUTE PROCESS FUNCTION
Public Function RunTIProcess(ByVal ServerName As String, ByVal ProcessName As String, ParamArray ProcessParameters()) As String
  Dim SessionHandle As Long, ValPoolHandle As Long
  Dim ServerHandle As Long, ProcessHandle As Long
  Dim TotParams As Long, i As Long, RawParameterArray() As Variant, ArrOffset As Byte
  Dim InitParamArray() As Long, ParamArrayHandle As Long
  Dim ExecuteResult As Long, numResults As Integer, k As Integer, myMsg As String
  Dim iType As Integer, errStr As String * 75, tempVal As Long, returnStr As String * 75

  'Get handles
  SessionHandle = GetExcelSessionHandle()
  If SessionHandle = 0 Then
    RunTIProcess = "ERROR: Cannot communicate with TM1 API."
    Exit Function
  End If

  ValPoolHandle = TM1ValPoolCreate(SessionHandle)
  On Error GoTo Cleanup_API
   
  'Get handle to server; check if connected
  ServerHandle = TM1SystemServerHandle(SessionHandle, ServerName)
  If ServerHandle = 0 Then
    RunTIProcess = "ERROR: Not connected to server " & ServerName & "."
    GoTo Cleanup_API
  End If

  'Get handle to process; check if valid
  ProcessHandle = TM1ObjectListHandleByNameGet(ValPoolHandle, ServerHandle, TM1ServerProcesses, TM1ValString(ValPoolHandle, ProcessName, 0))
  If TM1ValType(SessionHandle, ProcessHandle) <> TM1ValTypeObject Then
    RunTIProcess = "ERROR: Unable to access process " & ProcessName & "."
    GoTo Cleanup_API
  End If

  If TM1ValObjectCanRead(SessionHandle, ProcessHandle) = 0 Then
     RunTIProcess = "ERROR: No permissions to execute process " & ProcessName & "."
    GoTo Cleanup_API
  End If

  ' Get parameters, build array of param & type
  TotParams = UBound(ProcessParameters)
  If TotParams < 0 Then 'No parameters passed
    ReDim InitParamArray(1)
    InitParamArray(1) = TM1ValString(ValPoolHandle, "", 1)
    ParamArrayHandle = TM1ValArray(ValPoolHandle, InitParamArray, 0)
  Else
    ReDim RawParameterArray(TotParams, 1)
   
    'Collect the params, get their type
    For i = 0 To TotParams
      RawParameterArray(i, 0) = ProcessParameters(i)
      If VarType(ProcessParameters(i)) = vbString Then
        RawParameterArray(i, 1) = "S"
      Else
        RawParameterArray(i, 1) = "N"
      End If
    Next i
   
    'Now array of handles to params for process
    ReDim InitParamArray(TotParams)
    For i = 0 To TotParams
      If RawParameterArray(i, 1) = "S" Then
        InitParamArray(i) = TM1ValString(ValPoolHandle, CStr(RawParameterArray(i, 0)), 0)
      Else
        InitParamArray(i) = TM1ValReal(ValPoolHandle, CDbl(RawParameterArray(i, 0)))
      End If
    Next i
       
    'Set the parameters in TM1 array
    ParamArrayHandle = TM1ValArray(ValPoolHandle, InitParamArray, TotParams + 1)
    For i = 0 To TotParams
      TM1ValArraySet ParamArrayHandle, InitParamArray(i), i + 1
    Next i
  End If

  'Execute process
  ExecuteResult = TM1ProcessExecuteEx(ValPoolHandle, ProcessHandle, ParamArrayHandle)
  'ExecuteResult is an array containing information about the error type (minor, ProcessQuit, etc) and a reference to the error log location
  iType = TM1ValType(SessionHandle, ExecuteResult)

    If iType = CInt(TM1ValTypeIndex) Then
        RunTIProcess = "Process executed successfully"
    ElseIf iType = CInt(TM1ValTypeArray) Then
        'Retrieve the error
        TM1ValErrorString_VB SessionHandle, TM1ValArrayGet(SessionHandle, ExecuteResult, CDbl(1)), errStr, 75
        'Retrieve the error log file
        TM1ValStringGet_VB SessionHandle, TM1ValArrayGet(SessionHandle, ExecuteResult, CDbl(2)), returnStr, 75
        showProcessError errStr, returnStr
        RunTIProcess = "Errors occurred during process execution"
    ElseIf iType = CInt(TM1ValTypeError) Then
        RunTIProcess = "Returned an error value.  The process was not run for some reason"
    ElseIf iType = CInt(TM1ValTypeBool) Then
        RunTIProcess = "Returned a boolean value.  This should not happen."
    ElseIf iType = CInt(TM1ValTypeObject) Then
        RunTIProcess = "Returned an object.  This should not happen."
    ElseIf iType = CInt(TM1ValTypeReal) Then
        RunTIProcess = "Returned a real number.  This should not happen."
    ElseIf iType = CInt(TM1ValTypeString) Then
        RunTIProcess = "Returned a string.  This should not happen."
    Else
        RunTIProcess = "Unknown return value: " & iType
    End If

Cleanup_API:
  TM1ValPoolDestroy ValPoolHandle
End Function
Darkhorse
Posts: 141
Joined: Wed Mar 09, 2011 1:25 pm
OLAP Product: TM1
Version: 10.2.2
Excel Version: 2003 2007 2010 2013

Re: VBA Call TI

Post by Darkhorse »

Hi guys

thanks for all help loool found the answer after scrolling through google,

if anyones interested in the same thing i am then i suggest checking out the SDK pack that was produced

theres a process in there called run TI and Chore already Made and really self explanatory. just transfer the Class Module Transfer all the Declare Functions and move accross the Main Call sub routine into your project and away you go.

http://www.bihints.com/tm1_sdk
Post Reply