private function apply_remove($pid, $contact, AssignmentState $state, $m)
 {
     $prow = $state->prow($pid);
     // resolve twiddle portion
     if ($m[1] && $m[1] != "~~" && !ctype_digit(substr($m[1], 0, strlen($m[1]) - 1))) {
         $c = substr($m[1], 0, strlen($m[1]) - 1);
         $twiddlecids = ContactSearch::make_pc($c, $state->contact->contactId)->ids;
         if (count($twiddlecids) == 0) {
             return "“" . htmlspecialchars($c) . "” doesn’t match a PC member.";
         } else {
             if (count($twiddlecids) == 1) {
                 $m[1] = $twiddlecids[0] . "~";
             } else {
                 $m[1] = "(?:" . join("|", $twiddlecids) . ")~";
             }
         }
     }
     // resolve tag portion
     $search_ltag = null;
     if (strcasecmp($m[2], "none") == 0) {
         return;
     } else {
         if (strcasecmp($m[2], "any") == 0 || strcasecmp($m[2], "all") == 0) {
             if ($m[1]) {
                 $m[2] = "[^~]*";
             } else {
                 if ($state->contact->privChair) {
                     $m[2] = "(?:~~|" . $state->contact->contactId . "~|)[^~]*";
                 } else {
                     $m[2] = "(?:" . $state->contact->contactId . "~|)[^~]*";
                 }
             }
         } else {
             if (!preg_match(',[*(],', $m[1] . $m[2])) {
                 $search_ltag = $m[1] . $m[2];
             }
             $m[2] = str_replace("\\*", "[^~]*", preg_quote($m[2]));
         }
     }
     // resolve index comparator
     if (preg_match(',\\A(?:any|all|none|clear)\\z,i', $m[4])) {
         $m[3] = $m[4] = "";
     } else {
         if ($m[3] == "#") {
             $m[3] = "=";
         }
         $m[4] = cvtint($m[4], 0);
     }
     // if you can't view the tag, you can't clear the tag
     // (information exposure)
     if ($search_ltag && !$state->contact->can_view_tag($prow, $search_ltag, $state->override)) {
         return $this->cannot_view_error($state, $pid, $search_ltag);
     }
     // query
     $res = $state->query(array("type" => "tag", "pid" => $pid, "ltag" => $search_ltag));
     $tag_re = '{\\A' . $m[1] . $m[2] . '\\z}i';
     $vote_adjustments = array();
     foreach ($res as $x) {
         if (preg_match($tag_re, $x["ltag"]) && (!$m[3] || CountMatcher::compare($x["_index"], $m[3], $m[4])) && ($search_ltag || $state->contact->can_change_tag($prow, $x["ltag"], $x["_index"], null, $state->override))) {
             $state->remove($x);
             if ($v = TagInfo::votish_base($x["ltag"])) {
                 $vote_adjustments[$v] = true;
             }
         }
     }
     foreach ($vote_adjustments as $vtag => $v) {
         $this->account_votes($pid, $vtag, $state);
     }
 }