Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
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
Code Project
  1. Home
  2. The Lounge
  3. C# syntax I wish for

C# syntax I wish for

Scheduled Pinned Locked Moved The Lounge
csharpcomlounge
24 Posts 9 Posters 0 Views 1 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.
  • P Pete OHanlon

    It would seem to me that this would be more appropriate as a Task continuation, rather than as a blocking call inside a task. By the way, language proposals are now made on the Roslyn[^] site.

    This space for rent

    S Offline
    S Offline
    Super Lloyd
    wrote on last edited by
    #5

    I don't understand your message Pete, what blocking call are you talking about? My method effectively turn waiting for that particular next event into a task, which one can await or .Wait(), up to you! (though I do suggest await)

    A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

    P 1 Reply Last reply
    0
    • B BillWoodruff

      Why not post this on the C# language forum for discussion ?

      «There is a spectrum, from "clearly desirable behaviour," to "possibly dodgy behavior that still makes some sense," to "clearly undesirable behavior." We try to make the latter into warnings or, better, errors. But stuff that is in the middle category you don’t want to restrict unless there is a clear way to work around it.» Eric Lippert, May 14, 2008

      S Offline
      S Offline
      Super Lloyd
      wrote on last edited by
      #6

      It's not really a question at all... Just some meta.. programatical musing...

      A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

      B 1 Reply Last reply
      0
      • S Super Lloyd

        I don't understand your message Pete, what blocking call are you talking about? My method effectively turn waiting for that particular next event into a task, which one can await or .Wait(), up to you! (though I do suggest await)

        A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

        P Offline
        P Offline
        Pete OHanlon
        wrote on last edited by
        #7

        The blocking call I'm talking about is you waiting for the event. You're waiting for that to happen before you continue. If you are dependent on this, it just feels more natural that this would be a task continuation.

        This space for rent

        S 1 Reply Last reply
        0
        • S Super Lloyd

          Not sure where to post that, (there might some sort of MSDN link somewhere) for now I just post there. "Sometimes" one has to wait for an event to be triggered (once) and then do something, I'd like to write a WaitForEvent() method. Unfortunately, due to the particular of event syntax, I can't and I have to write one wait for *that* event method for every single event I am interested in!... :(( Mmm... case for a code sinppet me just think! :omg: :-\ :rolleyes: In any case here is the syntax for a specific event:

          Task WaitForThatEventAsync(Foo source)
          {
          var res = new TaskCompletionSource<bool>();
          EventHandler eh = null;
          eh = (o, e) =>
          {
          source.ThatEvent -= eh;
          res.TrySetResult(true);
          };
          source.ThatEvent += eh;
          return res.Task;
          }

          EDIT My explanation seem confusing.. another explanation is that I would like to be able to write a "general purpose" WaitForEvent() extension method that transform this cluncky code

          EventHandler ev = null;
          ev = (o, e) => {
          source.Event -= eh;
          DoSomething();
          };
          source.Event += eh;

          into this elegant code

          await source.Event.WaitForEvent()
          DoSomething();

          where both do the exact same thing! Sadly this is not possible right now... I have a to write a new WaitForThatEvent() method for each event I am interested in... :(( but it would be cool. Would make ReactiveC# better looking too.

          A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

          A Offline
          A Offline
          Anurag Gandhi
          wrote on last edited by
          #8

          How is different to subscribing to an Event and do your stuffs in Event Handlers.

          method()
          {
          // some code
          WhatEver.MyEvent += (myArgs) => {
          // Do your stuffs here.
          // You might create a named delegate if you want this event to handled only one time.
          }
          }

          Please help me understand if you are looking for something different which cannot be handled by Events and Delegates (Lambda expressions also simplifies your syntax). I might have different thought process and not able to understand what exactly you are looking for. ;P

          Life is a computer program and everyone is the programmer of his own life.

          S 1 Reply Last reply
          0
          • P Pete OHanlon

            The blocking call I'm talking about is you waiting for the event. You're waiting for that to happen before you continue. If you are dependent on this, it just feels more natural that this would be a task continuation.

            This space for rent

            S Offline
            S Offline
            Super Lloyd
            wrote on last edited by
            #9

            well... this is exactly the same thing, just different syntax (i.e. nice C# syntactic sugar), no?! when I write: await WaitForThatEvent() DoSomethingAfterward() The compiler generate (roughly.. there is cancellation to consider) WaitForThatEvent().ContinueWith(t => DoSomethingAfterward()); Isn't that nice?! :)

            A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

            1 Reply Last reply
            0
            • A Anurag Gandhi

              How is different to subscribing to an Event and do your stuffs in Event Handlers.

              method()
              {
              // some code
              WhatEver.MyEvent += (myArgs) => {
              // Do your stuffs here.
              // You might create a named delegate if you want this event to handled only one time.
              }
              }

              Please help me understand if you are looking for something different which cannot be handled by Events and Delegates (Lambda expressions also simplifies your syntax). I might have different thought process and not able to understand what exactly you are looking for. ;P

              Life is a computer program and everyone is the programmer of his own life.

              S Offline
              S Offline
              Super Lloyd
              wrote on last edited by
              #10

              How is that different? It is better looking! turning that basic version

              EventHandler ev = null;
              ev = (o, e) => {
              source.Event -= eh;
              DoSomething();
              };
              source.Event += eh;

              into that elegant version

              await source.Event.WaitForEvent()
              DoSomething();

              Can't you appreciate the beautiful simplicity and easier code flow of the second version?! :omg: Added bonus: DoSomething() will try to be in the same thread as the start of the method!!

              A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

              A Y 2 Replies Last reply
              0
              • S Super Lloyd

                How is that different? It is better looking! turning that basic version

                EventHandler ev = null;
                ev = (o, e) => {
                source.Event -= eh;
                DoSomething();
                };
                source.Event += eh;

                into that elegant version

                await source.Event.WaitForEvent()
                DoSomething();

                Can't you appreciate the beautiful simplicity and easier code flow of the second version?! :omg: Added bonus: DoSomething() will try to be in the same thread as the start of the method!!

                A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                A Offline
                A Offline
                Anurag Gandhi
                wrote on last edited by
                #11

                Yeah, your elegant version look cool while reading. accepted. But, I personally don't have problem with this too:

                source.Event += (o, e) => {
                source.Event -= eh;
                DoSomething();
                };

                Your elegant version might get complex when you would have to pass the parameters that DoSomething uses.

                oArgType o;
                hArgType h;
                await source.Event.WaitForEvent(out o, out h);
                DoSomething(o, h);

                Also, I feel that the generic implementation of "your elegant version" can be achieved by an extension method. I would try to do that in my free time and would post as a reply here. But nice thought, I appreciate it. :thumbsup:

                Life is a computer program and everyone is the programmer of his own life.

                S 1 Reply Last reply
                0
                • A Anurag Gandhi

                  Yeah, your elegant version look cool while reading. accepted. But, I personally don't have problem with this too:

                  source.Event += (o, e) => {
                  source.Event -= eh;
                  DoSomething();
                  };

                  Your elegant version might get complex when you would have to pass the parameters that DoSomething uses.

                  oArgType o;
                  hArgType h;
                  await source.Event.WaitForEvent(out o, out h);
                  DoSomething(o, h);

                  Also, I feel that the generic implementation of "your elegant version" can be achieved by an extension method. I would try to do that in my free time and would post as a reply here. But nice thought, I appreciate it. :thumbsup:

                  Life is a computer program and everyone is the programmer of his own life.

                  S Offline
                  S Offline
                  Super Lloyd
                  wrote on last edited by
                  #12

                  On the contrary after some practice with async methods you will see how they simplify all your code, not the opposite. Added bonus code after await is in the initial thread, when possible. One downside of async method is that they don't take out/ref parameter. But if you want the event args, here is another version that return the event

                  public static Task WaitForLocationChangedAsync(this IGps gps)
                  {
                  var res = new TaskCompletionSource<GpsLocationArgs>();
                  EventHandler<GpsLocation> eh = null;
                  eh = (o, e) =>
                  {
                  gps.LocationChanged -= eh;
                  res.TrySetResult(e);
                  };
                  gps.LocationChanged += eh;
                  return res.Task;
                  }
                  // ....
                  var loc = await myGps.WaitForLocationChangedAsync();
                  Console.WriteLine($"({loc.Latitude}, {loc.Longitude})");

                  sadly, as I complained, it is NOT possible to write a general purpose WaitForEvent() method.. :(( But give it a go, maybe using some LINQ expression magic and some reflection you can come up with a reasonably easy and elegant version....

                  A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                  1 Reply Last reply
                  0
                  • S Super Lloyd

                    Not sure where to post that, (there might some sort of MSDN link somewhere) for now I just post there. "Sometimes" one has to wait for an event to be triggered (once) and then do something, I'd like to write a WaitForEvent() method. Unfortunately, due to the particular of event syntax, I can't and I have to write one wait for *that* event method for every single event I am interested in!... :(( Mmm... case for a code sinppet me just think! :omg: :-\ :rolleyes: In any case here is the syntax for a specific event:

                    Task WaitForThatEventAsync(Foo source)
                    {
                    var res = new TaskCompletionSource<bool>();
                    EventHandler eh = null;
                    eh = (o, e) =>
                    {
                    source.ThatEvent -= eh;
                    res.TrySetResult(true);
                    };
                    source.ThatEvent += eh;
                    return res.Task;
                    }

                    EDIT My explanation seem confusing.. another explanation is that I would like to be able to write a "general purpose" WaitForEvent() extension method that transform this cluncky code

                    EventHandler ev = null;
                    ev = (o, e) => {
                    source.Event -= eh;
                    DoSomething();
                    };
                    source.Event += eh;

                    into this elegant code

                    await source.Event.WaitForEvent()
                    DoSomething();

                    where both do the exact same thing! Sadly this is not possible right now... I have a to write a new WaitForThatEvent() method for each event I am interested in... :(( but it would be cool. Would make ReactiveC# better looking too.

                    A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                    P Offline
                    P Offline
                    Pete OHanlon
                    wrote on last edited by
                    #13

                    By the way, the more I think about this, you can do what you want rather elegantly, using RX. If you view an event as an Observable, then it would be fairly simple to just observe that event and react to it. When I have a couple of free minutes, I'll write you a general purpose example that shows how to do this (and to wait for pretty much any event).

                    This space for rent

                    B S 2 Replies Last reply
                    0
                    • S Super Lloyd

                      Not sure where to post that, (there might some sort of MSDN link somewhere) for now I just post there. "Sometimes" one has to wait for an event to be triggered (once) and then do something, I'd like to write a WaitForEvent() method. Unfortunately, due to the particular of event syntax, I can't and I have to write one wait for *that* event method for every single event I am interested in!... :(( Mmm... case for a code sinppet me just think! :omg: :-\ :rolleyes: In any case here is the syntax for a specific event:

                      Task WaitForThatEventAsync(Foo source)
                      {
                      var res = new TaskCompletionSource<bool>();
                      EventHandler eh = null;
                      eh = (o, e) =>
                      {
                      source.ThatEvent -= eh;
                      res.TrySetResult(true);
                      };
                      source.ThatEvent += eh;
                      return res.Task;
                      }

                      EDIT My explanation seem confusing.. another explanation is that I would like to be able to write a "general purpose" WaitForEvent() extension method that transform this cluncky code

                      EventHandler ev = null;
                      ev = (o, e) => {
                      source.Event -= eh;
                      DoSomething();
                      };
                      source.Event += eh;

                      into this elegant code

                      await source.Event.WaitForEvent()
                      DoSomething();

                      where both do the exact same thing! Sadly this is not possible right now... I have a to write a new WaitForThatEvent() method for each event I am interested in... :(( but it would be cool. Would make ReactiveC# better looking too.

                      A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                      S Offline
                      S Offline
                      Shuqian Ying
                      wrote on last edited by
                      #14

                      I understand what you mean. We also have been using such a pattern (your less elegent one) for sometimes. The event property of an object is essentially a list of handlers for the event, which is designed before the introduction of async/await syntax for asynchronous programming. So it would be "un-natural" to have a method for it at the time. But yeah, I would also vote for something like that for events to complete the circle (for the introduction of async/await syntax).

                      Find more in 1-NET: connects your resources anywhere[^]. Email searcher Email Aggregation Manager[^].

                      S 1 Reply Last reply
                      0
                      • S Super Lloyd

                        Not sure where to post that, (there might some sort of MSDN link somewhere) for now I just post there. "Sometimes" one has to wait for an event to be triggered (once) and then do something, I'd like to write a WaitForEvent() method. Unfortunately, due to the particular of event syntax, I can't and I have to write one wait for *that* event method for every single event I am interested in!... :(( Mmm... case for a code sinppet me just think! :omg: :-\ :rolleyes: In any case here is the syntax for a specific event:

                        Task WaitForThatEventAsync(Foo source)
                        {
                        var res = new TaskCompletionSource<bool>();
                        EventHandler eh = null;
                        eh = (o, e) =>
                        {
                        source.ThatEvent -= eh;
                        res.TrySetResult(true);
                        };
                        source.ThatEvent += eh;
                        return res.Task;
                        }

                        EDIT My explanation seem confusing.. another explanation is that I would like to be able to write a "general purpose" WaitForEvent() extension method that transform this cluncky code

                        EventHandler ev = null;
                        ev = (o, e) => {
                        source.Event -= eh;
                        DoSomething();
                        };
                        source.Event += eh;

                        into this elegant code

                        await source.Event.WaitForEvent()
                        DoSomething();

                        where both do the exact same thing! Sadly this is not possible right now... I have a to write a new WaitForThatEvent() method for each event I am interested in... :(( but it would be cool. Would make ReactiveC# better looking too.

                        A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                        Y Offline
                        Y Offline
                        Yasen Dokov
                        wrote on last edited by
                        #15

                        I like that syntax! Where is the problem in writing a general purpose method that does this? (First time I'm posting here! Hey everyone! :))

                        1 Reply Last reply
                        0
                        • P Pete OHanlon

                          By the way, the more I think about this, you can do what you want rather elegantly, using RX. If you view an event as an Observable, then it would be fairly simple to just observe that event and react to it. When I have a couple of free minutes, I'll write you a general purpose example that shows how to do this (and to wait for pretty much any event).

                          This space for rent

                          B Offline
                          B Offline
                          BillWoodruff
                          wrote on last edited by
                          #16

                          Your code is eagerly awaited :)

                          «There is a spectrum, from "clearly desirable behaviour," to "possibly dodgy behavior that still makes some sense," to "clearly undesirable behavior." We try to make the latter into warnings or, better, errors. But stuff that is in the middle category you don’t want to restrict unless there is a clear way to work around it.» Eric Lippert, May 14, 2008

                          1 Reply Last reply
                          0
                          • P Pete OHanlon

                            By the way, the more I think about this, you can do what you want rather elegantly, using RX. If you view an event as an Observable, then it would be fairly simple to just observe that event and react to it. When I have a couple of free minutes, I'll write you a general purpose example that shows how to do this (and to wait for pretty much any event).

                            This space for rent

                            S Offline
                            S Offline
                            Super Lloyd
                            wrote on last edited by
                            #17

                            Reactive use a lot of callback as far as I remember... What I am trying is to make the code seemingly linear and callback free, using await.. (handy for try/catch, easier to understand the flow as well) that said.. I would be curious to see what you come back with! :)

                            A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                            1 Reply Last reply
                            0
                            • S Shuqian Ying

                              I understand what you mean. We also have been using such a pattern (your less elegent one) for sometimes. The event property of an object is essentially a list of handlers for the event, which is designed before the introduction of async/await syntax for asynchronous programming. So it would be "un-natural" to have a method for it at the time. But yeah, I would also vote for something like that for events to complete the circle (for the introduction of async/await syntax).

                              Find more in 1-NET: connects your resources anywhere[^]. Email searcher Email Aggregation Manager[^].

                              S Offline
                              S Offline
                              Super Lloyd
                              wrote on last edited by
                              #18

                              Glad someone understand! :)

                              A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                              1 Reply Last reply
                              0
                              • S Super Lloyd

                                It's not really a question at all... Just some meta.. programatical musing...

                                A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                                B Offline
                                B Offline
                                BillWoodruff
                                wrote on last edited by
                                #19

                                If it looks like code, smells like code, and walks like code, I think it's code, and having this kind of discussion here means that in the long run CodeProject will not benefit as much as if the discussion were in the language forum ... because this kind of content gets "drowned" in the flood of Lounge posts. It's an interesting topic, and becoming a compelling conversation. cheers, Bill

                                «There is a spectrum, from "clearly desirable behaviour," to "possibly dodgy behavior that still makes some sense," to "clearly undesirable behavior." We try to make the latter into warnings or, better, errors. But stuff that is in the middle category you don’t want to restrict unless there is a clear way to work around it.» Eric Lippert, May 14, 2008

                                1 Reply Last reply
                                0
                                • S Super Lloyd

                                  How is that different? It is better looking! turning that basic version

                                  EventHandler ev = null;
                                  ev = (o, e) => {
                                  source.Event -= eh;
                                  DoSomething();
                                  };
                                  source.Event += eh;

                                  into that elegant version

                                  await source.Event.WaitForEvent()
                                  DoSomething();

                                  Can't you appreciate the beautiful simplicity and easier code flow of the second version?! :omg: Added bonus: DoSomething() will try to be in the same thread as the start of the method!!

                                  A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                                  Y Offline
                                  Y Offline
                                  Yortw
                                  wrote on last edited by
                                  #20

                                  I believe you're correct in that you can't do this on the event itself, but you could make something nearly as good (depending on your definition of 'nearly as good').

                                  await source.WaitForEvent(nameof(source.Event));

                                  Would be possible. Using nameof in VS2015 means you have any issues with refactoring, though it is a bit uglier than your preferred syntax. Something like the following would implement the method (and returns the EventArgs if you need them). An alternate overload would be needed for non-generic event handler based evevents, but that's not hard.

                                  public static class EventExtensions
                                  {
                                  public static Task WaitForEvent(this object eventSource, string eventName) where T : EventArgs
                                  {
                                  var tcs = new System.Threading.Tasks.TaskCompletionSource();
                                  var eventInfo = eventSource.GetType().GetEvent(eventName);

                                  		EventHandler eventHandler = null;
                                  		eventHandler = new EventHandler(
                                  			(source, e) =>
                                  			{
                                  				eventInfo.RemoveEventHandler(eventSource, eventHandler);
                                  				tcs.TrySetResult(e);
                                  			}
                                  		);
                                  		eventInfo.AddEventHandler(eventSource, eventHandler);
                                  
                                  		return tcs.Task;
                                  	}
                                  }
                                  
                                  S 1 Reply Last reply
                                  0
                                  • Y Yortw

                                    I believe you're correct in that you can't do this on the event itself, but you could make something nearly as good (depending on your definition of 'nearly as good').

                                    await source.WaitForEvent(nameof(source.Event));

                                    Would be possible. Using nameof in VS2015 means you have any issues with refactoring, though it is a bit uglier than your preferred syntax. Something like the following would implement the method (and returns the EventArgs if you need them). An alternate overload would be needed for non-generic event handler based evevents, but that's not hard.

                                    public static class EventExtensions
                                    {
                                    public static Task WaitForEvent(this object eventSource, string eventName) where T : EventArgs
                                    {
                                    var tcs = new System.Threading.Tasks.TaskCompletionSource();
                                    var eventInfo = eventSource.GetType().GetEvent(eventName);

                                    		EventHandler eventHandler = null;
                                    		eventHandler = new EventHandler(
                                    			(source, e) =>
                                    			{
                                    				eventInfo.RemoveEventHandler(eventSource, eventHandler);
                                    				tcs.TrySetResult(e);
                                    			}
                                    		);
                                    		eventInfo.AddEventHandler(eventSource, eventHandler);
                                    
                                    		return tcs.Task;
                                    	}
                                    }
                                    
                                    S Offline
                                    S Offline
                                    Super Lloyd
                                    wrote on last edited by
                                    #21

                                    Man, I can't upvote this enough! Awesome, as good as it get, love it! :-D

                                    A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                                    Y 1 Reply Last reply
                                    0
                                    • S Super Lloyd

                                      Man, I can't upvote this enough! Awesome, as good as it get, love it! :-D

                                      A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                                      Y Offline
                                      Y Offline
                                      Yortw
                                      wrote on last edited by
                                      #22

                                      Always nice to be appreciated :)

                                      1 Reply Last reply
                                      0
                                      • S Super Lloyd

                                        Not sure where to post that, (there might some sort of MSDN link somewhere) for now I just post there. "Sometimes" one has to wait for an event to be triggered (once) and then do something, I'd like to write a WaitForEvent() method. Unfortunately, due to the particular of event syntax, I can't and I have to write one wait for *that* event method for every single event I am interested in!... :(( Mmm... case for a code sinppet me just think! :omg: :-\ :rolleyes: In any case here is the syntax for a specific event:

                                        Task WaitForThatEventAsync(Foo source)
                                        {
                                        var res = new TaskCompletionSource<bool>();
                                        EventHandler eh = null;
                                        eh = (o, e) =>
                                        {
                                        source.ThatEvent -= eh;
                                        res.TrySetResult(true);
                                        };
                                        source.ThatEvent += eh;
                                        return res.Task;
                                        }

                                        EDIT My explanation seem confusing.. another explanation is that I would like to be able to write a "general purpose" WaitForEvent() extension method that transform this cluncky code

                                        EventHandler ev = null;
                                        ev = (o, e) => {
                                        source.Event -= eh;
                                        DoSomething();
                                        };
                                        source.Event += eh;

                                        into this elegant code

                                        await source.Event.WaitForEvent()
                                        DoSomething();

                                        where both do the exact same thing! Sadly this is not possible right now... I have a to write a new WaitForThatEvent() method for each event I am interested in... :(( but it would be cool. Would make ReactiveC# better looking too.

                                        A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                                        U Offline
                                        U Offline
                                        User 10495434
                                        wrote on last edited by
                                        #23

                                        your prince code will come and rescue you someday ;P

                                        S 1 Reply Last reply
                                        0
                                        • U User 10495434

                                          your prince code will come and rescue you someday ;P

                                          S Offline
                                          S Offline
                                          Super Lloyd
                                          wrote on last edited by
                                          #24

                                          It already had!! :omg: :-\ The Lounge[^]

                                          A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                                          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
                                          • World
                                          • Users
                                          • Groups