Módulo Análise de Sistema

Fazer download em pdf ou txt
Fazer download em pdf ou txt
Você está na página 1de 27

Turma Técnico em Informática - INFNB T1-18.

Módulo – Análise de sistemas.

Apresentação do Módulo:

Objetivos Geral do Módulo


Desenvolver junto ao aluno a capacidade de realizar atividades de projetos de
sistemas, bem como torna-lo apto a empregar metodologias mais utilizadas e atuais
para implementação das atividades mencionadas.
Objetivos Específicos do Módulo
Ao final do curso o aluno terá condições de utilizar as metodologias e técnicas atuais
de projetos de sistemas.
Conteúdo
1. Conhecer os princípios da programação estruturada
2. Técnicas de modularização e refinamento, passo a passo
3. Técnicas de programação top down e botton-up
4. Fundamentos de programação orientada a objetos
5. Modelagem de processo de controle; modelagem de dados; definição de banco
de dados; definição de programas.
6. Etapas de projeto físico; Uso de formulários; Elaboração de layout de relatórios
Referências Bibliográficas
BEZERRA, Eduardo. Príncípios de análise e projetos de sistemas UML. Rio de
janeiro: Campus, 2002. 320p.
Gane, C.; SARSON, T. Análise estruturada de sistemas. Rio de janeiro: LTC,
1995. 258 p.
POMPILHO, S. Análise essencial: Guia prático de análise de sistemas. São Paulo:
Ciência Moderna, 2002, 288 p.
PRESSMAN, Roger S. Engenharia de software. São Paulo: Markron Books, 1995.
TONSIG, Sergio Luiz. Engenharia de software: Análise e projeto de sistemas. São
Paulo: Futura, 2003. 351 p.
YORDO, Edward; ARGILA, Carl. Análise e projetos Orientados a objetos. São
Paulo: Markron Books, 1999. 336 p.
1. Paradigma de programação.

Antes de falarmos de programação estruturada, é necessário entender que ela é um


paradigma de programação. E o que é paradigma de programação? É forma como
determinadas linguagens de programação devem ser utilizadas, como regras, estruturas
e processos que os programadores devem seguir para implementar um programa para
realizar uma solução em software. Paradigma de programação também pode ser
definido com um meio de se classificar as linguagens de programação baseado em
suas funcionalidades. As linguagens de programação podem ser classificadas em
vários paradigmas.

A figura a baixo mostra a estrutura básica e classificação de paradigmas de


programação.

Um paradigma de programação fornece e determina a visão que o programador possui


sobre a estruturação e execução do programa. Por exemplo, em programação
orientada a objetos, os programadores podem abstrair um programa como uma
coleção de objetos que interagem entre si, enquanto em programação funcional os
programadores abstraem o programa como uma sequência de funções executadas
de modo empilhado.
1.1 Classificação do paradigma de programação:

A) Paradigma de programação Funcional: É um paradigma de programação que


trata a computação como uma avaliação de funções matemáticas e que evita estados
ou dados mutáveis. Ela enfatiza a aplicação de funções, em contraste da programação
imperativa, que enfatiza mudanças no estado do programa. Enfatizando as expressões
invés de comandos, as expressões são utilizadas para cálculo de valores com dados
imutáveis. Ex.: Lisp.

B) Paradigma de programação Lógica: É um paradigma de programação que faz uso


da lógica matemática. Ex.: Prolog.

C) Programação Orientado a Objetos (POO): Neste paradigma, modelamos e


construímos sistemas, baseado nos objetos que compõem o mesmo. Como exemplo,
poderíamos pensar em uma aplicação de uma agência bancária como sendo
implementada através de objetos cliente, conta corrente, aplicação financeira e assim
por diante que se relacionam mutuamente. Ex.: C++ e Java.

D) Paradigma de programação estruturada, modular ou procedural: A programação


estruturada, também conhecida como programação modular ou procedural,
estabelece uma disciplina de desenvolvimento de algoritmos que facilita a
compreensão de programas através do número restrito de mecanismos de controle
da execução de programas. Qualquer algoritmo, independentemente da área de
aplicação, de sua complexidade e da linguagem de programação na qual será
codificado, pode ser descrito através destes mecanismos básicos. Ex.: C, Fortran,
Ada, Algol, Basic, Pascal, Python, lua, outros.

A programação estruturada é uma forma de programação de computadores que


estabelece uma disciplina de desenvolvimento de algoritmos, independentemente da
sua complexidade e da linguagem de programação na qual será codificado, que facilita
a compreensão da solução através de um número restrito de mecanismos de
codificação.
2. Algoritmos

Na linguagem humana, algoritmos são simplesmente uma "receita" para executarmos


uma tarefa ou resolver algum problema. E como toda receita, um algoritmo também
deve ser finito. Se seguirmos uma receita de bolo corretamente, conseguiremos fazer o
bolo. A computação utiliza muito esse recurso, então se você pretende aprender
programação, obviamente precisa saber o que é algoritmo. Você já deve ter usado
um algoritmo, só não sabia que era algoritmo, vejamos alguns exemplos simples:

Exemplo 1

Digamos que uma dona de casa irá dar ordens para sua empregada descascar batatas.
A dona de casa passará o seguinte algoritmo para descascar batatas:

Algoritmo descascar batatas

1.Traga a cesta de batatas da dispensa.

2.Traga a panela do armário.

3.Descasque as batatas.

3.Devolva a cesta ao porão.

Exemplo 2:

Quando você acorda pela manhã e precisar sair para o trabalho.

Algoritmo ir para o trabalho

1. Acordar.

2. Toma Banho.

3. Vestir-se.

4. Toma Café.

5. Pega ônibus.

6. Chega no trabalho.
Os exemplos a cima tratam-se de algoritmos simples, onde não há nenhum tipo de
condição, poderíamos aplicar outros passos, replicar outros exemplos de algoritmos,
trocando ou adicionando um novo passo, como por exemplo uma pessoa que vai ao
trabalho de carro e não de ônibus. A complexidade dos algoritmos varia de problema
para problema e existem algumas características a serem estudadas.

2.1 Variáveis

Dentro de um algoritmo, variáveis correspondem a posições de memória do


computador, onde fica armazenado determinado valor. As variáveis são representadas
por identificadores que são cadeias de caracteres alfanumérico.

Matrizes e vetores podem ser representados pelos seus elementos através de índices,
tais como vetor[i] e matriz[i,j].

As linguagens de programação possuem conjuntos enormes de tipos de variáveis, mas


podemos dizer que todos são derivados destas quatro primitivas:

- Inteiro: Representa os números inteiros;

- Real: Qualquer número real;

- Caracter: Variáveis que recebem caracteres.

- Lógico: Recebe valores falso e verdadeiro.

Podemos imaginar que variável é o nome de um local onde será armazenado qualquer
valor do conjunto de valores suportado pelo seu tipo.

- Toda variável deve ser declarada no algoritmo antes de ser utilizada com o
seguinte comando:

- Tipo da Variável: NomeA, NomeB;


Sendo assim, podemos observar na figura a baixo, a estrutura básica de um algoritmo.

Um comando básico que utilizamos muito nos algoritmos é a atribuição, ocorre após a
declaração das variáveis que serão usadas em nossos algoritmos e atribui valores nas
variáveis, veja o comando:

NomeDaVariável = expressão;

Onde a expressão pode ser somente um valor ou uma expressão matemática que utiliza
outros valores e variáveis.

Em resumo as variáveis ou var, são espaços definidos para o nome das variáveis e o
tipo que cada uma é, como por exemplo, posso definir uma variável num1 do tipo inteiro
que irá representar 1 número real inteiro.

2.2 Expressões aritméticas

Para representarmos as expressões aritméticas, utilizamos a notação matemática já


conhecida, logo é importante ressaltar que expressões aritméticas fazem parte dos
algoritmos, mas não são algoritmos. Veja a tabela a baixo:
2.3 Expressões Lógicas:

São expressões cujos resultados são sempre lógicos (Verdadeiro ou Falso), não
dependendo do tipo das variáveis ou expressões utilizadas. Existem operadores
relacionais e operadores lógicos.

Os operadores relacionais fazem a comparação entre valores não lógicos, retornando


um valor lógico e são mostrados na tabela a seguir:

Os operadores lógicos, por outro lado, permitem a combinação de relações cujos


resultados sejam lógicos e são:
2.4 Comandos de entrada e saída

Apesar dos parâmetros de entrada e saída serem especificados logo no início do algorit-
mo, devemos ler e escrever estes parâmetros no algoritmo para podermos utilizá-los.

O comando para leitura de um ou mais parâmetros é o:

Leia (Variável)

Onde a lista de variáveis pode conter qualquer parâmetro de entrada.

Quando o algoritmo termina, ele deve exibir os valores calculados, que estarão
armazenados nas variáveis dos parâmetros de saída. Para isso, devemos utilizar o
comando:

Escreva (resultado variáveis)

Onde a lista de variáveis contém as variáveis dos parâmetros de saída especificados.

É importante ressaltar que na visão computacional os algoritmos possuem uma


representação um pouco diferente a estrutura de algoritmo na visão computacional
também temos, de forma mais intensa, as estruturas condicionais.

2.5 Estruturas Condicionais

O uso de uma estrutura condicional torna possível a escolha dos comandos a serem
executados quando uma certa condição é satisfeita ou não. Esta estrutura permite o
controle de qual código será executado. As estruturas condicionais podem ser simples
ou compostas.

A) Estrutura Condicional Simples:

Esta estrutura é utilizada quando temos que decidir pela execução de um trecho do
algoritmo e possui a forma:

Se (condição lógica) então

(comandos)

Fim se
Nesta estrutura, o trecho (comandos) só será executado se a (condição lógica) for
verdadeira.

B) Estrutura condicional composta:

Esta estrutura é utilizada quando temos que decidir qual de dois caminhos seguir dentro
do algoritmo (somente um dos trechos é executado).

Se (condição lógica) então

(comandos 1)

Senão

(comandos 2)

Fim se

C) Estruturas de repetição

Em cálculo numérico, muitas vezes devemos repetir um trecho do algoritmo diversas


vezes, até que seja atendida uma condição específica.

Nestes casos, utilizamos as estruturas de repetição, que podem ter número definido
ou indefinido de repetições.

Repita

(comandos 1)

se (condição lógica) então

interrompa

fim se

(comandos 2)

Fim repita

(comandos 3)
D) Número definido de repetições

Quando o número de repetições a ser executado é conhecido, usamos a seguinte


estrutura:

Para (controle) = (valor inicial) até (valor final) faça

<comandos>

Fim para

Vejamos agora exemplos de algoritmos com estruturas apresentadas a cima.

Exemplo 1.

Algoritmo Ligar luz

Inicio

1 – Lâmpada não liga.

2 – A lâmpada está enroscada?

Se a lâmpada não está enroscada Então

3 – Enroscar lâmpada.

4 – Senão se verificar se a lâmpada está queimada Então

5 – Trocar lâmpada.

Senão

6 – Verificar instalação elétrica.

Fim-Se

Fim
Exemplo 2: Imagine o trabalho de um recepcionista de cinema, ele deve conferir os
bilhetes e direcionar o cliente para a sala correta. Além disso, se o cliente estiver 30
minutos adiantado o recepcionista deve informar que a sala do filme ainda não está
aberta. E quando o cliente estiver 30 minutos atrasado o recepcionista deve informar
que a entrada não é mais permitida.

Algoritmo Recepcionista de Cinema

Inicio

1 - Solicitar ao cliente o bilhete do filme.

2 - Conferir a data e o horário do filme no bilhete.

Se data/hora atual > data/hora do filme + 30 minutos Então

3 - Informar ao cliente que o tempo limite para entrada foi excedido.

4 - Não permitir a entrada.

Senão Se data/hora atual < data/hora do filme - 30 minutos Então

5 - Informar ao cliente que a sala do filme ainda não foi liberada para entrada.

6 - Não permitir a entrada.

Senão

7 - Permitir a entrada.

8 - Indicar ao cliente onde fica a sala do filme.

Fim-Se

Fim
Exemplo 3:
Algoritmo multiplicação de dois números
Var: num1, num2, result
Inicio
ler(num1)
ler(num2)
resultado <- num1 * num2
Fim

Exemplo 4:
Algoritmo maior e menor valor literal
Var: a, b, c: inteiro
Inicio
a = 100, b = 90 c=80
Se a >= b e a >= c Então
a é maior
Senão Se b >= a e b >= c Então
b é maior
senão
c é maior
fim se
Fim
Exemplo 4:

Algoritmo média de aluno

var

nome_aluno : caracter

n1,n2,n3,n4 : real

soma : real

media : real

inicio

escreva("Digite o Nome do Aluno: ")

leia(nome_aluno)

escreva("Digite a primeira nota: ")

leia(n1)

escreva("Digite a segunda nota: ")

leia(n2)

escreva("Digite a terceira nota: ")

leia(n3)

escreva("Digite a quarta nota: ")

leia(n4)

soma <-(n1+n2+n3+n4)

media<-(soma/4)

escreva(media)

fim
2.6 Fluxogramas

Existe outra forma de representar os algoritmos, essa forma chama-se de fluxogramas.


Os fluxogramas seguem o mesmo intuito, demostrar o passo a passo de uma
determinada ação, só que através de símbolos, eles representam até as condições
aplicadas nas ações.

Os fluxogramas possuem na sua estrutura as seguintes características:

Agora vamos verificar como os fluxogramas funcionam através de exemplos.


Exemplo 1

Fluxograma Lâmpada não liga:


Exemplo 2

Fluxograma recepcionista de cinema:

Exemplo 3

Fluxograma- inserir número ou letra:


3. Mecanismos básicos da programação estruturada

O princípio básico de programação estruturada é que um programa é composto por


blocos elementares de código que se interligam através de três mecanismos básicos,
que são sequência (Sequencial), seleção (Condicional) e iteração (Repetição).
Cada uma destas construções tem um ponto de início (o topo do bloco) e um ponto de
término (o fim do bloco) de execução.

Para entender o mecanismo básico da programação estruturada, precisamos entender


um pouco sobre algoritmos. Por isso tornou-se extremamente necessário o nosso
estudo sobre o assunto. As estruturas de sequência, seleção e iteração permitem
representar a solução de qualquer algoritmo. E é por esse motivo que elas são
tão importantes no seu aprendizado de construção de algoritmos.

3.1 Estrutura de controle de sequência (sequencial)

são estruturas onde há um grupo de comandos que são executados um após o outro,
permitindo a escolha do grupo de ações e estruturas a serem executados quando
determinadas condições, representadas por expressões lógicas, são ou não satisfeitas.
Ou seja, essa estrutura é usada quando a execução de um ou mais comandos só poderá
ser realizada dependendo de um ou mais testes anteriores. E esses testes são
condições lógicas que resultarão VERDADEIRO ou FALSO. Se o resultado da
expressão lógica for FALSO, então o grupo de comandos que dependia desse teste
para ser executado não será executado. É por isso que se deve prestar bastante
atenção aos testes que forem construídos num algoritmo, pois, se o retorno não for
adequado à solução proposta, isso comprometerá o resultado final do algoritmo. As
estruturas de seleção podem ser simples ou compostas, como é mostrado na tabela
abaixo. Por fim, as estruturas de controle de iteração ou repetição permitem que uma
sequência de comandos seja executada repetidamente até que uma determinada
condição de interrupção seja satisfeita. Veja como funciona:
3.2 Estrutura de controle de seleção (Condicional)

Podemos dividir a estrutura de controle de seleção condicional em estrutura de seleção


condicional simples e estrutura de seleção condicional composta. A primeira é
aquela em que a execução de um ou mais comandos depende de uma condição
verdadeira apenas, não tendo comandos a executar se a condição for falsa. Já a
composta é aquela que tem comandos a serem executados quando a condição for
verdadeira ou falsa. Na seleção composta, podemos utilizar estruturas aninhas e de
múltipla escolha. Primeiramente vamos ver como se comportam as estruturas simples
e compostas:
3.2.1 Estrutura de controle de seleção condicional aninhada

E quando possuímos mais de um teste lógico a realizar para decidir qual tarefa a ser
realizada pelo algoritmo? Nesse caso precisamos utilizar a estrutura aninhada. Não
temos um teste lógico que retorna verdadeiro ou falso na estrutura aninhada. Nessa
estrutura possuímos uma sequência de teste lógicos encadeados que deve ser
realizado, onde um bloco de código vai ser realizado na sequência, vai depender da
sequência de testes lógicos e seus resultados. Veja a figura abaixo, ela demonstra um
exemplo de algoritmo com estrutura aninhada, perceba que precisamos escolher entre
3 sequências lógicas encadeadas e o bloco de código a ser executado vai depender dos
resultados dos testes lógicos.
3.2.2 Estrutura de controle de seleção condicional múltipla escolha.

Outra estrutura de controle de seleção condicional que é bastante usada é a de escolha


múltipla. O uso dessa estrutura é indicado quando é necessário optar por uma opção
entre várias para uma certa variável. Seria possível usar uma estrutura do tipo se-então-
senão aninhadas, mas se o algoritmo puder ficar mais claro e objetivo, a estrutura de
escolha múltipla é a opção a ser escolhida. Essa estrutura possui uma expressão de
seleção e a partir dela é feita a escolha de um dos casos para serem executados os
comandos associados a ele. Se nenhum caso atender à expressão de seleção, há a
opção de inserir uma situação genérica com o uso de outro caso. Nessa estrutura, em
geral, os demais comandos que estão associados aos outros casos, não serão
executados, mas é importante ressaltar que esse aspecto pode ser alterado em algumas
linguagens de programação quando não se insere um comando de interrupção, e isso
apresenta uma flexibilidade bastante prática a esse tipo de estrutura. Na figura a baixo
podemos observar um exemplo do uso de escolha múltipla.
3.3 Estrutura de controle de iteração (Repetição)

A estrutura de controle de iteração pode ser classificada por condição e por contagem.
Na estrutura de repetição por condição temos a realização de testes que repetem
diferentes comandos ou ações dependendo se uma condição seja verdadeira ou falsa,
condição essa que é uma expressão processada e transformada em um valor booleano.
Está associado a ela além da condição (também chamada "expressão de controle" ou
"condição de parada") o bloco de código: verifica-se a condição, e caso seja verdadeira,
o bloco é executado. Após o final da execução do bloco, a condição é verificada
novamente, e caso ela ainda seja verdadeira, o código é executado novamente.

Deve-se observar que, caso o bloco de código nunca modificar o estado da condição, a
estrutura será executada para sempre, uma situação chamada laço infinito. Da mesma
forma, é possível especificar uma estrutura em que o bloco de código modifica o estado
da condição, mas esta é sempre verdadeira.

Algumas linguagens de programação especificam ainda uma palavra reservada para


sair da estrutura de repetição de dentro do bloco de código, "quebrando" a estrutura.
Também é oferecido por algumas linguagens uma palavra reservada para terminar uma
iteração específica do bloco de código, forçando nova verificação da condição. Veja
como essa estrutura se comporta:
Na iteração baseada em contagem, sabe-se antecipadamente quantas vezes um
conjunto de comandos vai ser repetido.

Para variável de valor_inicial até valor_final

passo valor_do_passo faça

comandos

fim para

Inicialmente a variável, que chamamos de variável controladora, é inicializada com o


valor_inicial. Devem ser do tipo inteiro. Em seguida, os comandos são repetidos zero
ou mais vezes, enquanto o valor da variável estiver entre o valor_inicial e o valor_final,
inclusive. No final de cada repetição do conjunto de comandos, a variável controladora
é automaticamente acrescida do valor_do_passo e o teste do limite é repetido.

Algoritmo conta_com_para

Variável

n, i: inteiro

leia(n)

Para i de 1 até n passo 1 faça

escreva(i)

fim para fim

4. Refinamento sucessivo passo a passo

Cotidianamente, os algoritmos são encontrados frequentemente em instruções para se


utilizar um aparelho eletrodoméstico, uma receita para preparo de algum prato, o guia
de preenchimento da declaração de Imposto de renda, a regra para determinação de
máximos e mínimos de funções por derivadas sucessivas, a maneira como as contas
de água, luz, telefone são calculadas mensalmente.
Um algoritmo é considerado completo se os seus comandos forem do entendimento do
seu destinatário.

Num algoritmo, um comando que não for do entendimento do destinatário terá de ser
desdobrado em novos comandos, que constituirão um refinamento do comando inicial.

Se um algoritmo é formado não apenas por um comando, mas por vários, isto significa
que na sua execução não se consideram apenas o estado inicial e o final de uma ação
dele resultante, mas que se consideram também estados intermediários que delimitam
as ações decorrentes de cada comando.

Vamos toma como exemplo o algoritmo que descreve os termos de Fibonacci


inferiores a L:

Agora vamos aplicar a técnica de refinamento passo a psso neste algoritmo e verificar
como ele fica:
Ref. Escreva os termos de Fibonacci inferiores a L

Receba o valor L

Processe os 2 primeiros termos

Processe os termos restantes

Fim ref

Um refinamento será sempre iniciado com a palavra Ref, seguida do comando refinado
e terminará com a expressão fim ref.
Um algoritmo e os seus refinamentos são formados por comandos que determinam as
ações a serem executadas pelo seu destinatário e por estruturas de controle que
determinam a ordem em que os comandos devem ser executados, se devem ser
executados ou não e quando devem ser repetidos.

No refinamento acima vigora a mais simples das estruturas de controle: a estrutura


sequencial, segundo a qual os comandos devem ser executados um após o outro, na
mesma ordem em que aparecem escritos.

Se um comando de um refinamento for um tanto vago. ele poderá, por sua vez, ser
desdobrado em novos comandos, produzindo-se o refinamento de um refinamento. e
assim sucessivamente. Portanto, o comando "Processe os 2 primeiros termos"
poderia ser desdobrado em:

Ref. Processe os 2 primeiros termos

Atribua o valor 1 ao primeiro termo

Se ele for menor que L

Então escreva-o

Fim se
Atribua o valor 1 ao segundo termo

Se ele for menor que L

Então escreva-o

Fim se

Fim ref

Neste refinamento, aparece uma segunda estrutura de controle: a estrutura condicional

Se condição

Então comandos

Fim se

o comando "escreva-o" só será executado se a condição "ele for menor que L" for
verdadeira. O comando "escreva-o" não será executado se a condição for falsa, isto é,
se ele for maior ou igual a L.
Vê-se, portanto, que um algoritmo, através de estruturas condicionais, pode provocar
ou não a realização de uma ação.
Uma terceira estrutura de controle, a estrutura de repetição, será necessária ao se
desdobrar o comando "Processe os termos restantes", através do novo refinamento:
Ref. Processe os termos restantes
Repita
Calcule novo termo somando os 2 anteriores
Se novo termo for maior ou igual a L
Então interrompa
Fim se
Escreva novo termo
fim repita
fim ref

pag 20
5. Técnicas de modularização

No fim da década de 60, um conjunto de problemas no desenvolvimento de sistemas de


programação levou os países desenvolvidos a chamada "crise de software". Os custos
das atividades de programação mostravam a cada ano uma clara tendência a se
elevarem muito em relação aos custos dos equipamentos. Essa tendência era devida,
em grande parte, ao rápido avanço tecnológico na fabricação dos equipamentos de
computação, em contrapartida com a lenta evolução das técnicas aplicadas ao
desenvolvimento de software.

Ausência de uma metodologia para a construção de programas conduz a um software


geralmente cheio de erros e com alto custo de desenvolvimento que consequentemente
exige um custo elevado para sua correção e manutenção futuras.

A programação estruturada é hoje o resultado de uma série de estudos e propostas de


disciplinas e metodologias para o desenvolvimento de software. Conceitos associados
como técnica de refinamentos sucessivos e modularização de programas integram
o ferramental para a elaboração de programas visando, principalmente, os aspectos de
confiabilidade, legalidade manutenibilidade e flexibilidade.

Pode-se reunir as ideias da programação estruturada em três grupos:

A) Desenvolvimento de algoritmos por fases ou refinamentos sucessivos;

B) Uso de um número muito limitado de estruturas de controle;

B) Transformação de certos refinamentos sucessivos em módulos.

O desenvolvimento de algoritmo por refinamentos sucessivos e o uso de número


limitado de estruturas de controle são técnicas largamente usadas nos capítulos
anteriores do presente texto.

Quando se desenvolve um algoritmo através de refinamentos sucessivos. faz-se uma


opção pela divisão do algoritmo, este procedimento conduz a modularização da solução
do problema.
Um módulo é, então, um grupo de comandos, constituindo um trecho de algoritmo com
uma função bem determinada e o mais independente possível em relação ao resto do
algoritmo.

Assim sendo, ao se elaborar um algoritmo para calcular o salário líquido de um


empregado tem-se as seguintes etapas:

Você também pode gostar

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy