Redux 101: gerenciadores de estados simplificados
Tags: react, redux, javascript, braziliandevs
Published: 2024-01-03 14:41:51

Estados complexos são um desafio, então você decide usar Redux, mas encontra outro desafio: **_entender o Redux_**. Mas hoje vamos ver tudo que você precisa saber para começar bem com essa ferramenta!

<!-- TOC start -->

## Table of contents
- [O que é o Redux](#o-que-e-o-redux)
- [Quando devo utilizar](#quando-devo-utilizar)
- [Quando não devo utilizar](#quando-não-devo-utilizar)
- [Como funciona o Redux](#como-funciona-o-redux)
   * [Arquitetura Flux](#arquitetura-flux)
   * [Mergulhando no Redux](#mergulhando-no-redux)
      + [Slices](#slices)
      + [Os Reducers](#os-reducers)
- [Mão na massa!](#mão-na-massa)
   * [Funcionalidades](#funcionalidades)
   * [Implementação](#implementação)
      + [1 Preparação](#1-preparação)
      + [2 Criando a Store](#2-criando-a-store)
      + [3 Configurando o Provider](#3-configurando-o-provider)
      + [4 Slices](#4-slices)
      + [5 Reducers](#5-reducers)
   * [Ligado os dados aos componentes!](#ligado-os-dados-aos-componentes)
- [Persistindo dados](#persistindo-dados)
   * [Seletores personalizados](#seletores-personalizados)
- [Redux com NextJs](#redux-com-nextjs)
- [Referências](#referencias)

## O que é o Redux <a name="o-que-e-o-redux"></a>

Basicamente, Redux é uma solução para gerenciar estados, ele brilha de verdade quando temos que lidar com casos mais complexos como estados distribuídos e [Prop Drilling](https://www.alura.com.br/artigos/prop-drilling-no-react-js).

De acordo com a sua [documentação](https://redux.js.org):

>O Redux é um contêiner de estado previsível para aplicativos JavaScript.
>Ele ajuda a escrever aplicativos que se comportam de forma consistente, são executados em diferentes ambientes (cliente, servidor e nativo) e são fáceis de testar.
>Além disso, ele fornece uma ótima experiência de desenvolvedor, como a edição de código ao vivo combinada com um depurador que viaja no tempo.

E realmente, essa biblioteca é bem versátil em trabalhar com outras bibliotecas e frameworks de visualização, tornando uma ótima escolha para trabalhar com gerenciamento de estados.

Contudo, é muito fácil fazer um uso equivocado desta ferramenta, devido a sua popularidade e praticidade, muitos projetos adicionam o Redux automaticamente sem refletir se realmente precisam disso.

## Quando devo utilizar <a name="quando-devo-utilizar"></a>

Como muitas coisas no mundo da tecnologia, o melhor uso do Redux vem quando você percebe sua necessidade na aplicação, e alguns sinais disso são:

- **Complexidade do Estado**:
Se sua aplicação tem um estado complexo, com múltiplos componentes que precisam acessar e modificar esse estado, o Redux pode fornecer uma maneira mais organizada de gerenciar o estado global.

- **Compartilhamento de Estado**:
Quando há a necessidade de compartilhar estado entre componentes que não têm uma relação pai-filho direta, o Redux oferece uma solução centralizada para acessar e modificar o estado.

![imagem de Componentes distantes](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ruhn99wnz9nzmn8iwrbq.png)


- **Prop Drilling**:
Quando existe uma relação pai-filho, mas para passar o estado para o filho desejado você precisa passar por vários componentes filhos até chegar nele.

![imagem de Prop Drilling](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f33vgxvdicqeq51naebs.png)

## Quando não devo utilizar <a name="quando-nao-devo-utilizar"></a>

- **Aplicação pequena ou simples**:
Se sua aplicação é pequena e possui requisitos de gerenciamento de estado simples, a introdução do Redux pode ser excessiva.

- **Curva de Aprendizado da Equipe**:
Se sua equipe não tem familiaridade com o Redux e a curva de aprendizado é um fator crítico, pode ser mais sensato evitar a introdução desta ferramenta, especialmente se os benefícios esperados não justificarem o tempo de aprendizado.

- **Ferramentas Alternativas**:
Existem várias alternativas no que se diz respeito a gerenciar estados no ReactJS, dentre elas podemos citar:

 - [Zustand](https://github.com/pmndrs/zustand)
 - [Recoil](https://recoiljs.org)
 - [MobX](https://mobx.js.org)

Mas existe algo melhor ainda: [React Context](https://react.dev/reference/react/createContext) e [useReducer hook](https://react.dev/reference/react/useReducer)

Nada melhor do que usar as ferramentas nativas do próprio ReactJS para resolver as questões que temos, assim podemos depender de menos bibliotecas externas e tornando nosso projeto mais simples.

Apesar desta abordagem ser algo que eu destaco como ideal, ou pelo menos mais interassante, é assunto para outro artigo, já que hoje vamos falar de Redux.

## Como funciona o Redux <a name="como-funciona-o-redux"></a>

### Arquitetura Flux <a name="arquitetura-flux"></a>

A arquitetura do [Flux](https://facebookarchive.github.io/flux/) foi proposta pelo Facebook para construção de SPAs que divide a aplicação nas seguintes partes:

- **View**: um componente React, ou Angular, etc;
- **Action**: um evento que descreve a mudança que está ocorrendo e carrega os dados necessários;
- **Dispatcher**: responsável por levar os eventos das actions até a `store` responsável;
- **Store**: recebe os eventos e lida com as mudanças de estado.

Importante ressaltar que:
- O estado é imutável, logo não pode ser modificado diretamente;
- A única forma de atualizar o estado é através das actions e dispatchers

Criei um exemplo visual para entendermos como isso funciona:

![arquitura flux](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/raocz91t22byxbsqf5r9.png)

Neste exemplo, temos uma `store` de carrinho de compras chamada `carrinho` e algumas `actions` que representam operações no carrinho.

![exemplo store flux](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lvllu743p9k2hdr5ws1t.png)

Logo depois vamos usar nos nossos componentes React:

![implementação do flux](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ctzbs14t5q26nkwps420.png)

- O componente `Carrinho` está observando a `store`, que contém  a lista de produtos do carrinho;
- O componente `Produto` , bem distante do carrinho, vai acionar a `action` chamada `adicionar ao carrinho`;
- A `action` vai ser recebida pelo `dispatcher` que vai interagir com a `store`;
- A `store` recebe a `action` e atualiza seu estado com o novo produto;
- O carrinho recebe o novo estado e se atualiza.

Se você entendeu este fluxo, praticamente entendeu toda a lógica maior do Redux, pois ele segue fielmente esta arquitetura!
### Mergulhando no Redux <a name="mergulhando-no-redux"></a>

Agora que já falamos sobre a arquitetura por trás de tudo, vamos ver como que o Redux funciona de fato. Vamos ver alguns termos e conceitos a se familiarizar na prática desta ferramenta.
#### Slices <a name="slices"></a>

É importante notar que a store é um estado "global" que contém outros estados, frequentemente chamados de "fatias" ou `slices`, então o nosso estado de carrinho é um `slice`.

![Redux Store](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ttf17sg504p8gyli7eyx.png)

#### Os Reducers <a name="os-reducers"></a>

Temos um novo jogador no campo, os reducers são funções super simples que  são utilizadas para atualizar o estado da aplicação.
Eles tem responsabilidades e escopos muito bem definidos, assim como as actions:

```
function addToCart(state, action) {  
  return {
     cart: [...state.cart, action.product]
  }
}
```

## Mão na massa! <a name="mao-na-massa-"></a>

Nada melhor do que um exemplo de código para entendermos como ligar nossa aplicação ReactJS com o Redux.

Para este propósito fiz o seguinte projeto didático: [React State Management 101](https://github.com/robertheory/react-state-management)

Essa demo é uma loja fictícia onde temos duas funcionalidades básicas para atender: gerenciar favoritos e carrinho de compras.

![print de tela](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xbstv5f3kcox4g4k0n1r.png)

Como nosso intuito aqui é a implementação do Redux, não vamos focar em detalhes como estilização..
### Funcionalidades <a name="funcionalidades"></a>

Antes mesmo de colocar a mão no código, precisamos entender as funcionalidades pretendidas nesta aplicação:

- Favoritar
Adiciona o item à lista de favoritos.
Caso este item já seja um favorito, ele será removido da lista.
- Adicionar ao carrinho
Adiciona este item ao carrinho.
Caso este item já esteja no carrinho, sua quantidade deve ser incrementada.
- Remover do carrinho
Decrementa a quantidade do item no carrinho.
Caso o item tenha apenas 1 de quantidade, é removido do carrinho.
- Deletar do carrinho
Remove completamente o item do carrinho.

### Implementação <a name="implementacao"></a>

Entraremos agora em detalhes de implementação do projeto, contudo não vou demonstrar todas as funcionalidades, apenas a de favoritar para simplificar este exemplo.
#### 1 Preparação <a name="1-preparacao"></a>

Começando do zero em um projeto ReactJS recém criado, execute:

`yarn add @reduxjs/toolkit`
ou
`npm install @reduxjs/toolkit`

Tendo em vista a atual implementação recomendada na documentação do [Redux](https://redux.js.org/), temos uma maneira mais interessante de seguir usando ReactJS: vamos utilizar o [React-Redux](https://react-redux.js.org/), uma forma de interagir melhor com os componentes React usando todo o poder da biblioteca original.

`yarn add react-redux`
ou
`npm install react-redux`

Agora estamos prontos para o primeiro passo: criar a nossa Store!
#### 2 Criando a Store <a name="2-criando-a-store"></a>

A Store é o centro de tudo, a partir dela teremos nossos Slices e usaremos em toda a aplicação, é o coração do gerenciamento de estado.

A partir da documentação oficial do React-Redux, temos o seguinte exemplo de código:

`src/store/index.ts`
```typescript
import { configureStore } from '@reduxjs/toolkit'
// ...

const store = configureStore({
  reducer: {
    posts: postsReducer,
    comments: commentsReducer,
    users: usersReducer,
  },
})

// Infer the RootState and AppDispatch types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
```

Como ainda não temos nenhum Slice, vamos criar assim por enquanto:
`src/store/index.ts`
``` typescript
import { configureStore } from '@reduxjs/toolkit'

const store = configureStore({
  reducer: {},
})


export type RootState = ReturnType<typeof store.getState>

export type AppDispatch = typeof store.dispatch
```

Com a Store criada, agora vamos para o próximo passo: configurar o Provider, assim toda aplicação poderá utilizar o Redux.
#### 3 Configurando o Provider <a name="3-configurando-o-provider"></a>

Este passo é o mais simples, nunca realmente vai mudar, apenas não esqueça pois é crucial.

Seguindo a documentação oficial, envolva o seu App com o Provider do React-Redux e passe para ele a sua Store recém criada.
`src/index.ts`
```typescript
...
import { Provider } from 'react-redux'
import store from './store'
import App from './App'

const root = ReactDOM.createRoot(document.getElementById('root'))

root.render(
  <Provider store={store}>
    <App />
  </Provider>
)
```

Agora chegou a hora de criarmos nossos Slices, através deles teremos nossos estados e reducers que vão fazer a mágica acontecer.
#### 4 Slices <a name="4-slices"></a>

Dentro da pasta `store` vamos criar nosso primeiro e mais simples Slice: `favoritesSlice.ts`

Antes de mais nada, gostaria de demonstrar a anatomia geral de um Slice, o que deve se repetir para todos os próximos:
`src/store/favoritesSlice.ts`
```typescript
import { createSlice } from '@reduxjs/toolkit';
import { RootState } from '.';
import { Movie } from '../interfaces';  

// declarei aqui o estado inicial para que assim pudesse inferir um tipo
// desta forma o slice irá aceitar apenas filmes em seu estado 
const initialState: Movie[] = [];  

export const favorites = createSlice({
	// nome identificador do slice
	name: 'favorites',
	// estado inicial
	initialState,
	reducers: {
		// funções reducers
	},
});

export const { 
	// reducers
} = favorites.actions;

// seletores (é uma forma de buscar dados dentro dos componentes react usando estas funções que podemos criar)
export const getFavorites = () => (state: RootState) => state.favorites;  
// RootState vai dar erro pois este slice ainda não está registrado na store, vamos ver a seguir...

export default favorites.reducer;
```

Como o Slice é apenas uma fatia do estado global, precisamos que ele se integre com a nossa Store criada anteriormente, e para isso faremos o seguinte:

`src/store/index.ts`
```typescript
import { configureStore } from '@reduxjs/toolkit'
import favorites from './favoritesSlice';

const store = configureStore({
  reducer: {
	  favorites // registrar o novo slice na Store
  },
})

// agora o RootState conhece o seu novo slice e deve corrigir o erro anterior
export type RootState = ReturnType<typeof store.getState>

export type AppDispatch = typeof store.dispatch
```

Agora que vimos como é a estrutura geral de uma Store, vamos à criação dos seus Reducers!
#### 5 Reducers <a name="5-reducers"></a>

Vamos criar o reducer de favoritar, e como descrito anteriormente, ele deve funcionar como um botão de liga/desliga, então chamaremos de `toggleFavorite`:
`src/store/favoritesSlice.ts`
```typescript
export const favorites = createSlice({
name: 'favorites',
initialState,
reducers: {
	// state: o estado de favoritos
	// action: a ação que está sendo realizada no slice, que por sua vez contém dados na em action.payload
	toggleFavorite: (state, action: { payload: Movie }) => {
	// a payload é onde podemos passar dados para o nosso reducer
	// neste caso fiz obrigatório o envio de um dado do tipo Movie na payload
		const index = state.findIndex((movie) => movie.id === action.payload.id);  
		
		if (index === -1) {
				state.push(action.payload);
			} else {
				state.splice(index, 1);
			}
		},
	},
});
```

Desta forma nosso primeiro reducer ganha vida, mas ainda não podemos usar ainda, temos que exportá-lo nas nossas actions:
`src/store/favoritesSlice.ts`
```typescript
export const { toggleFavorite } = favorites.actions;
```

E agora sim, nosso slice de favoritos está pronto para ser utilizado!

### Ligado os dados aos componentes! <a name="ligado-os-dados-aos-componentes"></a>

A página de favoritos é super simples, apenas iremos listar todos eles:
`src/pages/favorites/index.tsx`
```typescript
import { useSelector } from 'react-redux';
import Layout from '../../components/Layout';
import MovieCard from '../../components/MovieCard';
import { getFavorites } from '../../store/favoritesSlice';

const Favorites = () => {

	// a função useSelector do react-redux é responsável por interpretar a função getFavorites e retornar os dados
	const favorites = useSelector(getFavorites());
	
	return (
		<Layout>
			<h1>Favorites</h1>
			<div>	
				{favorites.length === 0 ? (
					<p>You don't have any favorite movies</p>
				) : (
					favorites.map((movie) => <MovieCard key={movie.id} movie={movie} />)
				)}
			</div>
		</Layout>
	);
};

export default Favorites;
```

Logo vamos seguir para onde acontece toda ação: no componente `MovieCard.tsx`

`src/components/MovieCard.tsx`
```typescript
import { FiHeart, FiShoppingCart } from 'react-icons/fi';
import { useDispatch, useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import { Movie } from '../interfaces';
import { getFavorites, toggleFavorite } from '../store/favoritesSlice';

type MovieCardProps = {
	movie: Movie;
};  

const MovieCard = ({ movie }: MovieCardProps) => {
	const navigate = useNavigate();

	// aqui utilizamos o useDispatch para que o Dispatcher do Redux possa executar os reducers que passarmos
	const dispatch = useDispatch();

	// novamente buscamos todos os favoritos com o seletor
	const favorites = useSelector(getFavorites());

	const isFavorite = !!favorites.find((fav) => fav.id === movie.id);  

	const handleAddToFavorites = () => {
		// aqui despachamos o reducer toggleFavorite passando os dados do filme em questão
		dispatch(toggleFavorite(movie));
	};  

	const price = new Intl.NumberFormat('en-US', {
		style: 'currency',
		currency: 'USD',
	}).format(movie.price);

	return (
	
	<div>	
		<h2>	
			{movie.title}
		</h2>
		<img src={movie.cover} alt={movie.title}/>
		
		<div>	
			<span className='text-lg font-bold mr-auto'>Price: {price}</span>
			
			<button>	
				<FiShoppingCart size={24} />
			</button>
			
			<button
			onClick={handleAddToFavorites}
			className={isFavorite && 'bg-red-500'}>	
				<FiHeart
					size={24}
					className={isFavorite && 'text-red-500'}
				/>
			</button>
		</div>
		
		<button
		onClick={() => navigate(`/movie/${movie.id}`)}>	
		More
		</button>
		
	</div>
	);
};

export default MovieCard;
```

Agora o componente `MovieCard` é capaz e favoritar os filmes e nossa página de favoritos irá exibi-los, aparentemente está tudo funcionando, mas existe um pequeno problema: *Estados React são reiniciados quando a tela atualiza*.
## Persistindo dados <a name="persistindo-dados"></a>

Uma vez que os dados da nossa Store naturalmente serão jogados fora ao recarregar a página, precisamos que estes dados sejam armazenados localmente no navegador do usuário.

Desta forma mesmo que feche o navegador ou desligue o computador, quando voltar para a aplicação seus favoritos estarão no mesmo lugar onde deixou.

Em alguns casos esta questão é trivial, nem sempre existe a necessidade de armazenar estes dados, mas nesta aqui é super importante que eu persista estes favoritos.

Mas a solução é simples: dentro do reducer, depois que atualizar o estado, utilize o localStore ou sessionStorage para armazenar estes dados no navegador do usuário, e no initialState é só buscar os dados no navegador!

Em teoria sim, isso funciona, mas vai dar um trabalho enorme para implementar isso na mão, fora outras questões que existem.

Mas não tem problema, temos o [Redux-Persist](https://github.com/rt2zz/redux-persist), uma solução completa e simplista para persistir os dados do seu Redux.

Vamos à implementação:

Primeiro instale o pacote:
`yarn add redux-persist`
ou
`npm i redux-persist`

O passo essencial agora é adaptar nossa Store para usar o Redux Persist:
`src/store/index.ts`
```typescript
import { combineReducers, configureStore } from '@reduxjs/toolkit';
import { persistReducer, persistStore } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import cart from './cartSlice';
import favorites from './favoritesSlice';

// configuração básica do redux-persist
const persistConfig = {
	key: 'root',
	// podemos utilizar outras formas de armazenamento, mas a padrão utiliza a localStorage do navegador
	storage,
};

// vamos mudar a forma como recebemos os reducers
// agora combinamos todos os reducers em um único
const rootReducer = combineReducers({
	favorites
});

// o persistedReducer vai comportar dos nossos reducers e com as configurações apropriadas que definimos
const persistedReducer = persistReducer(persistConfig, rootReducer);

// a store é finalmente criada com nosso reducer especial
export const store = configureStore({
	reducer: persistedReducer,
});

// responsável por persistir os dados da store
export const persistor = persistStore(store);

export type RootState = ReturnType<typeof store.getState>;

export type AppDispatch = typeof store.dispatch;
```

E por último, vamos configurar o provider do Redux-Persist:
`src/index.ts`
```typescript
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import { persistor, store } from '../store';

const root = ReactDOM.createRoot(document.getElementById('root'))

root.render(
// o mesmo provider que utilizamos antes
  <Provider store={store}>
  	// agora temos que passar o PersistGate em volta da aplicação
	<PersistGate loading={null} persistor={persistor}>
		<App />
	</PersistGate>
  </Provider>
)
```

Simples assim, agora os dados irão naturalmente persistir no localStorage.

Ainda sim vale a pena que você se familiarize com temas comuns do Redux-Persist como:
- Blacklist: uma lista dos slices que não devem ser permitidos persistir
- Whitelist: uma lista dos únicos slices que devem persistir
- stateReconciler: Os reconciliadores de estado definem como o estado de entrada é mesclado com o estado inicial

Todos estes temas você encontra na 
[documentação oficial do Redux-Persist](https://github.com/rt2zz/redux-persist).
### Seletores personalizados <a name="seletores-personalizados"></a>

Este ponto é bem simples mas ainda sim gostaria de trazer atenção para ele pois seu bom uso é extremamente benéfico no React.

Esta pequena função a seguir faz parte do exemplo dado acima na criação do slice.

`app/store/favoritesSlice.ts`
```typescript
export const getFavorites = () => (state: RootState) => state.favorites;
```

Neste exemplo apenas retornamos todos os favoritos disponíveis no slice, mas podemos realizar diversas modificação de acordo com a necessidade, como por exemplo:

`app/store/favoritesSlice.ts`
```typescript
// passando algum parâmetro
export const getSortedFavorites = (sorting:'asc'|'desc') => (state: RootState) => state.favorites.sort(.../* função para ordenar */);
																		// Editando o retorno													
export const getFormattedFavorites = () => (state: RootState) => state.favorites.map(.../* função para formatar os dados */);
```

## Redux com NextJS <a name="redux-com-nextjs"></a>

Existe um pequeno problema ao utilizar Redux com NextJS:

NextJS é executado no lado do cliente e no lado do servidor, e no lado do servidor *NÃO EXISTE WEB STORAGE*!

Contudo ainda tem solução: 
- Quando a aplicação for executada no lado do cliente utilizaremos o storage padrão;
- Quando a aplicação for executada no lado do servidor utilizaremos o storage fake.

Nossas funções do Redux estão sendo utilizadas apenas no lado do cliente, mas mesmo assim, encontraremos erros em tempo de execução devido a natureza de Server Side Rendering do NextJS.

Logo, vamos criar nosso novo storage:

`src/store/storage.ts`
```typescript
import createWebStorage from 'redux-persist/lib/storage/createWebStorage';

const createNoopStorage = () => {
	return {
		getItem(_key: any) {
			return Promise.resolve(null);
		},
		setItem(_key: any, value: any) {
			return Promise.resolve(value);
		},
		removeItem(_key: any) {
			return Promise.resolve();
		},
	};
};

const storage =
	typeof window !== 'undefined'
		? createWebStorage('local')
		: createNoopStorage();

export default storage;
```

E assim atualizamos a nossa Store:
`src/store/index.ts`
```typescript
...
// importação atualizada
import storage from './storage';

const persistConfig = {
	key: 'root',
	storage,
};
```

Gerenciamento avançado de estados é um tema crucial quando se fala de desenvolvimento web, compreender e utilizar a ferramenta Redux e outros semelhantes me ajudou bastante para desenvolver softwares mais sofisticados e complexos.

Espero que tenham gostado desta super introdução ao tema e à ferramenta.
Se quiser deixar alguma nota, complementar em algo ou se houver alguma ideia interessante, não deixe de compartilhar comigo.

## Referências <a name="referencias"></a>

Dias, D. L. (2022, 20 de fevereiro). Flux: A arquitetura JavaScript que funciona. Medium. [https://dayvsonlima.medium.com/flux-a-arquitetura-javascript-que-funciona-1197857464b8](https://dayvsonlima.medium.com/flux-a-arquitetura-javascript-que-funciona-1197857464b8)

FreeCodeCamp.org. (2022, 2 de agosto). Evite prop drilling em React. FreeCodeCamp.org. [https://www.freecodecamp.org/news/avoid-prop-drilling-in-react/](https://www.freecodecamp.org/news/avoid-prop-drilling-in-react/)

Redux.js.org. (s.d.). Redux. Redux.js.org. [https://redux.js.org/](https://redux.js.org/)

React-redux.js.org. (s.d.). React-redux. React-redux.js.org. [https://react-redux.js.org/](https://react-redux.js.org/)

FreeCodeCamp.org. (2022, 12 de março). O que é Redux store, ações e redutores explicados. FreeCodeCamp.org. [https://www.freecodecamp.org/news/what-is-redux-store-actions-reducers-explained/](https://www.freecodecamp.org/news/what-is-redux-store-actions-reducers-explained/)

GitHub. (s.d.). redux-persist. GitHub. [https://github.com/rt2zz/redux-persist](https://github.com/rt2zz/redux-persist)