static void parse_indexdef(IndexDef *stmt, Oid index, Oid table) { char *sql = pg_get_indexdef_string(index); const char *idxname = get_quoted_relname(index); const char *tblname = get_relation_name(table); /* CREATE [UNIQUE] INDEX */ stmt->create = sql; sql = skip_const(index, sql, "CREATE INDEX", "CREATE UNIQUE INDEX"); /* index */ stmt->index = sql; sql = skip_const(index, sql, idxname, NULL); /* ON */ sql = skip_const(index, sql, "ON", NULL); /* table */ stmt->table = sql; sql = skip_const(index, sql, tblname, NULL); /* USING */ sql = skip_const(index, sql, "USING", NULL); /* type */ stmt->type = sql; sql = skip_ident(index, sql); /* (columns) */ if ((sql = strchr(sql, '(')) == NULL) parse_error(index); sql++; stmt->columns = sql; if ((sql = skip_until(index, sql, ')')) == NULL) parse_error(index); /* options */ stmt->options = sql; }
static void socks4_client(int sock) { struct socks4_header h; struct sockaddr_in addr; int relay=INVALID_SOCKET; unsigned char c; if (recv(sock, &c, 1, MSG_PEEK) != 1) goto ex; if (c == SOCKS4_EXECBYTE) { socks4_exec(sock); closesocket(sock); return; } if (c != 0x04) goto reject; if (recv_bytes(sock, (char *)&h, sizeof(h), 0) != sizeof(h)) goto ex; if (skip_until(sock, '\0')) goto reject; if (h.vn != 0x04) goto reject; if (h.cd != 0x01) goto reject; /* BIND method is not supported */ if ((h.dstip != 0) && ((htonl(h.dstip) & 0xFFFFFF00) == 0)) /* 0.0.0.xxx, xxx!=0 */ /* SOCKS4A extension... */ if (parse_socks4a(sock, &h.dstip)) goto reject; addr.sin_family = AF_INET; addr.sin_port = h.dstport; addr.sin_addr.s_addr = h.dstip; relay = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (relay == INVALID_SOCKET) goto reject; if (connect(relay, (struct sockaddr *)&addr, sizeof(addr))) goto reject; h.vn = 0x04; h.cd = SOCKS4_SUCCEEDED; /* success */ send(sock, (char *)&h, sizeof(h), 0); relay_socks(sock, relay); ex: if (relay != INVALID_SOCKET) closesocket(relay); closesocket(sock); return; reject: h.vn = 0x04; h.cd = SOCKS4_REJECTED; /* rejected/failed */ send(sock, (char *)&h, sizeof(h), 0); goto ex; }
void declare_locals ( bool ignoring) { num_ilocals = 0; num_ulocals = 0; localno = 0; l_d_lineno = lineno; bool sav_rep_mul_lin = report_multiline; report_multiline = TRUE; if ( ignoring || error_check_locals() ) { if ( skip_until ( '}' ) ) { warn_unterm(TKERROR, "misplaced Local-Values Declaration", l_d_lineno); }else{ pc++ ; /* Get past the close-curly-brace */ } }else{ if (gather_locals( TRUE, &num_ilocals ) ) { gather_locals( FALSE, &num_ulocals ); } } /* If PC has reached the END, gather_locals() will * have already issued an "unterminated" Error; * a "multiline" warning would be redundant * repetitive, unnecessary, excessive, unaesthetic * and -- did I already mention? -- redundant. */ if ( pc < end ) { report_multiline = sav_rep_mul_lin; warn_if_multiline( "Local-Values declaration", l_d_lineno); } /* Don't do anything if no Locals were declared */ /* This could happen if the { } field is empty */ if ( localno != 0 ) { activate_locals(); } }
void read_series(istream& df, const string &name) { char ch; vec_convert vc; series t; while (df) { t.init(); vc.clear(); df >> ws; if (df.peek() == '*') { t.hide = true; df.ignore(); } if (hide_series) t.hide = true; df >> ws; ch = get_token(df, t.ID); if (isspace(ch)) ch = skip_until(df); if (ch != ',') continue; df >> ws; string str; ch = get_token(df, str); try { t.f = FindResidual(str); } catch (gError) { cout << NOEQ << t.ID << " - " << str << " - series ignored" << endl; while (ch = df.get(), ch != ';' && ch != EOF); continue; } parser p(df, name); SGML el; if (isspace(ch)) while (df >> ws, ch = df.peek(), ch == '<') { p.GetSGML(el); el.compare("var"); str = el.FindString("name"); if (!str.empty()) { t.vs.push_back(str); t.vx.push_back(el.FindDouble("value")); } } if (ch != ',') ch = skip_until(df); if (ch == ',') df.ignore(); else continue; while (df >> ws, ch = df.peek(), ch == '<') { vc.push_back(convert()); vc.back().read(p.GetSGML(el)); } if (ch == ',') df.ignore(); t.read(df, 0, t.f.NameOfX(), t.f.ScaleOfX()); if (!t) continue; if (vc.empty()) ser.push_back(t); else { series t1; t1.hide = t.hide; t1.ID = t.ID; t1.f = t.f; t1.vs = t.vs; t1.vx = t.vx; t1.set(t.Ntot(), vc.size()); for (size_t i = 0; i < vc.size(); ++i) { if (vc[i].name().empty()) throw gError("read_series: no name while converting"); else t1.name(i) = vc[i].name(); } t1.scale() = t.scale(); t1.NOfX() = SearchString(t1.names(), t1.f.NameOfX()); for (size_t i = 0; i < vc.size(); ++i) vc[i].SetID(t.names()); for (size_t i = 0; i < t.Ntot(); ++i) { t1.atr(i) = t.atr(i); for (size_t j = 0; j < vc.size(); ++j) t1(i, j) = vc[j](t(i)); } t1.set_av(); ser.push_back(t1); } ser.back().f.SetInput(ser.back().names()); ser.back().f.SetOnceInput(ser.back().vs); } }
int read_config(const char *path, int type) { char line[1024]; FILE *fp; char *s, *key, *val, *end_of_key; const char *error; char *cp, *cp2; int i; int lineno = 0; int got_transport = 0; int min_timeout = 0; struct ticket_config defaults = { { 0 } }; struct ticket_config *current_tk = NULL; fp = fopen(path, "r"); if (!fp) { log_error("failed to open %s: %s", path, strerror(errno)); return -1; } booth_conf = malloc(sizeof(struct booth_config) + TICKET_ALLOC * sizeof(struct ticket_config)); if (!booth_conf) { fclose(fp); log_error("failed to alloc memory for booth config"); return -ENOMEM; } memset(booth_conf, 0, sizeof(struct booth_config) + TICKET_ALLOC * sizeof(struct ticket_config)); ticket_size = TICKET_ALLOC; booth_conf->proto = UDP; booth_conf->port = BOOTH_DEFAULT_PORT; booth_conf->maxtimeskew = BOOTH_DEFAULT_MAX_TIME_SKEW; booth_conf->authkey[0] = '\0'; /* Provide safe defaults. -1 is reserved, though. */ booth_conf->uid = -2; booth_conf->gid = -2; strcpy(booth_conf->site_user, "hacluster"); strcpy(booth_conf->site_group, "haclient"); strcpy(booth_conf->arb_user, "nobody"); strcpy(booth_conf->arb_group, "nobody"); parse_weights("", defaults.weight); defaults.clu_test.path = NULL; defaults.clu_test.pid = 0; defaults.clu_test.status = 0; defaults.clu_test.progstate = EXTPROG_IDLE; defaults.term_duration = DEFAULT_TICKET_EXPIRY; defaults.timeout = DEFAULT_TICKET_TIMEOUT; defaults.retries = DEFAULT_RETRIES; defaults.acquire_after = 0; defaults.mode = TICKET_MODE_AUTO; error = ""; log_debug("reading config file %s", path); while (fgets(line, sizeof(line), fp)) { lineno++; s = skip_while(line, isspace); if (is_end_of_line(s) || *s == '#') continue; key = s; /* Key */ end_of_key = skip_while_in(key, isalnum, "-_"); if (end_of_key == key) { error = "No key"; goto err; } if (!*end_of_key) goto exp_equal; /* whitespace, and something else but nothing more? */ s = skip_while(end_of_key, isspace); if (*s != '=') { exp_equal: error = "Expected '=' after key"; goto err; } s++; /* It's my buffer, and I terminate if I want to. */ /* But not earlier than that, because we had to check for = */ *end_of_key = 0; /* Value tokenizing */ s = skip_while(s, isspace); switch (*s) { case '"': case '\'': val = s+1; s = skip_until(val, *s); /* Terminate value */ if (!*s) { error = "Unterminated quoted string"; goto err; } /* Remove and skip quote */ *s = 0; s++; if (*(s = skip_while(s, isspace)) && *s != '#') { error = "Surplus data after value"; goto err; } *s = 0; break; case 0: no_value: error = "No value"; goto err; break; default: val = s; /* Rest of line. */ i = strlen(s); /* i > 0 because of "case 0" above. */ while (i > 0 && isspace(s[i-1])) i--; s += i; *s = 0; } if (val == s) goto no_value; if (strlen(key) > BOOTH_NAME_LEN || strlen(val) > BOOTH_NAME_LEN) { error = "key/value too long"; goto err; } if (strcmp(key, "transport") == 0) { if (got_transport) { error = "config file has multiple transport lines"; goto err; } if (strcasecmp(val, "UDP") == 0) booth_conf->proto = UDP; else if (strcasecmp(val, "SCTP") == 0) booth_conf->proto = SCTP; else { error = "invalid transport protocol"; goto err; } got_transport = 1; continue; } if (strcmp(key, "port") == 0) { booth_conf->port = atoi(val); continue; } if (strcmp(key, "name") == 0) { safe_copy(booth_conf->name, val, BOOTH_NAME_LEN, "name"); continue; } #if HAVE_LIBGCRYPT || HAVE_LIBMHASH if (strcmp(key, "authfile") == 0) { safe_copy(booth_conf->authfile, val, BOOTH_PATH_LEN, "authfile"); continue; } if (strcmp(key, "maxtimeskew") == 0) { booth_conf->maxtimeskew = atoi(val); continue; } #endif if (strcmp(key, "site") == 0) { if (add_site(val, SITE)) goto err; continue; } if (strcmp(key, "arbitrator") == 0) { if (add_site(val, ARBITRATOR)) goto err; continue; } if (strcmp(key, "site-user") == 0) { safe_copy(booth_conf->site_user, optarg, BOOTH_NAME_LEN, "site-user"); continue; } if (strcmp(key, "site-group") == 0) { safe_copy(booth_conf->site_group, optarg, BOOTH_NAME_LEN, "site-group"); continue; } if (strcmp(key, "arbitrator-user") == 0) { safe_copy(booth_conf->arb_user, optarg, BOOTH_NAME_LEN, "arbitrator-user"); continue; } if (strcmp(key, "arbitrator-group") == 0) { safe_copy(booth_conf->arb_group, optarg, BOOTH_NAME_LEN, "arbitrator-group"); continue; } if (strcmp(key, "debug") == 0) { if (type != CLIENT && type != GEOSTORE) debug_level = max(debug_level, atoi(val)); continue; } if (strcmp(key, "ticket") == 0) { if (current_tk && strcmp(current_tk->name, "__defaults__")) { if (!postproc_ticket(current_tk)) { goto err; } } if (!strcmp(val, "__defaults__")) { current_tk = &defaults; } else if (add_ticket(val, ¤t_tk, &defaults)) { goto err; } continue; } /* current_tk must be allocated at this point, otherwise * we don't know to which ticket the key refers */ if (!current_tk) { error = "Unexpected keyword"; goto err; } if (strcmp(key, "expire") == 0) { current_tk->term_duration = read_time(val); if (current_tk->term_duration <= 0) { error = "Expected time >0 for expire"; goto err; } continue; } if (strcmp(key, "timeout") == 0) { current_tk->timeout = read_time(val); if (current_tk->timeout <= 0) { error = "Expected time >0 for timeout"; goto err; } if (!min_timeout) { min_timeout = current_tk->timeout; } else { min_timeout = min(min_timeout, current_tk->timeout); } continue; } if (strcmp(key, "retries") == 0) { current_tk->retries = strtol(val, &s, 0); if (*s || s == val || current_tk->retries<3 || current_tk->retries > 100) { error = "Expected plain integer value in the range [3, 100] for retries"; goto err; } continue; } if (strcmp(key, "renewal-freq") == 0) { current_tk->renewal_freq = read_time(val); if (current_tk->renewal_freq <= 0) { error = "Expected time >0 for renewal-freq"; goto err; } continue; } if (strcmp(key, "acquire-after") == 0) { current_tk->acquire_after = read_time(val); if (current_tk->acquire_after < 0) { error = "Expected time >=0 for acquire-after"; goto err; } continue; } if (strcmp(key, "before-acquire-handler") == 0) { if (parse_extprog(val, current_tk)) { goto err; } continue; } if (strcmp(key, "attr-prereq") == 0) { if (parse_attr_prereq(val, current_tk)) { goto err; } continue; } if (strcmp(key, "mode") == 0) { current_tk->mode = retrieve_ticket_mode(val); continue; } if (strcmp(key, "weights") == 0) { if (parse_weights(val, current_tk->weight) < 0) goto err; continue; } error = "Unknown keyword"; goto err; } fclose(fp); if ((booth_conf->site_count % 2) == 0) { log_warn("Odd number of nodes is strongly recommended!"); } /* Default: make config name match config filename. */ if (!booth_conf->name[0]) { cp = strrchr(path, '/'); cp = cp ? cp+1 : (char *)path; cp2 = strrchr(cp, '.'); if (!cp2) cp2 = cp + strlen(cp); if (cp2-cp >= BOOTH_NAME_LEN) { log_error("booth config file name too long"); goto out; } strncpy(booth_conf->name, cp, cp2-cp); *(booth_conf->name+(cp2-cp)) = '\0'; } if (!postproc_ticket(current_tk)) { goto out; } poll_timeout = min(POLL_TIMEOUT, min_timeout/10); if (!poll_timeout) poll_timeout = POLL_TIMEOUT; return 0; err: fclose(fp); out: log_error("%s in config file line %d", error, lineno); free(booth_conf); booth_conf = NULL; return -1; }
/** * @fn Datum reorg_get_index_keys(PG_FUNCTION_ARGS) * @brief Get key definition of the index. * * reorg_get_index_keys(index, table) * * @param index Oid of target index. * @param table Oid of table of the index. * @retval Create index DDL for temp table. * * FIXME: this function is named get_index_keys, but actually returns * an expression for ORDER BY clause. get_order_by() might be a better name. */ Datum reorg_get_index_keys(PG_FUNCTION_ARGS) { Oid index = PG_GETARG_OID(0); Oid table = PG_GETARG_OID(1); IndexDef stmt; char *token; char *next; StringInfoData str; Relation indexRel = NULL; int nattr; parse_indexdef(&stmt, index, table); elog(DEBUG2, "indexdef.create = %s", stmt.create); elog(DEBUG2, "indexdef.index = %s", stmt.index); elog(DEBUG2, "indexdef.table = %s", stmt.table); elog(DEBUG2, "indexdef.type = %s", stmt.type); elog(DEBUG2, "indexdef.columns = %s", stmt.columns); elog(DEBUG2, "indexdef.options = %s", stmt.options); /* * FIXME: this is very unreliable implementation but I don't want to * re-implement customized versions of pg_get_indexdef_string... * * TODO: Support ASC/DESC and NULL FIRST/LAST. */ initStringInfo(&str); for (nattr = 0, next = stmt.columns; next; nattr++) { char *opcname; token = next; while (isspace((unsigned char) *token)) token++; next = skip_until(index, next, ','); opcname = skip_until(index, token, ' '); if (opcname) { /* lookup default operator name from operator class */ Oid opclass; Oid oprid; int16 strategy = BTLessStrategyNumber; Oid opcintype; Oid opfamily; HeapTuple tp; Form_pg_opclass opclassTup; opclass = OpclassnameGetOpcid(BTREE_AM_OID, opcname); /* Retrieve operator information. */ tp = SearchSysCache(CLAOID, ObjectIdGetDatum(opclass), 0, 0, 0); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for opclass %u", opclass); opclassTup = (Form_pg_opclass) GETSTRUCT(tp); opfamily = opclassTup->opcfamily; opcintype = opclassTup->opcintype; ReleaseSysCache(tp); if (!OidIsValid(opcintype)) { if (indexRel == NULL) indexRel = index_open(index, NoLock); opcintype = RelationGetDescr(indexRel)->attrs[nattr]->atttypid; } oprid = get_opfamily_member(opfamily, opcintype, opcintype, strategy); if (!OidIsValid(oprid)) elog(ERROR, "missing operator %d(%u,%u) in opfamily %u", strategy, opcintype, opcintype, opfamily); opcname[-1] = '\0'; appendStringInfo(&str, "%s USING %s", token, get_opname(oprid)); } else appendStringInfoString(&str, token); if (next) appendStringInfoString(&str, ", "); } if (indexRel != NULL) index_close(indexRel, NoLock); PG_RETURN_TEXT_P(cstring_to_text(str.data)); }
static void parse_indexdef(IndexDef *stmt, Oid index, Oid table) { char *sql = pg_get_indexdef_string(index); const char *idxname = get_quoted_relname(index); const char *tblname = get_relation_name(table); const char *limit = strchr(sql, '\0'); /* CREATE [UNIQUE] INDEX */ stmt->create = sql; sql = skip_const(index, sql, "CREATE INDEX", "CREATE UNIQUE INDEX"); /* index */ stmt->index = sql; sql = skip_const(index, sql, idxname, NULL); /* ON */ sql = skip_const(index, sql, "ON", NULL); /* table */ stmt->table = sql; sql = skip_const(index, sql, tblname, NULL); /* USING */ sql = skip_const(index, sql, "USING", NULL); /* type */ stmt->type = sql; sql = skip_ident(index, sql); /* (columns) */ if ((sql = strchr(sql, '(')) == NULL) parse_error(index); sql++; stmt->columns = sql; if ((sql = skip_until(index, sql, ')')) == NULL) parse_error(index); /* options */ stmt->options = sql; stmt->tablespace = NULL; stmt->where = NULL; /* Is there a tablespace? Note that apparently there is never, but * if there was one it would appear here. */ if (sql < limit && strstr(sql, "TABLESPACE")) { sql = skip_until_const(index, sql, "TABLESPACE"); stmt->tablespace = sql; sql = skip_ident(index, sql); } /* Note: assuming WHERE is the only clause allowed after TABLESPACE */ if (sql < limit && strstr(sql, "WHERE")) { sql = skip_until_const(index, sql, "WHERE"); stmt->where = sql; } elog(DEBUG2, "indexdef.create = %s", stmt->create); elog(DEBUG2, "indexdef.index = %s", stmt->index); elog(DEBUG2, "indexdef.table = %s", stmt->table); elog(DEBUG2, "indexdef.type = %s", stmt->type); elog(DEBUG2, "indexdef.columns = %s", stmt->columns); elog(DEBUG2, "indexdef.options = %s", stmt->options); elog(DEBUG2, "indexdef.tspace = %s", stmt->tablespace); elog(DEBUG2, "indexdef.where = %s", stmt->where); }
int main(void) { int socket_client; int socket_serveur = creer_serveur(8080); initialiser_signaux(); const char* message_bienvenue = "#############################################################\n# #\n# BONJOUR ! #\n# Bienvenue sur le serveur Wichita #\n# #\n# ------ #\n# #\n# Wichita tient son nom d'une langue amérindienne. #\n# Cette langue est en voie de disparition... #\n# ... comme beaucoup d'autres. #\n# #\n# Quoi qu'il en soit, amusez-vous bien avec Wichita ! :-) #\n# #\n#############################################################\n"; const char *bad_request = "HTTP/1.1 400 Bad Request\nConnection: close\nContent-Length: 17\n\n400 Bad Request\n"; const char *connected = "HTTP/1.1 200 OK\nConnection: open\nContent-Length: 80\n\n"; while(1) { socket_client = accept(socket_serveur, NULL ,NULL); if (socket_client == -1) { perror("socket_client accept error"); continue; } if (fork() == 0) { char buffer[BUF_SIZE]; FILE * client_file = fdopen(socket_client, "w+"); if (fgets(buffer, BUF_SIZE, client_file) == NULL) { perror("fgets en-tete"); close(socket_client); exit(EXIT_FAILURE); } printf(buffer); if (http_get_request(buffer) != 0) { fprintf(client_file, "%s", bad_request); fflush(client_file); close(socket_client); exit(EXIT_FAILURE); } else { fprintf(client_file, "%s", connected); fflush(client_file); } skip_until(client_file, "\r\n"); fprintf(client_file, "%s", message_bienvenue); fflush(client_file); while(strcmp("FIN\n", buffer) != 0) { memset(buffer, '\0', strlen(buffer)); if (fgets(buffer, BUF_SIZE, client_file) != NULL) { // writes to the client //fprintf(client_file, "<Wichita> %s", buffer); // writes to the server printf("%s", buffer); } } close(socket_client); break; } else { close(socket_client); } } close(socket_serveur); return EXIT_SUCCESS; }
static void read_attribute_params (EVCardAttribute *attr, char **p, gboolean *quoted_printable) { char *lp; GString *str; EVCardAttributeParam *param = NULL; gboolean in_quote = FALSE; str = g_string_new (""); for( lp = skip_newline( *p, *quoted_printable ); *lp != '\n' && *lp != '\r' && *lp != '\0'; lp = skip_newline( lp, *quoted_printable ) ) { if (*lp == '"') { in_quote = !in_quote; lp = g_utf8_next_char (lp); } else if (in_quote || g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_') { g_string_append_unichar (str, g_utf8_get_char (lp)); lp = g_utf8_next_char (lp); } /* accumulate until we hit the '=' or ';'. If we hit * a '=' the string contains the parameter name. if * we hit a ';' the string contains the parameter * value and the name is either ENCODING (if value == * QUOTED-PRINTABLE) or TYPE (in any other case.) */ else if (*lp == '=') { if (str->len > 0) { param = e_vcard_attribute_param_new (str->str); g_string_assign (str, ""); lp = g_utf8_next_char (lp); } else { skip_until (&lp, ":;"); if (*lp == ';') { lp = g_utf8_next_char (lp); } else if (*lp == ':') { /* do nothing */ } else { skip_to_next_line( &lp ); break; } } } else if (*lp == ';' || *lp == ':' || *lp == ',') { gboolean colon = (*lp == ':'); gboolean comma = (*lp == ','); if (param) { if (str->len > 0) { e_vcard_attribute_param_add_value (param, str->str); g_string_assign (str, ""); if (!colon) lp = g_utf8_next_char (lp); } else { /* we've got a parameter of the form: * PARAM=(.*,)?[:;] * so what we do depends on if there are already values * for the parameter. If there are, we just finish * this parameter and skip past the offending character * (unless it's the ':'). If there aren't values, we free * the parameter then skip past the character. */ if (!param->values) { e_vcard_attribute_param_free (param); param = NULL; if (!colon) lp = g_utf8_next_char (lp); } } if (param && !g_ascii_strcasecmp (param->name, "encoding") && !g_ascii_strcasecmp (param->values->data, "quoted-printable")) { *quoted_printable = TRUE; e_vcard_attribute_param_free (param); param = NULL; } } else { if (str->len > 0) { char *param_name; if (!g_ascii_strcasecmp (str->str, "quoted-printable")) { param_name = "ENCODING"; *quoted_printable = TRUE; } /* apple's broken addressbook app outputs naked BASE64 parameters, which aren't even vcard 3.0 compliant. */ else if (!g_ascii_strcasecmp (str->str, "base64")) { param_name = "ENCODING"; g_string_assign (str, "b"); } else { param_name = "TYPE"; } if (param_name) { param = e_vcard_attribute_param_new (param_name); e_vcard_attribute_param_add_value (param, str->str); } g_string_assign (str, ""); if (!colon) lp = g_utf8_next_char (lp); } else { /* we've got an attribute with a truly empty attribute parameter. So it's of the form: ATTR;[PARAM=value;]*;[PARAM=value;]*: (note the extra ';') the only thing to do here is, well.. nothing. we skip over the character if it's not a colon, and the rest is handled for us: We'll either continue through the loop again if we hit a ';', or we'll break out correct below if it was a ':' */ if (!colon) lp = g_utf8_next_char (lp); } } if (param && !comma) { e_vcard_attribute_add_param (attr, param); param = NULL; } if (colon) break; } else { g_warning ("invalid character found in parameter spec"); g_string_assign (str, ""); /* skip_until (&lp, ":;"); */ skip_to_next_line( &lp ); } } if (str) g_string_free (str, TRUE); *p = lp; }