Cloudron makes it easy to run web apps like WordPress, Nextcloud, GitLab on your server. Find out more or install now.


Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Bookmarks
  • Search
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo

Cloudron Forum

Apps | Demo | Docs | Install
  1. Cloudron Forum
  2. App Wishlist
  3. OpenFire (XMPP server)

OpenFire (XMPP server)

Scheduled Pinned Locked Moved App Wishlist
40 Posts 8 Posters 5.6k Views 8 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • nebulonN nebulon

    @potemkin_ai I've created a repo at https://git.cloudron.io/cloudron/openfire-app and gave you access rights.

    potemkin_aiP Offline
    potemkin_aiP Offline
    potemkin_ai
    wrote on last edited by
    #12

    @nebulon thank you, pushed the code and GitHub Workflow automation at https://git.cloudron.io/cloudron/openfire-app

    You will notice that a manifest file mentions turn server - that's on purpose, to make sure that I can easily grab it's credentials, as I need both XMPP & TURN for my case.

    @guusdk , hi, I didn't expect that, but it's really nice to hear that!

    If you will check the repo (https://git.cloudron.io/cloudron/openfire-app), you will notice three *.patch files there: OpenFire checks if it can write into the at the folder other than /app/data, despite it seems not to use that at all - is that is something that could be adjusted at OpenFire side?

    As a general idea, I believe it would be great to make OpenFire to use Cloudron's database, to ensure it's all managed inside of it.

    If anything - please, let me know!

    guusdkG 1 Reply Last reply
    3
    • potemkin_aiP potemkin_ai

      @nebulon thank you, pushed the code and GitHub Workflow automation at https://git.cloudron.io/cloudron/openfire-app

      You will notice that a manifest file mentions turn server - that's on purpose, to make sure that I can easily grab it's credentials, as I need both XMPP & TURN for my case.

      @guusdk , hi, I didn't expect that, but it's really nice to hear that!

      If you will check the repo (https://git.cloudron.io/cloudron/openfire-app), you will notice three *.patch files there: OpenFire checks if it can write into the at the folder other than /app/data, despite it seems not to use that at all - is that is something that could be adjusted at OpenFire side?

      As a general idea, I believe it would be great to make OpenFire to use Cloudron's database, to ensure it's all managed inside of it.

      If anything - please, let me know!

      guusdkG Offline
      guusdkG Offline
      guusdk
      wrote on last edited by
      #13

      @potemkin_ai

      @potemkin_ai said in OpenFire (XMPP server):

      OpenFire checks if it can write into the at the folder other than /app/data, despite it seems not to use that at all .

      If I read your changes correctly, then what you are changing in JiveGlobals.java.patch is the check for write permission in Openfire's "home" directory. Some Openfire code, such as plugins, will write to the "home" directory. The monitoring plugin, for example, will create a folder there. As the plugin architecture is an API, any number of third party plugins might also depend on this. Maybe you have not used functionality yet that tries to write here, but I do believe that there is code out that that will do this. I do not think that you should disable the 'write' check. We certainly can't do this in the upstream project.

      As a general idea, I believe it would be great to make OpenFire to use Cloudron's database, to ensure it's all managed inside of it.

      There are various ways to do this: Openfire could simply re-use a database server that is being provided (but still have it's own, dedicated database), but it could also use an externally managed user store (eg: LDAP, AD, or some database tables), which would make Openfire use the users as defined in the system.

      There are some pros and cons for doing this. When using an external user store, Openfire will treat this as a 'read-only' store. This means that you can't add users through Openfire. If that's a feature or an issue is up to you. 🙂

      potemkin_aiP 1 Reply Last reply
      1
      • guusdkG guusdk

        @potemkin_ai

        @potemkin_ai said in OpenFire (XMPP server):

        OpenFire checks if it can write into the at the folder other than /app/data, despite it seems not to use that at all .

        If I read your changes correctly, then what you are changing in JiveGlobals.java.patch is the check for write permission in Openfire's "home" directory. Some Openfire code, such as plugins, will write to the "home" directory. The monitoring plugin, for example, will create a folder there. As the plugin architecture is an API, any number of third party plugins might also depend on this. Maybe you have not used functionality yet that tries to write here, but I do believe that there is code out that that will do this. I do not think that you should disable the 'write' check. We certainly can't do this in the upstream project.

        As a general idea, I believe it would be great to make OpenFire to use Cloudron's database, to ensure it's all managed inside of it.

        There are various ways to do this: Openfire could simply re-use a database server that is being provided (but still have it's own, dedicated database), but it could also use an externally managed user store (eg: LDAP, AD, or some database tables), which would make Openfire use the users as defined in the system.

        There are some pros and cons for doing this. When using an external user store, Openfire will treat this as a 'read-only' store. This means that you can't add users through Openfire. If that's a feature or an issue is up to you. 🙂

        potemkin_aiP Offline
        potemkin_aiP Offline
        potemkin_ai
        wrote on last edited by
        #14

        @guusdk I see, thank you for the comments!

        What would you suggest to keep OpenFire working and preserve the data?
        I'm thinking about some hard links for the folders, but I might be missing something obviously.

        As for the database - I'm not a user of LDAP thing, so I was thinking about Openfire main database running inside Cloudron's MySQL/PostgreSQL/MongoDB, what would be your say on that?

        guusdkG 1 Reply Last reply
        0
        • potemkin_aiP potemkin_ai

          @guusdk I see, thank you for the comments!

          What would you suggest to keep OpenFire working and preserve the data?
          I'm thinking about some hard links for the folders, but I might be missing something obviously.

          As for the database - I'm not a user of LDAP thing, so I was thinking about Openfire main database running inside Cloudron's MySQL/PostgreSQL/MongoDB, what would be your say on that?

          guusdkG Offline
          guusdkG Offline
          guusdk
          wrote on last edited by guusdk
          #15

          @potemkin_ai said in OpenFire (XMPP server):

          What would you suggest to keep OpenFire working and preserve the data?
          I'm thinking about some hard links for the folders, but I might be missing something obviously.

          I do not understand what you are saying. Please note that I'm completely unfamiliar with Cloudron. You will need to be able to keep/retain files and folders in the Openfire home directory, if that's what your asking.

          @potemkin_ai said in OpenFire (XMPP server):

          As for the database - I'm not a user of LDAP thing, so I was thinking about Openfire main database running inside Cloudron's MySQL/PostgreSQL/MongoDB, what would be your say on that?

          Openfire supports Postgres and MySQL, but not MongoDB. Openfire even supports a number of other databases, or can use an embedded database. Functionality-wise, there is no difference between using Postgres and MySQL. For production purposes, it's best to stay away from the embedded database.

          As an aside: even with LDAP integration, you'd still need a database for Openfire. They are not mutually exclusive. With LDAP integration, less data will be stored in Openfire's database (the user definitions), but the database will still be used by Openfire.

          potemkin_aiP 1 Reply Last reply
          0
          • guusdkG guusdk

            @potemkin_ai said in OpenFire (XMPP server):

            What would you suggest to keep OpenFire working and preserve the data?
            I'm thinking about some hard links for the folders, but I might be missing something obviously.

            I do not understand what you are saying. Please note that I'm completely unfamiliar with Cloudron. You will need to be able to keep/retain files and folders in the Openfire home directory, if that's what your asking.

            @potemkin_ai said in OpenFire (XMPP server):

            As for the database - I'm not a user of LDAP thing, so I was thinking about Openfire main database running inside Cloudron's MySQL/PostgreSQL/MongoDB, what would be your say on that?

            Openfire supports Postgres and MySQL, but not MongoDB. Openfire even supports a number of other databases, or can use an embedded database. Functionality-wise, there is no difference between using Postgres and MySQL. For production purposes, it's best to stay away from the embedded database.

            As an aside: even with LDAP integration, you'd still need a database for Openfire. They are not mutually exclusive. With LDAP integration, less data will be stored in Openfire's database (the user definitions), but the database will still be used by Openfire.

            potemkin_aiP Offline
            potemkin_aiP Offline
            potemkin_ai
            wrote on last edited by
            #16

            @nebulon or @girish will correct me if I'm wrong, but in a way I understand, /app/data is the only preservable place for the data + it's the place that is covered by a backups.

            So, @guusdk , I'm thinking if we can somehow place all of the OpenFire writeable data there. By introducing some variables and/or using hard links (https://www.geeksforgeeks.org/soft-hard-links-unixlinux/)

            guusdkG 1 Reply Last reply
            0
            • potemkin_aiP potemkin_ai

              @nebulon or @girish will correct me if I'm wrong, but in a way I understand, /app/data is the only preservable place for the data + it's the place that is covered by a backups.

              So, @guusdk , I'm thinking if we can somehow place all of the OpenFire writeable data there. By introducing some variables and/or using hard links (https://www.geeksforgeeks.org/soft-hard-links-unixlinux/)

              guusdkG Offline
              guusdkG Offline
              guusdk
              wrote on last edited by
              #17

              @potemkin_ai Different distributables for Openfire use different layouts for storing files on the file system. The RPM and DEB distributables do not add all that much. They check for dependencies (which is just "java") and add a service script, and provide a bit of infrastructure for updating/upgrading.

              When you use the tarball instead of the RPM or DEB, you will just get everything in one directory (that you can place where-ever you want). With that, you should only need to worry about the startup scripts pointing at the right place, and replacing only the right files when updating to a future new version. This might simplify things for you.

              potemkin_aiP 2 Replies Last reply
              0
              • guusdkG guusdk

                @potemkin_ai Different distributables for Openfire use different layouts for storing files on the file system. The RPM and DEB distributables do not add all that much. They check for dependencies (which is just "java") and add a service script, and provide a bit of infrastructure for updating/upgrading.

                When you use the tarball instead of the RPM or DEB, you will just get everything in one directory (that you can place where-ever you want). With that, you should only need to worry about the startup scripts pointing at the right place, and replacing only the right files when updating to a future new version. This might simplify things for you.

                potemkin_aiP Offline
                potemkin_aiP Offline
                potemkin_ai
                wrote on last edited by potemkin_ai
                #18
                This post is deleted!
                1 Reply Last reply
                0
                • guusdkG guusdk

                  @potemkin_ai Different distributables for Openfire use different layouts for storing files on the file system. The RPM and DEB distributables do not add all that much. They check for dependencies (which is just "java") and add a service script, and provide a bit of infrastructure for updating/upgrading.

                  When you use the tarball instead of the RPM or DEB, you will just get everything in one directory (that you can place where-ever you want). With that, you should only need to worry about the startup scripts pointing at the right place, and replacing only the right files when updating to a future new version. This might simplify things for you.

                  potemkin_aiP Offline
                  potemkin_aiP Offline
                  potemkin_ai
                  wrote on last edited by
                  #19

                  @guusdk apologies for the delay in getting back to you.

                  In a way I understand, what you say, it's that you are not familiar with Cloudron structure, so let me share what I believe is a key things here:

                  • app should strictly reside in /app folder
                  • the whole Docker image is mounted read-only (--read-only at docker run)
                  • and just a few folders are read-write, where the key folder for our purpose is /app/data

                  @girish , @nebulon , please, feel free to correct me if I'm wrong here!

                  So, the decision has been made to place the plugins at /app/data - for this we patch Dockerfile to create a link for the plugins to /app/data - via ln -s ${OPENFIRE_DATA_DIR}/plugins ${OPENFIRE_DIR}/

                  That's why removal of the RW check from the home directory seems like a proper decision. It shall also help to preserve the plugins from the backup, as they could be installed manually.

                  What do you think?

                  timconsidineT guusdkG 2 Replies Last reply
                  0
                  • potemkin_aiP potemkin_ai

                    @guusdk apologies for the delay in getting back to you.

                    In a way I understand, what you say, it's that you are not familiar with Cloudron structure, so let me share what I believe is a key things here:

                    • app should strictly reside in /app folder
                    • the whole Docker image is mounted read-only (--read-only at docker run)
                    • and just a few folders are read-write, where the key folder for our purpose is /app/data

                    @girish , @nebulon , please, feel free to correct me if I'm wrong here!

                    So, the decision has been made to place the plugins at /app/data - for this we patch Dockerfile to create a link for the plugins to /app/data - via ln -s ${OPENFIRE_DATA_DIR}/plugins ${OPENFIRE_DIR}/

                    That's why removal of the RW check from the home directory seems like a proper decision. It shall also help to preserve the plugins from the backup, as they could be installed manually.

                    What do you think?

                    timconsidineT Offline
                    timconsidineT Offline
                    timconsidine
                    App Dev
                    wrote on last edited by
                    #20

                    @potemkin_ai said in OpenFire (XMPP server):

                    app should strictly reside in /app folder

                    I thought specifically in /app/code but maybe I am wrong

                    1 Reply Last reply
                    0
                    • potemkin_aiP potemkin_ai

                      @guusdk apologies for the delay in getting back to you.

                      In a way I understand, what you say, it's that you are not familiar with Cloudron structure, so let me share what I believe is a key things here:

                      • app should strictly reside in /app folder
                      • the whole Docker image is mounted read-only (--read-only at docker run)
                      • and just a few folders are read-write, where the key folder for our purpose is /app/data

                      @girish , @nebulon , please, feel free to correct me if I'm wrong here!

                      So, the decision has been made to place the plugins at /app/data - for this we patch Dockerfile to create a link for the plugins to /app/data - via ln -s ${OPENFIRE_DATA_DIR}/plugins ${OPENFIRE_DIR}/

                      That's why removal of the RW check from the home directory seems like a proper decision. It shall also help to preserve the plugins from the backup, as they could be installed manually.

                      What do you think?

                      guusdkG Offline
                      guusdkG Offline
                      guusdk
                      wrote on last edited by
                      #21

                      @potemkin_ai In its most basic form, Openfire is installed in a directory, $OPENFIRE_HOME. Some distributions split this out over various locations on the file system (eg: logs to /var/log, etc).

                      Openfire will install plugins in $OPENFIRE_HOME/plugins/ where files will be downloaded, and folders will be extracted.

                      When running, Openfire will attempt to create and/or modify various other files and directories in or under $OPENFIRE_HOME. As an example, this includes, but is not limited to:

                      • $OPENFIRE_HOME/conf/available-plugins.xml where update checks are cached;
                      • $OPENFIRE_HOME/embedded-db/ where the embedded/in-memory database is persisted (this is not used when you're using an external database like MySQL or PostgreSQL);
                      • $OPENFIRE_HOME/resources/security/ where private key and certificate stores are being maintained;
                      • $OPENFIRE_HOME/logs where log files are written.

                      Furthermore, plugins can be expected to create content anywhere under $OPENFIRE_HOME/. A popular plugin, the Monitoring Service plugin, will, for example, create $OPENFIRE_HOME/monitoring/ to persist data that needs to survive an plugin upgrade.

                      In short, all of $OPENFIRE_HOME will need to be not only readable, but also writable to the user that is running the Openfire process. Functional issues of very varied impact will otherwise be almost guaranteed to occur.

                      potemkin_aiP 1 Reply Last reply
                      1
                      • guusdkG guusdk

                        @potemkin_ai In its most basic form, Openfire is installed in a directory, $OPENFIRE_HOME. Some distributions split this out over various locations on the file system (eg: logs to /var/log, etc).

                        Openfire will install plugins in $OPENFIRE_HOME/plugins/ where files will be downloaded, and folders will be extracted.

                        When running, Openfire will attempt to create and/or modify various other files and directories in or under $OPENFIRE_HOME. As an example, this includes, but is not limited to:

                        • $OPENFIRE_HOME/conf/available-plugins.xml where update checks are cached;
                        • $OPENFIRE_HOME/embedded-db/ where the embedded/in-memory database is persisted (this is not used when you're using an external database like MySQL or PostgreSQL);
                        • $OPENFIRE_HOME/resources/security/ where private key and certificate stores are being maintained;
                        • $OPENFIRE_HOME/logs where log files are written.

                        Furthermore, plugins can be expected to create content anywhere under $OPENFIRE_HOME/. A popular plugin, the Monitoring Service plugin, will, for example, create $OPENFIRE_HOME/monitoring/ to persist data that needs to survive an plugin upgrade.

                        In short, all of $OPENFIRE_HOME will need to be not only readable, but also writable to the user that is running the Openfire process. Functional issues of very varied impact will otherwise be almost guaranteed to occur.

                        potemkin_aiP Offline
                        potemkin_aiP Offline
                        potemkin_ai
                        wrote on last edited by
                        #22

                        @guusdk thank you!

                        I believe that what you see is achievable with a symlinks, and that's what we have in place already: https://github.com/GetZenDev/build-openfire-docker/blob/main/Dockerfile.patch#L29

                        The only one folder that has been missing - it's monitoring folder - here is the commit (also submitted to cloudrong's git): https://github.com/GetZenDev/build-openfire-docker/commit/788a95a7acc778dbcdb1a6df0156345aa42d68c1

                        Do you think we have it covered now?

                        guusdkG 1 Reply Last reply
                        1
                        • potemkin_aiP potemkin_ai

                          @guusdk thank you!

                          I believe that what you see is achievable with a symlinks, and that's what we have in place already: https://github.com/GetZenDev/build-openfire-docker/blob/main/Dockerfile.patch#L29

                          The only one folder that has been missing - it's monitoring folder - here is the commit (also submitted to cloudrong's git): https://github.com/GetZenDev/build-openfire-docker/commit/788a95a7acc778dbcdb1a6df0156345aa42d68c1

                          Do you think we have it covered now?

                          guusdkG Offline
                          guusdkG Offline
                          guusdk
                          wrote on last edited by
                          #23

                          @potemkin_ai My Docker knowledge is not sufficiently enough to answer that decisively. It does appear that the monitoring folder was specifically added to your Docker image. Although that probably resolves the issue for that particular plugin of Openfire, my point was more generic: any plugin can create any unexpected folder anywhere in $OPENFIRE_HOME. Adding specific folders for known cases is at best a patch, not a solution.

                          potemkin_aiP 1 Reply Last reply
                          1
                          • guusdkG guusdk

                            @potemkin_ai My Docker knowledge is not sufficiently enough to answer that decisively. It does appear that the monitoring folder was specifically added to your Docker image. Although that probably resolves the issue for that particular plugin of Openfire, my point was more generic: any plugin can create any unexpected folder anywhere in $OPENFIRE_HOME. Adding specific folders for known cases is at best a patch, not a solution.

                            potemkin_aiP Offline
                            potemkin_aiP Offline
                            potemkin_ai
                            wrote on last edited by
                            #24

                            @guusdk agree, seems like it's the best workaround considering a mixture of data & code in one place...

                            I would expect that you (OpenFire team) won't be changing the structure, separating the config files, binaries, extensions?

                            guusdkG 1 Reply Last reply
                            0
                            • potemkin_aiP potemkin_ai

                              @guusdk agree, seems like it's the best workaround considering a mixture of data & code in one place...

                              I would expect that you (OpenFire team) won't be changing the structure, separating the config files, binaries, extensions?

                              guusdkG Offline
                              guusdkG Offline
                              guusdk
                              wrote on last edited by
                              #25

                              @potemkin_ai Not without a very, very good reason. Making a convention that has been in place for ~20 years more strict like that will introduce a world of hurt, that I will try to avoid against pretty much all reasonable cost.

                              robiR 1 Reply Last reply
                              0
                              • guusdkG guusdk

                                @potemkin_ai Not without a very, very good reason. Making a convention that has been in place for ~20 years more strict like that will introduce a world of hurt, that I will try to avoid against pretty much all reasonable cost.

                                robiR Offline
                                robiR Offline
                                robi
                                wrote on last edited by
                                #26

                                @guusdk Would it not be wise to specify a plugin directory or at least a configurable environment variable?

                                Conscious tech

                                guusdkG 1 Reply Last reply
                                1
                                • robiR robi

                                  @guusdk Would it not be wise to specify a plugin directory or at least a configurable environment variable?

                                  guusdkG Offline
                                  guusdkG Offline
                                  guusdk
                                  wrote on last edited by
                                  #27

                                  @robi in hindsight, that would have been a good idea.

                                  I worry that introducing that now, after so many years of having a very static convention that internal code, but also third party code has grown to depend on, will cause a plethora of intermittent issues that are environment-specific, and hard to debug or explain.

                                  Introducing that now is not an insignificant task. It would also mean that we have to take on the commitment that we support and maintain that solution. If we would not do that, then this would potentially decrement from the perceived stability of Openfire.

                                  For me, the cost vs. weight doesn't balance.

                                  robiR 1 Reply Last reply
                                  0
                                  • potemkin_aiP potemkin_ai

                                    I would like to see OpenFire (easy to use and administer XMPP server) on Cloudron.

                                    I've prepared a private image - what is required to push it to your AppStore?

                                    L Offline
                                    L Offline
                                    LoudLemur
                                    wrote on last edited by
                                    #28

                                    @potemkin_ai said in OpenFire (XMPP server):

                                    I would like to see OpenFire (easy to use and administer XMPP server) on Cloudron.

                                    I've prepared a private image - what is required to push it to your AppStore?

                                    Thank you for doing this.

                                    potemkin_aiP 1 Reply Last reply
                                    0
                                    • guusdkG guusdk

                                      @robi in hindsight, that would have been a good idea.

                                      I worry that introducing that now, after so many years of having a very static convention that internal code, but also third party code has grown to depend on, will cause a plethora of intermittent issues that are environment-specific, and hard to debug or explain.

                                      Introducing that now is not an insignificant task. It would also mean that we have to take on the commitment that we support and maintain that solution. If we would not do that, then this would potentially decrement from the perceived stability of Openfire.

                                      For me, the cost vs. weight doesn't balance.

                                      robiR Offline
                                      robiR Offline
                                      robi
                                      wrote on last edited by
                                      #29

                                      @guusdk I hear you, however, things can be tested, beta'd and staged with all known plugins in a way to minimize those issues, with helpful migration scripts and other techniques that further enhance maintainability.

                                      Being frozen in fear of issues while doing the right things suggests many other insecurities from various perspectives.

                                      Plus this is a great time to root out the hidden issues that haven't been found yet, but are lurking behind the fear of no changes.

                                      I hope you're not in a legacy situation where dependecies prevent further updates.

                                      Conscious tech

                                      guusdkG 1 Reply Last reply
                                      0
                                      • robiR robi

                                        @guusdk I hear you, however, things can be tested, beta'd and staged with all known plugins in a way to minimize those issues, with helpful migration scripts and other techniques that further enhance maintainability.

                                        Being frozen in fear of issues while doing the right things suggests many other insecurities from various perspectives.

                                        Plus this is a great time to root out the hidden issues that haven't been found yet, but are lurking behind the fear of no changes.

                                        I hope you're not in a legacy situation where dependecies prevent further updates.

                                        guusdkG Offline
                                        guusdkG Offline
                                        guusdk
                                        wrote on last edited by
                                        #30

                                        @robi I appreciate that this would solve an issue that we are discussing here, but that issue seems to be very specific to this particular environment. To my knowledge, this is the first time that anyone has ever thought this to be important enough to even start discussing it with us.

                                        robiR potemkin_aiP 2 Replies Last reply
                                        0
                                        • guusdkG guusdk

                                          @robi I appreciate that this would solve an issue that we are discussing here, but that issue seems to be very specific to this particular environment. To my knowledge, this is the first time that anyone has ever thought this to be important enough to even start discussing it with us.

                                          robiR Offline
                                          robiR Offline
                                          robi
                                          wrote on last edited by robi
                                          #31

                                          @guusdk Actually, I am being much more general than this specific issue.

                                          I have no stake in it, as I don't use OpenFire yet, however reading about how any plugin can create files and folders in the home dir, that is as you agreed, less than optimal and a potential security issue via overwriting core files.

                                          If that is not a concern, I'm sure a code audit would bring up other useful architectural changes.

                                          If you're familiar with Wordpress, these are the categories of things they needed to address early on in their popularity, which still remains today.

                                          Conscious tech

                                          1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Bookmarks
                                          • Search