segunda-feira, 14 de setembro de 2009

Configurando Serviços no Linux

Os serviços são programas (daemons) que são iniciados e mantidos em execução em segundo plano, ficam monitorando o computador e respondem às mudanças. Por exemplo o servidor Apache possui um daemon chamado httpd (o d é de daemon) que fica escutando a porta 80 do computador e quando ele recebe uma requisição por uma página, ele envia os dados apropriados para a máquina cliente.

Muitos serviços ficam em execução na maioria do tempo entretanto muitos podem ser seguramente desligados por razões de segurança como também por razões de desempenho. Pode não ser muita a diferença mas o computador é iniciado um pouco mais rápido quando há menos serviços para iniciar.

Existem dois comandos que são usados para controlar os serviços:

/sbin/chkconfig - Este controla quais serviços serão iniciados durante a inicialização da máquina. As mudanças aplicadas por este programa não alterará o estado do serviço imediatamente, apenas deixará marcada a configuração para a próxima inicialização da máquina.

/sbin/service - Este controla o início ou o fim da execução dos serviços imediatamente durante a seção atual, não mantendo para a próxima inicialização da máquina.

Antes vamos conhecer como o sistema Linux organiza o controle dos serviços. Muitas variantes do Unix System V, e isto inclui diversas distribuições do Linux, usam scripts nos diretórios "/etc/rcN.d/" para controlar quais serviços serão iniciados dentre os níveis de execução. Se um serviço deve ser iniciado no nível de execução 5 então é colocado o seu script em "/etc/rc5.d/".

Entretanto este modelo envolve em existir múltiplas cópias do mesmo script em diretórios diferentes, então foi adotado o padrão de colocar todos os scripts de controle dos serviços no diretório "/etc/init.d/", e usar ligações simbólicas para estes scripts nos vários diretórios "/etc/rcN.d/". Isto permitiu a inovação com o comando "chkconfig".

Na distribuição Fedora Linux as ligações e os scripts estão nos diretórios "/etc/rc.d/rcN.d/" e "/etc/rc.d/init.d/", porém é mantido no diretório "/etc/" as ligações simbólicas para estes diretórios, imitando a origem vinda do Unix System V.

Para o comando "chkconfig" poder operar adequadamente, os arquivos dos scripts de controle devem ter seus nomes refletindo o nome do serviço o qual eles controlam. E no inicio de cada script deve existir um cabeçalho com algumas linhas que fazem com que o "chkconfig" entenda que pode controlar a execução.

A principal linha deste cabeçalho é a que especifica os níveis de execução e a ordem de execução dos scripts. Esta linha é semelhante a mostrada abaixo:

# chkconfig: 2345 55 25

O primeiro conjunto de números "2345" indica os níveis no qual o script será executado e "55" e "25" representam a ordem em que o script será executado e parado no nível de execução.

Para adicionar um script e ativar o controle do serviço pelo gerenciamento do "chkconfig" primeiro é preciso colocar o script no diretório "/etc/rc.d/init.d/" e então executar no prompt do terminal o comando "chkconfig --add nome_do_serviço". A partir deste ponto basta executar o comando "chkconfig nome_do_serviço on" para que a devida ligação simbólica seja criada nos diretórios "/etc/rc.d/rcN.d/" especificados no cabeçalho do script. Com a execução do comando "chkconfig nome_do_serviço off" estas ligações são removidas. Do mesmo modo, pode-se remover o controle do serviço pelo gerenciamento do "chkconfig" executando o comando "chkconfig --del nome_do_serviço".

Estas ligações simbólicas existentes dos diretórios "/etc/rc.d/rcN.d/" seguem um padrão em seus nomes. Os nomes iniciam com os caracteres "S" ou "K" (de Start e Kill) seguido do número da ordem de execução (aqueles do cabeçalho), semelhante a algo como por exemplo "S85httpd" ou "K30proftpd".

O comando "chkconfig --list" retorna uma listagem de todos os serviços disponíveis junto com suas respectivas configurações para a inicialização da máquina. Um retorno mais específico pode ser obtido com o comando "chkconfig --list nome_do_serviço". E é possível alterar os níveis definidos no cabeçalho diretamente na linha do comando, por exemplo se no cabeçalho do script estão definidos os níveis 2345 e a linha de comando for "chkconfig --level 35 nome_do_serviço on", somente será criada as ligações simbólicas nos diretórios "/etc/rc.d/rc3.d/" e "/etc/rc.d/rc5.d/".

Estes scripts usualmente atendem aos argumentos "start", "stop", "status" e "restart", do mesmo modo os comandos que controlam os serviços. A execução imediata do serviço pode ser feita com a chamada do próprio script pela linha de comando, em algo como "/etc/rc.d/init.d/nome_do_serviço start". Ou também utilizando o comando "service" em algo como "service nome_do_serviço start". Lembrando que estas formas só funcionam para a seção atual, não mantendo para a próxima inicialização da máquina. O argumento "stop" para o serviço, o argumento "status" mostra a situação atual do serviço e o argumento "restart" reinicia o serviço. O comando "service" pode ir mais além, executando o comando "service --status-all" ele retorna o estado de todos os serviços instalados no sistema.

Uma alternativa para o comando "chkconfig" é o utilitário "ntsysv", que é uma simples interface para configurar os serviços nos níveis de execução. Por padrão ele configura somente no nível de execução atual e para configurar também para algum outro nível é necessário executá-lo com o argumento "--level NNN", por exemplo "ntsysv --level 35" edita os níveis 3 e 5.

Estes comandos são o padrão na distribuição Fedora. As outras distros poderão ter comandos ligeiramente diferentes.

quinta-feira, 10 de setembro de 2009

Controlador de luz através da porta paralela

Há alguns anos saiu nas bancas uma coleção portuguesa chamada Electrónica PC. Eu comprei os números que vieram até a revista sair de linha. Era uma coleção que ensinava hardware, eletrônica digital e vinha com um projeto para montagem. No segundo fascículo veio o "Controlador luminoso através de Centronics".

É um equipamento que faz com que o computador controle oito saídas de energia da rede elétrica, comunicando pela porta paralela. Pode-se programar um software para operar o equipamento usando qualquer linguagem, em qualquer sistema operacional.

Anexado à este fascículo estava esta placa de circuito:





Bastou então adquirir os componentes necessários, que são estes:

8 resistores de 470 ohms.
8 resistores de 1200 ohms.
8 circuitos integrados MOC3011 ou MCP3011.
8 circuitos integrados TIC 226D ou BT 137.
8 terminais de ligação por parafuso para circuito impresso.
1 conector DB-25 macho dobrada para circuito impresso.
1 cabo de 25 condutores.
2 conectores DB-25 para cabo, macho e fêmea.
1 caixa plástica.
8 tomadas fêmea de 220 V.
cabo de ligação à rede, encaixes para CI etc.

Veja as fotos do equipamento montado:





Segundo a revista este equipamento agüenta até 800W por canal, mas os cabos que usei não tem bitola suficiente, então ligo somente lâmpadas de baixa potência.

Com um equipamento desse pode-se automatizar uma residência, ligando e desligando lâmpadas em horários pré-programados, também como televisão, rádio etc. Inclusive pode-se acessar remotamente o computador para modificar o estado das saídas. Pela internet é comum encontrar referências à equipamentos deste tipo como controlador de cafeteira.

Criando funções no Excel com o Visual Basic for Aplications

Além das funções que acompanham o software Excel, nós podemos desenvolver e acrescentar mais funções utilizando o Editor do Visual Basic for Aplications. Uma função é uma seqüência de comandos armazenada em um módulo do VBA. Uma função programada no Editor do VBA pode ser usada diretamente em uma célula, bastando por exemplo digitar =NomeDaFunção(), semelhante a qualquer outra função existente no Excel.

Este artigo descreve os procedimentos para o Excel versão 2003, para as outras versões pode haver alguma diferença.

Para criar uma funcão entre no Editor do VBA em Ferramentas -> Macro -> Editor do Visual Basic. Insira um módulo pelo menu Inserir -> Módulo e insira uma função dentro desse módulo pelo menu Inserir -> Procedimento. Escolha um nome, selecione o tipo Função e o escopo Público, clique OK. Na janela do módulo digite todo o código da sua função dentro do espaço em branco entre o nome da função e seu delimitador final. Salve as mudanças para este módulo e, de volta ao Excel, digite a chamada à função na célula desejada.

Para retornar à edição do código da função, volte no Editor do Visual Basic e na janela "Project Explorer" (menu Exibir) expanda VBAProject e Módulos, clique com o botão direito sobre um módulo e clique "Exibir código" (ou duplo clique sobre o módulo). Faça as alterações que desejar e salve. Para cada vez que o código de uma função for alterado, será necessário executar novamente a função dentro da célula.

Não é possível neste artigo ensinar toda a linguagem VBA, mas é possível apresentar um resumo contendo os principais comandos da linguagem. Assim pelo menos alguma coisa já vai ser possível fazer. Como em diversas linguagens de programação, no VBA existem palavras reservadas que são os comandos da linguagem. Estas palavras devem ser digitadas respeitando as letras maiúsculas e minúsculas e não podem ser usadas como por exemplo para nomes de variáveis.

Um procedimento é um conjunto de instruções, ao qual é atribuído um nome e sua execução feita individualmente num módulo. Existem dois tipos de procedimentos: Sub e Function. A diferença entre estes dois tipos reside no fato de Function poder devolver um valor, o que não acontece com Sub. Este artigo está demonstrando o desenvolvimento e o uso de funções então segue apenas a estrutura de uma Function:

Function nome(arg1,arg2,...) As tipo
Comando 1
Comando 2
...
nome = valor
End Function


Uma função pode receber valores para sua execução, valores vindos de outras células por exemplo, e estes valores entram como argumentos para o nome da função. No invocamento da função na célula usa-se a mesma sintaxe separando os argumentos com ponto-e-vírgula. E para que uma função possa devolver um determinado valor é necessário que uma de suas instruções faça a atribuição ao seu nome.

Todos os valores, numéricos ou não, são armazenados em variáveis. Antes de utilizar uma variável no código é necessário declará-la primeiro, seguindo o modelo:

Dim nome As tipo
Dim nome(1 To n) As tipo


Os tipos podem ser:

Boolean         True ou False
Byte inteiro de 0 até 255
Integer inteiro de -32.768 até 32.767
Long inteiro de -2.147.483.648 até 2.147.483.647
Single ponto flutuante de -3,4E38 e -1,4E-45 até 3,4E38 e 1,4E-45
Double ponto flutuante de -1,798E308 e -4,94E-324 até 1,798E308 e 4,94E-324
Currency ponto flutuante de -923.337.203.685.447,5808 até 922.337.203.685.447,5807
Date 01/01/100 até 31/12/9999 e horas de 0:00:00 até 23:59:59
String até 2 bilhões de caracteres
Error número de erro
Variant suporta todos os tipos


Observação: Uma variável declarada sem tipo, é do tipo Variant e pode conter qualquer valor.

Exemplos de declarações de variáveis:

Dim nome As String
Dim nota1,nota2 As Integer
Dim vetor(1 To 4) As Double
Dim matriz(1 To 5, 1 To 6) As Integer


Para uma variável receber um valor utiliza-se o operador de atribuição. Um operador de atribuição é o que atribui um valor à uma variável e é representado pelo sinal de igual "=". a = b significa a toma o valor de b, exemplos:

x = y
x = a + b
vetor(2) = 7
matriz(1,3) = x*y


Os operadores aritméticos fazem as operações aritméticas entre variáveis e ou valores, eles são:

Adição                 +
Subtração -
Multiplicação *
Divisão /
Inteiro da Divisão \
Potência ^
Resto da Divisão Mod

Exemplos: x/y a^2 a Mod b


No caso de Strings, que são conjunto de caracteres, existe o operador de concatenação & ou +. Então "bom" & "dia" ou "bom" + "dia" retorna "bomdia".

Também é possível comparar os conteúdos das variáveis utilizando os operadores de comparação, os quais retornam como resposta verdadeiro ou falso:

Igualdade               =
Diferença <>
Maior que >
Menor que <
Maior ou igual a >=
Menor ou igual a <=

Exemplos: a = b x >= 6


E diversas comparações podem ser agrupadas por operadores lógicos:

E               And
Ou Or
Ou Exclusivo Xor
Não Not

Exemplos: a = b And a > c x >= 3 Or y <> 7


Existem algumas estruturas de comandos que são para seleção e para repetição de partes do código. Uma estrutura de seleção atende a um retorno de um operador lógico e executa o código referente à resposta. Uma estrutura de repetição pode executar novamente o código, quantas vezes a condição for verdadeira.

Estruturas de Seleção:

If x>y Then            If x>y Or a<>b Then            If (x>y Or a=b) And i>=j Then
Comando 1 Comando 1 Comando 1
Comando 2 Comando 2 Comando 2
... ... ...
End If Else ElseIf x=y Then
Comando 1 Comando 1
Comando 2 Comando 2
... ...
End If Else
Comando 1
Comando 2
...
End If


Select Case x Select Case x
Case 2 Case Is < 2
Comando 1 Comando 1
Comando 2 Comando 2
... ...
Case 4 Case Is = 1, 3 To 5
Comando 1 Comando 1
Comando 2 Comando 2
... ...
Case 6 Case 6 To 8, 10
Comando 1 Comando 1
Comando 2 Comando 2
... ...
Case Else Case Else
Comando 1 Comando 1
Comando 2 Comando 2
... ...
End Select End Select



Estruturas de Repetição:

For i=1 To 10            For i=1 To 10 Step 2            For Each valor In matriz
Comando 1 Comando 1 Comando 1
Comando 2 Comando 2 Comando 2
... ... ...
Next Next Next


Do While x<=y Do Do
Comando 1 Comando 1 If x>y Then
Comando 2 Comando 2 Comandos
... ... Else
Loop Loop While x<=y Exit Do
Loop

Do Until x=y Do
Comando 1 Comando 1
Comando 2 Comando 2
... ...
Loop Loop Until x=y


Exemplo de código de uma função:

Public Function PRIMO(escolhido As Integer) As Long

Dim pos As Integer
Dim num, divisor, nprimo As Long

num = 2
pos = 0

If escolhido < 1 Then
PRIMO = 0
Else
Do While pos < escolhido
divisor = 2
Do While divisor <= num
If divisor = num Then
nprimo = num
pos = pos + 1
Exit Do
ElseIf num Mod divisor = 0 Then
Exit Do
Else
divisor = divisor + 1
End If
Loop
num = num + 1
Loop
PRIMO = nprimo
End If

End Function


A função demonstrada neste exemplo pode ser invocada em uma célula da planilha com o comando =PRIMO(B3), por exemplo. A função receberá o valor contido na célula B3 e a célula que invoca esta função receberá o valor de retorno da função.

O Visual Basic for Aplications proporciona aos usuários uma rica ferramenta para adaptar o Excel às suas necessidades. Assim o usuário não fica limitado aos recursos de fábrica do Excel. Experimente criar algumas funções e se houver interesse aprenda à fundo a linguagem VBA.

O desenvolvimento do núcleo Linux

O núcleo (kernel) que forma o coração do sistema Linux é o resultado de um dos maiores projetos cooperativos de software. Os lançamentos regulares a cada dois ou três meses entregam aos usuários do Linux atualizações estáveis, com novas características significativas, adicionando suporte a novos dispositivos e desempenho melhorado. A taxa de mudanças no núcleo é alta e está crescendo, a cada lançamento do núcleo mais de dez mil remendos (patches) são adicionados. E estes lançamentos contém o trabalho de mais de mil desenvolvedores individuais representando mais de duzentas empresas.

O núcleo Linux é o software de nível mais baixo executando em um sistema Linux. É encarregado de gerenciar o hardware, executar programas dos usuários e manter a segurança e a integridade de todo o sistema. O núcleo é relativamente a menor parte dentre os softwares de todo o sistema Linux, mas é o coração no qual determina como o sistema será executado e é a parte que é verdadeiramente o Linux.

O número de desenvolvedores individuais e de empresas que patrocinam o trabalho do desenvolvimento do Linux vem crescendo a cada lançamento de uma nova versão e a comunidade de desenvolvedores tem dobrado nos últimos três anos.

Sobre o grandioso número de desenvolvedores individuais apenas uma pequena parte faz a maioria do trabalho. Aproximadamente um terço dos desenvolvedores envolvidos contribuem com apenas um remendo. Nos últimos 4,5 anos os dez maiores desenvolvedores individuais contribuíram com 12% do número de mudanças e os trinta maiores tem contribuído com 25%.

O primeiro desenvolvedor do núcleo Linux, o finlandês Linus Torvalds, não está mais entre os trinta maiores desenvolvedores, porém sua contribuição não pode ser mais medida somente pelo número de mudanças realizadas pois o Linus ainda possui uma parte ativa e crucial no processo de desenvolvimento, realizando a organização, revisão e aprovação do código.

Algumas empresas patrocinam o desenvolvimento do núcleo Linux empregando os desenvolvedores individuais. Estas empresas não participam do desenvolvimento do núcleo, são empresas que estão satisfeitas com o andamento e não sentem a necessidade de ajudar o desenvolvimento em uma direção particular. As maiores empresas que patrocinam são a Red Hat, a IBM, a Novell, a Intel e a Oracle. Contudo a maior parte do desenvolvimento do núcleo Linux provém de indivíduos que fazem o trabalho por conta própria, não recebendo contribuições financeiras.

O núcleo Linux é um dos maiores e mais bem sucedidos projetos de software livre de toda a história. A imensa taxa de crescimento do código e do número de desenvolvedores individuais mostra o quanto está vibrante e ativa a comunidade de desenvolvedores. E esta taxa de crescimento está se elevando, aumentando ainda mais o número de desenvolvedores e de empresas envolvidas no processo. Com a expansão do uso do Linux em servidores, desktops e dispositivos embarcados, a expectativa é que continue a crescer.

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;

}

segunda-feira, 7 de setembro de 2009

Problema de Lógica: Pergunta aos guardas verdadeiro e mentiroso

Atenção, resposta logo após a pergunta!

No antigo Egito, havia um prisioneiro numa cela com duas saídas, cada uma delas com um guarda. Cada saída dava para um corredor diferente em que um dava para o campo e, portanto, para a liberdade e o outro para um fosso de crocodilos. Só os guardas sabiam qual a saída certa, mas um deles dizia sempre a verdade e outro mentia sempre. Os guardas se conheciam, isto é, o mentiroso sabia que o outro era verdadeiro e vice-versa. O prisioneiro não sabia nem qual a saída certa nem qual o guarda verdadeiro. Qual a pergunta, e uma só pergunta, que o prisioneiro deveria fazer à um dos guardas ao acaso, para saber qual a porta certa?





RESPOSTA





Pergunta: "Se eu perguntar ao seu colega, qual a porta certa, qual é a que ele me indica?"

Seja qual for o guarda inquirido, a resposta indica sempre a porta errada. Se perguntasse ao guarda verdadeiro, ele indicaria a porta errada pois o mentiroso não indica a porta certa. Se perguntasse ao guarda mentiroso, ele indicaria a porta errada pois o verdadeiro indica a porta certa.

domingo, 6 de setembro de 2009

O Sistema Internacional de Unidades

A metrologia é a ciência da medição, abrangendo todas as medições realizadas num nível conhecido de incerteza, em qualquer domínio da atividade humana. O desenvolvimento e a consolidação da cultura metrológica vêm-se constituindo em uma estratégia permanente das organizações, uma vez que resultam em ganhos de produtividade, qualidade dos produtos e serviços, redução de custos e eliminação de desperdícios. A construção de um senso de cultura metrológica não é tarefa simples, requer ações duradouras de longo prazo e depende não apenas de treinamentos especializados, mas de uma ampla difusão dos valores da qualidade em toda a sociedade.

A necessidade de medir é muito antiga e remonta à origem das civilizações. Por longo tempo cada país, cada região, teve o seu próprio sistema de medidas, baseado em unidades arbitrárias e imprecisas, como por exemplo, aquelas baseadas no corpo humano: palmo, pé, polegada, braça, côvado.

Em 1789, numa tentativa de resolver o problema, o Governo Republicano Francês pediu à Academia de Ciências da França que criasse um sistema de medidas baseado numa "constante natural". Assim foi criado o Sistema Métrico Decimal. Posteriormente, muitos outros países adotaram o sistema, inclusive o Brasil, aderindo à "Convenção do Metro". O Sistema Métrico Decimal adotou, inicialmente, três unidades básicas de medida: o metro, o litro e o quilograma.

O Bureau Internacional de Pesos e Medidas (BIPM) foi criado pela Convenção do Metro, assinada em Paris em 20 de maio de 1875. Funciona sob a fiscalização exclusiva do Comitê Internacional de Pesos e Medidas (CIPM), sob autoridade da Conferência Geral de Pesos e Medidas (CGPM). O Bureau Internacional, que tem por missão assegurar a unificação mundial das medidas físicas, é encarregado de estabelecer os padrões fundamentais e as escalas das principais grandezas físicas, de efetuar a comparação dos padrões nacionais e internacionais, de assegurar a coordenação das técnicas de medidas correspondentes e de efetuar e de coordenar as determinações relativas às constantes físicas que intervêm naquelas atividades.

Entretanto, o desenvolvimento científico e tecnológico passou a exigir medições cada vez mais precisas e diversificadas. Por isso, em 1960, o sistema métrico decimal foi substituído pelo Sistema Internacional de Unidades - SI, mais complexo e sofisticado, adotado também pelo Brasil em 1962 e ratificado pela Resolução nº 12 de 1988 do Conselho Nacional de Metrologia, Normalização e Qualidade Industrial - Conmetro, tornando-se de uso obrigatório em todo o Território Nacional.

As sete unidades de base do SI, fornecem as referências que permitem definir todas as unidades de medida do Sistema Internacional. Com o progresso da ciência e com o aprimoramento dos métodos de medição, torna-se necessário revisar e aprimorar periodicamente as suas definições. Quanto mais exatas forem as medições, maior deve ser o cuidado para a realização das unidades de medida.

As sete grandezas de base, que correspondem às sete unidades de base, são: comprimento, massa, tempo, corrente elétrica, temperatura termodinâmica, quantidade de substância e intensidade luminosa. As grandezas de base e as unidades de base se encontram listadas, juntamente com seus símbolos, na tabela abaixo:

Grandeza de base              Símbolo              Unidade de base       Símbolo

comprimento l, h, r, x metro m
massa m quilograma kg
tempo, duração t segundo s
corrente elétrica I, i ampere A
temperatura termodinâmica T kelvin K
quantidade de substância n mol mol
intensidade luminosa Iv candela cd


Todas as outras grandezas são descritas como grandezas derivadas e são medidas utilizando unidades derivadas, que são definidas como produtos de potências de unidades de base. Exemplos de grandezas derivadas e de unidades derivadas estão listadas abaixo:

Grandeza derivada             Símbolo              Unidade derivada                Símbolo

área A metro quadrado m²
volume V metro cúbico m³
velocidade v metro por segundo m/s
aceleração a metro por segundo ao quadrado m/s²


Algumas unidades derivadas recebem nome especial, sendo este simplesmente uma forma compacta de expressão de combinações de unidades de base que são usadas freqüentemente. Alguns exemplos abaixo:

Grandeza derivada             Nome da unidade      Símbolo da unidade   Expressão

angulo plano radiano radiano m/m = 1
freqüência hertz Hz s^-1
força newton N m kg s^-2
energia, trabalho, calor joule J N m = m^2 kg s^-2
potência watt W J/s = m^2 kg s^-2
diferença de potencial volt V W/A = m^2 kg s^-3 A^-1


Para mais informações e download dos documentos acesse os sites abaixo:

http://www.inmetro.gov.br/consumidor/unidLegaisMed.asp

http://www.bipm.org/en/si/