How to add GST to add-ons?
Add-ons are the product or services that you want to Upsell along with your primary tickets. You can easily sell additional items like clothing, accessories, accommodation, meals and more by adding add-on tickets to your event. This feature allows you to add separate GST to your product or services.
Note: If you're selling additional items as a ticket type, standard fees apply.
2. Select the event in which you want to add an Add-on ticket.
Go to the Tickets menu(Left bottom corner).
Click on Assign Add-on button.
Click on create the new add-on in the pop-up.
Fill all the required details(Ticket name like T-shirt, Accommodation, Meals etc).
4. Add separate GST on add-ons tickets.
Enter separate GST rate that applicable of Add-ons (like GST on clothing is 5% and accommodation is 12% ).
5. Manage Townscript & Payment gateways fee(Fourth row in add a new add-on page).
Select "Me" if you want to pay Townscript fee and Select "Buyer" if you want to charge from the buyer.
Select Payment gateway fee in the same way.
GST rates are applied on add-ons. you can check the same on your live event tickets.
Tips: You can assign the add-ons to the tickets from the same page, just click the assign add-ons button on ticket type and select an add-on.


Brunson spoke his lines and signed them, too. At the end, he brought the whole audience to its feet, showing them how to respond in a way Meena would recognize as applause.
The most valuable thing about theater is that it provides a chance to get inside the skins of people who aren't like us. Last Saturday, Children's Theatre unexpectedly brought that concept home in a powerful way.


text:
Posted inFeatures, Homes, News
COVID-19 and the real estate market
After a good start to spring sales, now uncertainty reigns
by Lacey Sikora March 26, 2020 Updated January 27, 2021
The local real estate market is facing uncertain times.
In the past two weeks, a lot has changed in the local landscape. School are closed. Restaurants and bars are closed. Gyms and movie theaters? You guessed it. Closed.
In the name of social distancing, everyone in Chicago and its suburbs is hunkering down and attempting to slow the spread of COVID-19.
On the Homes front, it appears to be more of the same. New Moms has cancelled its April 25 Kitchen Walk. The Frank Lloyd Wright Home and Studio is closed for tours.
Before March 9, the local real estate market was showing decided signs of a robust spring thaw. We caught up with a few local real estate agents to talk about how the spring market could change in light of the virus fears that are sweeping the country.
Change in behaviors
The first weekend of the shutdown, local agents said there was little discernible change to the real estate landscape.
Steve Scheuring of Compass notes that he had six showings on March 15 and more scheduled on March 16. Speaking of one family he is working with who want to move out of their rental, he says, "There are people out there who need to buy."
Linda Rooney, an agent with Oak Park's ReMax in the Village said she was very busy at an open house on Sunday, March 15.
"The first 45 minutes, I thought no one was coming and then I got bombarded," Rooney said.
She notes that she had 10 groups go through the house, and all of them were interested buyers, not curious neighbors.
While the potential buyers didn't let the fear of illness keep them from the open house, Rooney says she did make some changes, including having disinfectant wipes on hand and signing in all of the visitors herself, so that there was no shared pen. She also states that the sellers told her they conducted a hospital-level clean after the open house.
But, that might be Rooney's last open house for a while.
Rooney said ReMax has requested that agents not hold any open houses for the rest of March and plans to reassess at the end of the month.
Michael Nowicki, of Oak Park's Ideal Location Realty, says that he will hold open houses if his sellers request it, but he thinks few clients will request it in the current environment.
"I'm telling people, 'You're pretty much going to have 10 to 15 people walking through your house touching things,'" Nowicki said. "That's not something people want right now."
Nowicki is taking more precautions with his buyer clients as well. He notes that he does make sure clients are healthy and not of an age where exposure to others is a concern. He says he is not concerned about himself, but doesn't want any clients becoming ill.
"You don't want to pass it along to others," he said. "You have to look at this from all of the angles."
Nowicki also notes that rather than requesting that prospective buyers wear booties over their shoes while touring a home, he plans to hand out gloves for each showing. Rooney says she will offer virtual showings for any clients that would like her to preview houses for them.
Erica Cuneen, managing broker for Beyond Properties, emailed a list of new policies for her agents as guidance while dealing with the virus. Chief among them, she cancelled open houses.
She also said social distancing practices should be used when showing houses. Agents will not open doors with bare hands, are keeping their distance from clients while on tours and no longer ride in the car with clients. In addition, her agents can provide video tours and virtual final walkthroughs for clients to avoid the need for interaction.
She also states that some sellers in an abundance of caution have taken their homes off the market and will hold the listing a few weeks or put the house on the private listing market.
Cuneen says this can also be an effort to limit market time, and states people should take the virus into account when considering market time.
"This is definitely going to change the market times," she said. "It shouldn't necessarily be seen as a negative at this time."
Scheuring says he expects that some sellers will want to move their homes to the private listing network to limit how many potential buyers come in the door and make sure they take certain precautions in terms of health.
Spring market changes
Prior to the measures being taken for social distancing, local brokers reported that the spring market in Oak Park and River Forest was strong. Nowicki credited a lot of that to low interest rates.
"For Oak Park, the low rates are a bit of a godsend," he said. "It makes the tax bills less of an issue. I have yet to hear any buyer complain about the taxes this year, which has not been the case for the last two years."
Scheuring said that March may be one of his highest months for sales volume in 20 years, but states that even prior to the virus, the Oak Park and River Forest area was not a seller's market.
"We've been swamped, but it's not that the market is great," he said. "It's that the prices got down to a point where buyers decided to buy, plus the rates have been great."
Scheuring says that sellers have been more motivated to lower prices to get rid of houses they no longer live in, noting that last year's polar vortex caused a lot of maintenance issues for vacant homes on the market.
"When a seller has already left the house, they are motivated to lower the price," Scheuring said. "We were seeing sellers making offers to buyers as they came through the door."
Uncertainty for the future
All of the brokers expect continued uncertainty in the coming weeks or months. Scheuring points out that transfer stamps for transactions need to be purchased in person, something that could be a problem now that Oak Park village government has instituted a shelter-in-place order.
While Forest Park is still open for essential business, Nowicki says that Oak Park had already moved to an appointment-only system for transfer stamps and final water bills.
River Forest's Village Hall is modifying operations and has temporarily suspended transfer inspections, but can get final water readings remotely, so the village can still process transfer stamps.
The village advises that paperwork can be dropped off at village hall via the green mailbox rather than in person, and states that processing paperwork may take longer than usual.
Scheuring predicts that buyers will pull back for a time. Rooney agreed, stating, "We'll just have to see. The uncertainty is really tough, both on the market and on our families."
Nowicki said the greater the uncertainty, the more it will hurt the real estate market.
"There's a direct correlation between the two," Nowicki said. "I do think that if this resolves quickly, there will be a big rush. There will be sellers and buyers who are ready to go. If this goes on five to eight weeks, we'll be looking at some interesting scenarios."
Cuneen thinks that there will be some slow down given the ever-changing news, but says that even when confined to their own homes, potential buyers are still looking at homes online.
"People still have to move for jobs or for school," Cuneen said. "It's still a great time to buy and sell, and we have to try not to panic."

redpajama_set_name: RedPajamaCommonCrawl


Re: Can't KVM migrate between local storage.
> > state and trying to use the same for copying the volume between pools.
> > details for the mentioned volume and snapshot.
> >> looking at the wrong place were I get the error?
> >> > host, to see if they get copied correctly other the NFS too.
> >> > (stack trace) to have a better understanding of the issue.
> >> >> zone with the  only NFS secondary storage.
> >> >> > secondary storage ?
> >> >> >> next. Any help would be appreciated.
Previous by thread: Re: Can't KVM migrate between local storage.
Next by thread: Re: Can't KVM migrate between local storage.


This BPA free reusable bottle is ideal for cold drinks and a great alternative to disposable bottles. This sport bottle makes a great promotional giveaway, so that you can easily promote your logo or message every time you go to the gym. With a capacity of 18 oz. of your favorite beverage, this bottle features a leak-proof cap with loop attachment. This features a large opening to accommodate ice cubes as well. 7" H x 3" D.
" x 13 " x 19 "


Sandra Simpson and Claudia Romaniuk tied for low gross in the Alberni Golf Club ladies' club nine-hole play on Tuesday.
Sandra Simpson and Claudia Romaniuk tied for low gross in the Alberni Golf Club ladies' club nine-hole play on Tuesday. Both were playing in the low handicap group.
Kath Stolth won low net. Romaniuk and Kathy Toms tied for low putts.
For the nine-hole ladies high handicap Pat Dahlquist won low gross, Betty Adair won low net and Lauralee Edgell had the lowest putts.
Marta Williamson had a birdie on No. 17. Pars were had by Mel Mihychuk on No. 11, Nancy Blair with her chip-in on No. 12, Romaniuk No. 13 and 16, Joan Hall No. 13.
For the 18-hole ladies, Marie Randall shot an impressive 84 to win low gross, Shirley Goodman won low net with 68. Carol Bouchard held the challenge pin, Barb Sheare challenged for it and Bouchard won the match. Carol Hastings will challenge Bouchard next time.
Next week will be the "bring a guest" nine- and 18-hole ladies scramble. Bring as many guests as you would like: just let Carol Bouchard know so she can make up the draw at 250-723-0274.
Three Alberni ladies went to a tournament at Glacier Greens golf club in Comox last weekend: Barb Sheare won low net in her handicap division, Carol Bouchard won fourth low net in her division and La Donna Knutson also won a low net prize.
For the nine hole ladies low handicap group, Claudia Romaniuk won low gross and Lee Anne Van Lent won low net.
In high handicap Mary Ann Maddison won low gross, Bea Stuyt won low net.
For the 18-hole ladies, Carol Bouchard and Janice Cross tied for low gross. Carol Hastings won Monthly Medal for her low net.


text:
RUMOR: Giannis Antetokounmpo was recruiting Bogdan Bogdanovic to Bucks
Christopher Denson
While the Milwaukee Bucks were making a huge effort to secure Bogdan Bogdanovic, reigning MVP Giannis Antetokounmpo was also playing his part as lead recruiter to bring the 6-foot-6 talent to Milwaukee as well.
According to Sam Amick and Eric Nehm of The Athletic, Antetokounmpo continued to pursue Bogdanovic and sell him on the idea of playing in Milwaukee prior to the league opening an investigation into the trade.
Via The Athletic:
From there, don't be surprised if Bogdanovic draws interest from many of the same teams who would love nothing more than for all of this chaos to convince two-time MVP Giannis Antetokounmpo to eventually head their way (Miami, Dallas, the Clippers, the Knicks). Why? Because it's widely known that Antetokounmpo — who will be offered a supermax extension by the Bucks on Friday and has until Dec. 21 to sign it — has been recruiting Bogdanovic to come to Milwaukee. That reality, of course, means he has an added bit of value beyond his basketball talents.
At the moment, the Bucks are in the driver seat of a car with no steering wheel. Not being able to land a player that evidently interested Antetokounmpo certainly doesn't sit well with him or his desire to remain long term in Milwaukee. The franchise hasn't been known to land big-name free agents, with most of their stars coming via trades or drafts.
Antetokounmpo likely realizes that now, and it could deeply affect his decision going into Friday if he decides to pick up the supermax extension the Bucks will offer him.
JUST IN: REPORT: Lakers, Hawks among known Bogdan Bogdanovic suitors
Related TopicsBogdan BogdanovićBucksGiannis Antetokounmpo


text:
Home/World News/Middle East/Iraq/ISIL-held Iraqi city on verge of humanitarian crisis
ISIL-held Iraqi city on verge of humanitarian crisis
The city of Khan al-Baghdadi in Iraq's violence-scarred western province of al-Anbar is on the verge of a "humanitarian catastrophe," where some 50,000 residents remain blockaded by the ISIL Takfiri militants, Press TV reports.
Commander of the Baghdadi Emergency Forces, Colonel Sha'ban al-Obeidi, said on Saturday that a siege by ISIL members, which has been in place since June last year, has seen arms, food, and medicine supplies cut off in the city, situated about 180 kilometers (110 miles) northwest of the capital, Baghdad, raising fears that a humanitarian catastrophe would occur anytime soon.
The area is also suffering from water shortage as the ISIL snipers have prevented water department employees from entering the region to fix a water project.
Obeidi added that locals have managed to resist and repel the ISIL attacks despite the extremely tight blockade.
On December 24, ISIL militants attacked Khan al-Baghdadi with mortar shells loaded with chlorine gas.
The Takfiri ISIL militants killed at least 300 Iraqi soldiers in a chlorine gas attack on an army battalion in al-Anbar Province in September.
The ISIL militants also used the chemical gas against Iraqi soldiers in Saqlawiya district of the northern town of Fallujah.
The ISIL terrorists control some parts of Syria and Iraq. They are engaged in crimes against humanity in the areas under their control. ISIL militants have terrorized and killed people of all communities, including Shias, Sunnis, Kurds, and Christians.
Egyptian Envoy Calls for Further Expansion of Ties with Iran
Top cleric hails role of Imam Khomeini in guiding Iranians
Design: The Holy March in Karbala will İnshAllah open the doors of the Holy City Quds!
VIDEO: Imam Khomeini (r.aleyh) should have seen 20 million people marching in Karbala 40 years ago!


Year round fantastic walleye fishing right out your front door on beautiful Red Lake. 100' of hard sand bottom frontage and just east of Roger's Resort (boat landing, food & beverages). Lot includes a 2001 Timberland 27' travel trailer that sleeps 6 people. Located close to acres & acres of public hunting land. This property is a sportsman's paradise!


Rumors have it that one of stipulations being considered for the Brock Lesnar vs. Triple H is Hell in Cell. If this is true, Triple H will have the advantage because he has wrestled in five of these matches. Brock has only wrestled in one, but he is a fighter now not a wrestler so that is also an advantage. In the end, I predict Triple H's ego goes over at WrestleMania 29. I can't see him loss three straight years at the Grandest Stage of them All.


Note Nxxxx0081xxx has been entered 2 times. This is a 5 Euro note from 2013. The printer code is Nxxxxx.
zimmerge 2013-08-04 19:19:22 Wien 1220 31.07.2013 - BA - Donauplatte - AT-Banderole 221326 2 ES2 5 41 01 OBS 160712 - brandnew - "europa-note"


This is a comprehensive lease for letting a pub or licensed restaurant with a flat or maisonette above for the tenant to live. The premises may be detached or connected. Features are: service charge provision; guarantor; break provision; rent review options; option for assignment; sub-letting not allowed; draft agreement for security deposit.
This lease is for a pub or restaurant with a flat over. The premises may be in an urban shop frontage, a stand-alone site or away in the country.
The lease is drawn for maximum protection of landlord's interests. It is very thorough with many simple options where choices are possible.
Where relevant, the lease includes matters relating to licences and the Liquor Act 2003.


text:
#include <grpc/support/port_platform.h>

#include "src/core/ext/filters/client_channel/client_channel.h"

#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>

#include "src/core/ext/filters/client_channel/backup_poller.h"
#include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
#include "src/core/ext/filters/client_channel/resolver_registry.h"
#include "src/core/ext/filters/client_channel/retry_throttle.h"
#include "src/core/ext/filters/client_channel/subchannel.h"
#include "src/core/ext/filters/deadline/deadline_filter.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/connected_channel.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/service_config.h"
#include "src/core/lib/transport/static_metadata.h"

/* Client channel implementation */

grpc_tracer_flag grpc_client_channel_trace =
    GRPC_TRACER_INITIALIZER(false, "client_channel");

/*************************************************************************
 * METHOD-CONFIG TABLE
 */

typedef enum {
  /* zero so it can be default initialized */
  WAIT_FOR_READY_UNSET = 0,
  WAIT_FOR_READY_FALSE,
  WAIT_FOR_READY_TRUE
} wait_for_ready_value;

typedef struct {
  gpr_refcount refs;
  grpc_millis timeout;
  wait_for_ready_value wait_for_ready;
} method_parameters;

static method_parameters* method_parameters_ref(
    method_parameters* method_params) {
  gpr_ref(&method_params->refs);
  return method_params;
}

static void method_parameters_unref(method_parameters* method_params) {
  if (gpr_unref(&method_params->refs)) {
    gpr_free(method_params);
  }
}

// Wrappers to pass to grpc_service_config_create_method_config_table().
static void* method_parameters_ref_wrapper(void* value) {
  return method_parameters_ref((method_parameters*)value);
}
static void method_parameters_unref_wrapper(grpc_exec_ctx* exec_ctx,
                                            void* value) {
  method_parameters_unref((method_parameters*)value);
}

static bool parse_wait_for_ready(grpc_json* field,
                                 wait_for_ready_value* wait_for_ready) {
  if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) {
    return false;
  }
  *wait_for_ready = field->type == GRPC_JSON_TRUE ? WAIT_FOR_READY_TRUE
                                                  : WAIT_FOR_READY_FALSE;
  return true;
}

static bool parse_timeout(grpc_json* field, grpc_millis* timeout) {
  if (field->type != GRPC_JSON_STRING) return false;
  size_t len = strlen(field->value);
  if (field->value[len - 1] != 's') return false;
  char* buf = gpr_strdup(field->value);
  buf[len - 1] = '\0';  // Remove trailing 's'.
  char* decimal_point = strchr(buf, '.');
  int nanos = 0;
  if (decimal_point != nullptr) {
    *decimal_point = '\0';
    nanos = gpr_parse_nonnegative_int(decimal_point + 1);
    if (nanos == -1) {
      gpr_free(buf);
      return false;
    }
    int num_digits = (int)strlen(decimal_point + 1);
    if (num_digits > 9) {  // We don't accept greater precision than nanos.
      gpr_free(buf);
      return false;
    }
    for (int i = 0; i < (9 - num_digits); ++i) {
      nanos *= 10;
    }
  }
  int seconds = decimal_point == buf ? 0 : gpr_parse_nonnegative_int(buf);
  gpr_free(buf);
  if (seconds == -1) return false;
  *timeout = seconds * GPR_MS_PER_SEC + nanos / GPR_NS_PER_MS;
  return true;
}

static void* method_parameters_create_from_json(const grpc_json* json) {
  wait_for_ready_value wait_for_ready = WAIT_FOR_READY_UNSET;
  grpc_millis timeout = 0;
  for (grpc_json* field = json->child; field != nullptr; field = field->next) {
    if (field->key == nullptr) continue;
    if (strcmp(field->key, "waitForReady") == 0) {
      if (wait_for_ready != WAIT_FOR_READY_UNSET) return nullptr;  // Duplicate.
      if (!parse_wait_for_ready(field, &wait_for_ready)) return nullptr;
    } else if (strcmp(field->key, "timeout") == 0) {
      if (timeout > 0) return nullptr;  // Duplicate.
      if (!parse_timeout(field, &timeout)) return nullptr;
    }
  }
  method_parameters* value =
      (method_parameters*)gpr_malloc(sizeof(method_parameters));
  gpr_ref_init(&value->refs, 1);
  value->timeout = timeout;
  value->wait_for_ready = wait_for_ready;
  return value;
}

struct external_connectivity_watcher;

/*************************************************************************
 * CHANNEL-WIDE FUNCTIONS
 */

typedef struct client_channel_channel_data {
  /** resolver for this channel */
  grpc_resolver* resolver;
  /** have we started resolving this channel */
  bool started_resolving;
  /** is deadline checking enabled? */
  bool deadline_checking_enabled;
  /** client channel factory */
  grpc_client_channel_factory* client_channel_factory;

  /** combiner protecting all variables below in this data structure */
  grpc_combiner* combiner;
  /** currently active load balancer */
  grpc_lb_policy* lb_policy;
  /** retry throttle data */
  grpc_server_retry_throttle_data* retry_throttle_data;
  /** maps method names to method_parameters structs */
  grpc_slice_hash_table* method_params_table;
  /** incoming resolver result - set by resolver.next() */
  grpc_channel_args* resolver_result;
  /** a list of closures that are all waiting for resolver result to come in */
  grpc_closure_list waiting_for_resolver_result_closures;
  /** resolver callback */
  grpc_closure on_resolver_result_changed;
  /** connectivity state being tracked */
  grpc_connectivity_state_tracker state_tracker;
  /** when an lb_policy arrives, should we try to exit idle */
  bool exit_idle_when_lb_policy_arrives;
  /** owning stack */
  grpc_channel_stack* owning_stack;
  /** interested parties (owned) */
  grpc_pollset_set* interested_parties;

  /* external_connectivity_watcher_list head is guarded by its own mutex, since
   * counts need to be grabbed immediately without polling on a cq */
  gpr_mu external_connectivity_watcher_list_mu;
  struct external_connectivity_watcher* external_connectivity_watcher_list_head;

  /* the following properties are guarded by a mutex since API's require them
     to be instantaneously available */
  gpr_mu info_mu;
  char* info_lb_policy_name;
  /** service config in JSON form */
  char* info_service_config_json;
} channel_data;

/** We create one watcher for each new lb_policy that is returned from a
    resolver, to watch for state changes from the lb_policy. When a state
    change is seen, we update the channel, and create a new watcher. */
typedef struct {
  channel_data* chand;
  grpc_closure on_changed;
  grpc_connectivity_state state;
  grpc_lb_policy* lb_policy;
} lb_policy_connectivity_watcher;

static void watch_lb_policy_locked(grpc_exec_ctx* exec_ctx, channel_data* chand,
                                   grpc_lb_policy* lb_policy,
                                   grpc_connectivity_state current_state);

static void set_channel_connectivity_state_locked(grpc_exec_ctx* exec_ctx,
                                                  channel_data* chand,
                                                  grpc_connectivity_state state,
                                                  grpc_error* error,
                                                  const char* reason) {
  /* TODO: Improve failure handling:
   * - Make it possible for policies to return GRPC_CHANNEL_TRANSIENT_FAILURE.
   * - Hand over pending picks from old policies during the switch that happens
   *   when resolver provides an update. */
  if (chand->lb_policy != nullptr) {
    if (state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
      /* cancel picks with wait_for_ready=false */
      grpc_lb_policy_cancel_picks_locked(
          exec_ctx, chand->lb_policy,
          /* mask= */ GRPC_INITIAL_METADATA_WAIT_FOR_READY,
          /* check= */ 0, GRPC_ERROR_REF(error));
    } else if (state == GRPC_CHANNEL_SHUTDOWN) {
      /* cancel all picks */
      grpc_lb_policy_cancel_picks_locked(exec_ctx, chand->lb_policy,
                                         /* mask= */ 0, /* check= */ 0,
                                         GRPC_ERROR_REF(error));
    }
  }
  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
    gpr_log(GPR_DEBUG, "chand=%p: setting connectivity state to %s", chand,
            grpc_connectivity_state_name(state));
  }
  grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state, error,
                              reason);
}

static void on_lb_policy_state_changed_locked(grpc_exec_ctx* exec_ctx,
                                              void* arg, grpc_error* error) {
  lb_policy_connectivity_watcher* w = (lb_policy_connectivity_watcher*)arg;
  grpc_connectivity_state publish_state = w->state;
  /* check if the notification is for the latest policy */
  if (w->lb_policy == w->chand->lb_policy) {
    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
      gpr_log(GPR_DEBUG, "chand=%p: lb_policy=%p state changed to %s", w->chand,
              w->lb_policy, grpc_connectivity_state_name(w->state));
    }
    if (publish_state == GRPC_CHANNEL_SHUTDOWN &&
        w->chand->resolver != nullptr) {
      publish_state = GRPC_CHANNEL_TRANSIENT_FAILURE;
      grpc_resolver_channel_saw_error_locked(exec_ctx, w->chand->resolver);
      GRPC_LB_POLICY_UNREF(exec_ctx, w->chand->lb_policy, "channel");
      w->chand->lb_policy = nullptr;
    }
    set_channel_connectivity_state_locked(exec_ctx, w->chand, publish_state,
                                          GRPC_ERROR_REF(error), "lb_changed");
    if (w->state != GRPC_CHANNEL_SHUTDOWN) {
      watch_lb_policy_locked(exec_ctx, w->chand, w->lb_policy, w->state);
    }
  }
  GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "watch_lb_policy");
  gpr_free(w);
}

static void watch_lb_policy_locked(grpc_exec_ctx* exec_ctx, channel_data* chand,
                                   grpc_lb_policy* lb_policy,
                                   grpc_connectivity_state current_state) {
  lb_policy_connectivity_watcher* w =
      (lb_policy_connectivity_watcher*)gpr_malloc(sizeof(*w));
  GRPC_CHANNEL_STACK_REF(chand->owning_stack, "watch_lb_policy");
  w->chand = chand;
  GRPC_CLOSURE_INIT(&w->on_changed, on_lb_policy_state_changed_locked, w,
                    grpc_combiner_scheduler(chand->combiner));
  w->state = current_state;
  w->lb_policy = lb_policy;
  grpc_lb_policy_notify_on_state_change_locked(exec_ctx, lb_policy, &w->state,
                                               &w->on_changed);
}

static void start_resolving_locked(grpc_exec_ctx* exec_ctx,
                                   channel_data* chand) {
  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
    gpr_log(GPR_DEBUG, "chand=%p: starting name resolution", chand);
  }
  GPR_ASSERT(!chand->started_resolving);
  chand->started_resolving = true;
  GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
  grpc_resolver_next_locked(exec_ctx, chand->resolver, &chand->resolver_result,
                            &chand->on_resolver_result_changed);
}

typedef struct {
  char* server_name;
  grpc_server_retry_throttle_data* retry_throttle_data;
} service_config_parsing_state;

static void parse_retry_throttle_params(const grpc_json* field, void* arg) {
  service_config_parsing_state* parsing_state =
      (service_config_parsing_state*)arg;
  if (strcmp(field->key, "retryThrottling") == 0) {
    if (parsing_state->retry_throttle_data != nullptr) return;  // Duplicate.
    if (field->type != GRPC_JSON_OBJECT) return;
    int max_milli_tokens = 0;
    int milli_token_ratio = 0;
    for (grpc_json* sub_field = field->child; sub_field != nullptr;
         sub_field = sub_field->next) {
      if (sub_field->key == nullptr) return;
      if (strcmp(sub_field->key, "maxTokens") == 0) {
        if (max_milli_tokens != 0) return;  // Duplicate.
        if (sub_field->type != GRPC_JSON_NUMBER) return;
        max_milli_tokens = gpr_parse_nonnegative_int(sub_field->value);
        if (max_milli_tokens == -1) return;
        max_milli_tokens *= 1000;
      } else if (strcmp(sub_field->key, "tokenRatio") == 0) {
        if (milli_token_ratio != 0) return;  // Duplicate.
        if (sub_field->type != GRPC_JSON_NUMBER) return;
        // We support up to 3 decimal digits.
        size_t whole_len = strlen(sub_field->value);
        uint32_t multiplier = 1;
        uint32_t decimal_value = 0;
        const char* decimal_point = strchr(sub_field->value, '.');
        if (decimal_point != nullptr) {
          whole_len = (size_t)(decimal_point - sub_field->value);
          multiplier = 1000;
          size_t decimal_len = strlen(decimal_point + 1);
          if (decimal_len > 3) decimal_len = 3;
          if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len,
                                         &decimal_value)) {
            return;
          }
          uint32_t decimal_multiplier = 1;
          for (size_t i = 0; i < (3 - decimal_len); ++i) {
            decimal_multiplier *= 10;
          }
          decimal_value *= decimal_multiplier;
        }
        uint32_t whole_value;
        if (!gpr_parse_bytes_to_uint32(sub_field->value, whole_len,
                                       &whole_value)) {
          return;
        }
        milli_token_ratio = (int)((whole_value * multiplier) + decimal_value);
        if (milli_token_ratio <= 0) return;
      }
    }
    parsing_state->retry_throttle_data =
        grpc_retry_throttle_map_get_data_for_server(
            parsing_state->server_name, max_milli_tokens, milli_token_ratio);
  }
}

static void on_resolver_result_changed_locked(grpc_exec_ctx* exec_ctx,
                                              void* arg, grpc_error* error) {
  channel_data* chand = (channel_data*)arg;
  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
    gpr_log(GPR_DEBUG, "chand=%p: got resolver result: error=%s", chand,
            grpc_error_string(error));
  }
  // Extract the following fields from the resolver result, if non-NULL.
  bool lb_policy_updated = false;
  char* lb_policy_name_dup = nullptr;
  bool lb_policy_name_changed = false;
  grpc_lb_policy* new_lb_policy = nullptr;
  char* service_config_json = nullptr;
  grpc_server_retry_throttle_data* retry_throttle_data = nullptr;
  grpc_slice_hash_table* method_params_table = nullptr;
  if (chand->resolver_result != nullptr) {
    // Find LB policy name.
    const char* lb_policy_name = nullptr;
    const grpc_arg* channel_arg =
        grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_POLICY_NAME);
    if (channel_arg != nullptr) {
      GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
      lb_policy_name = channel_arg->value.string;
    }
    // Special case: If at least one balancer address is present, we use
    // the grpclb policy, regardless of what the resolver actually specified.
    channel_arg =
        grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES);
    if (channel_arg != nullptr && channel_arg->type == GRPC_ARG_POINTER) {
      grpc_lb_addresses* addresses =
          (grpc_lb_addresses*)channel_arg->value.pointer.p;
      bool found_balancer_address = false;
      for (size_t i = 0; i < addresses->num_addresses; ++i) {
        if (addresses->addresses[i].is_balancer) {
          found_balancer_address = true;
          break;
        }
      }
      if (found_balancer_address) {
        if (lb_policy_name != nullptr &&
            strcmp(lb_policy_name, "grpclb") != 0) {
          gpr_log(GPR_INFO,
                  "resolver requested LB policy %s but provided at least one "
                  "balancer address -- forcing use of grpclb LB policy",
                  lb_policy_name);
        }
        lb_policy_name = "grpclb";
      }
    }
    // Use pick_first if nothing was specified and we didn't select grpclb
    // above.
    if (lb_policy_name == nullptr) lb_policy_name = "pick_first";
    grpc_lb_policy_args lb_policy_args;
    lb_policy_args.args = chand->resolver_result;
    lb_policy_args.client_channel_factory = chand->client_channel_factory;
    lb_policy_args.combiner = chand->combiner;
    // Check to see if we're already using the right LB policy.
    // Note: It's safe to use chand->info_lb_policy_name here without
    // taking a lock on chand->info_mu, because this function is the
    // only thing that modifies its value, and it can only be invoked
    // once at any given time.
    lb_policy_name_changed =
        chand->info_lb_policy_name == nullptr ||
        strcmp(chand->info_lb_policy_name, lb_policy_name) != 0;
    if (chand->lb_policy != nullptr && !lb_policy_name_changed) {
      // Continue using the same LB policy.  Update with new addresses.
      lb_policy_updated = true;
      grpc_lb_policy_update_locked(exec_ctx, chand->lb_policy, &lb_policy_args);
    } else {
      // Instantiate new LB policy.
      new_lb_policy =
          grpc_lb_policy_create(exec_ctx, lb_policy_name, &lb_policy_args);
      if (new_lb_policy == nullptr) {
        gpr_log(GPR_ERROR, "could not create LB policy \"%s\"", lb_policy_name);
      }
    }
    // Find service config.
    channel_arg =
        grpc_channel_args_find(chand->resolver_result, GRPC_ARG_SERVICE_CONFIG);
    if (channel_arg != nullptr) {
      GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
      service_config_json = gpr_strdup(channel_arg->value.string);
      grpc_service_config* service_config =
          grpc_service_config_create(service_config_json);
      if (service_config != nullptr) {
        channel_arg =
            grpc_channel_args_find(chand->resolver_result, GRPC_ARG_SERVER_URI);
        GPR_ASSERT(channel_arg != nullptr);
        GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
        grpc_uri* uri =
            grpc_uri_parse(exec_ctx, channel_arg->value.string, true);
        GPR_ASSERT(uri->path[0] != '\0');
        service_config_parsing_state parsing_state;
        memset(&parsing_state, 0, sizeof(parsing_state));
        parsing_state.server_name =
            uri->path[0] == '/' ? uri->path + 1 : uri->path;
        grpc_service_config_parse_global_params(
            service_config, parse_retry_throttle_params, &parsing_state);
        grpc_uri_destroy(uri);
        retry_throttle_data = parsing_state.retry_throttle_data;
        method_params_table = grpc_service_config_create_method_config_table(
            exec_ctx, service_config, method_parameters_create_from_json,
            method_parameters_ref_wrapper, method_parameters_unref_wrapper);
        grpc_service_config_destroy(service_config);
      }
    }
    // Before we clean up, save a copy of lb_policy_name, since it might
    // be pointing to data inside chand->resolver_result.
    // The copy will be saved in chand->lb_policy_name below.
    lb_policy_name_dup = gpr_strdup(lb_policy_name);
    grpc_channel_args_destroy(exec_ctx, chand->resolver_result);
    chand->resolver_result = nullptr;
  }
  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
    gpr_log(GPR_DEBUG,
            "chand=%p: resolver result: lb_policy_name=\"%s\"%s, "
            "service_config=\"%s\"",
            chand, lb_policy_name_dup,
            lb_policy_name_changed ? " (changed)" : "", service_config_json);
  }
  // Now swap out fields in chand.  Note that the new values may still
  // be NULL if (e.g.) the resolver failed to return results or the
  // results did not contain the necessary data.
  //
  // First, swap out the data used by cc_get_channel_info().
  gpr_mu_lock(&chand->info_mu);
  if (lb_policy_name_dup != nullptr) {
    gpr_free(chand->info_lb_policy_name);
    chand->info_lb_policy_name = lb_policy_name_dup;
  }
  if (service_config_json != nullptr) {
    gpr_free(chand->info_service_config_json);
    chand->info_service_config_json = service_config_json;
  }
  gpr_mu_unlock(&chand->info_mu);
  // Swap out the retry throttle data.
  if (chand->retry_throttle_data != nullptr) {
    grpc_server_retry_throttle_data_unref(chand->retry_throttle_data);
  }
  chand->retry_throttle_data = retry_throttle_data;
  // Swap out the method params table.
  if (chand->method_params_table != nullptr) {
    grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table);
  }
  chand->method_params_table = method_params_table;
  // If we have a new LB policy or are shutting down (in which case
  // new_lb_policy will be NULL), swap out the LB policy, unreffing the
  // old one and removing its fds from chand->interested_parties.
  // Note that we do NOT do this if either (a) we updated the existing
  // LB policy above or (b) we failed to create the new LB policy (in
  // which case we want to continue using the most recent one we had).
  if (new_lb_policy != nullptr || error != GRPC_ERROR_NONE ||
      chand->resolver == nullptr) {
    if (chand->lb_policy != nullptr) {
      if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
        gpr_log(GPR_DEBUG, "chand=%p: unreffing lb_policy=%p", chand,
                chand->lb_policy);
      }
      grpc_pollset_set_del_pollset_set(exec_ctx,
                                       chand->lb_policy->interested_parties,
                                       chand->interested_parties);
      GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
    }
    chand->lb_policy = new_lb_policy;
  }
  // Now that we've swapped out the relevant fields of chand, check for
  // error or shutdown.
  if (error != GRPC_ERROR_NONE || chand->resolver == nullptr) {
    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
      gpr_log(GPR_DEBUG, "chand=%p: shutting down", chand);
    }
    if (chand->resolver != nullptr) {
      if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
        gpr_log(GPR_DEBUG, "chand=%p: shutting down resolver", chand);
      }
      grpc_resolver_shutdown_locked(exec_ctx, chand->resolver);
      GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
      chand->resolver = nullptr;
    }
    set_channel_connectivity_state_locked(
        exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN,
        GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
            "Got resolver result after disconnection", &error, 1),
        "resolver_gone");
    GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver");
    grpc_closure_list_fail_all(&chand->waiting_for_resolver_result_closures,
                               GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                                   "Channel disconnected", &error, 1));
    GRPC_CLOSURE_LIST_SCHED(exec_ctx,
                            &chand->waiting_for_resolver_result_closures);
  } else {  // Not shutting down.
    grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
    grpc_error* state_error =
        GRPC_ERROR_CREATE_FROM_STATIC_STRING("No load balancing policy");
    if (new_lb_policy != nullptr) {
      if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
        gpr_log(GPR_DEBUG, "chand=%p: initializing new LB policy", chand);
      }
      GRPC_ERROR_UNREF(state_error);
      state = grpc_lb_policy_check_connectivity_locked(exec_ctx, new_lb_policy,
                                                       &state_error);
      grpc_pollset_set_add_pollset_set(exec_ctx,
                                       new_lb_policy->interested_parties,
                                       chand->interested_parties);
      GRPC_CLOSURE_LIST_SCHED(exec_ctx,
                              &chand->waiting_for_resolver_result_closures);
      if (chand->exit_idle_when_lb_policy_arrives) {
        grpc_lb_policy_exit_idle_locked(exec_ctx, new_lb_policy);
        chand->exit_idle_when_lb_policy_arrives = false;
      }
      watch_lb_policy_locked(exec_ctx, chand, new_lb_policy, state);
    }
    if (!lb_policy_updated) {
      set_channel_connectivity_state_locked(exec_ctx, chand, state,
                                            GRPC_ERROR_REF(state_error),
                                            "new_lb+resolver");
    }
    grpc_resolver_next_locked(exec_ctx, chand->resolver,
                              &chand->resolver_result,
                              &chand->on_resolver_result_changed);
    GRPC_ERROR_UNREF(state_error);
  }
}

static void start_transport_op_locked(grpc_exec_ctx* exec_ctx, void* arg,
                                      grpc_error* error_ignored) {
  grpc_transport_op* op = (grpc_transport_op*)arg;
  grpc_channel_element* elem =
      (grpc_channel_element*)op->handler_private.extra_arg;
  channel_data* chand = (channel_data*)elem->channel_data;

  if (op->on_connectivity_state_change != nullptr) {
    grpc_connectivity_state_notify_on_state_change(
        exec_ctx, &chand->state_tracker, op->connectivity_state,
        op->on_connectivity_state_change);
    op->on_connectivity_state_change = nullptr;
    op->connectivity_state = nullptr;
  }

  if (op->send_ping != nullptr) {
    if (chand->lb_policy == nullptr) {
      GRPC_CLOSURE_SCHED(
          exec_ctx, op->send_ping,
          GRPC_ERROR_CREATE_FROM_STATIC_STRING("Ping with no load balancing"));
    } else {
      grpc_lb_policy_ping_one_locked(exec_ctx, chand->lb_policy, op->send_ping);
      op->bind_pollset = nullptr;
    }
    op->send_ping = nullptr;
  }

  if (op->disconnect_with_error != GRPC_ERROR_NONE) {
    if (chand->resolver != nullptr) {
      set_channel_connectivity_state_locked(
          exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN,
          GRPC_ERROR_REF(op->disconnect_with_error), "disconnect");
      grpc_resolver_shutdown_locked(exec_ctx, chand->resolver);
      GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
      chand->resolver = nullptr;
      if (!chand->started_resolving) {
        grpc_closure_list_fail_all(&chand->waiting_for_resolver_result_closures,
                                   GRPC_ERROR_REF(op->disconnect_with_error));
        GRPC_CLOSURE_LIST_SCHED(exec_ctx,
                                &chand->waiting_for_resolver_result_closures);
      }
      if (chand->lb_policy != nullptr) {
        grpc_pollset_set_del_pollset_set(exec_ctx,
                                         chand->lb_policy->interested_parties,
                                         chand->interested_parties);
        GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
        chand->lb_policy = nullptr;
      }
    }
    GRPC_ERROR_UNREF(op->disconnect_with_error);
  }
  GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "start_transport_op");

  GRPC_CLOSURE_SCHED(exec_ctx, op->on_consumed, GRPC_ERROR_NONE);
}

static void cc_start_transport_op(grpc_exec_ctx* exec_ctx,
                                  grpc_channel_element* elem,
                                  grpc_transport_op* op) {
  channel_data* chand = (channel_data*)elem->channel_data;

  GPR_ASSERT(op->set_accept_stream == false);
  if (op->bind_pollset != nullptr) {
    grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties,
                                 op->bind_pollset);
  }

  op->handler_private.extra_arg = elem;
  GRPC_CHANNEL_STACK_REF(chand->owning_stack, "start_transport_op");
  GRPC_CLOSURE_SCHED(
      exec_ctx,
      GRPC_CLOSURE_INIT(&op->handler_private.closure, start_transport_op_locked,
                        op, grpc_combiner_scheduler(chand->combiner)),
      GRPC_ERROR_NONE);
}

static void cc_get_channel_info(grpc_exec_ctx* exec_ctx,
                                grpc_channel_element* elem,
                                const grpc_channel_info* info) {
  channel_data* chand = (channel_data*)elem->channel_data;
  gpr_mu_lock(&chand->info_mu);
  if (info->lb_policy_name != nullptr) {
    *info->lb_policy_name = chand->info_lb_policy_name == nullptr
                                ? nullptr
                                : gpr_strdup(chand->info_lb_policy_name);
  }
  if (info->service_config_json != nullptr) {
    *info->service_config_json =
        chand->info_service_config_json == nullptr
            ? nullptr
            : gpr_strdup(chand->info_service_config_json);
  }
  gpr_mu_unlock(&chand->info_mu);
}

/* Constructor for channel_data */
static grpc_error* cc_init_channel_elem(grpc_exec_ctx* exec_ctx,
                                        grpc_channel_element* elem,
                                        grpc_channel_element_args* args) {
  channel_data* chand = (channel_data*)elem->channel_data;
  GPR_ASSERT(args->is_last);
  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
  // Initialize data members.
  chand->combiner = grpc_combiner_create();
  gpr_mu_init(&chand->info_mu);
  gpr_mu_init(&chand->external_connectivity_watcher_list_mu);

  gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
  chand->external_connectivity_watcher_list_head = nullptr;
  gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);

  chand->owning_stack = args->channel_stack;
  GRPC_CLOSURE_INIT(&chand->on_resolver_result_changed,
                    on_resolver_result_changed_locked, chand,
                    grpc_combiner_scheduler(chand->combiner));
  chand->interested_parties = grpc_pollset_set_create();
  grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
                               "client_channel");
  grpc_client_channel_start_backup_polling(exec_ctx, chand->interested_parties);
  // Record client channel factory.
  const grpc_arg* arg = grpc_channel_args_find(args->channel_args,
                                               GRPC_ARG_CLIENT_CHANNEL_FACTORY);
  if (arg == nullptr) {
    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
        "Missing client channel factory in args for client channel filter");
  }
  if (arg->type != GRPC_ARG_POINTER) {
    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
        "client channel factory arg must be a pointer");
  }
  grpc_client_channel_factory_ref(
      (grpc_client_channel_factory*)arg->value.pointer.p);
  chand->client_channel_factory =
      (grpc_client_channel_factory*)arg->value.pointer.p;
  // Get server name to resolve, using proxy mapper if needed.
  arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVER_URI);
  if (arg == nullptr) {
    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
        "Missing server uri in args for client channel filter");
  }
  if (arg->type != GRPC_ARG_STRING) {
    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
        "server uri arg must be a string");
  }
  char* proxy_name = nullptr;
  grpc_channel_args* new_args = nullptr;
  grpc_proxy_mappers_map_name(exec_ctx, arg->value.string, args->channel_args,
                              &proxy_name, &new_args);
  // Instantiate resolver.
  chand->resolver = grpc_resolver_create(
      exec_ctx, proxy_name != nullptr ? proxy_name : arg->value.string,
      new_args != nullptr ? new_args : args->channel_args,
      chand->interested_parties, chand->combiner);
  if (proxy_name != nullptr) gpr_free(proxy_name);
  if (new_args != nullptr) grpc_channel_args_destroy(exec_ctx, new_args);
  if (chand->resolver == nullptr) {
    return GRPC_ERROR_CREATE_FROM_STATIC_STRING("resolver creation failed");
  }
  chand->deadline_checking_enabled =
      grpc_deadline_checking_enabled(args->channel_args);
  return GRPC_ERROR_NONE;
}

static void shutdown_resolver_locked(grpc_exec_ctx* exec_ctx, void* arg,
                                     grpc_error* error) {
  grpc_resolver* resolver = (grpc_resolver*)arg;
  grpc_resolver_shutdown_locked(exec_ctx, resolver);
  GRPC_RESOLVER_UNREF(exec_ctx, resolver, "channel");
}

/* Destructor for channel_data */
static void cc_destroy_channel_elem(grpc_exec_ctx* exec_ctx,
                                    grpc_channel_element* elem) {
  channel_data* chand = (channel_data*)elem->channel_data;
  if (chand->resolver != nullptr) {
    GRPC_CLOSURE_SCHED(
        exec_ctx,
        GRPC_CLOSURE_CREATE(shutdown_resolver_locked, chand->resolver,
                            grpc_combiner_scheduler(chand->combiner)),
        GRPC_ERROR_NONE);
  }
  if (chand->client_channel_factory != nullptr) {
    grpc_client_channel_factory_unref(exec_ctx, chand->client_channel_factory);
  }
  if (chand->lb_policy != nullptr) {
    grpc_pollset_set_del_pollset_set(exec_ctx,
                                     chand->lb_policy->interested_parties,
                                     chand->interested_parties);
    GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
  }
  gpr_free(chand->info_lb_policy_name);
  gpr_free(chand->info_service_config_json);
  if (chand->retry_throttle_data != nullptr) {
    grpc_server_retry_throttle_data_unref(chand->retry_throttle_data);
  }
  if (chand->method_params_table != nullptr) {
    grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table);
  }
  grpc_client_channel_stop_backup_polling(exec_ctx, chand->interested_parties);
  grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
  grpc_pollset_set_destroy(exec_ctx, chand->interested_parties);
  GRPC_COMBINER_UNREF(exec_ctx, chand->combiner, "client_channel");
  gpr_mu_destroy(&chand->info_mu);
  gpr_mu_destroy(&chand->external_connectivity_watcher_list_mu);
}

/*************************************************************************
 * PER-CALL FUNCTIONS
 */

// Max number of batches that can be pending on a call at any given
// time.  This includes:
//   recv_initial_metadata
//   send_initial_metadata
//   recv_message
//   send_message
//   recv_trailing_metadata
//   send_trailing_metadata
// We also add room for a single cancel_stream batch.
#define MAX_WAITING_BATCHES 7

/** Call data.  Holds a pointer to grpc_subchannel_call and the
    associated machinery to create such a pointer.
    Handles queueing of stream ops until a call object is ready, waiting
    for initial metadata before trying to create a call object,
    and handling cancellation gracefully. */
typedef struct client_channel_call_data {
  // State for handling deadlines.
  // The code in deadline_filter.c requires this to be the first field.
  // TODO(roth): This is slightly sub-optimal in that grpc_deadline_state
  // and this struct both independently store pointers to the call stack
  // and call combiner.  If/when we have time, find a way to avoid this
  // without breaking the grpc_deadline_state abstraction.
  grpc_deadline_state deadline_state;

  grpc_slice path;  // Request path.
  gpr_timespec call_start_time;
  grpc_millis deadline;
  gpr_arena* arena;
  grpc_call_stack* owning_call;
  grpc_call_combiner* call_combiner;

  grpc_server_retry_throttle_data* retry_throttle_data;
  method_parameters* method_params;

  grpc_subchannel_call* subchannel_call;
  grpc_error* error;

  grpc_lb_policy* lb_policy;  // Holds ref while LB pick is pending.
  grpc_closure lb_pick_closure;
  grpc_closure lb_pick_cancel_closure;

  grpc_connected_subchannel* connected_subchannel;
  grpc_call_context_element subchannel_call_context[GRPC_CONTEXT_COUNT];
  grpc_polling_entity* pollent;

  grpc_transport_stream_op_batch* waiting_for_pick_batches[MAX_WAITING_BATCHES];
  size_t waiting_for_pick_batches_count;
  grpc_closure handle_pending_batch_in_call_combiner[MAX_WAITING_BATCHES];

  grpc_transport_stream_op_batch* initial_metadata_batch;

  grpc_linked_mdelem lb_token_mdelem;

  grpc_closure on_complete;
  grpc_closure* original_on_complete;
} call_data;

grpc_subchannel_call* grpc_client_channel_get_subchannel_call(
    grpc_call_element* elem) {
  call_data* calld = (call_data*)elem->call_data;
  return calld->subchannel_call;
}

// This is called via the call combiner, so access to calld is synchronized.
static void waiting_for_pick_batches_add(
    call_data* calld, grpc_transport_stream_op_batch* batch) {
  if (batch->send_initial_metadata) {
    GPR_ASSERT(calld->initial_metadata_batch == nullptr);
    calld->initial_metadata_batch = batch;
  } else {
    GPR_ASSERT(calld->waiting_for_pick_batches_count < MAX_WAITING_BATCHES);
    calld->waiting_for_pick_batches[calld->waiting_for_pick_batches_count++] =
        batch;
  }
}

// This is called via the call combiner, so access to calld is synchronized.
static void fail_pending_batch_in_call_combiner(grpc_exec_ctx* exec_ctx,
                                                void* arg, grpc_error* error) {
  call_data* calld = (call_data*)arg;
  if (calld->waiting_for_pick_batches_count > 0) {
    --calld->waiting_for_pick_batches_count;
    grpc_transport_stream_op_batch_finish_with_failure(
        exec_ctx,
        calld->waiting_for_pick_batches[calld->waiting_for_pick_batches_count],
        GRPC_ERROR_REF(error), calld->call_combiner);
  }
}

// This is called via the call combiner, so access to calld is synchronized.
static void waiting_for_pick_batches_fail(grpc_exec_ctx* exec_ctx,
                                          grpc_call_element* elem,
                                          grpc_error* error) {
  call_data* calld = (call_data*)elem->call_data;
  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
    gpr_log(GPR_DEBUG,
            "chand=%p calld=%p: failing %" PRIuPTR " pending batches: %s",
            elem->channel_data, calld, calld->waiting_for_pick_batches_count,
            grpc_error_string(error));
  }
  for (size_t i = 0; i < calld->waiting_for_pick_batches_count; ++i) {
    GRPC_CLOSURE_INIT(&calld->handle_pending_batch_in_call_combiner[i],
                      fail_pending_batch_in_call_combiner, calld,
                      grpc_schedule_on_exec_ctx);
    GRPC_CALL_COMBINER_START(exec_ctx, calld->call_combiner,
                             &calld->handle_pending_batch_in_call_combiner[i],
                             GRPC_ERROR_REF(error),
                             "waiting_for_pick_batches_fail");
  }
  if (calld->initial_metadata_batch != nullptr) {
    grpc_transport_stream_op_batch_finish_with_failure(
        exec_ctx, calld->initial_metadata_batch, GRPC_ERROR_REF(error),
        calld->call_combiner);
  } else {
    GRPC_CALL_COMBINER_STOP(exec_ctx, calld->call_combiner,
                            "waiting_for_pick_batches_fail");
  }
  GRPC_ERROR_UNREF(error);
}

// This is called via the call combiner, so access to calld is synchronized.
static void run_pending_batch_in_call_combiner(grpc_exec_ctx* exec_ctx,
                                               void* arg, grpc_error* ignored) {
  call_data* calld = (call_data*)arg;
  if (calld->waiting_for_pick_batches_count > 0) {
    --calld->waiting_for_pick_batches_count;
    grpc_subchannel_call_process_op(
        exec_ctx, calld->subchannel_call,
        calld->waiting_for_pick_batches[calld->waiting_for_pick_batches_count]);
  }
}

// This is called via the call combiner, so access to calld is synchronized.
static void waiting_for_pick_batches_resume(grpc_exec_ctx* exec_ctx,
                                            grpc_call_element* elem) {
  channel_data* chand = (channel_data*)elem->channel_data;
  call_data* calld = (call_data*)elem->call_data;
  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
    gpr_log(GPR_DEBUG,
            "chand=%p calld=%p: sending %" PRIuPTR
            " pending batches to subchannel_call=%p",
            chand, calld, calld->waiting_for_pick_batches_count,
            calld->subchannel_call);
  }
  for (size_t i = 0; i < calld->waiting_for_pick_batches_count; ++i) {
    GRPC_CLOSURE_INIT(&calld->handle_pending_batch_in_call_combiner[i],
                      run_pending_batch_in_call_combiner, calld,
                      grpc_schedule_on_exec_ctx);
    GRPC_CALL_COMBINER_START(exec_ctx, calld->call_combiner,
                             &calld->handle_pending_batch_in_call_combiner[i],
                             GRPC_ERROR_NONE,
                             "waiting_for_pick_batches_resume");
  }
  GPR_ASSERT(calld->initial_metadata_batch != nullptr);
  grpc_subchannel_call_process_op(exec_ctx, calld->subchannel_call,
                                  calld->initial_metadata_batch);
}

// Applies service config to the call.  Must be invoked once we know
// that the resolver has returned results to the channel.
static void apply_service_config_to_call_locked(grpc_exec_ctx* exec_ctx,
                                                grpc_call_element* elem) {
  channel_data* chand = (channel_data*)elem->channel_data;
  call_data* calld = (call_data*)elem->call_data;
  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
    gpr_log(GPR_DEBUG, "chand=%p calld=%p: applying service config to call",
            chand, calld);
  }
  if (chand->retry_throttle_data != nullptr) {
    calld->retry_throttle_data =
        grpc_server_retry_throttle_data_ref(chand->retry_throttle_data);
  }
  if (chand->method_params_table != nullptr) {
    calld->method_params = (method_parameters*)grpc_method_config_table_get(
        exec_ctx, chand->method_params_table, calld->path);
    if (calld->method_params != nullptr) {
      method_parameters_ref(calld->method_params);
      // If the deadline from the service config is shorter than the one
      // from the client API, reset the deadline timer.
      if (chand->deadline_checking_enabled &&
          calld->method_params->timeout != 0) {
        const grpc_millis per_method_deadline =
            grpc_timespec_to_millis_round_up(calld->call_start_time) +
            calld->method_params->timeout;
        if (per_method_deadline < calld->deadline) {
          calld->deadline = per_method_deadline;
          grpc_deadline_state_reset(exec_ctx, elem, calld->deadline);
        }
      }
    }
  }
}

static void create_subchannel_call_locked(grpc_exec_ctx* exec_ctx,
                                          grpc_call_element* elem,
                                          grpc_error* error) {
  channel_data* chand = (channel_data*)elem->channel_data;
  call_data* calld = (call_data*)elem->call_data;
  const grpc_connected_subchannel_call_args call_args = {
      calld->pollent,                  // pollent
      calld->path,                     // path
      calld->call_start_time,          // start_time
      calld->deadline,                 // deadline
      calld->arena,                    // arena
      calld->subchannel_call_context,  // context
      calld->call_combiner             // call_combiner
  };
  grpc_error* new_error = grpc_connected_subchannel_create_call(
      exec_ctx, calld->connected_subchannel, &call_args,
      &calld->subchannel_call);
  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
    gpr_log(GPR_DEBUG, "chand=%p calld=%p: create subchannel_call=%p: error=%s",
            chand, calld, calld->subchannel_call, grpc_error_string(new_error));
  }
  if (new_error != GRPC_ERROR_NONE) {
    new_error = grpc_error_add_child(new_error, error);
    waiting_for_pick_batches_fail(exec_ctx, elem, new_error);
  } else {
    waiting_for_pick_batches_resume(exec_ctx, elem);
  }
  GRPC_ERROR_UNREF(error);
}

// Invoked when a pick is completed, on both success or failure.
static void pick_done_locked(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
                             grpc_error* error) {
  call_data* calld = (call_data*)elem->call_data;
  channel_data* chand = (channel_data*)elem->channel_data;
  if (calld->connected_subchannel == nullptr) {
    // Failed to create subchannel.
    GRPC_ERROR_UNREF(calld->error);
    calld->error = error == GRPC_ERROR_NONE
                       ? GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                             "Call dropped by load balancing policy")
                       : GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                             "Failed to create subchannel", &error, 1);
    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
      gpr_log(GPR_DEBUG,
              "chand=%p calld=%p: failed to create subchannel: error=%s", chand,
              calld, grpc_error_string(calld->error));
    }
    waiting_for_pick_batches_fail(exec_ctx, elem, GRPC_ERROR_REF(calld->error));
  } else {
    /* Create call on subchannel. */
    create_subchannel_call_locked(exec_ctx, elem, GRPC_ERROR_REF(error));
  }
  GRPC_ERROR_UNREF(error);
}

// A wrapper around pick_done_locked() that is used in cases where
// either (a) the pick was deferred pending a resolver result or (b) the
// pick was done asynchronously.  Removes the call's polling entity from
// chand->interested_parties before invoking pick_done_locked().
static void async_pick_done_locked(grpc_exec_ctx* exec_ctx,
                                   grpc_call_element* elem, grpc_error* error) {
  channel_data* chand = (channel_data*)elem->channel_data;
  call_data* calld = (call_data*)elem->call_data;
  grpc_polling_entity_del_from_pollset_set(exec_ctx, calld->pollent,
                                           chand->interested_parties);
  pick_done_locked(exec_ctx, elem, error);
}

// Note: This runs under the client_channel combiner, but will NOT be
// holding the call combiner.
static void pick_callback_cancel_locked(grpc_exec_ctx* exec_ctx, void* arg,
                                        grpc_error* error) {
  grpc_call_element* elem = (grpc_call_element*)arg;
  channel_data* chand = (channel_data*)elem->channel_data;
  call_data* calld = (call_data*)elem->call_data;
  if (calld->lb_policy != nullptr) {
    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
      gpr_log(GPR_DEBUG, "chand=%p calld=%p: cancelling pick from LB policy %p",
              chand, calld, calld->lb_policy);
    }
    grpc_lb_policy_cancel_pick_locked(exec_ctx, calld->lb_policy,
                                      &calld->connected_subchannel,
                                      GRPC_ERROR_REF(error));
  }
  GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_callback_cancel");
}

// Callback invoked by grpc_lb_policy_pick_locked() for async picks.
// Unrefs the LB policy and invokes async_pick_done_locked().
static void pick_callback_done_locked(grpc_exec_ctx* exec_ctx, void* arg,
                                      grpc_error* error) {
  grpc_call_element* elem = (grpc_call_element*)arg;
  channel_data* chand = (channel_data*)elem->channel_data;
  call_data* calld = (call_data*)elem->call_data;
  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
    gpr_log(GPR_DEBUG, "chand=%p calld=%p: pick completed asynchronously",
            chand, calld);
  }
  GPR_ASSERT(calld->lb_policy != nullptr);
  GRPC_LB_POLICY_UNREF(exec_ctx, calld->lb_policy, "pick_subchannel");
  calld->lb_policy = nullptr;
  async_pick_done_locked(exec_ctx, elem, GRPC_ERROR_REF(error));
}

// Takes a ref to chand->lb_policy and calls grpc_lb_policy_pick_locked().
// If the pick was completed synchronously, unrefs the LB policy and
// returns true.
static bool pick_callback_start_locked(grpc_exec_ctx* exec_ctx,
                                       grpc_call_element* elem) {
  channel_data* chand = (channel_data*)elem->channel_data;
  call_data* calld = (call_data*)elem->call_data;
  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
    gpr_log(GPR_DEBUG, "chand=%p calld=%p: starting pick on lb_policy=%p",
            chand, calld, chand->lb_policy);
  }
  apply_service_config_to_call_locked(exec_ctx, elem);
  // If the application explicitly set wait_for_ready, use that.
  // Otherwise, if the service config specified a value for this
  // method, use that.
  uint32_t initial_metadata_flags =
      calld->initial_metadata_batch->payload->send_initial_metadata
          .send_initial_metadata_flags;
  const bool wait_for_ready_set_from_api =
      initial_metadata_flags &
      GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET;
  const bool wait_for_ready_set_from_service_config =
      calld->method_params != nullptr &&
      calld->method_params->wait_for_ready != WAIT_FOR_READY_UNSET;
  if (!wait_for_ready_set_from_api && wait_for_ready_set_from_service_config) {
    if (calld->method_params->wait_for_ready == WAIT_FOR_READY_TRUE) {
      initial_metadata_flags |= GRPC_INITIAL_METADATA_WAIT_FOR_READY;
    } else {
      initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY;
    }
  }
  const grpc_lb_policy_pick_args inputs = {
      calld->initial_metadata_batch->payload->send_initial_metadata
          .send_initial_metadata,
      initial_metadata_flags, &calld->lb_token_mdelem};
  // Keep a ref to the LB policy in calld while the pick is pending.
  GRPC_LB_POLICY_REF(chand->lb_policy, "pick_subchannel");
  calld->lb_policy = chand->lb_policy;
  GRPC_CLOSURE_INIT(&calld->lb_pick_closure, pick_callback_done_locked, elem,
                    grpc_combiner_scheduler(chand->combiner));
  const bool pick_done = grpc_lb_policy_pick_locked(
      exec_ctx, chand->lb_policy, &inputs, &calld->connected_subchannel,
      calld->subchannel_call_context, nullptr, &calld->lb_pick_closure);
  if (pick_done) {
    /* synchronous grpc_lb_policy_pick call. Unref the LB policy. */
    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
      gpr_log(GPR_DEBUG, "chand=%p calld=%p: pick completed synchronously",
              chand, calld);
    }
    GRPC_LB_POLICY_UNREF(exec_ctx, calld->lb_policy, "pick_subchannel");
    calld->lb_policy = nullptr;
  } else {
    GRPC_CALL_STACK_REF(calld->owning_call, "pick_callback_cancel");
    grpc_call_combiner_set_notify_on_cancel(
        exec_ctx, calld->call_combiner,
        GRPC_CLOSURE_INIT(&calld->lb_pick_cancel_closure,
                          pick_callback_cancel_locked, elem,
                          grpc_combiner_scheduler(chand->combiner)));
  }
  return pick_done;
}

typedef struct {
  grpc_call_element* elem;
  bool finished;
  grpc_closure closure;
  grpc_closure cancel_closure;
} pick_after_resolver_result_args;

// Note: This runs under the client_channel combiner, but will NOT be
// holding the call combiner.
static void pick_after_resolver_result_cancel_locked(grpc_exec_ctx* exec_ctx,
                                                     void* arg,
                                                     grpc_error* error) {
  pick_after_resolver_result_args* args = (pick_after_resolver_result_args*)arg;
  if (args->finished) {
    gpr_free(args);
    return;
  }
  // If we don't yet have a resolver result, then a closure for
  // pick_after_resolver_result_done_locked() will have been added to
  // chand->waiting_for_resolver_result_closures, and it may not be invoked
  // until after this call has been destroyed.  We mark the operation as
  // finished, so that when pick_after_resolver_result_done_locked()
  // is called, it will be a no-op.  We also immediately invoke
  // async_pick_done_locked() to propagate the error back to the caller.
  args->finished = true;
  grpc_call_element* elem = args->elem;
  channel_data* chand = (channel_data*)elem->channel_data;
  call_data* calld = (call_data*)elem->call_data;
  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
    gpr_log(GPR_DEBUG,
            "chand=%p calld=%p: cancelling pick waiting for resolver result",
            chand, calld);
  }
  // Note: Although we are not in the call combiner here, we are
  // basically stealing the call combiner from the pending pick, so
  // it's safe to call async_pick_done_locked() here -- we are
  // essentially calling it here instead of calling it in
  // pick_after_resolver_result_done_locked().
  async_pick_done_locked(exec_ctx, elem,
                         GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                             "Pick cancelled", &error, 1));
}

static void pick_after_resolver_result_start_locked(grpc_exec_ctx* exec_ctx,
                                                    grpc_call_element* elem);

static void pick_after_resolver_result_done_locked(grpc_exec_ctx* exec_ctx,
                                                   void* arg,
                                                   grpc_error* error) {
  pick_after_resolver_result_args* args = (pick_after_resolver_result_args*)arg;
  if (args->finished) {
    /* cancelled, do nothing */
    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
      gpr_log(GPR_DEBUG, "call cancelled before resolver result");
    }
    gpr_free(args);
    return;
  }
  args->finished = true;
  grpc_call_element* elem = args->elem;
  channel_data* chand = (channel_data*)elem->channel_data;
  call_data* calld = (call_data*)elem->call_data;
  if (error != GRPC_ERROR_NONE) {
    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
      gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver failed to return data",
              chand, calld);
    }
    async_pick_done_locked(exec_ctx, elem, GRPC_ERROR_REF(error));
  } else if (chand->lb_policy != nullptr) {
    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
      gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver returned, doing pick",
              chand, calld);
    }
    if (pick_callback_start_locked(exec_ctx, elem)) {
      // Even if the LB policy returns a result synchronously, we have
      // already added our polling entity to chand->interested_parties
      // in order to wait for the resolver result, so we need to
      // remove it here.  Therefore, we call async_pick_done_locked()
      // instead of pick_done_locked().
      async_pick_done_locked(exec_ctx, elem, GRPC_ERROR_NONE);
    }
  }
  // TODO(roth): It should be impossible for chand->lb_policy to be NULL
  // here, so the rest of this code should never actually be executed.
  // However, we have reports of a crash on iOS that triggers this case,
  // so we are temporarily adding this to restore branches that were
  // removed in https://github.com/grpc/grpc/pull/12297.  Need to figure
  // out what is actually causing this to occur and then figure out the
  // right way to deal with it.
  else if (chand->resolver != nullptr) {
    // No LB policy, so try again.
    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
      gpr_log(GPR_DEBUG,
              "chand=%p calld=%p: resolver returned but no LB policy, "
              "trying again",
              chand, calld);
    }
    pick_after_resolver_result_start_locked(exec_ctx, elem);
  } else {
    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
      gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver disconnected", chand,
              calld);
    }
    async_pick_done_locked(
        exec_ctx, elem, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Disconnected"));
  }
}

static void pick_after_resolver_result_start_locked(grpc_exec_ctx* exec_ctx,
                                                    grpc_call_element* elem) {
  channel_data* chand = (channel_data*)elem->channel_data;
  call_data* calld = (call_data*)elem->call_data;
  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
    gpr_log(GPR_DEBUG,
            "chand=%p calld=%p: deferring pick pending resolver result", chand,
            calld);
  }
  pick_after_resolver_result_args* args =
      (pick_after_resolver_result_args*)gpr_zalloc(sizeof(*args));
  args->elem = elem;
  GRPC_CLOSURE_INIT(&args->closure, pick_after_resolver_result_done_locked,
                    args, grpc_combiner_scheduler(chand->combiner));
  grpc_closure_list_append(&chand->waiting_for_resolver_result_closures,
                           &args->closure, GRPC_ERROR_NONE);
  grpc_call_combiner_set_notify_on_cancel(
      exec_ctx, calld->call_combiner,
      GRPC_CLOSURE_INIT(&args->cancel_closure,
                        pick_after_resolver_result_cancel_locked, args,
                        grpc_combiner_scheduler(chand->combiner)));
}

static void start_pick_locked(grpc_exec_ctx* exec_ctx, void* arg,
                              grpc_error* ignored) {
  grpc_call_element* elem = (grpc_call_element*)arg;
  call_data* calld = (call_data*)elem->call_data;
  channel_data* chand = (channel_data*)elem->channel_data;
  GPR_ASSERT(calld->connected_subchannel == nullptr);
  if (chand->lb_policy != nullptr) {
    // We already have an LB policy, so ask it for a pick.
    if (pick_callback_start_locked(exec_ctx, elem)) {
      // Pick completed synchronously.
      pick_done_locked(exec_ctx, elem, GRPC_ERROR_NONE);
      return;
    }
  } else {
    // We do not yet have an LB policy, so wait for a resolver result.
    if (chand->resolver == nullptr) {
      pick_done_locked(exec_ctx, elem,
                       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Disconnected"));
      return;
    }
    if (!chand->started_resolving) {
      start_resolving_locked(exec_ctx, chand);
    }
    pick_after_resolver_result_start_locked(exec_ctx, elem);
  }
  // We need to wait for either a resolver result or for an async result
  // from the LB policy.  Add the polling entity from call_data to the
  // channel_data's interested_parties, so that the I/O of the LB policy
  // and resolver can be done under it.  The polling entity will be
  // removed in async_pick_done_locked().
  grpc_polling_entity_add_to_pollset_set(exec_ctx, calld->pollent,
                                         chand->interested_parties);
}

static void on_complete(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) {
  grpc_call_element* elem = (grpc_call_element*)arg;
  call_data* calld = (call_data*)elem->call_data;
  if (calld->retry_throttle_data != nullptr) {
    if (error == GRPC_ERROR_NONE) {
      grpc_server_retry_throttle_data_record_success(
          calld->retry_throttle_data);
    } else {
      // TODO(roth): In a subsequent PR, check the return value here and
      // decide whether or not to retry.  Note that we should only
      // record failures whose statuses match the configured retryable
      // or non-fatal status codes.
      grpc_server_retry_throttle_data_record_failure(
          calld->retry_throttle_data);
    }
  }
  GRPC_CLOSURE_RUN(exec_ctx, calld->original_on_complete,
                   GRPC_ERROR_REF(error));
}

static void cc_start_transport_stream_op_batch(
    grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
    grpc_transport_stream_op_batch* batch) {
  call_data* calld = (call_data*)elem->call_data;
  channel_data* chand = (channel_data*)elem->channel_data;
  if (chand->deadline_checking_enabled) {
    grpc_deadline_state_client_start_transport_stream_op_batch(exec_ctx, elem,
                                                               batch);
  }
  GPR_TIMER_BEGIN("cc_start_transport_stream_op_batch", 0);
  // If we've previously been cancelled, immediately fail any new batches.
  if (calld->error != GRPC_ERROR_NONE) {
    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
      gpr_log(GPR_DEBUG, "chand=%p calld=%p: failing batch with error: %s",
              chand, calld, grpc_error_string(calld->error));
    }
    grpc_transport_stream_op_batch_finish_with_failure(
        exec_ctx, batch, GRPC_ERROR_REF(calld->error), calld->call_combiner);
    goto done;
  }
  if (batch->cancel_stream) {
    // Stash a copy of cancel_error in our call data, so that we can use
    // it for subsequent operations.  This ensures that if the call is
    // cancelled before any batches are passed down (e.g., if the deadline
    // is in the past when the call starts), we can return the right
    // error to the caller when the first batch does get passed down.
    GRPC_ERROR_UNREF(calld->error);
    calld->error = GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error);
    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
      gpr_log(GPR_DEBUG, "chand=%p calld=%p: recording cancel_error=%s", chand,
              calld, grpc_error_string(calld->error));
    }
    // If we have a subchannel call, send the cancellation batch down.
    // Otherwise, fail all pending batches.
    if (calld->subchannel_call != nullptr) {
      grpc_subchannel_call_process_op(exec_ctx, calld->subchannel_call, batch);
    } else {
      waiting_for_pick_batches_add(calld, batch);
      waiting_for_pick_batches_fail(exec_ctx, elem,
                                    GRPC_ERROR_REF(calld->error));
    }
    goto done;
  }
  // Intercept on_complete for recv_trailing_metadata so that we can
  // check retry throttle status.
  if (batch->recv_trailing_metadata) {
    GPR_ASSERT(batch->on_complete != nullptr);
    calld->original_on_complete = batch->on_complete;
    GRPC_CLOSURE_INIT(&calld->on_complete, on_complete, elem,
                      grpc_schedule_on_exec_ctx);
    batch->on_complete = &calld->on_complete;
  }
  // Check if we've already gotten a subchannel call.
  // Note that once we have completed the pick, we do not need to enter
  // the channel combiner, which is more efficient (especially for
  // streaming calls).
  if (calld->subchannel_call != nullptr) {
    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
      gpr_log(GPR_DEBUG,
              "chand=%p calld=%p: sending batch to subchannel_call=%p", chand,
              calld, calld->subchannel_call);
    }
    grpc_subchannel_call_process_op(exec_ctx, calld->subchannel_call, batch);
    goto done;
  }
  // We do not yet have a subchannel call.
  // Add the batch to the waiting-for-pick list.
  waiting_for_pick_batches_add(calld, batch);
  // For batches containing a send_initial_metadata op, enter the channel
  // combiner to start a pick.
  if (batch->send_initial_metadata) {
    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
      gpr_log(GPR_DEBUG, "chand=%p calld=%p: entering client_channel combiner",
              chand, calld);
    }
    GRPC_CLOSURE_SCHED(
        exec_ctx,
        GRPC_CLOSURE_INIT(&batch->handler_private.closure, start_pick_locked,
                          elem, grpc_combiner_scheduler(chand->combiner)),
        GRPC_ERROR_NONE);
  } else {
    // For all other batches, release the call combiner.
    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
      gpr_log(GPR_DEBUG,
              "chand=%p calld=%p: saved batch, yeilding call combiner", chand,
              calld);
    }
    GRPC_CALL_COMBINER_STOP(exec_ctx, calld->call_combiner,
                            "batch does not include send_initial_metadata");
  }
done:
  GPR_TIMER_END("cc_start_transport_stream_op_batch", 0);
}

/* Constructor for call_data */
static grpc_error* cc_init_call_elem(grpc_exec_ctx* exec_ctx,
                                     grpc_call_element* elem,
                                     const grpc_call_element_args* args) {
  call_data* calld = (call_data*)elem->call_data;
  channel_data* chand = (channel_data*)elem->channel_data;
  // Initialize data members.
  calld->path = grpc_slice_ref_internal(args->path);
  calld->call_start_time = args->start_time;
  calld->deadline = args->deadline;
  calld->arena = args->arena;
  calld->owning_call = args->call_stack;
  calld->call_combiner = args->call_combiner;
  if (chand->deadline_checking_enabled) {
    grpc_deadline_state_init(exec_ctx, elem, args->call_stack,
                             args->call_combiner, calld->deadline);
  }
  return GRPC_ERROR_NONE;
}

/* Destructor for call_data */
static void cc_destroy_call_elem(grpc_exec_ctx* exec_ctx,
                                 grpc_call_element* elem,
                                 const grpc_call_final_info* final_info,
                                 grpc_closure* then_schedule_closure) {
  call_data* calld = (call_data*)elem->call_data;
  channel_data* chand = (channel_data*)elem->channel_data;
  if (chand->deadline_checking_enabled) {
    grpc_deadline_state_destroy(exec_ctx, elem);
  }
  grpc_slice_unref_internal(exec_ctx, calld->path);
  if (calld->method_params != nullptr) {
    method_parameters_unref(calld->method_params);
  }
  GRPC_ERROR_UNREF(calld->error);
  if (calld->subchannel_call != nullptr) {
    grpc_subchannel_call_set_cleanup_closure(calld->subchannel_call,
                                             then_schedule_closure);
    then_schedule_closure = nullptr;
    GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, calld->subchannel_call,
                               "client_channel_destroy_call");
  }
  GPR_ASSERT(calld->lb_policy == nullptr);
  GPR_ASSERT(calld->waiting_for_pick_batches_count == 0);
  if (calld->connected_subchannel != nullptr) {
    GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, calld->connected_subchannel,
                                    "picked");
  }
  for (size_t i = 0; i < GRPC_CONTEXT_COUNT; ++i) {
    if (calld->subchannel_call_context[i].value != nullptr) {
      calld->subchannel_call_context[i].destroy(
          calld->subchannel_call_context[i].value);
    }
  }
  GRPC_CLOSURE_SCHED(exec_ctx, then_schedule_closure, GRPC_ERROR_NONE);
}

static void cc_set_pollset_or_pollset_set(grpc_exec_ctx* exec_ctx,
                                          grpc_call_element* elem,
                                          grpc_polling_entity* pollent) {
  call_data* calld = (call_data*)elem->call_data;
  calld->pollent = pollent;
}

/*************************************************************************
 * EXPORTED SYMBOLS
 */

const grpc_channel_filter grpc_client_channel_filter = {
    cc_start_transport_stream_op_batch,
    cc_start_transport_op,
    sizeof(call_data),
    cc_init_call_elem,
    cc_set_pollset_or_pollset_set,
    cc_destroy_call_elem,
    sizeof(channel_data),
    cc_init_channel_elem,
    cc_destroy_channel_elem,
    cc_get_channel_info,
    "client-channel",
};

static void try_to_connect_locked(grpc_exec_ctx* exec_ctx, void* arg,
                                  grpc_error* error_ignored) {
  channel_data* chand = (channel_data*)arg;
  if (chand->lb_policy != nullptr) {
    grpc_lb_policy_exit_idle_locked(exec_ctx, chand->lb_policy);
  } else {
    chand->exit_idle_when_lb_policy_arrives = true;
    if (!chand->started_resolving && chand->resolver != nullptr) {
      start_resolving_locked(exec_ctx, chand);
    }
  }
  GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "try_to_connect");
}

grpc_connectivity_state grpc_client_channel_check_connectivity_state(
    grpc_exec_ctx* exec_ctx, grpc_channel_element* elem, int try_to_connect) {
  channel_data* chand = (channel_data*)elem->channel_data;
  grpc_connectivity_state out =
      grpc_connectivity_state_check(&chand->state_tracker);
  if (out == GRPC_CHANNEL_IDLE && try_to_connect) {
    GRPC_CHANNEL_STACK_REF(chand->owning_stack, "try_to_connect");
    GRPC_CLOSURE_SCHED(
        exec_ctx,
        GRPC_CLOSURE_CREATE(try_to_connect_locked, chand,
                            grpc_combiner_scheduler(chand->combiner)),
        GRPC_ERROR_NONE);
  }
  return out;
}

typedef struct external_connectivity_watcher {
  channel_data* chand;
  grpc_polling_entity pollent;
  grpc_closure* on_complete;
  grpc_closure* watcher_timer_init;
  grpc_connectivity_state* state;
  grpc_closure my_closure;
  struct external_connectivity_watcher* next;
} external_connectivity_watcher;

static external_connectivity_watcher* lookup_external_connectivity_watcher(
    channel_data* chand, grpc_closure* on_complete) {
  gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
  external_connectivity_watcher* w =
      chand->external_connectivity_watcher_list_head;
  while (w != nullptr && w->on_complete != on_complete) {
    w = w->next;
  }
  gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
  return w;
}

static void external_connectivity_watcher_list_append(
    channel_data* chand, external_connectivity_watcher* w) {
  GPR_ASSERT(!lookup_external_connectivity_watcher(chand, w->on_complete));

  gpr_mu_lock(&w->chand->external_connectivity_watcher_list_mu);
  GPR_ASSERT(!w->next);
  w->next = chand->external_connectivity_watcher_list_head;
  chand->external_connectivity_watcher_list_head = w;
  gpr_mu_unlock(&w->chand->external_connectivity_watcher_list_mu);
}

static void external_connectivity_watcher_list_remove(
    channel_data* chand, external_connectivity_watcher* too_remove) {
  GPR_ASSERT(
      lookup_external_connectivity_watcher(chand, too_remove->on_complete));
  gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
  if (too_remove == chand->external_connectivity_watcher_list_head) {
    chand->external_connectivity_watcher_list_head = too_remove->next;
    gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
    return;
  }
  external_connectivity_watcher* w =
      chand->external_connectivity_watcher_list_head;
  while (w != nullptr) {
    if (w->next == too_remove) {
      w->next = w->next->next;
      gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
      return;
    }
    w = w->next;
  }
  GPR_UNREACHABLE_CODE(return );
}

int grpc_client_channel_num_external_connectivity_watchers(
    grpc_channel_element* elem) {
  channel_data* chand = (channel_data*)elem->channel_data;
  int count = 0;

  gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
  external_connectivity_watcher* w =
      chand->external_connectivity_watcher_list_head;
  while (w != nullptr) {
    count++;
    w = w->next;
  }
  gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);

  return count;
}

static void on_external_watch_complete_locked(grpc_exec_ctx* exec_ctx,
                                              void* arg, grpc_error* error) {
  external_connectivity_watcher* w = (external_connectivity_watcher*)arg;
  grpc_closure* follow_up = w->on_complete;
  grpc_polling_entity_del_from_pollset_set(exec_ctx, &w->pollent,
                                           w->chand->interested_parties);
  GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack,
                           "external_connectivity_watcher");
  external_connectivity_watcher_list_remove(w->chand, w);
  gpr_free(w);
  GRPC_CLOSURE_RUN(exec_ctx, follow_up, GRPC_ERROR_REF(error));
}

static void watch_connectivity_state_locked(grpc_exec_ctx* exec_ctx, void* arg,
                                            grpc_error* error_ignored) {
  external_connectivity_watcher* w = (external_connectivity_watcher*)arg;
  external_connectivity_watcher* found = nullptr;
  if (w->state != nullptr) {
    external_connectivity_watcher_list_append(w->chand, w);
    GRPC_CLOSURE_RUN(exec_ctx, w->watcher_timer_init, GRPC_ERROR_NONE);
    GRPC_CLOSURE_INIT(&w->my_closure, on_external_watch_complete_locked, w,
                      grpc_combiner_scheduler(w->chand->combiner));
    grpc_connectivity_state_notify_on_state_change(
        exec_ctx, &w->chand->state_tracker, w->state, &w->my_closure);
  } else {
    GPR_ASSERT(w->watcher_timer_init == nullptr);
    found = lookup_external_connectivity_watcher(w->chand, w->on_complete);
    if (found) {
      GPR_ASSERT(found->on_complete == w->on_complete);
      grpc_connectivity_state_notify_on_state_change(
          exec_ctx, &found->chand->state_tracker, nullptr, &found->my_closure);
    }
    grpc_polling_entity_del_from_pollset_set(exec_ctx, &w->pollent,
                                             w->chand->interested_parties);
    GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack,
                             "external_connectivity_watcher");
    gpr_free(w);
  }
}

void grpc_client_channel_watch_connectivity_state(
    grpc_exec_ctx* exec_ctx, grpc_channel_element* elem,
    grpc_polling_entity pollent, grpc_connectivity_state* state,
    grpc_closure* closure, grpc_closure* watcher_timer_init) {
  channel_data* chand = (channel_data*)elem->channel_data;
  external_connectivity_watcher* w =
      (external_connectivity_watcher*)gpr_zalloc(sizeof(*w));
  w->chand = chand;
  w->pollent = pollent;
  w->on_complete = closure;
  w->state = state;
  w->watcher_timer_init = watcher_timer_init;
  grpc_polling_entity_add_to_pollset_set(exec_ctx, &w->pollent,
                                         chand->interested_parties);
  GRPC_CHANNEL_STACK_REF(w->chand->owning_stack,
                         "external_connectivity_watcher");
  GRPC_CLOSURE_SCHED(
      exec_ctx,
      GRPC_CLOSURE_INIT(&w->my_closure, watch_connectivity_state_locked, w,
                        grpc_combiner_scheduler(chand->combiner)),
      GRPC_ERROR_NONE);
}

redpajama_set_name: RedPajamaGithub


text:
The Turning Point Of My Life
© Pradanya Mordia
Children Stories Inspirational
5 Minutes 316 19
#205 in Story (English)
Hi, it's me Pradanya Mordia living in stereo, no returning engagements, no encore and this time absolutely no requests, get a snack and settle in because I am about to tell you the story of my life...more specifically why my life had a turning point.
Being an old flame and habitual to my daily life routine, I headed towards the school where I entered taking all of my classmates' sentiments on me, but there is nothing to be amazed about because this remains the same. This all happened because ... one year ago I changed my class and was transferred to another section where everything was good except the behavioral act and the way my friends spoke to me. I know somewhere you all will find this extract to be a fake one but believe it is real not an imaginary story. To me this was irresistible. I had always been an average student and wasn't enough qualified in the eyes of my teachers.
A club of girls always had this feeling of jealousness from me whether it was in the corridor or at the mess. No matter how I cherished a right or privilege because I mind whatever I say to others otherwise how will my harmony differ from dregs, as I truly believe in that the tongue has no bones, but is stronger enough to break a heart. So we should be careful with what we say.
To my conclude, each person in every society feels that by these harsh talks somebody is letting him or her down and so they cannot be successful in their lives and take all these gross talks as their weak point but I took it as my strength where I found it to be successful.
The greatest achievement have I ever had, was visiting Stanford University, USA. During the Economics class; a teacher with a smile and enthusiasm walked into my class and said, "I am proud to announce that this letter is for Pradanya Mordia, given from the school authority and from the director of renowned Stanford University, who is been welcomed to spend a month at their University." And gave that letter to me. That letter to me at that time was a victory of self-discovery where I found another side of mine which can actually renovate my life towards the future. In the sense of belonging this day added a little glamour to my life where I surrendered my past and moved on to create a new story so that even I do something which is actually presentable in the eyes of society. So I promised myself that no matter what, but I will definitely achieve something or the others that other people do and will prove myself that even I can be like one.
Moving on, I have received thousands of mistakes… whether it is with studies or public speaking... but this all twisted so suddenly! That it made my busy schedule a desiring one; where anyone can enjoy each and every piece of their growth. I was been called on the stage in front of the whole school, teachers and above all my parents. School Principal called total 10 selective students out of which even my name was taken, I did not know how to react upon but a push from my mum and dad gave stability to go on. I started heading to the stage while each person sitting on the chairs started clapping for me, I couldn't resist myself and felt like crying moreover those clapping meant like a compliment to me without words which was really a wonderful feeling for me. In addition to this honestly, I did not have any idea that for what I was been called but was sure that if the public is appreciating then this has to be a good thing…well, I was perfectly correct they took my name because I was selected by the director of Stanford University so that I can come to their place and experience their type of involvement and their surroundings too.
Hearing this it became my afternoon delight and probably a way to my new beginning. Furthermore, I answered saying that this all magic is happening all because of mum and dad who had always been the supporters of mine and they both smiled with a welcome sight.
Going to California, at the University and San Francisco made an independent and bold feeling inside me and made me eligible that anything wanted in life can be achieved. I attended multiple classes but the best was the leadership class, but the professor made it more interactive because she spoke about her accidents too in her life. Felt after listening to her story that somehow I am related to hers. She began to say that once she was a very introvert and extremely shy person who did not have a social personality and was unable to speak in front of such a huge amount of people but…. One day she started to forget it and worked on and there she is won 15 English debate competitions and also being a public motivation list. She made me think to what I am and to have faith to see the true and actual side of yourself. I found the beauty inside of me where now I was really not worried about going somewhere. I managed to pay my own bills, to fight for the right, to tell people that an ordinary can make up to the World's Top 5 Universities.
I came back to India and saw a completely drastic change in my life where people appreciated my efforts and my friends asking me for help in every subject and letting me share my journey too. There is so much to do in this World... it' just a matter of time when you realize. So the most unbelievable and turning point for me till now in my life was to be changed from an average student to a practical and good student. So probably that is why I am able to write such stories because this platform has given me the opportunity to showcase of what I can do and hence even I am learning from this so one can say that keep trying and have faith in you like I did as characters cannot just be developed in ease and quiet, only through experience of trial and suffering can soul be strengthen, vision cleared and success achieved.. By this philosophy, I and my life changed.
strength encore debate


Are you after Acer Repairs Sydney? Our Acer service department has extensive knowledge, tools, and experience in Acer laptop, notebook, and desktop computer service and support. From a sudden virus infection to the most complex mother board issues we can assist you at our 7 day service centre.
No matter what model of Acer you have, we also offer full broken and smashed LCD screen replacement and repairs as well as liquid damage and power issue fault finding.
All of our Acer service and support jobs come with a three month warranty on parts and labour (T&Cs apply) and we only use high quality replacement parts and components when repairing your system. For those that can't make it to us, we can also arrange an onsite consult or a courier service.
You can reach us 7 days on (02) 9698-9644 or support@erepairs.com.au and you can view our full contact details by clicking here.


Our luxury custom home builders can help you design the home of your dreams. When it comes time to take the leap to building your new home, our home remodeling contractors have the experience. From every large decision down to the smallest detail, we will make sure your luxury custom home is everything you dreamed it would be.
Seeing your idea flourish during the design process can be a lot of fun. Sit down with our expert luxury custom home builder and designer to lay out the plans for your beautiful home today. Our home remodeling contractor will use three decades of experience to turn your dream into a great plan. When you describe your thoughts to us, we will transform that into a custom plan that will lead to a beautiful home. We can take the great ideas you have and turn them into something real. Your continued input throughout the process will ensure that we, as your luxury custom home builder, will be able to make it exactly what you want.
With decades in the home remodeling business, we are able to grasp your ideas and turn that into a workable design for our luxury custom home builder. From the beginning of the design process to the final inspection, we are there for you. Basement to roof, our expert craftsman will handle every detail and every custom design you have in mind. We know that when you hire a luxury custom home builder, you are making a big decision. We are as committed to getting it right as you are. When you have been doing this as long as we have, you take a tremendous amount of pride in your work. Get in touch with us right away and we will walk you through the whole process.
When you hire us as your luxury custom home builder, you can be sure that we will be there with you every step of the way. Our owner is personally committed to the design process and will be in contact with you continuously throughout the construction. As a home remodeling contractor, we know how important communication is with our clients. This is your home we are building. We will make doubly sure that everything we do is exactly what you want. Call us, and see how much we can offer you.
We are luxury custom home builders in Carmel, Fishers, Noblesville and all surrounding areas.