SOAPMethod.Parameter:
Sub Parameter(name as string, Assigns value as variant)
  inputParams.value(name) = value
End Sub

SOAPMethod.Constructor:
Sub Constructor()
  initialize
End Sub

SOAPMethod.ExecuteRPC:
Private Function ExecuteRPC() As SOAPResult
  dim response as string
  
  // intialize connection
  if connection = NIL then
    connection = new httpSocket
  end
  
  // set up the post data
  connection.setRequestHeader "SOAPAction",action
  connection.setPostContent formatEnvelope(),"text/xml"
  response = connection.post(url,timeout)
  
  // handle error
  if connection.errorCode() <> 0 then
    return NIL
  end
  
  // parse the response
  return parseSOAPResult(response)
End Function

SOAPMethod.ParseSOAPResult:
Private Function ParseSOAPResult(resultData as string) As SOAPResult
  dim sr as soapResult
  dim i,j as integer
  dim xnode as xmlNode
  
  // parse soap result
  sr = new soapResult
  sr.document = new xmlDocument
  sr.document.loadXML resultData
  
  // extract envelope
  for i = 0 to sr.document.childCount-1
    xnode = sr.document.child(i)
    if xnode.localName = "Envelope" then
      sr.envelope = xnode
      exit
    end
  next
  
  // provide access to the body tag without having to go through envelope
  for i = 0 to sr.envelope.childCount-1
    xnode = sr.envelope.child(i)
    if xnode.localName = "Body" then
      sr.body = xmlElement(xnode)
      exit
    end
  next
  
  // check for faults
  for i = 0 to sr.body.childCount-1
    xnode = sr.body.child(i)
    if xnode.localName = "Fault" then// fault was found
      sr.error = true
      for j = 0  to xnode.childCount-1// extract fault code and message
        if xnode.child(j).localName = "FaultCode" then
          sr.errorCode = val(xnode.child(j).firstChild.value)
        end
        if xnode.child(j).localName = "FaultString" then
          sr.errorMessage = xnode.child(j).firstChild.value
        end
      next
      exit
    end
  next
  
  
  // return the result
  return sr
  
  
exception err as XMLException
  sr.error = true
  sr.errorCode = -1
  sr.errorMessage = err.message
  return sr
End Function

SOAPMethod.Constructor:
Sub Constructor(WSDLurl as string)
  initialize
  loadWSDLFromURL WSDLurl
End Sub

SOAPMethod.LoadWSDLFromURL:
Sub LoadWSDLFromURL(url as string)
  dim pageGrab as _soapSocket
  dim response as string
  
  // use the user defined socket if one exists
  if connection = NIL then
    pageGrab = new httpSocket
  else
    pageGrab = me.connection
  end
  
  // get the wsdl
  response = pageGrab.get(url,timeout)
  if pageGrab.errorCode <> 0 then
    raise getSOAPException("WSDL could not be loaded from URL")
  end
  
  // parse the wsdl
  wsdl = new xmlDocument
  wsdl.loadXml response
End Sub

SOAPMethod.InvokeMethod:
Private Function InvokeMethod(name as string, paramIsArray as boolean) As string
  dim sr as soapResult
  dim resultNode as xmlNode
  
  // parse wsdl if found
  if wsdl <> NIL then
    parseWSDL name,paramIsArray
  else// call function with no wsdl
    methodName = name
  end
  
  // execute the function
  sr = executeRPC()
  if sr = NIL then
    return ""
  end
  
  // find the result node
  resultNode = sr.body.firstChild.firstChild.firstChild
  if resultNode = NIL then
    resultNode = sr.body.firstChild.firstChild
    return resultNode.value
  end
  
  // return the result
  if resultNode.type = 3 then
    return resultNode.value
  else
    return resultNode.toString()
  end if
End Function

SOAPMethod.Operator_Lookup:
Function Operator_Lookup(funcName as string, ParamArray params as variant) As string
  dim i as integer
  
  if ubound(params) = -1 then// there are no parameters
    if wsdl <> NIL then// clear parameters if there is a wsdl defined
      inputParams.clear
    end
  else// parameters exist
    inputParams.clear// clear stale parameters
    for i = 0 to ubound(params)// assign new parameters
      inputParams.value(str(i)) = params(i)
    next
  end
  
  return invokeMethod(funcName,true)
End Function

SOAPMethod.wsdlFindParamNodesParent:
Private Function wsdlFindParamNodesParent(funcName as string) As xmlNode
  dim rlist as xmlNodeList
  dim inputMessage as string
  dim inputmessageNode, sequenceNode as xmlNode
  
  // first find the port input name
  rlist = wsdlQuery("definitions/portType/operation[@name='" + funcName + "']/input")
  inputMessage = xmlElement(rlist.Item(0)).GetAttribute("message")
  inputMessage = nthField(inputMessage, ":", 2)
  
  rlist = wsdlQuery("definitions/message[@name='" + inputMessage + "']")
  inputMessageNode = rlist.Item(0)
  
  if inputMessageNode.childCount = 0 then
    return NIL
  end
  
  // some wsdl services will go ahead and have our param details here
  if inputMessageNode.childCount >= 1 AND xmlElement(inputMessageNode.firstChild).getAttribute("type") <> "" then
    return inputMessageNode
  end
  
  // if there is only one <part> tag and it has an "element" attribute, then we have to find our params
  // in the <types> node
  if inputMessageNode.childCount = 1 AND xmlElement(inputMessageNode.firstChild).getAttribute("element") <> "" then
    rlist = wsdlQuery("definitions/types/schema/element[@name='" + funcName + "']/complexType/sequence")
    sequenceNode = rlist.Item(0)
    return sequenceNode
  end
  
  return NIL
End Function

SOAPMethod.wsdlFunctionExists:
Private Function wsdlFunctionExists(funcName as string) As string
  dim rlist as xmlNodeList
  dim i as integer
  
  rlist = wsdlQuery("definitions/binding/operation[@name]")
  for i = 0 to rlist.length-1
    if xmlElement(rlist.item(i)).getAttribute("name") = funcName then
      return xmlElement(rlist.item(i)).getAttribute("name")
    end
  next
  
  return ""
End Function

SOAPMethod.wsdlGetAction:
Private Function wsdlGetAction(funcName as string) As string
  dim rlist as xmlNodeList
  dim action as string
  
  rlist = wsdlQuery("definitions/binding/operation[@name='" + funcName + "']/operation")
  action = xmlElement(rlist.item(0)).getAttribute("soapAction")
  
  return action
End Function

SOAPMethod.wsdlGetAddress:
Private Function wsdlGetAddress() As string
  dim rlist as xmlNodeList
  dim tmpNode as xmlNode
  dim address as string
  
  // lets get the real url of the service
  rlist = wsdlQuery("definitions/service/port/address")
  address = xmlElement(rlist.Item(0)).getAttribute("location")
  
  return address
End Function

SOAPMethod.wsdlGetMethodNS:
Private Function wsdlGetMethodNS(funcName as string) As string
  dim rlist as xmlNodeList
  dim ns as string
  
  rlist = wsdlQuery("definitions/binding/operation[@name='" + funcName + "']/input/body")
  ns = xmlElement(rlist.item(0)).getAttribute("namespace")
  
  if ns = "" then
    ns = wsdl.documentElement.getAttribute("targetNamespace")
  end
  
  return ns
End Function

SOAPMethod.Initialize:
Private Sub Initialize()
  inputParams = new dictionary
  
  namespaces = new dictionary
  namespaces.value("SOAP") = "http://schemas.xmlsoap.org/soap/envelope/"
  namespaces.value("xsd") = "http://www.w3.org/2001/XMLSchema"
  namespaces.value("xsi") = "http://www.w3.org/2001/XMLSchema-instance"
  namespaces.value("ENC") = "http://schemas.xmlsoap.org/soap/encoding/"
  namespaces.value("si") = "http://soapinterop.org/xsd"
  
  paramTypes = new dictionary
  paramTypes.value("0") = ""// nil
  paramTypes.value("2") = "int"// integer
  paramTypes.value("5") = "double"// double
  paramTypes.value("7") = "string"// date
  paramTypes.value("8") = "string"// string
  paramTypes.value("9") = ""// object
  paramTypes.value("11") = "boolean"// boolean
  paramTypes.value("16") = "string"// color
End Sub

SOAPMethod.Invoke:
Function Invoke(name as string) As SOAPResult
  // record the method name
  methodName = name
  
  // if a wsdl exists then use its definition of the method
  if wsdl <> NIL then
    parseWSDL name,false
  end
  
  // return result
  return executeRPC()
End Function

SOAPMethod.ParseWSDL:
Private Sub ParseWSDL(name as string, paramIsArray as boolean)
  dim paramParent as xmlNode
  dim i as integer
  
  // set method name
  methodName = wsdlFunctionExists(name)
  
  // does the function exist
  if methodName = "" then
    raise getSOAPException("Method name does not exist in WSDL")
  end
  
  // extract method properties from wsdl
  url = wsdlGetAddress()
  action = wsdlGetAction(methodName)
  methodNamespace = wsdlGetMethodNS(methodName)
  paramParent = wsdlFindParamNodesParent(methodName)
  
  // validate parameter count
  if paramParent = NIL then// no parameters found
    if inputParams.count > 0 then// parameters were passed in
      raise getSOAPException("Incorrect parameters")
    end
    return// no parameters so we are done
  end
  if paramParent.childCount <> inputParams.count then// compare input params with needed params
    raise getSOAPException("Incorrect parameters")
  end
  
  // set up parameters
  for i = 0 to paramParent.childCount-1
    if paramIsArray = true then// change array index to name
      inputParams.value(xmlElement(paramParent.child(i)).getAttribute("name")) = inputParams.value(str(i))
      inputParams.remove str(i)
    else// verify parameter names
      if inputParams.hasKey(xmlElement(paramParent.child(i)).getAttribute("name")) = false then
        raise getSOAPException("Incorrect parameters")
      end
    end
  next
End Sub

SOAPMethod.GetSOAPException:
Private Function GetSOAPException(message as string) As SOAPException
  dim err as SOAPException
  
  err = new SOAPException
  err.message = message
  
  return err
End Function

SOAPMethod.FormatEnvelope:
Private Function FormatEnvelope() As string
  dim env as xmlDocument
  dim xbody,xdef as xmlNode
  dim i as integer
  
  // create document
  env = new xmlDocument
  
  // setup envelope and namespaces
  env.appendChild env.createElement(namespaces.value("SOAP"),"SOAP:Envelope")
  for i = 0 to namespaces.count-1
    env.documentElement.setAttribute "xmlns:"+namespaces.key(i),namespaces.value(namespaces.key(i))
  next
  
  // create body
  xbody = env.createElement(namespaces.value("SOAP"),"SOAP:Body")
  env.documentElement.appendChild xbody
  
  // create method
  xdef = env.createElement(methodNameSpace,methodName)
  xbody.appendChild xdef
  
  // set parameters
  for i = 0 to inputParams.count-1
    xdef.appendChild getParameterNode(env,i)
  next
  
  // return envelope string
  return env.toString()
End Function

SOAPMethod.GetParameterNode:
Private Function GetParameterNode(env as xmlDocument, idx as integer) As xmlNode
  dim xnode as xmlElement
  dim pname,ptype,pval as string
  
  // extract parameter name and type
  pname = inputParams.key(idx)
  ptype = "xsd:"+ paramTypes.value(str(inputParams.value(pname).type))
  
  // format parameter types
  select case inputParams.value(pname).type
  case 11// boolean
    if inputParams.value(pname).booleanValue = true then
      pval = "1"
    else
      pval = "0"
    end
    
  case 9// object
    if inputParams.value(pname).objectValue isa XMLNode then
      xnode = xmlElement(inputParams.value(pname).objectValue)
    end
    
  else
    pval = inputParams.value(pname).stringValue
  end
  
  // create node from parameter data if parameter value wasn't already a node
  if xnode = NIL then
    xnode = env.createElement(pname)
    xnode.setAttribute namespaces.value("xsi"),"xsi:type",ptype
    xnode.appendChild env.createTextNode(pval)
  end
  
  // return parameter node
  return xnode
End Function

SOAPMethod.UseSocket:
Sub UseSocket(SOAPsocket as _SOAPSocket)
  me.connection = soapSocket
End Sub

SOAPMethod.ClearParameters:
Sub ClearParameters()
  inputParams.clear
End Sub

SOAPMethod.wsdlQuery:
Private Function wsdlQuery(query as string) As xmlNodeList
  dim i,x as integer
  dim output,qstr,tmp,attr as string
  
  // Format the XQL query to support namespaces.  We these queries after the fact
  // in order to keep them more human readable in code for debugging.
  for i = 1 to countFields(query,"/")
    tmp = nthField(query,"/",i)
    
    x = instr(tmp,"[")
    if x > 0 then
      attr = mid(tmp,x)
      tmp = nthField(tmp,"[",1)
    end
    
    qstr = "*[local-name()='"+ tmp +"']"
    if x > 0 then
      qstr = qstr + attr
    end
    
    output = output +"/"+ qstr
  next
  output = mid(output,2)
  
  // run the query
  return wsdl.xql(output)
End Function

CCoreController.commandAvailable:
Sub commandAvailable(args() as string)
  
  if ubound(args) = -1 then return
  
  dim index as integer = args(0).val
  
  try
    select case index
      
    case 1 //* QueryResult *//
      me.CQueryController1.handleQueryReply args()
      
    case 2 //* ConnectionInitialized *//
      me.CNetworkController1.connectionInitialized args()
      
    case 3 //* ConnectionClosed *//
      me.CNetworkController1.connectionClosed args()
      
    case 4 //* ConnectionsUpdated *//
      me.CNetworkController1.statsUpdated
      
    case 5 //* AddDownload *//
      me.CDownloadsController1.addDownload args()
      
    case 6 //* RemoveDownload *//
      me.CDownloadsController1.removeDownload args()
      
    case 7 //* UpdateDownloadStats *//
      me.CDownloadsController1.updateDownloadStats args()
      
    case 8 //* DownloadsUpdated *//
      me.CDownloadsController1.statsUpdated
      me.CQueryController1.statsUpdated
      
    case 9 //* AddUpload *//
      me.CUploadsController1.addUpload args()
      
    case 10 //* RemoveUpload *//
      me.CUploadsController1.removeUpload args()
      
    case 11 //* UpdateUploadStats *//
      me.CUploadsController1.updateUploadStats args()
      
    case 12 //* UploadsUpdated *//
      me.CUploadsController1.statsUpdated
      me.CFilterController1.statsUpdated
      
    case 13 //* AddSharedFile *//
      me.CFileurnsController1.addSharedFile args()
      
    case 14 //* BrowseHostFailed *//
      me.CQueryController1.browseHostFailed args()
      
    case 98 //* CoreConnected *//
      me.state = 1
      #if targetWin32
        setApplicationPriority("java.exe", &h40) //Idle
      #endif
      
    case 99 //* CoreInitialized *//
      me.state = 2
      me.setValue "All"
      me.sendBuffer
      coreStarted
      
    else //* Error Messages *//
      System.debugLog args(0)
      
    end
    
  catch e as RuntimeException
    System.debugLog e.message
    
  end
  
End Sub

CCoreController.Initialize:
Sub Initialize(network as CNetworkController, query as CQueryController, downloads as CDownloadsController, uploads as CUploadsController, fileurns as CFileurnsController, filter as CFilterController)
  
  dim javaBundlePath as string
  
  me.CNetworkController1 = network
  me.CQueryController1 = query
  me.CDownloadsController1 = downloads
  me.CUploadsController1 = uploads
  me.CFileurnsController1 = fileurns
  me.CFilterController1 = filter
  
  //* launch LimeWire core *//
  
  #if debugBuild and targetMachO
    try
      if getFolderItem("Contents").child("Resources").child("Java").child("CabosCore.jar").exists then
        javaBundlePath = getFolderItem("Contents").child("Resources").child("Java").posixPath
        me.execute _
            "cd """ + javaBundlePath + """;" + _
            "nice -n 20 java " + _
            "-Xms19M " + _
            "-Xmx114M " + _
            "-Dfile.encoding=UTF-8 " + _
            "-Djava.endorsed.dirs= " + _
            "-Djava.library.path=. " + _
            "-Djava.net.preferIPv4Stack=true " + _
            "-Djava.nio.preferSelect=true " + _
            "-Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog " + _
            "-Dorg.apache.commons.logging.simplelog.defaultlog=debug " + _
            "-cp CabosCore.jar" + _
            ":clink.jar" + _
            ":commons-logging.jar" + _
            ":commons-net.jar" + _
            ":dnsjava.jar" + _
            ":guice-1.0.jar" + _
            ":httpclient-4.0-alpha5-20080522.192134-5.jar" + _
            ":httpcore-4.0-beta2-20080510.140437-10.jar" + _
            ":httpcore-nio-4.0-beta2-20080510.140437-10.jar" + _
            ":icu4j.jar" + _
            ":jaudiotagger.jar" + _
            ":jcraft.jar" + _
            ":jmdns.jar" + _
            ":onion-common.jar" + _
            ":onion-fec.jar " + _
            "jp.sourceforge.cabos.AqMain"
        return
        
      end
      
    catch
    end
    
  #elseif targetMachO
    try
      if App.ExecutableFile.parent.parent.child("Resources").child("Java").child("CabosCore.jar").exists then
        javaBundlePath = App.ExecutableFile.parent.parent.child("Resources").child("Java").posixPath
        
        if kOldJava then //* old core *//
          me.execute _
              "cd """ + javaBundlePath + """;" + _
              "nice -n 20 java " + _
              "-Xms19M " + _
              "-Xmx114M " + _
              "-Dfile.encoding=UTF-8 " + _
              "-Djava.endorsed.dirs= " + _
              "-Djava.library.path=. " + _
              "-Djava.net.preferIPv4Stack=true " + _
              "-Djava.nio.preferSelect=true " + _
              "-Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog " + _
              "-Dorg.apache.commons.logging.simplelog.defaultlog=fatal " + _
              "-cp CabosCore.jar" + _
              ":clink.jar" + _
              ":commons-httpclient.jar" + _
              ":commons-logging.jar" + _
              ":cryptix.jar" + _
              ":i18n.jar" + _
              ":icu4j.jar" + _
              ":id3v2.jar" + _
              ":jcraft.jar" + _
              ":jmdns.jar" + _
              ":logicrypto.jar" + _
              ":xerces.jar" + _
              ":xml-apis.jar " + _
              "jp.sourceforge.cabos.AqMain"
          
        else //* new core *//
          me.execute _
              "cd """ + javaBundlePath + """;" + _
              "nice -n 20 java " + _
              "-Xms19M " + _
              "-Xmx114M " + _
              "-Dfile.encoding=UTF-8 " + _
              "-Djava.endorsed.dirs= " + _
              "-Djava.library.path=. " + _
              "-Djava.net.preferIPv4Stack=true " + _
              "-Djava.nio.preferSelect=true " + _
              "-Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog " + _
              "-Dorg.apache.commons.logging.simplelog.defaultlog=fatal " + _
              "-cp CabosCore.jar" + _
              ":clink.jar" + _
              ":commons-logging.jar" + _
              ":commons-net.jar" + _
              ":dnsjava.jar" + _
              ":guice-1.0.jar" + _
              ":httpclient-4.0-alpha5-20080522.192134-5.jar" + _
              ":httpcore-4.0-beta2-20080510.140437-10.jar" + _
              ":httpcore-nio-4.0-beta2-20080510.140437-10.jar" + _
              ":icu4j.jar" + _
              ":jaudiotagger.jar" + _
              ":jcraft.jar" + _
              ":jmdns.jar" + _
              ":onion-common.jar" + _
              ":onion-fec.jar " + _
              "jp.sourceforge.cabos.AqMain"
          
        end
        
        return
      end
      
    catch
    end
    
  #elseif targetCarbon
    try
      if App.ExecutableFile.parent.child("Contents").child("Resources").child("Java").child("CabosCore.jar").exists then
        me.port = 1024
        me.listen
        App.ExecutableFile.parent.child("Contents").child("Resources").child("Java").child("CabosCore").launch
        return
        
      end
      
    catch
    end
    
  #elseif targetWin32
    dim bs as binaryStream
    dim f as folderItem
    
    try
      if App.ExecutableFile.fixRbBug.parent.child("Contents").child("Resources").child("Java").child("CabosCore.jar").exists then
        
        if targetNT then
          javaBundlePath = App.ExecutableFile.fixRbBug.parent.child("Contents").child("Resources").child("Java").posixPath
          me.execute _
              javaBundlePath.left(2) + "&" + _
              "cd """ + javaBundlePath + """&" + _
              "java " + _
              "-ss32k " + _
              "-oss32k " + _
              "-ms4m " + _
              "-Xminf0.10 " + _
              "-Xmaxf0.25 " + _
              "-Dfile.encoding=UTF-8 " + _
              "-Djava.library.path=. " + _
              "-Djava.net.preferIPv4Stack=true " + _
              "-Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog " + _
              "-Dorg.apache.commons.logging.simplelog.defaultlog=fatal " + _
              "-cp CabosCore.jar" + _
              ";clink.jar" + _
              ";commons-logging.jar" + _
              ";commons-net.jar" + _
              ";dnsjava.jar" + _
              ";guice-1.0.jar" + _
              ";httpclient-4.0-alpha5-20080522.192134-5.jar" + _
              ";httpcore-4.0-beta2-20080510.140437-10.jar" + _
              ";httpcore-nio-4.0-beta2-20080510.140437-10.jar" + _
              ";icu4j.jar" + _
              ";jaudiotagger.jar" + _
              ";jcraft.jar" + _
              ";jmdns.jar" + _
              ";onion-common.jar" + _
              ";onion-fec.jar " + _
              "jp.sourceforge.cabos.AqMain"
          return
          
        else
          javaBundlePath = App.ExecutableFile.fixRbBug.parent.child("Contents").child("Resources").child("Java").posixPath
          f = PreferencesFolder.fixRbBug.child("CabosCore.bat")
          
          try
            bs = f.createBinaryFile("")
            bs.write convertEncoding( _
                javaBundlePath.left(2) + EndOfLine + _
                "cd """ + javaBundlePath + """" + EndOfLine + _
                "java " + _
                "-ss32k " + _
                "-oss32k " + _
                "-ms4m " + _
                "-Xminf0.10 " + _
                "-Xmaxf0.25 " + _
                "-Dfile.encoding=UTF-8 " + _
                "-Djava.library.path=. " + _
                "-Djava.net.preferIPv4Stack=true " + _
                "-Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog " + _
                "-Dorg.apache.commons.logging.simplelog.defaultlog=fatal " + _
                "-cp CabosCore.jar" + _
                ";clink.jar" + _
                ";commons-logging.jar" + _
                ";commons-net.jar" + _
                ";dnsjava.jar" + _
                ";guice-1.0.jar" + _
                ";httpclient-4.0-alpha5-20080522.192134-5.jar" + _
                ";httpcore-4.0-beta2-20080510.140437-10.jar" + _
                ";httpcore-nio-4.0-beta2-20080510.140437-10.jar" + _
                ";icu4j.jar" + _
                ";jaudiotagger.jar" + _
                ";jcraft.jar" + _
                ";jmdns.jar" + _
                ";onion-common.jar" + _
                ";onion-fec.jar " + _
                "jp.sourceforge.cabos.AqMain" + EndOfLine, _
                Encodings.systemDefault)
          catch
            
          finally
            if bs <> nil then bs.close
            
          end
          
          me.execute convertEncoding(f.posixPath, Encodings.systemDefault)
          return
          
        end
        
      end
      
    catch
    end
    
  #elseif targetLinux
    try
      if App.ExecutableFile.parent.child("Contents").fixRbBug.child("Resources").fixRbBug.child("Java").fixRbBug.child("CabosCore.jar").fixRbBug.exists then
        javaBundlePath = App.ExecutableFile.parent.child("Contents").fixRbBug.child("Resources").fixRbBug.child("Java").fixRbBug.posixPath
        
        me.execute _
            "cd """ + javaBundlePath + """;" + _
            "java " + _
            "-Xms32m " + _
            "-Dfile.encoding=UTF-8 " + _
            "-Djava.library.path=. " + _
            "-Djava.net.preferIPv4Stack=true " + _
            "-Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.NoOpLog " + _
            "-cp CabosCore.jar" + _
            ":clink.jar" + _
            ":commons-httpclient.jar" + _
            ":commons-logging.jar" + _
            ":cryptix.jar" + _
            ":i18n.jar" + _
            ":icu4j.jar" + _
            ":id3v2.jar" + _
            ":jcraft.jar" + _
            ":jmdns.jar" + _
            ":logicrypto.jar" + _
            ":xerces.jar" + _
            ":xml-apis.jar " + _
            "jp.sourceforge.cabos.AqMain"
        return
        
      end
      
    catch
    end
    
  #endif
  
  coreCorrupted
  
End Sub

CCoreController.coreDisconnected:
Sub coreDisconnected()
  
  #if not targetMachO and targetCarbon
    me.close
    
  #endif
  
  select case me.state
    
  case 0
    coreLoadingError
    
  case 1
    coreBlockedByFirewall
    
  case 2
    if me.isShuttingdown then
      coreStopped
    else
      coreCrashed
    end
    
  end
  
End Sub

CCoreController.setValue:
Sub setValue(defaults as string, param as string)
  
  select case defaults
    
    //* general *//
    
  case "kAqAdultFilter"
    me.sendCommand "setAdultFilter|" + kAqAdultFilter.getBoolAsString
    me.sendCommand "applyFilterSettings"
    
  case "kAqKeywordFilterKeywords"
    me.sendCommand "setBannedKeywords|" + kAqKeywordFilterKeywords.join("|")
    me.sendCommand "applyFilterSettings"
    
    //* download *//
    
  case "kAqSaveDirectory"
    me.sendCommand "setSaveDirectory|" + kAqSaveDirectory
    me.sendCommand "applySaveDirectory"
    
  case "kAqIncompletePurgeTime"
    me.sendCommand "setIncompletePurgeTime|" + str(kAqIncompletePurgeTime)
    
  case "kAqConcurrentDownloads"
    me.sendCommand "setMaxSimDownload|" + str(kAqConcurrentDownloads)
    
  case "kAqDownstreamLimit"
    me.sendCommand "setDownloadSpeed|" + str(kAqDownstreamLimit)
    me.sendCommand "applyDownloadSpeed"
    
    //* sharing *//
    
  case "kAqSharedDirectories"
    me.sendCommand "setDirectories|" + kAqSharedDirectories.join("|")
    me.sendCommand "applyDirectories"
    
  case "kAqPartialFileSharing"
    me.sendCommand "setAllowPartialSharing|" + kAqPartialFileSharing.getBoolAsString
    
  case "kAqCompleteFileSharing"
    me.sendCommand "setAllowCompleteSharing|" + kAqCompleteFileSharing.getBoolAsString
    
  case "kAqMaxUploads"
    me.sendCommand "setMaxUploads|" + str(kAqMaxUploads)
    
  case "kAqMaxUploadsPerPerson"
    me.sendCommand "setUploadsPerPerson|" + str(kAqMaxUploadsPerPerson)
    
  case "kAqUpstreamLimit"
    me.sendCommand "setUploadSpeed|" + str(kAqUpstreamLimit)
    me.sendCommand "applyUploadSpeed"
    
    //* Network *//
    
  case "kAqConnectionSpeed"
    me.sendCommand "setConnectionSpeed|" + str(kAqConnectionSpeed)
    
  case "kAqPort"
    me.sendCommand "setPort|" + str(kAqPort)
    
  case "kAqUPnPType"
    me.sendCommand "setUPnPType|" + str(kAqUPnPType)
    
  case "kAqEnableUltrapeer"
    me.sendCommand "setEnableUltrapeer|" + kAqEnableUltrapeer.getBoolAsString
    
  case "kAqLocale"
    me.sendCommand "setUsesLocalePreferencing|" + kAqLocale.getBoolAsString
    
  case "kAqPreferLocale"
    me.sendCommand "setLanguage|" + kAqPreferLocale
    
  case "kAqAllowFreeloaders"
    me.sendCommand "setAllowFreeloaders|" + kAqAllowFreeloaders.getBoolAsString
    
    //* Advanced *//
    
  case "kAqUseProxy"
    if kAqUseProxy then
      me.sendCommand "setProxyType|" + str(kAqProxyType)
      
    else
      me.sendCommand "setProxyType|0"
      
    end
    
  case "kAqProxyServer"
    me.sendCommand "setProxyServer|" + kAqProxyServer
    
  case "kAqProxyPort"
    me.sendCommand "setProxyPort|" + str(kAqProxyPort)
    
  case "kAqProxyRequiresAuthentication"
    me.sendCommand "setRequiresAuthentication|" + kAqProxyRequiresAuthentication.getBoolAsString
    
  case "kAqProxyUsername"
    me.sendCommand "setProxyUsername|" + kAqProxyUsername
    
  case "kAqProxyPassword"
    me.sendCommand "setProxyPassword|" + kAqProxyPassword
    
  case "kAqProxyPrivate"
    me.sendCommand "setProxyPrivate|" + kAqProxyPrivate.getBoolAsString
    
  case "kAqIPFilterIPs"
    me.sendCommand "setBannedIPs|" + kAqIPFilterIPs.join("|")
    me.sendCommand "applyFilterSettings"
    
  case "All"
    
    //* general *//
    
    me.sendCommand "setAdultFilter|" + kAqAdultFilter.getBoolAsString
    me.sendCommand "setBannedKeywords|" + kAqKeywordFilterKeywords.join("|")
    
    //* download *//
    
    me.sendCommand "setSaveDirectory|" + kAqSaveDirectory
    me.sendCommand "setIncompletePurgeTime|" + str(kAqIncompletePurgeTime)
    me.sendCommand "setMaxSimDownload|" + str(kAqConcurrentDownloads)
    me.sendCommand "setDownloadSpeed|" + str(kAqDownstreamLimit)
    
    //* sharing *//
    
    me.sendCommand "setDirectories|" + kAqSharedDirectories.join("|")
    me.sendCommand "setAllowPartialSharing|" + kAqPartialFileSharing.getBoolAsString
    me.sendCommand "setAllowCompleteSharing|" + kAqCompleteFileSharing.getBoolAsString
    me.sendCommand "setMaxUploads|" + str(kAqMaxUploads)
    me.sendCommand "setUploadsPerPerson|" + str(kAqMaxUploadsPerPerson)
    me.sendCommand "setUploadSpeed|" + str(kAqUpstreamLimit)
    
    //* network *//
    
    me.sendCommand "setConnectionSpeed|" + str(kAqConnectionSpeed)
    me.sendCommand "setPort|" + str(kAqPort)
    me.sendCommand "setUPnPType|" + str(kAqUPnPType)
    me.sendCommand "setEnableUltrapeer|" + kAqEnableUltrapeer.getBoolAsString
    me.sendCommand "setUsesLocalePreferencing|" + kAqLocale.getBoolAsString
    me.sendCommand "setLanguage|" + kAqPreferLocale
    me.sendCommand "setAllowFreeloaders|" + kAqAllowFreeloaders.getBoolAsString
    
    //* advanced *//
    
    if kAqUseProxy then
      me.sendCommand "setProxyType|" + str(kAqProxyType)
      
    else
      me.sendCommand "setProxyType|0"
      
    end
    
    me.sendCommand "setProxyServer|" + kAqProxyServer
    me.sendCommand "setProxyPort|" + str(kAqProxyPort)
    me.sendCommand "setRequiresAuthentication|" + kAqProxyRequiresAuthentication.getBoolAsString
    me.sendCommand "setProxyUsername|" + kAqProxyUsername
    me.sendCommand "setProxyPassword|" + kAqProxyPassword
    me.sendCommand "setProxyPrivate|" + kAqProxyPrivate.getBoolAsString
    me.sendCommand "setBannedIPs|" + kAqIPFilterIPs.join("|")
    
    me.sendCommand "start"
    
  end
  
End Sub

CCoreController.setValue:
Sub setValue(defaults as string)
  
  me.setValue defaults, ""
  
End Sub

CCoreController.sendCommand:
Sub sendCommand(arg as string)
  
  if me.state < 2 then
    me.buffers.append arg
    return
    
  end
  
  #if targetMachO or targetWin32 or targetLinux
    if me.isRunning then
      me.writeLine arg
      
    end
    
  #elseif targetCarbon
    if me.isConnected then
      me.write arg
      me.write EndOfLine.UNIX
      
    end
    
  #endif
  
End Sub

CCoreController.sendBuffer:
Sub sendBuffer()
  
  dim buffer as string
  
  for each buffer in me.buffers
    me.sendCommand buffer
  next
  
  redim me.buffers(-1)
  
End Sub

CCoreController.shutdown:
Sub shutdown()
  
  me.isShuttingdown = true
  me.sendCommand "shutdown"
  
End Sub

CCoreController.Completed:
Sub Completed()
  
  me.coreDisconnected
  
End Sub

CCoreController.DataAvailable:
Sub DataAvailable()
  
  #if targetMachO or targetWin32 or targetLinux
    dim messages(-1) as string
    dim line as string
    
    messages = me.readAll.defineEncoding(Encodings.UTF8).replaceAllB(EndOfLine, EndOfLine.UNIX).split(EndOfLine.UNIX)
    
    for each line in messages
      me.commandAvailable line.split("<aq/>")
    next
    
  #elseif targetCarbon
    dim position as integer = me.lookahead(Encodings.UTF8).instrb(EndOfLine.UNIX)
    
    while position <> 0
      me.commandAvailable me.read(position - 1, Encodings.UTF8).split("<aq/>")
      call me.read(1)
      position = me.lookahead(Encodings.UTF8).instrb(EndOfLine.UNIX)
    wend
    
  #endif
  
End Sub

CDefaultsController.Write:
Sub Write(key as string, value as variant)
  
  select case value.type
    
  case 11 //* boolean *//
    me.prefs.root.setBoolean key, value.BooleanValue
    
  case 2 //* integer *//
    me.prefs.root.setInteger key, value.IntegerValue
    
  case 8 //* string *//
    me.prefs.root.setString key, value.StringValue
    
  end
  
End Sub

CDefaultsController.Read:
Function Read(key as string, value as variant) As variant
  
  if me.prefs.root.exists(key) = false then return value
  
  try
    select case value.type
      
    case 11 //* boolean *//
      value = me.prefs.root.getBoolean(key)
      
    case 2 //* integer *//
      value = me.prefs.root.getInteger(key)
      
    case 8 //* string *//
      value = me.prefs.root.getString(key)
      
    end
    
  catch
    
  end
  
  return value
  
End Function

CDefaultsController.WriteArrayString:
Sub WriteArrayString(key as string, values() as string)
  
  me.prefs.root.SetList key, values, 0, ubound(values)
  
End Sub

CDefaultsController.Constructor:
Sub Constructor()
  
  //* load preferences *//
  
  dim f as folderItem
  
  try
    #if targetMacOS
      f = PreferencesFolder.Child("Cabos.plist")
      
    #elseif targetWin32
      f = PreferencesFolder.fixRbBug.Child("Cabos.plist")
      
    #elseif targetLinux
      f = PreferencesFolder.Child("Cabos.plist").fixRbBug
      
    #endif
    
    me.prefs = new plist(f)
    
  catch
    
  end
  
End Sub

CDefaultsController.Destructor:
Sub Destructor()
  
  //* save preferences *//
  
  try
    me.prefs.Save
    
  catch
    
  end
  
End Sub

CDefaultsController.ReadArrayString:
Function ReadArrayString(key as string, values() as string) As String()
  
  if me.prefs.root.exists(key) = false then return values
  
  me.prefs.root.GetList(key, values, 0)
  
  return values
  
End Function

CDefaultsController.ReadArrayInteger:
Function ReadArrayInteger(key as string, values() as integer) As Integer()
  
  if me.prefs.root.exists(key) = false then return values
  
  me.prefs.root.GetList(key, values, 0)
  
  return values
  
End Function

CDefaultsController.ReadArrayBoolean:
Function ReadArrayBoolean(key as string, values() as boolean) As Boolean()
  
  if me.prefs.root.exists(key) = false then return values
  
  me.prefs.root.GetList(key, values, 0)
  
  return values
  
End Function

CDefaultsController.WriteArrayBoolean:
Sub WriteArrayBoolean(key as string, values() as boolean)
  
  me.prefs.root.SetList key, values, 0, ubound(values)
  
End Sub

CDefaultsController.WriteArrayInteger:
Sub WriteArrayInteger(key as string, values() as integer)
  
  me.prefs.root.SetList key, values, 0, ubound(values)
  
End Sub

CDownloadsController.addDownload:
Sub addDownload(args() as string)
  
  if ubound(args) <> 6 then return
  
  if me.representedInfos.hasKey(args(1).val) then return
  
  dim c as new CDownloadModel(args)
  
  me.representedObjects.append c
  me.representedInfos.value(c.getRepresentation) = ubound(me.representedObjects)
  me.flush
  
  me.markedTable.value(c.sha1) = true
  
End Sub

CDownloadsController.removeDownload:
Sub removeDownload(args() as string)
  
  if ubound(args) <> 1 then return
  
  dim hashCode as integer = args(1).val
  
  if me.representedInfos.hasKey(hashCode) = false then return
  
  dim infoArray as integer = me.representedInfos.value(hashCode)
  dim c as CDownloadModel = CDownloadModel(me.representedObjects(infoArray))
  
  c.isComplete = true
  
  dim f, m as folderItem
  
  if c.isCanceled = false then
    try
      select case c.getMediaType
        
      case 1 //* music *//
        if kAqMoveMusic and kAqMoveMusicLocation <> "" then
          f = getPath2FolderItem(c.path)
          m = getPath2FolderItem(kAqMoveMusicLocation)
          f.moveFileTo m
          c.path = m.child(f.name).posixPath
          
        end
        
      case 2 //* picture *//
        if kAqMovePictures and kAqMovePicturesLocation <> "" then
          f = getPath2FolderItem(c.path)
          m = getPath2FolderItem(kAqMovePicturesLocation)
          f.moveFileTo m
          c.path = m.child(f.name).posixPath
          
        end
        
      case 3 //* movie *//
        if kAqMoveMovies and kAqMoveMoviesLocation <> "" then
          f = getPath2FolderItem(c.path)
          m = getPath2FolderItem(kAqMoveMoviesLocation)
          f.moveFileTo m
          c.path = m.child(f.name).posixPath
          
        end
        
      end
      
    catch
      
    end
    
    downloadCompleted c
    
  end
  
  if c.isCanceled or kAqAutoClearDownloads then
    me.remove infoArray
    
  else
    c.invalidateValues
    me.representedObjects(infoArray) = c
    
  end
  
  me.flush
  
End Sub

CDownloadsController.updateDownloadStats:
Sub updateDownloadStats(args() as string)
  
  if ubound(args) <> 12 then return
  
  dim hashCode as integer = args(1).val
  
  if me.representedInfos.hasKey(hashCode) = false then return
  
  dim infoArray as integer = me.representedInfos.value(hashCode)
  dim c as CDownloadModel = CDownloadModel(me.representedObjects(infoArray))
  
  c.updateStats args
  c.invalidateValues
  
  me.representedObjects(infoArray) = c
  
End Sub

CDownloadsController.statsUpdated:
Sub statsUpdated()
  
  dim o as CStatsModel
  dim c as CTransferModel
  dim downloading, negociating as integer
  dim bandwidth as double
  
  for each o in me.representedObjects
    c = CTransferModel(o)
    
    if c.isActive then
      downloading = downloading + 1
      bandwidth = bandwidth + c.measuredBandwidth
      
    elseif c.isComplete = false then
      negociating = negociating + 1
      
    end
    
  next
  
  me.flush
  updateCell downloading, negociating, bandwidth
  
End Sub

CDownloadsController.getDownloadHosts:
Function getDownloadHosts(index as integer) As string
  
  return CDownloadModel(me.representedObjects(index)).hosts
  
End Function

CDownloadsController.Constructor:
Sub Constructor()
  
  super.Constructor
  
  me.markedTable = new Dictionary
  
End Sub

CDownloadsController.hasMarkedDownloadItem:
Function hasMarkedDownloadItem(sha1 as string) As boolean
  
  return me.markedTable.hasKey(sha1)
  
End Function

CEditMenuController.openEditMenu:
Function openEditMenu(target as CEditField) As boolean
  
  me.actionPerformed = false
  me.target = target
  me.target.setFocus
  
  dim c as new clipboard
  
  if me.target.selLength <> 0 then
    me.addrow getLocalizedString("Cut", "ContextualMenu")
    me.addrow getLocalizedString("Copy", "ContextualMenu")
    
  end
  
  if c.TextAvailable then _
      me.addrow getLocalizedString("Paste", "ContextualMenu")
  
  me.addrow getLocalizedString("Clear", "ContextualMenu")
  
  if me.target.text.lenb <> 0 then
    me.addSeparator
    me.addrow getLocalizedString("Select All", "ContextualMenu")
    
  end
  
  c.close
  me.open
  me.deleteAllRows
  
  me.target = nil
  
  return me.actionPerformed
  
End Function

CEditMenuController.Action:
Sub Action(item As String)
  
  me.actionPerformed = true
  
  dim c as new clipboard
  dim position as integer
  
  select case item
    
  case getLocalizedString("Cut", "ContextualMenu")
    c.text = me.target.selText
    position = me.target.selStart
    me.target.text = me.target.text.left(me.target.selStart) + _
        me.target.text.mid(me.target.selStart + me.target.selLength + 1)
    me.target.selStart = position
    
  case getLocalizedString("Copy", "ContextualMenu")
    c.text = me.target.selText
    
  case getLocalizedString("Paste", "ContextualMenu")
    me.target.selText = c.text
    
  case getLocalizedString("Clear", "ContextualMenu")
    me.target.text = ""
    
  case getLocalizedString("Select All", "ContextualMenu")
    me.target.selStart = 0
    me.target.selLength = me.target.text.len
    
  end
  
  c.close
  
End Sub

CFileurnsController.hasKey:
Function hasKey(sha1 as string) As boolean
  
  return kAqExistingFileMatching and me.fileURNs.hasKey(sha1)
  
End Function

CFileurnsController.addSharedFile:
Sub addSharedFile(args() as string)
  
  if kAqExistingFileMatching = false or ubound(args) <> 1 then return
  
  me.fileURNs.value(args(1)) = true
  
End Sub

CFileurnsController.load:
Protected Sub load(cache as string)
  
  dim r as new regEx
  dim m as regexMatch
  dim bs as binaryStream
  dim s as string
  
  try
    #if targetMachO
      bs = PreferencesFolder.parent.child("Application Support").child("Cabos").child(cache).OpenAsBinaryFile(false)
      
    #elseif targetCarbon
      bs = PreferencesFolder.child(".cabos").child(cache).OpenAsBinaryFile(false)
      
    #elseif targetWin32
      if PreferencesFolder.fixRbBug.child("Cabos").exists then
        bs = PreferencesFolder.fixRbBug.child("Cabos").child(cache).OpenAsBinaryFile(false)
        
      elseif PreferencesFolder.fixRbBug.parent.child(".cabos").exists then
        bs = PreferencesFolder.fixRbBug.parent.child(".cabos").child(cache).OpenAsBinaryFile(false)
        
      end
      
    #elseif targetLinux
      bs = PreferencesFolder.child(".cabos").fixRbBug.child(cache).fixRbBug.OpenAsBinaryFile(false)
      
    #endif
    
    s = bs.read(bs.length, Encodings.ASCII)
    r.searchPattern = "(urn\:sha1\:[A-Z0-9]+)q"
    m = r.search(s)
    
    while m <> nil
      
      me.fileURNs.value(m.subExpressionString(1)) = true
      m = r.search(s, m.subExpressionStartB(1) + m.subExpressionString(1).lenb)
      
    wend
    
  catch
    
  finally
    if bs <> nil then bs.close
    
  end
  
End Sub

CFileurnsController.Constructor:
Sub Constructor()
  
  me.fileURNs = new dictionary
  
  if kAqExistingFileMatching then
    load "fileurns.cache"
    load "ttrees.cache"
    load "ttroot.cache"
    
  end
  
End Sub

CFilterController.Initialize:
Sub Initialize(query as CQueryController)
  
  me.CQueryController1 = query
  
End Sub

CFilterController.filterResults:
Sub filterResults()
  
  if me.currentFilter = nil or me.CQueryController1 = nil then return
  
  dim index as integer = me.CQueryController1.getCurrentIndex
  
  if me.CQueryController1.hasQueryModel(index) = false then return
  
  dim query as CQueryModel = me.CQueryController1.getQueryModel(index)
  dim o as CStatsModel
  dim c as CResponseModel
  dim d(-1) as CResponseModel
  dim f as new dictionary
  dim k as integer
  
  for each o in query.response.representedObjects
    
    c = CResponseModel(o)
    
    if me.isFilteredResponse(c) then
      d.append c
      f.value(c.sha1) = k
      k = k + 1
      
    end
    
  next
  
  me.CQueryController1.setFilteredQuery new CQueryModel(d, f)
  
End Sub

CFilterController.setSizeFilter:
Sub setSizeFilter(value as integer)
  
  if me.currentFilter = nil or me.CQueryController1 = nil or me.CQueryController1.getCurrentIndex = -1 then return
  
  me.currentFilter.size = value
  me.CQueryController1.setFilterModel new CFilterModel(me.currentFilter)
  
End Sub

CFilterController.setBitrateFilter:
Sub setBitrateFilter(value as integer)
  
  if me.currentFilter = nil or me.CQueryController1 = nil or me.CQueryController1.getCurrentIndex = -1 then return
  
  me.currentFilter.bitrate = value
  me.CQueryController1.setFilterModel new CFilterModel(me.currentFilter)
  
End Sub

CFilterController.setMediaFilter:
Sub setMediaFilter(value as integer)
  
  if me.currentFilter = nil or me.CQueryController1 = nil or me.CQueryController1.getCurrentIndex = -1 then return
  
  me.currentFilter.media = value
  me.CQueryController1.setFilterModel new CFilterModel(me.currentFilter)
  
End Sub

CFilterController.setKeywordFilter:
Sub setKeywordFilter(value as string)
  
  if me.currentFilter = nil or me.CQueryController1 = nil or me.CQueryController1.getCurrentIndex = -1 then return
  
  me.currentFilter.keyword = value.lowercase
  me.CQueryController1.setFilterModel new CFilterModel(me.currentFilter)
  
End Sub

CFilterController.isFilteredResponse:
Function isFilteredResponse(c as CResponseModel) As boolean
  
  return (c.spam = false or kAqSpamFilter = false) and _
      ((me.currentFilter.enabled = false) or _
      (me.currentFilter.media = 0 or me.currentFilter.media = c.mediaType) and _
      (me.currentFilter.bitrate <= c.bitrate) and _
      (me.currentFilter.size <= c.fileSize) and _
      (me.currentFilter.sources <= c.sources) and _
      (me.currentFilter.speed <= c.speed) and _
      (me.currentFilter.keyword.lenb = 0 or _
      c.fileName.lowercase.instrb(me.currentFilter.keyword) <> 0 or _
      c.artist.lowercase.instrb(me.currentFilter.keyword) <> 0 or _
      c.album.lowercase.instrb(me.currentFilter.keyword) <> 0 or _
      c.title.lowercase.instrb(me.currentFilter.keyword) <> 0))
  
End Function

CFilterController.updateResults:
Sub updateResults()
  
  if me.currentFilter = nil or me.CQueryController1 = nil then return
  
  dim index as integer = me.CQueryController1.getCurrentIndex
  
  if me.CQueryController1.hasQueryModel(index) = false then return
  
  dim k as integer
  dim query as CQueryModel = me.CQueryController1.getQueryModel(index)
  dim o as CStatsModel
  dim c as CResponseModel
  dim d(-1) as CResponseModel
  dim f as new dictionary
  
  query.response.sort me.currentFilter.sortColumn, me.currentFilter.sortDirection
  
  for each o in query.response.representedObjects
    
    c = CResponseModel(o)
    
    if me.isFilteredResponse(c) then
      d.append c
      f.value(c.sha1) = k
      k = k + 1
      
    end
    
  next
  
  me.CQueryController1.setQueryModel index, query
  me.CQueryController1.setFilteredQuery new CQueryModel(d, f)
  
End Sub

CFilterController.setSortDirection:
Sub setSortDirection(value as integer)
  
  if me.currentFilter = nil or me.CQueryController1 = nil or me.CQueryController1.getCurrentIndex = -1 then return
  
  me.currentFilter.sortDirection = value
  me.CQueryController1.setFilterModel new CFilterModel(me.currentFilter)
  
End Sub

CFilterController.setSortColumn:
Sub setSortColumn(value as integer)
  
  if me.currentFilter = nil or me.CQueryController1 = nil or me.CQueryController1.getCurrentIndex = -1 then return
  
  me.currentFilter.sortColumn = value
  me.CQueryController1.setFilterModel new CFilterModel(me.currentFilter)
  
End Sub

CFilterController.setNeedsSort:
Sub setNeedsSort()
  
  me.needsSort = true
  
End Sub

CFilterController.Constructor:
Sub Constructor()
  
  me.currentFilter = new CFilterModel
  
End Sub

CFilterController.toggleFilterEnabled:
Sub toggleFilterEnabled()
  
  if me.currentFilter = nil or me.CQueryController1 = nil or me.CQueryController1.getCurrentIndex = -1 then return
  
  me.currentFilter.enabled = not me.currentFilter.enabled
  me.CQueryController1.setFilterModel new CFilterModel(me.currentFilter)
  
End Sub

CFilterController.setSpeedFilter:
Sub setSpeedFilter(value as integer)
  
  if me.currentFilter = nil or me.CQueryController1 = nil or me.CQueryController1.getCurrentIndex = -1 then return
  
  me.currentFilter.speed = value
  me.CQueryController1.setFilterModel new CFilterModel(me.currentFilter)
  
End Sub

CFilterController.setSourcesFilter:
Sub setSourcesFilter(value as integer)
  
  if me.currentFilter = nil or me.CQueryController1 = nil or me.CQueryController1.getCurrentIndex = -1 then return
  
  me.currentFilter.sources = value
  me.CQueryController1.setFilterModel new CFilterModel(me.currentFilter)
  
End Sub

CFilterController.setFilterModel:
Sub setFilterModel()
  
  if me.CQueryController1 = nil or me.CQueryController1.getCurrentIndex = -1 then return
  
  me.currentFilter = me.CQueryController1.getFilterModel()
  
End Sub

CFilterController.statsUpdated:
Sub statsUpdated()
  
  //* query result stack *//
  
  if me.needsSort then
    me.needsSort = false
    me.updateResults
    
  end
  
End Sub

CFilterController.ignoreResults:
Sub ignoreResults(selectedItems as dictionary)
  
  if me.currentFilter = nil or me.CQueryController1 = nil then return
  
  dim index as integer = me.CQueryController1.getCurrentIndex
  
  if me.CQueryController1.hasQueryModel(index) = false then return
  
  dim i, k as integer
  dim query as CQueryModel = me.CQueryController1.getQueryModel(index)
  dim o as CStatsModel
  dim c as CResponseModel
  dim d(-1) as CResponseModel
  dim f as new dictionary
  
  for i = ubound(query.response.representedObjects) downto 0
    
    c = CResponseModel(query.response.representedObjects(i))
    
    if selectedItems.hasKey(c.getRepresentation) then _
        query.response.representedObjects.remove i
    
  next
  
  query.response.rehash
  
  for each o in query.response.representedObjects
    
    c = CResponseModel(o)
    
    if me.isFilteredResponse(c) then
      d.append c
      f.value(c.sha1) = k
      k = k + 1
      
    end
    
  next
  
  me.CQueryController1.setQueryModel index, query
  me.CQueryController1.setFilteredQuery new CQueryModel(d, f)
  
End Sub

CFilterController.setScrollPosition:
Sub setScrollPosition(value as integer)
  
  if me.currentFilter = nil or me.CQueryController1 = nil or me.CQueryController1.getCurrentIndex = -1 then return
  
  me.currentFilter.scrollPosition = value
  me.CQueryController1.setFilterModel new CFilterModel(me.currentFilter)
  
End Sub

CFilterController.updateFilter:
Sub updateFilter()
  
  if me.currentFilter = nil then return
  
  filterChanged me.currentFilter
  
End Sub

CFilterController.isFilteredResponse:
Function isFilteredResponse(c as CResponseModel, filter as CFilterModel) As boolean
  
  return (c.spam = false or kAqSpamFilter = false) and _
      ((filter.enabled = false) or _
      (filter.media = 0 or filter.media = c.mediaType) and _
      (filter.bitrate <= c.bitrate) and _
      (filter.size <= c.fileSize) and _
      (filter.sources <= c.sources) and _
      (filter.speed <= c.speed) and _
      (filter.keyword.lenb = 0 or _
      c.fileName.lowercase.instrb(filter.keyword) <> 0 or _
      c.artist.lowercase.instrb(filter.keyword) <> 0 or _
      c.album.lowercase.instrb(filter.keyword) <> 0 or _
      c.title.lowercase.instrb(filter.keyword) <> 0))
  
End Function

CFilterController.setColumnWidths:
Sub setColumnWidths(value as string)
  
  if me.currentFilter = nil or me.CQueryController1 = nil or me.CQueryController1.getCurrentIndex = -1 then return
  
  me.currentFilter.columnWidths = value
  me.CQueryController1.setFilterModel new CFilterModel(me.currentFilter)
  
End Sub

CFilterController.getFilterModel:
Function getFilterModel() As CFilterModel
  return me.currentFilter
End Function

CiTunesController.launchiTunes:
Function launchiTunes() As Boolean
  
  #if targetMacOS
    if me.getPlayerState <> -1 then return true
    
    dim ae as AppleEvent
    
    ae = NewAppleEvent("aevt", "odoc", "MACS")
    ae.ObjectSpecifierParam("----") = GetUniqueIDObjectDescriptor("appf", nil, "hook")
    
    return ae.Send
    
  #endif
  
End Function

CiTunesController.pause:
Function pause() As Boolean
  
  #if targetMacOS
    dim ae as AppleEvent
    
    ae = NewAppleEvent("hook", "Paus", "hook")
    
    return ae.Send
    
  #elseif targetWin32
    try
      new OLEObject("iTunes.Application").Pause
      return true
      
    catch
      
    end
    
  #endif
  
End Function

CiTunesController.play:
Function play(track As variant) As Boolean
  
  #if targetMacOS
    dim ae as AppleEvent
    dim obj1, obj2 as AppleEventObjectSpecifier
    
    obj1 = GetStringComparisonObjectDescriptor("=   ", "prop", "pDID", track)
    obj2 = GetIndexedObjectDescriptor("cLiP", nil, 1)
    obj2 = GetTestObjectDescriptor("cTrk", obj2, obj1)
    
    ae = NewAppleEvent("hook", "Play", "hook")
    ae.ObjectSpecifierParam("----") = obj2
    
    return ae.Send
    
  #elseif targetWin32
    try
      OLEObject(track.objectValue).Play
      return true
      
    catch
      
    end
    
  #endif
  
End Function

CiTunesController.getPlayerState:
Function getPlayerState() As Integer
  
  #if targetMacOS
    dim ae as AppleEvent
    
    ae = NewAppleEvent("core", "getd", "hook")
    ae.ObjectSpecifierParam("----") = GetPropertyObjectDescriptor(nil, "pPlS")
    
    if ae.Send then
      
      if StrComp(ae.ReplyString, "kPSp", 0) = 0 then // paused
        return 2
        
      Elseif StrComp(ae.ReplyString, "kPSP", 0) = 0 then // playing
        return 1
        
      Elseif StrComp(ae.ReplyString, "kPSS", 0) = 0 then // stopped
        return 0
        
      end
      
    end
    
    return -1
    
  #elseif targetWin32
    try
      return new OLEObject("iTunes.Application").PlayerState
      
    catch
      
    end
    
    
  #endif
  
End Function

CiTunesController.makePlaylist:
Function makePlaylist(playlist As String) As variant
  
  #if targetMacOS
    dim ae as AppleEvent
    dim rec as AppleEventRecord
    
    rec = New AppleEventRecord
    rec.StringParam("pnam") = playlist.convertEncoding(Encodings.systemDefault)
    
    ae = NewAppleEvent("core", "crel", "hook")
    ae.RecordParam("prdt") = rec
    ae.MacTypeParam("kocl") = "cPly"
    
    if ae.Send then return ae.ReplyInteger
    
    return -1
    
  #elseif targetWin32
    try
      new OLEObject("iTunes.Application").CreatePlaylist playlist
      return true
      
    catch
      
    end
    
  #endif
  
End Function

CiTunesController.getPlaylistIndex:
Function getPlaylistIndex(Playlist As String) As Integer
  
  #if targetMacOS
    dim ae as AppleEvent
    dim obj as AppleEventObjectSpecifier
    
    obj = GetNamedObjectDescriptor("cPly", nil, Playlist.convertEncoding(Encodings.systemDefault))
    
    ae = NewAppleEvent("core", "getd", "hook")
    ae.ObjectSpecifierParam("----") = GetPropertyObjectDescriptor(obj, "pidx")
    
    if ae.Send then return ae.ReplyInteger
    
    return -1
    
  #elseif targetWin32
    dim o as OLEObject
    dim i, j as integer
    
    try
      o = new OLEObject("iTunes.Application").LibrarySource.Playlists
      j = o.count
      
      for i = 1 to j
        
        if o.Item(i).Name = Playlist then return i
        
      next
      
    catch
      
    end
    
  #endif
  
End Function

CiTunesController.addTrackToPlaylist:
Function addTrackToPlaylist(track as variant, Playlist As Variant) As variant
  
  #if targetMacOS
    dim ae as AppleEvent
    dim obj1 as AppleEventObjectSpecifier
    dim obj2 as AppleEventObjectSpecifier
    
    obj1 = GetStringComparisonObjectDescriptor("=   ", "prop", "pDID", track)
    obj2 = GetIndexedObjectDescriptor("cLiP", nil, 1)
    
    ae = NewAppleEvent("core", "clon", "hook")
    ae.ObjectSpecifierParam("----") = GetTestObjectDescriptor("cTrk", obj2, obj1)
    ae.ObjectSpecifierParam("insh") = GetIndexedObjectDescriptor("cPly", nil, playlist)
    
    if ae.Send and ae.ReplyObjectSpecifier <> nil then
      obj1 = ae.ReplyObjectSpecifier
      
      ae = NewAppleEvent("core", "getd", "hook")
      ae.ObjectSpecifierParam("----") = GetPropertyObjectDescriptor(obj1, "pDID")
      
      if ae.Send then return ae.ReplyInteger
      
    end
    
    return -1
    
  #elseif targetWin32
    dim o as OLEObject
    dim v(1) as variant
    
    try
      v(1) = track.objectValue
      o = new OLEObject("iTunes.Application").LibrarySource.Playlists.ItemByName(Playlist.stringValue)
      o = o.invoke("AddTrack", v)
      return o
      
    catch
      
    end
    
    return nil
    
  #endif
  
End Function

CiTunesController.getCurrentTrackArtist:
Function getCurrentTrackArtist() As string
  
  #if targetMacOS
    Dim ae As AppleEvent
    Dim obj As AppleEventObjectSpecifier
    
    obj = GetPropertyObjectDescriptor( Nil, "pTrk" )
    
    ae = NewAppleEvent( "core", "getd", "hook" )
    ae.ObjectSpecifierParam("----") = GetPropertyObjectDescriptor( obj, "pArt" )
    
    if ae.Send then return ae.ReplyString.convertEncoding(Encodings.UTF8)
    
  #elseif TargetWin32
    try
      return new OLEObject("iTunes.Application").CurrentTrack.Artist
      
    catch
      
    end
    
  #endif
  
End Function

CiTunesController.getCurrentTrackName:
Function getCurrentTrackName() As string
  
  #if targetMacOS
    Dim ae As AppleEvent
    Dim obj As AppleEventObjectSpecifier
    
    obj = GetPropertyObjectDescriptor( Nil, "pTrk" )
    
    ae = NewAppleEvent( "core", "getd", "hook" )
    ae.ObjectSpecifierParam("----") = GetPropertyObjectDescriptor( obj, "pnam" )
    
    if ae.Send then return ae.ReplyString.convertEncoding(Encodings.UTF8)
    
  #elseif TargetWin32
    try
      return new OLEObject("iTunes.Application").CurrentTrack.Name
      
    catch
      
    end
    
  #endif
  
End Function

CiTunesController.addFileToLibrary:
Function addFileToLibrary(item As FolderItem) As variant
  
  #if targetMacOS
    dim ae as AppleEvent
    dim obj as AppleEventObjectSpecifier
    
    obj = GetIndexedObjectDescriptor("cLiP", nil, 1)
    
    ae = NewAppleEvent("hook", "Add ","hook")
    ae.FolderItemParam("----") = item
    ae.ObjectSpecifierParam("insh") = obj
    
    if ae.Send and ae.ReplyObjectSpecifier <> nil then
      obj = ae.ReplyObjectSpecifier
      
      ae = NewAppleEvent("core", "getd", "hook")
      ae.ObjectSpecifierParam("----") = GetPropertyObjectDescriptor(obj, "pDID")
      
      if ae.Send then return ae.ReplyInteger
      
    end
    
    return -1
    
  #elseif targetWin32
    dim o as OLEObject
    dim v(1) as variant
    
    try
      v(1) = item.posixPath
      o = new OLEObject("iTunes.Application").LibraryPlaylist.invoke("AddFile", v)
      return o.Tracks.Item(o.Tracks.count)
      
    catch
      
    end
    
    return nil
    
  #endif
  
End Function

CiTunesController.play:
Function play(TrackID As variant, PlaylistIndex As integer) As Boolean
  
  #if targetMacOS
    Dim ae As AppleEvent
    Dim obj1, obj2 As AppleEventObjectSpecifier
    
    obj1 = GetStringComparisonObjectDescriptor("=   ", "prop", "pDID", trackID)
    obj2 = GetIndexedObjectDescriptor("cPly", nil, PlaylistIndex)
    obj2 = GetTestObjectDescriptor("cTrk", obj2, obj1)
    
    ae = NewAppleEvent( "hook", "Play", "hook" )
    ae.ObjectSpecifierParam("----") = obj2
    
    Return ae.Send
    
  #endif
  
End Function

CiTunesController.getPlaylistName:
Function getPlaylistName(index as integer) As string
  
  #if targetWin32
    try
      return new OLEObject("iTunes.Application").LibrarySource.Playlists.Item(Index).Name
      
    catch
      
    end
    
  #endif
  
End Function

CLocalizationController.getLocalizedStringFromTable:
Function getLocalizedStringFromTable(key as string, tableName as string) As string
  
  if key.lenb = 0 then return ""
  
  #if debugBuild and targetMachO
    if me.table.haskey(tableName) = false then me.table.value(tableName) = new dictionary
    
    if Dictionary(me.table.value(tableName)).hasKey(key) = false then Dictionary(me.table.value(tableName)).value(key) = key
    
  #endif
  
  if me.table.haskey(tableName) and Dictionary(me.table.value(tableName)).hasKey(key) then return Dictionary(me.table.value(tableName)).value(key)
  
  return key
  
End Function

CLocalizationController.Destructor:
Sub Destructor()
  '
  '#if debugBuild and targetMachO
  'dim bs as binaryStream
  'dim d as dictionary
  'dim i, j, k as integer
  'dim fi as folderItem = getFolderItem("Contents").child("Resources").Child("English.lproj")
  '
  'for i = me.table.count - 1 downto 0
  '
  'try
  'bs = fi.child(me.table.key(i) + ".strings").createBinaryFile("")
  'bs.write encodings.UTF16.chr(&hFEFF)
  'd = me.table.value(me.table.key(i))
  'k = d.count - 1
  '
  'for j = 0 to k
  '
  'bs.write convertEncoding("""" + d.key(j).replaceAllB("""", "\""").replaceAllB(EndOfLine, "\n") + """ = """ + d.value(d.key(j)).replaceAllB("""", "\""").replaceAllB(EndOfLine, "\n") + """;" + EndOfLine.UNIX, encodings.UTF16)
  '
  'next
  '
  'catch
  '
  'finally
  'if bs <> nil then bs.close
  '
  'end
  '
  'next
  '
  '#endif
  '
End Sub

CLocalizationController.loadLocalizedStrings:
Protected Sub loadLocalizedStrings(fi as folderItem)
  
  dim bom, tableName, raw, key, value as string
  dim bs as binaryStream
  dim r as new regex
  dim m as regexmatch
  dim i as integer
  dim utf16bigbom as string = chrb(&hFE) + chrb(&hFF)
  dim utf16littlebom as string = chrb(&hFF) + chrb(&hFE)
  dim utf8bom as string = chrb(&hEF) + chrb(&hBB) + chrb(&hBF)
  
  r.searchpattern = """(.+)""\s*=\s*""(.*)"";"
  
  for i = fi.count downto 1
    
    if strcomp(fi.item(i).name.rightb(8), ".strings", 0) = 0 then
      tableName = fi.item(i).name.replaceb(".strings", "")
      
      try
        bs = fi.item(i).openAsBinaryFile(false)
        bom = bs.read(3)
        
        if strcomp(bom.leftB(2), utf16bigbom, 0) = 0 then
          bs.position = 2
          #if targetWin32 or targetLinux or targetX86 'Intel
            raw = bs.read(bs.length - 2).reverseEndian.convertEncoding(encodings.UTF8)
            
          #elseif targetMacOS 'PowerPC
            raw = bs.read(bs.length - 2, encodings.UTF16).convertEncoding(encodings.UTF8)
            
          #endif
          
        elseif strcomp(bom.leftB(2), utf16littlebom, 0) = 0 then
          bs.position = 2
          #if targetWin32 or targetLinux or targetX86 'Intel
            raw = bs.read(bs.length - 2, encodings.UTF16).convertEncoding(encodings.UTF8)
            
          #elseif targetMacOS 'PowerPC
            raw = bs.read(bs.length - 2).reverseEndian.convertEncoding(encodings.UTF8)
            
          #endif
          
        elseif strcomp(bom, utf8bom, 0) = 0 then
          bs.position = 3
          raw = bs.read(bs.length - 3, encodings.UTF8)
          
        else
          bs.position = 0
          raw = bs.read(bs.length, encodings.UTF8)
          
        end
        
        me.table.value(tableName) = new dictionary
        m = r.search(raw)
        
        while m <> nil
          
          key = m.SubExpressionString(1).replaceAllB("\""", """").replaceAllB("\n", EndOfLine)
          value = m.SubExpressionString(2).replaceAllb("\""", """").replaceAllb("\n", EndOfLine)
          
          if strcomp(key, value, 0) <> 0 then _
              Dictionary(me.table.value(tableName)).value(key) = value
          m = r.search(raw, m.subExpressionStartB(2) + m.subExpressionString(2).lenb)
          
        wend
        
      catch
        
      finally
        if bs <> nil then bs.close
        
      end
      
    end
    
  next
  
End Sub

CLocalizationController.Constructor:
Sub Constructor()
  
  me.table = new dictionary
  
  dim fi as folderItem
  
  //* find .lproj folder for current language *//
  
  #if debugBuild and targetMachO
    'dim MainBundle as new CFBundle(new CFURL(getFolderItem("")))
    'dim locArray as CFArray = MainBundle.Localizations
    'dim preferLoc as CFArray = MainBundle.PreferredLocalizations(locArray)
    'dim currentLanguage as string = new CFString(preferLoc.value(0))
    '
    'try
    'fi = getFolderItem("Contents").child("Resources").child(currentLanguage + ".lproj")
    '
    'catch
    '
    'end
    
  #elseif targetMachO
    dim MainBundle as new CFBundle
    dim locArray as CFArray = MainBundle.Localizations
    dim preferLoc as CFArray = MainBundle.PreferredLocalizations(locArray)
    dim currentLanguage as string = new CFString(preferLoc.value(0))
    
    try
      fi = App.ExecutableFile.parent.parent.child("Resources").child(currentLanguage + ".lproj")
      
    catch
      
    end
    
  #elseif targetCarbon
    Declare Function GetScriptVariable lib kCarbon (script as short, selector as short) as short
    Declare Function GetScriptManagerVariable lib kCarbon (selector as short) as short
    Declare Function LocaleRefFromLangOrRegionCode lib kCarbon (LangCode as short, RegionCode as short, LocaleRef as Integer) as short
    Declare Function LocaleRefGetPartString lib kCarbon (locale as Integer, partMask as Integer, maxStringLen as short, partString as Ptr) as short
    
    dim languageCode, regionCode, error as integer
    dim str255 as new MemoryBlock(255)
    dim localeRef as Integer
    
    const kSystemScript = -1
    const kCurrentLanguage = 28
    const smRegionCode = 40
    const kLocaleAllPartsMask = &h0000003F
    
    languageCode = GetScriptVariable(kSystemScript, kCurrentLanguage)
    regionCode = GetScriptManagerVariable(smRegionCode)
    error = LocaleRefFromLangOrRegionCode(languageCode, regionCode, localeRef)
    error = LocaleRefGetPartString(localeRef, kLocaleAllPartsMask, str255.Size, str255)
    
    dim d as new Dictionary
    
    //* A *//
    
    d.value(0) = "English"
    d.value(1) = "French"
    d.value(2) = "German"
    d.value(3) = "Italian"
    d.value(4) = "Dutch"
    d.value(5) = "Swedish"
    d.value(6) = "Spanish"
    d.value(7) = "Danish"
    d.value(8) = "Portuguese"
    d.value(9) = "Norwegian"
    d.value(10) = "Hebrew"
    d.value(11) = "Japanese"
    d.value(12) = "Arabic"
    d.value(13) = "Finnish"
    d.value(14) = "Greek"
    d.value(15) = "Icelandic"
    d.value(16) = "Maltese"
    d.value(17) = "Turkish"
    d.value(18) = "Croatian"
    d.value(19) = "Traditional Chinese"
    d.value(20) = "Urdu"
    d.value(21) = "Hindi"
    d.value(22) = "Thai"
    d.value(23) = "Korean"
    
    //* B *//
    
    d.value(24) = "Lithuanian"
    d.value(25) = "Polish"
    d.value(26) = "Hungarian"
    d.value(27) = "Estonian"
    d.value(28) = "Lettish"
    d.value(29) = "Sami"
    d.value(30) = "Faroese"
    d.value(31) = "Farsi"
    d.value(31) = "Persian"
    d.value(32) = "Russian"
    d.value(33) = "Simplified Chinese"
    d.value(34) = "Flemish"
    d.value(35) = "Irish Gaelic"
    d.value(36) = "Albanian"
    d.value(37) = "Romanian"
    d.value(38) = "Czech"
    d.value(39) = "Slovak"
    d.value(40) = "Slovenian"
    d.value(41) = "Yiddish"
    d.value(42) = "Serbian"
    d.value(43) = "Macedonian"
    d.value(44) = "Bulgarian"
    d.value(45) = "Ukrainian"
    d.value(46) = "Byelorussian"
    
    try
      fi = App.executableFile.parent.child("Contents").child("Resources").child(str255.CString(0) + ".lproj")
      
      if fi.exists = false then _
          fi = App.executableFile.parent.child("Contents").child("Resources").child(str255.CString(0).leftb(2) + ".lproj")
      
      if fi.exists = false then _
          fi = App.executableFile.parent.child("Contents").child("Resources").child(d.value(languageCode) + ".lproj")
      
    catch
      
    end
    
  #elseif targetWin32
    Declare Function GetLocaleInfoA Lib "kernel32" (Locale As integer, LCType As integer, lpLCData As ptr, cchData As integer) As Integer
    
    dim mb as memoryBlock
    dim iso639, locale, english as string
    
    Const LOCALE_USER_DEFAULT = &H400
    Const LOCALE_SISO639LANGNAME = &H59
    Const LOCALE_SISO3166CTRYNAME = &H5A
    Const LOCALE_SENGLANGUAGE = &H1001
    
    mb = new MemoryBlock( 256 )
    call GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, mb, mb.Size )
    iso639 = mb.CString( 0 ).defineEncoding(Encodings.UTF8)
    
    mb = new MemoryBlock( 256 )
    call GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, mb, mb.Size )
    locale = iso639 + "_" + mb.CString( 0 ).defineEncoding(Encodings.UTF8)
    
    mb = new MemoryBlock( 256 )
    call GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_SENGLANGUAGE, mb, mb.Size )
    english = mb.CString( 0 ).defineEncoding(Encodings.UTF8)
    
    try
      fi = App.ExecutableFile.fixRbBug.parent.child("Contents").child("Resources").child(iso639 + ".lproj")
      
      if fi.exists = false then _
          fi = App.ExecutableFile.fixRbBug.parent.child("Contents").child("Resources").child(locale + ".lproj")
      
      if fi.exists = false then _
          fi = App.ExecutableFile.fixRbBug.parent.child("Contents").child("Resources").child(english + ".lproj")
      
    catch
      
    end
    
  #elseif targetLinux
    'todo
    
  #endif
  
  if fi <> nil and fi.exists then
    me.loadLocalizedStrings fi
  end
  
End Sub

CActionsController.actionHeading:
Protected Sub actionHeading(item as string)
  
  dim i as integer
  
  if item = getLocalizedString("Reset to Default", "ContextualMenu") then
    me.receiver.setColumnWidths me.receiver.getInitialColumnWidths
    me.receiver.headingIndex = -1
    
    if me.receiver isa CResponseListBox then
      me.CFilterController1.setColumnWidths me.receiver.columnWidths
      me.CFilterController1.setSortColumn -1
      me.CFilterController1.setSortDirection ListBox.sortAscending
      
    end
    
    return
    
  else
    item = item.replaceb(kChecked, "").replaceb(kUnchecked, "")
    
    for i = me.receiver.columnCount - 1 downto 0
      
      if me.receiver.heading(i) = item then
        if me.receiver.column(i).widthExpression = "0%" then
          me.receiver.column(i).userResizable = true
          me.receiver.column(i).widthExpression = _
              me.receiver.getInitialColumnWidths.nthField(",", i + 1).trim
          
        else
          me.receiver.column(i).userResizable = false
          me.receiver.column(i).widthExpression = "0%"
          
        end
        
        me.receiver.columnWidths = me.receiver.columnWidths
        if me.receiver isa CResponseListBox then 
          me.CFilterController1.setColumnWidths me.receiver.columnWidths
        end
        return
        
      end
      
    next
    
  end
  
End Sub

CActionsController.openHeadingMenu:
Sub openHeadingMenu(sender as CStatsListBox)
  
  dim i, j as integer
  
  try
    me.actionType = 1 //* heading *//
    me.receiver = sender
    me.receiver.setFocus
    j = me.receiver.columnCount - 1
    
    for i = 0 to j
      
      if me.receiver.column(i).MaxWidthExpression <> me.receiver.column(i).MinWidthExpression then
        if me.receiver.column(i).WidthExpression = "0%" then
          me.addRow kUnchecked + me.receiver.heading(i)
          
        else
          me.addRow kChecked + me.receiver.heading(i)
          
        end
        
      end
      
    next
    
    me.addSeparator
    me.addRow getLocalizedString("Reset to Default", "ContextualMenu")
    me.open
    
  catch
    
  finally
    me.deleteAllRows
    me.actionType = 0 //* initialize *//
    me.receiver = nil
    
  end
  
End Sub

CActionsController.openNetworkMenu:
Sub openNetworkMenu(sender as CStatsListBox)
  
  dim i, j as integer
  dim items(-1) as string
  
  try
    me.actionType = 2 //* network *//
    me.receiver = sender
    me.receiver.setFocus
    
    select case me.receiver.selCount
      
    case 0
      me.addRow getLocalizedString("Remove All", "ContextualMenu")
      
    case 1
      me.addRow getLocalizedString("Remove", "ContextualMenu")
      me.addRow getLocalizedString("Remove All", "ContextualMenu")
      
      addBrowseHostFromNetwork me.receiver.listIndex, items()
      
      if ubound(items) = 0 then
        me.addSeparator
        me.addRow getLocalizedStringWithStringData("Browse %@", "ContextualMenu", items(0))
        
      end
      
    else
      me.addRow getLocalizedString("Remove", "ContextualMenu")
      me.addRow getLocalizedString("Remove All", "ContextualMenu")
      
      j = me.receiver.listCount - 1
      
      for i = 0 to j
        
        if me.receiver.selected(i) then _
            addBrowseHostFromNetwork i, items()
        
      next
      
      j = ubound(items)
      
      if j <> -1 then
        me.addSeparator
        
      end
      
      for i = 0 to j
        
        me.addRow getLocalizedStringWithStringData("Browse %@", "ContextualMenu", items(i))
        
      next
      
      if j > 0 then
        me.addSeparator
        me.addRow getLocalizedString("Browse All Selected Hosts", "ContextualMenu")
        
      end
      
    end
    
    me.open
    
  catch
    
  finally
    me.deleteAllRows
    me.actionType = 0 //* initialize *//
    me.receiver = nil
    
  end
  
End Sub

CActionsController.actionNetwork:
Protected Sub actionNetwork(item as string)
  
  dim i, j as integer
  dim items(-1) as string
  
  select case item
    
  case getLocalizedString("Remove", "ContextualMenu")
    actionNetworkRemove me.receiver
    
  case getLocalizedString("Remove All", "ContextualMenu")
    me.receiver.selectAll
    actionNetworkRemove me.receiver
    
  case getLocalizedString("Browse All Selected Hosts", "ContextualMenu")
    j = me.receiver.listCount - 1
    
    for i = 0 to j
      
      if me.receiver.selected(i) then _
          addBrowseHostFromNetwork i, items()
      
    next
    
    j = ubound(items)
    
    for i = 0 to j
      
      me.CQueryController1.handleQueryBrowse items(i)
      
    next
    
  else
    me.CQueryController1.handleQueryBrowse _
        item.replaceb(getLocalizedStringWithStringData("Browse %@", "ContextualMenu", ""), "")
    
  end
  
End Sub

CActionsController.openSidebarMenu:
Sub openSidebarMenu(sender as CStatsListBox)
  
  try
    me.actionType = 3 //* sidebar *//
    me.receiver = sender
    me.receiver.setFocus
    
    if me.receiver.listIndex <> -1 then
      if me.receiver.selcount <> 1 then
        
      elseif CStatsModel(me.receiver.dataSource(me.receiver.listIndex)).getRepresentation < 0 then
        me.addRow getLocalizedString("Start Query", "ContextualMenu")
        
        if me.CQueryController1.getKeepInSidebar(CStatsModel(me.receiver.dataSource(me.receiver.listIndex)).getRepresentation) = false then _
            me.addRow getLocalizedString("Keep in Sidebar", "ContextualMenu")
        
        me.addSeparator
        me.addRow getLocalizedString("Remove", "ContextualMenu")
        me.addSeparator
        
      else
        me.addRow getLocalizedString("Stop Query", "ContextualMenu")
        
        if me.CQueryController1.getKeepInSidebar(CStatsModel(me.receiver.dataSource(me.receiver.listIndex)).getRepresentation) = false then _
            me.addRow getLocalizedString("Keep in Sidebar", "ContextualMenu")
        
        me.addSeparator
        me.addRow getLocalizedString("Remove", "ContextualMenu")
        me.addSeparator
        
      end
      
      if me.receiver.selcount <> 1 then
        me.addRow getLocalizedString("Clear All Results and Restart Query", "ContextualMenu")
        me.addRow getLocalizedString("Clear All Results", "ContextualMenu")
        me.addSeparator
        me.addRow getLocalizedString("Remove", "ContextualMenu")
        me.addSeparator
        
      elseif me.CQueryController1.getResponseCount <> 0 then
        me.addRow getLocalizedString("Clear All Results and Restart Query", "ContextualMenu")
        me.addRow getLocalizedString("Clear All Results", "ContextualMenu")
        me.addSeparator
        
      end
      
    end
    
    me.addRow getLocalizedString("Remove All Queries", "ContextualMenu")
    me.open
    
  catch
    
  finally
    me.deleteAllRows
    me.actionType = 0 //* initialize *//
    me.receiver = nil
    
  end
  
End Sub

CActionsController.actionSidebar:
Protected Sub actionSidebar(item as string)
  
  dim i as integer
  
  select case item
    
  case getLocalizedString("Start Query", "ContextualMenu")
    me.CQueryController1.startQuery false
    
  case getLocalizedString("Stop Query", "ContextualMenu")
    me.CQueryController1.stopQuery' CStatsModel(me.receiver.dataSource(me.receiver.listIndex)).getRepresentation
    
  case getLocalizedString("Keep in Sidebar", "ContextualMenu")
    me.CQueryController1.setKeepInSidebar CStatsModel(me.receiver.dataSource(me.receiver.listIndex)).getRepresentation, true
    
  case getLocalizedString("Remove", "ContextualMenu")
    actionSidebarRemove me.receiver
    
  case getLocalizedString("Clear All Results and Restart Query", "ContextualMenu")
    for i = me.receiver.listCount - 1 downto 0
      
      if me.receiver.selected(i) then
        me.CQueryController1.clearAllResults CStatsModel(me.receiver.dataSource(i)).getRepresentation
        me.CQueryController1.startQuery CStatsModel(me.receiver.dataSource(i)).getRepresentation, false
        
      end
      
    next
    
  case getLocalizedString("Clear All Results", "ContextualMenu")
    for i = me.receiver.listCount - 1 downto 0
      
      if me.receiver.selected(i) then
        me.CQueryController1.clearAllResults CStatsModel(me.receiver.dataSource(i)).getRepresentation
        
      end
      
    next
    
  case getLocalizedString("Remove All Queries", "ContextualMenu")
    me.CQueryController1.removeAllQueries
    
  end
  
End Sub

CActionsController.openResponseMenu:
Sub openResponseMenu(sender as CStatsListBox)
  
  dim i, j as integer
  dim items(-1) as string
  
  try
    me.actionType = 4 //* query results *//
    me.receiver = sender
    me.receiver.setFocus
    
    select case me.receiver.selCount
      
    case 0
      me.addRow getLocalizedString("Clear All Results", "ContextualMenu")
      
    case 1
      me.addRow getLocalizedString("Download", "ContextualMenu")
      
      if me.CQueryController1.hasQueryString(me.receiver.helpTag) = false then
        me.addSeparator
        me.addRow getLocalizedString("Find More Sources", "ContextualMenu")
      end
      
      me.addSeparator
      #if targetMachO or targetWin32 or targetLinux
        me.addRow getLocalizedString("Mark As Spam", "ContextualMenu")
        if kAqSpamFilter = false then _
            me.addRow getLocalizedString("Mark As Not Spam", "ContextualMenu")
        me.addSeparator
      #endif
      
      me.addRow getLocalizedString("Clear All Results", "ContextualMenu")
      
      addBrowseHostFromResponse(me.receiver.listIndex, items())
      j = ubound(items)
      
      if j <> -1 then me.addSeparator
      
      for i = 0 to j
        
        me.addRow getLocalizedStringWithStringData("Browse %@", "ContextualMenu", items(i))
        
      next
      
      if j > 0 then
        me.addSeparator
        me.addRow getLocalizedString("Browse All Selected Hosts", "ContextualMenu")
        
      end
      
    else
      me.addRow getLocalizedString("Download", "ContextualMenu")
      
      me.addSeparator
      #if targetMachO or targetWin32 or targetLinux
        me.addRow getLocalizedString("Mark As Spam", "ContextualMenu")
        if kAqSpamFilter = false then _
            me.addRow getLocalizedString("Mark As Not Spam", "ContextualMenu")
        me.addSeparator
        
      #endif
      
      me.addRow getLocalizedString("Clear All Results", "ContextualMenu")
      j = me.receiver.listCount - 1
      
      for i = 0 to j
        
        if me.receiver.selected(i) then addBrowseHostFromResponse(i, items())
        
      next
      
      j = ubound(items)
      
      if j <> -1 then me.addSeparator
      
      for i = 0 to j
        
        me.addRow getLocalizedStringWithStringData("Browse %@", "ContextualMenu", items(i))
        
      next
      
      if j > 0 then
        me.addSeparator
        me.addRow getLocalizedString("Browse All Selected Hosts", "ContextualMenu")
        
      end
      
    end
    
    me.open
    
  catch
    
  finally
    me.deleteAllRows
    me.actionType = 0 //* initialize *//
    me.receiver = nil
    
  end
  
End Sub

CActionsController.addBrowseHostFromResponse:
Protected Sub addBrowseHostFromResponse(index as integer, byref items() as string)
  
  dim c as CResponseModel = me.CQueryController1.getResponseModel(index)
  
  if c = nil then return
  
  dim i, j as integer
  
  j = ubound(c.address)
  
  for i = 0 to j
    
    if c.isBrowseHostEnabled(i) and _
        items.indexOf(c.address(i)) = -1 and _
        me.CQueryController1.hasQueryString(c.address(i)) = false then _
        items.append c.address(i)
    
  next
  
  items.sort
  
End Sub

CActionsController.actionResponse:
Protected Sub actionResponse(item as string)
  
  dim i, j as integer
  dim arg, items(-1) as string
  
  select case item
    
  case getLocalizedString("Download", "ContextualMenu")
    actionResponseDownload me.receiver
    
  case getLocalizedString("Mark As Spam", "ContextualMenu")
    actionResponseSpam me.receiver
    
  case getLocalizedString("Mark As Not Spam", "ContextualMenu")
    j = me.receiver.listCount - 1
    
    for i = 0 to j
      
      if me.receiver.selected(i) then
        me.CCoreController1.sendCommand "removeSpamFiles|" + me.CQueryController1.getLocalIndexes(i)
        me.CQueryController1.setQuerySpam(i, false)
        
      end
      
    next
    
    me.CCoreController1.sendCommand "applyFilterSettings"
    me.CFilterController1.filterResults
    
  case getLocalizedString("Clear All Results", "ContextualMenu")
    me.CQueryController1.clearAllResults
    
  case getLocalizedString("Browse All Selected Hosts", "ContextualMenu")
    j = me.receiver.listCount - 1
    
    for i = 0 to j
      if me.receiver.selected(i) then addBrowseHostFromResponse i, items()
      
    next
    
    j = ubound(items)
    
    for i = 0 to j
      
      CQueryController1.handleQueryBrowse items(i)
      
    next
    
  case getLocalizedString("Find More Sources", "ContextualMenu")
    me.CQueryController1.handleQueryFindMoreSources me.receiver.helpTag.split(EndOfLine).top
    
  else
    me.CQueryController1.handleQueryBrowse _
        item.replaceb(getLocalizedStringWithStringData("Browse %@", "ContextualMenu", ""), "")
    
  end
  
End Sub

CActionsController.actionResponseDownload:
Sub actionResponseDownload(targetListBox as CListBox)
  
  dim i, j as integer
  
  j = targetListBox.listCount - 1
  
  for i = 0 to j
    
    if targetListBox.selected(i) then
      me.CCoreController1.sendCommand "download|" + me.CQueryController1.getLocalIndexes(i)
      me.CQueryController1.setQueryMarked(i, true)
      
    end
    
  next
  
  me.CQueryController1.flush
  
End Sub

CActionsController.openDownloadsMenu:
Sub openDownloadsMenu(sender as CStatsListBox)
  
  dim i, j as integer
  dim items(-1) as string
  
  try
    me.actionType = 5 //* downloads *//
    me.receiver = sender
    me.receiver.setFocus
    
    select case me.receiver.selCount
      
    case 0
      me.addRow getLocalizedString("Clear All Completed", "ContextualMenu")
      me.addSeparator
      me.addRow getLocalizedString("Remove All", "ContextualMenu")
      
    case 1
      me.addRow getLocalizedString("Open", "ContextualMenu")
      me.addRow getLocalizedString("Open With...", "ContextualMenu")
      me.addRow getLocalizedString("Reveal in Finder", "ContextualMenu")
      
      //* if not completed *//
      
      if me.CDownloadsController1.isCompletedTransferItem(me.receiver.listIndex) = false then
        me.addSeparator
        me.addRow getLocalizedString("Resume", "ContextualMenu")
        if me.CQueryController1.hasQueryString(me.receiver.helpTag) = false then _
            me.addRow getLocalizedString("Find More Sources", "ContextualMenu")
        
      end
      
      me.addSeparator
      me.addRow getLocalizedString("Clear All Completed", "ContextualMenu")
      me.addSeparator
      me.addRow getLocalizedString("Remove", "ContextualMenu")
      me.addRow getLocalizedString("Remove All", "ContextualMenu")
      
      addBrowseHostFromDownloads me.receiver.listIndex, items()
      j = ubound(items)
      
      if j <> -1 then me.addSeparator
      
      for i = 0 to j
        
        me.addRow getLocalizedStringWithStringData("Browse %@", "ContextualMenu", items(i))
        
      next
      
      if j > 0 then
        me.addSeparator
        me.addRow getLocalizedString("Browse All Selected Hosts", "ContextualMenu")
        
      end
      
    else //* if not completed *//
      me.addRow getLocalizedString("Resume", "ContextualMenu")
      me.addSeparator
      me.addRow getLocalizedString("Clear All Completed", "ContextualMenu")
      me.addSeparator
      me.addRow getLocalizedString("Remove", "ContextualMenu")
      me.addRow getLocalizedString("Remove All", "ContextualMenu")
      
      j = me.receiver.listCount - 1
      
      for i = 0 to j
        
        if me.receiver.selected(i) then _
            addBrowseHostFromDownloads i, items()
        
      next
      
      j = ubound(items)
      
      if j <> -1 then me.addSeparator
      
      for i = 0 to j
        
        me.addRow getLocalizedStringWithStringData("Browse %@", "ContextualMenu", items(i))
        
      next
      
      if j > 0 then
        me.addSeparator
        me.addRow getLocalizedString("Browse All Selected Hosts", "ContextualMenu")
        
      end
      
    end
    
    me.open
    
  catch
    
  finally
    me.deleteAllRows
    me.actionType = 0 //* initialize *//
    me.receiver = nil
    
  end
  
End Sub

CActionsController.openUploadsMenu:
Sub openUploadsMenu(sender as CStatsListBox)
  
  dim i, j as integer
  dim items(-1) as string
  
  try
    me.actionType = 6 //* uploads *//
    me.receiver = sender
    me.receiver.setFocus
    
    select case me.receiver.selCount
      
    case 0
      me.addRow getLocalizedString("Clear All Completed", "ContextualMenu")
      me.addSeparator
      me.addRow getLocalizedString("Remove All", "ContextualMenu")
      
    case 1
      me.addRow getLocalizedString("Open", "ContextualMenu")
      me.addRow getLocalizedString("Open With...", "ContextualMenu")
      me.addRow getLocalizedString("Reveal in Finder", "ContextualMenu")
      me.addSeparator
      me.addRow getLocalizedString("Clear All Completed", "ContextualMenu")
      me.addSeparator
      me.addRow getLocalizedString("Remove", "ContextualMenu")
      me.addRow getLocalizedString("Remove All", "ContextualMenu")
      addBrowseHostFromUploads me.receiver.listIndex, items()
      j = ubound(items)
      
      if j <> -1 then me.addSeparator
      
      for i = 0 to j
        
        me.addRow getLocalizedStringWithStringData("Browse %@", "ContextualMenu", items(i))
        
      next
      
      if j > 0 then
        me.addSeparator
        me.addRow getLocalizedString("Browse All Selected Hosts", "ContextualMenu")
        
      end
      
    else //* if not completed *//
      me.addRow getLocalizedString("Clear All Completed", "ContextualMenu")
      me.addSeparator
      me.addRow getLocalizedString("Remove", "ContextualMenu")
      me.addRow getLocalizedString("Remove All", "ContextualMenu")
      
      j = me.receiver.listCount - 1
      
      for i = 0 to j
        
        if me.receiver.selected(i) then _
            addBrowseHostFromUploads i, items()
        
      next
      
      j = ubound(items)
      
      if j <> -1 then me.addSeparator
      
      for i = 0 to j
        
        me.addRow getLocalizedStringWithStringData("Browse %@", "ContextualMenu", items(i))
        
      next
      
      if j > 0 then
        me.addSeparator
        me.addRow getLocalizedString("Browse All Selected Hosts", "ContextualMenu")
        
      end
      
    end
    
    me.open
    
  catch
    
  finally
    me.deleteAllRows
    me.actionType = 0 //* initialize *//
    me.receiver = nil
    
  end
  
End Sub

CActionsController.actionDownloads:
Protected Sub actionDownloads(item as string)
  
  dim fi(1) as folderItem
  dim path, items(-1) as string
  dim i, j as integer
  dim hasActiveTransfers as boolean
  
  select case item
    
  case getLocalizedString("Open", "ContextualMenu")
    actionDownloadsOpen me.receiver
    
  case getLocalizedString("Open With...", "ContextualMenu")
    if kAqWarnOpening = false or me.CDownloadsController1.isCompletedTransferItem(me.receiver.listIndex) or askOpening then
      path = me.CDownloadsController1.getTransferPath(me.receiver.listIndex)
      
      if path.lenB <> 0 then fi(0) = getPath2FolderItem(path)
      
      fi(1) = getOpenFolderItem("application/executable")
      
      if fi(0) <> nil and fi(0).exists and fi(1) <> nil and fi(1).exists then _
          fi(0).openWith(fi(1))
      
    end
    
  case getLocalizedString("Reveal in Finder", "ContextualMenu")
    actionDownloadsRevealInFinder me.receiver
    
  case getLocalizedString("Pause", "ContextualMenu")
    j = me.receiver.listCount - 1
    
    for i = 0 to j
      
      if me.receiver.selected(i) and _
          me.CDownloadsController1.isCompletedTransferItem(i) = false then _
          me.CCoreController1.sendCommand "pauseDownload|" + me.CDownloadsController1.getTransferHashCode(i)
      
    next
    
  case getLocalizedString("Resume", "ContextualMenu")
    j = me.receiver.listCount - 1
    
    for i = 0 to j
      if me.receiver.selected(i) and _
          me.CDownloadsController1.isCompletedTransferItem(i) = false then _
          me.CCoreController1.sendCommand "retryDownload|" + me.CDownloadsController1.getTransferHashCode(i)
    next
    
  case getLocalizedString("Find More Sources", "ContextualMenu")
    if me.CDownloadsController1.isCompletedTransferItem(me.receiver.listIndex) = false then _
        me.CQueryController1.handleQueryFindMoreSources me.CDownloadsController1.getTransferFileName(me.receiver.listIndex)
    
  case getLocalizedString("Clear All Completed", "ContextualMenu")
    for i = me.receiver.listCount - 1 downto 0
      if me.CDownloadsController1.isCompletedTransferItem(i) then _
          me.CDownloadsController1.remove(i)
    next
    
    me.CDownloadsController1.statsUpdated
    
  case getLocalizedString("Remove", "ContextualMenu")
    actionDownloadsRemove me.receiver
    
  case getLocalizedString("Remove All", "ContextualMenu")
    me.receiver.selectAll
    actionDownloadsRemove me.receiver
    
  case getLocalizedString("Browse All Selected Hosts", "ContextualMenu")
    j = me.receiver.listCount - 1
    
    for i = 0 to j
      if me.receiver.selected(i) then addBrowseHostFromDownloads i, items()
    next
    
    j = ubound(items)
    
    for i = 0 to j
      me.CQueryController1.handleQueryBrowse items(i)
    next
    
  else //* browse one selected host *//
    me.CQueryController1.handleQueryBrowse _
        item.replaceb(getLocalizedStringWithStringData("Browse %@", "ContextualMenu", ""), "")
    
  end
  
End Sub

CActionsController.addBrowseHostFromDownloads:
Protected Sub addBrowseHostFromDownloads(index as integer, byref items() as string)
  
  dim i, j as integer
  dim elements(-1) as string = _
      me.CDownloadsController1.getDownloadHosts(index).split(",")
  
  j = ubound(elements) - 1
  
  for i = 0 to j
    
    if items.indexOf(elements(i)) = -1 and _
        me.CQueryController1.hasQueryString(elements(i)) = false then _
        items.append elements(i)
    
  next
  
  items.sort
  
End Sub

CActionsController.addBrowseHostFromUploads:
Protected Sub addBrowseHostFromUploads(index as integer, byref items() as string)
  
  dim element as string = me.CUploadsController1.getUploadIPAndPort(index)
  
  if element.lenB <> 0 and _
      items.indexOf(element) = -1 and _
      me.CQueryController1.hasQueryString(element) = false then _
      items.append element
  
  items.sort
  
End Sub

CActionsController.actionUploads:
Protected Sub actionUploads(item as string)
  
  dim fi(1) as folderItem
  dim path, items(-1) as string
  dim i, j as integer
  
  select case item
    
  case getLocalizedString("Open", "ContextualMenu")
    actionUploadsOpen me.receiver
    
  case getLocalizedString("Open With...", "ContextualMenu")
    path = me.CUploadsController1.getTransferPath(me.receiver.listIndex)
    
    if path.lenB <> 0 then _
        fi(0) = getPath2FolderItem(path)
    
    fi(1) = getOpenFolderItem("application/executable")
    
    if fi(0) <> nil and fi(0).exists and fi(1) <> nil and fi(1).exists then _
        fi(0).openWith(fi(1))
    
  case getLocalizedString("Reveal in Finder", "ContextualMenu")
    actionUploadsRevealInFinder me.receiver
    
  case getLocalizedString("Clear All Completed", "ContextualMenu")
    for i = me.receiver.listCount - 1 downto 0
      
      if me.CUploadsController1.isCompletedTransferItem(i) then _
          me.CUploadsController1.remove(i)
      
    next
    
    me.CUploadsController1.statsUpdated
    
  case getLocalizedString("Remove", "ContextualMenu")
    actionUploadsRemove me.receiver
    
  case getLocalizedString("Remove All", "ContextualMenu")
    me.receiver.selectAll
    actionUploadsRemove me.receiver
    
  case getLocalizedString("Browse All Selected Hosts", "ContextualMenu")
    j = me.receiver.listCount - 1
    
    for i = 0 to j
      
      if me.receiver.selected(i) then _
          addBrowseHostFromUploads i, items()
      
    next
    
    j = ubound(items)
    
    for i = 0 to j
      
      me.CQueryController1.handleQueryBrowse items(i)
      
    next
    
  else //* browse one selected host *//
    me.CQueryController1.handleQueryBrowse _
        item.replaceb(getLocalizedStringWithStringData("Browse %@", "ContextualMenu", ""), "")
    
  end
  
End Sub

CActionsController.actionDownloadsRevealInFinder:
Sub actionDownloadsRevealInFinder(targetListBox as CListBox)
  
  me.CDownloadsController1.getTransferPath(targetListBox.listIndex).revealInFinder
  
End Sub

CActionsController.actionDownloadsOpen:
Sub actionDownloadsOpen(targetListBox as CListBox)
  
  if kAqWarnOpening = false or me.CDownloadsController1.isCompletedTransferItem(targetListBox.listIndex) or askOpening then _
      me.CDownloadsController1.getTransferPath(targetListBox.listIndex).open
  
End Sub

CActionsController.actionDownloadsRemove:
Sub actionDownloadsRemove(targetListBox as CListBox)
  
  dim i as integer
  dim hasActiveTransfers as boolean
  
  for i = targetListBox.listCount - 1 downto 0
    
    if targetListBox.selected(i) and _
        me.CDownloadsController1.isCompletedTransferItem(i) = false then
      hasActiveTransfers = true
      exit
      
    end
    
  next
  
  if kAqWarnDownloads and hasActiveTransfers and askRemoving = false then return
  
  for i = targetListBox.listCount - 1 downto 0
    
    if targetListBox.selected(i) then
      if me.CDownloadsController1.isCompletedTransferItem(i) then
        me.CDownloadsController1.remove(i)
        
      elseif me.CDownloadsController1.setCanceled(i) then
        me.CCoreController1.sendCommand "cancelDownload|" + me.CDownloadsController1.getTransferHashCode(i)
        
      end
      
    end
    
  next
  
  me.CDownloadsController1.statsUpdated
  
End Sub

CActionsController.actionNetworkRemove:
Sub actionNetworkRemove(targetListBox as CListBox)
  
  dim i as integer
  
  for i = targetListBox.listCount - 1 downto 0
    
    if targetListBox.selected(i) then _
        me.CCoreController1.sendCommand "closeConnection|" + me.CNetworkController1.getHostAndPort(i).replace(":", "|")
    
  next
  
End Sub

CActionsController.openDownloadsMenu:
Sub openDownloadsMenu(sender as CStatsListBox, item as string)
  
  dim i, j as integer
  dim items(-1) as string
  
  try
    me.actionType = 5 //* downloads *//
    me.receiver = sender
    me.receiver.setFocus
    
    select case item
      
    case getLocalizedString("Browse", "Toolbar")
      j = me.receiver.listCount - 1
      
      for i = 0 to j
        
        if me.receiver.selected(i) then _
            addBrowseHostFromDownloads i, items()
        
      next
      
      j = ubound(items)
      
      for i = 0 to j
        
        me.addRow getLocalizedStringWithStringData("Browse %@", "ContextualMenu", items(i))
        
      next
      
      if j > 0 then
        me.addSeparator
        me.addRow getLocalizedString("Browse All Selected Hosts", "ContextualMenu")
        
      end
      
      if j <> -1 then
        me.open
        me.deleteAllRows
        
      end
      
    case getLocalizedString("Remove", "Toolbar")
      if me.receiver.selCount <> 0 then _
          actionDownloads getLocalizedString("Remove", "ContextualMenu")
      
    case getLocalizedString("Clear", "Toolbar")
      actionDownloads getLocalizedString("Clear All Completed", "ContextualMenu")
      
    case getLocalizedString("Reveal", "Toolbar")
      if me.receiver.selCount = 1 then _
          actionDownloads getLocalizedString("Reveal in Finder", "ContextualMenu")
      
    case getLocalizedString("Resume", "Toolbar")
      if me.receiver.selCount > 0 then _
          actionDownloads getLocalizedString("Resume", "ContextualMenu")
      
    case getLocalizedString("Pause", "Toolbar")
      if me.receiver.selCount > 0 then _
          actionDownloads getLocalizedString("Pause", "ContextualMenu")
      
    end
    
  catch
    
  finally
    me.actionType = 0 //* initialize *//
    me.receiver = nil
    
  end
  
End Sub

CActionsController.openNetworkMenu:
Sub openNetworkMenu(sender as CStatsListBox, item as string)
  
  dim i, j as integer
  dim items(-1) as string
  
  try
    me.actionType = 2 //* network *//
    me.receiver = sender
    me.receiver.setFocus
    
    select case item
      
    case getLocalizedString("Browse", "Toolbar")
      if me.receiver.selcount > 0 then
        j = me.receiver.listCount - 1
        
        for i = 0 to j
          
          if me.receiver.selected(i) then _
              addBrowseHostFromNetwork i, items()
          
        next
        
        j = ubound(items)
        
        for i = 0 to j
          
          me.addRow getLocalizedStringWithStringData("Browse %@", "ContextualMenu", items(i))
          
        next
        
        if j > 0 then
          me.addSeparator
          me.addRow getLocalizedString("Browse All Selected Hosts", "ContextualMenu")
          
        end
        
        if j <> -1 then
          me.open
          me.deleteAllRows
          
        end
        
      end
      
    case getLocalizedString("Remove", "Toolbar")
      if me.receiver.selcount > 0 then _
          actionNetwork getLocalizedString("Remove", "ContextualMenu")
      
    end
    
  catch
    
  finally
    me.actionType = 0 //* initialize *//
    me.receiver = nil
    
  end
  
End Sub

CActionsController.openResponseMenu:
Sub openResponseMenu(sender as CStatsListBox, item as string)
  
  dim i, j as integer
  dim items(-1) as string
  
  try
    me.actionType = 4 //* query results *//
    me.receiver = sender
    me.receiver.setFocus
    
    select case item
      
    case getLocalizedString("Browse", "Toolbar")
      if me.receiver.selCount > 0 then
        j = me.receiver.listCount - 1
        
        for i = 0 to j
          
          if me.receiver.selected(i) then addBrowseHostFromResponse(i, items())
          
        next
        
        j = ubound(items)
        
        for i = 0 to j
          
          me.addRow getLocalizedStringWithStringData("Browse %@", "ContextualMenu", items(i))
          
        next
        
        if j > 0 then
          me.addSeparator
          me.addRow getLocalizedString("Browse All Selected Hosts", "ContextualMenu")
          
        end
        
        if j <> -1 then
          me.open
          me.deleteAllRows
          
        end
        
      end
      
    case getLocalizedString("Download", "Toolbar")
      if me.receiver.selCount > 0 then _
          actionResponse getLocalizedString("Download", "ContextualMenu")
      
    case getLocalizedString("Filter", "Toolbar")
      me.actionResponseFilterResults
      
    end
    
  catch
    
  finally
    me.actionType = 0 //* initialize *//
    me.receiver = nil
    
  end
  
End Sub

CActionsController.openUploadsMenu:
Sub openUploadsMenu(sender as CStatsListBox, item as string)
  
  dim i, j as integer
  dim items(-1) as string
  
  try
    me.actionType = 6 //* uploads *//
    me.receiver = sender
    me.receiver.setFocus
    
    select case item
      
    case getLocalizedString("Browse", "Toolbar")
      j = me.receiver.listCount - 1
      
      for i = 0 to j
        
        if me.receiver.selected(i) then _
            addBrowseHostFromUploads i, items()
        
      next
      
      j = ubound(items)
      
      for i = 0 to j
        
        me.addRow getLocalizedStringWithStringData("Browse %@", "ContextualMenu", items(i))
        
      next
      
      if j > 0 then
        me.addSeparator
        me.addRow getLocalizedString("Browse All Selected Hosts", "ContextualMenu")
        
      end
      
      if j <> -1 then
        me.open
        me.deleteAllRows
        
      end
      
    case getLocalizedString("Remove", "Toolbar")
      if me.receiver.selCount > 0 then _
          actionUploads getLocalizedString("Remove", "ContextualMenu")
      
    case getLocalizedString("Clear", "Toolbar")
      actionUploads getLocalizedString("Clear All Completed", "ContextualMenu")
      
    case getLocalizedString("Reveal", "Toolbar")
      if me.receiver.selCount = 1 then _
          actionUploads getLocalizedString("Reveal in Finder", "ContextualMenu")
      
    end
    
  catch
    
  finally
    me.actionType = 0 //* initialize *//
    me.receiver = nil
    
  end
  
End Sub

CActionsController.actionSidebarRemove:
Sub actionSidebarRemove(targetListBox as CStatsListBox)
  
  dim i as integer
  
  for i = targetListBox.listCount - 1 downto 0
    
    if targetListBox.selected(i) then _
        me.CQueryController1.removeQuery CStatsModel(targetListBox.dataSource(i)).getRepresentation
    
  next
  
  targetListBox.listIndex = -1
  
End Sub

CActionsController.Initialize:
Sub Initialize(core as CCoreController, query as CQueryController, filter as CFilterController, network as CNetworkController, downloads as CDownloadsController, uploads as CUploadsController)
  
  me.CCoreController1 = core
  me.CQueryController1 = query
  me.CFilterController1 = filter
  me.CNetworkController1 = network
  me.CDownloadsController1 = downloads
  me.CUploadsController1 = uploads
  
End Sub

CActionsController.addBrowseHostFromNetwork:
Protected Sub addBrowseHostFromNetwork(index as integer, byref items() as string)
  
  dim browseHost as string = me.CNetworkController1.getHostAndPort(index)
  
  if items.indexOf(browseHost) = -1 and _
      me.CQueryController1.hasQueryString(browseHost) = false then _
      items.append browseHost
  
  items.sort
  
End Sub

CActionsController.actionUploadsRevealInFinder:
Sub actionUploadsRevealInFinder(targetListBox as CListBox)
  
  me.CUploadsController1.getTransferPath(targetListBox.listIndex).revealInFinder
  
End Sub

CActionsController.actionUploadsRemove:
Sub actionUploadsRemove(targetListBox as CListBox)
  
  dim i as integer
  
  for i = targetListBox.listCount - 1 downto 0
    
    if targetListBox.selected(i) then
      
      if me.CUploadsController1.isCompletedTransferItem(i) then
        me.CUploadsController1.remove(i)
        
      elseif me.CUploadsController1.setCanceled(i) then
        me.CCoreController1.sendCommand "cancelUpload|" + me.CUploadsController1.getTransferHashCode(i)
        
      end
      
    end
    
  next
  
  me.CUploadsController1.statsUpdated
  
End Sub

CActionsController.actionUploadsOpen:
Sub actionUploadsOpen(targetListBox as CListBox)
  
  me.CUploadsController1.getTransferPath(targetListBox.listIndex).open
  
End Sub

CActionsController.actionResponseSpam:
Sub actionResponseSpam(targetListBox as CListBox)
  
  dim i, j as integer
  
  j = targetListBox.listCount - 1
  
  for i = 0 to j
    
    if targetListBox.selected(i) then
      me.CCoreController1.sendCommand "addSpamFiles|" + me.CQueryController1.getLocalIndexes(i)
      me.CQueryController1.setQuerySpam(i, true)
      
    end
    
  next
  
  me.CCoreController1.sendCommand "applyFilterSettings"
  me.CFilterController1.filterResults
  
End Sub

CActionsController.actionResponseFilterResults:
Sub actionResponseFilterResults()
  me.CFilterController1.toggleFilterEnabled
  me.CFilterController1.filterResults
  me.CFilterController1.updateFilter
End Sub

CActionsController.Action:
Sub Action(item As String)
  
  try
    select case me.actionType
      
    case 1 //* heading *//
      actionHeading item
      
    case 2 //* network *//
      actionNetwork item
      
    case 3 //* sidebar *//
      actionSidebar item
      
    case 4 //* query results *//
      actionResponse item
      
    case 5 //* downloads *//
      actionDownloads item
      
    case 6 //* uploads *//
      actionUploads item
      
    end
    
  catch
    
  end
  
End Sub

CNetworkController.connectionClosed:
Sub connectionClosed(args() as string)
  
  if ubound(args) <> 1 then return
  
  dim address as string = args(1)
  
  if me.representedInfos.hasKey(address) = false then return
  
  dim infoArray as integer = me.representedInfos.value(address)
  
  me.remove infoArray
  
  me.flush
  updateCell me.representedInfos.count
  
End Sub

CNetworkController.statsUpdated:
Sub statsUpdated()
  
  dim i as integer
  
  for i = ubound(me.representedObjects) downto 0
    
    CNetworkModel(me.representedObjects(i)).invalidateValues
    
  next
  
  me.flush
  
End Sub

CNetworkController.getHostAndPort:
Function getHostAndPort(index as integer) As string
  
  return CNetworkModel(me.representedObjects(index)).address
  
End Function

CNetworkController.flush:
Sub flush()
  
  updateDataSource me.representedObjects
  
End Sub

CNetworkController.getStringColumns:
Protected Sub getStringColumns(byref column as integer, byref temp1() as string, byref temp2() as string, byref temp3() as CStatsModel)
  
  dim c as CStatsModel
  
  select case column
    
  case 0 //* address *//
    for each c in me.representedObjects
      
      temp1.append CNetworkModel(c).address
      temp2.append CNetworkModel(c).address
      temp3.append c
      
    next
    
  case 1 //* agent *//
    for each c in me.representedObjects
      
      temp1.append CNetworkModel(c).agent
      temp2.append CNetworkModel(c).agent
      temp3.append c
      
    next
    
  case 2 //* language *//
    for each c in me.representedObjects
      
      temp1.append CNetworkModel(c).language
      temp2.append CNetworkModel(c).language
      temp3.append c
      
    next
    
  case 3 //* type *//
    for each c in me.representedObjects
      
      temp1.append CNetworkModel(c).type
      temp2.append CNetworkModel(c).type
      temp3.append c
      
    next
    
  end
  
End Sub

CNetworkController.getNumericColumns:
Protected Sub getNumericColumns(byref column as integer, byref temp1() as double, byref temp2() as double, byref temp3() as CStatsModel)
  
  dim c as CStatsModel
  
  for each c in me.representedObjects
    
    temp1.append CNetworkModel(c).uptime
    temp2.append CNetworkModel(c).uptime
    temp3.append c
    
  next
  
End Sub

CNetworkController.isNumericColumn:
Protected Function isNumericColumn(column as integer) As boolean
  
  return column = 4
  
End Function

CNetworkController.connectionInitialized:
Sub connectionInitialized(args() as string)
  
  if ubound(args) <> 4 then return
  
  if me.representedInfos.hasKey(args(1)) then return
  
  dim c as new CNetworkModel(args)
  
  me.representedObjects.append c
  me.representedInfos.value(c.getRepresentation) = ubound(me.representedObjects)
  
  me.flush
  updateCell me.representedInfos.count
  
End Sub

CPreferencesController.Constructor:
Sub Constructor()
  
  kAqImportMusicFile = 0
  kAqAdultFilter = false
  kAqAllowFreeloaders = true
  kAqAutoClearDownloads = false
  kAqAutoClearUploads = true
  kAqBounceDockIcon = true
  kAqCompleteFileSharing = true
  kAqConcurrentDownloads = 5
  kAqConnectionSpeed = 350
  kAqDeleteAfterImport = false
  kAqDownstreamLimit = 100
  kAqEnableUltrapeer = true
  kAqExistingFileMatching = true
  kAqID3Title = true
  kAqIncompletePurgeTime = 7
  redim kAqIPFilterIPs(-1)
  kAqKbFileSize = false
  kAqLengthFilter = false
  kAqLengthFilterCharacters = 180
  kAqLocale = true
  kAqMaxUploads = 15
  kAqMaxUploadsPerPerson = 3
  kAqMoveMovies = false
  kAqMoveMoviesLocation = ""
  kAqMoveMusic = false
  kAqMoveMusicLocation = ""
  kAqMovePictures = false
  kAqMovePicturesLocation = ""
  redim kAqKeywordFilterKeywords(-1)
  kAqNetBandwidth = true
  kAqPartialFileSharing = true
  kAqPlaySong = 0
  kAqPort = 6346
  kAqPositiveFilter = false
  kAqPreferLocale = ""
  kAqProxyPassword = ""
  kAqProxyPort = 0
  kAqProxyPrivate = false
  kAqProxyRequiresAuthentication = false
  kAqProxyServer = ""
  kAqProxyType = 1
  kAqProxyUsername = ""
  kAqSaveDirectory = ""
  redim kAqSharedDirectories(-1)
  kAqSidebarTextFont = kTextFont
  kAqSidebarTextSize = kMiddleTextSize
  kAqSizeFilter = false
  kAqSizeFilterKilobytes = 256
  kAqSpamFilter = true
  kAqStandardTextFont = kTextFont
  kAqStandardTextSize = kSmallTextSize
  kAqTexturedWindow = true
  kAqUPnPType = 0
  kAqUpstreamLimit = 100
  kAqUseProxy = false
  kAqWarnDownloads = true
  kAqWarnOpening = true
  kAqWarnQuit = true
  
  kAqImportMusicFile = defaultsRead("kAqImportMusicFile", kAqImportMusicFile)
  kAqAdultFilter = defaultsRead("kAqAdultFilter", kAqAdultFilter)
  kAqAllowFreeloaders = defaultsRead("kAqAllowFreeloaders", kAqAllowFreeloaders)
  kAqAutoClearDownloads = defaultsRead("kAqAutoClearDownloads", kAqAutoClearDownloads)
  kAqAutoClearUploads = defaultsRead("kAqAutoClearUploads", kAqAutoClearUploads)
  kAqBounceDockIcon = defaultsRead("kAqBounceDockIcon", kAqBounceDockIcon)
  kAqCompleteFileSharing = defaultsRead("kAqCompleteFileSharing", kAqCompleteFileSharing)
  kAqConcurrentDownloads = defaultsRead("kAqConcurrentDownloads", kAqConcurrentDownloads)
  kAqConnectionSpeed = defaultsRead("kAqConnectionSpeed", kAqConnectionSpeed)
  kAqDeleteAfterImport = defaultsRead("kAqDeleteAfterImport", kAqDeleteAfterImport)
  kAqDownstreamLimit = defaultsRead("kAqDownstreamLimit", kAqDownstreamLimit)
  kAqEnableUltrapeer = defaultsRead("kAqEnableUltrapeer", kAqEnableUltrapeer)
  kAqExistingFileMatching = defaultsRead("kAqExistingFileMatching", kAqExistingFileMatching)
  kAqID3Title = defaultsRead("kAqID3Title", kAqID3Title)
  kAqIncompletePurgeTime = defaultsRead("kAqIncompletePurgeTime", kAqIncompletePurgeTime)
  kAqIPFilterIPs = defaultsReadArrayString("kAqIPFilterIPs", kAqIPFilterIPs)
  kAqKbFileSize = defaultsRead("kAqKbFileSize", kAqKbFileSize)
  kAqLengthFilter = defaultsRead("kAqLengthFilter", kAqLengthFilter)
  kAqLengthFilterCharacters = defaultsRead("kAqLengthFilterCharacters", kAqLengthFilterCharacters)
  kAqLocale = defaultsRead("kAqLocale", kAqLocale)
  kAqMaxUploads = defaultsRead("kAqMaxUploads", kAqMaxUploads)
  kAqMaxUploadsPerPerson = defaultsRead("kAqMaxUploadsPerPerson", kAqMaxUploadsPerPerson)
  kAqMoveMovies = defaultsRead("kAqMoveMovies", kAqMoveMovies)
  kAqMoveMoviesLocation = defaultsRead("kAqMoveMoviesLocation", kAqMoveMoviesLocation)
  kAqMoveMusic = defaultsRead("kAqMoveMusic", kAqMoveMusic)
  kAqMoveMusicLocation = defaultsRead("kAqMoveMusicLocation", kAqMoveMusicLocation)
  kAqMovePictures = defaultsRead("kAqMovePictures", kAqMovePictures)
  kAqMovePicturesLocation = defaultsRead("kAqMovePicturesLocation", kAqMovePicturesLocation)
  kAqKeywordFilterKeywords = defaultsReadArrayString("kAqKeywordFilterKeywords", kAqKeywordFilterKeywords)
  kAqNetBandwidth = defaultsRead("kAqNetBandwidth", kAqNetBandwidth)
  kAqPartialFileSharing = defaultsRead("kAqPartialFileSharing", kAqPartialFileSharing)
  kAqPlaySong = defaultsRead("kAqPlaySong", kAqPlaySong)
  kAqPort = defaultsRead("kAqPort", kAqPort)
  kAqPositiveFilter = defaultsRead("kAqPositiveFilter", kAqPositiveFilter)
  kAqPreferLocale = defaultsRead("kAqPreferLocale", kAqPreferLocale)
  kAqProxyPassword = defaultsRead("kAqProxyPassword", kAqProxyPassword)
  kAqProxyPort = defaultsRead("kAqProxyPort", kAqProxyPort)
  kAqProxyPrivate = defaultsRead("kAqProxyPrivate", kAqProxyPrivate)
  kAqProxyRequiresAuthentication = defaultsRead("kAqProxyRequiresAuthentication", kAqProxyRequiresAuthentication)
  kAqProxyServer = defaultsRead("kAqProxyServer", kAqProxyServer)
  kAqProxyType = defaultsRead("kAqProxyType", kAqProxyType)
  kAqProxyUsername = defaultsRead("kAqProxyUsername", kAqProxyUsername)
  kAqSaveDirectory = defaultsRead("kAqSaveDirectory", kAqSaveDirectory)
  kAqSharedDirectories = defaultsReadArrayString("kAqSharedDirectories", kAqSharedDirectories)
  kAqSidebarTextFont = defaultsRead("kAqSidebarTextFont", kAqSidebarTextFont)
  kAqSidebarTextSize = defaultsRead("kAqSidebarTextSize", kAqSidebarTextSize)
  kAqSizeFilter = defaultsRead("kAqSizeFilter", kAqSizeFilter)
  kAqSizeFilterKilobytes = defaultsRead("kAqSizeFilterKilobytes", kAqSizeFilterKilobytes)
  kAqSpamFilter = defaultsRead("kAqSpamFilter", kAqSpamFilter)
  kAqStandardTextFont = defaultsRead("kAqStandardTextFont", kAqStandardTextFont)
  kAqStandardTextSize = defaultsRead("kAqStandardTextSize", kAqStandardTextSize)
  kAqTexturedWindow = defaultsRead("kAqTexturedWindow", kAqTexturedWindow)
  kAqUPnPType = defaultsRead("kAqUPnPType", kAqUPnPType)
  kAqUpstreamLimit = defaultsRead("kAqUpstreamLimit", kAqUpstreamLimit)
  kAqUseProxy = defaultsRead("kAqUseProxy", kAqUseProxy)
  kAqWarnDownloads = defaultsRead("kAqWarnDownloads", kAqWarnDownloads)
  kAqWarnOpening = defaultsRead("kAqWarnOpening", kAqWarnOpening)
  kAqWarnQuit = defaultsRead("kAqWarnQuit", kAqWarnQuit)
  
  if targetLeopard then
    kAqTexturedWindow = false
  end
  
  dim f as folderItem
  
  if kAqSaveDirectory.lenb <> 0 then f = getPath2FolderItem(kAqSaveDirectory)
  
  if f <> nil and f.exists then return
  
  try
    #if targetMachO
      f = DocumentsFolder.parent.child("Downloads")
      
    #elseif targetCarbon
      f = DocumentsFolder.child("Downloads")
      
    #elseif targetWin32
      f = DocumentsFolder.fixRbBug.child("Downloads")
      
    #elseif targetLinux
      f = DocumentsFolder.child("Downloads").fixRbBug
      
    #endif
    
    kAqSaveDirectory = f.posixPath
    
  catch
    
  end
  
  if ubound(kAqSharedDirectories) = -1 and f <> nil then _
      kAqSharedDirectories.append kAqSaveDirectory
  
End Sub

CPreferencesController.Destructor:
Sub Destructor()
  
  defaultsWrite "kAqImportMusicFile", kAqImportMusicFile
  defaultsWrite "kAqAdultFilter", kAqAdultFilter
  defaultsWrite "kAqAllowFreeloaders", kAqAllowFreeloaders
  defaultsWrite "kAqAutoClearDownloads", kAqAutoClearDownloads
  defaultsWrite "kAqAutoClearUploads", kAqAutoClearUploads
  defaultsWrite "kAqBounceDockIcon", kAqBounceDockIcon
  defaultsWrite "kAqCompleteFileSharing", kAqCompleteFileSharing
  defaultsWrite "kAqConcurrentDownloads", kAqConcurrentDownloads
  defaultsWrite "kAqConnectionSpeed", kAqConnectionSpeed
  defaultsWrite "kAqDeleteAfterImport", kAqDeleteAfterImport
  defaultsWrite "kAqDownstreamLimit", kAqDownstreamLimit
  defaultsWrite "kAqEnableUltrapeer", kAqEnableUltrapeer
  defaultsWrite "kAqExistingFileMatching", kAqExistingFileMatching
  defaultsWrite "kAqID3Title", kAqID3Title
  defaultsWrite "kAqIncompletePurgeTime", kAqIncompletePurgeTime
  defaultsWriteArrayString "kAqIPFilterIPs", kAqIPFilterIPs
  defaultsWrite "kAqKbFileSize", kAqKbFileSize
  defaultsWrite "kAqLengthFilter", kAqLengthFilter
  defaultsWrite "kAqLengthFilterCharacters", kAqLengthFilterCharacters
  defaultsWrite "kAqLocale", kAqLocale
  defaultsWrite "kAqMaxUploads", kAqMaxUploads
  defaultsWrite "kAqMaxUploadsPerPerson", kAqMaxUploadsPerPerson
  defaultsWrite "kAqMoveMovies", kAqMoveMovies
  defaultsWrite "kAqMoveMoviesLocation", kAqMoveMoviesLocation
  defaultsWrite "kAqMoveMusic", kAqMoveMusic
  defaultsWrite "kAqMoveMusicLocation", kAqMoveMusicLocation
  defaultsWrite "kAqMovePictures", kAqMovePictures
  defaultsWrite "kAqMovePicturesLocation", kAqMovePicturesLocation
  defaultsWriteArrayString "kAqKeywordFilterKeywords", kAqKeywordFilterKeywords
  defaultsWrite "kAqNetBandwidth", kAqNetBandwidth
  defaultsWrite "kAqPartialFileSharing", kAqPartialFileSharing
  defaultsWrite "kAqPlaySong", kAqPlaySong
  defaultsWrite "kAqPort", kAqPort
  defaultsWrite "kAqPositiveFilter", kAqPositiveFilter
  defaultsWrite "kAqPreferLocale", kAqPreferLocale
  defaultsWrite "kAqProxyPassword", kAqProxyPassword
  defaultsWrite "kAqProxyPort", kAqProxyPort
  defaultsWrite "kAqProxyPrivate", kAqProxyPrivate
  defaultsWrite "kAqProxyRequiresAuthentication", kAqProxyRequiresAuthentication
  defaultsWrite "kAqProxyServer", kAqProxyServer
  defaultsWrite "kAqProxyType", kAqProxyType
  defaultsWrite "kAqProxyUsername", kAqProxyUsername
  defaultsWrite "kAqSaveDirectory", kAqSaveDirectory
  defaultsWriteArrayString "kAqSharedDirectories", kAqSharedDirectories
  defaultsWrite "kAqSidebarTextFont", kAqSidebarTextFont
  defaultsWrite "kAqSidebarTextSize", kAqSidebarTextSize
  defaultsWrite "kAqSpamFilter", kAqSpamFilter
  defaultsWrite "kAqSizeFilter", kAqSizeFilter
  defaultsWrite "kAqSizeFilterKilobytes", kAqSizeFilterKilobytes
  defaultsWrite "kAqStandardTextFont", kAqStandardTextFont
  defaultsWrite "kAqStandardTextSize", kAqStandardTextSize
  defaultsWrite "kAqTexturedWindow", kAqTexturedWindow
  defaultsWrite "kAqUPnPType", kAqUPnPType
  defaultsWrite "kAqUpstreamLimit", kAqUpstreamLimit
  defaultsWrite "kAqUseProxy", kAqUseProxy
  defaultsWrite "kAqWarnDownloads", kAqWarnDownloads
  defaultsWrite "kAqWarnOpening", kAqWarnOpening
  defaultsWrite "kAqWarnQuit", kAqWarnQuit
  
End Sub

CPreferencesActionsController.openPreferencesMenu:
Sub openPreferencesMenu(sender as CHierarchicalListBox, row as integer, column as integer, defaults as string, d as Dictionary)
  
  dim i, j as integer
  dim items(-1) as string
  
  try
    me.receiver = sender
    me.row = row
    me.column = column
    me.defaults = defaults
    me.d = d
    
    j = me.d.count - 1
    
    for i = 0 to j
      
      if me.d.key(i).type = 8 and me.d.key(i) = "currentKey" then
        //
        
      elseif items.indexOf(me.d.value(me.d.key(i))) = -1 then
        items.append me.d.value(me.d.key(i))
        me.addRow me.d.value(me.d.key(i))
        
      end
      
    next
    
    me.open
    
  catch
    
  finally
    me.deleteAllRows
    me.receiver = nil
    me.row = 0
    me.column = 0
    me.defaults = ""
    me.d = nil
    
  end
  
End Sub

CPreferencesActionsController.Action:
Sub Action(item As String)
  
  dim f as folderItem
  dim i as integer
  dim s as string
  
  select case item
    
  case getLocalizedString("Clear Spam History", "Preferences")
    sendCommand "clearSpamFiles"
    
  case getLocalizedString("Add Keyword...", "Preferences")
    kAqKeywordFilterKeywords.insert 0, ""
    me.receiver.expanded(1) = false
    me.receiver.expanded(1) = true
    me.receiver.editCell(me.row + 1, me.column)
    
  case getLocalizedString("Add IP Address...", "Preferences")
    kAqIPFilterIPs.insert 0, ""
    me.receiver.expanded(7) = false
    me.receiver.expanded(7) = true
    me.receiver.editCell(me.row + 1, me.column)
    
  case getLocalizedString("Add Folder...", "Preferences")
    f = selectFolder
    
    if f <> nil and kAqSharedDirectories.indexOf(f.posixPath) = -1 then
      kAqSharedDirectories.append f.posixPath
      me.receiver.valueChanged me.row, me.column
      me.receiver.expanded(5) = false
      me.receiver.expanded(5) = true
      
    end
    
  case getLocalizedString("Remove", "Preferences")
    if me.defaults = "kAqSharedDirectories" then
      s = me.d.value("currentKey")
      
      if s <> "" and kAqSharedDirectories.indexOf(s) <> -1 then
        kAqSharedDirectories.remove kAqSharedDirectories.indexOf(s)
        me.receiver.valueChanged me.row, me.column
        me.receiver.removeRow me.row
        
      end
      
    elseif me.defaults = "kAqKeywordFilterKeywords" then
      s = me.d.value("currentKey")
      
      if kAqKeywordFilterKeywords.indexOf(s) <> -1 then
        kAqKeywordFilterKeywords.remove kAqKeywordFilterKeywords.indexOf(s)
        me.receiver.cellTag(me.row, 1) = nil
        me.receiver.valueChanged me.row, me.column
        me.receiver.removeRow me.row
        
      end
      
    elseif me.defaults = "kAqIPFilterIPs" then
      s = me.d.value("currentKey")
      
      if kAqIPFilterIPs.indexOf(s) <> -1 then
        kAqIPFilterIPs.remove kAqIPFilterIPs.indexOf(s)
        me.receiver.cellTag(me.row, 1) = nil
        me.receiver.valueChanged me.row, me.column
        me.receiver.removeRow me.row
        
      end
      
    end
    
  case getLocalizedString("Other...", "Preferences")
    f = selectFolder
    
    if f <> nil then
      s = f.posixPath
      me.d.value(s) = s
      me.d.value("currentKey") = s
      me.receiver.cell(me.row, me.column) = s
      me.receiver.cellTag(me.row, me.column) = me.d
      me.receiver.valueChanged me.row, me.column
      
    end
    
  else
    if me.defaults = "kAqKeywordFilterKeywords" then
      me.receiver.editCell(me.row, me.column)
      
    elseif me.defaults = "kAqIPFilterIPs" then
      me.receiver.editCell(me.row, me.column)
      
    else
      for i = me.d.count - 1 downto 0
        
        if me.d.key(i).type = 8 and me.d.key(i) = "currentKey" then
          //
          
        elseif me.d.value(me.d.key(i)) = item then
          me.d.value("currentKey") = me.d.key(i)
          me.receiver.cell(me.row, me.column) = item
          me.receiver.cellTag(me.row, me.column) = me.d
          me.receiver.valueChanged me.row, me.column
          exit
          
        end
        
      next
      
    end
    
  end
  
End Sub

CQueryController.handleQuery:
Sub handleQuery(arg as String, selected as boolean, keepInSidebar as boolean)
  
  if arg.lenb = 0 or arg.instrb("|") <> 0 then
    beep
    return
    
  end
  
  dim oldIndex, arrayIndex as integer
  dim c as CQueryModel
  
  if me.queryStrings.haskey(arg) = false then
    //* create new query *//
    
    me.positiveQueryIndex = me.positiveQueryIndex + 1
    
    c = new CQueryModel(me.positiveQueryIndex, arg, new CFilterModel(me.getFilterModel), keepInSidebar)
    c.queryFilter.enabled = false
    c.positiveQueryIndexes.append c.queryIndex
    
    me.queries.value(c.queryIndex) = c
    me.queryStrings.value(c.queryString) = c.queryIndex
    
    me.representedObjects.append new CSidebarModel(c.queryString, c.queryIndex, 120)
    arrayIndex = ubound(me.representedObjects)
    me.representedInfos.value(c.queryIndex) = arrayIndex
    
  else
    //* overwrite existing query index *//
    
    me.positiveQueryIndex = me.positiveQueryIndex + 1
    
    oldIndex = me.queryStrings.value(arg)
    c = me.queries.value(oldIndex)
    
    me.queries.remove oldIndex
    me.queryStrings.remove c.queryString
    
    arrayIndex = me.representedInfos.value(c.queryIndex)
    me.representedInfos.remove c.queryIndex
    
    c.queryIndex = me.positiveQueryIndex
    c.positiveQueryIndexes.append c.queryIndex
    
    me.queries.value(c.queryIndex) = c
    me.queryStrings.value(c.queryString) = c.queryIndex
    
    CSidebarModel(me.representedObjects(arrayIndex)).overwriteStats c.queryIndex, 120
    me.representedInfos.value(c.queryIndex) = arrayIndex
    
    if me.currentIndex = oldIndex then me.currentIndex = c.queryIndex
    
  end
  
  updateCell me.representedObjects
  
  if selected then selectCell arrayIndex
  
  select case c.queryType
    
  case 0 //* what's new query *//
    me.CCoreController1.sendCommand "queryWhatIsNew"
    
  case 1 //* browse query *//
    me.CCoreController1.sendCommand "doBrowseHost|" + arg.replaceb(":", "|")
    
  case 2 //* find more sources query *//
    me.CCoreController1.sendCommand "queryFindMoreSources|" + c.queryString
    
  case 3 //* normal query *//
    me.CCoreController1.sendCommand "query|" + c.positiveFilterKeywords.join
    
  end
  
End Sub

CQueryController.handleQueryReply:
Sub handleQueryReply(args() as String)
  
  if ubound(args) <> 15 then return
  
  dim queryIndex as integer = args(1).val
  
  if me.queries.hasKey(queryIndex) = false then return
  
  dim query as CQueryModel = me.queries.value(queryIndex)
  
  //* keyword filtering *//
  
  dim keywords(-1) as string
  
  keywords = query.positiveFilterKeywords
  
  if kAqPositiveFilter and ubound(keywords) <> -1 and _
      args(7).lowercase.completeMatches(keywords) = false and _
      args(12).lowercase.completeMatches(keywords) = false and _
      args(13).lowercase.completeMatches(keywords) = false and _
      args(14).lowercase.completeMatches(keywords) = false then return
  
  keywords = query.negativeFilterKeywords
  
  if ubound(keywords) <> -1 and _
      ( args(7).lowercase.matches(keywords) or _
      args(12).lowercase.matches(keywords) or _
      args(13).lowercase.matches(keywords) or _
      args(14).lowercase.matches(keywords) ) then return
  
  //* filename length filtering *//
  
  if kAqLengthFilter and args(7).lenb >= kAqLengthFilterCharacters then return
  
  //* file size filtering *//
  
  if kAqSizeFilter and args(9).val / 1024 <= kAqSizeFilterKilobytes then return
  
  //* spam filtering *//
  
  if kAqSpamFilter and args(15).val = 1 then return
  
  //* response handling *//
  
  dim c as CResponseModel
  dim arrayIndex as integer
  
  try
    
    if query.response.representedInfos.hasKey(args(6)) = false then
      c = new CResponseModel(args)
      c.exists = me.CFileurnsController1.hasKey(c.sha1)
      c.marked = me.CDownloadsController1.hasMarkedDownloadItem(c.sha1)
      
      query.response.representedObjects.append c
      query.response.representedInfos.value(c.sha1) = ubound(query.response.representedObjects) //* create hash map *//
      
      arrayIndex = me.representedInfos.value(queryIndex)
      CSidebarModel(me.representedObjects(arrayIndex)).incrementStats _
          (me.currentIndex = queryIndex), _
          me.CFilterController1.isFilteredResponse(c, query.queryFilter)
      CSidebarModel(me.representedObjects(arrayIndex)).invalidateValues
      
    else
      arrayIndex = query.response.representedInfos.value(args(6))
      CResponseModel(query.response.representedObjects(arrayIndex)).addResponse args
      CResponseModel(query.response.representedObjects(arrayIndex)).invalidateValues
      
    end
    
    me.queries.value(queryIndex) = query
    
    if me.currentIndex = queryIndex then me.CFilterController1.setNeedsSort
    
  catch
    
  end
  
End Sub

CQueryController.handleQueryWhatIsNew:
Sub handleQueryWhatIsNew()
  
  handleQuery getLocalizedString("What's New?", "Misc"), true, true
  
End Sub

CQueryController.getQueryString:
Function getQueryString() As string
  
  if me.currentIndex <> -1 and me.queries.hasKey(me.currentIndex) then _
      return CQueryModel(me.queries.value(me.currentIndex)).queryString
  
End Function

CQueryController.stopQuery:
Sub stopQuery()
  
  if me.currentIndex <> -1 then stopQuery me.currentIndex
  
End Sub

CQueryController.startQuery:
Sub startQuery(selected as boolean)
  
  if me.currentIndex <> -1 then startQuery me.currentIndex, selected
  
End Sub

CQueryController.getResponseCount:
Function getResponseCount() As integer
  
  return me.getResponseCount(me.currentIndex)
  
End Function

CQueryController.removeQuery:
Sub removeQuery(index as integer)
  
  if me.queries.hasKey(index) = false then return
  
  if me.currentIndex = index then me.currentIndex = -1
  
  dim c as CQueryModel = me.queries.value(index)
  dim arrayIndex as integer
  
  me.queries.remove c.queryIndex
  me.queryStrings.remove c.queryString
  
  arrayIndex = me.representedInfos.value(c.queryIndex)
  me.representedObjects.remove arrayIndex
  me.representedInfos.remove c.queryIndex
  me.rehash
  
  updateCell me.representedObjects
  
  if ubound(c.positiveQueryIndexes) <> -1 then
    me.CCoreController1.sendCommand "clearAllResults|" + c.positiveQueryIndexes.join("|")
    me.CCoreController1.sendCommand "removeQuery|" + c.positiveQueryIndexes.join("|")
    
  end
  
End Sub

CQueryController.clearAllResults:
Sub clearAllResults(index as integer)
  
  if me.queries.hasKey(index) = false then return
  
  dim c as CQueryModel = me.queries.value(index)
  
  c.clearAllResults
  me.queries.value(index) = c
  
  if me.currentIndex = index then
    me.filteredQuery.clearAllResults
    me.flush
  end
  
  dim arrayIndex as integer = me.representedInfos.value(index)
  
  CSidebarModel(me.representedObjects(arrayIndex)).updateStats 0, 0
  CSidebarModel(me.representedObjects(arrayIndex)).invalidateValues
  
  updateCell me.representedObjects
  
  if ubound(c.positiveQueryIndexes) <> -1 then _
      me.CCoreController1.sendCommand "clearAllResults|" + c.positiveQueryIndexes.join("|")
  
End Sub

CQueryController.removeAllQueries:
Sub removeAllQueries()
  
  me.currentIndex = -1
  me.queries.clear
  me.queryStrings.clear
  redim me.representedObjects(-1)
  me.representedInfos.clear
  me.filteredQuery = new CQueryModel
  
  updateCell me.representedObjects
  
  me.CCoreController1.sendCommand "removeAllQueries"
  
End Sub

CQueryController.getResponseModel:
Function getResponseModel(listIndex as integer) As CResponseModel
  
  return CResponseModel(me.filteredQuery.response.representedObjects(listIndex))
  
End Function

CQueryController.Initialize:
Sub Initialize(core as CCoreController, filter as CFilterController, fileurns as CFileurnsController, downloads as CDownloadsController)
  
  me.CCoreController1 = core
  me.CFilterController1 = filter
  me.CFileurnsController1 = fileurns
  me.CDownloadsController1 = downloads
  
  dim queryString(-1), keyword(-1), columnWidths(-1) as string
  dim enabled(-1) as boolean
  dim media(-1), bitrate(-1), size(-1), sources(-1), speed(-1), sortColumn(-1), sortDirection(-1) as integer
  dim i, j as integer
  
  queryString = defaultsReadArrayString("kAqSearchControllerStringsKey", queryString)
  keyword = defaultsReadArrayString("kAqFilterControllerKeyword", keyword)
  enabled = defaultsReadArrayBoolean("kAqFilterControllerEnabled", enabled)
  media = defaultsReadArrayInteger("kAqFilterControllerMedia", media)
  bitrate = defaultsReadArrayInteger("kAqFilterControllerBitrate", bitrate)
  size = defaultsReadArrayInteger("kAqFilterControllerSize", size)
  sources = defaultsReadArrayInteger("kAqFilterControllerSources", sources)
  speed = defaultsReadArrayInteger("kAqFilterControllerSpeed", speed)
  sortColumn = defaultsReadArrayInteger("kAqFilterControllerSortColumn", sortColumn)
  sortDirection = defaultsReadArrayInteger("kAqFilterControllerSortDirection", sortDirection)
  columnWidths = defaultsReadArrayString("kAqFilterControllerColumnWidths", columnWidths)
  
  j = ubound(queryString)
  
  for i = 0 to j
    
    try
      handleQueryInitial queryString(i), _
          new CFilterModel( _
          keyword(i), enabled(i), media(i), bitrate(i), _
          size(i), sources(i), speed(i), _
          sortColumn(i), sortDirection(i), columnWidths(i) _
          )
      
    catch
      handleQueryInitial queryString(i), new CFilterModel
      
    end
    
  next
  
  updateCell me.representedObjects
  
End Sub

CQueryController.getQueryModel:
Function getQueryModel(index as integer) As CQueryModel
  
  if me.queries.hasKey(index) then return me.queries.value(index)
  
End Function

CQueryController.setCurrentIndex:
Sub setCurrentIndex(index as integer)
  
  me.currentIndex = index
  
End Sub

CQueryController.setQueryModel:
Sub setQueryModel(index as integer, query as CQueryModel)
  
  me.queries.value(index) = query
  
End Sub

CQueryController.startQuery:
Sub startQuery(index as integer, selected as boolean)
  
  if me.queries.hasKey(index) = false then return
  
  dim c as CQueryModel = me.queries.value(index)
  
  handleQuery c.queryString, selected, c.keepInSidebar
  
End Sub

CQueryController.stopQuery:
Sub stopQuery(index as integer)
  
  if me.queries.hasKey(index) = false then return
  
  dim c as CQueryModel = me.queries.value(index)
  dim arrayIndex as integer
  
  //* overwrite existing query index *//
  
  me.negativeQueryIndex = me.negativeQueryIndex - 1
  
  me.queries.remove c.queryIndex
  me.queryStrings.remove c.queryString
  
  arrayIndex = me.representedInfos.value(c.queryIndex)
  me.representedInfos.remove c.queryIndex
  
  c.queryIndex = me.negativeQueryIndex
  me.queries.value(c.queryIndex) = c
  me.queryStrings.value(c.queryString) = c.queryIndex
  
  CSidebarModel(me.representedObjects(arrayIndex)).overwriteStats c.queryIndex, -1
  me.representedInfos.value(c.queryIndex) = arrayIndex
  
  if me.currentIndex = index then me.currentIndex = c.queryIndex
  
  updateCell me.representedObjects
  
End Sub

CQueryController.Finalize:
Sub Finalize()
  
  dim i, j as integer
  dim queryString(-1), keyword(-1), columnWidths(-1) as string
  dim enabled(-1) as boolean
  dim media(-1), bitrate(-1), size(-1), sources(-1), speed(-1), sortColumn(-1), sortDirection(-1) as integer
  dim c as CQueryModel
  
  j = ubound(me.representedObjects)
  
  for i = 0 to j
    
    c = me.queries.value(CSidebarModel(me.representedObjects(i)).index)
    
    if c.keepInSidebar then
      queryString.append c.queryString
      keyword.append c.queryFilter.keyword
      enabled.append c.queryFilter.enabled
      media.append c.queryFilter.media
      bitrate.append c.queryFilter.bitrate
      size.append c.queryFilter.size
      sources.append c.queryFilter.sources
      speed.append c.queryFilter.speed
      sortColumn.append c.queryFilter.sortColumn
      sortDirection.append c.queryFilter.sortDirection
      columnWidths.append c.queryFilter.columnWidths
      
    end
    
  next
  
  defaultsWriteArrayString "kAqSearchControllerStringsKey", queryString
  defaultsWriteArrayString "kAqFilterControllerKeyword", keyword
  defaultsWriteArrayBoolean "kAqFilterControllerEnabled", enabled
  defaultsWriteArrayInteger "kAqFilterControllerMedia", media
  defaultsWriteArrayInteger "kAqFilterControllerBitrate", bitrate
  defaultsWriteArrayInteger "kAqFilterControllerSize", size
  defaultsWriteArrayInteger "kAqFilterControllerSources", sources
  defaultsWriteArrayInteger "kAqFilterControllerSpeed", speed
  defaultsWriteArrayInteger "kAqFilterControllerSortColumn", sortColumn
  defaultsWriteArrayInteger "kAqFilterControllerSortDirection", sortDirection
  defaultsWriteArrayString "kAqFilterControllerColumnWidths", columnWidths
  
End Sub

CQueryController.handleQueryInitial:
Sub handleQueryInitial(queryString as string, filter as CFilterModel)
  
  dim c as CQueryModel
  
  if me.queryStrings.haskey(queryString) = false then
    //* create new query *//
    
    me.negativeQueryIndex = me.negativeQueryIndex - 1
    
    c = new CQueryModel(me.negativeQueryIndex, queryString, filter, true)
    
    me.queries.value(c.queryIndex) = c
    me.queryStrings.value(c.queryString) = c.queryIndex
    me.representedObjects.append new CSidebarModel(c.queryString, c.queryIndex, -1)
    me.representedInfos.value(c.queryIndex) = ubound(me.representedObjects)
    
  end
  
End Sub

CQueryController.handleQueryBrowse:
Sub handleQueryBrowse(arg as string)
  
  handleQuery arg, false, false
  
End Sub

CQueryController.getCurrentIndex:
Function getCurrentIndex() As integer
  
  return me.currentIndex
  
End Function

CQueryController.clearAllResults:
Sub clearAllResults()
  
  if me.currentIndex <> -1 then _
      clearAllResults me.currentIndex
  
End Sub

CQueryController.removeQuery:
Sub removeQuery()
  
  if me.currentIndex <> -1 then removeQuery me.currentIndex
  
End Sub

CQueryController.setQueryMarked:
Sub setQueryMarked(arrayIndex as integer, value as boolean)
  
  dim c as CResponseModel = CResponseModel(me.filteredquery.response.representedObjects(arrayIndex))
  
  c.marked = value
  c.invalidateValues
  me.filteredquery.response.representedObjects(arrayIndex) = c
  
  dim sha1 as string = c.sha1
  
  if me.currentIndex <> -1 and _
      CQueryModel(me.queries.value(me.currentIndex)).response.representedInfos.hasKey(sha1) then
    arrayIndex = CQueryModel(me.queries.value(me.currentIndex)).response.representedInfos.value(sha1)
    CQueryModel(me.queries.value(me.currentIndex)).response.representedObjects(arrayIndex) = c
    
  end
  
End Sub

CQueryController.hasQueryModel:
Function hasQueryModel(index as integer) As boolean
  
  return me.queries.hasKey(index)
  
End Function

CQueryController.setFilteredQuery:
Sub setFilteredQuery(filteredQuery as CQueryModel)
  
  me.filteredQuery = filteredQuery
  me.flush
  
  dim arrayIndex as integer = me.representedInfos.value(me.currentIndex)
  
  CSidebarModel(me.representedObjects(arrayIndex)).updateStats me.getResponseCount, me.filteredQuery.response.representedInfos.count
  CSidebarModel(me.representedObjects(arrayIndex)).invalidateValues
  
  updateCell me.representedObjects
  
End Sub

CQueryController.hasQueryString:
Function hasQueryString(browseQueryString as string) As boolean
  
  return me.queryStrings.hasKey(browseQueryString)
  
End Function

CQueryController.getLocalIndexes:
Function getLocalIndexes(listIndex as integer) As string
  
  dim c as CResponseModel = CResponseModel(me.filteredquery.response.representedObjects(listIndex))
  
  dim i, j as integer
  dim results(-1) as string
  
  j = ubound(c.queryIndexes)
  
  //* download index *//
  
  for i = 0 to j
    
    results.append c.queryIndexes(i).stringValue + ":" + c.localIndexes(i).stringValue
    
  next
  
  return results.join("|")
  
End Function

CQueryController.Constructor:
Sub Constructor()
  
  super.Constructor
  
  me.queries = new DIctionary
  me.queryStrings = new Dictionary
  me.filteredQuery = new CQueryModel
  me.currentIndex = -1
  me.positiveQueryIndex = -1
  me.negativeQueryIndex = -1
  
End Sub

CQueryController.setFilterModel:
Sub setFilterModel(c as CFilterModel)
  
  if me.currentIndex <> -1 and me.queries.hasKey(me.currentIndex) then _
      CQueryModel(me.queries.value(me.currentIndex)).queryFilter = c
  
End Sub

CQueryController.getFilterModel:
Function getFilterModel() As CFilterModel
  
  if me.currentIndex <> -1 and me.queries.hasKey(me.currentIndex) then
    return CQueryModel(me.queries.value(me.currentIndex)).queryFilter
    
  else
    return me.CFilterController1.getFilterModel
    
  end
  
End Function

CQueryController.browseHostFailed:
Sub browseHostFailed(args() as string)
  
  if ubound(args) <> 1 then return
  
  dim queryIndex as integer = args(1).val
  
  if me.representedInfos.hasKey(queryIndex) = false then return
  
  dim c as CSidebarModel = CSidebarModel(me.representedObjects(me.representedInfos.value(queryIndex)))
  
  if me.getKeepInSidebar(c.index) = false and me.getResponseCount(c.index) = 0 then
    me.removeQuery c.index
  else
    me.stopQuery c.index
  end
  
End Sub

CQueryController.flush:
Sub flush()
  
  updateDataSource me.filteredQuery.response.representedObjects
  
End Sub

CQueryController.convertEncoding:
Sub convertEncoding(arrayIndex as integer, type as integer)
  
  dim sha1 as string
  dim c as CResponseModel = CResponseModel(me.filteredquery.response.representedObjects(arrayIndex))
  
  c.convertEncoding type
  c.invalidateValues
  me.filteredquery.response.representedObjects(arrayIndex) = c
  
  if me.currentIndex <> -1 and _
      CQueryModel(me.queries.value(me.currentIndex)).response.representedInfos.hasKey(c.sha1) then
    arrayIndex = CQueryModel(me.queries.value(me.currentIndex)).response.representedInfos.value(c.sha1)
    CQueryModel(me.queries.value(me.currentIndex)).response.representedObjects(arrayIndex) = c
    
  end
  
End Sub

CQueryController.getKeepInSidebar:
Function getKeepInSidebar(index as integer) As boolean
  
  if me.queries.hasKey(index) then return CQueryModel(me.queries.value(index)).keepInSidebar
  
End Function

CQueryController.setKeepInSidebar:
Sub setKeepInSidebar(index as integer, value as boolean)
  
  if me.queries.hasKey(index) then CQueryModel(me.queries.value(index)).keepInSidebar = value
  
End Sub

CQueryController.getResponseCount:
Function getResponseCount(index as integer) As integer
  
  if me.queries.hasKey(index) then _
      return CQueryModel(me.queries.value(index)).response.representedInfos.count
  
End Function

CQueryController.setSidebarHighlighted:
Sub setSidebarHighlighted(index as integer, value as boolean)
  
  CSidebarModel(me.representedObjects(index)).highlighted = value
  
End Sub

CQueryController.reorderSidebarDatasource:
Sub reorderSidebarDatasource(newPosition as integer, selectedItems() as integer)
  
  dim i, j, index as integer
  dim temp(-1) as CStatsModel
  
  try
    newPosition = me.representedObjects(newPosition).getRepresentation
    
    j = ubound(me.representedObjects)
    
    for i = 0 to j
      
      if selectedItems.indexOf(i) = - 1 then temp.append me.representedObjects(i)
      
      if me.representedObjects(i).getRepresentation = newPosition then newPosition = i
      
    next
    
    j = ubound(selectedItems)
    
    for i = 0 to j
      
      temp.insert newPosition + i, me.representedObjects(selectedItems(i))
      
    next
    
    me.representedObjects = temp
    me.rehash
    
    updateCell me.representedObjects
    selectCell -1
    
  catch
    
  end
  
End Sub

CQueryController.handleQueryFindMoreSources:
Sub handleQueryFindMoreSources(arg as string)
  
  handleQuery arg, false, false
  
End Sub

CQueryController.handleQueryNormal:
Sub handleQueryNormal(arg as string)
  
  handleQuery arg, true, true
  
End Sub

CQueryController.setQuerySpam:
Sub setQuerySpam(arrayIndex as integer, spam as boolean)
  
  dim sha1 as string
  dim c as CResponseModel = CResponseModel(me.filteredquery.response.representedObjects(arrayIndex))
  
  c.spam = spam
  c.invalidateValues
  me.filteredquery.response.representedObjects(arrayIndex) = c
  sha1 = c.sha1
  
  if me.currentIndex <> -1 and _
      CQueryModel(me.queries.value(me.currentIndex)).response.representedInfos.hasKey(sha1) then
    arrayIndex = CQueryModel(me.queries.value(me.currentIndex)).response.representedInfos.value(sha1)
    CQueryModel(me.queries.value(me.currentIndex)).response.representedObjects(arrayIndex) = c
    
  end
  
End Sub

CQueryController.statsUpdated:
Sub statsUpdated()
  
  dim i as integer
  dim c as CSidebarModel
  
  for i = ubound(me.representedObjects) downto 0
    
    c = CSidebarModel(me.representedObjects(i))
    
    if c.interval > 0 then
      c.interval = c.interval - 1
      
      me.representedObjects(i) = c
      
      if c.interval = 0 then
        if me.getKeepInSidebar(c.index) = false and me.getResponseCount(c.index) = 0 then
          me.removeQuery c.index
          
        else
          me.stopQuery c.index
          
        end
        
      end
      
    end
    
  next
  
  updateCell me.representedObjects
  
End Sub

CResourceController.getSmallMediaPicture:
Function getSmallMediaPicture(c as CResponseModel) As picture
  
  if c.marked then return me.controlPictures(0)
  
  #if targetMachO
    if me.smallIconCache.hasKey(c.extension) or me.appendIconCache(c.extension) then _
        return me.smallIconCache.value(c.extension)
    
  #endif
  
  return me.smallMediaPictures(c.mediaType)
  
End Function

CResourceController.getLargeMediaPicture:
Function getLargeMediaPicture(type as integer, extension as string) As picture
  
  #if targetMachO
    if me.largeIconCache.hasKey(extension) or me.appendIconCache(extension) then _
        return me.largeIconCache.value(extension)
    
  #endif
  
  return me.largeMediaPictures(type)
  
End Function

CResourceController.getMaskedPicture:
Function getMaskedPicture(pictureName as string) As picture
  
  try
    #if debugBuild and targetMachO
      return getFolderItem("Contents").child("Resources").child(pictureName).openAsMaskedPicture
      
    #elseif targetMachO
      return App.ExecutableFile.parent.parent.child("Resources").child(pictureName).openAsMaskedPicture
      
    #elseif targetCarbon
      return App.ExecutableFile.parent.child("Contents").child("Resources").child(pictureName).openAsMaskedPicture
      
    #elseif targetWin32
      return App.ExecutableFile.fixRbBug.parent.child("Contents").child("Resources").child(pictureName).openAsMaskedPicture
      
    #elseif targetLinux
      return App.ExecutableFile.parent.child("Contents").fixRbBug.child("Resources").fixRbBug.child(pictureName).fixRbBug.openAsMaskedPicture
      
    #endif
    
  catch
    
  end
  
End Function

CResourceController.getControlPicture:
Function getControlPicture(type as integer) As picture
  
  return me.controlPictures(type)
  
End Function

CResourceController.appendIconCache:
Protected Function appendIconCache(extension as string) As boolean
  
  #if targetMachO
    dim f as folderItem
    dim b as BinaryStream
    dim p as picture
    
    try
      f = PreferencesFolder.parent.Child("Caches").child("Cabos").child("icon." + extension)
      
      try
        b = f.CreateBinaryFile("")
      catch
        
      finally
        if b <> nil then b.close
      end
      
      p = new MacIcon(f, 32)
      if p <> nil then me.largeIconCache.value(extension) = p
      
      p = new MacIcon(f, 16)
      if p <> nil then me.smallIconCache.value(extension) = p
      
      return me.largeIconCache.hasKey(extension) and me.smallIconCache.hasKey(extension)
      
    catch
      
    end
    
  #endif
  
End Function

CResourceController.getChasingArrows:
Function getChasingArrows(type as integer) As picture
  
  return me.chasingArrows(type)
  
End Function

CResourceController.Constructor:
Sub Constructor()
  
  #if targetMachO
    me.largeIconCache = new Dictionary
    me.smallIconCache = new Dictionary
    
    dim i as integer
    dim f as FolderItem
    dim p as picture
    dim extension as string
    
    try
      f = PreferencesFolder.parent.child("Caches")
      if f.exists = false then f.createAsFolder
      f = f.child("Cabos")
      if f.exists = false then f.createAsFolder
      
      for i = f.count downto 1
        if f.item(i).name.inStrb("icon.") <> 0 then
          extension = f.item(i).name.getExtension
          
          if extension.lenb <> 0 then
            p = new MacIcon(f.item(i), 32)
            if p <> nil then me.largeIconCache.value(extension) = p
            p = new MacIcon(f.item(i), 16)
            if p <> nil then me.smallIconCache.value(extension) = p
          end
          
        end
        
      next
      
    catch
      
    end
    
    for i = 0 to 5
      
      me.chasingArrows(i) = me.getMaskedPicture(str(i) + ".png")
      me.chasingArrows(i + 6) = me.getSilhouettePicture(me.chasingArrows(i))
      
    next
    
    me.smallMediaPictures(1) = me.getMaskedPicture("music-small.png")
    me.smallMediaPictures(2) = me.getMaskedPicture("pictures-small.png")
    me.smallMediaPictures(3) = me.getMaskedPicture("movies-small.png")
    me.smallMediaPictures(4) = me.getMaskedPicture("text-small.png")
    me.smallMediaPictures(5) = me.getMaskedPicture("files-small.png")
    
    me.largeMediaPictures(1) = me.getMaskedPicture("music.png")
    me.largeMediaPictures(2) = me.getMaskedPicture("pictures.png")
    me.largeMediaPictures(3) = me.getMaskedPicture("movies.png")
    me.largeMediaPictures(4) = me.getMaskedPicture("text.png")
    me.largeMediaPictures(5) = me.getMaskedPicture("files.png")
    
    me.controlPictures(0) = me.getMaskedPicture("complete_small.png")
    me.controlPictures(1) = me.getMaskedPicture("find_small.png")
    me.controlPictures(2) = me.getMaskedPicture("network_small.png")
    me.controlPictures(3) = me.getMaskedPicture("download_small.png")
    me.controlPictures(4) = me.getMaskedPicture("upload_small.png")
    me.controlPictures(5) = me.getSilhouettePicture(me.controlPictures(1))
    
  #elseif targetCarbon
    dim i as integer
    
    for i = 0 to 5
      
      me.chasingArrows(i) = me.getMaskedPicture(str(i) + ".png")
      me.chasingArrows(i + 6) = me.getSilhouettePicture(me.chasingArrows(i))
      
    next
    
    me.smallMediaPictures(1) = me.getMaskedPicture("music-small.png")
    me.smallMediaPictures(2) = me.getMaskedPicture("pictures-small.png")
    me.smallMediaPictures(3) = me.getMaskedPicture("movies-small.png")
    me.smallMediaPictures(4) = me.getMaskedPicture("text-small.png")
    me.smallMediaPictures(5) = me.getMaskedPicture("files-small.png")
    
    me.largeMediaPictures(1) = me.getMaskedPicture("music.png")
    me.largeMediaPictures(2) = me.getMaskedPicture("pictures.png")
    me.largeMediaPictures(3) = me.getMaskedPicture("movies.png")
    me.largeMediaPictures(4) = me.getMaskedPicture("text.png")
    me.largeMediaPictures(5) = me.getMaskedPicture("files.png")
    
    me.controlPictures(0) = me.getMaskedPicture("complete_small.png")
    me.controlPictures(1) = me.getMaskedPicture("find_small.png")
    me.controlPictures(2) = me.getMaskedPicture("network_small.png")
    me.controlPictures(3) = me.getMaskedPicture("download_small.png")
    me.controlPictures(4) = me.getMaskedPicture("upload_small.png")
    me.controlPictures(5) = me.getSilhouettePicture(me.controlPictures(1))
    
  #elseif targetWin32 or targetLinux
    dim i as integer
    
    for i = 0 to 5
      
      me.chasingArrows(i) = me.getMaskedPicture(str(i) + ".gif")
      me.chasingArrows(i + 6) = me.getSilhouettePicture(me.chasingArrows(i))
      
    next
    
    me.smallMediaPictures(1) = me.getMaskedPicture("music-small.gif")
    me.smallMediaPictures(2) = me.getMaskedPicture("pictures-small.gif")
    me.smallMediaPictures(3) = me.getMaskedPicture("movies-small.gif")
    me.smallMediaPictures(4) = me.getMaskedPicture("text-small.gif")
    me.smallMediaPictures(5) = me.getMaskedPicture("files-small.gif")
    
    me.largeMediaPictures(1) = me.getMaskedPicture("music.gif")
    me.largeMediaPictures(2) = me.getMaskedPicture("pictures.gif")
    me.largeMediaPictures(3) = me.getMaskedPicture("movies.gif")
    me.largeMediaPictures(4) = me.getMaskedPicture("text.gif")
    me.largeMediaPictures(5) = me.getMaskedPicture("files.gif")
    
    me.controlPictures(0) = me.getMaskedPicture("complete_small.gif")
    me.controlPictures(1) = me.getMaskedPicture("find_small.gif")
    me.controlPictures(2) = me.getMaskedPicture("network_small.gif")
    me.controlPictures(3) = me.getMaskedPicture("download_small.gif")
    me.controlPictures(4) = me.getMaskedPicture("upload_small.gif")
    me.controlPictures(5) = me.getSilhouettePicture(me.controlPictures(1))
    
  #endif
  
End Sub

CResourceController.getSilhouettePicture:
Protected Function getSilhouettePicture(p as picture) As picture
  
  #if targetMachO or targetWin32 or targetLinux
    dim result as picture
    dim x, y as integer
    
    try
      result = new picture(p.width, p.height, 32)
      
      for x = result.width downto 0
        
        for y = result.height downto 0
          
          result.RGBSurface.pixel(x, y) = &cFFFFFF
          result.mask.RGBSurface.pixel(x, y) = p.mask.RGBSurface.pixel(x, y)
          
        next
        
      next
      
      return result
      
    catch
      
    end
    
  #elseif targetCarbon
    return p
    
  #endif
  
End Function

CResponseController.getNumericColumns:
Protected Sub getNumericColumns(byref column as integer, byref temp1() as double, byref temp2() as double, byref temp3() as CStatsModel)
  
  dim c as CStatsModel
  
  select case column
    
  case 4 //* size *//
    for each c in me.representedObjects
      
      temp1.append CResponseModel(c).fileSize
      temp2.append CResponseModel(c).fileSize
      temp3.append c
      
    next
    
  case 5 //* bitrate *//
    for each c in me.representedObjects
      
      temp1.append CResponseModel(c).bitrate
      temp2.append CResponseModel(c).bitrate
      temp3.append c
      
    next
    
  case 6 //* seconds *//
    for each c in me.representedObjects
      
      temp1.append CResponseModel(c).seconds
      temp2.append CResponseModel(c).seconds
      temp3.append c
      
    next
    
  case 7 //* sources *//
    for each c in me.representedObjects
      
      temp1.append CResponseModel(c).sources
      temp2.append CResponseModel(c).sources
      temp3.append c
      
    next
    
  case 8 //* speed *//
    for each c in me.representedObjects
      
      temp1.append CResponseModel(c).speed
      temp2.append CResponseModel(c).speed
      temp3.append c
      
    next
    
  end
  
End Sub

CResponseController.getStringColumns:
Protected Sub getStringColumns(byref column as integer, byref temp1() as string, byref temp2() as string, byref temp3() as CStatsModel)
  
  dim c as CStatsModel
  
  select case column
    
  case 0 //* icon *//
    for each c in me.representedObjects
      
      temp1.append CResponseModel(c).extension
      temp2.append CResponseModel(c).extension
      temp3.append c
      
    next
    
  case 1 //* dispaly name *//
    for each c in me.representedObjects
      
      temp1.append CResponseModel(c).displayName
      temp2.append CResponseModel(c).displayName
      temp3.append c
      
    next
    
  case 2 //* artist *//
    for each c in me.representedObjects
      
      temp1.append CResponseModel(c).artist
      temp2.append CResponseModel(c).artist
      temp3.append c
      
    next
    
  case 3 //* album *//
    for each c in me.representedObjects
      
      temp1.append CResponseModel(c).album
      temp2.append CResponseModel(c).album
      temp3.append c
      
    next
    
  end
  
End Sub

CResponseController.isNumericColumn:
Protected Function isNumericColumn(column as integer) As boolean
  
  select case column
    
  case 0 //* icon *//
    return false
    
  case 1 //* dispaly name *//
    return false
    
  case 2 //* artist *//
    return false
    
  case 3 //* album *//
    return false
    
  case 4 //* size *//
    return true
    
  case 5 //* bitrate *//
    return true
    
  case 6 //* seconds *//
    return true
    
  case 7 //* sources *//
    return true
    
  case 8 //* speed *//
    return true
    
  end
  
End Function

CStatsController.Constructor:
Sub Constructor()
  
  me.representedInfos = new Dictionary
  
End Sub

CStatsController.rehash:
Sub rehash()
  
  dim i, j as integer
  
  j = ubound(me.representedObjects)
  
  for i = 0 to j
    
    me.representedInfos.value(me.representedObjects(i).getRepresentation) = i
    
  next
  
End Sub

CStatsController.remove:
Sub remove(index as integer)
  
  me.representedInfos.remove me.representedObjects(index).getRepresentation
  me.representedObjects.remove index
  me.rehash
  
End Sub

CStatsController.sort:
Sub sort(column as integer, direction as integer)
  
  if column = -1 or ubound(me.representedObjects) < 1 then return
  
  try
    if me.isNumericColumn(column) then
      me.sortNumber column, direction
      
    else
      me.sortString column, direction
      
    end
    
  catch
    
  end
  
End Sub

CStatsController.sortNumber:
Protected Sub sortNumber(column as integer, direction as integer)
  
  dim temp1(-1), temp2(-1) as double
  dim temp3(-1) as CStatsModel
  dim c as CStatsModel
  
  me.getNumericColumns column, temp1, temp2, temp3
  
  temp1.sort
  
  dim i, j, arrayIndex as integer
  
  j = ubound(temp1)
  
  if direction = 1 then
    for i = 0 to j
      
      arrayIndex = temp2.indexOf(temp1(i))
      me.representedObjects(i) = temp3(arrayIndex)
      me.representedInfos.value(me.representedObjects(i).getRepresentation) = i
      temp2.remove arrayIndex
      temp3.remove arrayIndex
      
    next
    
  else
    for i = 0 to j
      
      arrayIndex = temp2.indexOf(temp1(j - i))
      me.representedObjects(i) = temp3(arrayIndex)
      me.representedInfos.value(me.representedObjects(i).getRepresentation) = i
      temp2.remove arrayIndex
      temp3.remove arrayIndex
      
    next
    
  end
  
End Sub

CStatsController.getNumericColumns:
Protected Sub getNumericColumns(byref column as integer, byref temp1() as double, byref temp2() as double, byref temp3() as CStatsModel)
  
  //* Override *//
  
End Sub

CStatsController.sortString:
Protected Sub sortString(column as integer, direction as integer)
  
  dim temp1(-1), temp2(-1) as string
  dim temp3(-1) as CStatsModel
  dim c as CStatsModel
  
  me.getStringColumns column, temp1, temp2, temp3
  
  temp1.stringSort
  
  dim i, j, arrayIndex as integer
  
  j = ubound(temp1)
  
  if direction = 1 then
    for i = 0 to j
      
      arrayIndex = temp2.indexOf(temp1(i))
      me.representedObjects(i) = temp3(arrayIndex)
      me.representedInfos.value(me.representedObjects(i).getRepresentation) = i
      temp2.remove arrayIndex
      temp3.remove arrayIndex
      
    next
    
  else
    for i = 0 to j
      
      arrayIndex = temp2.indexOf(temp1(j - i))
      me.representedObjects(i) = temp3(arrayIndex)
      me.representedInfos.value(me.representedObjects(i).getRepresentation) = i
      temp2.remove arrayIndex
      temp3.remove arrayIndex
      
    next
    
  end
  
End Sub

CStatsController.isNumericColumn:
Protected Function isNumericColumn(column as integer) As boolean
  
  //* Override *//
  
End Function

CStatsController.getStringColumns:
Protected Sub getStringColumns(byref column as integer, byref temp1() as string, byref temp2() as string, byref temp3() as CStatsModel)
  
  //* Override *//
  
End Sub

CTransferController.hasActiveTransfers:
Function hasActiveTransfers() As boolean
  
  dim i as integer
  
  for i = ubound(me.representedObjects) downto 0
    
    if CTransferModel(me.representedObjects(i)).isActive then return true
    
  next
  
End Function

CTransferController.isCompletedTransferItem:
Function isCompletedTransferItem(index as integer) As boolean
  
  return CTransferModel(me.representedObjects(index)).isComplete
  
End Function

CTransferController.setCanceled:
Function setCanceled(index as integer) As boolean
  
  if CTransferModel(me.representedObjects(index)).canRemove then
    CTransferModel(me.representedObjects(index)).isCanceled = true
    return true
    
  end
  
End Function

CTransferController.getTransferPath:
Function getTransferPath(index as integer) As string
  
  return CTransferModel(me.representedObjects(index)).path
  
End Function

CTransferController.getTransferHashCode:
Function getTransferHashCode(index as integer) As variant
  
  return CTransferModel(me.representedObjects(index)).hashCode
  
End Function

CTransferController.getNumericColumns:
Protected Sub getNumericColumns(byref column as integer, byref temp1() as double, byref temp2() as double, byref temp3() as CStatsModel)
  
  dim c as CStatsModel
  
  select case column
    
  case 2 //* transfer *//
    for each c in me.representedObjects
      
      temp1.append CTransferModel(c).amountRequested
      temp2.append CTransferModel(c).amountRequested
      temp3.append c
      
    next
    
  case 3 //* progress *//
    for each c in me.representedObjects
      
      temp1.append CTransferModel(c).progress
      temp2.append CTransferModel(c).progress
      temp3.append c
      
    next
    
  case 4 //* time *//
    for each c in me.representedObjects
      
      temp1.append CTransferModel(c).timeRemaining
      temp2.append CTransferModel(c).timeRemaining
      temp3.append c
      
    next
    
  end
  
End Sub

CTransferController.getStringColumns:
Protected Sub getStringColumns(byref column as integer, byref temp1() as string, byref temp2() as string, byref temp3() as CStatsModel)
  
  dim c as CStatsModel
  
  if column = 0 then //* extension *//
    for each c in me.representedObjects
      
      temp1.append CTransferModel(c).extension
      temp2.append CTransferModel(c).extension
      temp3.append c
      
    next
    
  elseif column = 1 then //* filename *//
    for each c in me.representedObjects
      
      temp1.append CTransferModel(c).fileName
      temp2.append CTransferModel(c).fileName
      temp3.append c
      
    next
    
  end
  
End Sub

CTransferController.isNumericColumn:
Protected Function isNumericColumn(column as integer) As boolean
  
  return column <> 0 and column <> 1
  
End Function

CTransferController.getTransferFileName:
Function getTransferFileName(index as integer) As string
  
  return CTransferModel(me.representedObjects(index)).fileName
  
End Function

CTransferController.flush:
Sub flush()
  
  updateDataSource me.representedObjects
  
End Sub

CUploadsController.addUpload:
Sub addUpload(args() as string)
  
  if ubound(args) <> 10 then return
  
  if me.representedInfos.hasKey(args(1).val) then return
  
  dim c as new CUploadModel(args)
  
  me.representedObjects.append c
  me.representedInfos.value(c.getRepresentation) = ubound(me.representedObjects)
  
  me.flush
  
End Sub

CUploadsController.removeUpload:
Sub removeUpload(args() as string)
  
  if ubound(args) <> 1 then return
  
  dim hashCode as integer = args(1).val
  
  if me.representedInfos.hasKey(hashCode) = false then return
  
  dim infoArray as integer = me.representedInfos.value(hashCode)
  dim c as CUploadModel = CUploadModel(me.representedObjects(infoArray))
  
  c.isComplete = true
  
  if c.isCanceled or kAqAutoClearUploads or c.amountTransfered = c.startingPoint then
    me.remove infoArray
    
  else
    c.invalidateValues
    me.representedObjects(infoArray) = c
    
  end
  
  me.flush
  
End Sub

CUploadsController.updateUploadStats:
Sub updateUploadStats(args() as string)
  
  if ubound(args) <> 6 then return
  
  dim hashCode as integer = args(1).val
  
  if me.representedInfos.hasKey(hashCode) = false then return
  
  dim infoArray as integer = me.representedInfos.value(hashCode)
  dim c as CUploadModel = CUploadModel(me.representedObjects(infoArray))
  
  c.updateStats args
  c.invalidateValues
  
  me.representedObjects(infoArray) = c
  
End Sub

CUploadsController.statsUpdated:
Sub statsUpdated()
  
  dim c as CTransferModel
  dim i, uploading as integer
  dim bandwidth as double
  
  for i = ubound(me.representedObjects) downto 0
    
    c = CTransferModel(me.representedObjects(i))
    
    if c.isActive then
      uploading = uploading + 1
      bandwidth = bandwidth + c.measuredBandwidth
      
    end
    
  next
  
  me.flush
  updateCell uploading, bandwidth
  
End Sub

CUploadsController.getUploadIPAndPort:
Function getUploadIPAndPort(index as integer) As string
  
  dim c as CUploadModel = CUploadModel(me.representedObjects(index))
  
  if c.isBrowseHostEnabled then return c.ip + ":" + c.port
  
End Function

CAppController.UnhandledException:
Function UnhandledException(error As RuntimeException) As Boolean
  
  System.debugLog error.message
  return true
  
End Function

CAppController.Open:
Sub Open()
  
  initializeDefaults
  initializeLocalization
  initializePreferences
  initializeResources
  initializeColors
  
  localizeSubMenus getMenuHandle(CWindow1.handle), me.menuBar
  drawMenuItems CWindow1.handle
  
  CWindow1.show
  CWindow1.loadSplitterPosition
  
End Sub

CAppController.EnableMenuItems:
Sub EnableMenuItems()
  
  #if targetWin32 or targetLinux
    FileMainWindow.enabled = false
    
  #endif
  
End Sub

CAppController.Close:
Sub Close()
  
  finalizeLocalization
  finalizeResources
  finalizePreferences
  finalizeDefaults
  
End Sub

CAppController.Activate:
Sub Activate()
  
  if me.isFinalized = false then notifyStop CWindow1
  
  #if targetMachO
    if CWindow1.visible = false then CWindow1.show
    
  #endif
  
End Sub

CWindow1.askQuitting:
Function askQuitting() As boolean
  
  dim m as messageDialog
  
  if kAqWarnQuit and me.CDownloadsController1.hasActiveTransfers then
    m = getDialog( _
        getLocalizedString("Do you really wish to quit?", "Dialogs"), _
        getLocalizedString("Cabos is actively downloading files. Quitting will terminate these downloads and there is no guarantee that they will proceed successfully at a later time.", "Dialogs"), _
        getLocalizedString("Quit", "Dialogs"), _
        getLocalizedString("Cancel", "Dialogs"))
    
    if m.showModal = m.cancelButton then return false //Cancel
    
  end
  
  return true //Quit
  
End Function

CWindow1.preFinalize:
Sub preFinalize()
  
  me.CCoreController1.shutdown
  
  #if targetMacOS
    self.show
    
  #endif
  
  CWindow2.showModalWithin me
  
End Sub

CWindow1.loadSplitterPosition:
Sub loadSplitterPosition()
  
  //* restore splitter position *//
  
  dim result as integer = 170
  result = defaultsRead("CSplitter kAqMainSplitterLeft" , result)
  
  if self.CSplitter1.left <> result then setSplitter result
  
End Sub

CWindow1.setSplitter:
Sub setSplitter(position as integer)
  position = min(position, self.width - 10 - self.CEditField2.width - self.CStaticText2.width - self.PopupMenu1.width - self.CStaticText1.width - self.CSplitter1.width)
  position = max(position, self.CListBox1.left + CListBox.kScrollbarWidth)
  
  self.CSplitter1.left = position
  
  //* control order is important! *//
  
  self.CEditField1.width = self.CSplitter1.left - self.CEditField1.left
  self.CListBox1.width = self.CSplitter1.left - self.CListBox1.left
  self.CListBox1.textSize = self.CListBox1.textSize
  self.CListBox6.width = self.CSplitter1.left - self.CListBox6.left
  self.CListBox6.textSize = self.CListBox6.textSize
  self.CToolbar1.left = self.CSplitter1.left + self.CSplitter1.width
  self.CToolbar1.width = self.width - 10 - self.CToolbar1.left
  
  self.PagePanel1.left = self.CSplitter1.left + 5
  self.PagePanel1.width = self.width - self.PagePanel1.left - 5
  self.CListBox3.width = self.PagePanel1.width - 10
  self.CListBox3.textSize = self.CListBox3.textSize
  self.CListBox4.width = self.PagePanel1.width - 10
  self.CListBox4.textSize = self.CListBox4.textSize
  self.CListBox5.width = self.PagePanel1.width - 10
  self.CListBox5.textSize = self.CListBox5.textSize
  self.CListBox2.width = self.PagePanel1.width - 10
  self.CListBox2.textSize = self.CListBox2.textSize
  
  self.CEditField2.left = self.width - 10 - self.CEditField2.width
  self.Slider2.left = self.CEditField2.left
  self.Slider4.left = self.CEditField2.left
  
  self.CStaticText2.left = self.CEditField2.left - 5 - self.CStaticText2.width
  self.CStaticText4.left = self.CStaticText2.left
  self.CStaticText6.left = self.CStaticText2.left
  
  self.PopupMenu1.left = self.CStaticText2.left - 5 - self.PopupMenu1.width
  self.Slider1.left = self.PopupMenu1.left
  self.Slider3.left = self.PopupMenu1.left
  
  self.CStaticText1.left = self.PopupMenu1.left - 5 - self.CStaticText1.width
  self.CStaticText3.left = self.CStaticText1.left
  self.CStaticText5.left = self.CStaticText1.left
  
  self.refresh
  
End Sub

CWindow1.Resized:
Sub Resized()
  
  setSplitter self.CSplitter1.left
  
End Sub

CWindow1.EnableMenuItems:
Sub EnableMenuItems()
  
  dim i as integer
  
  if me.CListBox3.listCount <> 0 then FileConnect.enabled = false
  
  if me.CListBox1.listIndex = -1 then
    SearchStartSelectedSearches.enabled = false
    SearchStopSelectedSearches.enabled = false
    SearchDeleteSelectedSearches.enabled = false
    
  end
  
  if me.PagePanel1.value <> 4 or me.CListBox2.listIndex = -1 then
    EditConvertSelectedTags.item(0).enabled = false
    EditConvertSelectedTags.item(1).enabled = false
    'EditConvertSelectedTags.item(2).enabled = false
    
  end
  
  if me.CListBox1.listCount = 0 then
    SearchClearSearchSidebar.enabled = false
    'SearchStartAllQueries.enabled = false
    
  end
  
  ViewFilterResults.enabled = (me.PagePanel1.value = 4)
  
  select case me.PagePanel1.value
    
  case 2 //* downloads *//
    TransfersDownloadSelected.enabled = false
    
    if me.CListBox4.listIndex = -1 then
      TransfersRevealFileinFinder.enabled = false
      TransfersOpenSelectedFile.enabled = false
      TransfersCancelTransfer.enabled = false
      
    end
    
  case 3 //* uploads *//
    TransfersDownloadSelected.enabled = false
    
    if me.CListBox5.listIndex = -1 then
      TransfersRevealFileinFinder.enabled = false
      TransfersOpenSelectedFile.enabled = false
      TransfersCancelTransfer.enabled = false
      
    end
    
  case 4 //* network *//
    if me.ClistBox2.listIndex = -1 then TransfersDownloadSelected.enabled = false
    
    TransfersRevealFileinFinder.enabled = false
    TransfersOpenSelectedFile.enabled = false
    TransfersCancelTransfer.enabled = false
    
  else
    TransfersDownloadSelected.enabled = false
    TransfersRevealFileinFinder.enabled = false
    TransfersOpenSelectedFile.enabled = false
    TransfersCancelTransfer.enabled = false
    
  end
  
End Sub

CWindow1.CancelClose:
Function CancelClose(appQuitting as Boolean) As Boolean
  
  if appQuitting or App.isFinalized then return false
  
  #if targetMacOS
    me.hide
    
  #elseif targetWin32 or targetLinux
    if me.askQuitting then me.preFinalize
    
  #endif
  
  return true
  
End Function

CWindow1.Close:
Sub Close()
  
  me.saveSizeAndState "kAqMainWindow"
  
  //* Finalize Controllers *//
  
  me.CQueryController1.Finalize
  
End Sub

CWindow1.Open:
Sub Open()
  
  me.loadSizeAndState "kAqMainWindow"
  
  //* Initialize Controllers *//
  
  me.CMenuActionsController1.Initialize _
      me.CCoreController1, me.CQueryController1, me.CFilterController1, me.CNetworkController1, me.CDownloadsController1, me.CUploadsController1
  me.CQueryController1.Initialize me.CCoreController1, me.CFilterController1, me.CFileurnsController1, me.CDownloadsController1
  me.CFilterController1.Initialize me.CQueryController1
  me.CCoreController1.Initialize _
      me.CNetworkController1, me.CQueryController1, me.CDownloadsController1, me.CUploadsController1, me.CFileurnsController1, CFilterController1
  
End Sub

CWindow1.CEditField1.MouseDown:
Function MouseDown(X As Integer, Y As Integer) As Boolean
  
  if isCMMClick then
    return self.CEditMenuController1.openEditMenu(me)
    
  end
  
End Function

CWindow1.CEditField1.Open:
Sub Open()
  
  me.textSize = kMiddleTextSize
  
End Sub

CWindow1.CEditField1.KeyDown:
Function KeyDown(key as string) As boolean
  
  if key.ascb = 13 or key.ascb = 3 then
    self.CQueryController1.handleQueryNormal me.text
    me.text=""
    return true
    
  end
  
End Function

CWindow1.PagePanel1.Change:
Sub Change()
  
  self.CToolbar1.visible = false
  self.CToolbar1.clearMenu
  
  select case me.value
    
  case 0 //* sidebar *//
    self.setTitle getLocalizedString("Cabos", "Window")
    
  case 1 //* network *//
    self.setTitle getLocalizedString("Cabos - Network", "Window")
    self.CToolbar1.appendMenu getLocalizedString("Browse", "Toolbar"), _
        getLocalizedString("Browse Host", "Toolbar")
    self.CToolbar1.appendMenu getLocalizedString("Remove", "Toolbar"), _
        getLocalizedString("Remove Connection", "Toolbar")
    
  case 2 //* downloads *//
    self.setTitle getLocalizedString("Cabos - Downloads", "Window")
    self.CToolbar1.appendMenu getLocalizedString("Browse", "Toolbar"), _
        getLocalizedString("Browse Host", "Toolbar")
    self.CToolbar1.appendMenu getLocalizedString("Remove", "Toolbar"), _
        getLocalizedString("Remove Download", "Toolbar")
    self.CToolbar1.appendMenu getLocalizedString("Clear", "Toolbar"), _
        getLocalizedString("Clear Completed", "Toolbar")
    self.CToolbar1.appendMenu getLocalizedString("Reveal", "Toolbar"), _
        getLocalizedString("Reveal in Finder", "Toolbar")
    self.CToolbar1.appendMenu getLocalizedString("Resume", "Toolbar"), _
        getLocalizedString("Resume Download", "Toolbar")
    
    #if targetMachO or targetWin32 or targetLinux
      self.CToolbar1.appendMenu getLocalizedString("Pause", "Toolbar"), _
          getLocalizedString("Pause Download", "Toolbar")
      
    #endif
    
  case 3 //* uploads *//
    self.setTitle getLocalizedString("Cabos - Uploads", "Window")
    self.CToolbar1.appendMenu getLocalizedString("Browse", "Toolbar"), _
        getLocalizedString("Browse Host", "Toolbar")
    self.CToolbar1.appendMenu getLocalizedString("Remove", "Toolbar"), _
        getLocalizedString("Remove Upload", "Toolbar")
    self.CToolbar1.appendMenu getLocalizedString("Clear", "Toolbar"), _
        getLocalizedString("Clear Completed", "Toolbar")
    self.CToolbar1.appendMenu getLocalizedString("Reveal", "Toolbar"), _
        getLocalizedString("Reveal in Finder", "Toolbar")
    
  case 4 //* query results *//
    self.setTitle getLocalizedStringWithStringData("Cabos - %@", "Window", _
        self.CQueryController1.getQueryString)
    self.CToolbar1.appendMenu getLocalizedString("Browse", "Toolbar"), _
        getLocalizedString("Browse Host", "Toolbar")
    self.CToolbar1.appendMenu getLocalizedString("Download", "Toolbar"), _
        getLocalizedString("Download Selected Files", "Toolbar")
    self.CToolbar1.appendMenu getLocalizedString("Filter", "Toolbar"), _
        getLocalizedString("Filter Results", "Toolbar")
    
  end
  
  self.CToolbar1.visible = true
  
End Sub

CWindow1.CNetworkController1.updateDataSource:
Sub updateDataSource(c() as CStatsModel)
  
  self.CListBox3.dataSourceChanged c
  
End Sub

CWindow1.CNetworkController1.updateCell:
Sub updateCell(online as variant)
  
  if online <> 0 then
    CSidebarModel(self.CListBox6.dataSource(0)).pState = online
    
  else
    CSidebarModel(self.CListBox6.dataSource(0)).pState = nil
    
  end
  
  self.CListBox6.list(0) = ""
  
End Sub

CWindow1.CQueryController1.selectCell:
Sub selectCell(index as integer)
  
  self.CListBox1.listIndex = index
  
End Sub

CWindow1.CQueryController1.updateDataSource:
Sub updateDataSource(c() as CStatsModel)
  
  self.CListBox2.saveSelectedItems
  self.CListBox2.dataSourceChanged c
  self.CListBox2.restoreSelectedItems
  
End Sub

CWindow1.CQueryController1.updateCell:
Sub updateCell(c() as CStatsModel)
  
  self.CListBox1.dataSourceChanged c
  self.CListBox1.addOrRemoveScrollbar
  
End Sub

CWindow1.CDownloadsController1.updateDataSource:
Sub updateDataSource(c() as CStatsModel)
  
  self.CListBox4.dataSourceChanged c
  
End Sub

CWindow1.CDownloadsController1.downloadCompleted:
Sub downloadCompleted(c as CDownloadModel)
  
  if kAqBounceDockIcon then notifyStart self
  
  if kAqImportMusicFile = 0 or c.fileName.isiTunesAudio = false then return
  
  #if targetMacOS
    if targetLeopard then return
    
    dim playlistIndex as integer
    dim trackID as integer
    dim f as folderItem
    
    try
      if self.CiTunesController1.LaunchiTunes = false then return
      
      f = getPath2FolderItem(c.path)
      
      if f = nil then return
      
      trackID = self.CiTunesController1.addFileToLibrary(f)
      
      if trackID = -1 then return
      
      if kAqImportMusicFile = 2 then
        playlistIndex = self.CiTunesController1.getPlaylistIndex(kiTunesPlaylistName)
        
        if playlistIndex < 1 then
          playlistIndex = self.CiTunesController1.makePlaylist(kiTunesPlaylistName)
          //fix iTunes bug
          playlistIndex = self.CiTunesController1.getPlaylistIndex(kiTunesPlaylistName)
        end
        
        trackID = self.CiTunesController1.addTrackToPlaylist(trackID, playlistIndex)
        
        if trackID = -1 then return
        
      end
      
      select case kAqPlaySong
        
      case 0 //* Do not play the song *//
        
      case 1 //* Play the song *//
        if kAqImportMusicFile = 2 then
          if self.CiTunesController1.play(trackID, playlistIndex) = false then return
          
        else
          if self.CiTunesController1.play(trackID) = false then return
          
        end
        
      case 2 //* Play the song if nothing else is playing *//
        if self.CiTunesController1.getPlayerState = 1 then return
        
        if kAqImportMusicFile = 2 then
          if self.CiTunesController1.play(trackID, playlistIndex) = false then return
          
        else
          if self.CiTunesController1.play(trackID) = false then return
          
        end
        
      case 3 //* Add to iTunes "Party Shuffle" *//
        playlistIndex = 2
        
        if self.CiTunesController1.addTrackToPlaylist(trackID, playlistIndex) = -1 then return
        
      end
      
      if kAqDeleteAfterImport then f.delete
      
    catch
      
    end
    
  #elseif targetWin32
    dim track as OLEObject
    dim partyShufflePlaylist as string
    dim f as folderItem
    
    try
      f = getPath2FolderItem(c.path)
      
      if f = nil then return
      
      track = self.CiTunesController1.addFileToLibrary(f)
      
      if track = nil then return
      
      if kAqImportMusicFile = 2 then
        if self.CiTunesController1.getPlaylistIndex(kiTunesPlaylistName) = 0 and _
            self.CiTunesController1.makePlaylist(kiTunesPlaylistName) = false then return
        
        track = self.CiTunesController1.addTrackToPlaylist(track, kiTunesPlaylistName)
        
        if track = nil then return
        
      end
      
      select case kAqPlaySong
        
      case 0 //* Do not play the song *//
        
      case 1 //* Play the song *//
        if self.CiTunesController1.play(track) = false then return
        
      case 2 //* Play the song if nothing else is playing *//
        if self.CiTunesController1.getPlayerState = 1 then return
        
        if self.CiTunesController1.play(track) = false then return
        
      case 3 //* Add to iTunes "Party Shuffle" *//
        partyShufflePlaylist = self.CiTunesController1.getPlaylistName(2)
        
        if self.CiTunesController1.addTrackToPlaylist(track, partyShufflePlaylist) = nil then return
        
      end
      
      if kAqDeleteAfterImport then f.delete
      
    catch
      
    end
    
  #elseif targetLinux
    'todo
    
  #endif
  
End Sub

CWindow1.CDownloadsController1.updateCell:
Sub updateCell(downloading as variant, negociating as variant, bandwidth as double)
  
  if kAqNetBandwidth and downloading <> 0 and bandwidth <> 0 then
    CSidebarModel(self.CListBox6.dataSource(1)).caption = bandwidth.getKbs
    CSidebarModel(self.CListBox6.dataSource(1)).pState = downloading + "/" + negociating
    
  elseif downloading <> 0 or negociating <> 0 then
    CSidebarModel(self.CListBox6.dataSource(1)).caption = getLocalizedString("Downloads", "ListBox")
    CSidebarModel(self.CListBox6.dataSource(1)).pState = downloading + "/" + negociating
    
  else
    CSidebarModel(self.CListBox6.dataSource(1)).caption = getLocalizedString("Downloads", "ListBox")
    CSidebarModel(self.CListBox6.dataSource(1)).pState = nil
    
  end
  
  self.CListBox6.list(1) = ""
  
End Sub

CWindow1.CUploadsController1.updateDataSource:
Sub updateDataSource(c() as CStatsModel)
  
  'self.CListBox5.saveSelectedItems
  self.CListBox5.dataSourceChanged c
  'self.CListBox5.restoreSelectedItems
  
End Sub

CWindow1.CUploadsController1.updateCell:
Sub updateCell(uploading as variant, bandwidth as double)
  
  if kAqNetBandwidth and bandwidth <> 0 then
    CSidebarModel(self.CListBox6.dataSource(2)).caption = bandwidth.getKbs
    CSidebarModel(self.CListBox6.dataSource(2)).pState = uploading
    
  elseif uploading <> 0 then
    CSidebarModel(self.CListBox6.dataSource(2)).caption = getLocalizedString("Uploads", "ListBox")
    CSidebarModel(self.CListBox6.dataSource(2)).pState = uploading
    
  else
    CSidebarModel(self.CListBox6.dataSource(2)).caption = getLocalizedString("Uploads", "ListBox")
    CSidebarModel(self.CListBox6.dataSource(2)).pState = nil
    
  end
  
  self.CListBox6.list(2) = ""
  
End Sub

CWindow1.CMenuActionsController1.askOpening:
Function askOpening() As boolean
  
  dim m as messageDialog = getDialog( _
      getlocalizedString("Do you really wish to open the selected file?", "Dialogs"), _
      getLocalizedString("Cabos is trying to open incomplete file and current downloads may be affected.", "Dialogs"), _
      getLocalizedString("Open File", "Dialogs"), _
      getLocalizedString("Cancel", "Dialogs"))
  
  return (m.showModal = m.actionButton)
  
End Function

CWindow1.CMenuActionsController1.openPreferences:
Sub openPreferences()
  
  CWindow4.CHierarchicalListBox1.collapseAll
  CWindow4.CHierarchicalListBox1.expanded(1) = true
  'CWindow4.show
  
End Sub

CWindow1.CMenuActionsController1.askRemoving:
Function askRemoving() As boolean
  
  dim m as messageDialog = getDialog( _
      getlocalizedString("Do you really wish to remove the selected files?", "Dialogs"), _
      getLocalizedString("Removing the selected files cannot be undone and whatever data has already been downloaded will be deleted.", "Dialogs"), _
      getLocalizedString("Remove Files", "Dialogs"), _
      getLocalizedString("Cancel", "Dialogs"))
  
  return (m.showModal = m.actionButton)
  
End Function

CWindow1.CFilterController1.filterChanged:
Sub filterChanged(c as CFilterModel)
  
  //* control order is important! *//
  dim i as integer
  
  i = (c.bitrate / 320) * self.Slider2.maximum
  if self.Slider2.value <> i then self.Slider2.value = i
  
  i = (c.speed / 1000) * self.Slider4.maximum
  if self.Slider4.value <> i then self.Slider4.value = i
  
  if self.CEditField2.text <> c.keyword then self.CEditField2.text = c.keyword
  
  if self.PopupMenu1.listIndex <> c.media then self.PopupMenu1.listIndex = c.media
  
  i = (c.size / 104857600) * self.Slider1.maximum
  if self.Slider1.value <> i then self.Slider1.value = i
  
  i = (c.sources / 10) * self.Slider3.maximum
  if self.Slider3.value <> i then self.Slider3.value = i
  
  self.CToolbar1.setKeepPressed c.enabled
  
  if self.CEditField2.visible <> c.enabled then
    self.PagePanel1.visible = false
    
    if c.enabled then
      self.CListBox2.top = self.CListBox1.top + self.CListBox6.height + 6
      self.CListBox2.height = self.CListBox1.height
    end
    
    self.CEditField2.visible = c.enabled
    self.Slider2.visible = c.enabled
    self.Slider4.visible = c.enabled
    
    self.CStaticText2.visible = c.enabled
    self.CStaticText4.visible = c.enabled
    self.CStaticText6.visible = c.enabled
    
    self.PopupMenu1.visible = c.enabled
    self.Slider1.visible = c.enabled
    self.Slider3.visible = c.enabled
    
    self.CStaticText1.visible = c.enabled
    self.CStaticText3.visible = c.enabled
    self.CStaticText5.visible = c.enabled
    
    if c.enabled = false then
      self.CListBox2.top = self.CListBox1.top
      self.CListBox2.height = self.CListBox1.height + 6 + self.CListBox6.height
    end
    
    self.PagePanel1.visible = true
    
  end
  
  if c.sortColumn <> -1 and self.CListBox2.columnSortDirection(c.sortColumn) <> c.sortDirection then _
      self.CListBox2.columnSortDirection(c.sortColumn) = c.sortDirection
  
  if self.CListBox2.sortedColumn <> c.sortColumn then
    self.CListBox2.headingIndex = c.sortColumn
    self.CListBox2.sortedColumn = c.sortColumn
    
  end
  
  if self.CListBox2.columnWidths <> c.columnWidths then _
      self.CListBox2.setColumnWidths c.columnWidths
  
  if self.CListBox2.scrollPosition <> c.scrollPosition then _
      self.CListBox2.scrollPosition = c.scrollPosition
  
End Sub

CWindow1.CCoreController1.coreCrashed:
Sub coreCrashed()
  
  App.isFinalized = true
  CWindow2.close
  Quit
  
End Sub

CWindow1.CCoreController1.coreBlockedByFirewall:
Sub coreBlockedByFirewall()
  
  dim m as messageDialog = getDialog( _
      getLocalizedString("Cabos was unable to initialize.", "Dialogs"), _
      getLocalizedString("This is usually due to a personal firewall blocking Java access to the internet. Please allow Java access to the internet and restart Cabos.", "Dialogs"), _
      getLocalizedString("More Info...", "Dialogs"), _
      getLocalizedString("Quit", "Dialogs"))
  
  if m.showModal = m.actionButton then showURL "http://sourceforge.jp/projects/cabos/forums/"
  
  App.isFinalized = true
  Quit
  
End Sub

CWindow1.CCoreController1.coreCorrupted:
Sub coreCorrupted()
  
  dim m as messageDialog = getDialog( _
      getLocalizedString("Your copy of Cabos is corrupted.", "Dialogs"), _
      getLocalizedString("Certain files necessary for the program are either missing or corrupted. Please redownload the application to fix this situation.", "Dialogs"), _
      getLocalizedString("More Info...", "Dialogs"), _
      getLocalizedString("Quit", "Dialogs"))
  
  if m.showModal = m.actionButton then showURL "http://cabos.sourceforge.jp/"
  
  App.isFinalized = true
  Quit
  
End Sub

CWindow1.CCoreController1.coreStopped:
Sub coreStopped()
  
  App.isFinalized = true
  CWindow2.close
  Quit
  
End Sub

CWindow1.CCoreController1.coreLoadingError:
Sub coreLoadingError()
  
  dim m as messageDialog = getDialog( _
      getLocalizedString("The Java software cannot be loaded.", "Dialogs"), _
      getLocalizedString("Please visit Java software site to easily obtain the Java software.", "Dialogs"), _
      getLocalizedString("More Info...", "Dialogs"), _
      getLocalizedString("Quit", "Dialogs"))
  
  if m.showModal = m.actionButton then showURL "http://www.java.com/"
  
  App.isFinalized = true
  CWindow2.close
  Quit
  
End Sub

CWindow1.CCoreController1.coreStarted:
Sub coreStarted()
  
  #if not targetMachO and targetCarbon
    call hideApplication "CabosCore"
    
  #endif
  
  if ubound(kAqSharedDirectories) <> -1 then return
  
  dim m as messageDialog = getDialog( _
      getLocalizedString("You should share some files.", "Dialogs"), _
      getLocalizedString("The Gnutella network benefits when users share files. You will likely be rewarded with greater success finding and downloading files.", "Dialogs"), _
      getLocalizedString("Share Files...", "Dialogs"), _
      getLocalizedString("Later", "Dialogs"))
  
  dim f as folderItem
  
  if m.showModal = m.actionButton then
    CWindow4.CHierarchicalListBox1.collapseAll
    CWindow4.CHierarchicalListBox1.expanded(5) = true
    CWindow4.CHierarchicalListBox1.listIndex = 6
    CWindow4.show
    f = selectFolder
    
    if f <> nil and kAqSharedDirectories.indexOf(f.posixPath) = -1 then
      kAqSharedDirectories.append f.posixPath
      CWindow4.CHierarchicalListBox1.valueChanged 5, 1
      CWindow4.CHierarchicalListBox1.expanded(5) = false
      CWindow4.CHierarchicalListBox1.expanded(5) = true
      
    end
    
  end
  
End Sub

CWindow1.CToolbar1.Action:
Sub Action(item as string)
  
  select case self.PagePanel1.value
    
  case 0 //* sidebar *//
    //self.CMenuActionsController1.openSidebarMenu self.CListBox1
    
  case 1 //* network *//
    self.CMenuActionsController1.openNetworkMenu self.CListBox3, item
    
  case 2 //* downloads *//
    self.CMenuActionsController1.openDownloadsMenu self.CListBox4, item
    
  case 3 //* uploads *//
    self.CMenuActionsController1.openUploadsMenu self.CListBox5, item
    
  case 4 //* query results *//
    self.CMenuActionsController1.openResponseMenu self.CListBox2, item
    
  end
  
End Sub

CWindow1.CSplitter1.Close:
Sub Close()
  //* save splitter position *//
  
  defaultsWrite "CSplitter kAqMainSplitterLeft", me.left
  
End Sub

CWindow1.CSplitter1.Open:
Sub Open()
  
  me.mouseCursor = resizeCursor
  
End Sub

CWindow1.CSplitter1.MouseUp:
Sub MouseUp(X As Integer, Y As Integer)
  
  me.isDragging = false
  
  //* double click action *//
  
  if self.CEditField1.width = me.left - 10 then
    if me.singleClicked = false then
      me.singleClicked = true
      me.mouseCursor = arrowCursor
      me.refresh
      return
      
    else
      me.singleClicked = false
      me.mouseCursor = resizeCursor
      
      if me.left <> self.CListBox1.left + CListBox.kScrollbarWidth then
        me.left = self.CListBox1.left + CListBox.kScrollbarWidth
        
      else
        me.left = 170
        
      end
      
    end
    
  end
  
  setSplitter me.left
  
End Sub

CWindow1.CSplitter1.MouseMove:
Sub MouseMove(X As Integer, Y As Integer)
  
  #if targetMacOS
    if me.singleClicked then
      me.singleClicked = false
      me.mouseCursor = resizeCursor
      
    end
    
  #endif
  
End Sub

CWindow1.CSplitter1.MouseDrag:
Sub MouseDrag(X As Integer, Y As Integer)
  
  me.left = min(max(me.left - (me.targetX - x), self.CListBox1.left + CListBox.kScrollbarWidth), _
      self.width - 10 - self.CEditField2.width - self.CStaticText2.width - self.PopupMenu1.width - self.CStaticText1.width - me.width)
  me.refresh
  
End Sub

CWindow1.CSplitter1.MouseDown:
Function MouseDown(X As Integer, Y As Integer) As Boolean
  
  me.targetX = x
  me.isDragging = true
  return true
  
End Function

CWindow1.CSplitter1.MouseExit:
Sub MouseExit()
  
  me.singleClicked = false
  me.mouseCursor = resizeCursor
  
End Sub

CWindow1.CSplitter1.Paint:
Sub Paint(g As Graphics)
  
  if me.isDragging then
    g.foreColor = &c101010
    g.drawRect 0, 0, g.width, g.height
    
  end
  
End Sub

CWindow1.Slider1.Open:
Sub Open()
  
  #if targetMacOS
    me.top = me.top + 4
    
  #endif
  
End Sub

CWindow1.Slider1.ValueChanged:
Sub ValueChanged()
  
  dim i as integer = (me.value / me.maximum) * 104857600
  
  me.helpTag = i.getShortSize
  self.CFilterController1.setSizeFilter i
  self.CFilterController1.filterResults
  
End Sub

CWindow1.Slider2.Open:
Sub Open()
  
  #if targetMacOS
    me.top = me.top + 4
    
  #endif
  
End Sub

CWindow1.Slider2.ValueChanged:
Sub ValueChanged()
  
  dim i as integer = (me.value / me.maximum) * 320
  
  me.helpTag = i.getKbps
  self.CFilterController1.setBitrateFilter i
  self.CFilterController1.filterResults
  
End Sub

CWindow1.CEditField2.Open:
Sub Open()
  
  me.textSize = kMiddleTextSize
  
End Sub

CWindow1.CEditField2.TextChange:
Sub TextChange()
  
  self.CFilterController1.setKeywordFilter me.text
  self.CFilterController1.filterResults
  
End Sub

CWindow1.CStaticText1.Open:
Sub Open()
  
  me.textSize = kSmallTextSize
  
End Sub

CWindow1.CStaticText2.Open:
Sub Open()
  
  me.textSize = kSmallTextSize
  
End Sub

CWindow1.CStaticText3.Open:
Sub Open()
  
  me.textSize = kSmallTextSize
  
End Sub

CWindow1.CStaticText4.Open:
Sub Open()
  
  me.textSize = kSmallTextSize
  
End Sub

CWindow1.Slider3.Open:
Sub Open()
  
  #if targetMacOS
    me.top = me.top + 4
    
  #endif
  
End Sub

CWindow1.Slider3.ValueChanged:
Sub ValueChanged()
  
  dim i as integer = (me.value / me.maximum) * 10
  
  me.helpTag = str(i)
  self.CFilterController1.setSourcesFilter i
  self.CFilterController1.filterResults
  
End Sub

CWindow1.Slider4.Open:
Sub Open()
  
  #if targetMacOS
    me.top = me.top + 4
    
  #endif
  
End Sub

CWindow1.Slider4.ValueChanged:
Sub ValueChanged()
  
  dim i as integer = (me.value / me.maximum) * 1000
  
  me.helpTag = i.getKb
  self.CFilterController1.setSpeedFilter i
  self.CFilterController1.filterResults
  
End Sub

CWindow1.CStaticText5.Open:
Sub Open()
  
  me.textSize = kSmallTextSize
  
End Sub

CWindow1.CStaticText6.Open:
Sub Open()
  
  me.textSize = kSmallTextSize
  
End Sub

CWindow1.CListBox4.SortColumn:
Function SortColumn(column As Integer) As Boolean
  
  self.CDownloadsController1.sort column, me.columnSortDirection(column)
  return true
  
End Function

CWindow1.CListBox4.KeyDown:
Function KeyDown(key As String) As Boolean
  
  select case key.ascb
    
  case 8, 127
    self.CMenuActionsController1.actionDownloadsRemove me
    return true
    
  case 13, 3
    self.CMenuActionsController1.actionDownloadsOpen me
    return true
    
  case 28, 29
    clearFocus
    self.CListBox1.setFocus
    return true
    
  end
  
End Function

CWindow1.CListBox4.DoubleClick:
Sub DoubleClick()
  
  self.CMenuActionsController1.actionDownloadsOpen me
  
End Sub

CWindow1.CListBox4.CMMClicked:
Sub CMMClicked()
  
  self.CMenuActionsController1.openDownloadsMenu me
  
End Sub

CWindow1.CListBox4.Open:
Sub Open()
  
  me.textFont = kAqStandardTextFont
  me.textSize = kAqStandardTextSize
  
  dim result as string
  
  result = defaultsRead("CListBox kAqDownloadsColumnWidths", result)
  me.setColumnWidths result
  
  me.columnSortDirection(2) = ListBox.sortDescending
  me.columnSortDirection(3) = ListBox.sortDescending
  me.columnSortDirection(4) = ListBox.sortDescending
  
End Sub

CWindow1.CListBox4.Close:
Sub Close()
  
  defaultsWrite "CListBox kAqDownloadsColumnWidths", me.columnWidths
  
End Sub

CWindow1.CListBox4.HeaderCMMClicked:
Sub HeaderCMMClicked()
  
  self.CMenuActionsController1.openHeadingMenu me
  
End Sub

CWindow1.CListBox5.DoubleClick:
Sub DoubleClick()
  
  self.CMenuActionsController1.actionUploadsOpen me
  
End Sub

CWindow1.CListBox5.KeyDown:
Function KeyDown(key As String) As Boolean
  
  select case key.ascb
    
  case 8, 127
    self.CMenuActionsController1.actionUploadsRemove me
    return true
    
  case 13, 3
    self.CMenuActionsController1.actionUploadsOpen me
    return true
    
  case 28, 29
    clearFocus
    self.CListBox1.setFocus
    return true
    
  end
  
End Function

CWindow1.CListBox5.CMMClicked:
Sub CMMClicked()
  
  self.CMenuActionsController1.openUploadsMenu me
  
End Sub

CWindow1.CListBox5.SortColumn:
Function SortColumn(column As Integer) As Boolean
  
  self.CUploadsController1.sort column, me.columnSortDirection(column)
  return true
  
End Function

CWindow1.CListBox5.Close:
Sub Close()
  
  defaultsWrite "CListBox kAqUploadsColumnWidths", me.columnWidths
  
End Sub

CWindow1.CListBox5.Open:
Sub Open()
  
  me.textFont = kAqStandardTextFont
  me.textSize = kAqStandardTextSize
  
  dim result as string
  
  result = defaultsRead("CListBox kAqUploadsColumnWidths", result)
  me.setColumnWidths result
  
  me.columnSortDirection(2) = ListBox.sortDescending
  me.columnSortDirection(3) = ListBox.sortDescending
  me.columnSortDirection(4) = ListBox.sortDescending
  
End Sub

CWindow1.CListBox5.HeaderCMMClicked:
Sub HeaderCMMClicked()
  
  self.CMenuActionsController1.openHeadingMenu me
  
End Sub

CWindow1.CListBox3.SortColumn:
Function SortColumn(column As Integer) As Boolean
  
  self.CNetworkController1.sort column, me.columnSortDirection(column)
  return true
  
End Function

CWindow1.CListBox3.KeyDown:
Function KeyDown(key As String) As Boolean
  
  select case key.ascb
    
  case 28, 29
    clearFocus
    self.CListBox1.setFocus
    return true
    
  case 8, 127
    self.CMenuActionsController1.actionNetworkRemove me
    return true
    
  end
  
End Function

CWindow1.CListBox3.Close:
Sub Close()
  
  defaultsWrite "CListBox kAqNetworkConnectionsColumnWidths", me.columnWidths
  
End Sub

CWindow1.CListBox3.CMMClicked:
Sub CMMClicked()
  
  self.CMenuActionsController1.openNetworkMenu me
  
End Sub

CWindow1.CListBox3.Open:
Sub Open()
  
  me.textFont = kAqStandardTextFont
  me.textSize = kAqStandardTextSize
  
  dim result as string
  
  result = defaultsRead("CListBox kAqNetworkConnectionsColumnWidths", result)
  me.setColumnWidths result
  
  me.columnSortDirection(4) = ListBox.sortDescending
  
End Sub

CWindow1.CListBox3.HeaderCMMClicked:
Sub HeaderCMMClicked()
  
  self.CMenuActionsController1.openHeadingMenu me
  
End Sub

CWindow1.CListBox2.HeaderPressed:
Function HeaderPressed(column as Integer) As Boolean
  
  self.CFilterController1.setSortColumn column
  
  if column <> -1 then
    self.CFilterController1.setSortDirection me.columnSortDirection(column)
    
  else
    self.CFilterController1.setSortDirection ListBox.sortAscending
    
  end
  
End Function

CWindow1.CListBox2.SortColumn:
Function SortColumn(column As Integer) As Boolean
  
  self.CFilterController1.updateResults
  return true
  
End Function

CWindow1.CListBox2.KeyDown:
Function KeyDown(key As String) As Boolean
  
  select case key.ascb
    
  case 13, 3
    self.CMenuActionsController1.actionResponseDownload me
    return true
    
  case 28, 29
    clearFocus
    self.CListBox1.setFocus
    return true
    
  case 8, 127
    self.CMenuActionsController1.actionResponseSpam me
    return true
    
  end
  
End Function

CWindow1.CListBox2.DoubleClick:
Sub DoubleClick()
  
  self.CMenuActionsController1.actionResponseDownload me
  
End Sub

CWindow1.CListBox2.Close:
Sub Close()
  
  'defaultsWrite "CListBox kAqResponseColumnWidths", me.columnWidths
  
End Sub

CWindow1.CListBox2.CMMClicked:
Sub CMMClicked()
  
  self.CMenuActionsController1.openResponseMenu me
  
End Sub

CWindow1.CListBox2.Open:
Sub Open()
  
  me.textFont = kAqStandardTextFont
  me.textSize = kAqStandardTextSize
  
  'dim result as string
  '
  'result = defaultsRead("CListBox kAqResponseColumnWidths", result)
  'me.setColumnWidths result
  
  me.columnSortDirection(4) = ListBox.sortDescending
  me.columnSortDirection(5) = ListBox.sortDescending
  me.columnSortDirection(6) = ListBox.sortDescending
  me.columnSortDirection(7) = ListBox.sortDescending
  me.columnSortDirection(8) = ListBox.sortDescending
  
End Sub

CWindow1.CListBox2.HeaderCMMClicked:
Sub HeaderCMMClicked()
  
  self.CMenuActionsController1.openHeadingMenu me
  
End Sub

CWindow1.CListBox6.KeyDown:
Function KeyDown(key As String) As Boolean
  
  select case key.ascb
    
  case 28, 29
    clearFocus
    
    select case self.PagePanel1.value
      
    case 1
      self.CListBox3.setFocus
      
    case 2
      self.CListBox4.setFocus
      
    case 3
      self.CListBox5.setFocus
      
    case 4
      self.CListBox2.setFocus
      
    end
    
    return true
    
  end
  
End Function

CWindow1.CListBox6.Change:
Sub Change()
  
  self.PagePanel1.value = me.listIndex + 1
  
End Sub

CWindow1.CListBox6.Open:
Sub Open()
  
  me.textFont = kAqSidebarTextFont
  me.textSize = kAqSidebarTextSize
  
  dim c(2) as CStatsModel
  
  c(0) = new CSidebarModel(getLocalizedString("Network", "ListBox"))
  c(1) = new CSidebarModel(getLocalizedString("Downloads", "ListBox"))
  c(2) = new CSidebarModel(getLocalizedString("Uploads", "ListBox"))
  
  me.dataSourceChanged c
  
  #if targetWin32 or targetLinux//* to clear scrollbar *//
    me.top = me.top - 2
    me.height = me.height + 2
    
  #endif
  
End Sub

CWindow1.CListBox1.DoubleClick:
Sub DoubleClick()
  
  if CStatsModel(me.dataSource(me.listIndex)).getRepresentation < 0 then
    self.CQueryController1.startQuery CStatsModel(me.dataSource(me.listIndex)).getRepresentation, false
    
  else
    self.CQueryController1.stopQuery CStatsModel(me.dataSource(me.listIndex)).getRepresentation
    
  end
  
End Sub

CWindow1.CListBox1.MouseMove:
Sub MouseMove(row as integer, column as integer, x as integer, y as integer)
  
  if row <> -1 and x > 3 and x < 21 then
    me.mouseCursor = handCursor
    
  else
    me.mouseCursor = arrowCursor
    
  end
  
End Sub

CWindow1.CListBox1.DragReorderRows:
Function DragReorderRows(newPosition as Integer) As Boolean
  
  self.CQueryController1.reorderSidebarDatasource newPosition, me.getSelectedRows
  
  return true
  
End Function

CWindow1.CListBox1.CellClick:
Function CellClick(row as Integer, column as Integer, x as Integer, y as Integer) As Boolean
  
  if x > 3 and x < 21 then
    if CStatsModel(me.dataSource(row)).getRepresentation < 0 then
      self.CQueryController1.startQuery CStatsModel(me.dataSource(row)).getRepresentation, false
      
    else
      self.CQueryController1.stopQuery CStatsModel(me.dataSource(row)).getRepresentation
      
    end
    
    return true
    
  end
  
End Function

CWindow1.CListBox1.KeyDown:
Function KeyDown(key As String) As Boolean
  
  select case key.ascb
    
    'case 32
    'me.listIndex = me.listIndex
    'return true
    
  case 28, 29
    clearFocus
    
    select case self.PagePanel1.value
      
    case 1
      self.CListBox3.setFocus
      
    case 2
      self.CListBox4.setFocus
      
    case 3
      self.CListBox5.setFocus
      
    case 4
      self.CListBox2.setFocus
      
    end
    
    return true
    
  case 8, 127
    self.CMenuActionsController1.actionSidebarRemove me
    return true
    
  end
  
End Function

CWindow1.CListBox1.CMMClicked:
Sub CMMClicked()
  
  self.CMenuActionsController1.openSidebarMenu me
  
End Sub

CWindow1.CListBox1.Close:
Sub Close()
  
  self.CFilterController1.setColumnWidths self.CListBox2.columnWidths
  
End Sub

CWindow1.CListBox1.Open:
Sub Open()
  
  me.textFont = kAqSidebarTextFont
  me.textSize = kAqSidebarTextSize
  
  #if targetWin32 or targetLinux//* to clear scrollbar *//
    me.height = me.height - 2
    
  #endif
  
End Sub

CWindow1.CListBox1.Change:
Sub Change()
  
  if ubound(me.dataSource) <> me.listCount - 1 then me.listIndex = -1
  
  self.CFilterController1.setScrollPosition self.CListBox2.scrollPosition
  self.CFilterController1.setColumnWidths self.CListBox2.columnWidths
  
  if me.listIndex = -1 or me.selCount > 1 then
    self.CQueryController1.setCurrentIndex -1
    
    self.PagePanel1.value = 0
    
    'self.CFilterController1.setFilterModel
    
  else
    self.CQueryController1.setCurrentIndex CStatsModel(me.dataSource(me.listIndex)).getRepresentation
    self.CQueryController1.setSidebarHighlighted me.listIndex, false
    
    self.PagePanel1.value = 4
    
    self.CFilterController1.setFilterModel
    self.CFilterController1.updateResults
    self.CFilterController1.updateFilter
    '
    'if CStatsModel(me.dataSource(me.listIndex)).getRepresentation < 0 then _
    'self.CQueryController1.startQuery CStatsModel(me.dataSource(me.listIndex)).getRepresentation, false
    '
  end
  
End Sub

CWindow1.PopupMenu1.Change:
Sub Change()
  
  self.CFilterController1.setMediaFilter me.listIndex
  self.CFilterController1.filterResults
  
End Sub

CWindow1.PopupMenu1.Open:
Sub Open()
  
  me.textSize = kSmallTextSize
  me.addRow getLocalizedString("All Types", "PopupMenu")
  me.addRow getLocalizedString("Music", "PopupMenu")
  me.addRow getLocalizedString("Pictures", "PopupMenu")
  me.addRow getLocalizedString("Movies", "PopupMenu")
  me.addRow getLocalizedString("Text", "PopupMenu")
  me.addRow getLocalizedString("Files", "PopupMenu")
  me.listIndex = 0
  
End Sub

CWindow2.CStaticText1.Open:
Sub Open()
  
  me.textSize = kLargeTextSize
  
End Sub

CWindow3.Canvas1.Open:
Sub Open()
  
  #if targetMacOS
    me.backdrop = getMaskedPicture("icon.png")
    
  #elseif targetWin32 or targetLinux
    me.backdrop = getMaskedPicture("icon.gif")
    
  #endif
  
End Sub

CWindow3.CStaticText2.Open:
Sub Open()
  
  me.text = getLocalizedStringWithIntegerData("Version %i", "StaticText", App.PackageInfo)
  
End Sub

CWindow4.getMyFolderSet:
Protected Function getMyFolderSet(path as string) As dictionary
  
  dim d as new dictionary
  dim f as folderItem
  
  try
    #if targetMachO
      d.value(DesktopFolder.posixPath) = DesktopFolder.posixPath
      d.value(DocumentsFolder.posixPath) = DocumentsFolder.posixPath
      d.value(DocumentsFolder.parent.child("Music").posixPath) _
          = DocumentsFolder.parent.child("Music").posixPath
      d.value(DocumentsFolder.parent.child("Pictures").posixPath) _
          = DocumentsFolder.parent.child("Pictures").posixPath
      d.value(DocumentsFolder.parent.child("Movies").posixPath) _
          = DocumentsFolder.parent.child("Movies").posixPath
      
    #elseif targetCarbon or targetLinux
      d.value(DesktopFolder.posixPath) = DesktopFolder.posixPath
      d.value(DocumentsFolder.posixPath) = DocumentsFolder.posixPath
      d.value(DocumentsFolder.child("Music").fixRbBug.posixPath) _
          = DocumentsFolder.child("Music").fixRbBug.posixPath
      d.value(DocumentsFolder.child("Pictures").fixRbBug.posixPath) _
          = DocumentsFolder.child("Pictures").fixRbBug.posixPath
      d.value(DocumentsFolder.child("Movies").fixRbBug.posixPath) _
          = DocumentsFolder.child("Movies").fixRbBug.posixPath
      
    #elseif targetWin32
      f = DesktopFolder.fixRbBug
      d.value(f.posixPath) = f.posixPath
      f = DocumentsFolder.fixRbBug
      d.value(f.posixPath) = f.posixPath
      d.value(f.child("My Music").posixPath) = f.child("My Music").posixPath
      d.value(f.child("My Pictures").posixPath) = f.child("My Pictures").posixPath
      d.value(f.child("My Videos").posixPath) = f.child("My Videos").posixPath
      
    #endif
    
  catch
    
  end
  
  d.value(0) = "-"
  d.value(1) = getLocalizedString("Other...", "Preferences")
  
  if path <> "" then
    d.value(path) = path
    d.value("currentKey") = path
    
  else
    d.value(2) = getLocalizedString("None", "Preferences")
    d.value("currentKey") = 2
    
  end
  
  return d
  
End Function

CWindow4.requiresRestart:
Protected Sub requiresRestart()
  
  dim m as new messageDialog
  
  m.icon = 0
  m.message = getLocalizedString("The change will take effect the next time Cabos is restarted.", "Dialogs")
  
  #if targetMachO or targetWin32 or targetLinux
    m.actionButton.caption = getLocalizedString("OK", "Dialogs")
    
  #elseif targetCarbon
    m.actionButton.caption = getLocalizedString("OK", "Dialogs").convertEncoding(Encodings.systemDefault)
    
  #endif
  
  call m.showModal
  
End Sub

CWindow4.Close:
Sub Close()
  
  me.saveSizeAndState "kAqPreferencesWindow"
  
End Sub

CWindow4.Open:
Sub Open()
  
  me.loadSizeAndState "kAqPreferencesWindow"
  
End Sub

CWindow4.CPreferencesMenuController1.sendCommand:
Sub sendCommand(arg as string)
  
  CWindow1.CCoreController1.sendCommand arg
  
End Sub

CWindow4.CHierarchicalListBox1.KeyDown:
Function KeyDown(key As String) As Boolean
  
  if me.listIndex = -1 then return false
  
  select case key.ascb
    
  case 13, 3
    if me.cellTag(me.listIndex, 1) isa Dictionary then
      self.CPreferencesMenuController1.openPreferencesMenu _
          me, me.listIndex, 1, me.cellTag(me.listIndex, 0), me.cellTag(me.listIndex, 1)
      
    elseif me.cellType(me.listIndex, 1) = 3 then
      me.editCell me.listIndex, 1
      
    end
    
    return true
    
  case 32
    if me.cellType(me.listIndex, 0) = 2 then
      me.cellCheck(me.listIndex, 0) = not me.cellCheck(me.listIndex, 0)
      
    end
    
    return true
    
  case 28
    me.expanded(me.listIndex) = false
    return true
    
  case 29
    me.expanded(me.listIndex) = true
    return true
    
  end
  
End Function

CWindow4.CHierarchicalListBox1.SortColumn:
Function SortColumn(column As Integer) As Boolean
  
  return true
  
End Function

CWindow4.CHierarchicalListBox1.Close:
Sub Close()
  
  defaultsWrite "CListBox kAqPreferencesColumnWidths", me.columnWidths
  
End Sub

CWindow4.CHierarchicalListBox1.CellAction:
Sub CellAction(row as integer, column as integer)
  
  dim defaults as string = me.cellTag(row, 0)
  dim s as string
  
  //* fix rb bug *//
  try
    select case defaults
      
      //* general *//
      
    case "kAqPositiveFilter"
      kAqPositiveFilter = me.cellCheck(row, column)
      
    case "kAqKeywordFilterKeywords"
      if me.cellTag(row, column) <> nil and _
          kAqKeywordFilterKeywords.indexOf(Dictionary(me.cellTag(row, column)).value("currentKey")) <> -1 then
        s = me.cell(row, column).lowercase.trim
        me.cell(row, column) = s
        KAqKeywordFilterKeywords(kAqKeywordFilterKeywords.indexOf(Dictionary(me.cellTag(row, column)).value("currentKey"))) = s
        Dictionary(me.cellTag(row, column)).clear
        Dictionary(me.cellTag(row, column)).value(s) = s
        Dictionary(me.cellTag(row, column)).value(0) = "-"
        Dictionary(me.cellTag(row, column)).value(1) = getLocalizedString("Remove", "Preferences")
        Dictionary(me.cellTag(row, column)).value("currentKey") = s
      end
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqAdultFilter"
      kAqAdultFilter = me.cellCheck(row, column)
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqSpamFilter"
      kAqSpamFilter = me.cellCheck(row, column)
      CWindow1.CFilterController1.filterResults
      
    case "kAqLengthFilter"
      kAqLengthFilter = me.cellCheck(row, 0)
      kAqLengthFilterCharacters = max(min(me.cell(row, 1).val, 255), 0)
      me.cell(row, 1) = str(kAqLengthFilterCharacters)
      
    case "kAqSizeFilter"
      kAqSizeFilter = me.cellCheck(row, 0)
      kAqSizeFilterKilobytes = max(min(me.cell(row, 1).val, 1024), 0)
      me.cell(row, 1) = str(kAqSizeFilterKilobytes)
      
    case "kAqExistingFileMatching"
      kAqExistingFileMatching = me.cellCheck(row, column)
      
    case "kAqKbFileSize"
      kAqKbFileSize = me.cellCheck(row, column)
      
    case "kAqID3Title"
      kAqID3Title = me.cellCheck(row, column)
      
    case "kAqAutoClearDownloads"
      kAqAutoClearDownloads = me.cellCheck(row, column)
      
    case "kAqAutoClearUploads"
      kAqAutoClearUploads = me.cellCheck(row, column)
      
    case "kAqBounceDockIcon"
      kAqBounceDockIcon = me.cellCheck(row, column)
      
    case "kAqNetBandwidth"
      kAqNetBandwidth = me.cellCheck(row, column)
      
    case "kAqWarnDownloads"
      kAqWarnDownloads = me.cellCheck(row, column)
      
    case "kAqWarnOpening"
      kAqWarnOpening = me.cellCheck(row, column)
      
    case "kAqWarnQuit"
      kAqWarnQuit = me.cellCheck(row, column)
      
      //* Appearance *//
      
    case "kAqSidebarTextFont"
      kAqSidebarTextFont = Dictionary(me.cellTag(row, column)).value("currentKey")
      resizeAllListBoxes
      
    case "kAqSidebarTextSize"
      kAqSidebarTextSize = Dictionary(me.cellTag(row, column)).value("currentKey")
      resizeAllListBoxes
      
    case "kAqStandardTextFont"
      kAqStandardTextFont = Dictionary(me.cellTag(row, column)).value("currentKey")
      resizeAllListBoxes
      
    case "kAqStandardTextSize"
      kAqStandardTextSize = Dictionary(me.cellTag(row, column)).value("currentKey")
      resizeAllListBoxes
      
    case "kAqTexturedWindow"
      kAqTexturedWindow = me.cellCheck(row, column)
      self.requiresRestart
      
      //* Download *//
      
    case "kAqSaveDirectory"
      if Dictionary(me.cellTag(row, 1)).value("currentKey").type = 8 then
        kAqSaveDirectory = Dictionary(me.cellTag(row, 1)).value("currentKey")
        
      else
        kAqSaveDirectory = ""
        
      end
      
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqMoveMusic"
      kAqMoveMusic = me.cellCheck(row, 0)
      
      if Dictionary(me.cellTag(row, 1)).value("currentKey").type = 8 then
        kAqMoveMusicLocation = Dictionary(me.cellTag(row, 1)).value("currentKey")
        
      else
        kAqMoveMusicLocation = ""
        
      end
      
    case "kAqMoveMovies"
      kAqMoveMovies = me.cellCheck(row, 0)
      
      if Dictionary(me.cellTag(row, 1)).value("currentKey").type = 8 then
        kAqMoveMoviesLocation = Dictionary(me.cellTag(row, 1)).value("currentKey")
        
      else
        kAqMoveMoviesLocation = ""
        
      end
      
    case "kAqMovePictures"
      kAqMovePictures = me.cellCheck(row, 0)
      if Dictionary(me.cellTag(row, 1)).value("currentKey").type = 8 then
        kAqMovePicturesLocation = Dictionary(me.cellTag(row, 1)).value("currentKey")
        
      else
        kAqMovePicturesLocation = ""
        
      end
      
    case "kAqIncompletePurgeTime"
      kAqIncompletePurgeTime = max(min(me.cell(row, column).val, 100), 0)
      me.cell(row, column) = str(kAqIncompletePurgeTime)
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqConcurrentDownloads"
      kAqConcurrentDownloads = Dictionary(me.cellTag(row, column)).value("currentKey")
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqDownstreamLimit"
      kAqDownstreamLimit = max(min(me.cell(row, column).val, 100), 25)
      me.cell(row, column) = str(kAqDownstreamLimit)
      CWindow1.CCoreController1.setValue defaults
      
      //* iTunes *//
      
    case "kAqImportMusicFile"
      kAqImportMusicFile = Dictionary(me.cellTag(row, column)).value("currentKey")
      
    case "kAqPlaySong"
      kAqPlaySong = Dictionary(me.cellTag(row, column)).value("currentKey")
      
    case "kAqDeleteAfterImport"
      kAqDeleteAfterImport = me.cellCheck(row, column)
      
      //* Sharing *//
      
    case  "kAqSharedDirectories"
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqPartialFileSharing"
      kAqPartialFileSharing = me.cellCheck(row, column)
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqCompleteFileSharing"
      kAqCompleteFileSharing = me.cellCheck(row, column)
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqMaxUploads"
      kAqMaxUploads = Dictionary(me.cellTag(row, column)).value("currentKey")
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqMaxUploadsPerPerson"
      kAqMaxUploadsPerPerson = Dictionary(me.cellTag(row, column)).value("currentKey")
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqUpstreamLimit"
      kAqUpstreamLimit = max(min(me.cell(row, column).val, 100), 25)
      me.cell(row, column) = str(kAqUpstreamLimit)
      CWindow1.CCoreController1.setValue defaults
      
      //* Network *//
      
    case "kAqConnectionSpeed"
      kAqConnectionSpeed = Dictionary(me.cellTag(row, column)).value("currentKey")
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqPort"
      kAqPort = max(min(me.cell(row, column).val, 65536), 0)
      me.cell(row, column) = str(kAqPort)
      CWindow1.CCoreController1.setValue defaults
      self.requiresRestart
      
    case "kAqUPnPType"
      kAqUPnPType = Dictionary(me.cellTag(row, column)).value("currentKey")
      CWindow1.CCoreController1.setValue defaults
      self.requiresRestart
      
    case "kAqEnableUltrapeer"
      kAqEnableUltrapeer = me.cellCheck(row, column)
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqLocale"
      kAqLocale = me.cellCheck(row, 0)
      CWindow1.CCoreController1.setValue defaults
      kAqPreferLocale = Dictionary(me.cellTag(row, 1)).value("currentKey")
      CWindow1.CCoreController1.setValue "kAqPreferLocale"
      
    case "kAqAllowFreeloaders"
      kAqAllowFreeloaders = me.cellCheck(row, column)
      CWindow1.CCoreController1.setValue defaults
      
      //* Advanced *//
      
    case "kAqUseProxy"
      kAqUseProxy = me.cellCheck(row, column)
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqProxyServer"
      kAqProxyServer = me.cell(row, column).trim
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqProxyPort"
      kAqProxyPort = max(min(me.cell(row, column).val, 65536), 0)
      me.cell(row, column) = str(kAqProxyPort)
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqProxyType"
      kAqProxyType = Dictionary(me.cellTag(row, column)).value("currentKey")
      CWindow1.CCoreController1.setValue "kAqUseProxy"
      
    case "kAqProxyRequiresAuthentication"
      kAqProxyRequiresAuthentication = me.cellCheck(row, column)
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqProxyUsername"
      kAqProxyUsername = me.cell(row, column).trim
      me.cell(row, column) = kAqProxyUsername
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqProxyPassword"
      kAqProxyPassword = me.cell(row, column).trim
      me.cell(row, column) = kAqProxyPassword
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqProxyPrivate"
      kAqProxyPrivate = me.cellCheck(row, column)
      CWindow1.CCoreController1.setValue defaults
      
    case "kAqIPFilterIPs"
      if me.cellTag(row, column) <> nil and _
          kAqIPFilterIPs.indexOf(Dictionary(me.cellTag(row, column)).value("currentKey")) <> -1 then
        s = me.cell(row, column).lowercase.trim
        me.cell(row, column) = s
        kAqIPFilterIPs(kAqIPFilterIPs.indexOf(Dictionary(me.cellTag(row, column)).value("currentKey"))) = s
        Dictionary(me.cellTag(row, column)).clear
        Dictionary(me.cellTag(row, column)).value(s) = s
        Dictionary(me.cellTag(row, column)).value(0) = "-"
        Dictionary(me.cellTag(row, column)).value(1) = getLocalizedString("Remove", "Preferences")
        Dictionary(me.cellTag(row, column)).value("currentKey") = s
      end
      CWindow1.CCoreController1.setValue defaults
      
    end
    
  catch
    
  end
  
End Sub

CWindow4.CHierarchicalListBox1.CellClick:
Function CellClick(row as Integer, column as Integer, x as Integer, y as Integer) As Boolean
  
  if me.cellTag(row, column) isa Dictionary then
    me.listIndex = row
    me.refresh
    self.CPreferencesMenuController1.openPreferencesMenu _
        me, row, column, me.cellTag(row, 0), me.cellTag(row, 1)
    return true
    
  elseif me.cellType(row, column) = ListBox.TypeEditable then
    me.listIndex = row
    me.refresh
    me.editCell(row, column)
    return true
    
  end
  
End Function

CWindow4.CHierarchicalListBox1.ExpandRow:
Sub ExpandRow(row As Integer)
  
  dim test as string
  
  dim f as folderItem
  dim d as dictionary
  dim i, j as integer
  dim s as string = me.list(row)
  
  select case s
    
    //* General *//
    
  case getLocalizedString("General", "Preferences")
    me.addrow getLocalizedString("Transfers:", "Preferences")
    me.addrow getLocalizedString("Clear completed downloads", "Preferences"), _
        "kAqAutoClearDownloads", kAqAutoClearDownloads
    me.addrow getLocalizedString("Clear completed uploads", "Preferences"), _
        "kAqAutoClearUploads", kAqAutoClearUploads
    me.addrow getLocalizedString("Bounce Dock icon upon download success", "Preferences"), _
        "kAqBounceDockIcon", kAqBounceDockIcon
    me.addrow getLocalizedString("Display bandwidth usage in Sidebar", "Preferences"), _
        "kAqNetBandwidth", kAqNetBandwidth
    
    me.addrow getLocalizedString("Prompt user:", "Preferences")
    me.addrow getLocalizedString("Before removing partially downloaded files", "Preferences"), _
        "kAqWarnDownloads", kAqWarnDownloads
    me.addrow getLocalizedString("Before opening partially downloaded files", "Preferences"), _
        "kAqWarnOpening", kAqWarnOpening
    me.addrow getLocalizedString("Before quitting with active downloads", "Preferences"), _
        "kAqWarnQuit", kAqWarnQuit
    
    //* Searching *//
    
  case getLocalizedString("Searching", "Preferences")
    
    me.addrow getLocalizedString("Gray out files that are already on this computer", "Preferences"), _
        "kAqExistingFileMatching", kAqExistingFileMatching
    me.addrow getLocalizedString("Show track name as file name", "Preferences"), _
        "kAqID3Title", kAqID3Title
    me.addrow getLocalizedString("Show file size in bytes", "Preferences"), _
        "kAqKbFileSize", kAqKbFileSize
    
    me.addrow getLocalizedString("Ignore files that do not contain the search keywords", "Preferences"), _
        "kAqPositiveFilter", kAqPositiveFilter
    me.addRow getLocalizedString("Ignore files that are adult content", "Preferences"), _
        "kAqAdultFilter", kAqAdultFilter
    
    #if targetMachO or targetWin32 or targetLinux
      d = new Dictionary
      d.value(0) = getLocalizedString("Clear Spam History", "Preferences")
      d.value("currentKey") = 0
      me.addrow getLocalizedString("Ignore files that are spam content", "Preferences"), _
          "kAqSpamFilter", kAqSpamFilter, d
      
    #endif
    
    me.addrow getLocalizedString("Ignore files that are longer than (characters)", "Preferences"), _
        "kAqLengthFilter", kAqLengthFilter, str(kAqLengthFilterCharacters)
    me.addrow getLocalizedString("Ignore files that are smaller than (kB)", "Preferences"), _
        "kAqSizeFilter", kAqSizeFilter, str(kAqSizeFilterKiloBytes)
    
    d = new Dictionary
    d.value(0) = getLocalizedString("Add Keyword...", "Preferences")
    d.value("currentKey") = 0
    me.addrow _
        getLocalizedString("Ignore files that contain following keywords:", "Preferences"), _
        "kAqKeywordFilterKeywords", d
    
    j = ubound(kAqKeywordFilterKeywords)
    
    for i = 0 to j
      
      d = new Dictionary
      d.value(kAqKeywordFilterKeywords(i)) = kAqKeywordFilterKeywords(i)
      d.value(0) = "-"
      d.value(1) = getLocalizedString("Remove", "Preferences")
      d.value("currentKey") = kAqKeywordFilterKeywords(i)
      me.addrow "", "kAqKeywordFilterKeywords", d
      
    next
    
    
    //* Appearance *//
    
  case getLocalizedString("Appearance", "Preferences")
    d = new Dictionary
    j = fontCount - 1
    
    for i = 0 to j
      
      d.value(Font(i).convertEncoding(Encodings.UTF8)) = Font(i).convertEncoding(Encodings.UTF8)
      
    next
    
    d.value("currentKey") = kAqSidebarTextFont
    me.addRow getLocalizedString("Sidebar Text Font", "Preferences"), _
        "kAqSidebarTextFont", d
    
    d = new Dictionary
    d.value(kSmallTextSize) = getLocalizedString("Small", "Preferences")
    d.value(kMiddleTextSize) = getLocalizedString("Middle", "Preferences")
    d.value(kLargeTextSize) = getLocalizedString("Large", "Preferences")
    d.value("currentKey") = kAqSidebarTextSize
    me.addRow getLocalizedString("Sidebar Text Size", "Preferences"), _
        "kAqSidebarTextSize", d
    
    d = new Dictionary
    j = fontCount - 1
    
    for i = 0 to j
      
      #if targetMachO or targetCarbon
        d.value(Font(i).convertEncoding(Encodings.UTF8)) = Font(i).convertEncoding(Encodings.UTF8)
        
      #elseif targetWin32
        if Font(i).leftb(1) <> "@" then _
            d.value(Font(i).convertEncoding(Encodings.UTF8)) = Font(i).convertEncoding(Encodings.UTF8)
        
      #endif
      
    next
    
    d.value("currentKey") = kAqStandardTextFont
    me.addRow getLocalizedString("Standard Text Font", "Preferences"), _
        "kAqStandardTextFont", d
    
    d = new Dictionary
    d.value(kSmallTextSize) = getLocalizedString("Small", "Preferences")
    d.value(kMiddleTextSize) = getLocalizedString("Middle", "Preferences")
    d.value(kLargeTextSize) = getLocalizedString("Large", "Preferences")
    d.value("currentKey") = kAqStandardTextSize
    me.addRow getLocalizedString("Standard Text Size", "Preferences"), _
        "kAqStandardTextSize", d
    
    #if targetMachO
      if targetLeopard = false then
        me.addrow getLocalizedString("Use textured window", "Preferences"), _
            "kAqTexturedWindow", kAqTexturedWindow
      end
      
    #endif
    
    //* Download *//
    
  case getLocalizedString("Download", "Preferences")
    d = self.getMyFolderSet(kAqSaveDirectory)
    
    me.addrow getLocalizedString("Save downloaded files in", "Preferences"), _
        "kAqSaveDirectory", d
    
    d = self.getMyFolderSet(kAqMoveMusicLocation)
    
    me.addrow getLocalizedString("Move completed music files to", "Preferences"), _
        "kAqMoveMusic", kAqMoveMusic, d
    
    d = self.getMyFolderSet(kAqMovePicturesLocation)
    
    me.addrow getLocalizedString("Move completed picture files to", "Preferences"), _
        "kAqMovePictures", kAqMovePictures, d
    
    d = self.getMyFolderSet(kAqMoveMoviesLocation)
    
    me.addrow getLocalizedString("Move completed movie files to", "Preferences"), _
        "kAqMoveMovies", kAqMoveMovies, d
    
    me.addrow getLocalizedString("Minimum days to keep incomplete files", "Preferences"), _
        "kAqIncompletePurgeTime", kAqIncompletePurgeTime
    
    d = new Dictionary
    d.value(1) = 1
    d.value(2) = 2
    d.value(3) = 3
    d.value(4) = 4
    d.value(5) = 5
    d.value(6) = 6
    d.value(7) = 7
    d.value(8) = 8
    d.value(9) = 9
    d.value(10) = 10
    d.value(11) = 11
    d.value(12) = 12
    d.value(13) = 13
    d.value(14) = 14
    d.value(15) = 15
    d.value(16) = "-"
    d.value(100) = getLocalizedString("Unlimited", "Preferences")
    d.value("currentKey") = kAqConcurrentDownloads
    me.addrow getLocalizedString("Maximum downloads", "Preferences"), _
        "kAqConcurrentDownloads", d
    me.addrow getLocalizedString("Downstream bandwidth limit (%)", "Preferences"), _
        "kAqDownstreamLimit", kAqDownstreamLimit
    
    //* iTunes *//
    
  case getLocalizedString("iTunes", "Preferences")
    d = new Dictionary
    d.value(0) = getLocalizedString("Do not import to iTunes", "Preferences")
    d.value(1) = getLocalizedString("Add to iTunes Library", "Preferences")
    d.value(2) = getLocalizedString("Add to iTunes 'Cabos' Playlist", "Preferences")
    d.value("currentKey") = kAqImportMusicFile
    me.addrow getLocalizedString("Completed music file", "Preferences"), _
        "kAqImportMusicFile", d
    
    d = new Dictionary
    d.value(0) = getLocalizedString("Do not play", "Preferences")
    d.value(1) = getLocalizedString("Play", "Preferences")
    d.value(2) = getLocalizedString("Play if nothing else is playing", "Preferences")
    d.value(3) = getLocalizedString("Add to iTunes 'Party Shuffle'", "Preferences")
    d.value("currentKey") = kAqPlaySong
    me.addrow getLocalizedString("Imported music file", "Preferences"), "kAqPlaySong", d
    
    me.addrow getLocalizedString("Delete original music file after successful import", "Preferences"), _
        "kAqDeleteAfterImport", kAqDeleteAfterImport
    
    //* Sharing *//
    
  case getLocalizedString("Sharing", "Preferences")
    d = new Dictionary
    d.value(0) = getLocalizedString("Add Folder...", "Preferences")
    d.value("currentKey") = 0
    me.addrow _
        getLocalizedString("Share files in the following folders:", "Preferences"), _
        "kAqSharedDirectories", d
    
    j = ubound(kAqSharedDirectories)
    
    for i = 0 to j
      
      if kAqSharedDirectories(i) <> "" then
        d = new Dictionary
        d.value(kAqSharedDirectories(i)) = kAqSharedDirectories(i)
        d.value(0) = "-"
        d.value(1) = getLocalizedString("Remove", "Preferences")
        d.value("currentKey") = kAqSharedDirectories(i)
        me.addrow "", "kAqSharedDirectories", d
        
      end
      
    next
    
    me.addRow getLocalizedString("Share partially downloaded files (Recommended)", "Preferences"), _
        "kAqPartialFileSharing", kAqPartialFileSharing
    
    #if targetMachO or targetWin32 or targetLinux
      me.addRow getLocalizedString("Share completely downloaded files (Recommended)", "Preferences"), _
          "kAqCompleteFileSharing", kAqCompleteFileSharing
      
    #endif
    
    d = new Dictionary
    d.value(1) = 1
    d.value(2) = 2
    d.value(3) = 3
    d.value(4) = 4
    d.value(5) = 5
    d.value(6) = 6
    d.value(7) = 7
    d.value(8) = 8
    d.value(9) = 9
    d.value(10) = 10
    d.value(11) = 11
    d.value(12) = 12
    d.value(13) = 13
    d.value(14) = 14
    d.value(15) = 15
    d.value(16) = "-"
    d.value(100) = getLocalizedString("Unlimited", "Preferences")
    d.value("currentKey") = kAqMaxUploads
    me.addRow getLocalizedString("Maximum uploads", "Preferences"), _
        "kAqMaxUploads", d
    
    d = new Dictionary
    d.value(1) = 1
    d.value(2) = 2
    d.value(3) = 3
    d.value(4) = 4
    d.value(5) = 5
    d.value(6) = 6
    d.value(7) = 7
    d.value(8) = 8
    d.value(9) = 9
    d.value(10) = 10
    d.value(11) = 11
    d.value(12) = 12
    d.value(13) = 13
    d.value(14) = 14
    d.value(15) = 15
    d.value(16) = "-"
    d.value(100) = getLocalizedString("Unlimited", "Preferences")
    d.value("currentKey") = kAqMaxUploadsPerPerson
    me.addRow getLocalizedString("Maximum uploads per person", "Preferences"), _
        "kAqMaxUploadsPerPerson", d
    
    me.addRow getLocalizedString("Upstream bandwidth limit (%)", "Preferences"), _
        "kAqUpstreamLimit", kAqUpstreamLimit
    
    //* Network *//
    
  case getLocalizedString("Network", "Preferences")
    d = new Dictionary
    d.value(56) = getLocalizedString("Modem", "Preferences")
    d.value(350) = getLocalizedString("Cable or DSL", "Preferences")
    d.value(1000) = getLocalizedString("T1", "Preferences")
    d.value(3000) = getLocalizedString("T3", "Preferences")
    d.value("currentKey") = kAqConnectionSpeed
    me.addRow getLocalizedString("I connect to the internet via", "Preferences"), _
        "kAqConnectionSpeed", d
    
    me.addRow getLocalizedString("Listen for incoming connections on port", "Preferences"), _
        "kAqPort", kAqPort
    
    d = new Dictionary
    d.value(0) = getLocalizedString("Automatically (Requires UPnP)", "Preferences")
    d.value(1) = getLocalizedString("Manually", "Preferences")
    d.value(2) = getLocalizedString("Do nothing", "Preferences")
    d.value("currentKey") = kAqUPnPType
    me.addRow getLocalizedString("Configure my router to work behind a firewall", "Preferences"), _
        "kAqUPnPType", d
    
    me.addrow getLocalizedString("Allow this computer to become an Ultrapeer", "Preferences"), _
        "kAqEnableUltrapeer", kAqEnableUltrapeer
    
    d = new Dictionary
    d.value("") = getLocalizedString("Default", "Preferences")
    d.value(0) = "-"
    d.value("af") = "Afrikaans"
    d.value("ar") = "لغة عربية"
    d.value("be") = "Беларускі"
    d.value("bg") = "Български"
    d.value("bn") = "Bengla"
    d.value("br") = "Brezhoneg"
    d.value("bu") = "Myanmarese"
    d.value("ca") = "Català"
    d.value("cs") = "Čeština"
    d.value("da") = "Dansk"
    d.value("de") = "Deutsch"
    d.value("el") = "Ελληνικά"
    d.value("en") = "English"
    d.value("es") = "Español"
    d.value("et") = "Eesti"
    d.value("eu") = "Euskara"
    d.value("fa") = "فارسی"
    d.value("fi") = "Suomi"
    d.value("fr") = "Français"
    d.value("gl") = "Gallego"
    d.value("hi") = "Hindi"
    d.value("hr") = "Hrvatsky"
    d.value("hu") = "Magyar"
    d.value("id") = "Bahasa Indonesia"
    d.value("is") = "Íslenska"
    d.value("it") = "Italiano"
    d.value("iw") = "עברית"
    d.value("ja") = "日本語"
    d.value("kk") = "Казах"
    d.value("ko") = "한글"
    d.value("lt") = "Lietuvių"
    d.value("lv") = "Latviešu"
    d.value("mg") = "Malagasy"
    d.value("mk") = "Македонски јазик"
    d.value("ms") = "Bahasa Malaysia"
    d.value("nl") = "Nederlands"
    d.value("nn") = "Norsk Nynorsk"
    d.value("no") = "Norsk Bokmål"
    d.value("pl") = "Polski"
    d.value("pt") = "Português"
    d.value("ro") = "Romana"
    d.value("ru") = "Русский"
    d.value("sk") = "Slovenčina"
    d.value("sl") = "Slovenski"
    d.value("sq") = "Shqipe"
    d.value("sr") = "Српски"
    d.value("sv") = "Svenska"
    d.value("ta") = "Tamil"
    d.value("th") = "ภาษาไทย"
    d.value("tl") = "Tagalog"
    d.value("tr") = "Türkçe"
    d.value("uk") = "Українська мова"
    d.value("ur") = "اردو"
    d.value("vi") = "Tiếng Việt Nam"
    d.value("zh") = "汉语"
    d.value("currentKey") = kAqPreferLocale
    me.addrow getLocalizedString("Preferentially connect to hosts that are", "Preferences"), _
        "kAqLocale", kAqLocale, d
    
    me.addrow getLocalizedString("Allow freeloaders to connect to this computer", "Preferences"), _
        "kAqAllowFreeloaders", kAqAllowFreeloaders
    
    //* Advanced *//
    
  case getLocalizedString("Advanced", "Preferences")
    me.addrow getLocalizedString("Proxy Server:", "Preferences")
    me.addrow getLocalizedString("Use a proxy server", "Preferences"), _
        "kAqUseProxy", kAqUseProxy
    
    me.addIndentRow getLocalizedString("Server", "Preferences"), _
        "kAqProxyServer", kAqProxyServer
    me.addIndentRow getLocalizedString("Port", "Preferences"), _
        "kAqProxyPort", kAqProxyPort
    
    d = new Dictionary
    d.value(1) = getLocalizedString("HTTP proxy", "Preferences")
    d.value(4) = getLocalizedString("SOCKS v4 proxy", "Preferences")
    d.value(5) = getLocalizedString("SOCKS v5 proxy", "Preferences")
    d.value("currentKey") = kAqProxyType
    me.addIndentRow getLocalizedString("Type", "Preferences"), _
        "kAqProxyType", d
    
    me.addrow getLocalizedString("Requires authentication", "Preferences"), _
        "kAqProxyRequiresAuthentication", kAqProxyRequiresAuthentication
    me.addIndentRow getLocalizedString("Username", "Preferences"), _
        "kAqProxyUsername", kAqProxyUsername
    me.addIndentRow getLocalizedString("Password", "Preferences"), _
        "kAqProxyPassword", kAqProxyPassword
    
    me.addrow getLocalizedString("Use proxy server for private IP addresses", "Preferences"), _
        "kAqProxyPrivate", kAqProxyPrivate
    
    d = new Dictionary
    d.value(0) = getLocalizedString("Add IP Address...", "Preferences")
    d.value("currentKey") = 0
    me.addrow _
        getLocalizedString("Ignore hosts that contain following IP addresses:", "Preferences"), _
        "kAqIPFilterIPs", d
    
    j = ubound(kAqIPFilterIPs)
    
    for i = 0 to j
      
      d = new Dictionary
      d.value(kAqIPFilterIPs(i)) = kAqIPFilterIPs(i)
      d.value(0) = "-"
      d.value(1) = getLocalizedString("Remove", "Preferences")
      d.value("currentKey") = kAqIPFilterIPs(i)
      me.addrow "", "kAqIPFilterIPs", d
      
    next
    
  end
  
  try
    for i = me.listCount - 1 downto 0
      
      if me.list(i) <> s and me.expanded(i) then me.expanded(i) = false
      
    next
    
  catch
    
  end
  
End Sub

CWindow4.CHierarchicalListBox1.Open:
Sub Open()
  
  me.textFont = kAqStandardTextFont
  me.textSize = kAqStandardTextSize
  
  dim result as string
  
  result = defaultsRead("CListBox kAqPreferencesColumnWidths", result)
  me.setColumnWidths result
  
  me.addFolder getLocalizedString("General", "Preferences")
  me.addFolder getLocalizedString("Searching", "Preferences")
  me.addFolder getLocalizedString("Appearance", "Preferences")
  me.addFolder getLocalizedString("Download", "Preferences")
  if targetLeopard = false then _
      me.addFolder getLocalizedString("iTunes", "Preferences")
  me.addFolder getLocalizedString("Sharing", "Preferences")
  me.addFolder getLocalizedString("Network", "Preferences")
  me.addFolder getLocalizedString("Advanced", "Preferences")
  
End Sub

AssertionException.Constructor:
Sub Constructor(description as String)
  
End Sub

InvalidParameterException.Constructor:
Sub Constructor(msg as String)
  #if targetMacOS
    me.Message = msg
  #endif
End Sub

InvalidParameterException.Constructor:
Sub Constructor(className as String, methodName as String, msg as String)
  #if targetMacOS
    me.Message = className + "." + methodName + ": " + msg + "."
  #endif
End Sub

MacOSException.Constructor:
Sub Constructor(theFunction as String, theError as Integer)
  #if targetMacOS
    me.pFunctionName = theFunction
    me.pOSError = theError
  #endif
End Sub

MacOSException.ErrorCode:
Function ErrorCode() As Integer
  #if targetMacOS
    Return me.pOSError
  #endif
End Function

MacOSException.FunctionName:
Function FunctionName() As String
  #if targetMacOS
    Return me.pFunctionName
  #endif
End Function

CFArray.Constructor:
Sub Constructor(theArray as CFArray)
  #if targetMachO
    //copies theArray
    Declare Function CFArrayCreateCopy Lib CarbonLib (allocator as Integer, theArray as Integer) as Integer
    
    dim theRef as Integer
    dim nullList(-1) as CFType
    
    If theArray Is Nil then
      me.Constructor nullList
    Else
      theRef = CFArrayCreateCopy(CoreFoundation.kCFAllocatorDefault, me)
      CoreFoundation.CheckCFTypeRef theRef, "CFArray", "CopyConstructor", "CFArrayCreateCopy"
      me.Constructor theRef
    End if
    
  Finally
    CoreFoundation.Release theRef
    
  #endif
  
End Sub

CFArray.Value:
Function Value(index as Integer) As Integer
  #if targetMachO
    Declare Function CFArrayGetCount Lib CarbonLib (theArray as Integer) as Integer
    Declare Function CFArrayGetValueAtIndex Lib CarbonLib (theArray as Integer, idx as Integer) as Integer
    
    If index < 0 or index > CFArrayGetCount(me) - 1 then
      Raise new OutOfBoundsException
    End if
    
    Return CFArrayGetValueAtIndex(me, index)
  #endif
End Function

CFArray.Count:
Function Count() As Integer
  #if targetMachO
    Declare Function CFArrayGetCount Lib CarbonLib (theArray as Integer) as Integer
    
    Return CFArrayGetCount(me)
  #endif
End Function

CFArray.Constructor:
Sub Constructor(theList() as CFType)
  #if targetMachO
    Declare Function CFArrayCreate Lib CarbonLib (allocator as Integer, values as Ptr, numValues as Integer, callbacks as Ptr) as Integer
    Declare Function CFArrayCreate Lib CarbonLib (allocator as Integer, values as Integer, numValues as Integer, callbacks as Ptr) as Integer
    
    dim bundleItem as FolderItem
    dim bundleURL as CFURL
    dim bundle as CFBundle
    dim bundleError as RuntimeException
    dim arrayRef as Integer
    dim thevalues as MemoryBlock
    dim i as Integer
    dim defaultCallBacks as MemoryBlock
    
    Const kCFTypeArrayCallBacks = "kCFTypeArrayCallBacks"
    Const CarbonFramework = "com.apple.Carbon"
    Const Null = 0
    
    bundle = new CFBundle(CarbonFramework)
    defaultCallBacks = bundle.DataPointer(kCFTypeArrayCallBacks)
    If defaultCallBacks Is Nil then
      bundleError = new RuntimeException
      bundleError.Message = "CFArray.Constructor: Could not resolve " + kCFTypeArrayCallBacks + "."
      Raise bundleError
    End if
    
    If UBound(theList) > -1 then
      theValues = new MemoryBlock(4*(1 + UBound(theList)))
      For i = 0 to UBound(theList)
        thevalues.Long(4*i) = theList(i)
      Next
      arrayRef = CFArrayCreate(CoreFoundation.kCFAllocatorDefault, theValues, UBound(theList) + 1, defaultCallBacks)
    Else
      arrayRef = CFArrayCreate(CoreFoundation.kCFAllocatorDefault, Null, UBound(theList) + 1, defaultCallBacks)
    End if
    CoreFoundation.CheckCFTypeRef arrayRef, "CFArray", "Constructor", "CFArrayCreate"
    me.Constructor arrayRef
    
  Finally
    CoreFoundation.Release arrayRef
    
  #endif
  
End Sub

CFBoolean.Constructor:
Sub Constructor(theValue as Boolean)
  #if targetMachO
    dim frameworkBundle  as CFBundle
    dim symbolName as CFString
    dim p as MemoryBlock
    
    Const CFBooleanFalse = "kCFBooleanFalse"
    Const CFBooleanTrue = "kCFBooleanTrue"
    Const CarbonFramework = "com.apple.Carbon"
    
    If theValue then
      symbolName = new CFString(CFBooleanTrue)
    Else
      symbolName = new CFString(CFBooleanFalse)
    End if
    frameworkBundle = new CFBundle(CarbonFramework)
    p = frameworkBundle.DataPointer(symbolName)
    me.Constructor p.Long(0)
    
    //in Rb 6 we can use static variables here, I think...
  #endif
End Sub

CFBoolean.Operator_Convert:
Function Operator_Convert() As Boolean
  #if targetMachO
    Declare Function CFBooleanGetValue Lib CarbonLib (cf as Integer) as Boolean
    
    Return CFBooleanGetValue(me)
  #endif
End Function

CFBundle.Constructor:
Sub Constructor(theURL as CFURL)
  #if targetMachO
    Declare Function CFBundleCreate Lib CarbonLib (allocator as Integer, bundleURL as Integer) as Integer
    
    dim bundleRef as Integer
    
    If theURL Is Nil then
      me.Constructor()
    Else
      bundleRef = CFBundleCreate(CoreFoundation.kCFAllocatorDefault, theURL)
      CoreFoundation.CheckCFTypeRef bundleRef, "CFBundle", "Constructor", "CFBundleCreate"
      me.Constructor bundleRef
    End if
    
  Finally
    CoreFoundation.Release bundleRef
    
  #endif
  
End Sub

CFBundle.ExecutableFile:
Function ExecutableFile() As CFURL
  #if targetMachO
    Declare Function CFBundleCopyExecutableURL Lib CarbonLib (theBundle as Integer) as Integer
    
    dim theRef as Integer
    dim theURL as CFURL
    
    theRef = CFBundleCopyExecutableURL(me)
    If theRef = 0 then
      Return Nil
    End if
    theURL = new CFURL(theRef)
    
  Finally
    CoreFoundation.Release theRef
    Return theURL
    
  #endif
  
End Function

CFBundle.Resource:
Function Resource(name as CFString, type as CFString, subDirectoryName as CFString) As CFURL
  #if targetMachO
    Declare Function CFBundleCopyResourceURL Lib CarbonLib (bundle as Integer, resourceName as Integer, resourceType as Integer, subDirName as Integer) as Integer
    Declare Function CFBundleCopyResourceURLInDirectory Lib CarbonLib (bundleURL as Integer, resourceName as Integer, resourceType as Integer, subDirName as Integer) as Integer
    Declare Function CFBundleCopyBundleURL Lib CarbonLib (bundle as Integer) as Integer
    
    dim theRef as Integer
    dim theURL as CFURL
    dim typeRef as Integer
    dim subDirRef as Integer
    dim urlRef as Integer
    
    If name Is Nil then
      Return Nil
    End if
    If type Is Nil then
      typeRef = 0
    Else
      typeRef = type
    End if
    If subDirectoryName Is Nil then
      subDirRef = 0
    Else
      subDirRef = subDirectoryName
    End if
    
    theRef = CFBundleCopyResourceURL(me, name, typeRef, subDirRef)
    CoreFoundation.CheckCFTypeRef theRef, "CFBundle", "Resource", "CFBundleCopyResourceURL"
    theURL = new CFURL(theRef)
    
  Exception oops as CFTypeRefException
    theURL = Nil
    
  Finally
    CoreFoundation.Release theRef
    Return theURL
    
  #endif
  
End Function

CFBundle.ResourcesDirectory:
Function ResourcesDirectory() As CFURL
  #if targetMachO
    Declare Function CFBundleCopyResourcesDirectoryURL Lib CarbonLib  (theBundle as Integer) as Integer
    
    dim theRef as Integer
    dim theURL as CFURL
    
    theRef = CFBundleCopyResourcesDirectoryURL(me)
    CoreFoundation.CheckCFTypeRef theRef, "CFBundle", "ResourcesDirectory", "CFBundleCopyResourcesDirectoryURL"
    theURL = new CFURL(theRef)
    
  Exception theProblem as CFTypeRefException
    theURL = Nil
    
  Finally
    CoreFoundation.Release theRef
    Return theURL
    
  #endif
  
End Function

CFBundle.DataPointer:
Function DataPointer(symbolName as String) As MemoryBlock
  #if targetMachO
    Declare Function CFBundleGetDataPointerForName Lib CarbonLib (bundle as Integer, symbolName as Integer) as Integer
    
    dim ptr as MemoryBlock
    
    ptr = new MemoryBlock(4)
    ptr.Long(0) = CFBundleGetDataPointerForName(me, new CFString(symbolName))
    If ptr.Long(0) <> 0 then
      ptr = ptr.Ptr(0)
    Else
      ptr = Nil
    End if
    Return ptr
  #endif
End Function

CFBundle.Identifier:
Function Identifier() As CFString
  #if targetMachO
    Declare Function CFBundleGetIdentifier Lib CarbonLib (bundle as Integer) as Integer
    
    dim theRef as Integer
    dim theString as CFString
    
    theRef = CFBundleGetIdentifier(me)
    If theRef <> 0 then
      theString = new CFString(theRef)
    Else //no identifier was specified in the bundle plist, perhaps
      theString = new CFString("")
    End if
    Return theString
  #endif
End Function

CFBundle.URL:
Function URL() As CFURL
  #if targetMachO
    Declare Function CFBundleCopyBundleURL Lib CarbonLib (bundle as Integer) as Integer
    
    dim theRef as Integer
    dim theURL as CFURL
    
    theRef = CFBundleCopyBundleURL(me)
    If theRef = 0 then
      Return Nil
    End if
    theURL = new CFURL(theRef)
    
  Finally
    CoreFoundation.Release theRef
    Return theURL
    
  #endif
  
End Function

CFBundle.FunctionPointer:
Function FunctionPointer(symbolName as CFString) As Integer
  #if targetMachO
    Declare Function CFBundleGetFunctionPointerForName Lib CarbonLib (bundle as Integer, symbolName as Integer) as Integer
    
    If symbolName Is Nil then
      Return 0
    End if
    
    Return CFBundleGetFunctionPointerForName(me, symbolName)
  #endif
End Function

CFBundle.InfoDictionary:
Function InfoDictionary() As CFDictionary
  #if targetMachO
    Declare Function CFBundleGetInfoDictionary Lib CarbonLib (bundle as Integer) as Integer
    
    dim dictRef as Integer
    dim theDictionary as CFDictionary
    dim noKeys(-1) as CFType
    dim noValues(-1) as CFType
    
    dictRef = CFBundleGetInfoDictionary(me)
    If dictRef = 0 then //return an empty Dictionary
      theDictionary = new CFDictionary(noKeys, noValues)
    End if
    theDictionary =  new CFDictionary(dictRef)
    Return theDictionary
  #endif
End Function

CFBundle.InfoDictionaryValue:
Function InfoDictionaryValue(key as CFString) As CFType
  #if targetMachO
    Declare Function CFBundleGetValueForInfoDictionaryKey Lib CarbonLib (bundle as Integer, key as Integer) as Integer
    
    dim valueRef as Integer
    dim theValue as CFPropertyList
    
    Const kCFPropertyListImmutable = 0
    
    If key Is Nil then
      Return Nil
    End if
    
    valueRef = CFBundleGetValueForInfoDictionaryKey(me, key)
    If valueRef = 0 then //return an empty Dictionary
      Return nil
    End if
    theValue = CoreFoundation.NewCFPropertyListObject(valueRef, kCFPropertyListImmutable)
    Return CFType(theValue)
  #endif
End Function

CFBundle.Constructor:
Sub Constructor()
  #if targetMachO
    Declare Function CFBundleGetMainBundle Lib CarbonLib () as Integer
    
    dim theRef as Integer
    
    theRef = CFBundleGetMainBundle
    CoreFoundation.CheckCFTypeRef theRef, "CFBundle", "Constructor", "GetMainBundle"
    me.Constructor(theRef)
  #endif
End Sub

CFBundle.Constructor:
Sub Constructor(bundleIdentifier as String)
  #if targetMachO
    Declare Function CFBundleGetBundleWithIdentifier Lib CarbonLib (bundleID as Integer) as Integer
    
    dim theRef as Integer
    
    theRef = CFBundleGetBundleWithIdentifier(new CFString(bundleIdentifier))
    CoreFoundation.CheckCFTypeRef theRef, "CFBundle", "Constructor3", "CFBundleGetBundleWithIdentifier"
    me.Constructor(theRef)
  #endif
End Sub

CFBundle.LocalizedString:
Function LocalizedString(key as CFString, value as CFString, tableName as CFString) As CFString
  #if targetMachO
    Declare Function CFBundleCopyLocalizedString Lib CarbonLib (bundle as Integer, key as Integer, value as Integer, tableName as Integer) as Integer
    
    dim theRef as Integer
    dim theString as CFString
    
    theRef = CFBundleCopyLocalizedString(me, key, value, tableName)
    If theRef <> 0 then
      theString = new CFString(theRef)
    Else //no identifier was specified in the bundle plist, perhaps
      theString = new CFString("")
    End if
    Return theString
  #endif
End Function

CFBundle.Localizations:
Function Localizations() As CFArray
  #if targetMachO
    Declare Function CFBundleCopyBundleLocalizations Lib CarbonLib  (theBundle as Integer) as Integer
    
    dim theRef as Integer
    dim theArray as CFArray
    
    theRef = CFBundleCopyBundleLocalizations(me)
    CoreFoundation.CheckCFTypeRef theRef, "CFBundle", "Localizations", "CFBundleCopyBundleLocalizations"
    theArray = new CFArray(theRef)
    
  Exception theProblem as CFTypeRefException
    theArray = Nil
    
  Finally
    CoreFoundation.Release theRef
    Return theArray
    
  #endif
  
End Function

CFBundle.PreferredLocalizations:
Function PreferredLocalizations(locArray as CFArray) As CFArray
  #if targetMachO
    Declare Function CFBundleCopyPreferredLocalizationsFromArray Lib CarbonLib  (locArray as Integer) as Integer
    
    dim theRef as Integer
    dim theArray as CFArray
    
    theRef = CFBundleCopyPreferredLocalizationsFromArray(locArray)
    CoreFoundation.CheckCFTypeRef theRef, "CFBundle", "PreferredLocalizations", "CFBundleCopyPreferredLocalizationsFromArray"
    theArray = new CFArray(theRef)
    
  Exception theProblem as CFTypeRefException
    theArray = Nil
    
  Finally
    CoreFoundation.Release theRef
    Return theArray
    
  #endif
  
End Function

CFData.Constructor:
Sub Constructor(theData as String)
  #if targetMachO
    Declare Function CFDataCreate Lib CarbonLib (allocator as Integer, bytes as CString, length as Integer) as Integer
    
    dim theRef as Integer
    
    Const kCFAllocatorDefault = 0
    
    theRef = CFDataCreate(kCFAllocatorDefault, theData, LenB(theData))
    CoreFoundation.CheckCFTypeRef theRef, "CFData", "Constructor", "CFDataCreate failed."
    me.Constructor theRef
    
  Finally
    CoreFoundation.Release theRef
    
  #endif
  
End Sub

CFData.Data:
Function Data() As MemoryBlock
  dim L as Integer
  dim m as MemoryBlock
  
  #if targetMachO
    Declare Function CFDataGetLength Lib CarbonLib (theData as Integer) as Integer
    Declare Sub CFDataGetBytes Lib CarbonLib (theData as Integer, rangeStart as Integer, rangeLength as Integer, buffer as Ptr)
    
    L = CFDataGetLength(me)
    If L > 0 then
      m = new MemoryBlock(L)
      CFDataGetBytes me, 0, L, m
    Else
      m = nil
    End if
    Return m
  #endif
  
End Function

CFData.Constructor:
Sub Constructor(theData as MemoryBlock)
  
  #if targetMachO
    Declare Function CFDataCreate Lib CarbonLib (allocator as Integer, bytes as Ptr, length as Integer) as Integer
    Declare Sub CFRelease Lib CarbonLib (cf as Integer)
    
    dim theRef as Integer
    
    Const kCFAllocatorDefault = 0
    
    If theData Is Nil then
      me.Constructor ""
    Else
      theRef = CFDataCreate(kCFAllocatorDefault, theData, theData.Size)
      CoreFoundation.CheckCFTypeRef theRef, "CFData", "Constructor2", "CFDataCreate"
      me.Constructor theRef
    End if
    
  Finally
    CoreFoundation.Release theRef
    
  #endif
  
End Sub

CFDate.Constructor:
Sub Constructor(absTime as Double)
  #if targetMachO
    Declare Function CFDateCreate Lib CarbonLib (at as Double) as Integer
    
    dim theRef as Integer
    
    theRef = CFDateCreate(absTime)
    CoreFoundation.CheckCFTypeRef theRef, "CFDate", "Constructor", "CFDateCreate"
    me.Constructor theRef
    
  Finally
    CoreFoundation.Release theRef
    
  #endif
  
End Sub

CFDate.Constructor:
Sub Constructor(d as Date)
  #if targetMachO
    Declare Function CFDateCreate Lib CarbonLib (allocator as Integer, at as Double) as Integer
    
    dim bundle as CFBundle
    dim p as MemoryBlock
    dim theRef as Integer
    
    Const CarbonFramework = "com.apple.Carbon"
    Const kCFAbsoluteTimeIntervalSince1904 = "kCFAbsoluteTimeIntervalSince1904"
    Const kCFAllocatorDefault = 0
    
    If d Is Nil then
      d = New Date
    End if
    
    bundle = new CFBundle(CarbonFramework)
    p = bundle.DataPointer(kCFAbsoluteTimeIntervalSince1904)
    theRef = CFDateCreate(kCFAllocatorDefault, d.TotalSeconds - p.DoubleValue(0))
    CoreFoundation.CheckCFTypeRef theRef, "CFDate", "Constructor", "CFDateCreate"
    me.Constructor theRef
    
  Finally
    CoreFoundation.Release theRef
    
  #endif
  
End Sub

CFDate.Operator_Convert:
Function Operator_Convert() As Date
  dim bundle as CFBundle
  dim p as MemoryBlock
  dim d as Date
  
  Const CarbonFramework = "com.apple.Carbon"
  Const kCFAbsoluteTimeIntervalSince1904 = "kCFAbsoluteTimeIntervalSince1904"
  
  bundle = new CFBundle(CarbonFramework)
  p = bundle.DataPointer(kCFAbsoluteTimeIntervalSince1904)
  d = new Date
  d.TotalSeconds = me.AbsoluteTime + p.DoubleValue(0)
  Return d
End Function

CFDate.AbsoluteTime:
Function AbsoluteTime() As Double
  #if targetMachO
    Declare Function CFDateGetAbsoluteTime Lib CarbonLib (theDate as Integer) as Double
    
    Return CFDateGetAbsoluteTime(me)
  #endif
End Function

CFDate.Constructor:
Sub Constructor(theRef as Integer)
  Super.Constructor theRef
  //works around an Rb bug.
End Sub

CFDictionary.Count:
Function Count() As Integer
  #if targetMachO
    Declare Function CFDictionaryGetCount Lib CarbonLib (theDict as Integer) as Integer
    
    Return CFDictionaryGetCount(me)
  #endif
End Function

CFDictionary.Value:
Function Value(key as Integer) As Integer
  #if targetMachO
    Declare Function CFDictionaryGetValueIfPresent Lib CarbonLib (theDict as Integer, key as Integer, ByRef value as Integer) as Boolean
    
    dim theValue as Integer
    
    If CFDictionaryGetValueIfPresent(me, key, theValue) then
      Return theValue
    Else
      Raise new KeyNotFoundException
    End if
  #endif
End Function

CFDictionary.HasKey:
Function HasKey(key as Integer) As Boolean
  #if targetMachO
    Declare Function CFDictionaryContainsKey Lib CarbonLib (theDict as Integer, key as Integer) as Boolean
    
    Return CFDictionaryContainsKey(me, key)
  #endif
End Function

CFDictionary.Key:
Function Key(index as Integer) As Integer
  #if targetMachO
    Declare Function CFDictionaryGetCount Lib CarbonLib (theDict as Integer) as Integer
    Declare Sub CFDictionaryGetKeysAndValues Lib CarbonLib (theDict as Integer, keys as Ptr, values as Integer)
    
    Const Null = 0
    
    If index < 0 or index > CFDictionaryGetCount(me) - 1 then
      Raise new OutOfBoundsException
    End if
    
    If me.keyList Is Nil then
      me.keyList = new MemoryBlock(4*CFDictionaryGetCount(me)) //if Count = 0 then guard clause raised an exception
      CFDictionaryGetKeysAndValues me, me.keyList, Null
    End if
    Return me.keyList.Long(4*index)
  #endif
End Function

CFDictionary.Constructor:
Sub Constructor(theKeys() as CFType, theValues() as CFType)
  #if targetMachO
    Declare Function CFDictionaryCreate Lib CarbonLib (allocator as Integer, keys as Ptr, values as Ptr, numValues as Integer, keyCallBacks as Ptr, valueCallBacks as Ptr) as Integer
    Declare Function CFDictionaryCreate Lib CarbonLib (allocator as Integer, keys as Integer, values as Integer, numValues as Integer, keyCallBacks as Ptr, valueCallBacks as Ptr) as Integer
    
    dim bundle as CFBundle
    dim keyBlock as MemoryBlock
    dim valueBlock as MemoryBlock
    dim keyCallbacks as MemoryBlock
    dim valueCallbacks as MemoryBlock
    dim theRef as Integer
    dim i as Integer
    
    Const kCFAllocatorDefault = 0
    Const CarbonFramework = "com.apple.Carbon"
    Const defaultKeyCallBacks = "kCFTypeDictionaryKeyCallBacks"
    Const defaultValueCallBacks = "kCFTypeDictionaryValueCallBacks"
    Const Null = 0
    
    if UBound(theKeys) <> UBound(theValues) then
      Raise new InvalidParameterException("Key count must equal value count.")
    End if
    
    bundle = new CFBundle(CarbonFramework)
    keyCallbacks = bundle.DataPointer(defaultKeyCallBacks)
    valueCallbacks = bundle.DataPointer(defaultValueCallBacks)
    
    If UBound(theKeys) > 0 then
      keyBlock = new MemoryBlock(4*(1 + UBound(theKeys)))
      valueBlock = new MemoryBlock(4*(1 + UBound(theValues)))
      For i = 0 to UBound(theKeys)
        keyBlock.Long(4*i) = theKeys(i)
        valueBlock.Long(4*i) = theValues(i)
      Next
      theRef = CFDictionaryCreate(kCFAllocatorDefault, keyBlock, valueBlock, 1 + UBound(theKeys), keyCallbacks, valueCallbacks)
    Else
      theRef = CFDictionaryCreate(kCFAllocatorDefault, Null, Null, 1 + UBound(theKeys), keyCallbacks, valueCallbacks)
    End if
    CoreFoundation.CheckCFTypeRef theRef, me.ClassName, "Constructor", "CFDictionaryCreate"
    me.Constructor theRef
    
  Finally
    CoreFoundation.Release theRef
    
  #endif
  
End Sub

CFDictionary.Constructor:
Sub Constructor(theDictionary as CFDictionary)
  #if targetMachO
    Declare Function CFDictionaryCreateCopy Lib CarbonLib (allocator as Integer, theDict as Integer) as Integer
    
    dim theRef as Integer
    dim noKeys(-1) as CFType, noValues(-1) as CFType
    
    Const kCFAllocatorDefault = 0
    
    If theDictionary Is Nil then
      me.Constructor(noKeys, noValues)
    Else
      theRef = CFDictionaryCreateCopy(kCFAllocatorDefault, me)
      CoreFoundation.CheckCFTypeRef theRef, me.ClassName, "Constructor", "CFDictionaryCreateCopy"
      me.Constructor theRef
    End if
    
  Finally
    CoreFoundation.Release theRef
    
  #endif
  
End Sub

CFMutableArray.Value:
Sub Value(index as Integer, Assigns theValue as Integer)
  #if targetMachO
    Declare Function CFArrayGetCount Lib CarbonLib (theArray as Integer) as Integer
    Declare Sub CFArraySetValueAtIndex Lib CarbonLib (theArray as Integer, idx as Integer, theVal as Integer)
    
    If index < 0 or index > CFArrayGetCount(me) - 1 then
      Raise new OutOfBoundsException
    End if
    
    CFArraySetValueAtIndex me, index, theValue
  #endif
End Sub

CFMutableArray.Constructor:
Sub Constructor()
  
  #if targetMachO
    Declare Function CFArrayCreateMutable Lib CarbonLib (allocator as Integer, capacity as Integer, callbacks as Ptr) as Integer
    
    dim carbonBundle as CFBundle
    dim p as MemoryBlock
    dim theRef as Integer
    
    Const kCFAllocatorDefault = 0
    Const CarbonFramework = "com.apple.Carbon"
    Const defaultCallBacks = "kCFTypeArrayCallBacks"
    Const unlimited = 0
    
    carbonBundle = new CFBundle(CarbonFramework)
    p = carbonBundle.DataPointer(defaultCallBacks)
    theRef = CFArrayCreateMutable(kCFAllocatorDefault, unlimited, p)
    CoreFoundation.CheckCFTypeRef theRef, "CFMutableArray", "Constructor", "CFArrayCreateMutable"
    me.Constructor theRef
    
  Finally
    CoreFoundation.Release theRef
    
  #endif
  
End Sub

CFMutableArray.Append:
Sub Append(theItem as CFType)
  #if targetMachO
    Declare Sub CFArrayAppendValue Lib CarbonLib (theArray as Integer, theValue as Integer)
    
    If theItem <> nil then
      CFArrayAppendValue me, theItem
    Else
      CFArrayAppendValue me, 0
    End if
  #endif
End Sub

CFMutableString.Constructor:
Sub Constructor(s as String)
  me.Constructor
  me.Append s
End Sub

CFMutableString.Append:
Sub Append(s as String)
  Declare Sub CFStringAppendCString Lib CarbonLib (theString as Integer, cStr as CString, encoding as Integer)
  
  Const kCFTextEncodingUnknown = &hffff
  
  If Encoding(s) <> nil then
    CFStringAppendCString me, s, s.Encoding.Code
  Else
    CFStringAppendCString me, s, kCFTextEncodingUnknown
  End if
End Sub

CFMutableString.Uppercase:
Sub Uppercase()
  #if TargetMachO
    Declare Sub CFStringUppercase Lib CarbonLib (theString as Integer, locale as Integer)
    Declare Function CFLocaleGetSystem Lib CarbonLib () as Integer
    
    dim systemLocale as Integer
    
    systemLocale = CFLocaleGetSystem()
    If systemLocale = 0 then
      Return
    End if
    CFStringUppercase me, systemLocale
  #endif
End Sub

CFMutableString.Lowercase:
Sub Lowercase()
  #if TargetMachO
    Declare Sub CFStringLowercase Lib CarbonLib (theString as Integer, locale as Integer)
    Declare Function CFLocaleGetSystem Lib CarbonLib () as Integer
    
    dim systemLocale as Integer
    
    systemLocale = CFLocaleGetSystem()
    If systemLocale = 0 then
      Return
    End if
    CFStringLowercase me, systemLocale
  #endif
End Sub

CFMutableString.Constructor:
Sub Constructor()
  #if targetMachO
    Declare Function CFStringCreateMutable Lib CarbonLib (alloc as Integer, maxLength as Integer) as Integer
    
    dim theRef as Integer
    
    theRef = CFStringCreateMutable(CoreFoundation.kCFAllocatorDefault, 0)
    CoreFoundation.CheckCFTypeRef theRef, "CFMutableString", "Constructor", "CFStringCreateMutable"
    me.Constructor(theRef)
    
  Finally
    CoreFoundation.Release theRef
    
  #endif
  
End Sub

CFNumber.IntegerValue:
Function IntegerValue() As Integer
  #if targetMachO
    Declare Function CFNumberGetValue Lib CarbonLib (number as Integer, theType as Integer, ByRef valuePtr as Integer) as Boolean
    
    dim theValue as Integer
    
    Const kCFNumberSInt32Type = 3
    
    If CFNumberGetValue(me, kCFNumberSInt32Type, theValue) then
      Return theValue
    Else
      Return theValue //but it's an approximate value
    End if
  #endif
End Function

CFNumber.DoubleValue:
Function DoubleValue() As Double
  #if targetMachO
    Declare Function CFNumberGetValue Lib CarbonLib (number as Integer, theType as Integer, ByRef valuePtr as Double) as Boolean
    
    dim theValue as Double
    
    Const kCFNumberDoubleType = 13
    
    if CFNumberGetValue(me, kCFNumberDoubleType, theValue) then
      Return theValue
    Else
      Return theValue //but it's an approximate value
    End if
  #endif
End Function

CFPreferences.Value:
Protected Function Value(key as CFString) As CFPropertyList
  #if targetMachO
    Declare Function CFPreferencesCopyAppValue Lib CarbonLib (key as Integer, appID as Integer) as Integer
    Declare Sub CFRelease Lib CarbonLib (cf as Integer)
    
    dim theRef as Integer
    dim theValue as CFPropertyList
    
    theRef = CFPreferencesCopyAppValue(key, kCurrentApplication)
    If theRef <> 0 then
      theValue = NewCFPropertyListObject(theRef, 0)
    Else
      theValue = nil
    End if
    
  Finally
    CoreFoundation.Release theRef
    Return theValue
    
  #endif
  
End Function

CFPreferences.Value:
Protected Sub Value(key as CFString, Assigns theValue as CFPropertyList)
  #if targetMachO
    Declare Sub CFPreferencesSetAppValue Lib CarbonLib (key as Integer, aValue as Integer, appID as Integer)
    
    CFPreferencesSetAppValue key, CFType(theValue), kCurrentApplication
  #endif
End Sub

CFPreferences.Save:
Protected Sub Save()
  #if targetMachO
    Declare Function CFPreferencesAppSynchronize Lib CarbonLib (appID as Integer) as Boolean
    
    If CFPreferencesAppSynchronize(kCurrentApplication) then
      //success
    Else
      //failure
    End if
  #endif
End Sub

CFPreferences.kCurrentApplication:
Private Function kCurrentApplication() As Integer
  #if targetMachO
    dim frameworkBundle as CFBundle
    dim p as MemoryBlock
    
    Const CarbonFramework = "com.apple.Carbon"
    
    frameworkBundle = new CFBundle(CarbonFramework)
    p = frameworkBundle.DataPointer("kCFPreferencesCurrentApplication")
    If p Is Nil then
      Return 0
    End if
    Return p.Long(0)
  #endif
End Function

CFPropertyList.Operator_Convert:
Function Operator_Convert() As Integer
  
End Function

CFString.Operator_Convert:
Function Operator_Convert() As String
  #if targetMachO
    Declare Function CFStringGetLength Lib CarbonLib (theString as Integer) as Integer
    Declare Function CFStringGetMaximumSizeForEncoding Lib CarbonLib (length as Integer, enc as Integer) as Integer
    Declare Function CFStringGetCString Lib CarbonLib (theString as Integer, buffer as Ptr, bufferSize as Integer, enc as Integer) as Boolean
    
    dim charCount as Integer
    dim maxSize as Integer
    dim buffer as MemoryBlock
    
    Const kCFStringEncodingUTF8 = &h08000100
    
    charCount = CFStringGetLength(me)
    maxSize = CFStringGetMaximumSizeForEncoding(charCount, kCFStringEncodingUTF8)
    buffer = new MemoryBlock(1 + maxSize) //one extra byte for CString terminator
    If CFStringGetCString(me, buffer, buffer.Size, kCFStringEncodingUTF8) then
      Return Left(DefineEncoding(buffer.StringValue(0, maxSize), Encodings.UTF8), charCount)
    Else
      Return ""
    End if
  #endif
End Function

CFString.Constructor:
Sub Constructor(s as String)
  #if targetMachO
    Declare Function CFStringCreateWithCString Lib CarbonLib (alloc as Integer, cStr as CString,encoding as Integer) as Integer
    Declare Sub CFRelease Lib CarbonLib (ref as Integer)
    
    dim theRef as Integer
    
    Const kCFAllocatorDefault = 0
    Const kCFStringEncodingInvalidId = &hffffffff
    
    If Encoding(s) <> nil then
      theRef = CFStringCreateWithCString(kCFAllocatorDefault, s, Encoding(s).code)
    Else
      theRef = CFStringCreateWithCString(kCFAllocatorDefault, s, kCFStringEncodingInvalidId)
    End if
    CoreFoundation.CheckCFTypeRef theRef, "CFString", "Constructor", "CFStringCreateWithCString"
    me.Constructor theRef
    
  Finally
    CoreFoundation.Release theRef
    
  #endif
  
End Sub

CFTimeZone.Constructor:
Sub Constructor(timeZoneName as CFString)
  #if targetMachO
    Declare Function CFTimeZoneCreateWithName Lib CarbonLib (allocator as Integer, name as Integer, tryAbbrev as Boolean) as Integer
    
    dim theRef as Integer
    
    Const kCFAllocatorDefault = 0
    
    If timeZoneName Is Nil then
      me.Constructor()
    Else
      theRef = CFTimeZoneCreateWithName(kCFAllocatorDefault, timeZoneName, true)
      CoreFoundation.CheckCFTypeRef theRef, "CFTimeZone", "Constructor", "CFTimeZoneCreateWithName"
      me.Constructor theRef
    End if
    
  Finally
    CoreFoundation.Release theRef
    
  #endif
  
End Sub

CFTimeZone.Name:
Function Name() As CFString
  #if targetMachO
    Declare Function CFTimeZoneGetName Lib CarbonLib (tz as Integer) as Integer
    
    dim theRef as Integer
    dim theName as CFString
    
    theRef = CFTimeZoneGetName(me)
    If theRef <> 0 then
      theName = new CFString(theRef)
    Else
      theName = new CFString("")
    End if
    Return theName
    
  #endif
  
End Function

CFTimeZone.IsDST:
Function IsDST(d as Date) As Boolean
  #if targetMachO
    Declare Function CFTimeZoneIsDaylightSavingsTime Lib CarbonLib (tz as Integer, at as Double) as Boolean
    
    dim theDate as CFDate
    
    If d Is Nil then
      d = new Date
    End if
    
    theDate = new CFDate(d)
    Return CFTimeZoneIsDaylightSavingsTime(me, theDate.AbsoluteTime)
  #endif
End Function

CFTimeZone.Constructor:
Sub Constructor()
  #if targetMachO
    Declare Function CFTimeZoneCopySystem Lib CarbonLib () as Integer
    
    dim theRef as Integer
    
    theRef = CFTimeZoneCopySystem()
    CoreFoundation.CheckCFTypeRef theRef, "CFTimeZone", "Constructor", "CFTimeZoneCopySystem"
    me.Constructor(theRef)
  #endif
End Sub

CFTimeZone.Abbreviation:
Function Abbreviation(d as Date) As String
  #if targetMachO
    Declare Function CFTimeZoneCopyAbbreviation Lib CarbonLib (tz as Integer, at as Double) as Integer
    
    dim abbrRef as Integer
    dim abbr as CFString
    dim theDate as CFDate
    
    If d Is Nil then
      d = new Date
    End if
    
    theDate = new CFDate(d)
    abbrRef = CFTimeZoneCopyAbbreviation(me, theDate.AbsoluteTime)
    If abbrRef <> 0 then
      abbr = new CFString(abbrRef)
    Else
      abbr = new CFString("")
    End if
    
  Finally
    CoreFoundation.Release abbrRef
    Return abbr
    
  #endif
  
End Function

CFTimeZone.Offset:
Function Offset(d as Date) As Double
  
  #if targetMachO
    Declare Function CFTimeZoneGetSecondsFromGMT Lib CarbonLib (tz as Integer, at as Double) as Double
    
    dim theDate as CFDate
    
    If d Is Nil then
      d = new Date
    End if
    
    theDate = new CFDate(d)
    Return CFTimeZoneGetSecondsFromGMT(me, theDate.AbsoluteTime)// value in seconds
  #endif
End Function

CFType.Constructor:
Sub Constructor(theRef as Integer)
  #if targetMachO
    Declare Function CFRetain Lib CarbonLib (ref as Integer) as Integer
    
    If theRef = 0 then
      Raise new CFTypeRefException(me.ClassName, "Constructor", "CFRetain")
    End if
    
    me.Ref = CFRetain(theRef)
    CoreFoundation.CheckCFTypeRef me.Ref, me.ClassName, "Constructor", "CFRetain"
  #endif
End Sub

CFType.Destructor:
Sub Destructor()
  #if targetMachO
    Declare Sub CFRelease Lib CarbonLib (ref as Integer)
    
    If me.Ref <> 0 then
      CFRelease me.Ref
      me.Ref = 0
    End if
  #endif
End Sub

CFType.Equals:
Function Equals(theObj as CFType) As Boolean
  #if targetMachO
    Declare Function CFEqual Lib CarbonLib (cf1 as Integer, cf2 as Integer) as Boolean
    
    Return CFEqual(me, theObj)
  #endif
End Function

CFType.TypeID:
Function TypeID() As Integer
  #if targetMachO
    Declare Function CFGetTypeID Lib CarbonLib (cf as Integer) as Integer
    
    Return CFGetTypeID(me.Ref)
  #endif
End Function

CFType.Description:
Function Description() As CFString
  #if targetMachO
    Declare Function CFCopyDescription Lib CarbonLib (cf as Integer) as Integer
    
    dim descriptionRef as Integer
    dim theDescription as CFString
    
    descriptionRef = CFCopyDescription(me.Ref)
    If descriptionRef <> 0 then
      theDescription = new CFString(descriptionRef)
    Else
      theDescription = new CFString("")
    End if
    
  Finally
    CoreFoundation.Release descriptionRef
    Return theDescription
    
  #endif
  
End Function

CFType.TypeDescription:
Function TypeDescription() As CFString
  #if targetMachO
    Declare Function CFCopyTypeIDDescription Lib CarbonLib (cf as Integer) as Integer
    
    dim descriptionRef as Integer
    dim theDescription as CFString
    
    descriptionRef = CFCopyTypeIDDescription(me.Ref)
    If descriptionRef <> 0 then
      theDescription = new CFString(descriptionRef)
    Else
      theDescription = new CFString("")
    End if
    
  Finally
    CoreFoundation.Release descriptionRef
    Return theDescription
    
  #endif
  
End Function

CFType.RefCount:
Function RefCount() As Integer
  #if targetMachO
    Declare Function CFGetRetainCount Lib CarbonLib (cf as Integer) as Integer
  #endif
  
  #if targetMachO
    Return CFGetRetainCount(me.Ref)
  #endif
End Function

CFType.Hash:
Function Hash() As Integer
  #if targetMachO
    Declare Function CFHash Lib CarbonLib (cf as Integer) as Integer
    
    Return CFHash(me.Ref)
  #endif
End Function

CFType.Operator_Convert:
Function Operator_Convert() As Integer
  Return me.Ref
End Function

CFType.Show:
Sub Show()
  #if targetMachO
    Declare Sub CFShow Lib CarbonLib (obj as Integer)
    
    CFShow me
  #endif
End Sub

CFTypeRefException.Constructor:
Sub Constructor(theClass as String, theMethod as String, theCFFunction as String)
  me.pClassName = theClass
  me.pMethodName = theMethod
  me.pFunctionName = theCFFunction
End Sub

CFTypeRefException.ClassName:
Function ClassName() As String
  Return me.pClassName
End Function

CFTypeRefException.MethodName:
Function MethodName() As String
  Return me.pMethodName
End Function

CFTypeRefException.FunctionName:
Function FunctionName() As String
  Return me.pFunctionName
End Function

CFTypeRefException.Log:
Sub Log()
  System.Log System.LogLevelError,  me.ClassName + "." + me.MethodName + ": " + me.FunctionName + " failed."
End Sub

CFURL.Constructor:
Sub Constructor(theURL as String)
  me.Constructor Nil, theURL
End Sub

CFURL.StringValue:
Function StringValue() As CFString
  #if targetMachO
    Declare Function CFURLGetString Lib CarbonLib (anURL as Integer) as Integer
    
    dim stringRef as Integer
    dim cfStr as CFString
    
    stringRef = CFURLGetString(me)
    CoreFoundation.CheckCFTypeRef stringRef, "CFURL", "StringValue", "CFURLGetString"
    cfStr = new CFString(stringRef)
    
  Exception oops as CFTypeRefException
    cfStr = new CFString("")
    
  Finally
    CoreFoundation.Release stringRef
    Return cfStr
    
  #endif
  
End Function

CFURL.Scheme:
Function Scheme() As CFString
  
  #if targetMachO
    dim schemeRef as Integer
    dim scheme as CFString
    
    Declare Function CFURLCopyScheme Lib CarbonLib (anURL as Integer) as Integer
    
    schemeRef = CFURLCopyScheme(me)
    CoreFoundation.CheckCFTypeRef schemeRef, "CFURL", "Scheme", "CFURLCopyScheme"
    scheme = new CFString(schemeRef)
    
  Exception theError as CFTypeRefException
    scheme = new CFString("")
    
  Finally
    CoreFoundation.Release schemeRef
    Return scheme
    
  #endif
  
End Function

CFURL.NetLocation:
Function NetLocation() As CFString
  
  #if targetMachO
    Declare Function CFURLCopyNetLocation Lib CarbonLib (anURL as Integer) as Integer
    
    dim netLocationRef as Integer
    dim netLocation as CFString
    
    netLocationRef = CFURLCopyNetLocation(me)
    CoreFoundation.CheckCFTypeRef netLocationRef, "CFURL", "NetLocation", "CFURLCopyNetLocation"
    netLocation = new CFString(netLocationRef)
    
  Exception oops as CFTypeRefException
    netLocation = new CFString("")
    
  Finally
    CoreFoundation.Release netLocationRef
    Return netLocation
    
  #endif
  
End Function

CFURL.Constructor:
Sub Constructor(f as FolderItem)
  
  #if targetMachO
    Declare Function CFURLCreateFromFSRef Lib CarbonLib (allocator as Integer, fsRef as Ptr) as Integer
    Declare Function CFURLCreateWithBytes Lib CarbonLib (allocator as Integer, relativeURLBytes as CString, length as Integer, encoding as Integer, baseURL as Integer) as Integer
    
    dim theFSRef as FSRef
    dim parentURL as CFURL
    dim theURLRef as Integer
    
    If f Is Nil then
      Raise new InvalidParameterException("CFURL", "Constructor", "f cannot be nil.")
    End if
    
    If f.Exists then
      theFSRef = new FSRef(f)
      theURLRef = CFURLCreateFromFSRef(CoreFoundation.kCFAllocatorDefault, theFSRef)
      CoreFoundation.CheckCFTypeRef theURLRef, "CFURL", "Constructor", "CFURLCreateFromFSRef"
    Else
      If (f.Parent Is Nil OR NOT f.Parent.Exists) then
        //the impossible has happened
        Raise new RuntimeException
      End if
      parentURL = new CFURL(f.Parent)
      theURLRef = CFURLCreateWithBytes(CoreFoundation.kCFAllocatorDefault, f.Name, LenB(f.Name), Encoding(f.Name).code, parentURL)
      CoreFoundation.CheckCFTypeRef theURLRef, "CFURL", "Constructor", "CFURLCreateWithBytes"
    End if
    me.Constructor theURLRef
    
  Finally
    CoreFoundation.Release theURLRef
    
  #endif
  
End Sub

CFURL.Constructor:
Sub Constructor(baseURL as CFURL, relativeURL as String)
  #if targetMachO
    Declare Function CFURLCreateWithBytes Lib CarbonLib (allocator as Integer, URLBytes as CString, length as Integer, encoding as Integer, baseURL as Integer) as Integer
    
    dim theURLRef as Integer
    dim baseURLRef as Integer
    
    Const kCFAllocatorDefault = 0
    Const kCFStringEncodingInvalidId = &hffffffff
    
    If relativeURL <> "" then
      If baseURL Is Nil then
        baseURLRef = 0
      Else
        baseURLRef = baseURL
      End if
      
      If Encoding(relativeURL) <> nil then
        theURLRef = CFURLCreateWithBytes(kCFAllocatorDefault, relativeURL, LenB(relativeURL), Encoding(relativeURL).Code, baseURLRef )
      Else
        theURLRef = CFURLCreateWithBytes(kCFAllocatorDefault, relativeURL, LenB(relativeURL), kCFStringEncodingInvalidId, baseURLRef )
      End if
      CoreFoundation.CheckCFTypeRef theURLRef, "CFURL", "Constructor", "CFURLCreateWithBytes"
    Else
      theURLRef =  baseURL
    End if
    me.Constructor(theURLRef)
    
  Finally
    CoreFoundation.Release theURLRef
    
  #endif
  
End Sub

CFURL.AbsoluteURL:
Function AbsoluteURL() As CFURL
  #if targetMachO
    Declare Function CFURLCopyAbsoluteURL Lib CarbonLib (relativeURL as Integer) as Integer
    
    Dim urlRef as Integer
    dim newURL as CFURL
    dim theRef as Integer
    
    theRef = me
    urlRef = CFURLCopyAbsoluteURL(theRef)
    If urlRef = 0 then
      Return Nil
    End if
    newURL = new CFURL(urlRef)
    
  Finally
    CoreFoundation.Release urlRef
    Return newURL
    
  #endif
  
End Function

CFURL.BaseURL:
Function BaseURL() As CFURL
  #if targetMachO
    Declare Function CFURLGetBaseURL Lib CarbonLib (anURL as Integer) as Integer
    
    dim urlRef as Integer
    dim theBaseURL as CFURL
    
    urlRef = CFURLGetBaseURL(me)
    If urlRef <> 0 then
      theBaseURL = new CFURL(urlRef)
    Else
      theBaseURL = nil
    End if
    
  Finally
    CoreFoundation.Release urlRef
    Return theBaseURL
    
  #endif
  
End Function

CFURL.IsDecomposable:
Function IsDecomposable() As Boolean
  #if targetMachO
    Declare Function CFURLCanBeDecomposed Lib CarbonLib (anURL as Integer) as Boolean
    
    Return CFURLCanBeDecomposed(me)
  #endif
End Function

CFURL.Path:
Function Path() As String
  #if targetMachO
    Declare Function CFURLGetFileSystemRepresentation Lib CarbonLib (url as Integer, resolveAgainstBase as Boolean, buffer as Ptr, maxBufLen as Integer) as Boolean
    
    dim buffer as MemoryBlock
    
    buffer = new MemoryBlock(128)
    Do
      If CFURLGetFileSystemRepresentation(me, true, buffer, buffer.Size) then
        Exit
      Else
        buffer.Size = 2*buffer.Size
      End if
    Loop Until buffer.Size >= 131072
    Return DefineEncoding(buffer.CString(0), Encodings.SystemDefault)
  #endif
End Function

CFURL.Item:
Function Item() As FolderItem
  #if targetMachO
    dim theItem as FolderItem
    dim itemFSRef as FSRef
    dim fileNameRef as Integer
    dim fileName as CFString
    dim parentURLRef as Integer
    dim parentURL as CFURL
    dim parentFSRef as FSRef
    dim parentItem as FolderItem
    
    Declare Function CFURLGetFSRef Lib CarbonLib (url as Integer, fsRef as Ptr) as Boolean
    Declare Function CFURLCopyLastPathComponent Lib CarbonLib (url as Integer) as Integer
    Declare Function CFURLCreateCopyDeletingLastPathComponent Lib CarbonLib (allocator as Integer, url as Integer) as Integer
    
    itemFSRef = new FSRef
    If CFURLGetFSRef(me, itemFSRef) then
      theItem = itemFSRef
    Else
      fileNameRef = CFURLCopyLastPathComponent(me)
      CoreFoundation.CheckCFTypeRef fileNameRef, "CFURL", "Item", "CFURLCopyLastPathComponent"
      fileName = new CFString(fileNameRef)
      parentURLRef = CFURLCreateCopyDeletingLastPathComponent(CoreFoundation.kCFAllocatorDefault, me)
      CoreFoundation.CheckCFTypeRef parentURLRef , "CFURL", "Item", "CFURLCreateCopyDeletingLastPathComponent"
      parentURL = new CFURL(parentURLRef)
      parentFSRef = new FSRef
      If CFURLGetFSRef(me, parentFSRef) then
        parentItem = parentFSRef
        If parentItem <> nil then
          theItem = parentItem.Child(fileName)
        Else
          theItem = nil
        End if
      Else
        theItem = Nil
      End if
    End if
    
  Exception oops as CFTypeRefException
    theItem = Nil
    
  Finally
    CoreFoundation.Release fileNameRef
    CoreFoundation.Release parentURLRef
    Return theItem
    
  #endif
  
End Function

CoreFoundation.UnescapeURL:
Function UnescapeURL(theURL as String, escapeList as String) As String
  #if targetMachO
    dim ref as Integer
    dim theURLString as CFString
    dim escapeRef as CFString
    dim theResultRef as Integer
    dim theResult as CFString
    
    Const kCFAllocatorDefault = 0
    
    Declare Function CFURLCreateStringByReplacingPercentEscapes Lib CarbonLib (allocator as Integer, originalString as Integer, charactersToLeaveEscaped as Integer) as Integer
    
    If Encoding(theURL) Is Nil then
      Raise new InvalidParameterException("theURL must have non-nil encoding.")
    Else
      theURL = ConvertEncoding(theURL, Encodings.UTF8)
    End if
    If Encoding(escapeList) Is Nil then
      Raise new InvalidParameterException("escapeList must have non-nil encoding.")
    Else
      escapeList = ConvertEncoding(escapeList, Encodings.UTF8)
    End if
    
    theURLString = new CFString(theURL)
    escapeRef = new CFString(escapeList)
    theResultRef = CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault, theURLString, escapeRef)
    CoreFoundation.CheckCFTypeRef theResultRef, "CoreFoundation", "EscapeURL", "CFURLCreateStringByReplacingPercentEscapes"
    theResult  = new CFString(theResultRef)
    
  Exception oops as CFTypeRefException
    theResult = new CFString("")
    
  Finally
    CoreFoundation.Release theResultRef
    Return theResult
    
  #endif
  
End Function

CoreFoundation.EscapeURL:
Function EscapeURL(theURL as String, unescapeList as String, escapeList as String) As String
  #if targetMachO
    dim urlRef as CFString
    dim unescapeRef as CFString
    dim escapeRef as CFString
    dim escapedStringRef as Integer
    dim escapedString as CFString
    
    Const kCFAllocatorDefault = 0
    
    Declare Function CFURLCreateStringByAddingPercentEscapes Lib CarbonLib (allocator as Integer, originalString as Integer, unescape as Integer, escape as Integer, enc as Integer) as Integer
    
    If Encoding(theURL) Is Nil then
      Raise new InvalidParameterException("theURL must have non-nil encoding.")
    Else
      theURL = ConvertEncoding(theURL, Encodings.UTF8)
    End if
    If Encoding(unescapeList) Is Nil then
      Raise new InvalidParameterException("unescapeList must have non-nil encoding.")
    Else
      unescapeList = ConvertEncoding(unescapeList, Encodings.UTF8)
    End if
    If Encoding(escapeList) Is Nil then
      Raise new InvalidParameterException("escapeList must have non-nil encoding.")
    Else
      escapeList = ConvertEncoding(escapeList, Encodings.UTF8)
    End if
    
    urlRef = new CFString(theURL)
    unescapeRef = new CFString(unescapeList)
    escapeRef = new CFString(escapeList)
    escapedStringRef = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, urlRef, unescapeRef, escapeRef, Encodings.UTF8.code)
    CoreFoundation.CheckCFTypeRef escapedStringRef, "CoreFoundation", "EscapeURL", "CFURLCreateStringByAddingPercentEscapes"
    escapedString = new CFString(escapedStringRef)
    
  Exception oops as CFTypeRefException
    escapedString = new CFString("")
    
  Finally
    CoreFoundation.Release escapedStringRef
    Return escapedString
    
  #endif
  
End Function

CoreFoundation.XML:
Function XML(Extends theObj as CFPropertyList) As String
  #if targetMachO
    Declare Function CFPropertyListCreateXMLData Lib CarbonLib (allocator as Integer, propertyList as Integer) as Integer
    Declare Sub CFRelease Lib CarbonLib (cf as Integer)
    
    dim dataRef as Integer
    dim theData as CFData
    dim theXML as String
    
    Const kCFAllocatorDefault = 0
    
    dataRef = CFPropertyListCreateXMLData(kCFAllocatorDefault, theObj)
    If dataRef = 0 then
      Return ""
    End if
    theData = new CFData(dataRef)
    theXML = DefineEncoding(theData.Data, Encodings.UTF8)
    
  Finally
    CoreFoundation.Release dataRef
    Return theXML
    
  #endif
  
End Function

CoreFoundation.NewCFPropertyList:
Function NewCFPropertyList(theXML as String, mutability as Integer) As CFPropertyList
  #if targetMachO
    Declare Function CFPropertyListCreateFromXMLData Lib CarbonLib (allocator as Integer, xmlData as Integer, mutabilityOptions as Integer, errorString as Integer) as Integer
    Declare Sub CFRelease Lib CarbonLib (cf as Integer)
    
    dim theData as CFData
    dim theRef as Integer
    dim pList as CFPropertyList
    
    Const kCFAllocatorDefault = 0
    Const Null = 0
    
    theData = new CFData(theXML)
    theRef = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, theData, mutability, Null)
    If theRef = 0 then
      Return nil
    End if
    pList = NewCFPropertyListObject(theRef, mutability)
    
  Finally
    CoreFoundation.Release theRef
    Return pList
    
  #endif
  
End Function

CoreFoundation.Clone:
Function Clone(Extends theObj as CFPropertyList, mutability as Integer) As CFPropertyList
  #if targetMachO
    Declare Function CFPropertyListCreateDeepCopy Lib CarbonLib (allocator as Integer, propertyList as Integer, mutabilityOption as Integer) as Integer
    Declare Sub CFRelease Lib CarbonLib (cf as Integer)
    
    dim theRef as Integer
    dim pListTypeID as Integer
    dim pList as CFPropertyList
    
    Const kCFAllocatorDefault = 0
    
    theRef = CFPropertyListCreateDeepCopy(kCFAllocatorDefault, theObj, mutability)
    If theRef <> 0 then
      pList = NewCFPropertyListObject(theRef, mutability)
    Else
      pList = nil
    End if
    
  Finally
    Release theRef
    Return pList
    
  #endif
  
End Function

CoreFoundation.IsValid:
Function IsValid(Extends theObj as CFPropertyList, listFormat as Integer) As Boolean
  #if targetMachO
    Declare Function CFPropertyListIsValid Lib CarbonLib (cf as Integer, fmt as Integer) as Boolean
    
    Return CFPropertyListIsValid(theObj, listFormat)
  #endif
End Function

CoreFoundation.NewCFPropertyListObject:
Function NewCFPropertyListObject(theRef as Integer, mutability as Integer) As CFPropertyList
  #if targetMachO
    Declare Function CFGetTypeID Lib CarbonLib (cf as Integer) as Integer
    Declare Function CFStringGetTypeID Lib CarbonLib () as Integer
    Declare Function CFNumberGetTypeID Lib CarbonLib () as Integer
    Declare Function CFBooleanGetTypeID Lib CarbonLib () as Integer
    Declare Function CFDateGetTypeID Lib CarbonLib () as Integer
    Declare Function CFDataGetTypeID Lib CarbonLib () as Integer
    Declare Function CFArrayGetTypeID Lib CarbonLib () as Integer
    Declare Function CFDictionaryGetTypeID Lib CarbonLib () as Integer
    Declare Function CFRetain Lib CarbonLib (cf as Integer) as Integer
    
    dim pListTypeID as Integer
    dim pList as CFPropertyList
    
    Const kCFPropertyListImmutable = 0
    Const kCFPropertyListMutableContainers = 1
    Const kCFPropertyListMutableContainersAndLeaves = 2
    
    If theRef = 0 then
      Return nil
    End if
    
    theRef = CFRetain(theRef)
    pListTypeID = CFGetTypeID(theRef)
    If pListTypeID = CFStringGetTypeID then
      If mutability = kCFPropertyListMutableContainersAndLeaves then
        pList = new CFMutableString(theRef)
      Else
        pList = new CFString(theRef)
      End if
    ElseIf pListTypeID = CFNumberGetTypeID then
      pList = new CFNumber(theRef)
    ElseIf pListTypeID = CFBooleanGetTypeID then
      pList = new CFBoolean(theRef)
    ElseIf pListTypeID = CFDateGetTypeID then
      pList = new CFDate(theRef)
    ElseIf pListTypeID = CFDataGetTypeID then
      If mutability = kCFPropertyListMutableContainersAndLeaves then
        pList = new CFMutableData(theRef)
      Else
        pList = new CFData(theRef)
      End if
    ElseIf pListTypeID = CFArrayGetTypeID then
      If mutability = kCFPropertyListImmutable then
        pList = new CFArray(theRef)
      Else
        pList = new CFMutableArray(theRef)
      End if
    ElseIf pListTypeID = CFDictionaryGetTypeID then
      If mutability = kCFPropertyListImmutable then
        pList = new CFDictionary(theRef)
      Else
        pList = new CFMutableDictionary(theRef)
      End if
    Else
      pList = nil
    End if
    
  Finally
    CoreFoundation.Release theRef
    Return pList
    
  #endif
  
End Function

CoreFoundation.NewCFNumber:
Function NewCFNumber(theValue as Integer) As CFNumber
  #if targetMachO
    Declare Function CFNumberCreate Lib CarbonLib (allocator as Integer, theType as Integer, ByRef valuePtr as Integer) as Integer
    Declare Sub CFRelease Lib CarbonLib (cf as Integer)
    
    dim theRef as Integer
    dim theNumber as CFNumber
    
    Const kCFNumberSInt32Type = 3
    
    theRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, theValue)
    CoreFoundation.CheckCFTypeRef theRef, "CoreFoundation", "NewCFNumber", "CFNumberCreate"
    theNumber = new CFNumber(theRef)
    
  Finally
    Release theRef
    Return theNumber
    
  #endif
  
End Function

CoreFoundation.NewCFNumber:
Function NewCFNumber(theValue as Double) As CFNumber
  #if targetMachO
    Declare Function CFNumberCreate Lib CarbonLib (allocator as Integer, theType as Integer, ByRef valuePtr as Double) as Integer
    Declare Sub CFRelease Lib CarbonLib (cf as Integer)
    
    dim theRef as Integer
    dim theValueCopy as Double
    dim theNumber as CFNumber
    
    Const kCFNumberDoubleType = 13
    
    theRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, theValueCopy)
    CoreFoundation.CheckCFTypeRef theRef, "CoreFoundation", "NewCFNumber", "CFNumberCreate"
    theNumber = new CFNumber(theRef)
    
  Finally
    Release theRef
    Return theNumber
    
  #endif
  
End Function

CoreFoundation.CopyContents:
Sub CopyContents(sourceParent as FolderItem, destinationParent as FolderItem)
  dim i as Integer
  dim theItem as FolderItem
  
  If NOT sourceParent.Exists then
    Return
  End if
  If Not sourceParent.Directory then
    Return
  End if
  If destinationParent Is Nil then
    Return
  End if
  If NOT destinationParent.Exists then
    Return
  End if
  If NOT destinationParent.Directory then
    Return
  End if
  
  For i = 1 to sourceParent.Count
    theItem = sourceParent.TrueItem(i)
    If theItem <> nil then
      If theItem.Directory then
        destinationParent.Child(theItem.Name).CreateAsFolder
        CopyContents theItem, destinationParent.Child(theItem.Name)
      Else
        theItem.CopyFileTo destinationParent.Child(theItem.Name)
        if theItem.LastErrorCode <> 0 then
          //handle error
        End if
      End if
    Else
      //a problem occurred
    End if
  Next
End Sub

CoreFoundation.CurrentVersion:
Function CurrentVersion() As Double
  #if targetMachO
    dim frameworkBundle as CFBundle
    dim p as MemoryBlock
    
    Const CarbonFramework = "com.apple.Carbon"
    Const kCFCoreFoundationVersionNumber = "kCFCoreFoundationVersionNumber"
    
    frameworkBundle = new CFBundle(CarbonFramework)
    p = frameworkBundle.DataPointer(kCFCoreFoundationVersionNumber)
    
  Exception oops as CFTypeRefException
    p = new MemoryBlock(8)
    
  Finally
    Return p.DoubleValue(0)
    
  #endif
  
End Function

CoreFoundation.TextEncodingList:
Protected Function TextEncodingList() As TextEncoding()
  #if targetMachO
    dim m as MemoryBlock
    dim i as Integer
    dim encodingList(-1) as TextEncoding
    
    Const kCFStringEncodingInvalidId = &hffffffff
    
    Declare Function CFStringGetListOfAvailableEncodings Lib CarbonLib () as Ptr
    
    m = CFStringGetListOfAvailableEncodings
    If m <> Nil then
      i = 0
      While m.Long(i) <> kCFStringEncodingInvalidId
        encodingList.Append Encodings.GetFromCode(m.Long(i))
        i = i + 4
      Wend
    Else
      //
    End if
    Return encodingList
  #endif
  
End Function

CoreFoundation.TimeZoneNameList:
Protected Function TimeZoneNameList() As String()
  #if targetMachO
    Declare Function CFTimeZoneCopyKnownNames Lib CarbonLib () as Integer
    Declare Function CFGetRetainCount Lib CarbonLib (cf as Integer) as Integer
    
    dim theRef as Integer
    dim theArray as CFArray
    dim i, N as Integer
    dim theList(-1) as String
    
    theRef = CFTimeZoneCopyKnownNames()
    If theRef = 0 then
      Return theList
    End if
    theArray = new CFArray(theRef)
    N = theArray.Count - 1
    For i = 0 to N
      If theArray.Value(i) <> 0 then
        theList.Append new CFString(theArray.Value(i))
      End if
    Next
    
  Finally
    Release theRef
    Return theList
    
  #endif
  
End Function

CoreFoundation.Release:
Protected Sub Release(theRef as Integer)
  #if targetMachO
    Declare Sub CFRelease Lib CarbonLib (cf as Integer)
    
    If theRef <> 0 then
      CFRelease theRef
    Else
      //passing 0 to CFRelease is ver' bad
    End if
  #endif
End Sub

CoreFoundation.SystemTimeZone:
Protected Function SystemTimeZone() As CFTimeZone
  #if targetMachO
    dim theRef as Integer
    dim theTimeZone as CFTimeZone
    
    Declare Function CFTimeZoneCopySystem Lib CarbonLib () as Integer
    
    theRef = CFTimeZoneCopySystem()
    CoreFoundation.CheckCFTypeRef theRef, "CoreFoundation", "SystemTimeZone", "CFTimeZoneCopySystem"
    theTimeZone = new CFTimeZone(theRef)
    
  Finally
    Release theRef
    Return theTimeZone
    
  #endif
  
End Function

CoreFoundation.CheckCFTypeRef:
Protected Sub CheckCFTypeRef(theRef as Integer, theClass as String, theMethod as String, theFunction as String)
  If theRef = 0 then
    Raise new CFTypeRefException(theClass, theMethod, theFunction)
  End if
End Sub

FileManager.GetUserPrivileges:
Protected Function GetUserPrivileges(theFSRef as MemoryBlock) As Integer
  #if targetMacOS
    dim OSErr as Integer
    dim catalogBitmap as Integer
    dim catalogInfo as FSCatalogInfo
    
    Const kFSCatInfoUserPrivs = &h00020000
    Const Null = 0
    
    Declare Function FSGetCatalogInfo Lib InterfaceLib (ref as Ptr, whichInfo as Integer, catalogInfo as Ptr, outName as Integer, fsSpec as Integer, parentRef as Integer) as Short
    
    If theFSRef Is Nil then
      Raise new NilObjectException
    End if
    
    catalogBitmap = Bitwise.BitOr(0, kFSCatInfoUserPrivs)
    catalogInfo = new FSCatalogInfo
    OSErr = FSGetCatalogInfo(theFSRef, catalogBitmap, catalogInfo, Null, Null, Null)
    If OSErr = 0 then
      Return catalogInfo.Byte(13)
    Else
      Return 0
    End if
  #endif
End Function

FileManager.Swap:
Protected Sub Swap(f as FolderItem, g as FolderItem)
  
  #if TargetMacOS
    dim OSError as Integer
    dim fRef, gRef as FSRef
    dim temp as FolderItem
    dim fCatalogInfo, gCatalogInfo as FSCatalogInfo
    dim catalogInfoFlags as Integer
    dim error as RuntimeException
    dim i as Integer
    
    Const kFSCatInfoContentMod = &h00000040
    Const kFSCatInfoAttrMod = &h00000080
    Const kFSCatInfoSettableInfo = &h00001FE3
    Const Null = 0
    
    If f Is Nil or g Is Nil then
      Raise new NilObjectException
    End if
    
    Declare Function FSGetCatalogInfo Lib InterfaceLib (ref as Ptr, whichInfo as Integer, catalogInfo as Ptr, outName as Integer, fsSpec as Integer, parentRef as Integer) as Short
    Declare Function FSSetCatalogInfo Lib InterfaceLib (ref as Ptr, whichInfo as Integer, catalogInfo as Ptr) as Short
    
    fRef = new FSRef(f)
    gRef = new FSRef(g)
    catalogInfoFlags = kFSCatInfoSettableInfo
    catalogInfoFlags = Bitwise.BitAnd(kFSCatInfoSettableInfo, Bitwise.OnesComplement(Bitwise.BitOr(kFSCatInfoAttrMod, kFSCatInfoContentMod)))
    fCatalogInfo = new FSCatalogInfo
    OSError = FSGetCatalogInfo(fRef, catalogInfoFlags, fCatalogInfo, Null, Null, Null)
    If OSError <> 0 then
      Raise new MacOSException("FSGetCatalogInfo", OSError)
    End if
    gCatalogInfo = new FSCatalogInfo
    OSError = FSGetCatalogInfo(gRef, catalogInfoFlags, gCatalogInfo, Null, Null, Null)
    If OSError <> 0 then
      Raise new MacOSException("FSGetCatalogInfo", OSError)
    End if
    
    For i = 1 to 10
      temp = GetTempFile(f.Parent)
      If temp <> nil and NOT temp.Exists then
        Exit
      End if
    Next
    If temp Is Nil or temp.Exists then
      error = new RuntimeException
      error.Message = "Unable to create temp file."
      Raise error
    End if
    f.MoveFileTo temp
    If f.LastErrorCode <> 0 or f.Exists or NOT temp.Exists then
      error = new RuntimeException
      error.Message = "FolderItem.MoveFileTo failed."
      Raise error
    End if
    g.MoveFileTo f
    If g.LastErrorCode <> 0 or g.Exists or NOT f.Exists then
      error = new RuntimeException
      error.Message = "FolderItem.MoveFileTo failed."
      Raise error
    End if
    temp.MoveFileTo g
    If temp.LastErrorCode <> 0 or temp.Exists or NOT g.Exists then
      error = new RuntimeException
      error.Message = "FolderItem.MoveFileTo failed."
      Raise error
    End if
    
    //we need to recreate the FSRefs
    fRef = new FSRef(f)
    gRef = new FSRef(g)
    OSError = FSSetCatalogInfo(fRef, catalogInfoFlags , fCatalogInfo)
    If OSError <> 0 then
      Raise new MacOSException("FSSetCatalogInfo", OSError)
    End if
    OSError = FSSetCatalogInfo(gRef, catalogInfoFlags , gCatalogInfo)
    If OSError <> 0 then
      Raise new MacOSException("FSSetCatalogInfo", OSError)
    End if
  #endif
  
End Sub

FileManager.GetTempFile:
Protected Function GetTempFile(parentFolder as FolderItem) As FolderItem
  #if targetMacOS
    dim tempFile as FolderItem
    
    If parentFolder Is Nil or NOT parentFolder.Directory then
      Return nil
    End if
    
    tempFile = parentFolder.Child("Temp" + Format(Rnd, "000000000000"))
    Return tempFile
  #endif
End Function

FileManager.VolumeSupportsFSExchangeObjects:
Protected Function VolumeSupportsFSExchangeObjects(f as FolderItem) As Boolean
  #if TargetMacOS
    Declare Function PBHGetVolParmsSync Lib InterfaceLib (paramBlock as Ptr) as Short
    
    dim OSError as Integer
    dim paramBlock as HIOParam
    dim infoBuffer as GetVolParmsBuffer
    
    Const bSupportsFSExchangeObjects = 8
    
    If f Is Nil then
      Raise new NilObjectException
    End if
    
    paramBlock = new HIOParam
    paramBlock.Short(22) = f.MacVRefNum
    infoBuffer = new GetVolParmsBuffer
    paramBlock.Ptr(32) = infoBuffer
    paramBlock.Long(36) = infoBuffer.Size
    OSError = PBHGetVolParmsSync(paramBlock)
    If OSError <> 0 then
      Return False //?
    End if
    Return Bitwise.BitAnd(infoBuffer.Long(20), bSupportsFSExchangeObjects) <> 0
  #endif
End Function

FileManager.ExchangeObjects:
Protected Sub ExchangeObjects(f as FolderItem, g as FolderItem)
  #if TargetMacOS
    dim OSError as Integer
    dim fRef, gRef as MemoryBlock
    dim error as RuntimeException
    
    If f Is Nil or g Is Nil then
      Raise new NilObjectException
    End if
    
    Declare Function FSExchangeObjects Lib InterfaceLib (f1 as Ptr, f2 as Ptr) as Integer
    
    fRef = new FSRef(f)
    gRef = new FSRef(g)
    OSError= FSExchangeObjects(fRef, gRef)
    If OSError <> 0 then
      Raise new MacOSException("FSExchangeObjects", OSError)
    End if
  #endif
End Sub

FileManager.GetVolumeRef:
Function GetVolumeRef(index as Integer) As Integer
  #if targetMacOS
    dim volInfo as INteger//MemoryBlock
    dim OSError as Integer
    
    Declare Function FSGetVolumeInfo Lib InterfaceLib (volume as Short, volumeIndex as Integer, ByRef actualVolume as Integer, whichInfo as Integer, info as Integer, volumeName as Integer, rootDirectory as Integer) as Short
    
    'volInfo = new MemoryBlock(2)
    OSError = FSGetVolumeInfo(0, index, volInfo, 0, 0, 0, 0)
    Return volInfo\65536
  #endif
End Function

FileManager.VolumeHasOpenFiles:
Protected Function VolumeHasOpenFiles(f as FolderItem) As Boolean
  #if targetMacOS
    dim OSError as Integer
    dim info as FSVolumeInfo
    dim flags as Integer
    
    Const kFSVolInfoFlags = &h2000
    Const kFSVolFlagFilesOpenMask = &h0040
    Const Null = 0
    
    Declare Function FSGetVolumeInfo Lib InterfaceLib (volume as Short, volumeIndex as Integer, actualVolume as Integer, whichInfo as Integer, info as Ptr, volumeName as Integer, rootDirectory as Integer) as Short
    
    If f Is Nil then
      Return False
    End if
    
    info = new FSVolumeInfo
    OSError = FSGetVolumeInfo(f.MacVRefNum, 0, Null, kFSVolInfoFlags, info, Null, Null)
    If OSError <> 0 then
      //
    End if
    flags = info.UShort(116)
    Return (Bitwise.BitAnd(flags, kFSVolFlagFilesOpenMask) = kFSVolFlagFilesOpenMask)
  #endif
End Function

FileManager.IsNetworkVolume:
Protected Function IsNetworkVolume(f as FolderItem) As Boolean
  #if TargetMacOS
    dim OSError as Integer
    dim paramBlock as HIOParam
    dim infoBuffer as GetVolParmsBuffer
    dim theResult as Boolean
    
    Declare Function PBHGetVolParmsSync Lib InterfaceLib (paramBlock as Ptr) as Short
    
    If f Is Nil then
      Raise new NilObjectException
    End if
    
    paramBlock = new HIOParam
    paramBlock.Short(22) = f.MacVRefNum
    infoBuffer = new GetVolParmsBuffer
    paramBlock.Ptr(32) = infoBuffer
    paramBlock.Long(36) = infoBuffer.Size
    
    OSError = PBHGetVolParmsSync(paramBlock)
    If OSError <> 0 then
      Return False
    End if
    theResult = (infoBuffer.Long(10) <> 0)
    Return theResult
  #endif
  
End Function

FileManager.Compare:
Protected Function Compare(ref1 as MemoryBlock, ref2 as MemoryBlock) As Boolean
  #if targetMacOS
    dim OSErr as Integer
    
    Declare Function FSCompareFSRefs Lib InterfaceLib (ref1 as Ptr, ref2 as Ptr) as Short
    
    if ref1 Is Nil or ref2 Is Nil then
      Raise new NilObjectException
    End if
    
    OSErr = FSCompareFSRefs(ref1, ref2)
    Return OSErr = 0
  #endif
End Function

FileManager.AddFolderModificationReceiver:
Sub AddFolderModificationReceiver(theReceiver as FolderModificationReceiver)
  #if targetMacOS
    If theReceiver Is Nil then
      Return
    End if
    
    If FolderModificationReceivers Is Nil then
      FolderModificationReceivers = new Dictionary
    End if
  #endif
End Sub

FileManager.RemoveFolderModificationReceiver:
Sub RemoveFolderModificationReceiver(theReceiver as FolderModificationReceiver)
  
End Sub

FileManager.FolderModificationEventDispatcher:
Sub FolderModificationEventDispatcher(message as Integer, flags as Integer, refcon as Integer, subscription as Integer)
  
End Sub

FileManager.ExchangeFiles:
Protected Sub ExchangeFiles(f as FolderItem, g as FolderItem)
  #if TargetMacOS
    dim OSError as Integer
    dim fRef, gRef as MemoryBlock
    
    If f Is Nil or g Is Nil then
      Raise new NilObjectException
    End if
    
    Declare Function FSpExchangeFiles Lib InterfaceLib (f1 as Ptr, f2 as Ptr) as Integer
    
    fRef = new FSSpec(f)
    gRef = new FSSpec(g)
    OSError = FSpExchangeFiles(fRef, gRef)
    If OSError <> 0 then
      Raise new MacOSException("FSpExchangeFiles", OSError)
    End if
  #endif
End Sub

FileManager.VolumeSupportsFSpExchangeFiles:
Protected Function VolumeSupportsFSpExchangeFiles(f as FolderItem) As Boolean
  #if TargetMacOS
    Declare Function PBHGetVolParmsSync Lib InterfaceLib (paramBlock as Ptr) as Short
    
    dim OSError as Integer
    dim paramBlock as HIOParam
    dim infoBuffer as GetVolParmsBuffer
    
    Const bHasFileIDs = 64
    
    If f Is Nil then
      Raise new NilObjectException
    End if
    
    paramBlock = new HIOParam
    paramBlock.Short(22) = f.MacVRefNum
    infoBuffer = new GetVolParmsBuffer
    paramBlock.Ptr(32) = infoBuffer
    paramBlock.Long(36) = infoBuffer.Size
    OSError = PBHGetVolParmsSync(paramBlock)
    If OSError <> 0 then
      Return false
    End if
    Return Bitwise.BitAnd(infoBuffer.Long(2), bHasFileIDs) <> 0
  #endif
End Function

FileManager.Exchange:
Protected Sub Exchange(f as FolderItem, g as FolderItem)
  #if targetMacOS
    If f Is Nil then
      Raise new InvalidParameterException("FileManager", "Exchange", "f cannot be nil.")
    End if
    If NOT f.Exists then
      Raise new InvalidParameterException("FileManager", "Exchange", "f must exist.")
    End if
    If g Is Nil then
      Raise new InvalidParameterException("FileManager", "Exchange", "g cannot be nil.")
    End if
    If NOT g.Exists then
      Raise new InvalidParameterException("FileManager", "Exchange", "g must exist.")
    End if
    If f.MacVRefNum <> g.MacVRefNum then
      Raise new InvalidParameterException("FileManager", "Exchange", "f and g must be on same volume.")
    End if
    
    If VolumeSupportsFSExchangeObjects(f) then
      ExchangeObjects f, g
    ElseIf VolumeSupportsFSpExchangeFiles(f) then
      ExchangeFiles f, g
    Else
      Swap f, g
    End if
  #endif
End Sub

FolderModificationReceiver.Key:
Function Key() As Integer
  #if targetMacOS
    dim v as Variant
    
    v  = me
    Return v.Hash
  #endif
End Function

FSCatalogInfo.Constructor:
Sub Constructor()
  #if targetMacOS
    Super.MemoryBlock(144)
  #endif
End Sub

FSRef.Constructor:
Sub Constructor()
  #if targetMacOS
    Super.MemoryBlock 80
  #endif
End Sub

FSRef.Constructor:
Sub Constructor(f as FolderItem)
  #if TargetMacOS
    Declare Function FSMakeFSRefUnicode Lib InterfaceLib (parentPtr as Ptr, nameLength as Integer, name as CString, enc as Integer, outRef as Ptr) as Short
    Declare Function FSGetVolumeInfo Lib InterfaceLib (volume as Short, volumeIndex as Integer, actualVolume as Integer, whichInfo as Integer, info as Integer, volumeName as Integer, rootDirectory as Ptr) as Short
    
    dim parentFSRef as MemoryBlock
    dim theFSRef as MemoryBlock
    dim OSErr as Integer
    dim itemName as String
    
    Const Null = 0
    Const kTextEncodingUnknown = &hffff
    
    If f Is Nil then
      Raise new InvalidParameterException("f <> nil")
    End if
    If NOT f.Exists then
      Raise new InvalidParameterException("f.Exists = true")
    End if
    
    me.Constructor
    
    If f.Parent Is nil then //f is the root directory of the volume
      OSErr = FSGetVolumeInfo(f.MacVRefNum, 0, Null, Null, Null, Null, me)
    Else
      parentFSRef = new FSRef(f.Parent)
      itemName = ConvertEncoding(f.Name, Encodings.UTF16)
      OSErr = FSMakeFSRefUnicode(parentFSRef, Len(itemName), itemName, kTextEncodingUnknown, me)
    End if
    If OSErr <> 0 then
      Raise new MacOSException("FSMakeFSRefUnicode", OSErr)
    End if
  #endif
End Sub

FSRef.Path:
Function Path() As String
  
  #if targetMacOS
    dim pathBuffer as MemoryBlock
    dim OSError as Integer
    
    Declare Function FSRefMakePath Lib InterfaceLib (ref as Ptr, path as Ptr, maxPathSize as Integer) as Integer
    
    pathBuffer = new MemoryBlock(256)
    OSError = FSRefMakePath(me, pathBuffer, pathBuffer.Size)
    If OSError <> 0 then
      Return ""
    End if
    Return Trim(DefineEncoding(pathBuffer.StringValue(0, pathBuffer.Size), Encodings.ASCII))
  #endif
  
End Function

FSRef.Item:
Private Function Item(theFSRef as FSRef) As FolderItem
  
  #if targetMacOS
    dim OSError as Integer
    dim parentRef as FSRef
    dim catalogInfo as MemoryBlock
    dim f as FolderItem
    dim i as Integer
    dim parentDirectoryID as Integer
    dim volumeID as Integer
    dim itemName as MemoryBlock
    
    Const  fsRtParID = 1
    Const kFSCatInfoNone = &h0000000
    Const kFSCatInfoVolume = &h00000004
    Const kFSCatInfoParentDirID = &h00000008
    Const Null = 0
    
    Declare Function FSGetCatalogInfo Lib InterfaceLib (ref as Ptr, whichInfo as Integer, catalogInfo as Integer, outName as Ptr, fsSpec as Integer, parentRef as Integer) as Short
    Declare Function FSGetCatalogInfo Lib InterfaceLib (ref as Ptr, whichInfo as Integer, catalogInfo as Ptr, outName as Integer, fsSpec as Integer, parentRef as Ptr) as Short
    
    If theFSRef Is Nil then
      Return nil
    End if
    
    parentRef = new FSRef
    catalogInfo = new MemoryBlock(144)
    OSError = FSGetCatalogInfo(theFSRef, kFSCatInfoVolume + kFSCatInfoParentDirID, catalogInfo, Null, Null, parentRef)
    If OSError <> 0 then
      Return nil
    End if
    parentDirectoryID = catalogInfo.Long(4)
    If parentDirectoryID = fsRtParID then //is root directory, and parentRef is invalid
      volumeID = catalogInfo.Short(2)
      For i = 0 to VolumeCount - 1
        If Volume(i).MacVRefNum = volumeID then
          f = Volume(i)
          Exit
        End if
      Next
      Return f
    Else
      f = me.Item(parentRef)
      If f Is nil then
        Return nil
      End if
      itemName = new MemoryBlock(512)
      OSError = FSGetCatalogInfo(theFSRef, kFSCatInfoNone, Null, itemName, Null, Null)
      If OSError <> 0 then
        Return nil
      End if
      Return f.Child(DefineEncoding(itemName.StringValue(2, 2*itemName.UShort(0)), Encodings.UTF16))
    End if
  #endif
  
End Function

FSRef.Operator_Convert:
Function Operator_Convert() As FolderItem
  #if TargetMacOS
    Declare Function FSGetCatalogInfo Lib InterfaceLib (ref as Ptr, whichInfo as Integer, catalogInfo as Integer, outName as Ptr, fsSpec as Integer, parentRef as Integer) as Short
    Declare Function FSGetCatalogInfo Lib InterfaceLib (ref as Ptr, whichInfo as Integer, catalogInfo as Ptr, outName as Integer, fsSpec as Integer, parentRef as Ptr) as Short
    
    dim OSError as Integer
    dim parentRef as FSRef
    dim catalogInfo as FSCatalogInfo
    dim f as FolderItem
    dim i as Integer
    dim parentDirectoryID as Integer
    dim volumeID as Integer
    dim itemName as HFSUniStr255
    
    Const  fsRtParID = 1
    Const kFSCatInfoNone = &h0000000
    Const kFSCatInfoVolume = &h00000004
    Const kFSCatInfoParentDirID = &h00000008
    Const Null = 0
    
    parentRef = new FSRef
    catalogInfo = new FSCatalogInfo
    OSError = FSGetCatalogInfo(me, kFSCatInfoVolume + kFSCatInfoParentDirID, catalogInfo, Null, Null, parentRef)
    If OSError <> 0 then
      Return nil
    End if
    parentDirectoryID = catalogInfo.Long(4)
    If parentDirectoryID = fsRtParID then //is root directory, and parentRef is invalid
      volumeID = catalogInfo.Short(2)
      For i = 0 to VolumeCount - 1
        If Volume(i).MacVRefNum = volumeID then
          f = Volume(i)
          Exit
        End if
      Next
      Return f
    Else
      f = parentRef //calls Operator_Convert recursively
      If f Is nil then
        Return nil
      End if
      itemName = new HFSUniStr255
      OSError = FSGetCatalogInfo(me, kFSCatInfoNone, Null, itemName, Null, Null)
      If OSError <> 0 then
        Return nil
      End if
      Return f.TrueChild(itemName.RbString)
    End if
  #endif
End Function

FSRef.Constructor:
Sub Constructor(theFSSpec as FSSpec)
  #if TargetMacOS
    Declare Function FSpMakeFSRef Lib InterfaceLib (source as Ptr, newRef as Ptr) as Short
    
    dim OSError as Integer
    
    If theFSSpec Is Nil then
      Raise new InvalidParameterException("FSRef", "Constructor",  "theFSSpec cannot be nil.")
    End if
    
    me.Constructor()
    OSError = FSpMakeFSRef(theFSSpec, me)
    If OSError <> 0 then
      Raise new MacOSException("FSpMakeFSRef", OSError)
    End if
  #endif
End Sub

FSRef.IsValid:
Function IsValid() As Boolean
  
  #if targetMacOS
    dim OSError as Integer
    
    Const kFSCatInfoNone = 0
    Const Null = 0
    
    Declare Function FSGetCatalogInfo Lib InterfaceLib (ref as Ptr, whichInfo as Integer, catalogInfo as Integer, outName as Integer, fsSpec as Integer, parentRef as Integer) as Short
    
    OSError = FSGetCatalogInfo(me, kFSCatInfoNone, Null, Null, Null, Null)
    Return (OSError = 0)
  #endif
  
End Function

FSRef.Name:
Function Name() As String
  
  #if targetMacOS
    dim OSErr as Integer
    dim itemName as HFSUniStr255
    
    Const kFSCatInfoNone = 0
    Const Null = 0
    
    Declare Function FSGetCatalogInfo Lib InterfaceLib (ref as Ptr, whichInfo as Integer, catalogInfo as Integer, outName as Ptr, fsSpec as Integer, parentRef as Integer) as Short
    
    itemName = new HFSUniStr255
    OSErr = FSGetCatalogInfo(me, kFSCatInfoNone, Null, itemName, Null, Null)
    If OSErr = 0 then
      Return itemName.RBString
    Else
      Return ""
    End if
  #endif
  
End Function

FSRef.AlternateConstructor:
Sub AlternateConstructor(f as FolderItem)
  #if TargetMacOS
    Declare Function FSGetVolumeInfo Lib InterfaceLib (volume as Short, volumeIndex as Integer, actualVolume as Integer, whichInfo as Integer, info as Integer, volumeName as Integer, rootDirectory as Ptr) as Short
    Declare Function FSMakeFSRefUnicode Lib InterfaceLib (parentPtr as Ptr, nameLength as Integer, name as CString, enc as Integer, outRef as Ptr) as Short
    
    dim parentRef as MemoryBlock
    dim fileName as String
    dim OSError as Integer
    
    Const kTextEncodingUnknown = &hffff
    Const fsRtParID = 1
    Const Null = 0
    
    If f Is Nil then
      Raise new InvalidParameterException("FSRef.Constructor: f cannot be nil")
    End if
    If NOT f.Exists then
      Raise new InvalidParameterException("FSRef.Constructor: f must exist.")
    End if
    
    me.Constructor()
    If f.MacDirID = fsRtParID then //f is a volume, so get root directory directly
      OSError = FSGetVolumeInfo(f.MacVRefNum, 0, Null, Null, Null, Null, me)
    Else
      parentRef = new FSRef(new FSSpec(f.Parent))
      fileName = ConvertEncoding(f.name, Encodings.UTF16)
      OSError = FSMakeFSRefUnicode(parentRef, Len(fileName), fileName, kTextEncodingUnknown, me)
      If OSError <> 0 then
        Raise new MacOSException("FSMakeFSRefUnicode", OSError)
      End if
    End if
  #endif
End Sub

FSSpec.Constructor:
Sub Constructor()
  #if TargetMacOS
    Super.MemoryBlock 70
  #endif
End Sub

FSSpec.Constructor:
Sub Constructor(f as FolderItem)
  #if TargetMacOS
    Declare Function FSMakeFSSpec Lib InterfaceLib (vRefNum as Short, dirID as Integer, filename as Pstring, spec as Ptr) as Short
    
    dim OSError as Integer
    dim fileName as String
    
    Const noError = 0
    Const fileNotFound = -43
    
    If f Is Nil then
      Raise new InvalidParameterException("FSSpec", "Constructor", "f cannot be nil.")
    End if
    
    me.Constructor
    
    filename = ConvertEncoding(f.Name, Encodings.SystemDefault)
    OSError = FSMakeFSSpec(f.MacVRefNum, f.MacDirID, fileName, me)
    If OSError = noError or OSError = fileNotFound then
      //success
    Else
      Raise new MacOSException("FSMakeFSSpec", OSError)
    End if
  #endif
End Sub

FSSpec.Operator_Convert:
Function Operator_Convert() As FolderItem
  #if TargetMacOS
    Declare Function FSMakeFSSpec Lib InterfaceLib (vRefNum as Short, dirID as Integer, filename as Pstring, spec as Ptr) as Short
    
    dim f as FolderItem
    dim i as Integer
    dim parentSpec as FSSpec
    dim OSError as Integer
    
    Const  fsRtParID = 1 //directoryID of parent of root directory
    
    If me.parID = fsRtParID then //I am the root directory
      For i = 0 to VolumeCount - 1
        If Volume(i).MacVRefNum = me.vRefNum then
          f = Volume(i)
          Exit
        End if
      Next
      Return f
    Else
      parentSpec = new FSSpec
      OSError = FSMakeFSSpec(me.vRefNum, me.parID, "", parentSpec)
      If OSError <> 0 then
        Return nil
      End if
      f = parentSpec
      If f <> nil then
        Return f.TrueChild(me.Name)
      Else
        Return nil
      End if
    End if
  #endif
End Function

FSSpec.Constructor:
Sub Constructor(theFSRef as FSRef)
  #if targetMacOS
    Declare Function FSGetCatalogInfo Lib InterfaceLib (ref as Ptr, whichInfo as Integer, catalogInfo as Integer, outName as Integer, fsSpec as Ptr, parentRef as Integer) as Short
    
    dim OSError as Integer
    
    Const kFSCatInfoNone = 0
    Const Null = 0
    
    If theFSRef Is Nil then
      Raise new InvalidParameterException("FSSpec", "Constructor", "theFSRef cannot be nil.")
    End if
    
    me.Constructor
    OSError = FSGetCatalogInfo(theFSRef, kFSCatInfoNone, Null, Null, me, Null)
    If OSError <> 0 then
      Raise new MacOSException("FSGetCatalogInfo", OSError)
    End if
  #endif
End Sub

FSSpec.vRefNum:
Function vRefNum() As Integer
  #if targetMacOS
    Return me.Short(0)
  #endif
End Function

FSSpec.parID:
Function parID() As Integer
  #if targetMacOS
    Return me.Long(2)
  #endif
End Function

FSSpec.Name:
Function Name() As String
  #if targetMacOS
    Return DefineEncoding(me.PString(6), Encodings.SystemDefault)
  #endif
End Function

FSVolumeInfo.Constructor:
Sub Constructor()
  #if targetMacOS
    Super.MemoryBlock 126
  #endif
End Sub

GetVolParmsBuffer.Constructor:
Sub Constructor()
  
  #if targetMacOS
    Super.MemoryBlock(32)
  #endif
  
End Sub

HFSUniStr255.Constructor:
Sub Constructor()
  #if targetMacOS
    Super.MemoryBlock(512)
  #endif
End Sub

HFSUniStr255.RBString:
Function RBString() As String
  #if targetMacOS
    Return DefineEncoding(me.StringValue(2, 2*me.UShort(0)), Encodings.UTF16)
  #endif
End Function

HIOParam.Constructor:
Sub Constructor()
  #if targetMacOS
    Super.MemoryBlock(50)
  #endif
End Sub

MacIcon.Constructor:
Sub Constructor(theIconRef as Integer)
  #if targetMachO
    Declare Function AcquireIconRef Lib kCarbon (theIconRef as Integer) as Short
    
    dim OSError as Integer
    
    me.Constructor()
    OSError = AcquireIconRef(theIconRef)
    me.IconRef = theIconRef
  #endif
End Sub

MacIcon.Destructor:
Sub Destructor()
  #if targetMachO
    me.Release me.IconRef
    me.IconRef = 0
  #endif
End Sub

MacIcon.Release:
Protected Sub Release(theIconRef as integer)
  #if targetMachO
    Declare Function ReleaseIconRef Lib kCarbon (theIconRef as Integer) as Short
    
    dim OSError as Integer
    
    OSError = ReleaseIconRef(theIconRef)
  #endif
End Sub

MacIcon.Constructor:
Sub Constructor(f as folderItem, size as integer)
  #if targetMachO
    
    me.pSize = size
    
    dim OSError as Integer
    dim theFileSpec as FSSpec
    dim theIconRef as MemoryBlock
    dim theLabel as MemoryBlock
    
    Const NULL = 0
    Const kSystemIconsCreator = "macs"
    Const kUnknownFileType = "????"
    Const kOnSystemDisk = -32768
    
    Declare Function GetIconRef Lib kCarbon (vRefNum as Short, creator as OSType, icnType as OSType, theIconRef as Ptr) as Short
    Declare Function GetIconRefFromFile Lib kCarbon (theFile as Ptr, theIconRef as Ptr, theLabel as Ptr) as Short
    
    If f <> Nil and f.Exists then
      theFileSpec = new FSSpec(f)
      theIconRef = new MemoryBlock(4)
      theLabel = NewMemoryBlock(2)
      OSError = GetIconRefFromFile(theFileSpec, theIconRef, theLabel)
    Else
      OSError = GetIconRef(kOnSystemDisk, kSystemIconsCreator, kUnknownFileType, theIconRef)
    End if
    me.Constructor(theIconRef.Long(0))
    
  Finally
    me.Release theIconRef.Long(0)
  #endif
  
End Sub

MacIcon.Draw:
Protected Sub Draw(g as graphics, left as integer, top as integer)
  #if targetMachO
    Declare Function PlotIconRef Lib kCarbon (theRect as Ptr, align as Short, transform as Short, theIconServicesUsageFlags as Integer, iconRef as Integer) as Short
    
    dim OSError as Integer
    dim rect as MemoryBlock
    
    const kAlignNone = 0
    const kIconServicesNormalUsageFlag = 0
    
    g.FillRect 0, 0, 0, 0 //sets graphics port
    rect = new Rect(Top, Left, Top + me.pSize - 1, Left + me.pSize - 1)
    OSError = PlotIconRef(rect, kAlignNone, me.pTransform, kIconServicesNormalUsageFlag, me.IconRef)
    
  #endif
End Sub

MacIcon.Operator_Convert:
Function Operator_Convert() As Picture
  #if targetMachO
    dim OSError as Integer
    
    Const depth = 32
    
    Declare Function SetThemeBackground Lib kCarbon (inBrush as Integer, inDepth as Integer, inIsColorDevice as Boolean) as Integer
    
    If me.icon <> nil Then
      Return me.icon
      
    Else
      me.icon = new Picture(me.pSize, me.pSize, 32)
      me.icon.transparent = 1
      
      //* 32bit color *//
      
      me.icon.Graphics.ClearRect 0, 0, 1, 1
      OSError = SetThemeBackground(me.pBackground, depth, true)
      me.icon.Graphics.ClearRect 0, 0, me.icon.Width, me.icon.Height
      me.Draw me.icon.Graphics, 0, 0
      
      //* 8bit Mask *//
      
      'me.pTransform = BitWise.bitOr(&h4000, &h03)
      '
      'me.icon.mask.Graphics.ClearRect 0, 0, 1, 1
      'OSError = SetThemeBackground(me.pBackground, depth, true)
      'me.icon.mask.Graphics.ClearRect 0, 0, me.icon.Width, me.icon.Height
      'me.Draw me.icon.mask.Graphics, 0, 0
      
      Return me.icon
      
    End if
    
  #endif
End Function

MacIcon.Constructor:
Sub Constructor()
  #if targetMachO
    Const kTransformNone = 0
    Const kThemeBrushListViewBackground = 10
    
    me.pTransform = kTransformNone
    me.pBackground = kThemeBrushListViewBackground
  #endif
End Sub

Rect.Constructor:
Sub Constructor(left as integer, top as integer, right as integer, bottom as integer)
  #if targetMachO
    
    super.MemoryBlock(8)
    super.short(0) = left
    super.short(2) = top
    super.short(4) = right
    super.short(6) = bottom
    
  #endif
End Sub

plist.plist:
Sub plist(f As FolderItem)
  Load(f)
End Sub

plist.Load:
Sub Load(f As folderItem)
  dim t As textInputStream
  dim s As string
  
  root=new plistDict
  
  savePath=f
  
  if f.exists then
    t=f.OpenAsTextFile
    while t.eof = false and s <> "<dict>"
      s=t.ReadLine(Encodings.UTF8)
    wend
    if s="<dict>" then
      root.Load(t,"root",false,nil,me,true)
    else
      error=true
      errorMessage="Not a plist file"
    end
    t.close
  else
    error=true
    errorMessage=f.AbsolutePath+" does not exist"
  end
  
  if error then
    root.load(t,"root",false,nil,me,false)
  end
  
End Sub

plist.Save:
Sub Save()
  dim o As TextOutputStream
  
  o=savePath.CreateTextFile
  if o<>nil then
    //header
    o.WriteLine "<?xml version=""1.0"" encoding=""UTF-8""?>"
    o.WriteLine "<!DOCTYPE plist PUBLIC ""-//Apple Computer//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">"
    o.WriteLine "<plist version=""1.0"">"
    o.WriteLine "<dict>"
    
    root.Write(o,1)
    
    //footer
    o.WriteLine "</dict>"
    o.WriteLine "</plist>"
  else
    error=true
    errorMessage="Could not open file for saving"
  end
  o.close
End Sub

plist.Find:
Function Find(searchText as string) As boolean
  foundDict=nil
  foundKey=""
  foundValue=""
  foundType=""
  ClearSearch(root)
  lastSearch=searchText
  Return ReadStructure(root,searchText,"valueSearch")
End Function

plist.ReadStructure:
Private Function ReadStructure(dict as plistDict,searchText as string,searchType as string) As boolean
  Dim key,type,value as string
  dim ok As Boolean
  
  dict.MoveFirst
  While not dict.eof
    key=dict.CurrentKey
    type=dict.GetType(key)
    If type="dict" or type="array" then
      if ReadStructure(dict.child(key),searchText,searchType) then
        return true
      end
    else
      value=dict.GetValue(key)
      if (instr(value,searchText)>0 and searchType="valueSearch") or (instr(key,searchText)>0 and searchType="keySearch") then
        if not dict.searched.HasKey(key) then
          dict.searched.Value(key)=false
        end
        if not dict.searched.Value(key) then
          foundDict=dict
          foundKey=key
          foundType=type
          foundValue=value
          dict.searched.Value(key)=true
          Return true
        end
      end
    end
    dict.MoveNext
  Wend
  return false
  
End Function

plist.FindNext:
Function FindNext(searchText as string) As boolean
  if searchText<>lastSearch then
    ClearSearch(root)
  end
  Return ReadStructure(root,searchText,"valueSearch")
End Function

plist.ClearSearch:
Sub ClearSearch(dict as plistDict)
  Dim key,type,value as string
  dim ok As Boolean
  
  dict.MoveFirst
  While not dict.eof
    key=dict.CurrentKey
    type=dict.GetType(key)
    If type="dict" or type="array" then
      ClearSearch(dict.child(key))
    else
      dict.searched.Value(key)=false
    end
    dict.MoveNext
  Wend
  
End Sub

plistDict.Load:
Sub Load(t As TextInputStream,n As string,ia As boolean,pr As plistDict,rt As plist,loadDict As boolean)
  dim s,key,type,value,tag,endTag,tagValue,line As string
  dim f,count,i As integer
  dim inTag,placeHolder As boolean
  
  
  values=new dictionary
  types=new dictionary
  name=n
  parent=pr
  rootClass=rt
  indexOf=-1
  
  isArray=ia
  if isArray then
    endTag="</array>"
  else
    endTag="</dict>"
  end
  if loadDict then
    while not t.eof and s<>endTag and s<>"<dict/>"
      if isArray and not inTag then
        indexOf=indexOf+1
        key=str(indexOf)
      end
      line=StripAll(t.ReadLine)
      line=replaceAll(line,"><",">"+chr(13)+"<")
      line=ReplaceAll(line,">"+chr(13)+"</","></")
      for i=1 to CountFields(line,chr(13))
        s=NthField(line,chr(13),i)
        if left(s,5)="<key>"  then
          s=right(s,len(s)-5)
          if right(s,6)="</key>" then
            s=left(s,len(s)-6)
          end
          key=s
        elseif s<>endTag then
          if inTag and s<>"</"+tag+">" then
            f=instr(s,"</"+tag+">")
            if f>0 then
              s=left(s,f-1)
              inTag=false
            end
            value=value+CodeToBrackets(s)
            if tag<>"data" then
              value=value+chr(13)
            end
            if not inTag then
              values.value(key)=CodeToBrackets(value)
            end
          else
            f=instr(s,">")
            if f>0 then
              tag=left(s,f-1)
              if left(tag,1)="<" then
                tag=right(tag,len(tag)-1)
              end
              if tag="false/" then
                types.value(key)="boolean"
                values.value(key)="false"
                type="boolean"
              elseif tag="true/" then
                types.value(key)="boolean"
                values.value(key)="true"
                type="boolean"
              elseif tag="/"+type or tag="/key" then
                inTag=false
                values.value(key)=CodeToBrackets(value)
                value=""
              else
                type=tag
                if right(type,1)="/" then
                  type=left(type,len(type)-1)
                  placeHolder=true
                else
                  placeHolder=false
                end
                types.value(key)=type
                if type<>"array" and type<>"dict" and type<>"dict/" then
                  s=right(s,len(s)-f)
                  f=instr(s,"</"+type)
                  if f>0 then
                    value=left(s,f-1)
                    values.value(key)=CodeToBrackets(value)
                  else
                    inTag=true
                    f=instr(s,">")
                    if f=0 then
                      value=ReplaceAll(s,"&lt;","<")
                      value=ReplaceAll(value,"&gt;",">")
                      if type<>"data" then
                        value=value+chr(13)
                      end
                    else
                      value=""
                    end
                  end
                end
              end
              if type="dict"  then
                children.append new plistDict
                childrenNames.append key
                children(ubound(children)).Load(t,key,false,me,rootClass,not placeHolder)
                if placeHolder then
                  s=""
                end
              elseif type="array" then
                children.append new plistDict
                childrenNames.append key
                children(ubound(children)).Load(t,key,true,me,rootClass,not placeHolder)
              end
            end
          end
        end
      next
    wend
  end
End Sub

plistDict.StripAll:
Protected Function StripAll(s As string) As string
  dim temp As string
  
  if s<>"" then
    temp=s
    while asc(left(temp,1))<32
      temp=right(temp,len(temp)-1)
    wend
  end
  return temp
End Function

plistDict.child:
Function child(name As string) As plistDict
  dim count As integer
  
  for count=1 to ubound(children)
    if childrenNames(count)=name then
      return children(count)
    end
  next
  AddChild(name)
  return child(name)
  
End Function

plistDict.GetValue:
Function GetValue(key As string,default As string) As string
  dim result As string
  
  if not Exists(key) then
    SetString(key,default)
  end
  if rootClass<>nil then
    SetError(false,"")
  end
  if values.HasKey(key) then
    if TypeOK(key) then
      result=values.value(key)
    end
  else
    SetError(true,"Key "+key+" does not exist")
  end
  return result
End Function

plistDict.GetType:
Function GetType(key As string) As string
  return types.value(key)
End Function

plistDict.index:
Function index(index As integer) As plistDict
  dim count As integer
  
  for count=1 to ubound(children)
    if childrenNames(count)=str(index) then
      return children(count)
    end
  next
  return nil
End Function

plistDict.Write:
Sub Write(o As TextOutputStream,level As integer)
  dim count,count2 As integer
  dim key,type,value,tabs As string
  
  for count=1 to level
    tabs=tabs+chr(9)
  next
  for count=0 to types.count-1
    key=types.key(count)
    type=types.value(key)
    if type<>"dict" and type<>"array" then
      value=BracketsToCode(values.value(key))
    end
    if not isArray then
      o.WriteLine tabs+"<key>"+key+"</key>"
    end
    if type="data" then
      o.WriteLine tabs+"<data>"
      o.WriteLine tabs+value
      o.WriteLine tabs+"</data>"
    elseif type="dict" then
      for count2=1 to ubound(childrenNames)
        if childrenNames(count2)=key then
          if children(count2).count>0 then
            o.WriteLine tabs+"<dict>"
            children(count2).Write(o,level+1)
            o.WriteLine tabs+"</dict>"
          else
            o.WriteLine tabs+"<dict/>"
          end
        end
      next
    elseif type="array" then
      for count2=1 to ubound(childrenNames)
        if childrenNames(count2)=key then
          if children(count2).count>0 then
            o.WriteLine tabs+"<array>"
            children(count2).Write(o,level+1)
            o.WriteLine tabs+"</array>"
          else
            o.WriteLine tabs+"<array/>"
          end
        end
      next
    elseif type="boolean" then
      if value="true" then
        o.WriteLine tabs+"<true/>"
      else
        o.WriteLine tabs+"<false/>"
      end
    else
      o.WriteLine tabs+"<"+type+">"+value+"</"+type+">"
    end
  next
End Sub

plistDict.GetString:
Function GetString(key As string,default As string) As string
  return GetValue(key,default)
End Function

plistDict.TypeOK:
Protected Function TypeOK(key As string) As boolean
  dim type As string
  
  type=types.value(key)
  if type="dict" or type="array" then
    if rootClass<>nil then
      SetError(true,"Illegal Type: "+key+" is a "+type)
    end
    return false
  else
    return true
  end
End Function

plistDict.GetInteger:
Function GetInteger(key As string,default As integer) As integer
  dim value As integer
  
  if not Exists(key) then
    SetInteger(key,default)
  end
  if TypeOK(key) then
    if types.value(key)="date" then
      SetError(true,"Type Mismatch: "+key+" is a date")
      value=-1
    else
      value=cdbl(GetValue(key))
    end
  end
  return value
End Function

plistDict.GetBoolean:
Function GetBoolean(key As string,default As boolean) As boolean
  dim value As boolean
  
  if not Exists(key) then
    SetBoolean(key,default)
  end
  if types.value(key)<>"boolean" then
    SetError(true,"Type Mismatch: "+key+" is a "+types.value(key))
  elseif values.value(key)="true" then
    value=true
  end
  return value
End Function

plistDict.GetDate:
Function GetDate(key As string,default As date) As date
  dim dt As Date
  dim value,datePart,timePart,month,day,year As string
  dim f As integer
  
  if not Exists(key) then
    SetDate(key,default)
  end
  if TypeOK(key) then
    dt=new Date
    value=GetValue(key)
    f=instr(value,"T")
    if f>0 then
      datePart=left(value,f-1)
      timePart=right(value,len(value)-f)
      if right(timePart,1)="Z" then
        timePart=left(timePart,len(timePart)-1)
      end
    else
      datePart=value
    end
    year=NthField(datePart,"-",1)
    month=NthField(datePart,"-",2)
    day=NthField(datePart,"-",3)
    datePart=month+"/"+day+"/"+year
    if ParseDate(datePart,dt) then
      if timePart<>"" then
        dt.hour=cdbl(NthField(timePart,":",1))
        dt.minute=cdbl(NthField(timePart,":",2))
        dt.second=cdbl(NthField(timePart,":",3))
      end
    else
      SetError(true,"Could not create date object from "+key+"("+value+")")
    end
  end
  return dt
End Function

plistDict.GetData:
Function GetData(key As string,default As string) As string
  return GetValue(key,default)
End Function

plistDict.SetBoolean:
Sub SetBoolean(key As string,v As boolean)
  dim result As integer
  dim value As string
  
  result=CheckType(key,"boolean")
  if result<>0 then
    if v then
      value="true"
    else
      value="false"
    end
    values.value(key)=value
    types.value(key)="boolean"
    searched.Value(key)=false
  end
  indexOf=-1
End Sub

plistDict.CheckType:
Protected Function CheckType(key As string,type As string) As integer
  dim result As integer
  
  SetError(false,"")
  // Check for correct type 0=incorrect type, 1=correct type, 2=does not exist
  if types.HasKey(key) then
    if types.value(key)=type then
      result=1
    end
  else
    result=2
  end
  if result=0 then
    SetError(true,"Type Mismatch: "+key+" is a "+types.value(key))
  end
  return result
End Function

plistDict.SetString:
Sub SetString(key As string,v As string)
  dim result As integer
  
  result=CheckType(key,"string")
  if result<>0 then
    values.value(key)=v
    types.value(key)="string"
    searched.Value(key)=false
  end
End Sub

plistDict.SetInteger:
Sub SetInteger(key As string,v As double)
  dim result As integer
  dim value As string
  
  result=CheckType(key,"integer")
  if result<>0 then
    values.value(key)=format(v,"-#")
    types.value(key)="integer"
    searched.Value(key)=false
  end
End Sub

plistDict.GetDouble:
Function GetDouble(key As string,default As double) As double
  dim value As double
  
  if not Exists(key) then
    SetDouble(key,default)
  end
  if TypeOK(key) then
    if types.value(key)="date" then
      SetError(true,"Type Mismatch: "+key+" is a date")
      value=-1
    else
      value=cdbl(GetValue(key))
    end
  end
  return value
End Function

plistDict.SetDouble:
Sub SetDouble(key As string,v As double)
  dim result As integer
  dim value As string
  
  result=CheckType(key,"real")
  if result<>0 then
    values.value(key)=str(v)
    types.value(key)="real"
    searched.Value(key)=false
  end
End Sub

plistDict.SetData:
Sub SetData(key As string,v As string)
  values.value(key)=v
  types.value(key)="data"
  searched.Value(key)=false
End Sub

plistDict.SetDate:
Sub SetDate(key As string,dt As date)
  dim result As integer
  dim value As string
  
  result=CheckType(key,"date")
  if result<>0 then
    value=str(dt.year)+"-"
    value=value+MakeTwo(dt.month)+"-"
    value=value+MakeTwo(dt.day)+"T"
    value=value+MakeTwo(dt.hour)+":"
    value=value+MakeTwo(dt.minute)+":"
    value=value+MakeTwo(dt.second)+"Z"
    values.value(key)=value
    types.value(key)="date"
    searched.Value(key)=false
  end
End Sub

plistDict.MakeTwo:
Protected Function MakeTwo(value As integer) As string
  if value>9 then
    return str(value)
  else
    return "0"+str(value)
  end
End Function

plistDict.AddChild:
Sub AddChild(name As string)
  dim index As integer
  
  SetError(false,"")
  if types.HasKey(name) then
    SetError(true,"Child exists: "+name+" already exists")
  else
    types.value(name)="dict"
    childrenNames.append name
    children.append new plistDict
    index=ubound(children)
    children(index).name=name
    children(index).isArray=false
    children(index).parent=me
    children(index).rootClass=rootClass
    searched.Value(name)=false
  end
End Sub

plistDict.plistDict:
Sub plistDict()
  values=new dictionary
  types=new dictionary
  searched=new Dictionary
  indexOf=-1
End Sub

plistDict.AddArray:
Function AddArray(name As string) As boolean
  dim index As integer
  
  SetError(false,"")
  if types.HasKey(name) then
    SetError(true,"Array exists: "+name+" already exists")
    return false
  end
  types.value(name)="array"
  childrenNames.append name
  children.append new plistDict
  index=ubound(children)
  children(index).name=name
  children(index).isArray=true
  children(index).parent=me
  children(index).rootClass=rootClass
  searched.Value(name)=false
  return true
End Function

plistDict.AppendInteger:
Sub AppendInteger(value As integer)
  if CheckArray then
    indexOf=types.count
    types.value(str(indexOf))="integer"
    values.value(str(indexOf))=str(value)
  end
End Sub

plistDict.AppendDict:
Sub AppendDict()
  dim index as integer
  
  if CheckArray then
    indexOf=types.count
    types.value(str(indexOf))="dict"
    childrenNames.append str(indexOf)
    children.append new plistDict
    index=ubound(children)
    children(index).isArray=false
    children(index).parent=me
    children(index).rootClass=rootClass
  end
End Sub

plistDict.AppendArray:
Sub AppendArray()
  dim index as integer
  
  if CheckArray then
    indexOf=types.count
    types.value(str(indexOf))="array"
    childrenNames.append str(indexOf)
    children.append new plistDict
    index=ubound(children)
    children(index).name=str(indexOf)
    children(index).isArray=true
    children(index).parent=me
    children(index).rootClass=rootClass
  end
End Sub

plistDict.AppendBoolean:
Sub AppendBoolean(value As boolean)
  if CheckArray then
    indexOf=types.count
    types.value(str(indexOf))="boolean"
    if value then
      values.value(str(indexOf))="true"
    else
      values.value(str(indexOf))="false"
    end
  end
End Sub

plistDict.AppendDouble:
Sub AppendDouble(value As double)
  if CheckArray then
    indexOf=types.count
    types.value(str(indexOf))="double"
    values.value(str(indexOf))=str(value)
  end
End Sub

plistDict.AppendString:
Sub AppendString(value As string)
  if CheckArray then
    indexOf=types.count
    types.value(str(indexOf))="string"
    values.value(str(indexOf))=value
  end
End Sub

plistDict.AppendData:
Sub AppendData(value As string)
  if CheckArray then
    indexOf=types.count
    types.value(str(indexOf))="data"
    values.value(str(indexOf))=value
  end
End Sub

plistDict.AppendDate:
Sub AppendDate(dt As date)
  dim value As string
  
  if CheckArray then
    indexOf=types.count
    types.value(str(indexOf))="date"
    
    value=str(dt.year)+"-"
    value=value+MakeTwo(dt.month)+"-"
    value=value+MakeTwo(dt.day)+"T"
    value=value+MakeTwo(dt.hour)+":"
    value=value+MakeTwo(dt.minute)+":"
    value=value+MakeTwo(dt.second)+"Z"
    values.value(str(indexOf))=value
  end
End Sub

plistDict.CheckArray:
Function CheckArray() As boolean
  SetError(false,"")
  if isArray then
    return true
  else
    SetError(true, name+" is not an array")
  end
End Function

plistDict.Remove:
Sub Remove(toRemove As variant)
  dim i,index,which,cnt As integer
  dim value,key,type As string
  
  if toRemove.isNumeric then
    index=toRemove.IntegerValue
    if CheckArray then
      cnt=types.count-1
      if index>count-1 or index<0 then
        SetError(true,"Subscript out of range")
      end
      key=str(index)
      type=types.value(key)
      if type="dict" or type="array" then
        childrenNames.Remove(index+1)
        children.Remove(index+1)
      end
      if values.hasKey(key) then
        values.Remove(key)
      end
      types.Remove(key)
      for i=index+1 to cnt
        key=str(i)
        if types.HasKey(key) then
          type=types.value(key)
          if values.hasKey(key) then
            value=values.value(key)
          end
          key=str(i-1)
          types.value(key)=type
          if type<>"dict" and type<>"array" then
            values.value(key)=value
          end
        end
      next
      key=str(cnt)
      if types.hasKey(key) then
        types.remove(key)
        if values.hasKey(key) then
          values.Remove(key)
        end
      end
    end
  else
    key=toRemove.StringValue
    if values.HasKey(key) then
      values.Remove(key)
    end
    types.Remove(key)
    for i=1 to ubound(childrenNames)
      if key=childrenNames(i) then
        which=i
      end
    next
    if which>0 then
      childrenNames.Remove(which)
      children.Remove(which)
    end
  end
End Sub

plistDict.count:
Function count() As integer
  return types.count
End Function

plistDict.MoveNext:
Sub MoveNext()
  currentIndex=currentIndex+1
  if currentIndex>types.count-1 then
    currentIndex=0
    eof=true
  end
End Sub

plistDict.MoveFirst:
Sub MoveFirst()
  currentIndex=0
  eof=false
End Sub

plistDict.MoveLast:
Sub MoveLast()
  currentIndex=types.count-1
End Sub

plistDict.CurrentKey:
Function CurrentKey() As string
  if currentIndex<=types.count-1 then
    return types.key(currentIndex)
  else
    eof=true
    currentIndex=0
    return ""
  end
End Function

plistDict.SetReal:
Sub SetReal(key As string,v As double)
  dim result As integer
  dim value As string
  
  result=CheckType(key,"double")
  if result<>0 then
    values.value(key)=str(v)
    types.value(key)="real"
    searched.Value(key)=false
  end
End Sub

plistDict.GetReal:
Function GetReal(key As string,default As double) As double
  dim value As double
  
  if not Exists(key) then
    SetReal(key,default)
  end
  if TypeOK(key) then
    if types.value(key)="date" then
      SetError(true,"Type Mismatch: "+key+" is a date")
      value=-1
    else
      value=cdbl(GetValue(key))
    end
  end
  return value
End Function

plistDict.GetBoolean:
Function GetBoolean(key As string) As boolean
  return GetBoolean(key,true)
End Function

plistDict.Exists:
Function Exists(key As string) As boolean
  return types.HasKey(key)
End Function

plistDict.GetData:
Function GetData(key As string) As string
  return GetData(key,"")
End Function

plistDict.GetDate:
Function GetDate(key As string) As date
  dim dt As date
  
  dt=new date
  return GetDate(key,dt)
End Function

plistDict.GetDouble:
Function GetDouble(key As string) As double
  return GetDouble(key,0)
End Function

plistDict.GetInteger:
Function GetInteger(key As string) As integer
  return GetInteger(key,0)
End Function

plistDict.GetReal:
Function GetReal(key As string) As double
  return GetReal(key,0)
End Function

plistDict.GetString:
Function GetString(key As string) As string
  return GetString(key,"")
End Function

plistDict.GetValue:
Function GetValue(key As string) As string
  return GetValue(key,"")
End Function

plistDict.BracketsToCode:
Function BracketsToCode(s As string) As string
  dim temp As string
  
  temp=s
  temp=ReplaceAll(temp,"<","&lt;")
  temp=ReplaceAll(temp,">","&gt;")
  return temp
End Function

plistDict.CodeToBrackets:
Function CodeToBrackets(s As string) As string
  dim temp As string
  
  temp=s
  temp=ReplaceAll(temp,"&lt;","<")
  temp=ReplaceAll(temp,"&gt;",">")
  return temp
End Function

plistDict.SetError:
Sub SetError(value As boolean,msg As string)
  if rootClass<>nil then
    rootClass.error=value
    rootClass.errorMessage=msg
    if value and rootClass.debug then
      MsgBox msg
    end
  end
End Sub

plistDict.Dump:
Sub Dump(level As integer)
  dim count,count2 As integer
  dim key,type,value,tabs As string
  dim s,cr As string
  dim c As clipboard
  
  cr=chr(13)
  for count=1 to level
    tabs=tabs+chr(9)
  next
  for count=0 to types.count-1
    key=types.key(count)
    type=types.value(key)
    if type<>"dict" and type<>"array" then
      value=BracketsToCode(values.value(key))
    end
    if not isArray then
      s=s+tabs+"<key>"+key+"</key>"+cr
      if searched.HasKey(key) then
        s=s+tabs+"<search/>"+cr
      else
        s=s+tabs+"<nosearch/>"+cr
      end
    end
    if type="data" then
      s=s+tabs+"<data>"+cr
      s=s+tabs+value+cr
      s=s+tabs+"</data>"+cr
    elseif type="dict" then
      for count2=1 to ubound(childrenNames)
        if childrenNames(count2)=key then
          if children(count2).count>0 then
            s=s+tabs+"<dict>"+cr
            children(count2).Dump(level+1)
            s=s+tabs+"</dict>"+cr
          else
            s=s+tabs+"<dict/>"+cr
          end
        end
      next
    elseif type="array" then
      for count2=1 to ubound(childrenNames)
        if childrenNames(count2)=key then
          if children(count2).count>0 then
            s=s+tabs+"<array>"+cr
            children(count2).Dump(level+1)
            s=s+tabs+"</array>"+cr
          else
            s=s+tabs+"<array/>"+cr
          end
        end
      next
    elseif type="boolean" then
      if value="true" then
        s=s+tabs+"<true/>"+cr
      else
        s=s+tabs+"<false/>"+cr
      end
    else
      s=s+tabs+"<"+type+">"+value+"</"+type+">"+cr
    end
  next
  c=new clipboard
  c.text=c.text+s
  c.close
End Sub

plistDict.SetColor:
Sub SetColor(key as string,v as color)
  dim result As integer
  dim value As string
  
  result=CheckType(key,"string")
  if result<>0 then
    value=hex(v.red)+hex(v.green)+hex(v.blue)
    values.value(key)=value
    types.value(key)="string"
    searched.Value(key)=false
    indexOf=-1
  end
End Sub

plistDict.GetColor:
Function GetColor(key As string) As color
  return GetColor(key,RGB(0,0,0))
End Function

plistDict.GetColor:
Function GetColor(key As string,default As color) As color
  dim c As color
  dim value As string
  
  if not Exists(key) then
    SetColor(key,default)
  end
  if types.value(key)<>"string" then
    SetError(true,"Type Mismatch: "+key+" is a "+types.value(key))
  else
    value=GetValue(key)
    c=RGB(cdbl("&h"+left(value,2)),cdbl("&h"+mid(value,3,2)),cdbl("&h"+right(value,2)))
    return c
  end
End Function

plistDict.AppendColor:
Sub AppendColor(v as color)
  dim value as string
  
  if CheckArray then
    indexOf=types.count
    value=hex(v.red)+hex(v.green)+hex(v.blue)
    types.value(str(indexOf))="string"
    values.value(str(indexOf))=value
  end
End Sub

plistDict.SetList:
Sub SetList(key as string,items() as string,startIndex as integer,endIndex as integer)
  dim count,si,ei as Integer
  
  if exists(key) then
    Remove(key)
  end
  si=startIndex
  ei=endIndex
  if si>UBound(items) then
    si=0
  end
  if ei>UBound(items) then
    ei=UBound(items)
  end
  if AddArray(key) then
    searched.Value(key)=false
    for count=si to ei
      child(key).AppendString items(count)
    next
  end
End Sub

plistDict.GetList:
Sub GetList(key as string,byref items() as string,indexStart as integer)
  dim count As integer
  dim newArray(0) as string
  
  if indexStart=0 then
    redim newArray(-1)
  end
  for count=0 to child(key).count-1
    newArray.Append child(key).GetString(str(count))
  next
  items=newArray
End Sub

plistDict.AppendList:
Sub AppendList(items() as string,startIndex as integer,endIndex as integer)
  dim count,si,ei,idx as Integer
  
  if CheckArray then
    si=startIndex
    ei=endIndex
    if si>UBound(items) then
      si=0
    end
    if ei>UBound(items) then
      ei=UBound(items)
    end
    AppendArray
    idx=count-1
    for count=si to ei
      child(str(idx)).AppendString items(count)
    next
  end
End Sub

plistDict.AbsolutePath:
Function AbsolutePath() As string
  path=":"+name
  BuildPath(parent,path)
  return path
End Function

plistDict.BuildPath:
Private Sub BuildPath(parent as plistDict,p as string)
  if parent.name<>"root" then
    path=":"+parent.name+path
    BuildPath(parent.parent,path)
  else
    path=":root"+path
  end
End Sub

plistDict.Move:
Sub Move(key as string,dest as plistDict,deleteSrc as boolean,newName as string)
  dim value as Variant
  dim type,nm,ck,targetName As string
  dim dst as plistDict
  
  SetError(false,"")
  if dest<>nil then
    if Exists(key) then
      type=types.Value(key)
      if newName="" then
        targetName=key
      else
        targetName=newName
      end
      select case type
      case "array"
        if dest.isArray then
          dest.AppendDict
          nm=str(dest.count)
          dst=dest.child(nm)
        else
          nm=key
          dest.AddChild(targetName)
          dst=dest.child(targetName)
        end
        child(key).MoveFirst
        while not child(key).eof
          ck=child(key).CurrentKey
          child(key).Move(ck,dst,false,"")
          child(key).MoveNext
        wend
      case "dict"
        if dest.isArray then
          dest.AppendDict
          nm=str(dest.count)
          dst=dest.child(nm)
        else
          nm=key
          dest.AddChild(targetName)
          dst=dest.child(targetName)
        end
        child(key).MoveFirst
        while not child(key).eof
          ck=child(key).CurrentKey
          child(key).Move(ck,dst,false,"")
          child(key).MoveNext
        wend
        
      case "string"
        value=GetString(key)
        if dest.isArray then
          dest.AppendString value
        else
          dest.SetString(targetName,value)
        end
        
      case "boolean"
        value=GetBoolean(key)
        if dest.isArray then
          dest.AppendBoolean value
        else
          dest.SetBoolean(targetName,value)
        end
        
      case "real"
        value=GetDouble(key)
        if dest.isArray then
          dest.AppendDouble value
        else
          dest.SetDouble(targetName,value)
        end
        
      case "integer"
        value=GetInteger(key)
        if dest.isArray then
          dest.AppendInteger value
        else
          dest.SetInteger(targetName,value)
        end
        
      case "data"
        value=GetString(key)
        if dest.isArray then
          dest.AppendData value
        else
          dest.SetData(targetName,value)
        end
        
      case "date"
        value=GetDate(key)
        if dest.isArray then
          dest.AppendDate value
        else
          dest.SetDate(targetName,value)
        end
      end
      
      if deleteSrc then
        Remove(key)
      end
      
    else
      SetError(true,"Source does not exist.")
    end
  else
    SetError(true,"Destination is nil")
  end
End Sub

plistDict.Move:
Sub Move(key as string,dest as plistDict)
  Move(key,dest,true,"")
End Sub

plistDict.Copy:
Sub Copy(key as string,dest as plistDict)
  Move(key,dest,false,"")
End Sub

plistDict.Rename:
Sub Rename(key as string,newName as string)
  SetError(false,"")
  if Exists(newName) then
    SetError(true,"Key "+newName+" already exists.")
  else
    Move(key,me,true,newName)
  end
End Sub

plistDict.GetList:
Sub GetList(key as string,byref items() as integer,indexStart as integer)
  dim count As integer
  dim newArray(0) as integer
  
  if indexStart=0 then
    redim newArray(-1)
  end
  for count=0 to child(key).count-1
    newArray.Append child(key).GetInteger(str(count))
  next
  items=newArray
End Sub

plistDict.SetList:
Sub SetList(key as string,items() as integer,startIndex as integer,endIndex as integer)
  dim count,si,ei as Integer
  
  if exists(key) then
    Remove(key)
  end
  si=startIndex
  ei=endIndex
  if si>UBound(items) then
    si=0
  end
  if ei>UBound(items) then
    ei=UBound(items)
  end
  if AddArray(key) then
    searched.Value(key)=false
    for count=si to ei
      child(key).AppendInteger items(count)
    next
  end
End Sub

plistDict.SetList:
Sub SetList(key as string,items() as boolean,startIndex as integer,endIndex as integer)
  dim count,si,ei as Integer
  
  if exists(key) then
    Remove(key)
  end
  si=startIndex
  ei=endIndex
  if si>UBound(items) then
    si=0
  end
  if ei>UBound(items) then
    ei=UBound(items)
  end
  if AddArray(key) then
    searched.Value(key)=false
    for count=si to ei
      child(key).AppendBoolean items(count)
    next
  end
End Sub

plistDict.GetList:
Sub GetList(key as string,byref items() as boolean,indexStart as integer)
  dim count As integer
  dim newArray(0) as boolean
  
  if indexStart=0 then
    redim newArray(-1)
  end
  for count=0 to child(key).count-1
    newArray.Append child(key).GetBoolean(str(count))
  next
  items=newArray
End Sub

CDownloadModel.getStateAsString:
Protected Function getStateAsString() As string
  
  dim status(-1) as string
  
  #if targetPPC or kOldJava
    //* old core before bittorrent integration *//
    
    select case me.state
    case 0 'QUEUED
      return getLocalizedString("Queued", "Misc")
      
    case 1 'CONNECTING
      return getLocalizedString("Connecting...", "Misc")
      
    case 2 'DOWNLOADING
      
    case 3 'BUSY
      
    case 4 'COMPLETE
      return getLocalizedString("Complete", "Misc")
      
    case 5 'ABORTED
      return getLocalizedString("Aborted", "Misc")
      
    case 6 'GAVE_UP
      return getLocalizedString("Gave up", "Misc")
      
    case 7 'DISK_PROBLEM
      return getLocalizedString("Disk error occurred", "Misc")
      
    case 8 'WAITING_FOR_RESULTS
      return getLocalizedString("Gathering sources...", "Misc")
      
    case 9 'CORRUPT_FILE
      return getLocalizedString("Possibly corrupt", "Misc")
      
    case 10 'REMOTE_QUEUED
      
    case 11 'HASHING
      return getLocalizedString("Verifying...", "Misc")
      
    case 12 'SAVING
      return getLocalizedString("Saving...", "Misc")
      
    case 13 'WAITING_FOR_USER
      
    case 14 'WAITING_FOR_CONNECTIONS
      return getLocalizedString("Connecting...", "Misc")
      
    case 15 'ITERATIVE_GUESSING
      return getLocalizedString("Gathering sources...", "Misc")
      
    case 16 'IDENTIFY_CORRUPTION
      
    case 17 'RECOVERY_FAILED
      
    case 18 'PAUSED
      return getLocalizedString("Paused", "Misc")
      
    case 19 'INVALID
      return getLocalizedString("Invalid license", "Misc")
      
    end
    
  #else //* new core *//
    select case me.state
    case 1 'QUEUED
      return getLocalizedString("Queued", "Misc")
      
    case 2 'CONNECTING
      return getLocalizedString("Connecting...", "Misc")
      
    case 5 'COMPLETE
      return getLocalizedString("Complete", "Misc")
      
    case 6 'ABORTED
      return getLocalizedString("Aborted", "Misc")
      
    case 7 'GAVE_UP
      return getLocalizedString("Gave up", "Misc")
      
    case 8 'DISK_PROBLEM
      return getLocalizedString("Disk error occurred", "Misc")
      
    case 9 'WAITING_FOR_RESULTS
      return getLocalizedString("Gathering sources...", "Misc")
      
    case 10 'CORRUPT_FILE
      return getLocalizedString("Possibly corrupt", "Misc")
      
    case 12 'HASHING
      return getLocalizedString("Verifying...", "Misc")
      
    case 13 'SAVING
      return getLocalizedString("Saving...", "Misc")
      
    case 20 'PAUSED
      return getLocalizedString("Paused", "Misc")
      
    case 21 'INVALID
      return getLocalizedString("Invalid license", "Misc")
      
    end
    
  #endif
  
  if me.active <> 0 then status.append _
      getLocalizedStringWithIntegerData("%i active", "Misc", me.active)
  
  if me.queued <> 0 then status.append _
      getLocalizedStringWithIntegerData("%i queued", "Misc", me.queued)
  
  if me.busy <> 0 then status.append _
      getLocalizedStringWithIntegerData("%i busy", "Misc", me.busy)
  
  if ubound(status) = -1 then
    return getLocalizedString("No active sources", "Misc")
    
  else
    return status.join(getLocalizedString(", ", "Misc"))
    
  end
  
End Function

CDownloadModel.isActive:
Function isActive() As boolean
  
  #if targetPPC or kOldJava
    return me.isComplete = false and (me.state = 2 or me.measuredBandwidth <> 0)
  #else
    return me.isComplete = false and (me.state = 3 or me.measuredBandwidth <> 0)
  #endif
  
End Function

CDownloadModel.Constructor:
Sub Constructor(args() as string)
  
  me.hashCode = args(1).val
  me.filename = args(2)
  me.state = args(3).val
  me.amountRequested = args(4).val
  me.amountTransfered = args(5).val
  me.sha1 = args(6)
  
  me.extension = me.fileName.getExtension
  me.progress = me.amountTransfered / me.amountRequested
  
End Sub

CDownloadModel.updateStats:
Sub updateStats(args() as string)
  
  me.state = args(2).val
  me.amountRequested = args(3).val
  me.amountTransfered = args(4).val
  me.measuredBandwidth = args(5).val
  me.averageBandwidth = args(6).val
  me.active = args(7)
  me.busy = args(8)
  me.files = args(9)
  me.queued = args(10)
  me.path = args(11)
  me.hosts = args(12)
  
  if me.measuredBandwidth <> 0 then
    me.timeRemaining = (me.amountRequested - me.amountTransfered) / me.averageBandwidth
    
  else
    me.timeRemaining = 0
    
  end
  
  me.progress = me.amountTransfered / me.amountRequested
  
End Sub

CDownloadModel.invalidateValues:
Sub invalidateValues()
  
  me.sName = nil
  
  me.pTransfer = nil
  me.sTransfer = nil
  
  me.pTime = nil
  me.sTime = nil
  
End Sub

CDownloadModel.getSName:
Function getSName() As Variant
  
  if me.sName = nil then me.sName = me.getStateAsString
  
  return me.sName
  
End Function

CDownloadModel.canRemove:
Function canRemove() As boolean
  
  return me.isCanceled = false
  
End Function

CDownloadModel.getSTransfer:
Function getSTransfer() As Variant
  
  if me.sTransfer = nil then
    if me.isComplete then
      me.sTransfer = me.amountTransfered.getShortSize
      
    elseif me.amountTransfered = 0 then
      me.sTransfer = "~/" + me.amountRequested.getShortSize
      
    else
      me.sTransfer = me.amountTransfered.getShortSize + "/" + me.amountRequested.getShortSize
      
    end
    
  end
  
  return me.sTransfer
  
End Function

CFilterModel.Constructor:
Sub Constructor()
  
  me.enabled = false
  me.sortColumn = -1
  me.sortDirection = ListBox.sortAscending
  me.columnWidths = "18, 15%, 15%, 15%, 10%, 10%, 10%, 10%, 10%, 600"
  
End Sub

CFilterModel.Constructor:
Sub Constructor(keyword as string, enabled as boolean, media as integer, bitrate as integer, size as integer,sources as integer, speed as integer, sortColumn as integer, sortDirection as integer, columnWidths as string)
  
  me.keyword = keyword
  me.enabled = enabled
  me.media = media
  me.bitrate = bitrate
  me.size = size
  me.sources = sources
  me.speed = speed
  me.sortColumn = sortColumn
  me.sortDirection = sortDirection
  me.columnWidths = columnWidths
  
End Sub

CFilterModel.Constructor:
Sub Constructor(filter as CFilterModel)
  
  me.bitrate = filter.bitrate
  me.enabled = filter.enabled
  me.keyword = filter.keyword
  me.media = filter.media
  me.size = filter.size
  me.sortColumn = filter.sortColumn
  me.sortDirection = filter.sortDirection
  me.columnWidths = filter.columnWidths
  me.sources = filter.sources
  me.speed = filter.speed
  me.scrollPosition = filter.scrollPosition
  
End Sub

CNetworkModel.Constructor:
Sub Constructor(args() as string)
  
  me.address = args(1)
  me.agent = args(2)
  me.language = args(3)
  me.type = args(4)
  me.uptime = ticks
  
End Sub

CNetworkModel.getPTime:
Function getPTime() As Variant
  
  if me.pTime = nil then me.pTime = getUptime(ticks - me.uptime)
  
  return me.pTime
  
End Function

CNetworkModel.invalidateValues:
Sub invalidateValues()
  
  me.pTime = nil
  
End Sub

CNetworkModel.getRepresentation:
Function getRepresentation() As variant
  
  return me.address
  
End Function

CQueryModel.Constructor:
Sub Constructor(queryIndex as integer, queryString as string, queryFilter as CFilterModel, keepInSidebar as boolean)
  
  dim arg, args(-1) as string
  
  me.response = new CResponseController
  me.queryIndex = queryIndex
  me.queryString = queryString
  me.queryFilter = queryFilter
  me.keepInSidebar = keepInSidebar
  args = queryString.split(":")
  
  if queryString = getLocalizedString("What's New?", "Misc") then
    me.queryType = 0 //* what's new query *//
    
  elseif ubound(args) = 1 and isNumeric(args(1)) then
    me.queryType = 1 //* browse query *//
    
  elseif queryString.getExtension <> "" then
    me.queryType = 2 //* find more sources query *//
    
  else
    me.queryType = 3 //* normal query *//
    args = queryString.lowercase.trim.split
    
    for each arg in args
      if arg.leftb(1) = "-" then
        me.negativeFilterKeywords.append arg.midb(2)
        
      else
        me.positiveFilterKeywords.append arg
        
      end
      
    next
    
  end
  
End Sub

CQueryModel.clearAllResults:
Sub clearAllResults()
  
  redim me.response.representedObjects(-1)
  me.response.representedInfos.clear
  
End Sub

CQueryModel.Constructor:
Sub Constructor(responses() as CResponseModel, hashTable as Dictionary)
  
  me.response = new CResponseController
  me.response.representedObjects = responses
  me.response.representedInfos = hashTable
  
End Sub

CQueryModel.Constructor:
Sub Constructor(queryString as string)
  
  me.response = new CResponseController
  me.queryString = queryString
  
End Sub

CQueryModel.Constructor:
Sub Constructor()
  
  me.response = new CResponseController
  
End Sub

CResponseModel.addResponse:
Sub addResponse(args() as string)
  
  me.queryIndexes.append args(1).val
  me.localIndexes.append args(2).val
  
  if me.address.indexOf(args(4)) = -1 then
    
    me.sources = me.sources + args(3).val + 1
    me.address.append args(4)
    me.isBrowseHostEnabled.append (args(5).val = 1)
    me.speed = me.speed + args(8).val
    
  end
  
End Sub

CResponseModel.Constructor:
Sub Constructor(args() as string)
  
  me.queryIndexes(0) = args(1).val
  me.localIndexes(0) = args(2).val
  
  me.sources = args(3).val + 1
  me.address(0) = args(4)
  me.isBrowseHostEnabled(0) = (args(5).val =  1)
  
  me.sha1 = args(6)
  me.fileName = args(7)
  me.extension = me.fileName.getExtension
  me.mediaType = me.extension.getMediaType
  me.speed = args(8).val
  me.fileSize = args(9).val
  me.bitrate = args(10).val
  me.seconds = args(11).val
  me.artist = args(12)
  me.album = args(13)
  me.title = args(14)
  me.spam = (args(15).val = 1)
  
  if kAqID3Title and me.title.lenb <> 0 then
    me.displayName = me.title
    
  else
    me.displayName = me.fileName
    
  end
  
End Sub

CResponseModel.getPIcon:
Function getPIcon() As Variant
  
  if me.pIcon = nil then
    if me.marked then
      me.pIcon = getControlPicture(3)
      
    else
      me.pIcon = getSmallMediaPicture(me)
      
    end
    
  end
  
  return me.pIcon
  
End Function

CResponseModel.getPSize:
Function getPSize() As Variant
  
  if me.pSize = nil then me.pSize = me.fileSize.getShortSize
  
  return me.pSize
  
End Function

CResponseModel.getPBitrate:
Function getPBitrate() As Variant
  
  if me.pBitrate = nil then me.pBitrate = me.bitrate.getKbps
  
  return me.pBitrate
  
End Function

CResponseModel.getPLength:
Function getPLength() As Variant
  
  if me.pLength = nil then me.pLength = me.seconds.getLength
  
  return me.pLength
  
End Function

CResponseModel.getPSources:
Function getPSources() As Variant
  
  if me.pSources = nil then me.pSources = me.sources.getQuality
  
  return me.pSources
  
End Function

CResponseModel.getPSpeed:
Function getPSpeed() As Variant
  
  if me.pSpeed = nil then me.pSpeed = me.speed.getKb
  
  return me.pSpeed
  
End Function

CResponseModel.invalidateValues:
Sub invalidateValues()
  
  me.pIcon = nil
  me.pSources = nil
  me.pSpeed = nil
  
End Sub

CResponseModel.convertEncoding:
Sub convertEncoding(type as integer)
  
  select case type
    
  case 0
    if me.displayName.canNonLossyConversation(Encodings.ISOLatin1) then _
        me.displayName = me.displayName.convertEncoding(Encodings.ISOLatin1).defineEncoding(Encodings.systemDefault)
    if me.artist.canNonLossyConversation(Encodings.ISOLatin1) then _
        me.artist = me.artist.convertEncoding(Encodings.ISOLatin1).defineEncoding(Encodings.systemDefault)
    if me.album.canNonLossyConversation(Encodings.ISOLatin1) then _
        me.album = me.album.convertEncoding(Encodings.ISOLatin1).defineEncoding(Encodings.systemDefault)
    
  case 1
    if me.displayName.canNonLossyConversation(Encodings.ASCII) then _
        me.displayName = me.displayName.convertEncoding(Encodings.ASCII).defineEncoding(Encodings.systemDefault)
    if me.artist.canNonLossyConversation(Encodings.ASCII) then _
        me.artist = me.artist.convertEncoding(Encodings.ASCII).defineEncoding(Encodings.systemDefault)
    if me.album.canNonLossyConversation(Encodings.ASCII) then _
        me.album = me.album.convertEncoding(Encodings.ASCII).defineEncoding(Encodings.systemDefault)
    
    'case 2
    'if me.displayName.canNonLossyConversation(Encodings.ASCII) then _
    'me.displayName = me.displayName.convertEncoding(Encodings.ASCII).convertPSString.defineEncoding(Encodings.systemDefault)
    'if me.artist.canNonLossyConversation(Encodings.ASCII) then _
    'me.artist = me.artist.convertEncoding(Encodings.ASCII).convertPSString.defineEncoding(Encodings.systemDefault)
    'if me.album.canNonLossyConversation(Encodings.ASCII) then _
    'me.album = me.album.convertEncoding(Encodings.ASCII).convertPSString.defineEncoding(Encodings.systemDefault)
    
  end
  
End Sub

CResponseModel.getRepresentation:
Function getRepresentation() As variant
  
  return me.sha1
  
End Function

CSidebarModel.Constructor:
Sub Constructor(caption as string)
  
  me.caption = caption
  me.primary = 0
  me.secondary = 0
  me.index = 0
  me.interval = -1
  me.highlighted = true
  
End Sub

CSidebarModel.getRepresentation:
Function getRepresentation() As variant
  
  return me.index
  
End Function

CSidebarModel.Constructor:
Sub Constructor(caption as string, index as integer, interval as integer)
  
  me.caption = caption
  me.primary = 0
  me.secondary = 0
  me.index = index
  me.interval = interval
  
End Sub

CSidebarModel.incrementStats:
Sub incrementStats(selected as boolean, increaseSecondary as boolean)
  
  me.highlighted = not selected
  me.primary = me.primary + 1
  
  if increaseSecondary then me.secondary = me.secondary + 1
  
End Sub

CSidebarModel.overwriteStats:
Sub overwriteStats(index as integer, interval as integer)
  
  me.index = index
  me.interval = interval
  
End Sub

CSidebarModel.getPState:
Function getPState() As variant
  
  if me.pState = nil then
    if me.primary = 0 then
      me.pState = nil
      
    elseif me.primary = me.secondary then
      me.pState = me.primary
      
    else
      me.pState =  me.secondary + "/" + me.primary
      
    end
    
  end
  
  return me.pState
  
End Function

CSidebarModel.invalidateValues:
Sub invalidateValues()
  
  me.pState = nil
  
End Sub

CSidebarModel.updateStats:
Sub updateStats(primary as variant, secondary as variant)
  
  me.primary = primary
  me.secondary = secondary
  
End Sub

CStatsModel.getRepresentation:
Function getRepresentation() As variant
  
  //* Overide *//
  
End Function

CToolbarModel.Constructor:
Sub Constructor(caption as string, helptag as string, width as integer)
  
  me.caption = caption
  me.helpTag = helpTag
  me.width = width
  
End Sub

CTransferModel.getMediaType:
Function getMediaType() As Integer
  
  return me.extension.getMediaType
  
End Function

CTransferModel.getPName:
Function getPName() As Variant
  
  if me.pName = nil then me.pName = me.fileName
  
  return me.pName
  
End Function

CTransferModel.isActive:
Function isActive() As boolean
  
  //* Overrides *//
  
End Function

CTransferModel.canRemove:
Function canRemove() As Boolean
  
  //* Override *//
  
End Function

CTransferModel.getSTime:
Function getSTime() As Variant
  
  if me.sTime = nil and me.isComplete = false and me.timeRemaining <> 0 then me.sTime = getLocalizedString("remaining", "Misc")
  
  return me.sTime
  
End Function

CTransferModel.getPTime:
Function getPTime() As Variant
  
  if me.pTime = nil and me.isComplete = false and me.timeRemaining <> 0 then me.pTime = me.timeRemaining.getTimeRemaining
  
  return me.pTime
  
End Function

CTransferModel.getPTransfer:
Function getPTransfer() As Variant
  
  if me.pTransfer = nil and me.isComplete = false and me.measuredBandwidth <> 0 then me.pTransfer = me.measuredBandwidth.getKbs
  
  return me.pTransfer
  
End Function

CTransferModel.getSName:
Function getSName() As Variant
  
  //* Override *//
  
End Function

CTransferModel.getSTransfer:
Function getSTransfer() As Variant
  
  //* Override *//
  
End Function

CTransferModel.getPIcon:
Function getPIcon() As Variant
  
  if me.pIcon = nil then me.pIcon = getLargeMediaPicture(me.getMediaType, me.extension)
  
  return me.pIcon
  
End Function

CTransferModel.getRepresentation:
Function getRepresentation() As variant
  
  return me.hashCode
  
End Function

CUploadModel.isActive:
Function isActive() As boolean
  
  return me.isComplete = false and (me.state = 3 or me.measuredBandwidth <> 0)
  
End Function

CUploadModel.Constructor:
Sub Constructor(args() as string)
  
  me.hashCode = args(1).val
  me.fileName = args(2)
  me.ip = args(3)
  me.port = args(4)
  me.userAgent = args(5)
  me.state = args(6).val
  me.amountRequested = args(7).val
  me.amountTransfered = args(8).val
  me.path = args(9)
  me.isBrowseHostEnabled = (args(10).val = 1)
  
  me.extension = me.fileName.getExtension
  me.progress = me.amountTransfered / me.amountRequested
  me.startingPoint = me.amountTransfered
  
End Sub

CUploadModel.canRemove:
Function canRemove() As boolean
  
  return true
  
End Function

CUploadModel.updateStats:
Sub updateStats(args() as string)
  
  me.state = args(2).val
  me.amountRequested = args(3).val
  me.amountTransfered = args(4).val
  me.measuredBandwidth = args(5).val
  me.averageBandwidth = args(6).val
  
  if me.measuredBandwidth <> 0 then
    me.timeRemaining = (me.amountRequested - me.amountTransfered) / me.averageBandwidth
    
  else
    me.timeRemaining = 0
    
  end
  
  me.progress = me.amountTransfered / me.amountRequested
  
End Sub

CUploadModel.invalidateValues:
Sub invalidateValues()
  
  me.pTransfer = nil
  me.sTransfer = nil
  
  me.pTime = nil
  me.sTime = nil
  
End Sub

CUploadModel.getSName:
Function getSName() As Variant
  
  if me.sName = nil then
    if me.isBrowseHostEnabled then
      me.sName = me.ip + ":" + me.port + getLocalizedString(", ", "Misc") + me.userAgent
      
    else
      me.sName = me.ip + getLocalizedString(", ", "Misc") + me.userAgent
      
    end
    
  end
  
  return me.sName
  
End Function

CUploadModel.getSTransfer:
Function getSTransfer() As Variant
  
  if me.sTransfer = nil then
    if me.isComplete then
      me.sTransfer = getLocalizedStringWithStringData("%@ sent", "Misc", me.amountTransfered.getShortSize)
      
    elseif me.amountTransfered = 0 then
      me.sTransfer = "~/" + me.amountRequested.getShortSize
      
    else
      me.sTransfer = me.amountTransfered.getShortSize + "/" + me.amountRequested.getShortSize
      
    end
    
  end
  
  return me.sTransfer
  
End Function

MApplicationExtension.notifyStart:
Sub notifyStart(w as window)
  
  #if targetMacOS
    Declare Function NMInstall Lib kCarbon (nmReqPtr as Ptr) As Integer
    Declare Function GetResource lib kCarbon (resType as integer, resID as integer) as integer
    
    dim resourceType as memoryBlock
    dim flashIconHandle as integer
    
    const kResourceIDFinder = 3
    
    if notify = nil then
      resourceType = newMemoryBlock(5)
      resourceType.pString(0) = "SICN"
      flashIconHandle = GetResource(resourceType.long(1), kResourceIDFinder)
      notify = newMemoryBlock(36)
      notify.short(4) = 8
      notify.short(14) = 1
      notify.long(16) = flashIconHandle
      
      call NMInstall(notify)
      
    end
    
  #elseif targetWin32
    Dim FlashInfo As memoryblock
    
    Const FLASHW_STOP = 0 'Stop flashing. The system restores the window to its original state.
    Const FLASHW_CAPTION = &H1 'Flash the window caption.
    Const FLASHW_TRAY = &H2 'Flash the taskbar button.
    Const FLASHW_TIMER = &H4 'Flash continuously, until the FLASHW_STOP flag is set.
    Const FLASHW_TIMERNOFG = &HC 'Flash continuously until the window comes to the foreground.
    
    if targetNT then
      Declare Function FlashWindowEx Lib "user32" (pfwi As ptr) As integer
      flashinfo = newmemoryBlock(20)
      'Specifies the size of the structure.
      flashinfo.Long(0) = 20
      'Specifies the flash status
      flashinfo.long(8) = FLASHW_CAPTION + FLASHW_TRAY + FLASHW_TIMERNOFG
      'Specifies the rate, in milliseconds, at which the window will be flashed. If dwTimeout is zero, the function uses the default cursor blink rate.
      FlashInfo.long(16) = 0
      'Handle to the window to be flashed. The window can be either opened or minimized.
      FlashInfo.long(4) = w.winhWND
      'Specifies the number of times to flash the window.
      FlashInfo.long(12) = 0
      call FlashWindowEx(FlashInfo)
      
    else
      Declare Function FlashWindow Lib "user32" (hwnd As integer, bInvert As integer) As integer
      call FlashWindow(w.winhwnd, 1)
      
    end
    
  #elseif targetLinux
    'todo
    
  #endif
  
End Sub

MApplicationExtension.notifyStop:
Sub notifyStop(w as window)
  
  #if targetMacOS
    Declare Function NMRemove Lib kCarbon (nmReqPtr as Ptr) As Integer
    
    if notify <> nil then
      call NMRemove(notify)
      notify = nil
      
    end
    
  #elseif targetWin32
    Dim FlashInfo As memoryblock
    
    Const FLASHW_STOP = 0 'Stop flashing. The system restores the window to its original state.
    Const FLASHW_CAPTION = &H1 'Flash the window caption.
    Const FLASHW_TRAY = &H2 'Flash the taskbar button.
    Const FLASHW_TIMER = &H4 'Flash continuously, until the FLASHW_STOP flag is set.
    Const FLASHW_TIMERNOFG = &HC 'Flash continuously until the window comes to the foreground.
    
    if targetNT then
      Declare Function FlashWindowEx Lib "user32" (pfwi As ptr) As integer
      flashinfo = newmemoryBlock(20)
      'Specifies the size of the structure.
      flashinfo.Long(0) = 20
      'Specifies the flash status
      flashinfo.long(8) = FLASHW_STOP
      'Specifies the rate, in milliseconds, at which the window will be flashed. If dwTimeout is zero, the function uses the default cursor blink rate.
      FlashInfo.long(16) = 0
      'Handle to the window to be flashed. The window can be either opened or minimized.
      FlashInfo.long(4) = w.winhWND
      'Specifies the number of times to flash the window.
      FlashInfo.long(12) = 0
      call FlashWindowEx(FlashInfo)
      
    end
    
  #elseif targetLinux
    'todo
    
  #endif
  
End Sub

MApplicationExtension.targetNT:
Function targetNT() As Boolean
  
  #if targetWin32
    Declare Sub GetVersionExA lib "Kernel32" ( info as Ptr )
    
    dim info as new MemoryBlock( 148 )
    
    info.Long( 0 ) = info.Size
    GetVersionExA( info )
    
    return info.Long( 4 ) >= 5 'Windows 2000/XP/2003
    
  #endif
  
End Function

MApplicationExtension.hideApplication:
Function hideApplication(appName as string) As boolean
  
  #if targetMacOS
    Dim ae as appleevent
    Dim obj as AppleEventObjectSpecifier
    
    ae = NewAppleEvent( "core", "setd", "MACS" )
    
    obj = GetNamedObjectDescriptor( "prcs", Nil, AppName.convertEncoding(Encodings.systemDefault) )
    obj = GetPropertyObjectDescriptor( obj, "pvis" )
    ae.ObjectSpecifierParam( "----" ) = obj
    
    ae.BooleanParam( "data" ) = false
    
    return ae.send
    
  #endif
  
End Function

MApplicationExtension.resizeAllListBoxes:
Sub resizeAllListBoxes()
  
  dim i, j as integer
  dim w as Window
  dim c as ListBox
  
  for i = windowCount - 1 downto 0
    
    if window(i) isa CWindow then
      w = window(i)
      
      for j = w.controlCount - 1 downto 0
        
        if w.control(j) isa ListBox then
          c = ListBox(w.control(j))
          
          if c.hasHeading then
            c.textFont = kAqStandardTextFont
            c.textSize = kAqStandardTextSize
            
          else
            c.textFont = kAqSidebarTextFont
            c.textSize = kAqSidebarTextSize
            
          end
          
        end
        
      next
      
    end
    
  next
  
End Sub

MApplicationExtension.getDialog:
Function getDialog(primary as string, secondary as string, ok as string, cancel as string) As messageDialog
  
  dim m as new messageDialog
  
  m.icon = 0
  m.message = primary
  m.explanation = secondary
  
  #if targetMachO or targetWin32 or targetLinux
    m.actionButton.caption = ok
    m.cancelButton.caption = cancel
    
  #elseif targetCarbon
    m.actionButton.caption = ok.convertEncoding(Encodings.systemDefault)
    m.cancelButton.caption = cancel.convertEncoding(Encodings.systemDefault)
    
  #endif
  
  m.cancelButton.visible = true
  
  return m
  
End Function

MApplicationExtension.getMenuHandle:
Function getMenuHandle(hWnd as integer) As integer
  
  #if targetWin32
    Declare Function GetMenu Lib "user32" (hWnd As integer) As integer
    return GetMenu(hWnd)
    
  #endif
  
End Function

MApplicationExtension.getSubMenuHandle:
Function getSubMenuHandle(hMenu as integer, nPos as integer) As integer
  
  #if targetWin32
    Declare Function GetSubMenu Lib "user32" (hMenu As integer, nPos As integer) As integer
    return GetSubMenu(hMenu, nPos)
    
  #endif
  
End Function

MApplicationExtension.localizeSubMenus:
Sub localizeSubMenus(hMenu as integer, m as menuItem)
  
  #if targetMachO
    dim i, j as integer
    
    j = m.count - 1
    
    for i = 0 to j
      
      if m.item(i).text <> "-" then
        m.item(i).text = getLocalizedString(m.item(i).text, "MenuItem")
        m.item(i).commandKey = getLocalizedString(m.item(i).commandKey, "MenuItem")
        
        if m.item(i).count <> 0 then localizeSubMenus 0, m.item(i)
        
      end
      
    next
    
  #elseif targetCarbon
    dim i, j as integer
    
    j = m.count - 1
    
    for i = 0 to j
      
      //* fix rb bug *//
      
      if m.item(i).text <> "-" then
        if m.item(i).count = 0 then
          m.item(i).text = getLocalizedString(m.item(i).text, "MenuItem")
          m.item(i).commandKey = getLocalizedString(m.item(i).commandKey, "MenuItem")
          
        else
          localizeSubMenus 0, m.item(i)
          
        end
        
      end
      
    next
    
  #elseif targetWin32
    Declare Function ModifyMenuA Lib "user32" (hMenu As integer, nPosition As integer, wFlags As integer, wIDNewItem As integer, lpString As ptr) As integer
    Declare Function ModifyMenuW Lib "user32" (hMenu As integer, nPosition As integer, wFlags As integer, wIDNewItem As integer, lpString As ptr) As integer
    
    Const MF_BYPOSITION = &H400
    Const MF_POPUP = &H10
    Const MF_HELP = &H4000
    
    dim lpString as new MemoryBlock(255)
    dim i, j as integer
    
    //* fix rb bug *//
    
    j = m.count - 1
    
    for i = 0 to j
      
      if m.item(i).text <> "-" then
        
        if m.item(i).count = 0 then
          m.item(i).text = getLocalizedString(m.item(i).text, "MenuItem")
          m.item(i).commandKey = getLocalizedString(m.item(i).commandKey, "MenuItem")
          
        else
          if targetNT then
            lpString.stringValue(0, 255) = getLocalizedString(m.item(i).text, "MenuItem").convertEncoding(Encodings.UTF16)
            call ModifyMenuW(hMenu, i, MF_BYPOSITION, getSubMenuHandle(hMenu, i), lpString)
            
          else
            lpString.CString(0) = getLocalizedString(m.item(i).text, "MenuItem").convertEncoding(Encodings.systemDefault)
            call ModifyMenuA(hMenu, i, MF_BYPOSITION, getSubMenuHandle(hMenu, i), lpString)
            
          end
          
          localizeSubMenus getSubMenuHandle(hMenu, i), m.item(i)
          
        end
        
      end
      
    next
    
  #elseif targetLinux
    'todo
    
  #endif
  
End Sub

MApplicationExtension.drawMenuItems:
Sub drawMenuItems(hWnd as integer)
  
  #if targetWin32
    Declare Function DrawMenuBar Lib "user32" (hwnd As Integer) As Integer
    call DrawMenuBar(hWnd)
    
  #endif
  
End Sub

MApplicationExtension.initializeColors:
Sub initializeColors()
  
  #if targetMacOS or targetLinux
    kBackColor = &cFFFFFF
    kTextColor = &c000000
    
  #elseif targetWin32
    dim res as memoryblock
    dim c as color
    
    Const COLOR_WINDOW = 5
    Const COLOR_WINDOWTEXT = 8
    
    Declare Function GetSysColor Lib "user32" (nIndex As integer) As integer
    res = newmemoryBlock(4)
    
    res.long(0) = GetSysColor(COLOR_WINDOW)
    kBackColor = rgb(res.byte(0),res.byte(1),res.byte(2))
    res.long(0) = GetSysColor(COLOR_WINDOWTEXT)
    kTextColor = rgb(res.byte(0),res.byte(1),res.byte(2))
    
  #endif
  
  'kRowColor = &cEBF5FF
  kRowColor = rgb(bitwise.bitXor(kBackColor.red, &h14), _
      bitwise.bitXor(kBackColor.green, &h0A), _
      bitwise.bitXor(kBackColor.blue, &h00))
  
  'kGrayTextColor = &c808080
  kGrayTextColor = rgb(bitwise.bitXor(kTextColor.red, &h80), _
      bitwise.bitXor(kTextColor.green, &h80), _
      bitwise.bitXor(kTextColor.blue, &h80))
  
  'kLightGrayTextColor = &c949494
  kLightGrayTextColor = rgb(bitwise.bitXor(kTextColor.red, &h94), _
      bitwise.bitXor(kTextColor.green, &h94), _
      bitwise.bitXor(kTextColor.blue, &h94))
  
  'kLightRedTextColor = &cF03934
  kLightRedTextColor = rgb(bitwise.bitXor(kTextColor.red, &hF0), _
      bitwise.bitXor(kTextColor.green, &h39), _
      bitwise.bitXor(kTextColor.blue, &h34))
  
End Sub

MApplicationExtension.setApplicationPriority:
Sub setApplicationPriority(processName as string, level as integer)
  'typedef struct tagPROCESSENTRY32
  '{
  'DWORD   4 dwSize; 
  'DWORD   4 cntUsage;
  'DWORD   4 th32ProcessID;          // this process
  'ULONG_PTR 4 th32DefaultHeapID;
  'DWORD   4 th32ModuleID;           // associated exe
  'DWORD   4 cntThreads;
  'DWORD   4 th32ParentProcessID;    // this process's parent process
  'LONG    4 pcPriClassBase;         // Base priority of process's threads
  'DWORD   4 dwFlags;
  'CHAR    260 szExeFile[MAX_PATH];    // Path
  '} PROCESSENTRY32;
  
  #if TargetWin32
    Declare Function GetLastError Lib "Kernel32" () as Integer
    
    Declare Function CreateToolhelp32Snapshot Lib "Kernel32" (flags as Integer, id as Integer ) as Integer
    Declare Sub CloseHandle Lib "Kernel32" ( handle as Integer )
    Declare Sub Process32First Lib "Kernel32" ( handle as Integer, entry as Ptr )
    Declare Function Process32Next Lib "Kernel32" ( handle as Integer, entry as Ptr ) as Boolean
    
    Declare Function OpenProcess Lib "Kernel32" ( access as Integer, inherit as Boolean, procID as Integer ) as Integer
    Declare Sub SetPriorityClass Lib "Kernel32" ( handle as Integer, priority as Integer )
    
    dim snapHandle as Integer
    snapHandle = CreateToolhelp32Snapshot( 2, 0 )
    
    dim mb as new MemoryBlock( 260 + 36 )
    dim file as String
    
    mb.Long( 0 ) = mb.Size
    Process32First( snapHandle, mb )
    
    dim err as Integer = GetLastError
    dim pid as integer = -1
    
    do
      file = mb.CString( 36 )
      
      if file = processName then
        pid = mb.long( 8 )
        exit
      end
      
      Call Process32Next( snapHandle, mb )
    loop until GetLastError() = 18
    
    CloseHandle( snapHandle )
    if pid = -1 then return
    
    ' Get a handle to the current process
    dim processHandle as Integer
    const PROCESS_SET_INFORMATION = &h200
    processHandle = OpenProcess( PROCESS_SET_INFORMATION, false, pid )
    
    ' And set the priority
    SetPriorityClass( processHandle, level )
    
    ' And close the handle to the module
    CloseHandle( processHandle )
    
  #endif
  
End Sub

MApplicationExtension.targetLeopard:
Function targetLeopard() As boolean
  
  #if targetMachO
    dim ver as integer
    if System.gestalt("sysv", ver) and ver >= &h1050 then return true
    
  #endif
  
End Function

MDataExtension.getTimeRemaining:
Function getTimeRemaining(Extends seconds as double) As String
  
  if seconds = 0 then return ""
  
  dim value as variant
  
  value = seconds / 86400 mod 24
  
  if value = 1 then return getLocalizedString("1 day", "Misc")
  if value <> 0 then return getLocalizedStringWithIntegerData("%i days", "Misc", value)
  
  value = seconds / 3600 mod 60
  
  if value = 1 then return getLocalizedString("1 hour", "Misc")
  if value <> 0 then return getLocalizedStringWithIntegerData("%i hours", "Misc", value)
  
  value = seconds / 60 mod 60
  
  if value = 1 then return getLocalizedString("1 minute", "Misc")
  if value <> 0 then return getLocalizedStringWithIntegerData("%i minutes", "Misc", value)
  
  value =  seconds mod 60
  
  if value = 1 then return getLocalizedString("1 second", "Misc")
  if value <> 0 then return getLocalizedStringWithIntegerData("%i seconds", "Misc", value)
  
End Function

MDataExtension.getShortSize:
Function getShortSize(Extends bytes as double) As String
  
  if kAqKbFileSize then
    return format(bytes, "#,#,#,#,#")
    
  else
    if bytes < 1048576 then
      return format(bytes / 1024, getLocalizedString("#.0\ \k\B", "Misc"))
      
    elseif bytes < 1073741824 then
      return format(bytes / 1048576, getLocalizedString("#.0\ \M\B", "Misc"))
      
    else
      return format(bytes / 1073741824, getLocalizedString("#.0\ \G\B", "Misc"))
      
    end
    
  end
  
End Function

MDataExtension.getUptime:
Function getUptime(millseconds as double) As String
  
  dim seconds as double = millseconds \ 60
  
  if seconds = 0 then return ""
  
  dim value as variant
  
  value = seconds \ 86400 mod 24
  
  if value = 1 then return getLocalizedString("1 day", "Misc")
  if value <> 0 then return getLocalizedStringWithIntegerData("%i days", "Misc", value)
  
  value = seconds \ 3600 mod 60
  
  if value = 1 then return getLocalizedString("1 hour", "Misc")
  if value <> 0 then return getLocalizedStringWithIntegerData("%i hours", "Misc", value)
  
  value = seconds \ 60 mod 60
  
  if value = 1 then return getLocalizedString("1 minute", "Misc")
  if value <> 0 then return getLocalizedStringWithIntegerData("%i minutes", "Misc", value)
  
End Function

MDataExtension.getMediaType:
Function getMediaType(Extends extension as string) As integer
  
  dim position as integer = kExtensions.instrb(extension)
  
   //* File *//
  if position = 0 then
    return 5
    
    //* Music *//
  elseif position < 43 then
    return 1
    
    //* Picture *//
  elseif position < 86 then
    return 2
    
    //* Movie *//
  elseif position < 147 then
    return 3
    
    //* Text *//
  else
    return 4
    
  end
  
End Function

MDataExtension.getQuality:
Function getQuality(Extends sources as variant) As string
  
  if sources > 19 then
    return kFourStars + sources
    
  elseif sources > 6 then
    return kThreeStars + sources
    
  elseif sources > 2 then
    return kTwoStars + sources
    
  elseif sources = 2 then
    return kOneStar + sources
    
  end
  
  
End Function

MDataExtension.getKb:
Function getKb(Extends kbps as integer) As string
  
  //* kbps / 8 = kb/s
  //* down 350kbps / 7 = up 50kbps
  //* bandwidth limit 50%
  
  if kbps < 1048576 then
    return format(kbps / 1024, getLocalizedString("#.0\ \k\B", "Misc"))
    
  elseif kbps < 1073741824 then
    return format(kbps / 1048576, getLocalizedString("#.0\ \M\B", "Misc"))
    
  else
    return format(kbps / 1073741824, getLocalizedString("#.0\ \G\B", "Misc"))
    
  end
  
End Function

MDataExtension.getKbps:
Function getKbps(Extends kbps as variant) As string
  
  if kbps <> 0 then return getLocalizedStringWithIntegerData("%i kbps", "Misc", kbps)
  
End Function

MDataExtension.getKbs:
Function getKbs(Extends bs as double) As string
  
  if bs <> 0 then return format(bs / 1024, getLocalizedString("#.0\ \k\B\/\s", "Misc"))
  
End Function

MDataExtension.getBoolAsString:
Function getBoolAsString(Extends b as boolean) As string
  
  if b then
    return "1"
  else
    return "0"
  end
  
End Function

MDataExtension.join:
Function join(Extends s() as string, separator as string = " ") As string
  
  return join(s, separator)
  
End Function

MDataExtension.stringValue:
Function stringValue(Extends value as double) As string
  
  //* Returns unsigned string value *//
  
  return format(value, "-#")
  
End Function

MDataExtension.removeExtension:
Function removeExtension(Extends fileName as string) As string
  
  dim s(-1) as string = fileName.split(".")
  
  if ubound(s) = -1 then return fileName
  
  dim position as integer = kExtensions.instrb(s(ubound(s)).lowercase)
  
  if position <> 0 then
    s.remove ubound(s)
    return s.join(".")
    
  else
    return fileName
    
  end
  
End Function

MDataExtension.reverseEndian:
Function reverseEndian(Extends s as string) As string
  
  dim i, j, byte as integer
  
  j = s.lenb
  
  if j = 0 then return ""
  
  dim m as MemoryBlock = newMemoryBlock(j)
  
  m.stringValue(0,j) = s
  j = j - 1
  
  for i = 0 to j step 2
    
    byte = m.Byte(i)
    m.Byte(i) = m.Byte(i + 1)
    m.Byte(i + 1) = byte
    
  next
  
  return m.StringValue(0, j + 1).defineEncoding(Encodings.UTF16)
  
End Function

MDataExtension.canNonLossyConversation:
Function canNonLossyConversation(Extends s as string, e as textEncoding) As boolean
  
  return s.lenb = s.convertEncoding(e).convertEncoding(Encoding(s)).lenb
  
End Function

MDataExtension.getExtension:
Function getExtension(Extends fileName as string) As string
  
  dim s(-1) as string = fileName.split(".")
  
  if ubound(s) < 1 then return ""
  
  dim i as integer = s(ubound(s)).lenb
  
  if i > 0 and i <= 12 then return s(ubound(s)).lowercase
  
End Function

MDataExtension.join:
Function join(Extends integers() as integer, separator as string) As string
  
  dim i as integer
  dim results(-1) as string
  
  for i = ubound(integers) downto 0
    
    results.append integers(i).stringValue
    
  next
  
  return results.join(separator)
  
End Function

MDataExtension.getLength:
Function getLength(Extends seconds as integer) As String
  
  if seconds = 0 then
    return ""
    
  elseif seconds < 3600 then //minutes : seconds
    return format(seconds \ 60, "#") + ":" + format(seconds mod 60, "00")
    
  else // hours : minutes : seconds
    return format(seconds \ 3600, "#,###") + ":" + format(seconds mod 3600 \ 60, "00") + ":" + format(seconds mod 60, "00")
    
  end
  
End Function

MDataExtension.smartLeftB:
Function smartLeftB(Extends arg as string, length as integer) As string
  
  dim i as integer = arg.len
  
  while arg.left(i).lenb > length
    
    i = i - 1
    
  wend
  
  return arg.left(i)
  
End Function

MDataExtension.equals:
Function equals(Extends args() as string, phase() as string) As Boolean
  
  if ubound(args) <> ubound(phase) then return false
  
  dim i as integer
  
  for i = ubound(args) downto 0
    
    if strcomp(args(i), phase(i), 0) <> 0 then return false
    
  next
  
  return true
  
End Function

MDataExtension.nullStrcomp:
Function nullStrcomp(av as string, bv as string, option as integer) As integer
  
  if av.lenb = 0 or bv.lenb = 0 then
    return strcomp(bv, av, option)
    
  else
    return strcomp(av, bv, option)
    
  end
  
End Function

MDataExtension.completeMatches:
Function completeMatches(extends A as string, B() as string) As boolean
  
  dim i, j, matches as integer
  
  matches = -1
  j = ubound(B)
  
  for i = 0 to j
    
    if A.instrb(B(i)) <> 0 then matches = matches + 1
    
  next
  
  return matches = j
  
End Function

MDataExtension.trim:
Function trim(extends A() as string) As String()
  
  dim i as integer
  
  for i = ubound(A) downto 0
    
    A(i) = A(i).trim
    
    if A(i).lenb = 0 then A.remove i
    
  next
  
  return A
  
End Function

MDataExtension.stringSort:
Sub stringSort(Extends byref temp() as string)
  
  dim i as integer
  dim temp2(-1) as string
  
  for i = ubound(temp) downto 0
    
    if temp(i).lenb = 0 then
      temp2.append temp(i)
      temp.remove i
      
    end
    
  next
  
  temp.sort
  
  for i = ubound(temp2) downto 0
    
    temp.append temp2(i)
    
  next
  
End Sub

MDataExtension.matches:
Function matches(extends A as string, B() as string) As boolean
  
  dim i, j as integer
  
  j = ubound(B)
  
  for i = 0 to j
    
    if A.instrb(B(i)) <> 0 then return true
    
  next
  
  return false
  
End Function

MDataExtension.top:
Function top(Extends theArray() as string) As string
  if ubound(theArray) >= 0 then return theArray(0)
End Function

MDataExtension.convertPSString:
Function convertPSString(extends s as string) As string
  
  dim i, bytes as integer
  dim phase, result as string
  
  while i <= s.lenb
    
    phase = s.midb(i, 1)
    
    if phase.ascb = 92 then
      phase = s.midb(i + 1, 1)
      
      if isNumeric(phase) then
        bytes = val("&o" + s.midB(i + 1, 3))
        result = result + chrb(bytes)
        i = i + 4
        
      else
        result = result + phase
        i = i + 2
        
      end
      
    else
      result = result + phase
      i = i + 1
      
    end
    
  wend
  
  return result
  
End Function

MDefautsController.initializeDefaults:
Sub initializeDefaults()
  
  CDefaultsController1 = new CDefaultsController
  
End Sub

MDefautsController.defaultsWrite:
Sub defaultsWrite(key as string, value as variant)
  
  CDefaultsController1.Write(key, value)
  
End Sub

MDefautsController.finalizeDefaults:
Sub finalizeDefaults()
  
  CDefaultsController1 = nil
  
End Sub

MDefautsController.defaultsReadArrayString:
Function defaultsReadArrayString(key as string, values() as string) As String()
  
  return CDefaultsController1.ReadArrayString(key, values)
  
End Function

MDefautsController.defaultsRead:
Function defaultsRead(key as string, value as variant) As variant
  
  return CDefaultsController1.Read(key, value)
  
End Function

MDefautsController.defaultsWriteArrayString:
Sub defaultsWriteArrayString(key as string, values() as string)
  
  CDefaultsController1.WriteArrayString(key, values)
  
End Sub

MDefautsController.defaultsReadArrayInteger:
Function defaultsReadArrayInteger(key as string, values() as integer) As Integer()
  
  return CDefaultsController1.ReadArrayInteger(key, values)
  
End Function

MDefautsController.defaultsReadArrayBoolean:
Function defaultsReadArrayBoolean(key as string, values() as boolean) As Boolean()
  
  return CDefaultsController1.ReadArrayBoolean(key, values)
  
End Function

MDefautsController.defaultsWriteArrayInteger:
Sub defaultsWriteArrayInteger(key as string, values() as integer)
  
  CDefaultsController1.WriteArrayInteger(key, values)
  
End Sub

MDefautsController.defaultsWriteArrayBoolean:
Sub defaultsWriteArrayBoolean(key as string, values() as boolean)
  
  CDefaultsController1.WriteArrayBoolean(key, values)
  
End Sub

MFolderItemExtension.revealInFinder:
Sub revealInFinder(Extends f as folderitem)
  
  #if targetMacOS
    dim a as AppleEvent = NewAppleEvent("misc", "mvis", "MACS")
    
    a.FolderItemParam("----") = f
    
    if a.send = false then return
    
    a = NewAppleEvent("misc", "actv", "MACS")
    call a.send
    
  #elseif targetWin32
    
    dim l as new Shell
    
    if targetNT then
      l.execute "explorer /select, """ + f.posixPath + """"
      
    else
      l.execute convertEncoding("explorer /select, """ + f.posixPath + """", Encodings.systemDefault)
      
    end
    
  #elseif targetLinux
    f.parent.launch
    
  #endif
  
End Sub

MFolderItemExtension.openWith:
Sub openWith(Extends document as folderItem, application as folderItem)
  
  #if targetMacOS
    dim ae as AppleEvent
    dim obj As AppleEventObjectSpecifier
    
    ae = NewAppleEvent("aevt", "odoc", "MACS")
    obj = GetNamedObjectDescriptor("file", nil, document.absolutePath)
    ae.ObjectSpecifierParam("----") = obj
    obj = GetNamedObjectDescriptor("appf", nil, application.absolutePath)
    ae.ObjectSpecifierParam("usin") = obj
    call ae.send
    
  #elseif targetWin32
    dim l as new Shell
    
    if targetNT then
      l.execute """" + application.posixPath + """ """ + document.posixPath + """"
      
    else
      l.execute convertEncoding("""" + application.posixPath + """ """ + document.posixPath + """", Encodings.systemDefault)
      
    end
    
  #elseif targetLinux
    dim l as new Shell
    
    l.execute """" + application.posixPath + """ """ + document.posixPath + """"
    
  #endif
  
End Sub

MFolderItemExtension.openAsMaskedPicture:
Function openAsMaskedPicture(Extends f as folderItem) As picture
  
  dim p as Picture = f.openAsPicture
  dim result as new Picture(p.width, p.height, 32)
  
  result.graphics.drawPicture p, 0, 0
  result.mask.graphics.drawPicture f.parent.child("Mask").child(f.name).openAsPicture, 0, 0
  
  return result
  
End Function

MFolderItemExtension.posixPath:
Function posixPath(Extends f as folderItem) As string
  
  #if targetMachO
    if f <> nil then _
        return f.shellPath.convertPSString.defineEncoding(Encodings.UTF8)
    
  #elseif targetCarbon
    dim s(0) as string
    
    while f <> nil
      s.insert 1, f.name
      f = f.parent
      
    wend
    
    return s.join("/")
    
  #elseif targetWin32
    if f <> nil then
      if targetNT then
        if f.absolutePath.encoding = Encodings.UTF8 then
          return f.absolutePath.replaceall("¥", "\")
        else
          return f.absolutePath.convertEncoding(Encodings.UTF8).replaceall("¥", "\")
          
        end
        
      else
        return f.shellPath.convertEncoding(Encodings.UTF8).replaceall("¥", "\")
        
      end
      
    end
    
  #elseif targetLinux
    if f <> nil then _
        return f.shellPath.convertEncoding(Encodings.UTF8)
    
  #endif
  
End Function

MFolderItemExtension.getPath2FolderItem:
Function getPath2FolderItem(s as string) As folderItem
  
  if s.lenb = 0 then return nil
  
  #if targetMachO or targetLinux
    try
      return getFolderItem(s, FolderItem.pathTypeShell)
      
    catch
      
    end
    
  #elseif targetCarbon
    dim f, f2 as folderItem
    
    s = s.midb(2).replaceAllb("/", ":")
    
    try
      f = getFolderItem(s, FolderItem.pathTypeAbsolute)
      
      if f <> nil and f.exists then return f
      
      //* fix rb bug *//
      
      f2 = getFolderItem(s.convertEncoding(Encodings.systemDefault), FolderItem.pathTypeAbsolute)
      
      if f2 <> nil and f2.exists then return f2
      
      return f
      
    catch
      
    end
    
  #elseif targetWin32
    try
      if targetNT then
        return getFolderItem(s, FolderItem.pathTypeAbsolute)
        
      else
        return getFolderItem(s, FolderItem.pathTypeShell)
        
      end
      
    catch
      
    end
    
  #endif
  
End Function

MFolderItemExtension.fixRbBug:
Function fixRbBug(Extends f as folderItem) As folderitem
  
  #if targetWin32
    if f = nil or f.exists then return f
    
    dim f2 as folderItem
    
    f2 = getFolderItem( f.absolutePath.defineEncoding(Encodings.systemDefault).convertEncoding(Encodings.UTF8).replaceall("¥", "\"), FolderItem.pathTypeAbsolute )
    
    if f2 <> nil and f2.exists then return f2
    
    return f
    
  #elseif targetLinux
    if f = nil or f.lastErrorCode <> 0 then return nil
    
    return f
    
  #endif
  
End Function

MFolderItemExtension.open:
Sub open(Extends path as string)
  
  if path.lenB = 0 then return
  
  dim fi as folderItem = getPath2FolderItem(path)
  
  if fi <> nil and fi.exists then fi.launch
  
End Sub

MFolderItemExtension.revealInFinder:
Sub revealInFinder(Extends path as string)
  
  if path.lenB = 0 then return
  
  dim fi as folderItem = getPath2FolderItem(path)
  
  if fi <> nil then
    if fi.exists then
      fi.revealInFinder
      
    elseif fi.parent.exists and fi.parent.directory then
      fi.parent.launch
      
    end
    
  end
  
End Sub

MiTunesController.isiTunesAudio:
Function isiTunesAudio(Extends fileName as string) As boolean
  
  dim extension as string = fileName.getExtension
  
  return kITunesAudioExtensions.instrb(extension) <> 0
  
End Function

MLocalizationController.initializeLocalization:
Sub initializeLocalization()
  
  CLocalizationController1 = new CLocalizationController
  
End Sub

MLocalizationController.getLocalizedString:
Function getLocalizedString(key as string, table as string) As string
  
  return CLocalizationController1.getLocalizedStringFromTable(key, table)
  
End Function

MLocalizationController.finalizeLocalization:
Sub finalizeLocalization()
  
  CLocalizationController1 = nil
  
End Sub

MLocalizationController.getLocalizedStringWithStringData:
Function getLocalizedStringWithStringData(key as string, table as string, replaced as string) As string
  
  return CLocalizationController1.getLocalizedStringFromTable(key, table).replaceb("%@", replaced)
  
End Function

MLocalizationController.getLocalizedStringWithIntegerData:
Function getLocalizedStringWithIntegerData(key as string, table as string, replaced as string) As string
  
  return CLocalizationController1.getLocalizedStringFromTable(key, table).replaceb("%i", replaced)
  
End Function

MPreferencesController.initializePreferences:
Sub initializePreferences()
  
  CPreferencesController1 = new CPreferencesController
  
End Sub

MPreferencesController.finalizePreferences:
Sub finalizePreferences()
  
  CPreferencesController1 = nil
  
End Sub

MResourcesController.initializeResources:
Sub initializeResources()
  
  CResourceController1 = new CResourceController
  
End Sub

MResourcesController.getLargeMediaPicture:
Function getLargeMediaPicture(type as integer, extension as string) As picture
  
  return CResourceController1.getLargeMediaPicture(type, extension)
  
End Function

MResourcesController.getMaskedPicture:
Function getMaskedPicture(pictureName as string) As picture
  
  return CResourceController1.getMaskedPicture(pictureName)
  
End Function

MResourcesController.getControlPicture:
Function getControlPicture(type as integer) As picture
  
  return CResourceController1.getControlPicture(type)
  
End Function

MResourcesController.getChasingArrows:
Function getChasingArrows(type as integer) As picture
  
  return CResourceController1.getChasingArrows(type)
  
End Function

MResourcesController.getSmallMediaPicture:
Function getSmallMediaPicture(c as CResponseModel) As picture
  
  return CResourceController1.getSmallMediaPicture(c)
  
End Function

MResourcesController.finalizeResources:
Sub finalizeResources()
  
  CResourceController1 = nil
  
End Sub

CEditField.Localize:
Protected Sub Localize()
  
  me.helpTag = getLocalizedString(me.helpTag, "EditField")
  
End Sub

CEditField.LostFocus:
Sub LostFocus()
  
  if me.text.lenb = 0 then
    me.textColor = kGrayTextColor
    me.text = me.helpTag
    
  end
  
End Sub

CEditField.GotFocus:
Sub GotFocus()
  
  if me.textColor = kGrayTextColor then
    me.textColor = kTextColor
    me.text = ""
    
  end
  
End Sub

CEditField.KeyDown:
Function KeyDown(Key As String) As Boolean
  
  #if targetMacOS
    dim i as integer
    if ascb(key) = 8 then
      i = me.selStart
      me.text = me.text.left(me.selStart - 1) + me.text.right(me.text.len - me.selStart)
      me.selStart = i - 1
      return true
    end
  #endif
  
  return KeyDown(Key)
  
End Function

CEditField.Open:
Sub Open()
  
  me.backColor = kBackColor
  me.textColor = kTextColor
  Localize
  Open
  
End Sub

CHierarchicalListBox.addRow:
Sub addRow(rowName as string, defaults as string, value as variant)
  
  me.addrow rowName
  
  dim index as integer = me.lastIndex
  
  select case value.Type
    
  case 2 //* integer *//
    me.cellType(index, 1) = ListBox.TypeEditable
    me.cell(index, 1) = value
    
  case 8 //* string *//
    me.cellType(index, 1) = ListBox.TypeEditable
    me.cell(index, 1) = value
    
  case 9 //* object *//
    if value isa Dictionary and Dictionary(value).hasKey("currentKey") then _
        me.cell(index, 1) = Dictionary(value).value(Dictionary(value).value("currentKey"))
    
  case 11 //* boolean *//
    me.cellType(index, 0) = ListBox.TypeCheckbox
    me.cellCheck(index, 0) = value
    
  end
  
  me.cellTag(index, 0) = defaults
  me.cellTag(index, 1) = value
  
End Sub

CHierarchicalListBox.valueChanged:
Sub valueChanged(row as integer, column as integer)
  
  CellAction(row, column)
  
End Sub

CHierarchicalListBox.addIndentRow:
Sub addIndentRow(rowName as string, defaults as string, value as variant)
  
  me.addRow rowName, defaults, value
  me.cellAlignmentOffset(me.lastIndex, 0) = 20
  
End Sub

CHierarchicalListBox.addRow:
Sub addRow(rowName as string, defaults as string, value1 as boolean, value2 as variant)
  
  me.addrow rowName
  
  dim index as integer = me.lastIndex
  
  me.cellType(index, 0) = 2
  me.cellCheck(index, 0) = value1
  
  select case value2.Type
    
  case 2 //* integer *//
    me.cellType(index, 1) = 3
    me.cell(index, 1) = value2
    
  case 8 //* string *//
    me.cellType(index, 1) = 3
    me.cell(index, 1) = value2
    
  case 9 //* object *//
    if value2 isa Dictionary and Dictionary(value2).hasKey("currentKey") then _
        me.cell(index, 1) = Dictionary(value2).value(Dictionary(value2).value("currentKey"))
    
  end
  
  me.cellTag(index, 0) = defaults
  me.cellTag(index, 1) = value2
  
End Sub

CHierarchicalListBox.collapseAll:
Sub collapseAll()
  
  dim i as integer
  
  for i = me.listCount - 1 downto 0
    if me.expanded(i) then me.expanded(i) = false
  next
  
End Sub

CHierarchicalListBox.MouseMove:
Sub MouseMove(row as integer, column as integer, x as integer, y as integer)
  
  try
    if row = -1 or column = -1 then
      me.mouseCursor = arrowCursor
      
    elseif me.cellTag(row, column) isa Dictionary then
      me.mouseCursor = handCursor
      
    elseif me.cellType(row, column) = ListBox.TypeEditable then
      me.mouseCursor = IBeamCursor
      
    else
      me.mouseCursor = arrowCursor
      
    end
    
  catch
    me.mouseCursor = arrowCursor
    
  end
  
End Sub

CHierarchicalListBox.CellTextPaint:
Function CellTextPaint(g As Graphics, row As Integer, column As Integer, x as Integer, y as Integer) As Boolean
  
  #if targetMachO
    if g.width <= me.cellAlignmentOffset(row, column) then
      return false
    else
      'g.drawStringInCell me.cell(row, column), x, y)
      g.drawString me.cell(row, column), x, y
      return true
    end
    
  #endif
  
End Function

CHierarchicalListBox.DoubleClick:
Sub DoubleClick()
  
  if me.listIndex <> -1 then _
      me.expanded(me.listIndex) = not me.expanded(me.listIndex)
  
End Sub

CHierarchicalListBox.CellAction:
Sub CellAction(row As Integer, column As Integer)
  
  CellAction(row, column)
  
End Sub

CHierarchicalListBox.CollapseRow:
Sub CollapseRow(row As Integer)
  
  me.scrollposition = 0
  
End Sub

CHierarchicalListBox.CellBackgroundPaint:
Function CellBackgroundPaint(g As Graphics, row As Integer, column As Integer) As Boolean
  
  #if targetMachO
    if me.selected(row) = false and (row mod 2) = 0 then
      g.foreColor = kRowColor
      g.fillRect 0, 0, g.width, g.height
      return true
    end
    
  #elseif targetWin32 or targetLinux
    if (row mod 2) = 0 then
      g.foreColor = kRowColor
      g.fillRect 0, 0, g.width, g.height
      return true
    end
    
  #endif
  
End Function

CListBox.Localize:
Protected Sub Localize()
  
  if me.hasHeading = false then return
  
  dim i as integer
  
  for i = me.columnCount - 1 downto 0
    
    me.heading(i) = getLocalizedString(me.heading(i), "ListBox")
    
  next
  
End Sub

CListBox.getInitialColumnWidths:
Function getInitialColumnWidths() As string
  
  return me.initialColumnWidths
  
End Function

CListBox.setColumnWidths:
Sub setColumnWidths(value as string)
  
  if value.countFields(",") = me.columnCount then me.columnWidths = value
  
  dim i as integer
  
  for i = me.columnCount - 1 downto 0
    
    if isNumeric(me.column(i).widthExpression) then
      me.column(i).userResizable = false
      me.column(i).minWidthExpression = me.column(i).widthExpression
      me.column(i).maxWidthExpression = me.column(i).widthExpression
      
    else
      me.column(i).userResizable = (me.column(i).widthExpression <> "0%")
      me.column(i).minWidthExpression = "0%"
      me.column(i).maxWidthExpression = "100%"
      
    end
    
  next
  
End Sub

CListBox.getCellText:
Protected Function getCellText(row as integer, column as integer) As string
  
  return me.Cell(row, column)
  
End Function

CListBox.selectAll:
Sub selectAll()
  
  dim i as integer
  
  try
    for i = me.listCount - 1 downto 0
      me.selected(i) = true
    next
    
  catch
    
  end
  
End Sub

CListBox.setHelpTag:
Protected Sub setHelpTag(x as integer, y as integer, byref theRow as integer, byref theColumn as integer)
  
  dim i, j, theRowHeight, theColumnWidth as integer
  
  try
    if x < 0 or x > me.width or y < 0 or y > me.height then
      if me.HelpTag.lenb <> 0 then me.HelpTag = ""
      return
    end
    
    theRow = -1
    theColumn = -1
    
    if me.hasHeading then
      theRowHeight = kHeadingHeight
    else
      theRowHeight = 0
    end
    
    j = me.listCount - 1
    
    for i = 0 to j
      
      if theRowHeight < y and theRowHeight + me.defaultRowHeight > y then
        theRow = me.scrollPosition + i
        exit
      else
        theRowHeight = theRowHeight + me.defaultRowHeight
      end
      
    next
    
    j = me.columnCount - 1
    
    for i = 0 to j
      
      if theColumnWidth < x and theColumnWidth + me.column(i).widthActual > x then
        theColumn = i
        exit
      else
        theColumnWidth = theColumnWidth + me.column(i).widthActual
      end
      
    next
    
    if theRow > -1 and theRow < me.listCount and _
        theColumn > -1 and theColumn < me.columnCount then
      
      if me.HelpTag <> me.getCellText(theRow, theColumn) then _
          me.HelpTag = me.getCellText(theRow, theColumn)
      
      return
      
    else
      if me.HelpTag.lenb <> 0 then me.HelpTag = ""
      return
      
    end
    
  catch
    
  end
  
End Sub

CListBox.MouseMove:
Sub MouseMove(X As Integer, Y As Integer)
  
  dim theRow, theColumn as integer
  
  setHelpTag x, y, theRow, theColumn
  MouseMove theRow, theColumn, x, y
  
End Sub

CListBox.MouseExit:
Sub MouseExit()
  
  MouseExit
  
  if me.HelpTag.lenb <> 0 then me.HelpTag = ""
  
End Sub

CListBox.EnableMenuItems:
Sub EnableMenuItems()
  
  EditSelectAll.enabled = (me.selectionType <> 0)
  EditCopy.enabled = (me.helpTag.lenb <> 0)
  
End Sub

CListBox.MouseDown:
Function MouseDown(x As Integer, y As Integer) As Boolean
  
  dim theRow, theColumn as integer
  
  setHelpTag x, y, theRow, theColumn
  
  if isCMMClick = false then return false
  
  if me.hasHeading and y < 18 then
    HeaderCMMClicked
    return true
    
  else
    try
      if me.selectionType = 1 and me.selected(theRow) = false then
        if Keyboard.asyncControlKey then
          me.selected(theRow) = true
        else
          me.listIndex = theRow
        end
      end
    catch
    end
    
    CMMClicked
    return true
    
  end
  
End Function

CListBox.Open:
Sub Open()
  
  me.initialColumnWidths = me.columnWidths
  Localize
  Open
  
End Sub

CNetworkListBox.getCellText:
Protected Function getCellText(row as integer, column as integer) As string
  
  dim c as CNetworkModel = CNetworkModel(me.dataSource(row))
  
  if column = 0 then
    return c.address
    
  elseif column = 1 then
    return c.agent
    
  elseif column = 2 then
    return c.language
    
  elseif column = 3 then
    return c.type
    
  elseif column = 4 then
    return c.getPTime
    
  else
    return ""
    
  end
  
End Function

CNetworkListBox.CellTextPaint:
Function CellTextPaint(g As Graphics, row As Integer, column As Integer, x as Integer, y as Integer) As Boolean
  
  dim c as CNetworkModel
  
  try
    c = CNetworkModel(me.dataSource(row))
    
    if column = 0 then
      'g.drawStringInCell c.address, x, y
      g.drawString c.address, x, y
      return true
      
    elseif column = 1 then
      'g.drawStringInCell c.agent, x, y
      g.drawString c.agent, x, y
      return true
      
    elseif column = 2 then
      g.drawString c.language, (g.width - g.stringWidth(c.language)) / 2, y
      return true
      
    elseif column = 3 then
      g.drawString c.type, (g.width - g.stringWidth(c.type)) / 2, y
      return true
      
    elseif column = 4 then
      g.drawString c.getPTime, (g.width - g.stringWidth(c.getPTime)) / 2, y
      return true
      
    end
    
  catch
    
  end
  
End Function

CNetworkListBox.CellBackgroundPaint:
Function CellBackgroundPaint(g As Graphics, row As Integer, column As Integer) As Boolean
  
  if me.selected(row) = false and (row mod 2) = 0 then
    g.foreColor = kRowColor
    g.fillRect 0, 0, g.width, g.height
    
  end
  
  return true
  
End Function

CResponseListBox.getCellText:
Protected Function getCellText(row as integer, column as integer) As string
  
  dim c as CResponseModel = CResponseModel(me.dataSource(row))
  
  if column = 0 then
    return ""
    
  elseif column = 1 then
    return c.displayName' + EndOfLine + c.getRepresentation
    
  elseif column = 2 then
    return c.artist
    
  elseif column = 3 then
    return c.album
    
  elseif column = 4 then
    return c.getPSize
    
  elseif column = 5 then
    return c.getPBitrate
    
  elseif column = 6 then
    return c.getPLength
    
  elseif column = 7 then
    return c.address.join(EndOfLine)
    
  elseif column = 8 then
    return c.getPSpeed
    
  else
    return ""
    
  end
  
End Function

CResponseListBox.CellTextPaint:
Function CellTextPaint(g As Graphics, row As Integer, column As Integer, x as Integer, y as Integer) As Boolean
  
  dim c as CResponseModel
  
  try
    c = CResponseModel(me.dataSource(row))
    
    //* gray out existing or red out spam *//
    
    if (c.exists and me.selected(row) = false) then
      g.foreColor = kLightGrayTextColor
      
    elseif (c.spam and me.selected(row) = false) then
      g.foreColor = kLightRedTextColor
      
    end
    
    if column = 0 then
      return true
      
    elseif column = 1 then
      'g.drawStringInCell c.displayName, x, y
      g.drawString c.displayName, x, y
      return true
      
    elseif column = 2 then
      'g.drawStringInCell c.artist, x, y
      g.drawString c.artist, x, y
      return true
      
    elseif column = 3 then
      'g.drawStringInCell c.album, x, y
      g.drawString c.album, x, y
      return true
      
    elseif column = 4 then
      if kAqKbFileSize = false then
        g.drawString c.getPSize, (g.width - g.stringWidth(c.getPSize)) / 2, y
      else
        g.drawString c.getPSize, (g.width - g.stringWidth(c.getPSize)), y
      end
      
      return true
      
    elseif column = 5 then
      g.drawString c.getPBitrate, (g.width - g.stringWidth(c.getPBitrate)) / 2, y
      return true
      
    elseif column = 6 then
      g.drawString c.getPLength, (g.width - g.stringWidth(c.getPLength)) / 2, y
      return true
      
    elseif column = 7 then
      g.drawString c.getPSources, (g.width - g.stringWidth(c.getPSources)) / 2, y
      return true
      
    elseif column = 8 then
      g.drawString c.getPSpeed, (g.width - g.stringWidth(c.getPSpeed)) / 2, y
      return true
      
    else
      return true
      
    end
    
  catch
    
  end
  
End Function

CResponseListBox.CellBackgroundPaint:
Function CellBackgroundPaint(g As Graphics, row As Integer, column As Integer) As Boolean
  
  if me.selected(row) = false and (row mod 2) = 0 then
    g.foreColor = kRowColor
    g.fillRect 0, 0, g.width, g.height
    
  end
  
  try
    if column = 0 then _
        g.drawPicture CResponseModel(me.dataSource(row)).getPIcon, 1, 1
    
  catch
    
  end
  
  return true
  
End Function

CSidebarListBox.getCellText:
Protected Function getCellText(row as integer, column as integer) As string
  
  dim c as CSidebarModel = CSidebarModel(me.dataSource(row))
  
  return c.caption
  
End Function

CSidebarListBox.CellTextPaint:
Function CellTextPaint(g As Graphics, row As Integer, column As Integer, x as Integer, y as Integer) As Boolean
  
  dim c as CSidebarModel
  dim i as integer
  
  try
    c = CSidebarModel(me.dataSource(row))
    
    g.drawString c.caption, 18, y
    
    if c.getPState <> nil then
      g.bold = true
      i = g.stringWidth(c.getPState)
      x = g.width - i - 12
      
      if c.highlighted = false then
        g.foreColor = &cFFFFFF
        g.fillRoundRect x, 4, i + 8, y, 8, 8
        g.foreColor = &cE2E2E2
        g.drawString c.getPState, x + 4, y + 1
        g.foreColor = &c383838
        g.drawString c.getPState, x + 4, y
        
      else
        g.foreColor = &c909090
        g.fillRoundRect x, 4, i + 8, y, 8, 8
        g.foreColor = &c3F3F3F
        g.drawString c.getPState, x + 4, y + 1
        g.foreColor = &cFFFFFF
        g.drawString c.getPState, x + 4, y
        
      end
      
    end
    
    if c.interval > -1 then
      if me.selected(row) = false then
        g.drawPicture getChasingArrows(c.interval mod 6), 1, 4
        
      else
        g.drawPicture getChasingArrows(6 + (c.interval mod 6)), 1, 4
        
      end
      
      return true
      
    elseif c.index < 0 then
      if me.selected(row) = false then
        g.drawPicture getControlPicture(1), 1, 4
        
      else
        g.drawPicture getControlPicture(5), 1, 4
        
      end
      
      return true
      
    else
      if row = 0 then
        g.drawPicture getControlPicture(2), 0, 3
        
      elseif row = 1 then
        g.drawPicture getControlPicture(3), 0, 3
        
      elseif row = 2 then
        g.drawPicture getControlPicture(4), 0, 3
        
      end
      
      return true
      
    end
    
  catch
    
  end
  
End Function

CStaticText.Localize:
Protected Sub Localize()
  
  me.text = getLocalizedString(me.text, "StaticText")
  'me.helpTag = getLocalizedString(me.helpTag, "StaticText")
  
End Sub

CStaticText.Open:
Sub Open()
  
  Localize
  Open
  
End Sub

CStatsListBox.dataSourceChanged:
Sub dataSourceChanged(c() as CStatsModel)
  
  me.dataSource = c
  
  me.setRowCount ubound(c) + 1
  me.invalidateAllCells
  
End Sub

CStatsListBox.invalidateAllCells:
Protected Sub invalidateAllCells()
  
  dim i, j as integer
  dim startPosition as integer = me.scrollPosition
  dim displayRows as integer = (me.height \ me.defaultRowHeight)
  displayRows = min(me.listCount - 1, startPosition + displayRows)
  
  try
    
    for i = displayRows downto startPosition
      
      for j = me.columnCount - 1 downto 0
        
        me.cell(i, j) = ""
        
      next
      
    next
    
  catch
    
  end
  
End Sub

CStatsListBox.saveSelectedItems:
Sub saveSelectedItems()
  
  dim i as integer
  
  try
    for i = ubound(me.dataSource) downto 0
      
      if me.selected(i) then selectedItems.value(me.dataSource(i).getRepresentation) = true
      
    next
    
  catch
    
  end
  
End Sub

CStatsListBox.Constructor:
Sub Constructor()
  
  me.selectedItems = new Dictionary
  
End Sub

CStatsListBox.getSelectedRows:
Function getSelectedRows() As integer()
  
  dim i, j, results(-1) as integer
  
  try
    j = me.listCount - 1
    
    for i = 0 to j
      
      if me.selected(i) then results.append i
      
    next
    
  catch
    
  end
  
  return results
  
End Function

CStatsListBox.addOrRemoveScrollbar:
Sub addOrRemoveScrollbar()
  
  dim count as integer = me.listCount - 1
  dim displayRows as integer = (me.height \ me.defaultRowHeight)
  dim needsScrollbar as boolean = (displayRows <= count)
  
  if me.scrollBarVertical <> needsScrollbar then
    me.scrollBarVertical = needsScrollbar
    
    if me.scrollPosition > count - displayRows then _
        me.scrollPosition = count - displayRows
    
  end
  
End Sub

CStatsListBox.setRowCount:
Protected Sub setRowCount(rowCount as integer)
  
  while me.listCount > rowCount
    
    me.removeRow me.listCount - 1
    
  Wend
  
  dim i as integer
  
  while me.listCount < rowCount
    
    me.addrow ""
    
    for i = me.columnCount - 1 downto 0
      
      me.cell(me.lastIndex, i) = ""
      
    next
    
  Wend
  
End Sub

CStatsListBox.restoreSelectedItems:
Sub restoreSelectedItems()
  
  dim i as integer
  
  try
    for i = me.listCount - 1 downto 0
      
      if me.selected(i) <> me.selectedItems.hasKey(me.dataSource(i).getRepresentation) then _
          me.selected(i) = not me.selected(i)
      
    next
    
  catch
    
  end
  
  me.selectedItems.clear
  
End Sub

CStatsListBox.getSelectedItems:
Function getSelectedItems() As Dictionary
  
  return me.selectedItems
  
End Function

CToolbar.appendMenu:
Sub appendMenu(caption as string, helpTag as string)
  
  me.graphics.textFont = kTextFont
  me.graphics.textSize = kSmallTextSize
  me.graphics.bold = true
  
  me.CToolbarModels.append new CToolbarModel(caption, helpTag, me.graphics.stringWidth(caption) + 16)
  
End Sub

CToolbar.clearMenu:
Sub clearMenu()
  
  redim me.CToolbarModels(-1)
  
End Sub

CToolbar.setKeepPressed:
Sub setKeepPressed(value as boolean)
  
  dim c as CToolbarModel
  
  try
    c = me.CToolbarModels(ubound(me.CToolbarModels))
    if c.caption = getLocalizedString("Filter", "Toolbar") then
      c.keepPressed = value
      me.refresh
      
    end
    
  catch
    
  end
End Sub

CToolbar.MouseExit:
Sub MouseExit()
  
  dim c as CToolbarModel
  dim changed as boolean
  
  try
    for each c in me.CToolbarModels
      
      if c.entered then
        c.entered = false
        changed = true
        
      end
      
    next
    
    if me.HelpTag.lenb <> 0 then me.HelpTag = ""
    
    if changed then me.refresh
    
  catch
    
  end
  
End Sub

CToolbar.MouseMove:
Sub MouseMove(X As Integer, Y As Integer)
  
  dim x2 as integer = me.width
  dim c as CToolbarModel
  dim changed as boolean
  
  try
    for each c in me.CToolbarModels
      
      x2 = x2 - c.width
      
      if c.entered <> (x > x2 and x < x2 + c.width and y > 0 and y < 16) then
        c.entered = not c.entered
        changed = true
        
        if c.entered and me.helpTag <> c.helpTag then me.helpTag = c.helpTag
        
      end
      
    next
    
    if changed then me.refresh
    
  catch
    
  end
  
End Sub

CToolbar.MouseDrag:
Sub MouseDrag(X As Integer, Y As Integer)
  
  dim x2 as integer = me.width
  dim c as CToolbarModel
  
  try
    for each c in me.CToolbarModels
      
      x2 = x2 - c.width
      
      if c.pressed and c.entered <> (x > x2 and x < x2 + c.width and y > 0 and y < 16) then
        c.entered = not c.entered
        me.refresh
        return
        
      end
      
    next
    
  catch
    
  end
  
End Sub

CToolbar.MouseUp:
Sub MouseUp(X As Integer, Y As Integer)
  
  dim c as CToolbarModel
  
  try
    for each c in me.CToolbarModels
      
      if c.pressed then
        c.pressed = false
        me.refresh
        
        if c.entered and c.caption = getLocalizedString("Filter", "Toolbar") then _
            c.keepPressed = not c.KeepPressed
        
        if c.entered and c.caption <> getLocalizedString("Browse", "Toolbar") then _
            Action c.caption
        
        return
        
      end
      
    next
    
  catch
    
  end
  
End Sub

CToolbar.MouseDown:
Function MouseDown(X As Integer, Y As Integer) As Boolean
  
  dim c as CToolbarModel
  
  try
    for each c in me.CToolbarModels
      
      if c.entered then
        c.pressed = true
        me.refresh
        
        if c.caption = getLocalizedString("Browse", "Toolbar") then _
            Action c.caption
        
        return true
        
      end
      
    next
    
  catch
    
  end
  
End Function

CToolbar.Paint:
Sub Paint(g As Graphics)
  
  dim x as integer = g.width
  dim c as CToolbarModel
  
  g.textFont = kTextFont
  g.textSize = kSmallTextSize
  g.Bold = true
  
  try
    for each c in me.CToolbarModels
      
      x = x - c.width
      
      if x < 0 then return
      if c.pressed and c.entered then
        g.foreColor = &c707070
        g.fillRoundRect x, 0, c.width, 16, 16, 16
        g.foreColor = &c3F3F3F
        g.drawString c.caption, x + 8, 13
        g.foreColor = &cFFFFFF
        g.drawString c.caption, x + 8, 12
        
      elseif c.keepPressed then
        g.foreColor = &c636363
        g.fillRoundRect x, 0, c.width, 16, 16, 16
        g.foreColor = &c3F3F3F
        g.drawString c.caption, x + 8, 13
        g.foreColor = &cFFFFFF
        g.drawString c.caption, x + 8, 12
        
      elseif c.entered then
        g.foreColor = &c808080
        g.fillRoundRect x, 0, c.width, 16, 16, 16
        g.foreColor = &c3F3F3F
        g.drawString c.caption, x + 8, 13
        g.foreColor = &cFFFFFF
        g.drawString c.caption, x + 8, 12
        
      else
        g.foreColor = &cE2E2E2
        g.drawString c.caption, x + 8, 13
        g.foreColor = &c383838
        g.drawString c.caption, x + 8, 12
        
      end
      
    next
    
  catch
    
  end
  
End Sub

CTransferListBox.getCellText:
Protected Function getCellText(row as integer, column as integer) As string
  
  dim c as CTransferModel = CTransferModel(me.dataSource(row))
  
  if column = 0 then
    return ""
    
  elseif column = 1 then
    return c.getPName
    
  elseif column = 2 then
    return c.getSTransfer
    
  elseif column = 3 then
    return ""
    
  elseif column = 4 then
    return c.getPTime
    
  else
    return ""
    
  end
  
End Function

CTransferListBox.CellBackgroundPaint:
Function CellBackgroundPaint(g As Graphics, row As Integer, column As Integer) As Boolean
  
  if me.selected(row) = false and (row mod 2) = 0 then
    g.foreColor = kRowColor
    g.fillRect 0, 0, g.width, g.height
    
  end
  
  try
    if column = 0 then _
        g.drawPicture CTransferModel(me.dataSource(row)).getPIcon, 2, 2
    
  catch
    
  end
  
  return true
  
End Function

CTransferListBox.CellTextPaint:
Function CellTextPaint(g As Graphics, row As Integer, column As Integer, x as Integer, y as Integer) As Boolean
  
  dim c as CTransferModel
  dim p as picture
  
  try
    c = CTransferModel(me.dataSource(row))
    
    if column = 0 then
      return true
      
    elseif column = 1 then
      g.textSize = kMiddleTextSize
      'g.drawStringInCell c.getPName, x, y - 7
      g.drawString c.getPName, x, y - 7
      
      if me.selected(row) = false then g.foreColor = kGrayTextColor
      
      g.textSize = kSmallTextSize
      'g.drawStringInCell c.getSName, x, y + 7
      g.drawString c.getSName, x, y + 7
      return true
      
    elseif column = 2 then
      g.textSize = kMiddleTextSize
      g.drawString c.getPTransfer, (g.width - g.stringWidth(c.getPTransfer)) / 2, y - 7
      
      if me.selected(row) = false then g.foreColor = kGrayTextColor
      
      g.textSize = kSmallTextSize
      g.drawString c.getSTransfer, (g.width - g.stringWidth(c.getSTransfer)) / 2, y + 7
      return true
      
    elseif column = 3 then
      p = new Picture(g.width, g.height, 32)
      
      x = g.width - 12
      p.mask.graphics.foreColor = &cFFFFFF
      p.mask.graphics.fillRect 0, 0, g.width, g.height
      p.mask.graphics.foreColor = &c000000
      p.mask.graphics.fillRoundRect 6, 12, x, 12, 12, 12
      
      if c.isActive then
        p.graphics.foreColor = &cAAAAAA
        p.graphics.fillRect 6, 12, x * c.progress, 12
        p.graphics.foreColor = &c808080
        p.graphics.drawRoundRect 6, 12, x, 12, 12, 12
        
      else
        p.graphics.foreColor = &cEEEEEE
        p.graphics.fillRect 6, 12, x * c.progress, 12
        p.graphics.foreColor = &cE6E6E6
        p.graphics.drawRoundRect 6, 12, x, 12, 12, 12
        
      end
      
      if c.isComplete then _
          p.graphics.drawPicture getControlPicture(0), (g.width - 14) / 2, 11
      
      g.drawPicture p, 0, 0
      P = nil
      return true
      
    elseif column = 4 then
      g.textSize = kMiddleTextSize
      g.drawString c.getPTime, (g.width - g.stringWidth(c.getPTime)) / 2, y - 7
      
      if me.selected(row) = false then g.foreColor = kGrayTextColor
      
      g.textSize = kSmallTextSize
      g.drawString c.getSTime, (g.width - g.stringWidth(c.getSTime)) / 2, y + 7
      return true
      
    else
      return true
      
    end
    
  catch
    
  end
  
End Function

CWindow.Localize:
Protected Sub Localize()
  
  me.title = getLocalizedString(me.title, "Window")
  
End Sub

CWindow.setTitle:
Sub setTitle(title as string)
  
  me.title = title
  me.menu.text = title
  
End Sub

CWindow.minimize:
Sub minimize()
  
  #if targetMacOS
    Declare Function CollapseWindow Lib kCarbon (w as WindowPtr, b as Boolean) as Integer
    
    call CollapseWindow(me, true)
    
  #elseif targetWin32
    Const SW_MINIMIZE = 6
    Declare Sub ShowWindow Lib "user32" (wnd As Integer, nCmdShow As Integer)
    
    ShowWindow( me.WinHWND, SW_MINIMIZE )
    
  #elseif targetLinux
    'todo
    
  #endif
  
End Sub

CWindow.isTextured:
Sub isTextured(Assigns b As Boolean)
  
  #if targetMachO then
    Declare Function ChangeWindowAttributes Lib kCarbon _
        (window as WindowPtr, setTheseAttributes as Integer, clearTheseAttributes as Integer) as Integer
    
    const ATTRIB = 256
    
    if b then
      call ChangeWindowAttributes(me, ATTRIB, 0)
      
    else
      call ChangeWindowAttributes(me, 0, ATTRIB)
      
    end
    
  #endif
  
End Sub

CWindow.maximize:
Sub maximize()
  
  #if targetMacOS
    'Declare Sub ZoomWindow Lib kCarbon (window as WindowPtr, partCode as Integer, front as Boolean)
    'Declare Function IsWindowInStandardState Lib kCarbon (window as WindowPtr, idealSize as Integer, idealStandardState as Integer) as Boolean
    '
    'if IsWindowInStandardState(me, 0, 0) then
    'ZoomWindow(me, 7, false)
    '
    'else
    'ZoomWindow(me, 8, false)
    '
    'end
    '
  #elseif targetWin32
    Const SW_MAXIMIZE = 3
    Declare Sub ShowWindow Lib "user32" (wnd As Integer, nCmdShow As Integer)
    
    ShowWindow( me.WinHWND, SW_MAXIMIZE )
    
  #elseif targetLinux
    'todo
    
  #endif
  
End Sub

CWindow.getState:
Protected Function getState() As Integer
  
  #if targetWin32
    Declare Function IsIconic Lib "user32" (ByVal hwnd As Integer) As Integer
    Declare Function IsZoomed Lib "user32" (ByVal hwnd As Integer) As Integer
    
    Dim minflag, maxflag As Integer
    
    minflag = IsIconic(me.WinHWND)  //is window minimized?
    maxflag = IsZoomed(me.WinHWND)  //is window maximized?
    
    If minflag <> 0 Then
      return kWindowStateMinimized
      
    ElseIf maxflag <> 0 Then
      return kWindowStateMaximized
      
    Else
      return kWindowStateRestored
      
    End If
    
  #endif
  
End Function

CWindow.loadSizeAndState:
Sub loadSizeAndState(name as string)
  
  #if targetMacOS
    me.isTextured = kAqTexturedWindow
    
    dim args(-1), result as string
    
    result = defaultsRead("CWindow " + name, result)
    args = result.split
    
    if ubound(args) = 3 then
      me.left = args(0).val
      me.top = args(1).val
      me.width = args(2).val
      me.height = args(3).val
      
    end
    
  #elseif targetWin32
    dim args(-1), result as string
    dim mode as integer
    
    mode = defaultsRead("CWindowState " + name, mode)
    
    select case mode
      
    case kWindowStateRestored
      result = defaultsRead("CWindow " + name, result)
      args = result.split
      
      if ubound(args) = 3 then
        me.left = args(0).val
        me.top = args(1).val
        me.width = args(2).val
        me.height = args(3).val
        
      end
      
    case kWindowStateMinimized
      me.minimize
      
    case kWindowStateMaximized
      me.maximize
      
    end
    
  #elseif targetLinux
    dim args(-1), result as string
    
    result = defaultsRead("CWindow " + name, result)
    args = result.split
    
    if ubound(args) = 3 then
      me.left = args(0).val
      me.top = args(1).val
      me.width = args(2).val
      me.height = args(3).val
      
    end
    
  #endif
  
End Sub

CWindow.saveSizeAndState:
Sub saveSizeAndState(name as string)
  
  #if targetMacOS or targetLinux
    defaultsWrite "CWindow " + name, _
        str(me.left) + " " + str(me.top) + " " + str(me.width) + " " + str(me.height)
    
  #elseif targetWin32
    defaultsWrite "CWindow " + name, _
        str(me.left) + " " + str(me.top) + " " + str(me.width) + " " + str(me.height)
    defaultsWrite "CWindowState " + name, me.getState
    
  #endif
  
End Sub

CWindow.Deactivate:
Sub Deactivate()
  
  if me.menu <> nil then me.menu.checked = false
  
End Sub

CWindow.Activate:
Sub Activate()
  
  if me.menu <> nil then me.menu.checked = true
  
End Sub

CWindow.Close:
Sub Close()
  
  if me.menu <> nil then me.menu.close
  
  Close
  
End Sub

CWindow.Open:
Sub Open()
  
  Localize
  me.menu = new WindowMenus
  me.menu.text = me.title
  Open
  
End Sub

