├── src
├── env.d.ts
├── assets
│ ├── dummies
│ │ ├── trustplus.json
│ │ ├── trustplus-censored.json
│ │ └── trustplus-total.json
│ └── images
│ │ ├── trust+.png
│ │ ├── bg-purple.svg
│ │ └── dea-logo.svg
├── pages
│ ├── 404.astro
│ ├── statistic.astro
│ └── index.astro
├── components
│ ├── astro
│ │ ├── Hero.astro
│ │ ├── Announcement.astro
│ │ ├── utilities
│ │ │ ├── SiteMeta.astro
│ │ │ └── Navbar.astro
│ │ ├── base
│ │ │ └── _Link.astro
│ │ └── DangerousCategory.astro
│ └── react
│ │ ├── PopupResult.tsx
│ │ └── Search.tsx
├── helpers
│ ├── suggestedDomain.ts
│ └── response.ts
├── styles
│ └── globals.css
└── layouts
│ └── Layout.astro
├── bun.lockb
├── tailwind.config.cjs
├── astro.config.mjs
├── tsconfig.json
├── package.json
├── public
└── favicon.svg
└── README.md
/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/bun.lockb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deaafrizal/unofficial-trust/HEAD/bun.lockb
--------------------------------------------------------------------------------
/src/assets/dummies/trustplus.json:
--------------------------------------------------------------------------------
1 | {
2 | "domain": [
3 | "raymondibrahim.com"
4 | ]
5 | }
--------------------------------------------------------------------------------
/src/assets/dummies/trustplus-censored.json:
--------------------------------------------------------------------------------
1 | {
2 | "censored_domain": [
3 | "r*****dibrahim.com"
4 | ]
5 | }
--------------------------------------------------------------------------------
/src/assets/images/trust+.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deaafrizal/unofficial-trust/HEAD/src/assets/images/trust+.png
--------------------------------------------------------------------------------
/src/pages/404.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Layout from "@layouts/Layout.astro";
3 |
4 | ---
5 |
6 |
7 | 404 Not Found
8 | Go Home!
9 |
--------------------------------------------------------------------------------
/src/pages/statistic.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Layout from "@layouts/Layout.astro";
3 |
4 | ---
5 |
6 |
7 | Statistic (Coming Soon)
8 |
--------------------------------------------------------------------------------
/tailwind.config.cjs:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | }
9 |
--------------------------------------------------------------------------------
/src/components/astro/Hero.astro:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | ---
4 |
5 | <>
6 |
7 | Unofficial Trust+
11 |
12 | >
13 |
--------------------------------------------------------------------------------
/src/components/astro/Announcement.astro:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | ---
4 |
5 |
6 |
7 | Education purpose only!
8 | the official site is here
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import DangerousCategory from "@component/astro/DangerousCategory.astro";
3 | import Hero from "@component/astro/Hero.astro";
4 | import Search from "@component/react/Search";
5 | import Layout from "@layouts/Layout.astro";
6 | ---
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig, passthroughImageService } from 'astro/config';
2 | import tailwind from "@astrojs/tailwind";
3 | import react from "@astrojs/react";
4 |
5 | import vercel from "@astrojs/vercel/serverless";
6 |
7 | // https://astro.build/config
8 | export default defineConfig({
9 | image: {
10 | service: passthroughImageService()
11 | },
12 | integrations: [tailwind(), react()],
13 | output: "server",
14 | adapter: vercel()
15 | });
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/base",
3 | "compilerOptions": {
4 | "strict": true,
5 | "strictNullChecks": true,
6 | "baseUrl": "./",
7 | "paths": {
8 | "@styles/*": [
9 | "src/styles/*"
10 | ],
11 | "@helpers/*": [
12 | "src/helpers/*"
13 | ],
14 | "@assets/*": [
15 | "src/assets/*"
16 | ],
17 | "@layouts/*": [
18 | "src/layouts/*"
19 | ],
20 | "@component/*": [
21 | "src/components/*"
22 | ]
23 | },
24 | "jsx": "react-jsx",
25 | "jsxImportSource": "react"
26 | }
27 | }
--------------------------------------------------------------------------------
/src/helpers/suggestedDomain.ts:
--------------------------------------------------------------------------------
1 | import { censored_domain } from "@assets/dummies/trustplus-censored.json";
2 |
3 | export const suggestedDomain = (chunk: any, searchInput: string): string => {
4 | let domainPrediction: string;
5 |
6 | const suggestedDomain: string = chunk.find((item: string) => item.toLocaleLowerCase().includes(searchInput.toLocaleLowerCase()));
7 | const indexOfSensorDomain: number = chunk.findIndex((item: string) => item.toLowerCase().includes(searchInput.toLowerCase()));
8 |
9 | return suggestedDomain == `"${searchInput}"` ? domainPrediction = suggestedDomain : domainPrediction = censored_domain[indexOfSensorDomain]
10 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "unofficial-trustpositif-website",
3 | "type": "module",
4 | "version": "0.0.1",
5 | "scripts": {
6 | "dev": "bunx --bun astro dev",
7 | "start": "astro dev",
8 | "build": "astro build",
9 | "preview": "astro preview",
10 | "astro": "astro"
11 | },
12 | "dependencies": {
13 | "@astrojs/react": "^3.0.2",
14 | "@astrojs/tailwind": "^5.0.0",
15 | "@astrojs/vercel": "^5.0.1",
16 | "@types/react": "^18.0.21",
17 | "@types/react-dom": "^18.0.6",
18 | "astro": "^3.2.2",
19 | "react": "^18.0.0",
20 | "react-dom": "^18.0.0",
21 | "react-router-dom": "^6.16.0",
22 | "react-toastify": "^9.1.3",
23 | "tailwindcss": "^3.0.24",
24 | "vercel": "latest",
25 | "zod": "^3.22.3"
26 | }
27 | }
--------------------------------------------------------------------------------
/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/src/assets/dummies/trustplus-total.json:
--------------------------------------------------------------------------------
1 | {
2 | "categoriesCount": {
3 | "lastYear": "2022",
4 | "TotalPerjudian": "156975",
5 | "TotalPornografi": "51588",
6 | "TotalRadikalisme": "1",
7 | "TotalPenipuanOnline": "1887",
8 | "TotalInvestasiIlegal": "0",
9 | "TotalObatdanKosmetikIlegal": "0",
10 | "TotalHKI": "2005",
11 | "TotalPelanggaranKeamananInformasi": "1",
12 | "TotalKekerasan": "5",
13 | "TotalKekerasanPornografiAnak": "2",
14 | "TotalSARA": "1",
15 | "TotalPelanggaranUUITE": "0",
16 | "TotalPerdaganganProdukAturanKhusus": "0",
17 | "TotalKontenNegatifDirekomendasikanInstansiSektor": "1266",
18 | "TotalKontenMeresahkanMasyarakat": "0",
19 | "TotalFitnah": "0",
20 | "TotalSeparatisme": "1",
21 | "TotalKontenMelanggarNilaiSosialBudaya": "0",
22 | "TotalHOAKS": "3",
23 | "TotalPemerasan": "0",
24 | "TotalKontenMemfasilitasiKontenNegatif": "0"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/astro/utilities/SiteMeta.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { z } from 'astro/zod';
3 |
4 | const siteMetaSchema = z.object({
5 | title: z.string().optional(),
6 | description: z.string().min(9).optional(),
7 | image: z.string().optional(),
8 | author: z.string().optional(),
9 | url: z.string().optional()
10 | })
11 |
12 | type Props = z.infer
13 |
14 | const { title, description, image, author, url }: Props = Astro.props;
15 | ---
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
30 | {title} - {description}
31 |
--------------------------------------------------------------------------------
/src/helpers/response.ts:
--------------------------------------------------------------------------------
1 | import { domain } from "@assets/dummies/trustplus.json";
2 | import { categoriesCount } from "@assets/dummies/trustplus-total.json";
3 | import { suggestedDomain } from "./suggestedDomain";
4 |
5 | type DomainResult = {
6 | domain: string;
7 | suggestedDomain: string;
8 | status: boolean;
9 | };
10 |
11 | type StringifyJson = {
12 | [key: string]: string;
13 | };
14 |
15 | type CategorisResult = {
16 | categoriesCount: StringifyJson;
17 | };
18 |
19 | //! Get Domains Formatted Response
20 | export const domainResponse = (searchInput: string): DomainResult => {
21 | const convertedDomains = JSON.stringify(domain);
22 | const chunk = convertedDomains.split(",");
23 | const isMatch = convertedDomains.includes(searchInput.toLowerCase());
24 |
25 | return {
26 | domain: searchInput,
27 | suggestedDomain: suggestedDomain(chunk, searchInput),
28 | status: isMatch,
29 | };
30 | };
31 |
32 | //! Get Count Data From Categories
33 | export const categoryResponse = (): CategorisResult => {
34 | return { categoriesCount }
35 | };
36 |
--------------------------------------------------------------------------------
/src/styles/globals.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Gabarito&display=swap');
2 |
3 | @tailwind base;
4 | @tailwind components;
5 | @tailwind utilities;
6 |
7 | *,
8 | *::before,
9 | *::after {
10 | padding: 0;
11 | margin: 0;
12 | box-sizing: border-box;
13 | }
14 |
15 | :root {
16 | font-family: 'Gabarito', cursive;
17 | --toastify-toast-width: 520px !important;
18 | --toastify-toast-min-height: 160px !important;
19 | --toastify-font-family: 'Gabarito', cursive !important;
20 | }
21 |
22 | html {
23 | background-color: #1e1e1e;
24 | background-image: url("../assets/images/bg-purple.svg");
25 | background-position: center;
26 | background-attachment: fixed;
27 | background-size: cover;
28 | }
29 |
30 | code {
31 | font-family:
32 | Menlo,
33 | Monaco,
34 | Lucida Console,
35 | Liberation Mono,
36 | DejaVu Sans Mono,
37 | Bitstream Vera Sans Mono,
38 | Courier New,
39 | monospace;
40 | }
41 |
42 | main {
43 | margin: auto;
44 | color: white;
45 | font-size: 20px;
46 | line-height: 1.6;
47 | }
48 |
49 | h1 {
50 | font-weight: 700;
51 | line-height: 1;
52 | }
--------------------------------------------------------------------------------
/src/assets/images/bg-purple.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/astro/base/_Link.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { z } from "zod";
3 |
4 | const linkSchema = z.object({
5 | title: z.string(),
6 | url: z.string(),
7 | variant: z.enum(["primary", "secondary"]).optional(),
8 | style: z.string().optional(),
9 | });
10 |
11 | type Props = z.infer;
12 | const { title, url, variant, style }: Props = Astro.props;
13 |
14 | let variantStyle: string = "";
15 |
16 | switch (variant) {
17 | case "primary":
18 | variantStyle =
19 | "flex justify-center items-center sm:rounded-2xl rounded-xl border bg-fuchsia-400 border-fuchsia-400 sm:px-5 sm:py-2.5 px-3 py-1.5 sm:text-lg font-medium text-white hover:bg-gray-100 hover:text-black hover:border-fuchsia-400 transition-all cursor-pointer";
20 | break;
21 |
22 | case "secondary":
23 | variantStyle =
24 | "flex justify-center items-center sm:rounded-2xl rounded-xl border border-fuchsia-400 sm:px-5 sm:py-2.5 px-3 py-1.5 sm:text-lg font-medium text-white hover:bg-fuchsia-500 hover:border-gray-50 transition-all cursor-pointer";
25 | break;
26 |
27 | default:
28 | variantStyle = "text-white transition hover:text-fuchsia-300/75";
29 | break;
30 | }
31 | ---
32 |
33 |
34 | {title}
35 |
36 |
--------------------------------------------------------------------------------
/src/layouts/Layout.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { ViewTransitions } from "astro:transitions";
3 |
4 | import SiteMeta from "@component/astro/utilities/SiteMeta.astro";
5 | import Navbar from "@component/astro/utilities/Navbar.astro";
6 | import "@styles/globals.css";
7 | import Announcement from "@component/astro/Announcement.astro";
8 |
9 | type Props = {
10 | title?: string,
11 | description?: string
12 | }
13 |
14 | const {
15 | title = "Trust+",
16 | description = "Unofficial Trust Positive Indonesia",
17 | }: Props = Astro.props;
18 | ---
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/components/astro/utilities/Navbar.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { Image } from "astro:assets";
3 | import logo from "@assets/images/dea-logo.svg";
4 | import Link from "@component/astro/base/_Link.astro";
5 | ---
6 |
7 |
36 |
--------------------------------------------------------------------------------
/src/components/astro/DangerousCategory.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { categoryResponse } from "@helpers/response";
3 | const category = categoryResponse().categoriesCount
4 | ---
5 |
6 |
7 |
Last Year On {category.lastYear}
8 |
9 |
10 |
11 |
Pornography
12 |
15 |
16 |
17 |
Gambling
18 |
21 |
22 |
23 |
Human Rights Violations
24 |
27 |
28 |
32 | & More
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/components/react/PopupResult.tsx:
--------------------------------------------------------------------------------
1 | import z from 'zod';
2 |
3 | const trustedSiteSchema = z.object({
4 | domain: z.string(),
5 | suggestedDomain: z.string(),
6 | status: z.boolean(),
7 | });
8 |
9 | type TrustedSite = z.infer;
10 |
11 | const PopupResult = ({ domain, suggestedDomain, status }: TrustedSite) => {
12 | return (
13 |
14 |
15 |
16 |
17 | Search for
18 |
19 |
20 | Suggested URL
21 |
22 |
23 | Status
24 |
25 |
26 |
27 |
28 |
29 |
30 | {domain}
31 |
32 |
33 | {suggestedDomain}
34 |
35 |
36 | {status ? "blocked" : "-"}
37 |
38 |
39 |
40 |
41 | )
42 | }
43 |
44 | export default PopupResult
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Unofficial Trust+ Website
2 |
3 |
4 |
5 | 
6 |
7 |
8 |
9 | The Unofficial Trust+ Website is an open source project that aims to provide a user-friendly interface for searching a list of websites that have been blocked by the government. This project aims to promote a new modern looks & feels.
10 |
11 | ```javascript
12 | $: our data maybe not 100% correct & up to date since it based on static JSON dummies 😄.
13 | $: But we grab it from the endpoint of real truspositive websites.
14 | ```
15 |
16 | ## Features & Roadmap
17 |
18 | - [✅] **Search Functionality**: Users can search for specific websites in the blocked list by entering a keyword or URL.
19 | - [✅] **User-Friendly Interface**: The website is designed to be intuitive and easy to navigate, ensuring a smooth user experience for visitors.
20 |
21 | 👇 this is your journey, i'm just open the door, OK? 😄 👇
22 |
23 | - [🔥] **User Contributions**: Users can contribute to the project by suggesting new websites to be added to the blocked list or providing updates to existing JSON entries.
24 | - [⏳] **Statistic Page**: Showing a list of data count based on available categories.
25 | - [⏳] **Statistic Graphs**: Showing a graph for visualizing the data
26 | - [⏳] **Data Scrapping? 🤦♂️**: Get a realtime blocked website list by the gov? i'm not 100% sure legal. (original trustpositive API enpoint (GET & POST) is `publicly accessible` via POSTMAN or other api tester tools. but then they give us `CORS` when we use from our web client).
27 |
28 | ## Installation
29 |
30 | To run the Unofficial Trust+ Website locally, follow these steps (we use `bun runtime`):
31 |
32 | 1. Clone the repository: `git clone [this repos]`
33 | 2. Navigate to the project directory
34 | 3. Install the project dependencies: `bun install`
35 | 4. Start the development server: `bun dev`
36 | 5. Open your web browser and visit `http://localhost:4321` to access the Unofficial Trust+ Website.
37 | 6. Take a look at `./src/assets/dummies/.....`: here is our data related to the original websites.
38 |
39 | ## Contributing
40 |
41 | Contributions to the Unofficial Trust+ Website are welcome and encouraged! To contribute to the project, please follow these steps:
42 |
43 | 1. Fork the repository on GitHub.
44 | 2. Create a new branch from the `main` branch.
45 | 3. Make your desired changes or additions to the codebase.
46 | 4. Commit and push your changes to your forked repository.
47 | 5. Submit a pull request to the original repository, describing your changes in detail.
48 |
49 | Please ensure that your contributions align with the project's code of conduct and follow the established guidelines.
50 |
51 | ## License
52 |
53 | The Unofficial Trust+ Website is released under the [MIT License](LICENSE). You are free to modify and distribute the project as per the terms of the license.
54 |
55 | ## Acknowledgements
56 |
57 | - [Trust+](https://unofficial-trustpositif-website.vercel.app/) - for providing the data and inspiration for this project.
58 | - [React](https://reactjs.org) - for the JavaScript library used to provide a great UI component control.
59 | - [Astro](https://astro.build) - for the Framework used to create website structure.
60 | - [Vercel](https://vercel.com/) - for the Edge runtime used to run the run the server.
61 |
62 | ## Contact
63 |
64 | If you have any questions, suggestions, or feedback, please don't hesitate to contact us:
65 |
66 | - Project Website: [Trust+](https://unofficial-trustpositif-website.vercel.app/)
67 | - Email: [deacourse@icloud.com](mailto:deacourse@icloud.com)
68 | - Issue Tracker: [GitHub Issues](https://github.com/deaaprizal/unofficial-trust-plus-website/issues)
69 |
70 | We appreciate your interest in the Unofficial Trust+ Website and look forward to hearing from you!
71 |
--------------------------------------------------------------------------------
/src/components/react/Search.tsx:
--------------------------------------------------------------------------------
1 | import { useRef, useState } from "react";
2 | import { ToastContainer, toast } from "react-toastify";
3 | import { z } from "zod";
4 | import { domainResponse } from "@helpers/response";
5 | import PopupResult from "@component/react/PopupResult";
6 |
7 | import "react-toastify/dist/ReactToastify.css";
8 |
9 | const searchInputSchema = z.string().min(3);
10 | type SearchInput = z.infer;
11 |
12 | const DEFAULT_INPUT_LABEL: string = "site url / keyword :";
13 |
14 | const Search = () => {
15 | const [error, setError] = useState(null);
16 | const searchInputRef = useRef(null);
17 | const [lastSearchInput, setLastSearchInput] = useState(null);
18 |
19 | const notify = (message: any) =>
20 | toast(message, {
21 | onOpen: () => setError(null),
22 | onClose: () => (searchInputRef.current!.value = ""),
23 | });
24 |
25 | const getTrustedData = async (searchInput: SearchInput): Promise => {
26 | if (searchInput === lastSearchInput) return;
27 |
28 | setLastSearchInput(searchInput);
29 |
30 | const result = domainResponse(searchInput);
31 | notify(
32 |
37 | );
38 | };
39 |
40 | const validateInput = () => {
41 | let searchInput = searchInputRef.current!.value;
42 | const validateSearchInput = searchInputSchema.safeParse(searchInput);
43 |
44 | !validateSearchInput.success
45 | ? setError(validateSearchInput.error.errors[0].message)
46 | : getTrustedData(validateSearchInput.data);
47 | };
48 |
49 | const handleSearchButton = (): void => {
50 | validateInput();
51 | };
52 |
53 | const handleEnterKeyboard = (
54 | event: React.KeyboardEvent
55 | ) => {
56 | event.stopPropagation();
57 |
58 | if (event.key === "Enter") {
59 | event.preventDefault();
60 | validateInput();
61 | }
62 | };
63 |
64 | return (
65 | <>
66 |
67 |
68 | {error ? error : DEFAULT_INPUT_LABEL}
69 |
70 |
71 |
72 |
Search
73 |
81 |
85 | Search
86 |
94 |
99 |
100 |
101 |
102 |
103 |
104 |
114 | >
115 | );
116 | };
117 |
118 | export default Search;
119 |
--------------------------------------------------------------------------------
/src/assets/images/dea-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
--------------------------------------------------------------------------------