• Visit Rebornbuddy
  • Default Combat Discussion

    Discussion in 'Combat Routines' started by Ama, Jan 5, 2015.

    1. alltrueist

      alltrueist Active Member

      Joined:
      Dec 10, 2012
      Messages:
      1,424
      Likes Received:
      16
      Trophy Points:
      38
      That line
      Code:
      HealCandidates = new List<TorCharacter>();
      is gone. What I've linked above is literally the entire Targeting.cs file now. I'm back from my outing so I'm going to test this version out in a bit, but I still need everyone's help. The earlier version with no caching worked fine for me, so there's no way for me to tell a difference now.
       
    2. wired203

      wired203 Community Developer

      Joined:
      Jan 22, 2015
      Messages:
      391
      Likes Received:
      1
      Trophy Points:
      18
      So default is based upon Pure so I went to lookup pure.

      https://subversion.assembla.com/svn/pureswtor/trunk/PureSwtor/Managers/HealingManager.cs

      I found out how Pure ran with less hitching than Default. They used a increment to only run it every other run where default runs with every pulse of the bot.

      Code:
              public static int cacheCount = 75;
              public static int maxCacheCount = 2;
      
      
                      return new Action(delegate
                      {
                          //increment shit!
                          cacheCount++;
      
                          if (cacheCount >= maxCacheCount)
                              updateObjects();
      
      
                  //Reset dat count
                  cacheCount = 0;
      
      
      That's from various parts of that routine however you can easily add that to the default combat targeting.cs

      Still trying to wrap my head around how you can have the exact same list, have mobs in that list and still pick heals.
       
    3. alltrueist

      alltrueist Active Member

      Joined:
      Dec 10, 2012
      Messages:
      1,424
      Likes Received:
      16
      Trophy Points:
      38
      Yeah, I hate that part and that's what I'm trying to get rid of. When I used your Logger, I noticed that even with my frequently using the unit.IsFriendly checks the bot would still sometimes read the enemy mob's health percent when healing. We need to totally divorce these two. Beyond that, it will allow us to separate tanks (like I did in my more extreme edit) and focus only on party members (the Default profile goes nuts when another player enters the area).

      Like I said earlier, what got changed in the .884 update totally messed up my extreme edits. I've gone back to the drawing board on them and I'm also trying to see how to salvage the Default targeting file. I'll need to work on it more tomorrow though, it's too late to start anything big tonight.
       
    4. alltrueist

      alltrueist Active Member

      Joined:
      Dec 10, 2012
      Messages:
      1,424
      Likes Received:
      16
      Trophy Points:
      38
      Also can I just say that the original PureRotation for Honorbuddy (and PureSWTOR to a much lesser extent) was the best CR ever written. Holy cow, I still go back to that to look at how they handled certain super complicated situations. Even 4 years later it still holds up. And it all ran so damn smoothly. Buddywing will never be there, but I always want us to move as close as possible.
       
    5. wired203

      wired203 Community Developer

      Joined:
      Jan 22, 2015
      Messages:
      391
      Likes Received:
      1
      Trophy Points:
      18
      I have the start of something, it does target my pet but seemed to miss combat start. I can zip it up if you want needs some polishing but I literally pulled the entire healroutine from Pure that targeting is based on. With all of the Party checks and pet etc. I then added the dps portions but ran out of time last night.
       
    6. alltrueist

      alltrueist Active Member

      Joined:
      Dec 10, 2012
      Messages:
      1,424
      Likes Received:
      16
      Trophy Points:
      38
      Did Pure do different checks for friends and enemies? I may have to dig it up and root through it. It worked so well until it broke.
       
    7. wired203

      wired203 Community Developer

      Joined:
      Jan 22, 2015
      Messages:
      391
      Likes Received:
      1
      Trophy Points:
      18
      Test This

      I get quite a few errors in the log, however it seems to do the trick. Needs more testing and especially group testing.

      edit - Cleaned up folder and added fixed Targeting.cs for DPS aoe.

      Errors in log seem mostly to be loot which isn't handled within default combat.

      View attachment DefaultCombat.zip
       
      Last edited: Mar 13, 2016
    8. wired203

      wired203 Community Developer

      Joined:
      Jan 22, 2015
      Messages:
      391
      Likes Received:
      1
      Trophy Points:
      18
      That incombat check came from using the non move combat bot completely blank profile. When using the one that spoofs questing it was fine and was good in a grind profile.
       
    9. wired203

      wired203 Community Developer

      Joined:
      Jan 22, 2015
      Messages:
      391
      Likes Received:
      1
      Trophy Points:
      18
      I found a bug that I was wondering if I would, the DPS aoe count wasn't working. Moved it into the loop and it fired right off like it should. Fixed file is in the zip file above.


      edit - removed attachment as it was causing confusion.
       

      Attached Files:

      Last edited: Mar 14, 2016
    10. russ1979

      russ1979 Member

      Joined:
      Aug 25, 2011
      Messages:
      357
      Likes Received:
      0
      Trophy Points:
      16
      new healing routines need to be updated. This is with wired's updated Medicine routine

      2016-03-14 16:31:42,095 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\ProximityInteract.cs(76,8) : warning CS0618: 'Buddy.Common.Logging.Write(string)' is obsolete: 'Logging.WriteX is no longer used, declare [private ILog _log = Log.Get();] in your type and use its members instead!'
      2016-03-14 16:31:42,096 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Helpers\Logger.cs(23,4) : warning CS0618: 'Buddy.Common.Logging.Write(System.Windows.Media.Color, string, params object[])' is obsolete: 'Logging.WriteX is no longer used, declare [private ILog _log = Log.Get();] in your type and use its members instead!'
      2016-03-14 16:31:42,096 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(65,71) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTank'
      2016-03-14 16:31:42,097 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(66,61) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTank'
      2016-03-14 16:31:42,097 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(67,64) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTarget'
      2016-03-14 16:31:42,097 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(68,64) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTarget'
      2016-03-14 16:31:42,098 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(69,65) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTarget'
      2016-03-14 16:31:42,098 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(70,61) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTarget'
      2016-03-14 16:31:42,099 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(71,65) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTarget'
      2016-03-14 16:31:42,100 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(65,87) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTank'
      2016-03-14 16:31:42,100 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(65,126) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'injuredfriendCount'
      2016-03-14 16:31:42,101 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(65,155) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTank'
      2016-03-14 16:31:42,102 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(66,77) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTank'
      2016-03-14 16:31:42,102 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(67,82) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTarget'
      2016-03-14 16:31:42,103 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(67,116) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTarget'
      2016-03-14 16:31:42,103 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(68,82) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTarget'
      2016-03-14 16:31:42,103 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(68,158) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTarget'
      2016-03-14 16:31:42,104 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(69,83) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTarget'
      2016-03-14 16:31:42,104 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(70,79) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTarget'
      2016-03-14 16:31:42,105 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(70,112) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTarget'
      2016-03-14 16:31:42,105 [7] ERROR AssemblyLoader`1 - Compiler Error: d:\Star Wars-The Old Republic\Killer\Routines\DefaultCombat\Routines\Advanced\Operative\Medicine.cs(71,83) : error CS0117: 'DefaultCombat.Core.Targeting' does not contain a definition for 'hTarget'
       
    11. alltrueist

      alltrueist Active Member

      Joined:
      Dec 10, 2012
      Messages:
      1,424
      Likes Received:
      16
      Trophy Points:
      38
      That's from an experimental build I was working on that got scrapped. Try using the Default one with wired203's update and targeting update.
       
    12. russ1979

      russ1979 Member

      Joined:
      Aug 25, 2011
      Messages:
      357
      Likes Received:
      0
      Trophy Points:
      16



      im using this posts from Wired which seems to be the latest and greatest within the last 24hrs and the medicine routine he posted on page 88


      It still only heals one single player in the FP and it doesnt switch around
       
    13. alltrueist

      alltrueist Active Member

      Joined:
      Dec 10, 2012
      Messages:
      1,424
      Likes Received:
      16
      Trophy Points:
      38
      I'm telling you that the Medicine.cs file is from an experiment I was doing. The other stuff from wired203 is fine and should work.
       
    14. wired203

      wired203 Community Developer

      Joined:
      Jan 22, 2015
      Messages:
      391
      Likes Received:
      1
      Trophy Points:
      18
      One thing to understand and the reason for a complete copy of DefaultCombat.zip is due to the fact I had to make a lot of changes. I had to modify global.cs, extensions.cs as well as others. I did all of this based off of a clean copy of Default Combat. For this to be tested I would recommend cleaning out your Default Combat folder (if you made custom changes please back them up) and replacing it with this full Default Combat. Now in my testing since I used Pures targeting all the chars I tested were able to use the routines as written. This was the base of Default Combat which is why the rotations worked.

      There was an exception because the bot wouldn't return the discipline correctly on one of my chars and several of Alltrueists which we put in a bug for. Just some remaining classes that haven't been played really or fixed since 4.0(merc bodyguard was mine)

      I don't have a real healer so I changed spec on a char of mine, logged him in with pet and ran default combat. (Note this is pre fix) My character then proceeded to ignore my pet, pick some random person like 50-100ft away and try to heal them non stop.

      After I took several hours sewing Pures targeting rotation in I was able to log that same char, gimped my Companion to 1 ability (taunt), stripped off gear so I would have a fight that needed heals, I then saw the bot now targeted the companion when needed and healed. I used a grind profile to test with. Blank profile requires you to target yourself but I really wanted to test targeting.

      One of my biggest concerns was Pures targeting routine came from a pure heal targeting routine only. Was DPS going to work and would the AOE counts work. So I busted out my farmer and hit his grind profile. I had to then modify slightly the file but it worked after and re-tested healing with companion only.

      Pures targeting had a lot of additional checks in it that didn't make it over to Default Combat and the biggest one was Party checks. So Default when building a list for heals would pull every character around. Pures makes sure they are in your party which should resolve the random selection for healing everywhere. I don't have the character to run flashpoints or ops with as a healer (no gear) and if the script failed I wouldn't be able play manual as I have no clue how to play a healer.

      I spent most of yesterday tracking down errors but found even with a clean base default combat (no modifications) I got those same errors (after beating my head against a wall for hours) I have to check as there was 1 error that showed with the change which went away in my mods but since I was focused on the other error I have to re-investigate that and see if it's occurring or not now.
       
    15. russ1979

      russ1979 Member

      Joined:
      Aug 25, 2011
      Messages:
      357
      Likes Received:
      0
      Trophy Points:
      16
      The Medicine.cs that is released in the defaultcombat routine is wrong as well. I can not even try the MErc Bodyguard routine because BW does not recognize the Spec. So If someone wants to post the correct combat routine with rotation/target /proper core ready to run ill provide some logs. Right now I have to tear through the last 15pages to find out what needs to be changed or updated.
       
    16. alltrueist

      alltrueist Active Member

      Joined:
      Dec 10, 2012
      Messages:
      1,424
      Likes Received:
      16
      Trophy Points:
      38
      I'll fix Sawbones (the Scoundrel mirror to Medicine) tonight or tomorrow and post that here. Then you'll just need to change the names of the spells and buffs/debuffs and you'll be set.
       
    17. wired203

      wired203 Community Developer

      Joined:
      Jan 22, 2015
      Messages:
      391
      Likes Received:
      1
      Trophy Points:
      18
      Merc Bodyguard wont run as I said, put in a bug report for Aevitas because Logger.Write("Discipline: " + BuddyTor.Me.Discipline); returns CanNotBeDetermined. which makes that class untestable. So I changed my Sorc over to heals and tested. I may have an op I can see if it runs at all but my Medicine.cs looks correct which is the one I compressed into a zip.
       
    18. wired203

      wired203 Community Developer

      Joined:
      Jan 22, 2015
      Messages:
      391
      Likes Received:
      1
      Trophy Points:
      18

      Ok so the medicine your referring to is from another person who's name is Cass to test a different rewrite of the targeting engine (Alltrueists) This is my own attempt at fixing it and it is a all inclusive zip file. No adding this or that or this just the zip. No reading 15 pages just the zip.

      Code:
       Spell.Cast("Recuperative Nanotech", onTarget => T.hTank, ret => T.hTank.HealthPercent <= 80 && Targeting.injuredfriendCount(Targeting.hTank, Distance.MeleeAoE) >= 3),
                          Spell.Cast("Kolto Probe", onTarget => T.hTank, ret => T.hTank.BuffCount("Kolto Probe") < 2),
                          Spell.Cast("Kolto Infusion", onTarget => T.hTarget, ret => T.hTarget.HealthPercent <= 80 && !T.hTarget.HasMyBuff("Kolto Infusion") && Me.BuffCount("Tactical Advantage") >= 2 && Me.EnergyPercent >= 60),
                          Spell.Cast("Surgical Probe", onTarget => T.hTarget, ret => T.hTarget.HealthPercent <= 90 && Me.BuffCount("Tactical Advantage") >= 2 && T.hTarget.BuffCount("Kolto Probe") == 2),
                          Spell.Cast("Kolto Injection", onTarget => T.hTarget, ret => T.hTarget.HealthPercent <= 80),
      Those T.hTarget calls were for a custom targeting Alltrueist made, someone converted that for testing. Normal default combat looks like this.

      Code:
      				return new PrioritySelector(
      					Spell.Heal("Surgical Probe", 30),
      					Spell.Heal("Recuperative Nanotech", on => Tank, 80, ret => Targeting.ShouldAoeHeal),
      					Spell.Heal("Kolto Probe", on => Tank, 100,
      						ret => Tank != null && Tank.BuffCount("Kolto Probe") < 2 || Tank.BuffTimeLeft("Kolto Probe") < 6),
      					Spell.Heal("Kolto Infusion", 80,
      						ret => Me.BuffCount("Tactical Advantage") >= 2 && Me.EnergyPercent >= 60 && !HealTarget.HasBuff("Kolto Infusion")),
      					Spell.Heal("Surgical Probe", 80, ret => Me.BuffCount("Tactical Advantage") >= 2),
      					Spell.Heal("Kolto Injection", 80),
      					Spell.Cleanse("Toxin Scan"),
      					Spell.Heal("Kolto Probe", 90,
      
      That is the routine packaged within the Default Combat zip I provided. EVERYTHING is in that 1 zip and you need to replace EVERYTHING in default combat to test. Now buffs may have changed since 4.0 but that is easily editable by anyone especially if they play a healer.
       
    19. alltrueist

      alltrueist Active Member

      Joined:
      Dec 10, 2012
      Messages:
      1,424
      Likes Received:
      16
      Trophy Points:
      38
      This should work for Sawbones, you just need to copy/paste and change the ability names and buff/debuff names (remember that the names are case-sensitive:

      PHP:
      // Copyright (C) 2011-2015 Bossland GmbH
      // See the file LICENSE for the source code's detailed license

      using Buddy.BehaviorTree;
      using DefaultCombat.Core;
      using DefaultCombat.Helpers;

      namespace 
      DefaultCombat.Routines
      {
          public class 
      Sawbones RotationBase
          
      {
              public 
      override string Name
              
      {
                  
      get { return "Scoundrel Sawbones"; }
              }

              public 
      override Composite Buffs
              
      {
                  
      get
                  
      {
                      return new 
      PrioritySelector(
                          
      Spell.Buff("Lucky Shots"),
                          
      Spell.Buff("Stealth"ret => !Rest.KeepResting() && !Rest.NeedRest())
                          );
                  }
              }

              public 
      override Composite Cooldowns
              
      {
                  
      get
                  
      {
                      return new 
      PrioritySelector(
                          
      Spell.Buff("Cool Head"ret => Me.EnergyPercent <= 20),
                          
      Spell.Buff("Pugnacity"ret => Me.EnergyPercent <= 70 && Me.BuffCount("Upper Hand") < 3),
                          
      Spell.Buff("Defense Screen"ret => Me.HealthPercent <= 75),
                          
      Spell.Buff("Dodge"ret => Me.HealthPercent <= 50),
                          
      Spell.Buff("Escape"ret => Me.IsCrowdControlled())
                          );
                  }
              }

              
      //DPS
              
      public override Composite SingleTarget
              
      {
                  
      get
                  
      {
                      return new 
      PrioritySelector(
                          
      Spell.Cast("Distraction"ret => Me.CurrentTarget.IsCasting && Me.CurrentTarget.Distance <= 1f),
                          
      Spell.Cast("Back Blast"ret => Me.IsBehind(Me.CurrentTarget)),
                          
      Spell.Cast("Blaster Whip"),
                          
      Spell.Cast("Vital Shot"ret => !Me.CurrentTarget.HasDebuff("Vital Shot")),
                          
      Spell.Cast("Charged Burst"ret => Me.EnergyPercent >= 70),
                          
      Spell.Cast("Quick Shot"ret => Me.EnergyPercent >= 70),
                          
      Spell.Cast("Flurry of Bolts")
                          );
                  }
              }

              
      //Healing
              
      public override Composite AreaOfEffect
              
      {
                  
      get
                  
      {
                      return new 
      PrioritySelector(
                          
      Spell.HealGround("Kolto Waves"ret => Targeting.ShouldAoeHeal),
                          
      Spell.Heal("Kolto Cloud"on => Tank80ret => Tank != null && Targeting.ShouldAoeHeal),
                          
      Spell.Heal("Emergency Medpac"90ret => emergencyMedpac()),
                          
      Spell.Heal("Slow-release Medpac"on => Tank100ret => Tank != null && tankSlowMedpac()),
                          
      Spell.Heal("Kolto Pack"80ret => Me.BuffCount("Upper Hand") >= && Me.EnergyPercent >= 60 && !HealTarget.HasMyBuff("Kolto Pack")),
                          
      Spell.Heal("Underworld Medicine"80),
                          
      Spell.Cleanse("Triage"),
                          
      Spell.Heal("Slow-release Medpac"90ret => targetSlowMedpac()),
                          
      Spell.Heal("Diagnostic Scan"95)
                          );
                  }
              }

              public static 
      bool tankSlowMedpac()
              {
                  if (
      Targeting.Tank.BuffCount("Slow-release Medpac") < 2)
                      return 
      true;
                  if (
      Targeting.Tank.BuffTimeLeft("Slow-release Medpac") < 3)
                      return 
      true;
                  return 
      false;
              }

              public static 
      bool targetSlowMedpac()
              {
                  if (
      Targeting.HealTarget.BuffCount("Slow-release Medpac") < 2)
                      return 
      true;
                  if (
      Targeting.HealTarget.BuffTimeLeft("Slow-release Medpac") < 3)
                      return 
      true;
                  return 
      false;
              }

              public static 
      bool emergencyMedpac()
              {
                  if (
      Targeting.HealTarget.BuffTimeLeft("Slow-release Medpac") > 6)
                      return 
      false;
                  if (
      Targeting.HealTarget.BuffCount("Slow-release Medpac") < 2)
                      return 
      false;
                  if (
      Me.BuffCount("Upper Hand") < 2)
                      return 
      false;
                  return 
      true;
              }
          }
      }
       
    20. wired203

      wired203 Community Developer

      Joined:
      Jan 22, 2015
      Messages:
      391
      Likes Received:
      1
      Trophy Points:
      18
      Update - Kicking my Op to a healer has shown me that companion isn't being auto selected when no other tank is there, not a biggie. So I selected f12 to set him as a tank and 1 Kolto fired and it fell back to me. I went through the tank selection and found that it was never setting the TankName string even though the script does look for it. So I changed this function.

      Code:
              public static void SetTank()
              {
                  if (Me.CurrentTarget != null && Me.CurrentTarget.IsFriendly)
                  {
                      Tank = Me.CurrentTarget;
                      Logger.Write("Tank set to : " + Tank.Name);
                      TankName = Tank.ToString();
                  }
              }
      
      This allowed the tank to be set static as it should. Attaching a full copy of everything including this change.

      View attachment DefaultCombat.zip
       

    Share This Page