Results 1 to 15 of 15

Thread: Bestandstype koppelen/associatie android (XE10.3 FMX)

  1. #1

    Bestandstype koppelen/associatie android (XE10.3 FMX)

    De App waar ik mee bezig ben werkt met .gpx bestanden.
    Nu zou ik het graag zo hebben dat als er op een .gpx bestand geklikt wordt deze App gestart wordt of
    dat ook deze App gekozen kan worden (als er meerdere App's zijn die met een .gpx bestand werken).

    Ik kom wel van alles tegen maar krijg het helaas niet werkend, dus wie kan hier iets over vertellen ?

    Als ik hier naar kijk:
    http://codeverge.com/embarcadero.del...ociate/1057456

    Daar staat dat deze code toegevoegd moet worden in de main activity van het bestand "AndroidManifest.template.xml".

    Code:
    	<intent-filter
    	    android:label="%activityLabel%"
    	    android:priority='1'>
    	    <action android:name="android.intent.action.VIEW" />
    	    <action android:name="android.intent.action.EDIT" /> 
    	    <action android:name="android.intent.action.PICK" />
    	    <category android:name="android.intent.category.DEFAULT" />
    	    <category android:name="android.intent.category.BROWSABLE" /> 
    	    
    	    <data android:mimeType="text/csv" />  
    	    <data android:pathPattern="*.csv" />
    	</intent-filter>
    	
    	<intent-filter>
    	    <action android:name="android.intent.action.VIEW" />
    	    <category android:name="android.intent.category.DEFAULT" />
    	    <category android:name="android.intent.category.BROWSABLE" />
    	     
    	    <data android:mimeType="text/csv" android:scheme="http" android:host="*" android:pathPattern=".*\\.csv" />
    	    <data android:mimeType="text/csv" android:scheme="https" android:host="*" android:pathPattern=".*\\.csv" />
    	 </intent-filter>
    Nu is deze code voor een .csv bestand en dit zou ik dan moeten wijzigen in .gpx, maar het werkt ongewijzigd al niet voor een .csv bestand !


    Dit is de inhoud van mijn "AndroidManifest.template.xml" bestand:

    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <!-- BEGIN_INCLUDE(manifest) -->
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
            package="%package%"
            android:versionCode="%versionCode%"
            android:versionName="%versionName%"
            android:installLocation="%installLocation%">
    
        <uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="%targetSdkVersion%" />
        <%uses-permission%>
        <uses-feature android:glEsVersion="0x00020000" android:required="True"/>
        <application android:persistent="%persistent%" 
            android:restoreAnyVersion="%restoreAnyVersion%" 
            android:label="%label%" 
            android:debuggable="%debuggable%" 
            android:largeHeap="%largeHeap%"
            android:icon="%icon%"
            android:theme="%theme%"
            android:hardwareAccelerated="%hardwareAccelerated%"
            android:resizeableActivity="false">
    
            <%provider%>
            <%application-meta-data%>
            <%uses-libraries%>
            <%services%>
            <!-- Our activity is a subclass of the built-in NativeActivity framework class.
                 This will take care of integrating with our NDK code. -->
            <activity android:name="com.embarcadero.firemonkey.FMXNativeActivity"
                    android:label="%activityLabel%"
                    android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
                    android:launchMode="singleTask">
                <!-- Tell NativeActivity the name of our .so -->
                <meta-data android:name="android.app.lib_name"
                    android:value="%libNameValue%" />
                <intent-filter>  
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter> 
            </activity>
            <%activity%>
            <%receivers%>
        </application>
    </manifest>
    <!-- END_INCLUDE(manifest) -->
    Waar moet ik dit precies plaatsen denken jullie ?

  2. #2
    Na deze gevolgd te hebben:
    http://docwiki.embarcadero.com/CodeE...Intents_Sample
    https://stackoverflow.com/questions/...open-gpx-files

    Start de App nu als ik op een .gpx bestand klik, maar nu heb ik nog het probleem dat ik niet weet hoe
    ik de naam en het path van dit bestand kan uitlezen.

    Wie heeft een idee hoe ik dat voor elkaar kan krijgen ?

  3. #3
    Op Android 8 werkt het nu, maar op Android 10 helaas nog niet.
    Daarbij staat deze App niet in de lijst met beschikbare App's als ik op een .gpx bestand klik.

    Wie kan hier iets over vertellen ?


    Dit is wat ik doe als test:
    Begin een nieuw project: Android 32 bit

    Open het "AndroidManifest.template.xml" bestand met bijvoorbeeld NotePad++, en plaats onder "<%application-meta-data%>"
    dit (ik weet niet of de laatste 3 regels er ook bij horen, deze gebruik ik wel maar of dat nodig is ?):

    Code:
            <!-- Our activity is a subclass of the built-in NativeActivity framework class.
                 This will take care of integrating with our NDK code. -->
            <activity android:name="com.embarcadero.firemonkey.FMXNativeActivity"
                    android:label="%activityLabel%"
                    android:configChanges="orientation|keyboard|keyboardHidden"
                    android:launchMode="singleTask">
    
                <!-- Tell NativeActivity the name of our .so -->
                <meta-data android:name="android.app.lib_name"
                    android:value="%libNameValue%" />
                <intent-filter>  
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
    
                <intent-filter>
                    <action android:name="android.intent.action.VIEW" />
                    <category android:name="android.intent.category.DEFAULT" />
    
                    <data android:scheme="content" />
                    <data android:host="*" />
                    <data android:mimeType="application/gpx+xml" />
                </intent-filter> 
    
            </activity>
    
            <%activity%>
            <receiver android:name="com.embarcadero.firemonkey.notifications.FMXNotificationAlarm" />
            <%receivers%>
    //------------------------------------------------------------------------------

    Run de App 1 keer en sluit deze af.
    Als je nu op een .gpx bestand klik dan openend de App of kan je deze kiezen als er meer App's zijn die met een .gpx bestand werken.
    Last edited by MMSoft; 31-Mar-21 at 11:04.

  4. #4
    Er bestaat een app IntentIntercept.
    Die geeft extra gegevens aan als je een intent start.
    Welke gegevens zijn dit op Android 10?

    Probeer ook de regels met host eens weg te laten.

  5. #5
    Met dank aan Rik, ben ik een stukje verder.

    De regel:
    Code:
                    <data android:mimeType="application/gpx+xml" />
    Werkt alleen op de oudere Android versie (getest met versie 8) .

    Om dit ook werkend te krijgen op Android 10, heb ik deze regel toegevoegd:
    Code:
                    <data android:mimeType="application/gpx" />
    Bij een klik op een .gpx bestand start nu mijn App, maar nu de volgende stap:

    Hoe kan ik het path en de bestandsnaam van het .gpx bestand opvragen, en wel zo dat dit werkt met alle Android versies ?


    Edit:

    Met deze code, kan ik data ophalen:
    Code:
    procedure TForm1.FormCreate(Sender: TObject);
    var
     Intent: JIntent;
     Uri: Jnet_Uri;
     UriStr: String;
    
    begin
     Intent := SharedActivity.getIntent;
    
     if Intent <> nil then
     begin
    
       if TJIntent.JavaClass.ACTION_VIEW.equals(Intent.getAction) then
       begin
         Uri := Intent.getData;
         UriStr := JStringToString(Uri.toString);
    
         Memo1.Lines.Add( UriStr );
       end;
    
     end;
    
    end;
    Maar daar krijg is zoiets uit:
    content://0@media/external/file/225725

    Het Bestand staat hier dus als nummer en niet als naam, maar ik wil het Path en de naam van het bestand.
    Of is er een mogelijkheid om dit bestand te openen en uit te lezen ?

    Wie kan hier iets over vertellen ?
    Last edited by MMSoft; 02-Apr-21 at 12:35.

  6. #6
    Counting your refs
    Join Date
    Feb 2002
    Location
    Lage Zwaluwe
    Posts
    2,131
    Dat werkt onder Android (en iOS) niet zo triviaal, je deelt niet zomaar bestanden met andere apps maar "content". Om deze content uit te lezen gebruik je een content resolver: die maak je aan op basis van deze URL, daar query je tegen "wat heb je voor content voor me", en dan kun je daar de bestandsnaam uit lezen.

    Twee fragmentjes voorbeeldcode (Java) die je wellicht verder kunnen helpen met de juiste zoektermen/concepten om 't in Delphi/FMX uit te schrijven:

    Achterhalen bestandsnaam (alleen als je 'm nodig hebt)
    Code:
               String[] proj = {MediaStore.Images.Media.DATA};
                cursor = cordova.getActivity().getContentResolver().query(uri, proj, null, null, null);
                if (cursor != null)
                {
                    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                    cursor.moveToFirst();
                    fileName = cursor.getString(column_index);
                    fileName = new File(fileName).getName();
                }
    Het echte uitlezen van de data doe je vrij simpel met een InputStream:
    Code:
               InputStream inputStream = contentResolver.openInputStream(mijnUri);
            // en dan iets van readAllBytes ofzo, ik hoop dat FMX hier iets prachtigs voor gemaakt heeft :D
    Last edited by Paul-Jan; 02-Apr-21 at 16:01.

  7. #7
    Ik probeer de data uit te lezen:

    Code:
    var
     jis: JInputStream;
     Test :String;
    
    begin
     jis := TAndroidHelper.Context.getContentResolver.openInputStream(Uri);
     Test := TAndroidHelper.contentResolver.openInputStream(Uri);
    Geen idee welke van deze 2 de juiste is, en hoe ik deze kan gebruiken om het bestand uit te lezen.
    Ik vindt bij beide niet iets als readAllBytes, en heb nu geen idee of ik op de juiste weg ben.


    Edit:
    Code:
      jis := MainActivity.getContentResolver.openInputStream(Uri);
    
      m := jis.read;
      Memo1.Lines.Add( IntToStr(m) );  //Welk bestand ik ook kies, hier krijg ik altijd het getal 239
    Zit ik op de goede weg ?
    Last edited by MMSoft; 03-Apr-21 at 08:52.

  8. #8
    Counting your refs
    Join Date
    Feb 2002
    Location
    Lage Zwaluwe
    Posts
    2,131
    Je zou zeggen van wel

    Op https://stackoverflow.com/questions/...g-its-jnet-uri doen ze het volgende:

    Delphi Code:
    1. var
    2.   ms: TMemoryStream;
    3.   jis: JInputStream;
    4.   b: TJavaArray<Byte>;
    5.  
    6. begin
    7.   // ...
    8.   ms := TMemoryStream.Create;
    9.  
    10.   // Inlezen via JInputStream
    11.   jis := TAndroidHelper.Context.getContentResolver.openInputStream(uri);
    12.   b := TJavaArray<Byte>.Create(jis.available);
    13.   jis.read(b);
    14.   ms.Write(b.Data^, b.Length);
    15.   jis.close;

    Ze geven daar dus de java array mee als argument aan jis.read(b), en kopieren daarna de data naar een memorystream. Ik zou het zelf meteen naar een byte array kopieren ipv naar een memorystream, maar dat hangt maar net er vanaf wat je er mee wil. :-)

  9. #9
    "Begin_Route" is een string, en deze bestaat uit het path en het bestand van de route die ik inlees.

    Deze las ik hier in:
    Map1.LoadFromFile( Begin_Route ); //Route inlezen
    Dit werkt prima,
    maar nu de nieuwe uitbreiding, dus de App starten door op een route bestand te klikken:

    Als de App gestart wordt met een Route bestand (.gpx), dan wil ik dit bestand dus hier inlezen:
    Map1.LoadFromFile( ... ); //Route inlezen

    Hoe kan ik dat op een liefst zo eenvoudig mogelijke manier voor elkaar krijgen ?

  10. #10
    Quote Originally Posted by Paul-Jan View Post

    Achterhalen bestandsnaam (alleen als je 'm nodig hebt)
    Code:
               String[] proj = {MediaStore.Images.Media.DATA};
                cursor = cordova.getActivity().getContentResolver().query(uri, proj, null, null, null);
                if (cursor != null)
                {
                    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                    cursor.moveToFirst();
                    fileName = cursor.getString(column_index);
                    fileName = new File(fileName).getName();
                }
    Omdat ik uiteindelijk ook de bestands naam en path nodig heb ben ik hier nu mee bezig, maar hier loop ik helaas van alle kanten vast.

    Dus hoe pak ik dit aan in FMX ?
    Last edited by MMSoft; 04-Apr-21 at 08:44.

  11. #11
    Ik ben nu zover dat ik een file nummer krijg, bijvoorbeeld: 121427

    Er is maar 1 regel (Cursor.getCount = 1), dus heb ik het zo gedaan:

    Code:
    var
     Cursor: JCursor;
     name: String;
     fileName: String;
    
    
    
     Cursor := TAndroidHelper.Context.getContentResolver.Query(Uri, nil, nil, nil, nil);
     Cursor.moveToFirst;
     name := JStringToString( Cursor.getString(0) );  //Het bestands nummer ophalen
     Memo1.Lines.Add( name ); //Het bestands nummer
    
     fileName := ...
    
     Cursor.close;

    Hoe kan ik dit nummer gebruiken om het bestand dat hierbij hoort te gebruiken ?
    Van dat bestand wil ik graag de bestands naam en het path hebben, dus wij kan mij weer een beetje verder helpen ?


    Edit:
    Bovenstaande code werkt op Android 8 wel, maar op Android 10 helaas niet, met onderstaande code kan ik met beide Android versies het path + File nummer opvragen,
    maar is dit wel een goede manier ?

    Code:
       Memo1.Lines.Add( JStringToString( Uri.getPath ) );
    Dit geeft bijvoorbeeld: /external/file/37968

    En hoe kan ik met behulp van het file nummer de bestandsnaam en zijn path opvragen ?
    Last edited by MMSoft; 05-Apr-21 at 11:37.

  12. #12
    Counting your refs
    Join Date
    Feb 2002
    Location
    Lage Zwaluwe
    Posts
    2,131
    In je codefragmentje vraag je kolom 0 op, dat is niet de kolom waar de filename in staat. De juiste kolom vraag je in Java op via cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME ).

    Ik heb hieronder even een volledig (getest, werkend) voorbeeldje in Android Java uitgeschreven. Ik werk al een jaar of 8 niet meer met Delphi, dus ik kan je echt niet helpen met het stukje vertalen naar FMX. Eventueel kunnen andere mensen op het forum vast wel bijspringen als de vertaalslag stukloopt.

    Ik weet niet waarom het in jouw testen niet werkt onder Android 10, ik heb dat nu niet expliciet getest. Het is ongetwijfeld een kwestie van instellingen/permissies, ik zou je aanraden eerst de "werkende" situatie af te polijsten. Dit is echt de standaard manier om file associations te implementeren onder Android, een andere manier is er niet bij mijn weten.

    Code:
    package com.eponalabs.test.gpxviewer;
    
    import android.content.ContentResolver;
    import android.content.Intent;
    import android.database.Cursor;
    import android.net.Uri;
    import android.os.Bundle;
    import android.provider.OpenableColumns;
    import android.widget.Toast;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Locale;
    import java.util.Objects;
    
    public class MainActivity extends AppCompatActivity
    {
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Intent intent = getIntent();
            String action = intent.getAction();
    
            if (Objects.equals(action, Intent.ACTION_VIEW))
            {
                String scheme = intent.getScheme();
                ContentResolver resolver = getContentResolver();
    
                if (Objects.equals(scheme, ContentResolver.SCHEME_CONTENT))
                {
                    Uri uri = intent.getData();
                    if (uri == null)
                        return;
                    // Filename uitlezen
                    String name = getFilename(uri);
    
                    // Data uitlezen
                    InputStream inputStream;
                    try
                    {
                        // Inputstream even omzetten naar bytes
                        inputStream = resolver.openInputStream(uri);
                        if (inputStream == null)
                            return;
                        byte[] data = convertToByteArray(inputStream);
    
                        // Hier gaan we iets interessanters doen met deze bytes dan deze toast
                        String text = String.format(Locale.US, "We hebben %d bytes uit het bestand %s gelezen", data.length, name);
                        Toast toast = Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG);
                        toast.show();
                    } catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        public String getFilename(Uri uri)
        {
            String result = null;
            if (uri != null && Objects.equals(uri.getScheme(), "content"))
            {
                try (Cursor cursor = getContentResolver().query(uri, null, null, null, null))
                {
                    if (cursor != null && cursor.moveToFirst())
                    {
                        result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
                    }
                }
            }
    
            if (result == null && uri != null)
            {
                result = uri.getPath();
                if (result != null)
                {
                    int cut = result.lastIndexOf('/');
                    if (cut != -1)
                    {
                        result = result.substring(cut + 1);
                    }
                }
            }
            return result;
        }
    
        public byte[] convertToByteArray(InputStream inputStream) throws IOException
        {
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            int nRead;
            byte[] data = new byte[1024];
            while ((nRead = inputStream.read(data, 0, data.length)) != -1)
            {
                buffer.write(data, 0, nRead);
            }
    
            buffer.flush();
            return buffer.toByteArray();
        }
    }

  13. #13
    Ik ben bezig met het vertalen naar FMX, dit heb ik nu:

    Code:
    procedure TForm1.FormCreate(Sender: TObject);
    var
     Intent: JIntent;
     action: String;
     scheme: String;
     resolver: JContentResolver;
    
    begin
    
     //super.onCreate(savedInstanceState);
     //???
    
     //setContentView(R.layout.activity_main);
     //???
    
     //Intent intent = getIntent();
     Intent := SharedActivity.getIntent;
    
     //String action = intent.getAction();
     action := JStringToString( Intent.getAction() );
    
     //if (Objects.equals(action, Intent.ACTION_VIEW))
     if TJIntent.JavaClass.ACTION_VIEW.equals(Intent.getAction) then
      begin
    
        //String scheme = intent.getScheme();
        scheme := JStringToString( intent.getScheme() );
    
        //ContentResolver resolver = getContentResolver();
        resolver := TAndroidHelper.Activity.getContentResolver();
    
        //if (Objects.equals(scheme, ContentResolver.SCHEME_CONTENT))
        if TJIntent.JavaClass.SCHEME_CONTENT.equals(ContentResolver.getscheme) then
         begin
    
    
         end;
    
      end;
    
    
    end;
    Denken jullie dat het zo klopt ?

    En deze regel krijg ik niet vertaald:
    if (Objects.equals(scheme, ContentResolver.SCHEME_CONTENT))

    Tips zijn erg welkom

  14. #14
    Ik heb het eindelijk werkend !!!

    Het is niet "DISPLAY_NAME" maar "_DISPLAY_NAME", dat heeft even tijd gekost voor ik dat door had
    Met "_DISPLAY_NAME", krijg je de Bestands naam, en met "_Data" het Path + Bestands naam.

    Deze code is vast en zeker nog niet perfect, maar het werkt...

    Code:
    procedure TForm1.FormCreate(Sender: TObject);
    var
     Intent: JIntent;
     Uri: Jnet_Uri;
     action: String;
     scheme: String;
     resolver: JContentResolver;
     name: String;
    
    begin
    
     Intent := SharedActivity.getIntent;
     action := JStringToString( Intent.getAction() );
    
     if TJIntent.JavaClass.ACTION_VIEW.equals(Intent.getAction) then
      begin
        scheme := JStringToString( intent.getScheme() );
        resolver := TAndroidHelper.Activity.getContentResolver();
    
        Uri := Intent.getData;
        if (Uri.getScheme.equals(TJContentResolver.JavaClass.SCHEME_CONTENT)) then
          begin
            if Uri = nil then
              begin
               ShowMessage('Exit');
               exit
              end;
    
            // Path + Filename uitlezen
            name := getPathFilename(Uri);
            ShowMessage('Path + Naam: ' + name);
    
            // Filename uitlezen
            name := getFilename(Uri);
            ShowMessage('Naam: ' + name);
          end;
    
      end;
    
    end;
    
    //------------------------------------------------------------------------------
    
    function getFilename(Uri: Jnet_Uri): String;
    var
     Cursor: JCursor;
     Kolom : Integer;
    
    begin
     result := '';
    
     if (Uri <> nil) and (Uri.getScheme.equals(TJContentResolver.JavaClass.SCHEME_CONTENT)) then
      begin
       try 
         Cursor := TAndroidHelper.Context.getContentResolver.Query(Uri, nil, nil, nil, nil);
         Cursor.moveToFirst;
    
         //Bestands naam:
         Kolom := cursor.getColumnIndex( StringToJString(  '_DISPLAY_NAME') ); //In welke Kolom staat '_DISPLAY_NAME'
         result := JStringToString( cursor.getString( Kolom ) ); //De inhoud van deze Kolom uitlezen
    
       except
         ShowMessage('Error 1');
       end;
    
      end;
    
    end;
    
    //------------------------------------------------------------------------------
    
    function getPathFilename(Uri: Jnet_Uri): String;
    var
     Cursor: JCursor;
     Kolom : Integer;
    
    begin
     result := '';
    
     if (Uri <> nil) and (Uri.getScheme.equals(TJContentResolver.JavaClass.SCHEME_CONTENT)) then
      begin
       try 
         Cursor := TAndroidHelper.Context.getContentResolver.Query(Uri, nil, nil, nil, nil);
         Cursor.moveToFirst;
    
         //Path + Bestands naam:
         Kolom := cursor.getColumnIndex( StringToJString(  '_Data') ); //In welke Kolom staat '_Data' ?
         result := JStringToString( cursor.getString( Kolom ) ); //De inhoud van deze Kolom uitlezen
    
       except
         ShowMessage('Error 1');
       end;
    
      end;
    
    end;
    Op en aanmerkingen zijn erg welkom.

  15. #15
    Counting your refs
    Join Date
    Feb 2002
    Location
    Lage Zwaluwe
    Posts
    2,131
    Gefeliciteerd Mario! Het heeft je heel wat bloed, zweet en tranen gekost, maar je hebt het werkend gekregen!

    Code:
    ────────────────────░███░
    ───────────────────░█░░░█░
    ──────────────────░█░░░░░█░
    ─────────────────░█░░░░░█░
    ──────────░░░───░█░░░░░░█░
    ─────────░███░──░█░░░░░█░
    ───────░██░░░██░█░░░░░█░
    ──────░█░░█░░░░██░░░░░█░
    ────░██░░█░░░░░░█░░░░█░
    ───░█░░░█░░░░░░░██░░░█░
    ──░█░░░░█░░░░░░░░█░░░█░
    ──░█░░░░░█░░░░░░░░█░░░█░
    ──░█░░█░░░█░░░░░░░░█░░█░
    ─░█░░░█░░░░██░░░░░░█░░█░
    ─░█░░░░█░░░░░██░░░█░░░█░
    ─░█░█░░░█░░░░░░███░░░░█░
    ░█░░░█░░░██░░░░░█░░░░░█░
    ░█░░░░█░░░░█████░░░░░█░
    ░█░░░░░█░░░░░░░█░░░░░█░
    ░█░█░░░░██░░░░█░░░░░█░
    ─░█░█░░░░░████░░░░██░
    ─░█░░█░░░░░░░█░░██░█░
    ──░█░░██░░░██░░█░░░█░
    ───░██░░███░░██░█░░█░
    ────░██░░░███░░░█░░░█░
    ──────░███░░░░░░█░░░█░
    ──────░█░░░░░░░░█░░░█░
    ──────░█░░░░░░░░░░░░█░
    ──────░█░░░░░░░░░░░░░█░
    ──────░█░░░░░░░░░░░░░█░

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •