Mostrando postagens com marcador estrutura. Mostrar todas as postagens
Mostrando postagens com marcador estrutura. Mostrar todas as postagens

sábado, 10 de abril de 2010

Conhecendo as Estruturas de Repetição

Na Ciência da Computação, uma estrutura de repetição é uma estrutura presente nas linguagens de programação, que possibilita repetir a execução de um bloco de comandos em um certo número de vezes, dependendo de uma condição verdadeira ou falsa. Também é conhecida como estrutura de laço.

Os componentes de uma estrutura de repetição são o comando de iteração, a condição de parada (expressão lógica ou expressão de controle) e o bloco de comandos, que geralmente possui delimitadores. Em algumas estruturas a condição é verificada antes do bloco de comandos. Neste caso pode ocorrer nenhuma execução do bloco. Em outras estruturas a condição é verificada após a primeira execução do bloco de comandos. Nesta o bloco é executado pelo menos uma vez.

Caso a condição de parada nunca aconteça, a repetição torna-se infinita, o que é um erro de programação. Em algumas linguagens de programação existem ainda palavras reservadas para sair da estrutura de repetição de dentro do bloco de comandos ("break" em C e "Exit Do" em Visual Basic, por exemplo) e para terminar a iteração atual do bloco de comandos e forçar uma nova verificação da condição ("continue" em C, por exemplo).

O comando "enquanto-faça"

Neste comando a verificação da condição é no início da estrutura, ou seja, antes de entrar no bloco de comandos a expressão lógica é verificada e caso o resultado for verdadeiro, os comandos que estão no bloco são executados. Após a execução dos comandos, a expressão lógica é novamente verificada. Caso o resultado da expressão lógica for falso, o algoritmo sai da estrutura de repetição e segue para a próxima linha.

Geralmente o comando que altera o valor utilizado na condição está inserido dentro do bloco de comandos ou depende de alguma variável externa que será fornecida em tempo de execução. O comando "enquanto-faça" é usado principalmente quando não se sabe com antecedência a quantidade de repetições que precisam ser realizadas.

Sua sintaxe básica em linguagem de algoritmo é:

enquanto <condição> faça
    <bloco de comandos>
fim enquanto

Exemplos em algumas linguagens de programação:

a) C

while(x<=10) {
    <comandos>;
}

b) Pascal

while x<=10 do
begin
    <comandos>;
end;

c) Visual Basic

Do While x<=10
    <comandos>
Loop

O comando "até-faça"

Neste comando a verificação da condição também é no início, ou seja, antes de entrar no bloco de comandos. Entretanto, os comandos que estão no bloco são executados caso o resultado da condição for falso. Após a execução dos comandos, a expressão lógica é novamente verificada. Caso o resultado da expressão lógica for verdadeiro, o algoritmo sai da estrutura de repetição e segue para a próxima linha.

E igualmente ao comando "enquanto-faça", o comando que altera o valor utilizado na condição está inserido dentro do bloco de comandos ou depende de alguma variável externa. O comando "até-faça" também é usado quando não se sabe com antecedência a quantidade de repetições que precisam ser realizadas.

Sua sintaxe básica em linguagem de algoritmo é:

até <condição> faça
    <bloco de comandos>
fim até

Exemplos em algumas linguagens de programação:

a) Visual Basic

Do Until i>10
    <comandos>
Loop

O comando "faça-enquanto"

Neste comando a verificação da condição é no final da estrutura, ou seja, a estrutura "faça-enquanto" difere da estrutura "enquanto-faça" somente por executar o bloco de comandos antes de verificar se a condição é verdadeira. Assim, utilizando o "faça-enquanto" o bloco de comandos é sempre executado pelo menos uma vez, mesmo que a condição seja falsa.

Se a condição for verdadeira o bloco é executado, também o comando de alteração do valor para a condição deve estar dentro do bloco de comandos ou vindo de uma variável externa, e também é usado quando não se sabe com antecedência a quantidade de repetições que precisam ser realizadas.

Sua sintaxe básica em linguagem de algoritmo é:

faça
    <bloco de comandos>
enquanto <condição>

Exemplos em algumas linguagens de programação:

a) C

do {
    <comandos>;
} while(x<=10);

b) Visual Basic

Do
    <comandos>
Loop While i<=10

O comando "faça-até"

Neste comando a verificação da condição é no final da estrutura, ou seja, a estrutura "faça-até" difere da estrutura "até-faça" somente por executar o bloco de comandos antes de verificar se a condição é falsa. Assim, utilizando o "faça-até" o bloco de comandos é sempre executado pelo menos uma vez, mesmo que a condição seja verdadeira.

Se a condição for falsa o bloco é executado, também o comando de alteração do valor para a condição deve estar dentro do bloco de comandos ou vindo de uma variável externa, e também é usado quando não se sabe com antecedência a quantidade de repetições que precisam ser realizadas.

Sua sintaxe básica em linguagem de algoritmo é:

faça
    <bloco de comandos>
até <condição>

Exemplos em algumas linguagens de programação:

a) Pascal

repeat
    <comandos>;
until i>10;

b) Visual Basic

Do
    <comandos>
Loop Until i>10

O comando "para-faça"

A estrutura "para-faça" é composta de um mecanismo de controle que estabelece de antemão quantas vezes a iteração será executada. A estrutura para ser utilizada precisa das informações referentes aos valores de início, fim e incremento do passo. Nesta estrutura, uma determinada variável assumirá valores pertencentes ao intervalo identificado pelos valores de início e fim, respeitando o incremento informado, cujo comando é realizado dentro da própria expressão de controle.

Neste comando a verificação da condição é no início da estrutura e a execução do bloco de comandos é repetida em um número pré-determinado, teoricamente fixo. Quando o valor do fim for alcançado, o algoritmo sai da estrutura de repetição e segue para a próxima linha.

Sua sintaxe básica em linguagem de algoritmo é:

para variável de início até fim passo incremento faça
    <bloco de comandos>
fim parada

Exemplos em algumas linguagens de programação:

a) C

for(i=1; i<=10; i++) {
    <comandos>;
}

b) Pascal

for i:=1 to 10 do
begin
   <comandos>;
end;

c) Visual Basic

For i=1 To 10 Step 1
   <comandos>
Next

Os comandos de iteração não estão todos presentes em todas as linguagens, como percebido pelos exemplos apresentados neste artigo. Um comando ausente em determinada linguagem entretanto pode ser substituído por outro existente, com algumas adaptações na lógica do algoritmo. Este artigo limitou-se em apenas apresentar exemplos nas linguagens C, Pascal e Visual Basic.

quinta-feira, 10 de setembro de 2009

Lista ligada simples

Na Ciência da Computação, uma lista ligada ou lista encadeada é uma estrutura de dados que consiste em uma seqüência de registros de dados, semelhante a um vetor (array), porém em cada registro existe um campo contendo a referência para o próximo registro na seqüência.

Uma característica da lista ligada é ser dinâmica quanto ao seu tamanho em número de elementos, o limite passa a ser o espaço livre na memória, diferentemente de um vetor pois seu tamanho é fixo. Conseqüentemente não há desperdício de memória como existe por exemplo em um vetor com apenas 30% de espaço ocupado e os 70% restantes também consumindo a memória. Possui outra vantagem em relação a um vetor na inserção de um dado no início ou no meio pois não é necessário deslocar os dados à frente. Uma desvantagem é que para ter acesso a um dado é necessário percorrer a lista desde o início.

Cada registro, ou elemento, de uma lista é denominado célula, ou nó, e em uma lista ligada simples a célula é composta por dois campos, um campo que armazena o dado e um campo que armazena o endereço para a próxima célula. O campo dado é uma variável comum de qualquer tipo para armazenar um valor qualquer. O campo que armazena o endereço para o próximo é um ponteiro. A informação fundamental é o início da lista, a partir dele as outras células são acessadas. O último elemento da lista aponta para o nada, para o vazio.

Diversas implementações podem ser acrescentadas em uma lista ligada. A lista pode ser circular, onde o último elemento aponta para o primeiro elemento da lista. A lista pode ser duplamente ligada, deste modo cada célula também contém o endereço da célula anterior. Pode-se ter a informação do endereço da última célula, assim não é necessário percorrer toda a lista para adicionar uma célula no final. A lista pode ser com cabeça, onde existe um "falso" primeiro elemento, que não contém dado e apenas é um ponteiro que contém o endereço da primeira célula, ou até ser uma estrutura especial contendo também o endereço do último elemento. E cada célula da lista pode ter mais de um dado armazenado, por exemplo um pequeno vetor.

Abaixo apresento um exemplo de código, na linguagem C, de um programa capaz de manipular uma lista ligada simples. O código está estruturado em funções que criam, removem, imprimem e contam as células, junto com um menu para a interface com o usuário. O código está preparado para ser compilado no sistema Linux, utilizando a biblioteca nCurses. Para compilar em outro sistema pode ser necessária uma adaptação.

/**
Compilar com o comando:
gcc -o listaligada listaligada.c -lncurses
*/

#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>

#define ESC 27 /* Constante ESC recebe o código da tecla Esc */

struct celula { // Estrutura de cada célula da lista.
int valor; // A célula terá um valor qualquer.
struct celula *prox; // E o endereço para à próxima célula.
};

struct celula *inicio; // Variáveis globais para guardar o início e o fim da lista.
struct celula *ultimo;

int contacelulas() { /** Função que retorna o número de células da lista. */

int cont=0;
struct celula *aux, *pos;

aux = inicio; // Nossa variável auxiliar retorna no início da lista.

while (aux != NULL) { // Enquanto a célula que "aux" se refere não for vazia.
cont++;
pos = aux->prox; // A variável "pos" recebe o endereço da próxima depois da que "aux" se refere.
aux = pos; // A variável auxiliar avança para à próxima célula.
}

return cont;

}

void mostralista() { /** Função que imprime a toda a lista na tela. */

struct celula *aux;

for (aux=inicio; aux!=NULL; aux=aux->prox) // Percorre desde o início usando a variável "aux" para o deslocamento nas células.
printw("%d ", aux->valor); // Imprime o valor contido na célula atual em que "aux" se refere.

printw("(%d)", contacelulas()); // Mudança de linha na tela.

}

void inserecelula(int posicao, int valor){ /** Função que insere (cria) uma célula na posição escolhida. */

int i;
struct celula *aux, *pos;

pos=inicio; // Usaremos a variável "pos" para percorrer a lista desde o início.

if(inicio==NULL) { // Se ainda não existe a lista...

inicio = (struct celula *)malloc(sizeof(struct celula)); // Aloca memória para a primeira célula da lista.
inicio->valor = valor; // Alimenta um valor para esta primeira célula.
inicio->prox = NULL; // Esta primeira célula, como ainda é a única, recebe NULL como endereço para uma próxima.
ultimo = inicio; // Como ainda só temos uma célula então a última é a primeira célula.

} else { // Se já existe a lista...

if(posicao == 1) { // Se vai inserir antes da primeira célula...

aux = (struct celula *)malloc(sizeof(struct celula)); // Aloca memória para a nova célula da lista.
aux->valor = valor; // Alimenta esta nova célula com o valor de parâmetro.
aux->prox = inicio; // Esta nova célula vai apontar para o inicio.
inicio = aux; // O início passa a ser esta célula inserida.

} else if(posicao > contacelulas()) { // Se vai inserir após a última célula...

aux = (struct celula *)malloc(sizeof(struct celula)); // Aloca memória para a próxima célula da lista.
aux->valor = valor; // Esta próxima célula é alimentada com o valor de "valor".
aux->prox = NULL; // E recebe NULL como endereço para uma próxima.
ultimo->prox = aux; // A última célula aponta para esta próxima.
ultimo = aux; // Esta próxima célula passa a ser a última.

} else { // Se não é antes da primeira nem após a última...

for(i=1; i<=posicao-1; i++) { // Percorre da primeira até a célula anterior à posição que receberá uma nova célula.
if(i==posicao-1) { // Se chegamos na posição anterior...
aux = (struct celula *)malloc(sizeof(struct celula)); // Aloca memória para a nova célula da lista.
aux->valor = valor; // Alimenta esta nova célula com o valor de parâmetro.
aux->prox = pos->prox; // Esta nova célula vai apontar para a próxima na qual a anterior estava apontando.
pos->prox = aux; // A célula anterior agora aponta para esta nova célula.
} else // Se ainda não chegamos na posição...
pos = pos->prox; // A variável avança para à próxima célula.

}
}
}
}

void removecelula(int posicao) { /** Função que remove uma célula na posição escolhida. */

int i;
struct celula *aux, *ant;

aux=inicio; // Nossa variável auxiliar retorna no início da lista.

if(inicio!=NULL) { // Se existe a lista...

if(posicao == 1) { // Se vai remover a primeira célula...

inicio = aux->prox; // A variável "inicio" recebe o endereço da próxima depois da que "aux" se refere.
free(aux); // Libera o espaço alocado na memória.

} else if(posicao == contacelulas()) { // Se vai remover a última célula...

for(i=1; i<=posicao; i++) { // Percorre da primeira célula até a posição da célula que será removida.
if(i==posicao-1) { // Se está na célula anterior à que vai ser removida...
ant = aux; // Guardamos ela como sendo a anterior da que será removida.
ant->prox = NULL; // A anterior recebe NULL como endereço para uma próxima.
}
if(i==posicao) { // Se está na célula que será removida...
free(aux); // Libera o espaço alocado na memória.
ultimo = ant; // A última célula agora é a anterior.
} else // Se ainda não chegou na célula à ser removida...
aux = aux->prox; // A variável auxiliar avança para à próxima célula.
}

} else if((posicao > 1) && (posicao < contacelulas())) { // Se não é a primeira nem a última que vai ser removida...

for(i=1; i<=posicao; i++) { // Percorre da primeira célula até a posição da célula que será removida.
if(i==posicao-1) // Se está na célula anterior à que vai ser removida...
ant = aux; // Guardamos ela como sendo a anterior da que será removida.
if(i==posicao) { // Se está na célula que será removida...
ant->prox = aux->prox; // A célula anterior recebe o endereço da próxima depois da que vai ser removida.
free(aux); // Libera o espaço alocado na memória.
} else // Se ainda não chegou na célula à ser removida...
aux = aux->prox; // A variável auxiliar avança para à próxima célula.
}

}
}
}

void limpalista() { /** Função que limpa toda a memória alocada pelas células da lista. */

struct celula *aux;

aux = inicio; // Nossa variável auxiliar retorna no início da lista.

while (aux != NULL) { // Enquanto a célula que "aux" se refere não for vazia.
inicio = aux->prox; // A variável "inicio" recebe o endereço da próxima depois da que "aux" se refere.
free(aux); // Libera a memória alocada para a célula em que "aux" se refere.
aux = inicio; // A variável auxiliar avança para à próxima célula, que passa a ser o início.
}

}

int main() {

initscr(); /* Inicialização do ncurses */
cbreak(); /* Desabilita o buffer do teclado */
echo(); /* Ativa o echo para os caracteres digitados */
clear(); /* Limpa a tela */

char tecla; /* Variável que recebe os comandos para as ações na fila */
int valor; /* Variável que recebe o valor para ser adicionado */
int posicao; /* Variável que recebe a posição para a operação */
int i;
inicio = NULL; /* Ainda não existe uma lista na memória */

while (tecla != ESC) { /* Enquanto não for pressionado Esc é executado o bloco a seguir */

clear(); /* Limpa a tela */
printw("\nOperacoes em Lista Ligada Simples, o que deseja fazer? (ESC sair)"); /* menu inicial */
printw("\n\nOpcoes: (i)nserir");
printw("\n (r)emover");
printw("\n\nConteudo da fila: ");
if(contacelulas() > 0) /* Se a fila não estiver vazia */
mostralista(); /* Imprime todos os valores */
else
printw("vazio");

printw("\n\nDigite a opcao: "); /* Prompt de linha comando */

posicao = contacelulas()+1;
valor = 0;

tecla = getch(); /* Lê a tecla pressionada, comando inserir ou remover */

switch(tecla) {
case 'i': /* Operação de inserção na fila */
printw("\n\nInserir:");
printw(" Em qual posicao? ");
scanw("%d", &posicao); /* Recebe a posição */
printw("\n Qual o valor? ");
scanw("%d", &valor); /* Recebe o valor */
inserecelula(posicao, valor); /* Executa a função */
break;
case 'r': /* Operação de remoção na fila */
printw("\n\nRemover:");
printw(" Qual posicao? ");
scanw("%d", &posicao); /* Recebe a posição */
removecelula(posicao); /* Executa a função */
break;
case ESC: /* Operação de saída com confirmação */
printw("\n\nDeseja sair? s/n ");
if(getch() == 'n')
tecla = 'n'; /* Se não quiser sair então é retirado o Esc da tecla */
break;
}

}

limpalista(); /* Executa a função */
endwin(); /* Finaliza o ncurses */
return 0;

}

sábado, 5 de setembro de 2009

Pilhas e Filas

Em Ciência da Computação, uma estrutura de dados é uma forma particular de armazenamento e organização de dados em um computador de modo que possam ser usados de maneira eficiente. Os algoritmos que representam as estruturas de dados podem ser aplicados em diversas linguagens de programação. As estruturas básicas são a pilha, a fila, a lista e a árvore.

As pilhas são estruturas baseadas no princípio LIFO (last in, first out), na qual os dados que foram inseridos por último na pilha serão os primeiros a serem removidos. Existem duas funções que se aplicam a todas as pilhas: PUSH, que insere um dado no topo da pilha, e POP, que remove um dado do topo da pilha. As duas funções devem respeitar uma o limite de capacidade e a outra o estado vazio da pilha.

As filas são estruturas baseadas no princípio FIFO (first in, first out), em que os primeiros elementos que foram inseridos serão os primeiros a serem removidos. Uma fila possui duas funções básicas: INSERT, que adiciona um dado ao final da fila, e REMOVE, que remove um dado do início da fila. A mesma coisa para fila, as duas funções devem respeitar uma o limite de capacidade e a outra o estado vazio da fila.

Na estrutura de uma pilha devem conter as informações do limite, que indica a última posição disponível, e do topo, que indica a posição do último valor adicionado. E na estrutura de uma fila devem conter as informações do limite, que indica a última posição disponível, e do fim, que indica a posição do último valor adicionado. Em ambas as estruturas os valores são armazenados em vetores comuns.

Abaixo apresento um exemplo de código, na linguagem C, que traz as funções para as operações em pilhas e filas, contendo também uma interface para a escolha da operação. O código está preparado para o ambiente Linux, utilizando a biblioteca nCurses.


/*
* pilhaefila.c
*
* Pequeno programa que demonstra as operações em uma pilha e uma fila.
*
* Compilar com o comando:
* gcc -o pilhaefila pilhaefila.c -lncurses
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>

#define ESC 27 /* constante ESC recebe o código da tecla Esc */

struct pilha{ /* pilha é LIFO, last in first out */
int topo; /* posição do último valor adicionado */
int limite; /* última posição disponível no vetor */
int lista[10]; /* vetor de 0 a 9 */
};

struct fila{ /* fila é FIFO, first in first out */
int limite; /* última posição disponível no vetor */
int fim; /* posição do último valor adicionado */
int lista[10]; /* vetor de 0 a 9 */
};

int push(struct pilha* pi, int valor){ /* função que adiciona valor na pilha*/
if(pi->limite == pi->topo){ /* se o topo já estiver no limite */
printw("\nErro: Pilha cheia!");
printw("\nPressione qualquer tecla para continuar...");
getch();
}
else{
pi->lista[pi->topo+1] = valor; /* o vetor da pilha recebe o valor na posição acima do topo */
pi->topo++; /* o topo é incrementado para corresponder à posição do novo valor */
}
}

int pop(struct pilha* pi){ /* função que retira um valor da pilha*/
int AUX;
if(pi->topo == -1){ /* se a pilha estiver vazia */
printw("\n\nErro: Pilha vazia!");
printw("\nPressione qualquer tecla para continuar...");
getch();
}
else{
AUX = pi->lista[pi->topo]; /* valor a ser retirado da pilha, o de cima */
pi->lista[pi->topo] = 0; /* limpa a posição na qual estava o valor retirado */
pi->topo--; /* decrementa o topo para a posição do valor abaixo */
return AUX;
}
}

int insert(struct fila* fi, int valor){ /* função que adiciona valor na fila*/
if(fi->limite == fi->fim){ /* se o fim já estiver no limite */
printw("\nErro: Fila cheia!");
printw("\nPressione qualquer tecla para continuar...");
getch();
}
else{
fi->lista[fi->fim+1] = valor; /* o vetor da fila recebe o valor na posição atrás do último */
fi->fim++; /* o fim é incrementado para corresponder à posição do novo valor */
}
}

int remover(struct fila* fi){ /* função que retira um valor da fila*/
int AUX, i;
if(fi->fim == -1){ /* se a fila estiver vazia */
printw("\n\nErro: Fila vazia!");
printw("\nPressione qualquer tecla para continuar...");
getch();
}
else{
AUX = fi->lista[0]; /* valor a ser retirado da fila, o primeiro */
for(i = 1; i <= fi->fim; i++){ /* do segundo valor até o último */
fi->lista[i-1] = fi->lista[i]; /* transfere para uma posição à frente */
}
fi->lista[fi->fim] = 0; /* limpa a posição na qual estava o último valor */
fi->fim--; /* decrementa o fim para atualizar a posição do último valor */
return AUX;
}
}

int main(){

initscr(); /* inicialização do ncurses */
cbreak(); /* desabilita o buffer do teclado */
echo(); /* ativa o echo para os caracteres digitados */
clear(); /* limpa a tela */

char tecla; /* variável que recebe os comandos para as ações em pilha e fila */
int valor, /* variável que recebe o valor para ser adicionado */
i;

struct pilha p1; /* estruturação das variáveis tipo pilha e fila */
struct fila f1;

/* inicialização dos valores para topo, fim e limite na pilha e na fila */
p1.topo = -1; /* pilha vazia */
p1.limite = 9; /* última posição no vetor */
f1.fim = -1; /* fila vazia */
f1.limite = 9; /* última posição no vetor */

while (tecla != ESC){ /* enquanto não for pressionado Esc é executado o bloco a seguir */

clear(); /* limpa a tela */
printw("\nOperações em Pilha e Fila, o que deseja fazer? (ESC sair)"); /* menu inicial */
printw("\n\nSintaxe: (p)ilha (p)ush|p(o)p [valor]");
printw("\n (f)ila (i)nsert|(r)emove [valor]");
printw("\n\nEx.: pp45, fi9, po, fr.");
printw("\n\nConteúdo da pilha: ");
if(p1.topo >= 0){ /* se a pilha não estiver vazia */
for(i = 0; i <= p1.topo; i++){ /* da posição 0 até a posição do topo */
printw("%d ", p1.lista[i]); /* imprime todos os valores */
}
} else {
printw("vazio");
}
printw("\nConteúdo da fila: ");
if(f1.fim >= 0){ /* se a fila não estiver vazia */
for(i = 0; i <= f1.fim; i++){ /* da posição 0 até a posição do fim */
printw("%d ", f1.lista[i]); /* imprime todos os valores */
}
} else {
printw("vazio");
}
printw("\n\n> "); /* prompt de linha comando */

tecla = getch(); /* Lê a tecla pressionada, comando pilha ou fila */

switch(tecla){
case 'p': /* operação na pilha */
tecla = getch(); /* Lê a tecla pressionada, comando push ou pop */
switch(tecla){
case 'p': /* chama a função que adiciona um valor */
scanw("%d", &valor); /* recebe o valor */
push(&p1, valor); /* executa a função */
break;
case 'o': /* chama a função que retira um valor */
pop(&p1); /* executa a função */
break;
case ESC: /* operação de saída com confirmação */
printw("\n\nDeseja sair? s/n ");
if(getch() == 'n'){
tecla = 'n'; /* se não quiser sair então é retirado o Esc da tecla */
}
break;
}
break;
case 'f': /* operação na fila */
tecla = getch(); /* Lê a tecla pressionada, comando insert ou remove */
switch(tecla){
case 'i': /* chama a função que adiciona um valor */
scanw("%d", &valor); /* recebe o valor */
insert(&f1, valor); /* executa a função */
break;
case 'r': /* chama a função que retira um valor */
remover(&f1); /* executa a função */
break;
case ESC: /* operação de saída com confirmação */
printw("\n\nDeseja sair? s/n ");
if(getch() == 'n'){
tecla = 'n'; /* se não quiser sair então é retirado o Esc da tecla */
}
break;
}
break;
case ESC: /* operação de saída com confirmação */
printw("\n\nDeseja sair? s/n ");
if(getch() == 'n'){
tecla = 'n'; /* se não quiser sair então é retirado o Esc da tecla */
}
break;
}
}

endwin(); /* Finaliza o ncurses */
return 0;
}