Codelab do Firebase Angular Web Frameworks

1. O que você vai criar

Neste codelab, você criará um blog de viagens com um mapa colaborativo em tempo real com as novidades da biblioteca do Angular: o AngularFire. O app da Web final será um blog de viagens onde você pode fazer upload de imagens para cada local que visitou.

O AngularFire será usado para criar o app da Web, o Pacote de emuladores para testes locais, o Authentication para rastrear dados de usuários, o Firestore e o Storage para manter dados e mídia, com tecnologia do Cloud Functions e, por fim, o Firebase Hosting para implantar o app.

Conteúdo

  • Como desenvolver localmente com produtos do Firebase usando o Pacote de emuladores
  • Como aprimorar seu app da Web com o AngularFire
  • Como manter seus dados no Firestore
  • Como persistir mídia no Storage
  • Como implantar o app no Firebase Hosting
  • Como usar o Cloud Functions para interagir com bancos de dados e APIs

Pré-requisitos

  • Node.js versão 10 ou mais recente
  • Uma Conta do Google para a criação e o gerenciamento do seu projeto do Firebase
  • A CLI do Firebase versão 11.14.2 ou mais recente
  • em um navegador da sua escolha, como o Chrome;
  • Noções básicas de Angular e JavaScript

2. Acessar o exemplo de código

Clone o repositório do GitHub do codelab na linha de comando:

git clone https://github.com/firebase/codelab-friendlychat-web

Se você não tiver o git instalado, faça o download do repositório como um arquivo ZIP (link em inglês).

O repositório do GitHub contém projetos de amostra para várias plataformas.

Este codelab usa apenas o repositório webframework:

  • 📁 webframework: o código inicial que será usado como base durante este codelab.

Instalar dependências

Após a clonagem, instale as dependências nas pastas raiz e functions antes de criar o app da Web.

cd webframework && npm install
cd functions && npm install

Instalar a CLI do Firebase

Instale a CLI do Firebase usando este comando em um terminal:

npm install -g firebase-tools

Verifique se a versão da CLI do Firebase é mais recente que 11.14.2 usando:

firebase  --version

Se sua versão for anterior à 11.14.2, atualize-a usando:

npm update firebase-tools

3. Criar e configurar um projeto do Firebase

Criar um projeto do Firebase

  1. Faça login no Firebase.
  2. No console do Firebase, clique em Adicionar projeto e nomeie seu projeto do Firebase como <your-project>. Lembre-se do ID do seu projeto do Firebase.
  3. Clique em Criar projeto.

Importante: seu projeto do Firebase será chamado <your-project>, mas o Firebase atribuirá automaticamente a ele um ID de projeto exclusivo no formato <your-project>-1234. Esse identificador exclusivo é como seu projeto é realmente identificado (inclusive na CLI), enquanto <your-project> é simplesmente um nome de exibição.

O aplicativo que criaremos usa produtos do Firebase disponíveis para apps da Web:

  • Firebase Authentication: usado para permitir que os usuários façam login no seu app com facilidade.
  • Cloud Firestore: é usado para salvar dados estruturados na nuvem e receber notificações instantâneas quando os dados são alterados.
  • Cloud Storage para Firebase: é usado para salvar arquivos na nuvem.
  • Firebase Hosting: é usado para hospedar e exibir seus recursos.
  • Funções para interagir com APIs internas e externas.

Alguns desses produtos precisam de configurações especiais ou ser ativados usando o Console do Firebase.

Adicionar um app da Web do Firebase ao projeto

  1. Clique no ícone da Web para criar um app da Web do Firebase.
  2. Na próxima etapa, você verá um objeto de configuração. Copie o conteúdo desse objeto no arquivo environments/environment.ts.

Ative o Login do Google para o Firebase Authentication.

Para permitir que os usuários façam login no app da Web com as próprias Contas do Google, usaremos o método de login do Google.

Para ativar o Login do Google:

  1. No Console do Firebase, localize a seção Build no painel esquerdo.
  2. Clique em Autenticação e na guia Método de login (ou clique aqui para acessá-la).
  3. Ative o provedor de login do Google e clique em Salvar.
  4. Defina o nome público do app como <your-project-name> e escolha um E-mail de suporte do projeto no menu suspenso.

Ativar o Cloud Firestore

  1. Na seção Build do Console do Firebase, clique em Firestore Database.
  2. Clique em Criar banco de dados no painel do Cloud Firestore.
  3. Defina o local em que os dados do Cloud Firestore são armazenados. Mantenha essa configuração como padrão ou escolha uma região próxima a você.

Ativar o Cloud Storage

O app da Web usa o Cloud Storage para Firebase para armazenar, fazer upload e compartilhar imagens.

  1. Na seção Build do Console do Firebase, clique em Armazenamento.
  2. Se não houver um botão Get Started, isso significa que o Cloud Storage já está

ativado, e você não precisa seguir as etapas abaixo.

  1. Clique em Começar.
  2. Leia a exoneração de responsabilidade sobre as regras de segurança do seu projeto do Firebase e clique em Próxima.
  3. O local do Cloud Storage é pré-selecionado com a mesma região que você escolheu para seu banco de dados do Cloud Firestore. Clique em Concluído para finalizar a configuração.

Com as regras de segurança padrão, qualquer usuário autenticado pode gravar o que quiser no Cloud Storage. Vamos tornar nosso armazenamento mais seguro mais adiante neste codelab.

4. Conectar ao seu projeto do Firebase

A interface de linha de comando (CLI) do Firebase permite usar o Firebase Hosting para disponibilizar seu app da Web localmente e implantá-lo no projeto do Firebase.

Confira se a linha de comando está acessando o diretório local webframework do app.

Conecte o código do app da Web ao seu projeto do Firebase. Primeiro, faça login na CLI do Firebase na linha de comando:

firebase login

Em seguida, execute o seguinte comando para criar um alias de projeto. Substitua $YOUR_PROJECT_ID pelo ID do seu projeto do Firebase.

firebase  use  $YOUR_PROJECT_ID

Adicionar o AngularFire

Para adicionar o AngularFire ao app, execute o comando:

ng add @angular/fire

Em seguida, siga as instruções da linha de comando e selecione os recursos que existem no seu projeto do Firebase.

Inicializar o Firebase

Para inicializar o projeto do Firebase, execute:

firebase init

Em seguida, seguindo os prompts da linha de comando, selecione os recursos e emuladores que foram usados no seu projeto do Firebase.

Iniciar os emuladores

No diretório webframework, execute o seguinte comando para iniciar os emuladores:

firebase  emulators:start

Futuramente, você vai encontrar algo assim:

$  firebase  emulators:start

i  emulators:  Starting  emulators:  auth,  functions,  firestore,  hosting,  functions

i  firestore:  Firestore  Emulator  logging  to  firestore-debug.log

i  hosting:  Serving  hosting  files  from:  public

✔  hosting:  Local  server:  http://localhost:5000

i  ui:  Emulator  UI  logging  to  ui-debug.log

i  functions:  Watching  "/functions"  for  Cloud  Functions...

✔  functions[updateMap]:  firestore  function  initialized.

  

┌─────────────────────────────────────────────────────────────┐

│  ✔  All  emulators  ready!  It  is  now  safe  to  connect  your  app.  │

│  i  View  Emulator  UI  at  http://localhost:4000  │

└─────────────────────────────────────────────────────────────┘

  

┌────────────────┬────────────────┬─────────────────────────────────┐

│  Emulator  │  Host:Port  │  View  in  Emulator  UI  │

├────────────────┼────────────────┼─────────────────────────────────┤

│  Authentication  │  localhost:9099  │  http://localhost:4000/auth  │

├────────────────┼────────────────┼─────────────────────────────────┤

│  Functions  │  localhost:5001  │  http://localhost:4000/functions  │

├────────────────┼────────────────┼─────────────────────────────────┤

│  Firestore  │  localhost:8080  │  http://localhost:4000/firestore  │

├────────────────┼────────────────┼─────────────────────────────────┤

│  Hosting  │  localhost:5000  │  n/a  │

└────────────────┴────────────────┴─────────────────────────────────┘

Emulator  Hub  running  at  localhost:4400

Other  reserved  ports:  4500

  

Issues?  Report  them  at  https://github.com/firebase/firebase-tools/issues  and  attach  the  *-debug.log  files.

Depois que a mensagem ✔All emulators ready! aparecer, os emuladores estarão prontos para uso.

Você verá a interface do seu app de viagens, que (ainda) não está funcionando:

Agora vamos criar!

5. Conectar o app da Web aos emuladores

Com base na tabela dos registros do emulador, o emulador do Cloud Firestore está escutando na porta 8080 e o emulador do Authentication está escutando na porta 9099.

Abrir a EmulatorUI

No navegador da Web, acesse http://127.0.0.1:4000/. A IU do Pacote de emuladores é exibida.

Encaminhar o app para usar os emuladores

Em src/app/app.module.ts, adicione o seguinte código à lista de importações de AppModule:

@NgModule({
	declarations: [...],
	imports: [
		provideFirebaseApp(() =>  initializeApp(environment.firebase)),

		provideAuth(() => {
			const  auth = getAuth();
			if (location.hostname === 'localhost') {
				connectAuthEmulator(auth, 'http://127.0.0.1:9099', { disableWarnings:  true });
			}
			return  auth;
		}),

		provideFirestore(() => {
			const  firestore = getFirestore();
			if (location.hostname === 'localhost') {
				connectFirestoreEmulator(firestore, '127.0.0.1', 8080);
			}
			return  firestore;
		}),

		provideFunctions(() => {
			const  functions = getFunctions();
			if (location.hostname === 'localhost') {
				connectFunctionsEmulator(functions, '127.0.0.1', 5001);
			}
			return  functions;
		}),

		provideStorage(() => {
			const  storage = getStorage();
			if (location.hostname === 'localhost') {
				connectStorageEmulator(storage, '127.0.0.1', 5001);
			}
			return  storage;
		}),
		...
	]

Agora, o app está configurado para usar emuladores locais, permitindo que o teste e o desenvolvimento sejam feitos localmente.

6. Adicionar autenticação

Agora que os emuladores estão configurados para o app, podemos adicionar recursos do Authentication para garantir que cada usuário esteja conectado antes de postar mensagens.

Para fazer isso, podemos importar as funções signin diretamente do AngularFire e acompanhar o estado de autenticação do usuário com a função authState. Modifique as funções da página de login para que ela verifique o estado de autenticação do usuário no carregamento.

Como injetar autenticação do AngularFire

No src/app/pages/login-page/login-page.component.ts, importe Auth do @angular/fire/auth e injete-o no LoginPageComponent. Provedores de autenticação, como o Google, e funções como signin e signout também podem ser importados diretamente do mesmo pacote e usados no app.

import { Auth, GoogleAuthProvider, signInWithPopup, signOut, user } from  '@angular/fire/auth';

export  class  LoginPageComponent  implements  OnInit {
	private  auth: Auth = inject(Auth);
	private  provider = new  GoogleAuthProvider();
	user$ = user(this.auth);
	constructor() {}  

	ngOnInit(): void {} 

	login() {
		signInWithPopup(this.auth, this.provider).then((result) => {
			const  credential = GoogleAuthProvider.credentialFromResult(result);
			return  credential;
		})
	}

	logout() {
		signOut(this.auth).then(() => {
			console.log('signed out');}).catch((error) => {
				console.log('sign out error: ' + error);
		})
	}
}

A página de login já está funcionando. Tente fazer login e confira os resultados no emulador do Authentication.

7. Como configurar o Firestore

Nesta etapa, você vai adicionar a funcionalidade de publicar e atualizar postagens de blogs de viagens armazenadas no Firestore.

Assim como o Authentication, as funções do Firestore vêm pré-empacotadas do AngularFire. Cada documento pertence a uma coleção, e cada documento também pode ter coleções aninhadas. É necessário saber o path do documento no Firestore para criar e atualizar uma postagem do blog de viagens.

Implementação do TravelService

Como muitas páginas diferentes precisarão ler e atualizar documentos do Firestore no app da Web, podemos implementar as funções em src/app/services/travel.service.ts para não injetar repetidamente as mesmas funções do AngularFire em todas as páginas.

Comece injetando Auth, semelhante à etapa anterior, e Firestore no nosso serviço. Definir um objeto user$ observável que detecta o status atual da autenticação também é útil.

import { doc, docData, DocumentReference, Firestore, getDoc, setDoc, updateDoc, collection, addDoc, deleteDoc, collectionData, Timestamp } from  "@angular/fire/firestore";

export  class  TravelService {
	firestore: Firestore = inject(Firestore);
	auth: Auth = inject(Auth);
	user$ = authState(this.auth).pipe(filter(user  =>  user !== null), map(user  =>  user!));
	router: Router = inject(Router);

Adicionar uma postagem de viagem

As postagens de viagem existem como documentos armazenados no Firestore. Como os documentos precisam estar dentro de coleções, a coleção que contém todas as postagens de viagens será chamada de travels. Assim, o caminho de qualquer postagem de viagem será travels/.

Usando a função addDoc do AngularFire, um objeto pode ser inserido em uma coleção:

async  addEmptyTravel(userId: String) {
	...
	addDoc(collection(this.firestore, 'travels'), travelData).then((travelRef) => {
		collection(this.firestore, `travels/${travelRef.id}/stops`);
		setDoc(travelRef, {... travelData, id:  travelRef.id})
		this.router.navigate(['edit', `${travelRef.id}`]);
		return  travelRef;

	})
}

Atualizar e excluir dados

Com o UID de qualquer postagem de viagem, é possível deduzir o caminho do documento armazenado no Firestore, que pode ser lido, atualizado ou excluído usando as funções updateFoc e deleteDoc do AngularFire:

async  updateData(path: string, data: Partial<Travel | Stop>) {
	await  updateDoc(doc(this.firestore, path), data)
}

async  deleteData(path: string) {
	const  ref = doc(this.firestore, path);
	await  deleteDoc(ref)
}

Ler dados como um elemento observável

Como as postagens de viagem e as paradas ao longo do caminho podem ser modificadas após a criação, seria mais útil usar objetos de documentos como observáveis para receber as mudanças feitas. Essa funcionalidade é oferecida pelas funções docData e collectionData do @angular/fire/firestore.

getDocData(path: string) {
	return  docData(doc(this.firestore, path), {idField:  'id'}) as  Observable<Travel | Stop>
}

  
getCollectionData(path: string) {
	return  collectionData(collection(this.firestore, path), {idField:  'id'}) as  Observable<Travel[] | Stop[]>
}

Adicionar paradas a uma postagem de viagem

Agora que as operações de postagem de viagem estão configuradas, é hora de considerar as paradas, que estarão em uma subcoleção de uma postagem de viagem como esta: travels//stops/

Esse recurso é quase idêntico à criação de uma postagem de viagem. Então, tente fazer a implementação por conta própria ou confira a implementação abaixo:

async  addStop(travelId: string) {
	...
	const  ref = await  addDoc(collection(this.firestore, `travels/${travelId}/stops`), stopData)
	setDoc(ref, {...stopData, id:  ref.id})
}

Muito bem! As funções do Firestore foram implementadas no serviço Travel, então você pode vê-las em ação.

Como usar as funções do Firestore no app

Navegue até src/app/pages/my-travels/my-travels.component.ts e injete TravelService para usar as funções dele.

travelService = inject(TravelService);
travelsData$: Observable<Travel[]>;
stopsList$!: Observable<Stop[]>;
constructor() {
	this.travelsData$ = this.travelService.getCollectionData(`travels`) as  Observable<Travel[]>
}

TravelService é chamado no construtor para receber uma matriz observável de todas as viagens.

No caso em que apenas as viagens do usuário atual são necessárias, use a função query.

Outros métodos para garantir a segurança incluem a implementação de regras de segurança ou o uso do Cloud Functions com o Firestore, conforme explorado nas etapas opcionais abaixo.

Em seguida, basta chamar as funções implementadas em TravelService.

async  createTravel(userId: String) {
	this.travelService.addEmptyTravel(userId);
}

deleteTravel(travelId: String) {
	this.travelService.deleteData(`travels/${travelId}`)
}

Agora a página "Minhas viagens" deve funcionar. Confira o que acontece no emulador do Firestore quando você cria uma nova postagem de viagem.

Depois, repita essas etapas para as funções de atualização em /src/app/pages/edit-travels/edit-travels.component.ts :

travelService: TravelService = inject(TravelService)
travelId = this.activatedRoute.snapshot.paramMap.get('travelId');
travelData$: Observable<Travel>;
stopsData$: Observable<Stop[]>;

constructor() {
	this.travelData$ = this.travelService.getDocData(`travels/${this.travelId}`) as  Observable<Travel>
	this.stopsData$ = this.travelService.getCollectionData(`travels/${this.travelId}/stops`) as  Observable<Stop[]>
}

updateCurrentTravel(travel: Partial<Travel>) {
	this.travelService.updateData(`travels${this.travelId}`, travel)
}

  

updateCurrentStop(stop: Partial<Stop>) {
	stop.type = stop.type?.toString();
	this.travelService.updateData(`travels${this.travelId}/stops/${stop.id}`, stop)
}

  

addStop() {
	if (!this.travelId) return;
	this.travelService.addStop(this.travelId);
}

deleteStop(stopId: string) {
	if (!this.travelId || !stopId) {
		return;
	}
	this.travelService.deleteData(`travels${this.travelId}/stops/${stopId}`)
	this.stopsData$ = this.travelService.getCollectionData(`travels${this.travelId}/stops`) as  Observable<Stop[]>

}

8. Como configurar o armazenamento

Agora você vai implementar o Storage para armazenar imagens e outros tipos de mídia.

O Cloud Firestore é melhor usado para armazenar dados estruturados, como objetos JSON. O Cloud Storage foi projetado para armazenar arquivos ou blobs. Neste app, você vai usar o app para permitir que os usuários compartilhem fotos de viagens.

Da mesma forma que acontece com o Firestore, armazenar e atualizar arquivos com o Storage requer um identificador exclusivo para cada arquivo.

Vamos implementar as funções em TraveService:

Como enviar um arquivo

Navegue até src/app/services/travel.service.ts e injete o armazenamento do AngularFire:

export  class  TravelService {
firestore: Firestore = inject(Firestore);
auth: Auth = inject(Auth);
storage: Storage = inject(Storage);

E implemente a função de upload:

async  uploadToStorage(path: string, input: HTMLInputElement, contentType: any) {
	if (!input.files) return  null
	const  files: FileList = input.files;
		for (let  i = 0; i  <  files.length; i++) {
			const  file = files.item(i);
			if (file) {
				const  imagePath = `${path}/${file.name}`
				const  storageRef = ref(this.storage, imagePath);
				await  uploadBytesResumable(storageRef, file, contentType);
				return  await  getDownloadURL(storageRef);
			}
		}
	return  null;
}

A principal diferença entre acessar documentos do Firestore e arquivos do Cloud Storage é que, embora ambos sigam caminhos estruturados de pasta, a combinação de URL de base e caminho é recebida pelo getDownloadURL, que pode ser armazenado e usado em um arquivo .

Como usar a função no app

Navegue até src/app/components/edit-stop/edit-stop.component.ts e chame a função de upload usando:

	async  uploadFile(file: HTMLInputElement, stop: Partial<Stop>) {
	const  path = `/travels/${this.travelId}/stops/${stop.id}`
	const  url = await  this.travelService.uploadToStorage(path, file, {contentType:  'image/png'});
	stop.image = url ? url : '';
	this.travelService.updateData(path, stop);
}

Quando a imagem é enviada, o próprio arquivo de mídia é enviado para o armazenamento, e o URL é armazenado no documento no Firestore.

9. Como implantar o aplicativo

Agora estamos prontos para implantar o aplicativo.

Copie as configurações firebase de src/environments/environment.ts para src/environments/environment.prod.ts e execute:

firebase deploy

Você vai conferir algo parecido com:

✔ Browser application bundle generation complete.
✔ Copying assets complete.
✔ Index html generation complete.

=== Deploying to 'friendly-travels-b6a4b'...

i  deploying storage, firestore, hosting
i  firebase.storage: checking storage.rules for compilation errors...
✔  firebase.storage: rules file storage.rules compiled successfully
i  firestore: reading indexes from firestore.indexes.json...
i  cloud.firestore: checking firestore.rules for compilation errors...
✔  cloud.firestore: rules file firestore.rules compiled successfully
i  storage: latest version of storage.rules already up to date, skipping upload...
i  firestore: deploying indexes...
i  firestore: latest version of firestore.rules already up to date, skipping upload...
✔  firestore: deployed indexes in firestore.indexes.json successfully for (default) database
i  hosting[friendly-travels-b6a4b]: beginning deploy...
i  hosting[friendly-travels-b6a4b]: found 6 files in .firebase/friendly-travels-b6a4b/hosting
✔  hosting[friendly-travels-b6a4b]: file upload complete
✔  storage: released rules storage.rules to firebase.storage
✔  firestore: released rules firestore.rules to cloud.firestore
i  hosting[friendly-travels-b6a4b]: finalizing version...
✔  hosting[friendly-travels-b6a4b]: version finalized
i  hosting[friendly-travels-b6a4b]: releasing new version...
✔  hosting[friendly-travels-b6a4b]: release complete

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/friendly-travels-b6a4b/overview
Hosting URL: https://friendly-travels-b6a4b.web.app

10. Parabéns!

Agora seu aplicativo deve estar completo e implantado no Firebase Hosting. Agora todos os dados e análises podem ser acessados no console do Firebase.

Para mais recursos relacionados ao AngularFire, Functions, regras de segurança, confira as etapas opcionais abaixo e outros codelabs do Firebase.

11. Opcional: proteções de autenticação do AngularFire.

Além do Firebase Authentication, o AngularFire também oferece proteções baseadas em autenticação nas rotas para que usuários com acesso insuficiente possam ser redirecionados. Isso ajuda a proteger o app contra usuários que acessam dados protegidos.

No src/app/app-routing.module.ts, importe

import {AuthGuard, redirectLoggedInTo, redirectUnauthorizedTo} from  '@angular/fire/auth-guard'

Você pode definir funções de quando e para onde os usuários devem ser redirecionados em determinadas páginas:

const  redirectUnauthorizedToLogin = () =>  redirectUnauthorizedTo(['signin']);
const  redirectLoggedInToTravels = () =>  redirectLoggedInTo(['my-travels']);

Em seguida, basta adicioná-los aos seus trajetos:

const  routes: Routes = [
	{path:  '', component:  LoginPageComponent, canActivate: [AuthGuard], data: {authGuardPipe:  redirectLoggedInToTravels}},
	{path:  'signin', component:  LoginPageComponent, canActivate: [AuthGuard], data: {authGuardPipe:  redirectLoggedInToTravels}},
	{path:  'my-travels', component:  MyTravelsComponent, canActivate: [AuthGuard], data: {authGuardPipe:  redirectUnauthorizedToLogin}},
	{path:  'edit/:travelId', component:  EditTravelsComponent, canActivate: [AuthGuard], data: {authGuardPipe:  redirectUnauthorizedToLogin}},
];

12. Opcional: regras de segurança

O Firestore e o Cloud Storage usam regras de segurança (firestore.rules e security.rules, respectivamente) para aplicar a segurança e validar os dados.

No momento, os dados do Firestore e do Storage têm acesso aberto para leituras e gravações, mas você não quer que as pessoas mudem as postagens de outras pessoas. Você pode usar regras de segurança para restringir o acesso a coleções e documentos.

Regras do Firestore

Para permitir que apenas usuários autenticados vejam as postagens de viagem, acesse o arquivo firestore.rules e adicione:

rules_version  =  '2';
service  cloud.firestore  {
	match  /databases/{database}/travels  {
		allow  read:  if  request.auth.uid  !=  null;
		allow  write:
		if  request.auth.uid  ==  request.resource.data.userId;
	}
}

As regras de segurança também podem ser usadas para validar dados:

rules_version  =  '2';
service  cloud.firestore  {
	match  /databases/{database}/posts  {
		allow  read:  if  request.auth.uid  !=  null;
		allow  write:
		if  request.auth.uid  ==  request.resource.data.userId;
		&&  "author"  in  request.resource.data
		&&  "text"  in  request.resource.data
		&&  "timestamp"  in  request.resource.data;
	}
}

Regras de armazenamento

Da mesma forma, podemos usar regras de segurança para aplicar o acesso a bancos de dados de armazenamento no storage.rules. Também podemos usar funções para verificações mais complexas:

rules_version  =  '2';

function  isImageBelowMaxSize(maxSizeMB)  {
	return  request.resource.size  <  maxSizeMB  *  1024  *  1024
		&&  request.resource.contentType.matches('image/.*');
}

 service  firebase.storage  {
	match  /b/{bucket}/o  {
		match  /{userId}/{postId}/{filename}  {
			allow  write:  if  request.auth  !=  null
			&&  request.auth.uid  ==  userId  &&  isImageBelowMaxSize(5);
			allow  read;
		}
	}
}