├── placequran-layer ├── .env ├── .npmignore ├── .gitignore ├── src │ ├── data │ │ ├── sqlite │ │ ├── me_quran.ttf │ │ ├── OpenSans-Regular.ttf │ │ ├── NotoNaskhArabic-Regular.ttf │ │ ├── ScheherazadeNew-Regular.ttf │ │ ├── KFGQPC Uthman Taha Naskh Regular.ttf │ │ ├── KFGQPC Uthmanic Script HAFS Regular.otf │ │ └── mysql2sqlite │ └── index.js ├── build.sh ├── publish.sh └── package.json ├── placequran-serverless ├── .env ├── .gitignore ├── img │ └── arch.png ├── .npmignore ├── src │ ├── interfaces │ │ ├── verses.ts │ │ └── param.ts │ ├── lib │ │ ├── log.ts │ │ ├── hash-key.ts │ │ ├── hash-key.spec.ts │ │ ├── cache-header.ts │ │ ├── html2image.ts │ │ ├── get404.ts │ │ └── quran-data.ts │ ├── config.ts │ ├── generator.spec.ts │ ├── generator.ts │ ├── origin-lambda.ts │ ├── quran.ts │ └── quran.spec.ts ├── README.md ├── .babelrc ├── env.js ├── tsconfig.json ├── package.json ├── webpack.config.js └── serverless.yml ├── placequran-website ├── .env ├── .gitignore ├── static │ ├── robots.txt │ ├── image.png │ ├── .favicon.ico │ ├── favicon.ico │ ├── error-404.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── apple-touch-icon.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── manifest.json │ └── .404.svg ├── src │ ├── img │ │ ├── joomla.png │ │ ├── blogspot.png │ │ ├── notfound.jpg │ │ └── wordpress.png │ ├── css │ │ ├── gplaypattern.png │ │ ├── style.css │ │ ├── main.css │ │ └── highlight.default.css │ ├── index.html │ └── js │ │ └── highlight.pack.js ├── deploy.sh └── package.json ├── .gitignore ├── .vscode └── settings.json ├── workspace.code-workspace ├── .env.example ├── package.json ├── LICENSE.md └── README.md /placequran-layer/.env: -------------------------------------------------------------------------------- 1 | ../.env -------------------------------------------------------------------------------- /placequran-serverless/.env: -------------------------------------------------------------------------------- 1 | ../.env -------------------------------------------------------------------------------- /placequran-website/.env: -------------------------------------------------------------------------------- 1 | ../.env -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .parcel-cache 3 | /.env 4 | -------------------------------------------------------------------------------- /placequran-layer/.npmignore: -------------------------------------------------------------------------------- 1 | nodejs/ 2 | *.sh 3 | *.tgz 4 | *.zip 5 | -------------------------------------------------------------------------------- /placequran-website/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .cache 4 | -------------------------------------------------------------------------------- /placequran-website/static/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /placequran-layer/.gitignore: -------------------------------------------------------------------------------- 1 | placequran-layer.zip 2 | chrome_aws_lambda.zip 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "placequran-*": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /placequran-layer/src/data/sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-layer/src/data/sqlite -------------------------------------------------------------------------------- /placequran-serverless/.gitignore: -------------------------------------------------------------------------------- 1 | .webpack 2 | .webpackCache 3 | .serverless 4 | .build 5 | node_modules 6 | yarn-error.log 7 | -------------------------------------------------------------------------------- /placequran-serverless/img/arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-serverless/img/arch.png -------------------------------------------------------------------------------- /placequran-website/static/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-website/static/image.png -------------------------------------------------------------------------------- /placequran-layer/src/data/me_quran.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-layer/src/data/me_quran.ttf -------------------------------------------------------------------------------- /placequran-website/src/img/joomla.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-website/src/img/joomla.png -------------------------------------------------------------------------------- /placequran-website/static/.favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-website/static/.favicon.ico -------------------------------------------------------------------------------- /placequran-website/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-website/static/favicon.ico -------------------------------------------------------------------------------- /placequran-serverless/.npmignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless -------------------------------------------------------------------------------- /placequran-serverless/src/interfaces/verses.ts: -------------------------------------------------------------------------------- 1 | export type Verse = { 2 | sura: number; 3 | aya: number; 4 | text: string; 5 | }; 6 | -------------------------------------------------------------------------------- /placequran-website/src/img/blogspot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-website/src/img/blogspot.png -------------------------------------------------------------------------------- /placequran-website/src/img/notfound.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-website/src/img/notfound.jpg -------------------------------------------------------------------------------- /placequran-website/src/img/wordpress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-website/src/img/wordpress.png -------------------------------------------------------------------------------- /placequran-website/static/error-404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-website/static/error-404.png -------------------------------------------------------------------------------- /placequran-serverless/README.md: -------------------------------------------------------------------------------- 1 | # Placequran Serverless 2 | 3 | The architecture diagram. 4 | 5 | ![Architecture Diagram](img/arch.png) 6 | -------------------------------------------------------------------------------- /placequran-website/src/css/gplaypattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-website/src/css/gplaypattern.png -------------------------------------------------------------------------------- /placequran-website/static/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-website/static/favicon-16x16.png -------------------------------------------------------------------------------- /placequran-website/static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-website/static/favicon-32x32.png -------------------------------------------------------------------------------- /placequran-layer/src/data/OpenSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-layer/src/data/OpenSans-Regular.ttf -------------------------------------------------------------------------------- /placequran-website/static/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-website/static/apple-touch-icon.png -------------------------------------------------------------------------------- /placequran-serverless/src/interfaces/param.ts: -------------------------------------------------------------------------------- 1 | export type QuranParam = { 2 | surah: number; 3 | verses: number[]; 4 | translations: string[]; 5 | }; 6 | -------------------------------------------------------------------------------- /placequran-layer/src/data/NotoNaskhArabic-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-layer/src/data/NotoNaskhArabic-Regular.ttf -------------------------------------------------------------------------------- /placequran-layer/src/data/ScheherazadeNew-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-layer/src/data/ScheherazadeNew-Regular.ttf -------------------------------------------------------------------------------- /placequran-website/static/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-website/static/android-chrome-192x192.png -------------------------------------------------------------------------------- /placequran-website/static/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-website/static/android-chrome-512x512.png -------------------------------------------------------------------------------- /placequran-layer/src/data/KFGQPC Uthman Taha Naskh Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-layer/src/data/KFGQPC Uthman Taha Naskh Regular.ttf -------------------------------------------------------------------------------- /placequran-layer/src/data/KFGQPC Uthmanic Script HAFS Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faizshukri/placequran/HEAD/placequran-layer/src/data/KFGQPC Uthmanic Script HAFS Regular.otf -------------------------------------------------------------------------------- /placequran-website/src/css/style.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "font declaration here because phantomjs has a bug that prevent to use the first declared font"; 3 | } 4 | 5 | 6 | -------------------------------------------------------------------------------- /placequran-serverless/src/lib/log.ts: -------------------------------------------------------------------------------- 1 | import * as util from "util"; 2 | 3 | export default function (variable) { 4 | return console.log(util.inspect(variable, false, null, false)); 5 | } 6 | -------------------------------------------------------------------------------- /placequran-serverless/src/config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | max_verses: 15, 3 | max_translation: 3, 4 | translations: { 5 | ar: "quran_text", 6 | en: "en_sahih", 7 | ms: "ms_basmeih", 8 | id: "id_indonesian", 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /placequran-serverless/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "node": "12" 8 | } 9 | } 10 | ], 11 | ["@babel/preset-typescript"] 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /workspace.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": ".", 5 | "name": "placequran" 6 | }, 7 | { 8 | "path": "placequran-serverless" 9 | }, 10 | { 11 | "path": "placequran-website" 12 | }, 13 | { 14 | "path": "placequran-layer" 15 | } 16 | ], 17 | "settings": {} 18 | } 19 | -------------------------------------------------------------------------------- /placequran-website/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BUCKET=$BUCKET_NAME-$ENVIRONMENT 4 | 5 | # Put cache control on all file 6 | aws s3 sync --delete --cache-control max-age=259200,s-maxage=31536000 --exclude 'tmp/*' --exclude "error*" ./dist s3://$BUCKET 7 | 8 | # except on error files 9 | aws s3 sync --delete --exclude "*" --include "error*" ./dist s3://$BUCKET 10 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | ENVIRONMENT=beta 2 | BUCKET_NAME=placequran-website 3 | AWS_DEFAULT_REGION=us-east-1 4 | CLOUDFRONT_PRICECLASS=PriceClass_100 5 | CLOUDFRONT_DOMAINS=beta.placequran.com 6 | CLOUDFRONT_ACM_CERT_ARN=arn:aws:acm:us-east-1:321068630266:certificate/10cfa1d6-4dc9-4110-a1e5-4c34e3de12ef 7 | PLACEQURAN_LAYER_ARN=arn:aws:lambda:us-east-1:321068630266:layer:placequran-layer:3 8 | -------------------------------------------------------------------------------- /placequran-serverless/env.js: -------------------------------------------------------------------------------- 1 | const dotenv = require("dotenv"); 2 | 3 | module.exports = async ({ options, resolveVariable }) => { 4 | // Load env vars into Serverless environment 5 | // You can do more complicated env var resolution with dotenv here 6 | const envVars = dotenv.config().parsed; 7 | return Object.assign( 8 | {}, 9 | envVars, // `dotenv` environment variables 10 | process.env // system environment variables 11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /placequran-serverless/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "preserveConstEnums": true, 4 | "inlineSources": true, 5 | "inlineSourceMap": true, 6 | "sourceRoot": "/", 7 | "target": "es2017", 8 | "outDir": ".build", 9 | "module": "commonjs", 10 | "moduleResolution": "node", 11 | "esModuleInterop": true, 12 | "lib": ["es2019", "dom"], 13 | "rootDir": "./src", 14 | "resolveJsonModule": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /placequran-layer/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | 3 | rm -rf nodejs placequran-layer.zip 4 | unzip chrome_aws_lambda.zip 5 | 6 | npm install --prefix nodejs --no-package-lock --no-save better-sqlite3@7.4.3 7 | 8 | pack=$(npm pack) 9 | 10 | mkdir -p nodejs/node_modules/placequran-layer/ 11 | tar --directory nodejs/node_modules/placequran-layer/ --extract --file $pack --strip-components=1 12 | 13 | rm $pack 14 | 15 | zip -r9 placequran-layer.zip nodejs 16 | rm -rf nodejs 17 | -------------------------------------------------------------------------------- /placequran-layer/publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | 3 | S3_BUCKET_NAME=$BUCKET_NAME-$ENVIRONMENT 4 | 5 | aws s3 cp \ 6 | placequran-layer.zip \ 7 | s3://$S3_BUCKET_NAME/placequran-layer.zip 8 | 9 | aws lambda publish-layer-version \ 10 | --region "$AWS_DEFAULT_REGION" \ 11 | --layer-name "placequran-layer" \ 12 | --description "placequran layer" \ 13 | --content S3Bucket="$S3_BUCKET_NAME",S3Key=placequran-layer.zip 14 | 15 | aws s3 rm s3://$S3_BUCKET_NAME/placequran-layer.zip 16 | -------------------------------------------------------------------------------- /placequran-website/static/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "placequran", 3 | "short_name": "placequran", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /placequran-serverless/src/lib/hash-key.ts: -------------------------------------------------------------------------------- 1 | import { parsePath } from "../generator"; 2 | import { filterParam, parseParam } from "../quran"; 3 | import { createHash } from "crypto"; 4 | 5 | export default (path: string) => { 6 | const { surah, verses, translations, size } = parsePath(path, ""); 7 | const params = JSON.stringify({ 8 | ...filterParam(parseParam(surah, verses, translations)), 9 | size, 10 | }); 11 | 12 | return "tmp/" + createHash("md5").update(params).digest("hex") + ".png"; 13 | }; 14 | -------------------------------------------------------------------------------- /placequran-serverless/src/lib/hash-key.spec.ts: -------------------------------------------------------------------------------- 1 | import test from "ava"; 2 | import getHashKey from "./hash-key"; 3 | 4 | test("HashKey should works correctly", (t) => { 5 | t.is(getHashKey("/115/1-3/ar,ms"), getHashKey("/115/22")); // both invalid 6 | t.is(getHashKey("/2/1-3,5,7-9/ar,ms"), getHashKey("/2/2,1,7-9,3,5/ar,ms")); // order not the same 7 | t.is(getHashKey("/1/1-7"), getHashKey("/m/1/1-7")); // default size is m 8 | t.not(getHashKey("/1/1-7"), getHashKey("/s/1/1-7")); // different key with other size 9 | }); 10 | -------------------------------------------------------------------------------- /placequran-serverless/src/generator.spec.ts: -------------------------------------------------------------------------------- 1 | import test from "ava"; 2 | import { parsePath } from "./generator"; 3 | 4 | test("Parse path should work correctly", (t) => { 5 | t.deepEqual(parsePath("/2/1-2", ""), { 6 | surah: "2", 7 | verses: "1-2", 8 | translations: undefined, 9 | type: null, 10 | size: "m", 11 | }); 12 | 13 | t.deepEqual(parsePath("/s/2/1-2", ""), { 14 | surah: "2", 15 | verses: "1-2", 16 | translations: undefined, 17 | type: null, 18 | size: "s", 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /placequran-layer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "placequran-layer", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "build": "./build.sh", 8 | "postdeploy": "rimraf placequran-layer.zip", 9 | "deploy": "dotenv cross-var ./publish.sh" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "better-sqlite3": "^7.4.3" 16 | }, 17 | "devDependencies": { 18 | "cross-var": "^1.1.0", 19 | "dotenv-cli": "^4.0.0", 20 | "rimraf": "^3.0.2" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /placequran-website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "placequran-website", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "dev": "parcel src/index.html", 7 | "prebuild": "rimraf ./dist", 8 | "build": "parcel build src/index.html", 9 | "postbuild": "rsync -av static/ dist/ --exclude=.*", 10 | "predeploy": "npm run build", 11 | "deploy": "dotenv cross-var ./deploy.sh" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "devDependencies": { 17 | "cross-var": "^1.1.0", 18 | "dotenv-cli": "^4.0.0", 19 | "parcel": "^2.0.0-rc.0", 20 | "rimraf": "^3.0.2" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "placequran", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "", 6 | "scripts": {}, 7 | "repository": { 8 | "type": "git", 9 | "url": "git+ssh://git@gitlab.com/faizshukri/placequran-serverless.git" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "bugs": { 15 | "url": "https://gitlab.com/faizshukri/placequran-serverless/issues" 16 | }, 17 | "homepage": "https://gitlab.com/faizshukri/placequran-serverless#readme", 18 | "workspaces": [ 19 | "placequran*" 20 | ], 21 | "devDependencies": { 22 | "@parcel/transformer-image": "2.0.0-rc.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /placequran-website/src/css/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: url(gplaypattern.png) repeat fixed; 3 | } 4 | 5 | .row > div { 6 | background-color: white; 7 | padding-top: 20px; 8 | padding-bottom: 20px; 9 | border: 1px solid #eee; 10 | } 11 | 12 | .highlight { 13 | font-weight: bold; 14 | color: green; 15 | } 16 | 17 | .usage ol { 18 | padding-left: 20px; 19 | } 20 | 21 | h1, h2, h3, h4, .jumbotron { 22 | font-family: 'Open Sans', sans-serif; 23 | font-weight: 600; 24 | } 25 | .jumbotron h1 { 26 | font-weight: 400; 27 | } 28 | 29 | .developer-footer { 30 | display: inline; 31 | } 32 | 33 | @media (max-width: 767px){ 34 | .developer-footer { 35 | display: block; 36 | } 37 | } -------------------------------------------------------------------------------- /placequran-website/static/.404.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Layer 1 5 | 6 | 7 | Image 8 | Not Available 9 | 10 | 11 | placequran.com 14 | 15 | 16 | -------------------------------------------------------------------------------- /placequran-serverless/src/lib/cache-header.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | 3 | export default ( 4 | filename: string, 5 | statusCode: number 6 | ): { "Cache-Control"?: string } => { 7 | const extension = path.extname(filename).toLowerCase(); 8 | const isQuranImage = filename.startsWith("tmp/") && extension == ".png"; 9 | 10 | // do not pass cache-control on error 11 | // let cloudfront handle it 12 | if (statusCode !== 200) { 13 | return {}; 14 | } 15 | 16 | // Let's return default for all cases 17 | // max-age : for browser cache 18 | // s-maxage : for cloudfront cache 19 | return { 20 | "Cache-Control": `max-age=${ 21 | 1 /* days */ * 24 /* hours */ * 60 /* minutes */ * 60 /* seconds */ 22 | }, s-maxage=${ 23 | 90 /* days */ * 24 /* hours */ * 60 /* minutes */ * 60 /* seconds */ 24 | }`, 25 | }; 26 | }; 27 | -------------------------------------------------------------------------------- /placequran-serverless/src/lib/html2image.ts: -------------------------------------------------------------------------------- 1 | import chromium from "chrome-aws-lambda"; 2 | 3 | export default async (html = ""): Promise => { 4 | const browser = await chromium.puppeteer.launch({ 5 | args: chromium.args, 6 | defaultViewport: chromium.defaultViewport, 7 | executablePath: await chromium.executablePath, 8 | headless: true, 9 | ignoreHTTPSErrors: true, 10 | }); 11 | 12 | const page = await browser.newPage(); 13 | await page.setContent(html); 14 | 15 | const content = await page.$("body"); 16 | if (!content) { 17 | throw new Error("Body is empty"); 18 | } 19 | const imageBuffer = await content.screenshot(); 20 | 21 | // await page.goto("https://placequran.com"); 22 | // const imageBuffer = await page.screenshot(); 23 | 24 | await page.close(); 25 | await browser.close(); 26 | 27 | return imageBuffer as Buffer; 28 | }; 29 | -------------------------------------------------------------------------------- /placequran-layer/src/index.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const sqlite3 = require("better-sqlite3"); 3 | const fs = require("fs"); 4 | 5 | const loadFont = (filename, format) => () => { 6 | const base64Font = fs 7 | .readFileSync(path.resolve(__dirname, `data/${filename}`)) 8 | .toString("base64"); 9 | 10 | return { 11 | data: `data:font/${format};charset=utf-8;base64,${base64Font}`, 12 | format, 13 | }; 14 | }; 15 | 16 | module.exports = { 17 | sqliteDb: new sqlite3(path.resolve(__dirname, "data/sqlite")), 18 | fontBase64: { 19 | MeQuran: loadFont("me_quran.ttf", "truetype"), 20 | NotoNaskhArabic: loadFont("NotoNaskhArabic-Regular.ttf", "truetype"), 21 | OpenSans: loadFont("OpenSans-Regular.ttf", "truetype"), 22 | Scheherazade: loadFont("ScheherazadeNew-Regular.ttf", "truetype"), 23 | KFGQPCUthmanTahaNaskh: loadFont( 24 | "KFGQPC Uthman Taha Naskh Regular.ttf", 25 | "truetype" 26 | ), 27 | KFGQPCUthmanScriptHafs: loadFont( 28 | "KFGQPC Uthmanic Script HAFS Regular.otf", 29 | "opentype" 30 | ), 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Faiz Shukri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /placequran-serverless/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "placequran-serverless", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "dev": "sls offline", 7 | "test": "ava -v" 8 | }, 9 | "keywords": [], 10 | "author": "Faiz Shukri ", 11 | "license": "ISC", 12 | "dependencies": { 13 | "chrome-aws-lambda": "^10.1.0", 14 | "fs-extra": "^10.0.0", 15 | "placequran-layer": "^1.0.0", 16 | "puppeteer-core": "^10.4.0", 17 | "ramda": "^0.27.1" 18 | }, 19 | "devDependencies": { 20 | "@babel/core": "^7.15.8", 21 | "@babel/preset-env": "^7.15.8", 22 | "@babel/preset-typescript": "^7.15.0", 23 | "@types/aws-lambda": "^8.10.84", 24 | "@types/better-sqlite3": "^7.4.0", 25 | "@types/fs-extra": "^9.0.13", 26 | "ava": "^3.15.0", 27 | "aws-sdk": "^2.1004.0", 28 | "babel": "^6.23.0", 29 | "babel-loader": "^8.2.2", 30 | "cache-loader": "^4.1.0", 31 | "dotenv": "^10.0.0", 32 | "fork-ts-checker-webpack-plugin": "^6.3.4", 33 | "node-loader": "^2.0.0", 34 | "puppeteer": "^10.4.0", 35 | "serverless-offline": "^8.2.0", 36 | "serverless-plugin-typescript": "^2.1.0", 37 | "serverless-webpack": "^5.5.4", 38 | "ts-node": "^10.3.0", 39 | "typescript": "^4.4.3", 40 | "webpack": "^5.58.1" 41 | }, 42 | "ava": { 43 | "extensions": [ 44 | "ts" 45 | ], 46 | "require": [ 47 | "ts-node/register" 48 | ] 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /placequran-serverless/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const slsw = require("serverless-webpack"); 3 | const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); 4 | 5 | module.exports = { 6 | entry: slsw.lib.entries, 7 | target: "node", 8 | mode: "production", 9 | optimization: { 10 | // We no not want to minimize our code. 11 | minimize: false, 12 | }, 13 | performance: { 14 | // Turn off size warnings for entry points 15 | hints: false, 16 | }, 17 | devtool: "nosources-source-map", 18 | resolve: { 19 | extensions: [".js", ".jsx", ".json", ".ts", ".tsx"], 20 | }, 21 | externals: ["aws-sdk", "chrome-aws-lambda", "placequran-layer"], 22 | module: { 23 | rules: [ 24 | { 25 | // Include ts, tsx, js, and jsx files. 26 | test: /\.(ts|js)x?$/, 27 | exclude: /node_modules/, 28 | use: [ 29 | { 30 | loader: "cache-loader", 31 | options: { 32 | cacheDirectory: path.resolve(".webpackCache"), 33 | }, 34 | }, 35 | "babel-loader", 36 | ], 37 | }, 38 | { 39 | test: /\.node$/, 40 | loader: "node-loader", 41 | }, 42 | ], 43 | }, 44 | plugins: [new ForkTsCheckerWebpackPlugin()], 45 | output: { 46 | libraryTarget: "commonjs2", 47 | path: path.join(__dirname, ".webpack"), 48 | filename: "[name].js", 49 | sourceMapFilename: "[file].map", 50 | }, 51 | }; 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Placequran Monorepo 2 | 3 | This repo contains 3 main components. You can install dependencies for all component by running `yarn` in root folder, or by component by run `yarn` in the component folder. 4 | 5 | Every component has different command available, and need to be run inside their folder. 6 | 7 | ## 1. Serverless 8 | 9 | A serverless project that bootstraping all aws components. 10 | 11 | | Command | Description | 12 | | ---------- | ----------------------------------- | 13 | | yarn dev | Run serverless offline | 14 | | yarn test | Run unit test | 15 | | sls deploy | Deploy the whole serverless project | 16 | 17 | Here is the [architecture diagram](placequran-serverless/README.md) of this project. 18 | 19 | ## 2. Website 20 | 21 | A static website to serve the main page. 22 | 23 | | Command | Description | 24 | | ----------- | -------------------------- | 25 | | yarn dev | Run local dev server | 26 | | yarn build | Build the production files | 27 | | yarn deploy | Sync to the S3 bucket | 28 | 29 | ## 3. Layer 30 | 31 | A separate project to build a dependency lambda layer, to be consumed by `serverless` component. The major dependencies here are `puppeteer`, `better-sqlite3`, quran font and database. 32 | 33 | Before you can build, you need to download the [chrome_aws_lambda.zip](https://github.com/shelfio/chrome-aws-lambda-layer) or ([build by yourself](https://github.com/alixaxel/chrome-aws-lambda#aws-lambda-layer)), and save it as `placequran-layer/chrome_aws_lambda.zip`. 34 | 35 | | Command | Description | 36 | | ----------- | ------------------------------- | 37 | | yarn build | Build the layer zip file | 38 | | yarn deploy | Publish the layer to aws lambda | 39 | -------------------------------------------------------------------------------- /placequran-serverless/src/generator.ts: -------------------------------------------------------------------------------- 1 | import { URLSearchParams } from "url"; 2 | import { 3 | getVerses, 4 | parseParam, 5 | prepareForHtml, 6 | generateHtml, 7 | renderImage, 8 | } from "./quran"; 9 | 10 | export const parsePath = (path: string, query: string) => { 11 | path = path.replace(/^\s*\/*/, ""); 12 | 13 | let surah: string, verses: string, translations: string, size: string; 14 | 15 | if (["s", "m", "l"].some((size) => path.startsWith(`${size}/`))) { 16 | [size, surah, verses, translations] = path.split("/").filter(Boolean); 17 | } else { 18 | [surah, verses, translations] = path.split("/").filter(Boolean); 19 | size = "m"; 20 | } 21 | const queryParams = new URLSearchParams(query); 22 | const type = queryParams.get("t"); 23 | 24 | return { 25 | surah, 26 | verses, 27 | translations, 28 | type, 29 | size, 30 | }; 31 | }; 32 | 33 | const response = async ( 34 | { 35 | surah, 36 | verses, 37 | translations, 38 | }: { surah: string; verses: string; translations: string }, 39 | operation: string, 40 | size: string 41 | ): Promise<{ type: string; body: string }> => { 42 | const params = parseParam(surah, verses, translations); 43 | if (operation === "param") { 44 | return { 45 | type: "application/json", 46 | body: Buffer.from(JSON.stringify(params)).toString("base64"), 47 | }; 48 | } 49 | 50 | const api = await getVerses(params); 51 | if (operation === "api") { 52 | return { 53 | type: "application/json", 54 | body: Buffer.from(JSON.stringify(api)).toString("base64"), 55 | }; 56 | } 57 | 58 | const api2 = prepareForHtml(api); 59 | if (operation === "api2") { 60 | return { 61 | type: "application/json", 62 | body: Buffer.from(JSON.stringify(api2)).toString("base64"), 63 | }; 64 | } 65 | 66 | const html = generateHtml(api2, size); 67 | if (operation === "html") { 68 | return { 69 | type: "text/html; charset=utf-8", 70 | body: Buffer.from(html).toString("base64"), 71 | }; 72 | } 73 | 74 | return { 75 | type: "image/png", 76 | body: (await renderImage(html)).toString("base64"), 77 | }; 78 | }; 79 | 80 | export const generator = async (path: string, query: string) => { 81 | let { surah, verses, translations, type, size } = parsePath(path, query); 82 | 83 | if (!type || !["param", "api", "api2", "html", "image"].includes(type)) { 84 | type = "image"; 85 | } 86 | 87 | return response({ surah, verses, translations }, type, size); 88 | }; 89 | -------------------------------------------------------------------------------- /placequran-website/src/css/highlight.default.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Original style from softwaremaniacs.org (c) Ivan Sagalaev 4 | 5 | */ 6 | 7 | .hljs { 8 | display: block; padding: 0.5em; 9 | background: #F0F0F0; 10 | } 11 | 12 | .hljs, 13 | .hljs-subst, 14 | .hljs-tag .hljs-title, 15 | .lisp .hljs-title, 16 | .clojure .hljs-built_in, 17 | .nginx .hljs-title { 18 | color: black; 19 | } 20 | 21 | .hljs-string, 22 | .hljs-title, 23 | .hljs-constant, 24 | .hljs-parent, 25 | .hljs-tag .hljs-value, 26 | .hljs-rules .hljs-value, 27 | .hljs-rules .hljs-value .hljs-number, 28 | .hljs-preprocessor, 29 | .hljs-pragma, 30 | .haml .hljs-symbol, 31 | .ruby .hljs-symbol, 32 | .ruby .hljs-symbol .hljs-string, 33 | .hljs-aggregate, 34 | .hljs-template_tag, 35 | .django .hljs-variable, 36 | .smalltalk .hljs-class, 37 | .hljs-addition, 38 | .hljs-flow, 39 | .hljs-stream, 40 | .bash .hljs-variable, 41 | .apache .hljs-tag, 42 | .apache .hljs-cbracket, 43 | .tex .hljs-command, 44 | .tex .hljs-special, 45 | .erlang_repl .hljs-function_or_atom, 46 | .asciidoc .hljs-header, 47 | .markdown .hljs-header, 48 | .coffeescript .hljs-attribute { 49 | color: #800; 50 | } 51 | 52 | .smartquote, 53 | .hljs-comment, 54 | .hljs-annotation, 55 | .hljs-template_comment, 56 | .diff .hljs-header, 57 | .hljs-chunk, 58 | .asciidoc .hljs-blockquote, 59 | .markdown .hljs-blockquote { 60 | color: #888; 61 | } 62 | 63 | .hljs-number, 64 | .hljs-date, 65 | .hljs-regexp, 66 | .hljs-literal, 67 | .hljs-hexcolor, 68 | .smalltalk .hljs-symbol, 69 | .smalltalk .hljs-char, 70 | .go .hljs-constant, 71 | .hljs-change, 72 | .lasso .hljs-variable, 73 | .makefile .hljs-variable, 74 | .asciidoc .hljs-bullet, 75 | .markdown .hljs-bullet, 76 | .asciidoc .hljs-link_url, 77 | .markdown .hljs-link_url { 78 | color: #080; 79 | } 80 | 81 | .hljs-label, 82 | .hljs-javadoc, 83 | .ruby .hljs-string, 84 | .hljs-decorator, 85 | .hljs-filter .hljs-argument, 86 | .hljs-localvars, 87 | .hljs-array, 88 | .hljs-attr_selector, 89 | .hljs-important, 90 | .hljs-pseudo, 91 | .hljs-pi, 92 | .haml .hljs-bullet, 93 | .hljs-doctype, 94 | .hljs-deletion, 95 | .hljs-envvar, 96 | .hljs-shebang, 97 | .apache .hljs-sqbracket, 98 | .nginx .hljs-built_in, 99 | .tex .hljs-formula, 100 | .erlang_repl .hljs-reserved, 101 | .hljs-prompt, 102 | .asciidoc .hljs-link_label, 103 | .markdown .hljs-link_label, 104 | .vhdl .hljs-attribute, 105 | .clojure .hljs-attribute, 106 | .asciidoc .hljs-attribute, 107 | .lasso .hljs-attribute, 108 | .coffeescript .hljs-property, 109 | .hljs-phony { 110 | color: #88F 111 | } 112 | 113 | .hljs-keyword, 114 | .hljs-id, 115 | .hljs-title, 116 | .hljs-built_in, 117 | .hljs-aggregate, 118 | .css .hljs-tag, 119 | .hljs-javadoctag, 120 | .hljs-phpdoc, 121 | .hljs-yardoctag, 122 | .smalltalk .hljs-class, 123 | .hljs-winutils, 124 | .bash .hljs-variable, 125 | .apache .hljs-tag, 126 | .go .hljs-typename, 127 | .tex .hljs-command, 128 | .asciidoc .hljs-strong, 129 | .markdown .hljs-strong, 130 | .hljs-request, 131 | .hljs-status { 132 | font-weight: bold; 133 | } 134 | 135 | .asciidoc .hljs-emphasis, 136 | .markdown .hljs-emphasis { 137 | font-style: italic; 138 | } 139 | 140 | .nginx .hljs-built_in { 141 | font-weight: normal; 142 | } 143 | 144 | .coffeescript .javascript, 145 | .javascript .xml, 146 | .lasso .markup, 147 | .tex .hljs-formula, 148 | .xml .javascript, 149 | .xml .vbscript, 150 | .xml .css, 151 | .xml .hljs-cdata { 152 | opacity: 0.5; 153 | } 154 | -------------------------------------------------------------------------------- /placequran-serverless/src/origin-lambda.ts: -------------------------------------------------------------------------------- 1 | import log from "./lib/log"; 2 | import { S3 } from "aws-sdk"; 3 | import { generator } from "./generator"; 4 | import { URLSearchParams } from "url"; 5 | import getCacheHeader from "./lib/cache-header"; 6 | import get404 from "./lib/get404"; 7 | import getHashKey from "./lib/hash-key"; 8 | import { 9 | APIGatewayProxyEventV2, 10 | APIGatewayProxyResultV2, 11 | Context, 12 | } from "aws-lambda"; 13 | 14 | export async function handler( 15 | event: APIGatewayProxyEventV2, 16 | context: Context 17 | ): Promise { 18 | log(event.rawPath); 19 | 20 | const regex = /^\/?(?:[s|m|l]\/)?(\d+)(?:\/|$)/gm; 21 | const isImageRequest = regex.test(event.rawPath); 22 | const typeParam = new URLSearchParams(event.rawQueryString).get("t"); 23 | const shouldReturnImageFormat = !typeParam || typeParam == "image"; 24 | const key = await (async () => { 25 | if (!isImageRequest) { 26 | return event.rawPath.replace(/^\/?/gm, "") || "index.html"; 27 | } 28 | 29 | return getHashKey(event.rawPath); 30 | })(); 31 | 32 | let body = ""; 33 | let contentType = "image/png"; 34 | let statusCode = 200; 35 | const client = new S3(); 36 | 37 | try { 38 | if ( 39 | process.env.IS_OFFLINE || 40 | (isImageRequest && !shouldReturnImageFormat) 41 | ) { 42 | throw new Error("Skip get file"); 43 | } 44 | 45 | // get file from s3 46 | console.log("111: get file from s3"); 47 | const { Body, ContentType } = await client 48 | .getObject({ 49 | Bucket: process.env.WEBSITE_BUCKET as string, 50 | Key: key, 51 | }) 52 | .promise(); 53 | 54 | if (!ContentType || !Body) { 55 | contentType = "text/plain"; 56 | body = Buffer.from("body or content-type empty", "utf8").toString( 57 | "base64" 58 | ); 59 | } else { 60 | contentType = ContentType; 61 | body = Body.toString("base64"); 62 | } 63 | } catch { 64 | if (isImageRequest) { 65 | try { 66 | // generate image 67 | console.log("222: generate image"); 68 | const result = await generator(event.rawPath, event.rawQueryString); 69 | body = result.body; 70 | contentType = result.type; 71 | 72 | if (!process.env.IS_OFFLINE && shouldReturnImageFormat) { 73 | await client 74 | .putObject({ 75 | Bucket: process.env.WEBSITE_BUCKET as string, 76 | Key: key, 77 | Body: Buffer.from(body, "base64"), 78 | ContentType: contentType, 79 | }) 80 | .promise(); 81 | } 82 | } catch (err) { 83 | console.log("333: generate error"); 84 | console.log(err); 85 | 86 | // we serve body with 200 instead of throwing 404 here because 87 | // custom error page was set to have short cache time, meant for website. 88 | body = get404(); 89 | } 90 | } else { 91 | // serve 404 92 | console.log("444: serve error"); 93 | 94 | // throw 404 here to let cloudfront use custom error page 95 | statusCode = 404; 96 | contentType = "text/plain"; 97 | body = Buffer.from("Not found").toString("base64"); 98 | } 99 | } 100 | 101 | // log({ event }); 102 | // log({ context }); 103 | return { 104 | statusCode, 105 | isBase64Encoded: true, 106 | body, 107 | headers: Object.assign( 108 | { 109 | "Content-Type": contentType, 110 | }, 111 | isImageRequest 112 | ? { 113 | "Access-Control-Allow-Origin": "*", 114 | "Cross-Origin-Resource-Policy": "cross-origin", 115 | } 116 | : {}, 117 | getCacheHeader(key, statusCode) 118 | ), 119 | }; 120 | } 121 | -------------------------------------------------------------------------------- /placequran-serverless/src/lib/get404.ts: -------------------------------------------------------------------------------- 1 | // can't get lambda to read local image. 2 | // lets return base64 directly, at least faster than another read to s3. 3 | // this is from error-404.png in placequran-website 4 | export default (): string => { 5 | return "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"; 6 | }; 7 | -------------------------------------------------------------------------------- /placequran-serverless/serverless.yml: -------------------------------------------------------------------------------- 1 | service: placequran-sls 2 | frameworkVersion: "2" 3 | variablesResolutionMode: 20210326 4 | 5 | plugins: 6 | - serverless-webpack 7 | 8 | # to works locally, comment `serverless-webpack` above, and uncomment both below 9 | # - serverless-plugin-typescript 10 | # - serverless-offline 11 | 12 | custom: 13 | dotenvVars: ${file(env.js)} 14 | 15 | provider: 16 | name: aws 17 | runtime: nodejs14.x 18 | lambdaHashingVersion: 20201221 19 | 20 | stage: ${self:custom.dotenvVars.ENVIRONMENT, 'dev'} 21 | region: ${self:custom.dotenvVars.AWS_DEFAULT_REGION, 'us-east-1'} 22 | 23 | iamRoleStatements: 24 | - Effect: "Allow" 25 | Action: 26 | - "s3:GetObject" 27 | Resource: 28 | Fn::Join: ["", ["arn:aws:s3:::", { "Ref": WebsiteBucket }, "/*"]] 29 | - Effect: "Allow" 30 | Action: 31 | - "s3:ListBucket" 32 | Resource: 33 | Fn::Join: ["", ["arn:aws:s3:::", { "Ref": WebsiteBucket }]] 34 | - Effect: "Allow" 35 | Action: 36 | - "s3:PutObject" 37 | Resource: 38 | Fn::Join: ["", ["arn:aws:s3:::", { "Ref": WebsiteBucket }, "/*"]] 39 | 40 | environment: 41 | WEBSITE_BUCKET: !Ref WebsiteBucket 42 | 43 | package: 44 | individually: true 45 | 46 | functions: 47 | originLambda: 48 | handler: src/origin-lambda.handler 49 | timeout: 20 50 | layers: 51 | - ${self:custom.dotenvVars.PLACEQURAN_LAYER_ARN, 'arn:aws:lambda:us-east-1:321068630266:layer:placequran-layer:3'} 52 | events: 53 | - httpApi: "*" 54 | 55 | resources: 56 | Resources: 57 | WebsiteBucket: 58 | Type: AWS::S3::Bucket 59 | Properties: 60 | BucketName: ${self:custom.dotenvVars.BUCKET_NAME, 'placequran-website'}-${self:provider.stage} 61 | LifecycleConfiguration: 62 | Rules: 63 | - Id: remove-tmp-after-3-month 64 | Prefix: tmp/ 65 | Status: Enabled 66 | ExpirationInDays: 90 67 | WebsiteBucketAllowPublicReadPolicy: 68 | Type: AWS::S3::BucketPolicy 69 | Properties: 70 | Bucket: !Ref WebsiteBucket 71 | PolicyDocument: 72 | Version: "2012-10-17" 73 | Statement: 74 | - Effect: Allow 75 | Action: "s3:GetObject" 76 | Resource: 77 | - !Join ["/", [!GetAtt [WebsiteBucket, Arn], "*"]] 78 | Principal: "*" 79 | CloudfronOriginRequestPolicy: 80 | Type: AWS::CloudFront::OriginRequestPolicy 81 | Properties: 82 | OriginRequestPolicyConfig: 83 | Name: CustomOriginRequestPolicy 84 | Comment: "Device headers" 85 | HeadersConfig: 86 | HeaderBehavior: whitelist 87 | Headers: 88 | - User-Agent 89 | - Referer 90 | - CloudFront-Is-Mobile-Viewer 91 | - CloudFront-Is-Tablet-Viewer 92 | - CloudFront-Is-Desktop-Viewer 93 | CookiesConfig: 94 | CookieBehavior: none 95 | QueryStringsConfig: 96 | QueryStringBehavior: none 97 | CloudFrontDistribution: 98 | Type: AWS::CloudFront::Distribution 99 | Properties: 100 | DistributionConfig: 101 | Enabled: true 102 | PriceClass: ${self:custom.dotenvVars.CLOUDFRONT_PRICECLASS, 'PriceClass_100'} 103 | Origins: 104 | - Id: Lambda Origin 105 | DomainName: 106 | Fn::Join: 107 | [ 108 | ".", 109 | [ 110 | { "Ref": HttpApi }, 111 | "execute-api", 112 | { "Ref": AWS::Region }, 113 | "amazonaws.com", 114 | ], 115 | ] 116 | CustomOriginConfig: 117 | OriginProtocolPolicy: match-viewer 118 | - Id: S3 Origin 119 | DomainName: !GetAtt [WebsiteBucket, RegionalDomainName] 120 | S3OriginConfig: {} 121 | CacheBehaviors: 122 | - TargetOriginId: S3 Origin 123 | CachePolicyId: "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" # CachingDisabled temporarily for dev 124 | ViewerProtocolPolicy: redirect-to-https 125 | PathPattern: "*.*" 126 | - TargetOriginId: Lambda Origin 127 | CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6" # CachingOptimized 128 | ViewerProtocolPolicy: redirect-to-https 129 | PathPattern: "*/*" 130 | OriginRequestPolicyId: !Ref CloudfronOriginRequestPolicy 131 | FunctionAssociations: 132 | - EventType: viewer-request 133 | FunctionARN: !GetAtt CloudfrontFunction.FunctionMetadata.FunctionARN 134 | DefaultCacheBehavior: 135 | TargetOriginId: S3 Origin 136 | CachePolicyId: "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" # CachingDisabled temporarily for dev 137 | ViewerProtocolPolicy: redirect-to-https 138 | DefaultRootObject: index.html 139 | Aliases: 140 | Fn::Split: 141 | - "," 142 | - ${self:custom.dotenvVars.CLOUDFRONT_DOMAINS, "${self:provider.stage}.placequran.com"} 143 | ViewerCertificate: 144 | AcmCertificateArn: ${self:custom.dotenvVars.CLOUDFRONT_ACM_CERT_ARN, "arn:aws:acm:us-east-1:321068630266:certificate/10cfa1d6-4dc9-4110-a1e5-4c34e3de12ef"} 145 | MinimumProtocolVersion: TLSv1 146 | SslSupportMethod: sni-only 147 | CustomErrorResponses: 148 | - ErrorCode: 400 149 | ResponseCode: 200 150 | ResponsePagePath: "/error-404.png" 151 | - ErrorCode: 403 152 | ResponseCode: 200 153 | ResponsePagePath: "/error-404.png" 154 | - ErrorCode: 404 155 | ResponseCode: 200 156 | ResponsePagePath: "/error-404.png" 157 | - ErrorCode: 500 158 | ResponseCode: 200 159 | ResponsePagePath: "/error-404.png" 160 | - ErrorCode: 503 161 | ResponseCode: 200 162 | ResponsePagePath: "/error-404.png" 163 | CloudfrontFunction: 164 | Type: AWS::CloudFront::Function 165 | Properties: 166 | Name: serve-by-device 167 | AutoPublish: true 168 | FunctionConfig: 169 | Comment: !Sub "${AWS::StackName} Dynamic Size" 170 | Runtime: cloudfront-js-1.0 171 | FunctionCode: | 172 | function handler(event) { 173 | var request = event.request; 174 | var headers = request.headers; 175 | 176 | var isMobile = 177 | headers["cloudfront-is-mobile-viewer"] && 178 | headers["cloudfront-is-mobile-viewer"].value.toLowerCase() == "true"; 179 | 180 | var isTablet = 181 | headers["cloudfront-is-tablet-viewer"] && 182 | headers["cloudfront-is-tablet-viewer"].value.toLowerCase() == "true"; 183 | 184 | var isDesktop = 185 | headers["cloudfront-is-desktop-viewer"] && 186 | headers["cloudfront-is-desktop-viewer"].value.toLowerCase() == "true"; 187 | 188 | if (["s", "m", "l"].some((size) => request.uri.startsWith(`/${size}/`))) { 189 | return request; 190 | } 191 | 192 | if (isDesktop) { 193 | request.uri = "/l" + request.uri; 194 | } else if (isMobile && !isTablet) { 195 | request.uri = "/s" + request.uri; 196 | } else { 197 | request.uri = "/m" + request.uri; 198 | } 199 | 200 | return request; 201 | } 202 | -------------------------------------------------------------------------------- /placequran-website/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Place Quran 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 |

Place Quran

36 |

The easiest way to get quran aya image.

37 |
38 |
39 |
Just call this url to get a Quran image
40 |
41 |
42 | placequran.com / {surah} / {aya} / {translation} 43 |
44 |
    45 |
  • 46 | Translation is optional. If not specified, it will use the default ar. 47 |
  • 48 |
  • 49 | Aya will be return in order as you specify in the url. 50 |
  • 51 |
  • 52 | Image size automatically adapts to the viewing device. 53 |
  • 54 |
55 |
56 |

Usage

57 |

Basic

58 |
    59 |
  1. 60 | Return aya 14 from surah 2 (al Baqarah) 61 |
    placequran.com/2/14
    62 |
    63 |
  2. 64 |
  3. 65 | Return aya 10 to 18 from surah 3 (ali Imran) 66 |
    placequran.com/3/10-18
    67 |
    68 |
  4. 69 |
70 |

Mix aya

71 |
    72 |
  1. 73 | Return aya 20, 25, and 33 from surah 4 (an Nisa) 74 |
    placequran.com/4/20,25,33
    75 |
    76 |
  2. 77 |
  3. 78 | You can mix individual and range of aya. Below will return aya 2, 5, 7 - 10, and 13 from surah 5 (al Maidah) 79 |
    placequran.com/5/2,5,7-10,13
    80 |
    81 |
  4. 82 |
83 |

Translation

84 |
    85 |
  1. 86 | Return aya 40 to 42 from surah 6 (Surat Al-'An`ām), with Arabic and Malay translation 87 |
    placequran.com/6/40-42/ar,ms
    88 | Below are the supported translations. (will add more upon request) 89 |
      90 |
    • ar Arabic (Original Al-Quran Text)
    • 91 |
    • en English (Yusuf Ali)
    • 92 |
    • ms Malay (Basmeih)
    • 93 |
    • in Indonesian (Bahasa Indonesia)
    • 94 |
    95 |
  2. 96 |
97 |

Size

98 |

By default, image size automatically adapts to the viewing device. To request a specific size regardless of the viewing device, put the size as prefix.

99 |
    100 |
  1. 101 | Always return the small image size. 102 |
    placequran.com/s/2/14
    103 | Where size can be s / m / l. 104 |
    105 |
  2. 106 |
107 |

Use in HTML

108 | Since every request to the URL will get image response, you can put the URL inside any image source link. 109 |
<img src="https://placequran.com/2/70,71/ar,en"/>
110 |
111 |

Limitation

112 |
    113 |
  1. The first request will take few seconds, as it being generated. Subsequent requests will be blazing fast as it load from the CDN.
  2. 114 |
  3. In a single image, only 15 aya and 3 translations can be displayed. Feel free to generate another one if you need more.
  4. 115 |
116 |
117 |
118 | 119 |

Screenshot

120 | Image 121 | Image 122 | Image 123 |
124 |
125 |

Contributers

126 |
    127 |
  • Faiz Shukri (Developer)
  • 128 |
  • Tanzil.net (Quran & Translation provider)
  • 129 |
130 |

131 |
132 |
Created with ♥ by © Faiz Shukri (@le_faizshukri) | 2014 -
133 |
134 |
135 |
136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 154 | 155 | -------------------------------------------------------------------------------- /placequran-layer/src/data/mysql2sqlite: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | # Authors: @esperlu, @artemyk, @gkuenning, @dumblob 4 | 5 | # FIXME detect empty input file and issue a warning 6 | 7 | function printerr( s ){ print s | "cat >&2" } 8 | 9 | BEGIN { 10 | if( ARGC != 2 ){ 11 | printerr( \ 12 | "USAGE:\n"\ 13 | " mysql2sqlite dump_mysql.sql > dump_sqlite3.sql\n" \ 14 | " OR\n" \ 15 | " mysql2sqlite dump_mysql.sql | sqlite3 sqlite.db\n" \ 16 | "\n" \ 17 | "NOTES:\n" \ 18 | " Dash in filename is not supported, because dash (-) means stdin." ) 19 | no_END = 1 20 | exit 1 21 | } 22 | 23 | # Find INT_MAX supported by both this AWK (usually an ISO C signed int) 24 | # and SQlite. 25 | # On non-8bit-based architectures, the additional bits are safely ignored. 26 | 27 | # 8bit (lower precision should not exist) 28 | s="127" 29 | # "63" + 0 avoids potential parser misbehavior 30 | if( (s + 0) "" == s ){ INT_MAX_HALF = "63" + 0 } 31 | # 16bit 32 | s="32767" 33 | if( (s + 0) "" == s ){ INT_MAX_HALF = "16383" + 0 } 34 | # 32bit 35 | s="2147483647" 36 | if( (s + 0) "" == s ){ INT_MAX_HALF = "1073741823" + 0 } 37 | # 64bit (as INTEGER in SQlite3) 38 | s="9223372036854775807" 39 | if( (s + 0) "" == s ){ INT_MAX_HALF = "4611686018427387904" + 0 } 40 | # # 128bit 41 | # s="170141183460469231731687303715884105728" 42 | # if( (s + 0) "" == s ){ INT_MAX_HALF = "85070591730234615865843651857942052864" + 0 } 43 | # # 256bit 44 | # s="57896044618658097711785492504343953926634992332820282019728792003956564819968" 45 | # if( (s + 0) "" == s ){ INT_MAX_HALF = "28948022309329048855892746252171976963317496166410141009864396001978282409984" + 0 } 46 | # # 512bit 47 | # s="6703903964971298549787012499102923063739682910296196688861780721860882015036773488400937149083451713845015929093243025426876941405973284973216824503042048" 48 | # if( (s + 0) "" == s ){ INT_MAX_HALF = "3351951982485649274893506249551461531869841455148098344430890360930441007518386744200468574541725856922507964546621512713438470702986642486608412251521024" + 0 } 49 | # # 1024bit 50 | # s="89884656743115795386465259539451236680898848947115328636715040578866337902750481566354238661203768010560056939935696678829394884407208311246423715319737062188883946712432742638151109800623047059726541476042502884419075341171231440736956555270413618581675255342293149119973622969239858152417678164812112068608" 51 | # if( (s + 0) "" == s ){ INT_MAX_HALF = "44942328371557897693232629769725618340449424473557664318357520289433168951375240783177119330601884005280028469967848339414697442203604155623211857659868531094441973356216371319075554900311523529863270738021251442209537670585615720368478277635206809290837627671146574559986811484619929076208839082406056034304" + 0 } 52 | # # higher precision probably not needed 53 | 54 | FS=",$" 55 | print "PRAGMA synchronous = OFF;" 56 | print "PRAGMA journal_mode = MEMORY;" 57 | print "BEGIN TRANSACTION;" 58 | } 59 | 60 | # historically 3 spaces separate non-argument local variables 61 | function bit_to_int( str_bit, powtwo, i, res, bit, overflow ){ 62 | powtwo = 1 63 | overflow = 0 64 | # 011101 = 1*2^0 + 0*2^1 + 1*2^2 ... 65 | for( i = length( str_bit ); i > 0; --i ){ 66 | bit = substr( str_bit, i, 1 ) 67 | if( overflow || ( bit == 1 && res > INT_MAX_HALF ) ){ 68 | printerr( \ 69 | NR ": WARN Bit field overflow, number truncated (LSBs saved, MSBs ignored)." ) 70 | break 71 | } 72 | res = res + bit * powtwo 73 | # no warning here as it might be the last iteration 74 | if( powtwo > INT_MAX_HALF ){ overflow = 1; continue } 75 | powtwo = powtwo * 2 76 | } 77 | return res 78 | } 79 | 80 | # CREATE TRIGGER statements have funny commenting. Remember we are in trigger. 81 | /^\/\*.*(CREATE.*TRIGGER|create.*trigger)/ { 82 | gsub( /^.*(TRIGGER|trigger)/, "CREATE TRIGGER" ) 83 | print 84 | inTrigger = 1 85 | next 86 | } 87 | # The end of CREATE TRIGGER has a stray comment terminator 88 | /(END|end) \*\/;;/ { gsub( /\*\//, "" ); print; inTrigger = 0; next } 89 | # The rest of triggers just get passed through 90 | inTrigger != 0 { print; next } 91 | 92 | # CREATE VIEW looks like a TABLE in comments 93 | /^\/\*.*(CREATE.*TABLE|create.*table)/ { 94 | inView = 1 95 | next 96 | } 97 | # end of CREATE VIEW 98 | /^(\).*(ENGINE|engine).*\*\/;)/ { 99 | inView = 0 100 | next 101 | } 102 | # content of CREATE VIEW 103 | inView != 0 { next } 104 | 105 | # skip comments 106 | /^\/\*/ { next } 107 | 108 | # skip PARTITION statements 109 | /^ *[(]?(PARTITION|partition) +[^ ]+/ { next } 110 | 111 | # print all INSERT lines 112 | ( /^ *\(/ && /\) *[,;] *$/ ) || /^(INSERT|insert|REPLACE|replace)/ { 113 | prev = "" 114 | 115 | # first replace \\ by \_ that mysqldump never generates to deal with 116 | # sequnces like \\n that should be translated into \n, not \. 117 | # After we convert all escapes we replace \_ by backslashes. 118 | gsub( /\\\\/, "\\_" ) 119 | 120 | # single quotes are escaped by another single quote 121 | gsub( /\\'/, "''" ) 122 | gsub( /\\n/, "\n" ) 123 | gsub( /\\r/, "\r" ) 124 | gsub( /\\"/, "\"" ) 125 | gsub( /\\\032/, "\032" ) # substitute char 126 | 127 | gsub( /\\_/, "\\" ) 128 | 129 | # sqlite3 is limited to 16 significant digits of precision 130 | while( match( $0, /0x[0-9a-fA-F]{17}/ ) ){ 131 | hexIssue = 1 132 | sub( /0x[0-9a-fA-F]+/, substr( $0, RSTART, RLENGTH-1 ), $0 ) 133 | } 134 | if( hexIssue ){ 135 | printerr( \ 136 | NR ": WARN Hex number trimmed (length longer than 16 chars)." ) 137 | hexIssue = 0 138 | } 139 | print 140 | next 141 | } 142 | 143 | # CREATE DATABASE is not supported 144 | /^(CREATE DATABASE|create database)/ { next } 145 | 146 | # print the CREATE line as is and capture the table name 147 | /^(CREATE|create)/ { 148 | if( $0 ~ /IF NOT EXISTS|if not exists/ || $0 ~ /TEMPORARY|temporary/ ){ 149 | caseIssue = 1 150 | printerr( \ 151 | NR ": WARN Potential case sensitivity issues with table/column naming\n" \ 152 | " (see INFO at the end)." ) 153 | } 154 | if( match( $0, /`[^`]+/ ) ){ 155 | tableName = substr( $0, RSTART+1, RLENGTH-1 ) 156 | } 157 | aInc = 0 158 | prev = "" 159 | firstInTable = 1 160 | print 161 | next 162 | } 163 | 164 | # Replace `FULLTEXT KEY` (probably other `XXXXX KEY`) 165 | /^ (FULLTEXT KEY|fulltext key)/ { gsub( /[A-Za-z ]+(KEY|key)/, " KEY" ) } 166 | 167 | # Get rid of field lengths in KEY lines 168 | / (PRIMARY |primary )?(KEY|key)/ { gsub( /\([0-9]+\)/, "" ) } 169 | 170 | aInc == 1 && /PRIMARY KEY|primary key/ { next } 171 | 172 | # Replace COLLATE xxx_xxxx_xx statements with COLLATE BINARY 173 | / (COLLATE|collate) [a-z0-9_]*/ { gsub( /(COLLATE|collate) [a-z0-9_]*/, "COLLATE BINARY" ) } 174 | 175 | # Print all fields definition lines except the `KEY` lines. 176 | /^ / && !/^( (KEY|key)|\);)/ { 177 | if( match( $0, /[^"`]AUTO_INCREMENT|auto_increment[^"`]/) ){ 178 | aInc = 1 179 | gsub( /AUTO_INCREMENT|auto_increment/, "PRIMARY KEY AUTOINCREMENT" ) 180 | } 181 | gsub( /(UNIQUE KEY|unique key) (`.*`|".*") /, "UNIQUE " ) 182 | gsub( /(CHARACTER SET|character set) [^ ]+[ ,]/, "" ) 183 | # FIXME 184 | # CREATE TRIGGER [UpdateLastTime] 185 | # AFTER UPDATE 186 | # ON Package 187 | # FOR EACH ROW 188 | # BEGIN 189 | # UPDATE Package SET LastUpdate = CURRENT_TIMESTAMP WHERE ActionId = old.ActionId; 190 | # END 191 | gsub( /(ON|on) (UPDATE|update) (CURRENT_TIMESTAMP|current_timestamp)(\(\))?/, "" ) 192 | gsub( /(DEFAULT|default) (CURRENT_TIMESTAMP|current_timestamp)(\(\))?/, "DEFAULT current_timestamp") 193 | gsub( /(COLLATE|collate) [^ ]+ /, "" ) 194 | gsub( /(ENUM|enum)[^)]+\)/, "text " ) 195 | gsub( /(SET|set)\([^)]+\)/, "text " ) 196 | gsub( /UNSIGNED|unsigned/, "" ) 197 | gsub( /_utf8mb3/, "" ) 198 | gsub( /` [^ ]*(INT|int|BIT|bit)[^ ]*/, "` integer" ) 199 | gsub( /" [^ ]*(INT|int|BIT|bit)[^ ]*/, "\" integer" ) 200 | ere_bit_field = "[bB]'[10]+'" 201 | if( match($0, ere_bit_field) ){ 202 | sub( ere_bit_field, bit_to_int( substr( $0, RSTART +2, RLENGTH -2 -1 ) ) ) 203 | } 204 | 205 | # remove USING BTREE and other suffixes for USING, for example: "UNIQUE KEY 206 | # `hostname_domain` (`hostname`,`domain`) USING BTREE," 207 | gsub( / USING [^, ]+/, "" ) 208 | 209 | # field comments are not supported 210 | gsub( / (COMMENT|comment).+$/, "" ) 211 | # Get commas off end of line 212 | gsub( /,.?$/, "" ) 213 | if( prev ){ 214 | if( firstInTable ){ 215 | print prev 216 | firstInTable = 0 217 | } 218 | else { 219 | print "," prev 220 | } 221 | } 222 | else { 223 | # FIXME check if this is correct in all cases 224 | if( match( $1, 225 | /(CONSTRAINT|constraint) ["].*["] (FOREIGN KEY|foreign key)/ ) ){ 226 | print "," 227 | } 228 | } 229 | prev = $1 230 | } 231 | 232 | / ENGINE| engine/ { 233 | if( prev ){ 234 | if( firstInTable ){ 235 | print prev 236 | firstInTable = 0 237 | } 238 | else { 239 | print "," prev 240 | } 241 | } 242 | prev="" 243 | print ");" 244 | next 245 | } 246 | # `KEY` lines are extracted from the `CREATE` block and stored in array for later print 247 | # in a separate `CREATE KEY` command. The index name is prefixed by the table name to 248 | # avoid a sqlite error for duplicate index name. 249 | /^( (KEY|key)|\);)/ { 250 | if( prev ){ 251 | if( firstInTable ){ 252 | print prev 253 | firstInTable = 0 254 | } 255 | else { 256 | print "," prev 257 | } 258 | } 259 | prev = "" 260 | if( $0 == ");" ){ 261 | print 262 | } 263 | else { 264 | if( match( $0, /`[^`]+/ ) ){ 265 | indexName = substr( $0, RSTART+1, RLENGTH-1 ) 266 | } 267 | if( match( $0, /\([^()]+/ ) ){ 268 | indexKey = substr( $0, RSTART+1, RLENGTH-1 ) 269 | } 270 | # idx_ prefix to avoid name clashes (they really happen!) 271 | key[tableName] = key[tableName] "CREATE INDEX \"idx_" \ 272 | tableName "_" indexName "\" ON \"" tableName "\" (" indexKey ");\n" 273 | } 274 | } 275 | 276 | END { 277 | if( no_END ){ exit 1} 278 | # print all KEY creation lines. 279 | for( table in key ){ printf key[table] } 280 | 281 | print "END TRANSACTION;" 282 | 283 | if( caseIssue ){ 284 | printerr( \ 285 | "INFO Pure sqlite identifiers are case insensitive (even if quoted\n" \ 286 | " or if ASCII) and doesnt cross-check TABLE and TEMPORARY TABLE\n" \ 287 | " identifiers. Thus expect errors like \"table T has no column named F\".") 288 | } 289 | } 290 | -------------------------------------------------------------------------------- /placequran-serverless/src/quran.ts: -------------------------------------------------------------------------------- 1 | import { QuranParam } from "./interfaces/param"; 2 | import { Verse } from "./interfaces/verses"; 3 | import * as R from "ramda"; 4 | import html2image from "./lib/html2image"; 5 | import { sqliteDb, fontBase64 } from "placequran-layer"; 6 | import config from "./config"; 7 | import { Sura } from "./lib/quran-data"; 8 | 9 | export class QuranParamError extends Error { 10 | constructor(m: string) { 11 | super(m); 12 | } 13 | } 14 | 15 | export const parseParam = ( 16 | surah: string, 17 | verses: string, 18 | translations?: string 19 | ): QuranParam => { 20 | if (!surah || !verses) { 21 | throw new QuranParamError("Both surah and verses are required"); 22 | } 23 | 24 | if (isNaN(parseInt(surah))) { 25 | throw new QuranParamError("Invalid surah"); 26 | } 27 | 28 | if (/[^\d,-\s]/.test(verses) || /(^|[,-])\s*([,-]|$)/.test(verses)) { 29 | throw new QuranParamError("Invalid verses"); 30 | } 31 | 32 | if ( 33 | translations === "" || 34 | /[^\w\d,\s]/.test(translations) || 35 | /(^|[,])\s*([,]|$)/.test(translations) 36 | ) { 37 | throw new QuranParamError("Invalid translations"); 38 | } 39 | 40 | return { 41 | surah: parseInt(surah), 42 | verses: verses 43 | .replace(" ", "") 44 | .split(",") 45 | .flatMap((num) => { 46 | if (num.includes("-")) { 47 | const [from, to] = num.split("-").map((num) => parseInt(num)); 48 | if (from > to) { 49 | throw new QuranParamError("Invalid verses"); 50 | } 51 | 52 | return Array(to - from + 1) 53 | .fill(0) 54 | .map((_, idx) => from + idx); 55 | } 56 | 57 | return parseInt(num); 58 | }) 59 | .sort((a, b) => a - b), 60 | translations: 61 | translations && translations.length 62 | ? translations.replace(" ", "").split(",") 63 | : ["ar"], 64 | }; 65 | }; 66 | 67 | export const filterParam = (param: QuranParam): QuranParam => { 68 | if (param.surah < 1 || param.surah > 114) { 69 | return { 70 | surah: 0, 71 | verses: [], 72 | translations: ["ar"], 73 | }; 74 | } 75 | 76 | const maxVerses = Sura[param.surah][1]; 77 | 78 | param.verses = param.verses 79 | .filter((a) => a <= maxVerses) 80 | .slice(0, config.max_verses); 81 | 82 | param.translations = param.translations 83 | .filter((a) => !!config.translations[a]) 84 | .slice(0, config.max_translation); 85 | 86 | return param; 87 | }; 88 | 89 | export const getVerses = async ( 90 | param: QuranParam 91 | ): Promise<{ [key: string]: Verse[] }> => { 92 | const { surah, verses, translations } = filterParam(param); 93 | const results = await Promise.all( 94 | translations.map(async (translation) => { 95 | return sqliteDb 96 | .prepare( 97 | `SELECT aya, sura, text FROM ${ 98 | config.translations[translation] 99 | } WHERE sura = ? AND aya IN (${verses 100 | .slice(0, config.max_verses) 101 | .map(() => "?") 102 | .join(", ")})` 103 | ) 104 | .all(surah, ...verses.slice(0, config.max_verses)); 105 | }) 106 | ); 107 | 108 | const response = {}; 109 | translations.forEach((translation, index) => { 110 | response[translation] = results[index]; 111 | }); 112 | 113 | return response; 114 | }; 115 | 116 | export const prepareForHtml = (translations: { 117 | [key: string]: Verse[]; 118 | }): { translation: string; meta?: string; verses: Verse[] }[] => { 119 | const merged = Object.keys(translations).flatMap((translation) => { 120 | return translations[translation].map((verse) => ({ 121 | ...verse, 122 | translation, 123 | })); 124 | }); 125 | 126 | // const debug = (a) => { 127 | // console.log(util.inspect(a, false, null, true /* enable colors */)); 128 | // return a; 129 | // }; 130 | const metadata = {}; 131 | const getMeta = (verses) => { 132 | return { 133 | translation: "meta", 134 | meta: `${Sura[verses[0].sura][5]}: ${verses[0].aya}${ 135 | verses.length > 1 ? `-${R.last(verses).aya}` : "" 136 | }`, 137 | verses: [], 138 | }; 139 | }; 140 | 141 | return R.pipe( 142 | R.sort(R.ascend(R.prop("aya"))), 143 | R.reduce((acc, verse) => { 144 | const lastTranslationIndex = R.findLastIndex( 145 | R.propEq("translation", verse.translation) 146 | )(acc); 147 | 148 | if (lastTranslationIndex < 0) { 149 | const { translation, ...others } = verse; 150 | acc.push({ 151 | translation, 152 | verses: [others], 153 | }); 154 | return acc; 155 | } 156 | 157 | const { translation, verses } = acc[lastTranslationIndex]; 158 | const lastVerse = verses[verses.length - 1]; 159 | 160 | if ( 161 | verse.translation === translation && 162 | verse.aya === lastVerse.aya + 1 163 | ) { 164 | delete verse.translation; 165 | acc[lastTranslationIndex].verses.push(verse); 166 | } else { 167 | const metaKey = `meta-${acc[lastTranslationIndex].verses[0].aya}`; 168 | if (!metadata[metaKey]) { 169 | metadata[metaKey] = true; 170 | acc.push(getMeta(R.last(acc).verses)); 171 | } 172 | const { translation, ...others } = verse; 173 | 174 | acc.push({ 175 | translation, 176 | verses: [others], 177 | }); 178 | } 179 | 180 | return acc; 181 | }, []), 182 | (val) => { 183 | val.push(getMeta(R.last(val).verses)); 184 | return val; 185 | } 186 | )(merged); 187 | }; 188 | 189 | export const romanToArabic = (number: number): string => { 190 | const numeral = [".", "١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩"]; 191 | return number 192 | .toString() 193 | .split("") 194 | .map((a) => numeral[a]) 195 | .join(""); 196 | }; 197 | 198 | export const generateHtml = ( 199 | translations: { translation: string; meta?: string; verses: Verse[] }[], 200 | size?: string 201 | ): string => { 202 | if (!translations || translations.length == 0) { 203 | throw new QuranParamError("Data not available"); 204 | } 205 | 206 | if (!size) { 207 | size = "m"; 208 | } 209 | 210 | const fonts = { 211 | MeQuran: fontBase64.MeQuran(), 212 | NotoNaskhArabic: fontBase64.NotoNaskhArabic(), 213 | OpenSans: fontBase64.OpenSans(), 214 | }; 215 | 216 | return ` 217 | 218 | 219 | 220 | Place Quran 221 | 222 | 223 | 318 | 319 | 320 | ${translations 321 | .map(({ translation, meta, verses }) => { 322 | return ` 323 |
324 | ${ 325 | translation == "meta" 326 | ? `— ${meta}` 327 | : verses 328 | .map((verse, index) => { 329 | const isLast = index == verses.length - 1; 330 | return `${verse.text}${ 331 | translation === "ar" 332 | ? `  ۝ ${romanToArabic( 335 | verse.aya 336 | )}` 337 | : ` [${verse.aya}]` 338 | }`; 339 | }) 340 | .join("  ") 341 | } 342 |
343 | `; 344 | }) 345 | .join("")} 346 | 347 | 348 | `; 349 | }; 350 | 351 | export const renderImage = html2image; 352 | -------------------------------------------------------------------------------- /placequran-website/src/js/highlight.pack.js: -------------------------------------------------------------------------------- 1 | var hljs=new function(){function k(v){return v.replace(/&/gm,"&").replace(//gm,">")}function t(v){return v.nodeName.toLowerCase()}function i(w,x){var v=w&&w.exec(x);return v&&v.index==0}function d(v){return Array.prototype.map.call(v.childNodes,function(w){if(w.nodeType==3){return b.useBR?w.nodeValue.replace(/\n/g,""):w.nodeValue}if(t(w)=="br"){return"\n"}return d(w)}).join("")}function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.className:"")).split(/\s+/);v=v.map(function(x){return x.replace(/^language-/,"")});return v.filter(function(x){return j(x)||x=="no-highlight"})[0]}function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y){v[w]=y[w]}}return v}function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nextSibling){if(A.nodeType==3){z+=A.nodeValue.length}else{if(t(A)=="br"){z+=1}else{if(A.nodeType==1){v.push({event:"start",offset:z,node:A});z=w(A,z);v.push({event:"stop",offset:z,node:A})}}}}return z})(x,0);return v}function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!y.length){return w.length?w:y}if(w[0].offset!=y[0].offset){return(w[0].offset"}function E(G){F+=""}function v(G){(G.event=="start"?A:E)(G.node)}while(w.length||y.length){var D=B();F+=k(C.substr(x,D[0].offset-x));x=D[0].offset;if(D==w){z.reverse().forEach(E);do{v(D.splice(0,1)[0]);D=B()}while(D==w&&D.length&&D[0].offset==x);z.reverse().forEach(A)}else{if(D[0].event=="start"){z.push(D[0].node)}else{z.pop()}v(D.splice(0,1)[0])}}return F+k(C.substr(x))}function m(y){function v(z){return(z&&z.source)||z}function w(A,z){return RegExp(v(A),"m"+(y.cI?"i":"")+(z?"g":""))}function x(D,C){if(D.compiled){return}D.compiled=true;D.k=D.k||D.bK;if(D.k){var z={};function E(G,F){if(y.cI){F=F.toLowerCase()}F.split(" ").forEach(function(H){var I=H.split("|");z[I[0]]=[G,I[1]?Number(I[1]):1]})}if(typeof D.k=="string"){E("keyword",D.k)}else{Object.keys(D.k).forEach(function(F){E(F,D.k[F])})}D.k=z}D.lR=w(D.l||/\b[A-Za-z0-9_]+\b/,true);if(C){if(D.bK){D.b=D.bK.split(" ").join("|")}if(!D.b){D.b=/\B|\b/}D.bR=w(D.b);if(!D.e&&!D.eW){D.e=/\B|\b/}if(D.e){D.eR=w(D.e)}D.tE=v(D.e)||"";if(D.eW&&C.tE){D.tE+=(D.e?"|":"")+C.tE}}if(D.i){D.iR=w(D.i)}if(D.r===undefined){D.r=1}if(!D.c){D.c=[]}var B=[];D.c.forEach(function(F){if(F.v){F.v.forEach(function(G){B.push(o(F,G))})}else{B.push(F=="self"?D:F)}});D.c=B;D.c.forEach(function(F){x(F,D)});if(D.starts){x(D.starts,C)}var A=D.c.map(function(F){return F.bK?"\\.?\\b("+F.b+")\\b\\.?":F.b}).concat([D.tE]).concat([D.i]).map(v).filter(Boolean);D.t=A.length?w(A.join("|"),true):{exec:function(F){return null}};D.continuation={}}x(y)}function c(S,L,J,R){function v(U,V){for(var T=0;T";U+=Z+'">';return U+X+Y}function N(){var U=k(C);if(!I.k){return U}var T="";var X=0;I.lR.lastIndex=0;var V=I.lR.exec(U);while(V){T+=U.substr(X,V.index-X);var W=E(I,V);if(W){H+=W[1];T+=w(W[0],V[0])}else{T+=V[0]}X=I.lR.lastIndex;V=I.lR.exec(U)}return T+U.substr(X)}function F(){if(I.sL&&!f[I.sL]){return k(C)}var T=I.sL?c(I.sL,C,true,I.continuation.top):g(C);if(I.r>0){H+=T.r}if(I.subLanguageMode=="continuous"){I.continuation.top=T.top}return w(T.language,T.value,false,true)}function Q(){return I.sL!==undefined?F():N()}function P(V,U){var T=V.cN?w(V.cN,"",true):"";if(V.rB){D+=T;C=""}else{if(V.eB){D+=k(U)+T;C=""}else{D+=T;C=U}}I=Object.create(V,{parent:{value:I}})}function G(T,X){C+=T;if(X===undefined){D+=Q();return 0}var V=v(X,I);if(V){D+=Q();P(V,X);return V.rB?0:X.length}var W=z(I,X);if(W){var U=I;if(!(U.rE||U.eE)){C+=X}D+=Q();do{if(I.cN){D+=""}H+=I.r;I=I.parent}while(I!=W.parent);if(U.eE){D+=k(X)}C="";if(W.starts){P(W.starts,"")}return U.rE?0:X.length}if(A(X,I)){throw new Error('Illegal lexeme "'+X+'" for mode "'+(I.cN||"")+'"')}C+=X;return X.length||1}var M=j(S);if(!M){throw new Error('Unknown language: "'+S+'"')}m(M);var I=R||M;var D="";for(var K=I;K!=M;K=K.parent){if(K.cN){D=w(K.cN,D,true)}}var C="";var H=0;try{var B,y,x=0;while(true){I.t.lastIndex=x;B=I.t.exec(L);if(!B){break}y=G(L.substr(x,B.index-x),B[0]);x=B.index+y}G(L.substr(x));for(var K=I;K.parent;K=K.parent){if(K.cN){D+=""}}return{r:H,value:D,language:S,top:I}}catch(O){if(O.message.indexOf("Illegal")!=-1){return{r:0,value:k(L)}}else{throw O}}}function g(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:k(y)};var w=v;x.forEach(function(z){if(!j(z)){return}var A=c(z,y,false);A.language=z;if(A.r>w.r){w=A}if(A.r>v.r){w=v;v=A}});if(w.language){v.second_best=w}return v}function h(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function(w,z,y,x){return z.replace(/\t/g,b.tabReplace)})}if(b.useBR){v=v.replace(/\n/g,"
")}return v}function p(z){var y=d(z);var A=r(z);if(A=="no-highlight"){return}var v=A?c(A,y,true):g(y);var w=u(z);if(w.length){var x=document.createElementNS("http://www.w3.org/1999/xhtml","pre");x.innerHTML=v.value;v.value=q(w,u(x),y)}v.value=h(v.value);z.innerHTML=v.value;z.className+=" hljs "+(!A&&v.language||"");z.result={language:v.language,re:v.r};if(v.second_best){z.second_best={language:v.second_best.language,re:v.second_best.r}}}var b={classPrefix:"hljs-",tabReplace:null,useBR:false,languages:undefined};function s(v){b=o(b,v)}function l(){if(l.called){return}l.called=true;var v=document.querySelectorAll("pre code");Array.prototype.forEach.call(v,p)}function a(){addEventListener("DOMContentLoaded",l,false);addEventListener("load",l,false)}var f={};var n={};function e(v,x){var w=f[v]=x(this);if(w.aliases){w.aliases.forEach(function(y){n[y]=v})}}function j(v){return f[v]||f[n[v]]}this.highlight=c;this.highlightAuto=g;this.fixMarkup=h;this.highlightBlock=p;this.configure=s;this.initHighlighting=l;this.initHighlightingOnLoad=a;this.registerLanguage=e;this.getLanguage=j;this.inherit=o;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE]};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE]};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.REGEXP_MODE={cN:"regexp",b:/\//,e:/\/[gim]*/,i:/\n/,c:[this.BE,{b:/\[/,e:/\]/,r:0,c:[this.BE]}]};this.TM={cN:"title",b:this.IR,r:0};this.UTM={cN:"title",b:this.UIR,r:0}}();hljs.registerLanguage("javascript",function(a){return{aliases:["js"],k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require"},c:[{cN:"pi",b:/^\s*('|")use strict('|")/,r:10},a.ASM,a.QSM,a.CLCM,a.CBLCLM,a.CNM,{b:"("+a.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[a.CLCM,a.CBLCLM,a.REGEXP_MODE,{b:/;/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,c:[a.inherit(a.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[a.CLCM,a.CBLCLM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+a.IR,r:0}]}});hljs.registerLanguage("css",function(a){var b="[a-zA-Z-][a-zA-Z0-9_-]*";var c={cN:"function",b:b+"\\(",e:"\\)",c:["self",a.NM,a.ASM,a.QSM]};return{cI:true,i:"[=/|']",c:[a.CBLCLM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:true,eE:true,r:0,c:[c,a.ASM,a.QSM,a.NM]}]},{cN:"tag",b:b,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[a.CBLCLM,{cN:"rule",b:"[^\\s]",rB:true,e:";",eW:true,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:true,i:"[^\\s]",starts:{cN:"value",eW:true,eE:true,c:[c,a.NM,a.QSM,a.ASM,a.CBLCLM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]}]}]}});hljs.registerLanguage("xml",function(a){var c="[A-Za-z0-9\\._:-]+";var d={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php",subLanguageMode:"continuous"};var b={eW:true,i:/]+/}]}]}]};return{aliases:["html"],cI:true,c:[{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[b],starts:{e:"",rE:true,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},d,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",c:[{cN:"title",b:"[^ /><]+",r:0},b]}]}});hljs.registerLanguage("php",function(b){var e={cN:"variable",b:"\\$+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*"};var a={cN:"preprocessor",b:/<\?(php)?|\?>/};var c={cN:"string",c:[b.BE,a],v:[{b:'b"',e:'"'},{b:"b'",e:"'"},b.inherit(b.ASM,{i:null}),b.inherit(b.QSM,{i:null})]};var d={v:[b.BNM,b.CNM]};return{cI:true,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally",c:[b.CLCM,b.HCM,{cN:"comment",b:"/\\*",e:"\\*/",c:[{cN:"phpdoc",b:"\\s@[A-Za-z]+"},a]},{cN:"comment",b:"__halt_compiler.+?;",eW:true,k:"__halt_compiler",l:b.UIR},{cN:"string",b:"<<<['\"]?\\w+['\"]?$",e:"^\\w+;",c:[b.BE]},a,e,{cN:"function",bK:"function",e:/[;{]/,i:"\\$|\\[|%",c:[b.UTM,{cN:"params",b:"\\(",e:"\\)",c:["self",e,b.CBLCLM,c,d]}]},{cN:"class",bK:"class interface",e:"{",i:/[:\(\$"]/,c:[{bK:"extends implements",r:10},b.UTM]},{bK:"namespace",e:";",i:/[\.']/,c:[b.UTM]},{bK:"use",e:";",c:[b.UTM]},{b:"=>"},c,d]}}); -------------------------------------------------------------------------------- /placequran-serverless/src/quran.spec.ts: -------------------------------------------------------------------------------- 1 | import test from "ava"; 2 | import { 3 | filterParam, 4 | generateHtml, 5 | getVerses, 6 | parseParam, 7 | prepareForHtml, 8 | QuranParamError, 9 | romanToArabic, 10 | } from "./quran"; 11 | 12 | let config; 13 | 14 | test.beforeEach(async (t) => { 15 | config = (await import("./config")).default; 16 | }); 17 | 18 | test("Parse expected param correctly", (t) => { 19 | t.deepEqual(parseParam("1", "1"), { 20 | surah: 1, 21 | verses: [1], 22 | translations: ["ar"], 23 | }); 24 | 25 | t.deepEqual(parseParam("1", "1", "ar"), { 26 | surah: 1, 27 | verses: [1], 28 | translations: ["ar"], 29 | }); 30 | 31 | t.deepEqual(parseParam("1", "1,3", "ar"), { 32 | surah: 1, 33 | verses: [1, 3], 34 | translations: ["ar"], 35 | }); 36 | 37 | t.deepEqual(parseParam("1", "1, 3", "ar"), { 38 | surah: 1, 39 | verses: [1, 3], 40 | translations: ["ar"], 41 | }); 42 | 43 | t.deepEqual(parseParam("1", "1,3,5-7", "ar"), { 44 | surah: 1, 45 | verses: [1, 3, 5, 6, 7], 46 | translations: ["ar"], 47 | }); 48 | 49 | t.deepEqual(parseParam("1", "5-7,3,1", "ar"), { 50 | surah: 1, 51 | verses: [1, 3, 5, 6, 7], 52 | translations: ["ar"], 53 | }); 54 | 55 | t.deepEqual(parseParam("1", "9-11,3,1", "ar,ms"), { 56 | surah: 1, 57 | verses: [1, 3, 9, 10, 11], 58 | translations: ["ar", "ms"], 59 | }); 60 | 61 | t.deepEqual(parseParam("1", "1", "ar, ms"), { 62 | surah: 1, 63 | verses: [1], 64 | translations: ["ar", "ms"], 65 | }); 66 | 67 | t.deepEqual(parseParam("1", "1", "ar,ms,23"), { 68 | surah: 1, 69 | verses: [1], 70 | translations: ["ar", "ms", "23"], 71 | }); 72 | }); 73 | 74 | test("FilterParam should works correctly", (t) => { 75 | t.deepEqual(filterParam(parseParam("112", "1-5", "fake,ar")), { 76 | surah: 112, 77 | verses: [1, 2, 3, 4], 78 | translations: ["ar"], 79 | }); 80 | 81 | t.deepEqual(filterParam(parseParam("115", "1-5", "ms")), { 82 | surah: 0, 83 | verses: [], 84 | translations: ["ar"], 85 | }); 86 | 87 | t.deepEqual(filterParam(parseParam("115", "1-5")), { 88 | surah: 0, 89 | verses: [], 90 | translations: ["ar"], 91 | }); 92 | 93 | config.max_verses = 2; 94 | config.max_translation = 2; 95 | 96 | t.deepEqual(filterParam(parseParam("2", "1-10", "ar,aa,ms,en")), { 97 | surah: 2, 98 | verses: [1, 2], 99 | translations: ["ar", "ms"], 100 | }); 101 | }); 102 | 103 | test("Trim request when over limit", async (t) => { 104 | config.max_verses = 2; 105 | config.max_translation = 2; 106 | 107 | t.deepEqual( 108 | await getVerses({ 109 | surah: 2, 110 | verses: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 111 | translations: ["ar", "22", "ms", "en"], 112 | }), 113 | { 114 | ar: [ 115 | { 116 | aya: 1, 117 | sura: 2, 118 | text: "بِسْمِ ٱللَّهِ ٱلرَّحْمَـٰنِ ٱلرَّحِيمِ الٓمٓ", 119 | }, 120 | { 121 | aya: 2, 122 | sura: 2, 123 | text: "ذَٰلِكَ ٱلْكِتَـٰبُ لَا رَيْبَ ۛ فِيهِ ۛ هُدًۭى لِّلْمُتَّقِينَ", 124 | }, 125 | ], 126 | ms: [ 127 | { 128 | aya: 1, 129 | sura: 2, 130 | text: "Alif, Laam, Miim.", 131 | }, 132 | { 133 | aya: 2, 134 | sura: 2, 135 | text: "Kitab Al-Quran ini, tidak ada sebarang syak padanya (tentang datangnya dari Allah dan tentang sempurnanya); ia pula menjadi petunjuk bagi orang-orang yang (hendak) bertaqwa;", 136 | }, 137 | ], 138 | } 139 | ); 140 | }); 141 | 142 | test("Throw error due to unexpected param", (t) => { 143 | t.throws(() => parseParam("", ""), { instanceOf: QuranParamError }); 144 | 145 | t.throws(() => parseParam("1", ""), { instanceOf: QuranParamError }); 146 | t.throws(() => parseParam("", "1"), { instanceOf: QuranParamError }); 147 | t.throws(() => parseParam("a", "1"), { instanceOf: QuranParamError }); 148 | t.throws(() => parseParam("1", "1,a"), { instanceOf: QuranParamError }); 149 | t.throws(() => parseParam("1", "1,-2"), { instanceOf: QuranParamError }); 150 | t.throws(() => parseParam("1", "3-1"), { instanceOf: QuranParamError }); 151 | t.throws(() => parseParam("1", "1--2"), { instanceOf: QuranParamError }); 152 | t.throws(() => parseParam("1", "1-,2"), { instanceOf: QuranParamError }); 153 | t.throws(() => parseParam("1", "1,,2"), { instanceOf: QuranParamError }); 154 | t.throws(() => parseParam("1", "1,"), { instanceOf: QuranParamError }); 155 | t.throws(() => parseParam("1", ",1"), { instanceOf: QuranParamError }); 156 | t.throws(() => parseParam("1", "1-"), { instanceOf: QuranParamError }); 157 | t.throws(() => parseParam("1", ",1"), { instanceOf: QuranParamError }); 158 | t.throws(() => parseParam("1", "1", ""), { instanceOf: QuranParamError }); 159 | t.throws(() => parseParam("1", "1", "aa,"), { instanceOf: QuranParamError }); 160 | t.throws(() => parseParam("1", "1", ",aa"), { instanceOf: QuranParamError }); 161 | t.throws(() => parseParam("1", "1", "aa,,bb"), { 162 | instanceOf: QuranParamError, 163 | }); 164 | t.throws(() => parseParam("1", "1", "aa-bb"), { 165 | instanceOf: QuranParamError, 166 | }); 167 | }); 168 | 169 | test("Get verses correctly", async (t) => { 170 | const result = await getVerses({ 171 | surah: 1, 172 | verses: [1, 2], 173 | translations: ["ar", "ms"], 174 | }); 175 | 176 | t.deepEqual(result, { 177 | ar: [ 178 | { 179 | aya: 1, 180 | sura: 1, 181 | text: "بِسْمِ ٱللَّهِ ٱلرَّحْمَـٰنِ ٱلرَّحِيمِ", 182 | }, 183 | { 184 | aya: 2, 185 | sura: 1, 186 | text: "ٱلْحَمْدُ لِلَّهِ رَبِّ ٱلْعَـٰلَمِينَ", 187 | }, 188 | ], 189 | ms: [ 190 | { 191 | aya: 1, 192 | sura: 1, 193 | text: "Dengan nama Allah, Yang Maha Pemurah, lagi Maha Mengasihani.", 194 | }, 195 | { 196 | aya: 2, 197 | sura: 1, 198 | text: "Segala puji tertentu bagi Allah, Tuhan yang memelihara dan mentadbirkan sekalian alam.", 199 | }, 200 | ], 201 | }); 202 | }); 203 | 204 | test("Get missing verses correctly", async (t) => { 205 | let result = await getVerses({ 206 | surah: 1, 207 | verses: [1], 208 | translations: ["da", "ms"], 209 | }); 210 | 211 | t.deepEqual(result, { 212 | ms: [ 213 | { 214 | aya: 1, 215 | sura: 1, 216 | text: "Dengan nama Allah, Yang Maha Pemurah, lagi Maha Mengasihani.", 217 | }, 218 | ], 219 | }); 220 | 221 | result = await getVerses({ 222 | surah: 115, 223 | verses: [1], 224 | translations: ["ar"], 225 | }); 226 | 227 | t.deepEqual(result, { 228 | ar: [], 229 | }); 230 | 231 | result = await getVerses({ 232 | surah: 1, 233 | verses: [10], 234 | translations: ["ar"], 235 | }); 236 | 237 | t.deepEqual(result, { 238 | ar: [], 239 | }); 240 | 241 | result = await getVerses({ 242 | surah: 1, 243 | verses: [7, 8, 9, 10], 244 | translations: ["ar"], 245 | }); 246 | 247 | t.deepEqual(result, { 248 | ar: [ 249 | { 250 | aya: 7, 251 | sura: 1, 252 | text: "صِرَٰطَ ٱلَّذِينَ أَنْعَمْتَ عَلَيْهِمْ غَيْرِ ٱلْمَغْضُوبِ عَلَيْهِمْ وَلَا ٱلضَّآلِّينَ", 253 | }, 254 | ], 255 | }); 256 | }); 257 | 258 | test("Prepare html", async (t) => { 259 | const result = prepareForHtml({ 260 | ar: [ 261 | { 262 | sura: 2, 263 | aya: 1, 264 | text: "a", 265 | }, 266 | { 267 | sura: 2, 268 | aya: 2, 269 | text: "b", 270 | }, 271 | { 272 | sura: 2, 273 | aya: 4, 274 | text: "c", 275 | }, 276 | { 277 | sura: 2, 278 | aya: 6, 279 | text: "d", 280 | }, 281 | { 282 | sura: 2, 283 | aya: 7, 284 | text: "e", 285 | }, 286 | ], 287 | en: [ 288 | { 289 | sura: 2, 290 | aya: 1, 291 | text: "a", 292 | }, 293 | { 294 | sura: 2, 295 | aya: 2, 296 | text: "b", 297 | }, 298 | { 299 | sura: 2, 300 | aya: 4, 301 | text: "c", 302 | }, 303 | { 304 | sura: 2, 305 | aya: 6, 306 | text: "d", 307 | }, 308 | { 309 | sura: 2, 310 | aya: 7, 311 | text: "e", 312 | }, 313 | ], 314 | }); 315 | 316 | t.deepEqual(result, [ 317 | { 318 | translation: "ar", 319 | verses: [ 320 | { 321 | sura: 2, 322 | aya: 1, 323 | text: "a", 324 | }, 325 | { 326 | sura: 2, 327 | aya: 2, 328 | text: "b", 329 | }, 330 | ], 331 | }, 332 | { 333 | translation: "en", 334 | verses: [ 335 | { 336 | sura: 2, 337 | aya: 1, 338 | text: "a", 339 | }, 340 | { 341 | sura: 2, 342 | aya: 2, 343 | text: "b", 344 | }, 345 | ], 346 | }, 347 | { 348 | meta: "Al-Baqara: 1-2", 349 | translation: "meta", 350 | verses: [], 351 | }, 352 | { 353 | translation: "ar", 354 | verses: [ 355 | { 356 | sura: 2, 357 | aya: 4, 358 | text: "c", 359 | }, 360 | ], 361 | }, 362 | { 363 | translation: "en", 364 | verses: [ 365 | { 366 | sura: 2, 367 | aya: 4, 368 | text: "c", 369 | }, 370 | ], 371 | }, 372 | { 373 | meta: "Al-Baqara: 4", 374 | translation: "meta", 375 | verses: [], 376 | }, 377 | { 378 | translation: "ar", 379 | verses: [ 380 | { 381 | sura: 2, 382 | aya: 6, 383 | text: "d", 384 | }, 385 | { 386 | sura: 2, 387 | aya: 7, 388 | text: "e", 389 | }, 390 | ], 391 | }, 392 | { 393 | translation: "en", 394 | verses: [ 395 | { 396 | sura: 2, 397 | aya: 6, 398 | text: "d", 399 | }, 400 | { 401 | sura: 2, 402 | aya: 7, 403 | text: "e", 404 | }, 405 | ], 406 | }, 407 | { 408 | meta: "Al-Baqara: 6-7", 409 | translation: "meta", 410 | verses: [], 411 | }, 412 | ]); 413 | }); 414 | 415 | test("GenerateHtml should works properly", async (t) => { 416 | t.throws(() => generateHtml([]), { instanceOf: QuranParamError }); 417 | t.true( 418 | generateHtml([ 419 | { 420 | translation: "test", 421 | verses: [ 422 | { 423 | aya: 1, 424 | sura: 1, 425 | text: "test", 426 | }, 427 | ], 428 | }, 429 | ]) 430 | .trim() 431 | .startsWith("") 432 | ); 433 | }); 434 | 435 | test("Convert roman to arabic correctly", async (t) => { 436 | t.is(romanToArabic(0), "."); 437 | t.is(romanToArabic(25), "٢٥"); 438 | t.is(romanToArabic(139), "١٣٩"); 439 | }); 440 | -------------------------------------------------------------------------------- /placequran-serverless/src/lib/quran-data.ts: -------------------------------------------------------------------------------- 1 | // Quran Metadata (ver 1.0) 2 | // Copyright (C) 2008-2009 Tanzil.info 3 | // License: Creative Commons Attribution 3.0 4 | 5 | //------------------ Sura Data --------------------- 6 | 7 | export const Sura = [ 8 | // [start, ayas, order, rukus, name, tname, ename, type] 9 | [], 10 | [0, 7, 5, 1, "الفاتحة", "Al-Faatiha", "The Opening", "Meccan"], 11 | [7, 286, 87, 40, "البقرة", "Al-Baqara", "The Cow", "Medinan"], 12 | [ 13 | 293, 14 | 200, 15 | 89, 16 | 20, 17 | "آل عمران", 18 | "Aal-i-Imraan", 19 | "The Family of Imraan", 20 | "Medinan", 21 | ], 22 | [493, 176, 92, 24, "النساء", "An-Nisaa", "The Women", "Medinan"], 23 | [669, 120, 112, 16, "المائدة", "Al-Maaida", "The Table", "Medinan"], 24 | [789, 165, 55, 20, "الأنعام", "Al-An'aam", "The Cattle", "Meccan"], 25 | [954, 206, 39, 24, "الأعراف", "Al-A'raaf", "The Heights", "Meccan"], 26 | [ 27 | 1160, 28 | 75, 29 | 88, 30 | 10, 31 | "الأنفال", 32 | "Al-Anfaal", 33 | "The Spoils of War", 34 | "Medinan", 35 | ], 36 | [1235, 129, 113, 16, "التوبة", "At-Tawba", "The Repentance", "Medinan"], 37 | [1364, 109, 51, 11, "يونس", "Yunus", "Jonas", "Meccan"], 38 | [1473, 123, 52, 10, "هود", "Hud", "Hud", "Meccan"], 39 | [1596, 111, 53, 12, "يوسف", "Yusuf", "Joseph", "Meccan"], 40 | [1707, 43, 96, 6, "الرعد", "Ar-Ra'd", "The Thunder", "Medinan"], 41 | [1750, 52, 72, 7, "ابراهيم", "Ibrahim", "Abraham", "Meccan"], 42 | [1802, 99, 54, 6, "الحجر", "Al-Hijr", "The Rock", "Meccan"], 43 | [1901, 128, 70, 16, "النحل", "An-Nahl", "The Bee", "Meccan"], 44 | [ 45 | 2029, 46 | 111, 47 | 50, 48 | 12, 49 | "الإسراء", 50 | "Al-Israa", 51 | "The Night Journey", 52 | "Meccan", 53 | ], 54 | [2140, 110, 69, 12, "الكهف", "Al-Kahf", "The Cave", "Meccan"], 55 | [2250, 98, 44, 6, "مريم", "Maryam", "Mary", "Meccan"], 56 | [2348, 135, 45, 8, "طه", "Taa-Haa", "Taa-Haa", "Meccan"], 57 | [ 58 | 2483, 59 | 112, 60 | 73, 61 | 7, 62 | "الأنبياء", 63 | "Al-Anbiyaa", 64 | "The Prophets", 65 | "Meccan", 66 | ], 67 | [2595, 78, 103, 10, "الحج", "Al-Hajj", "The Pilgrimage", "Medinan"], 68 | [ 69 | 2673, 70 | 118, 71 | 74, 72 | 6, 73 | "المؤمنون", 74 | "Al-Muminoon", 75 | "The Believers", 76 | "Meccan", 77 | ], 78 | [2791, 64, 102, 9, "النور", "An-Noor", "The Light", "Medinan"], 79 | [2855, 77, 42, 6, "الفرقان", "Al-Furqaan", "The Criterion", "Meccan"], 80 | [2932, 227, 47, 11, "الشعراء", "Ash-Shu'araa", "The Poets", "Meccan"], 81 | [3159, 93, 48, 7, "النمل", "An-Naml", "The Ant", "Meccan"], 82 | [3252, 88, 49, 8, "القصص", "Al-Qasas", "The Stories", "Meccan"], 83 | [3340, 69, 85, 7, "العنكبوت", "Al-Ankaboot", "The Spider", "Meccan"], 84 | [3409, 60, 84, 6, "الروم", "Ar-Room", "The Romans", "Meccan"], 85 | [3469, 34, 57, 3, "لقمان", "Luqman", "Luqman", "Meccan"], 86 | [3503, 30, 75, 3, "السجدة", "As-Sajda", "The Prostration", "Meccan"], 87 | [3533, 73, 90, 9, "الأحزاب", "Al-Ahzaab", "The Clans", "Medinan"], 88 | [3606, 54, 58, 6, "سبإ", "Saba", "Sheba", "Meccan"], 89 | [3660, 45, 43, 5, "فاطر", "Faatir", "The Originator", "Meccan"], 90 | [3705, 83, 41, 5, "يس", "Yaseen", "Yaseen", "Meccan"], 91 | [ 92 | 3788, 93 | 182, 94 | 56, 95 | 5, 96 | "الصافات", 97 | "As-Saaffaat", 98 | "Those drawn up in Ranks", 99 | "Meccan", 100 | ], 101 | [3970, 88, 38, 5, "ص", "Saad", "The letter Saad", "Meccan"], 102 | [4058, 75, 59, 8, "الزمر", "Az-Zumar", "The Groups", "Meccan"], 103 | [4133, 85, 60, 9, "غافر", "Al-Ghaafir", "The Forgiver", "Meccan"], 104 | [4218, 54, 61, 6, "فصلت", "Fussilat", "Explained in detail", "Meccan"], 105 | [4272, 53, 62, 5, "الشورى", "Ash-Shura", "Consultation", "Meccan"], 106 | [4325, 89, 63, 7, "الزخرف", "Az-Zukhruf", "Ornaments of gold", "Meccan"], 107 | [4414, 59, 64, 3, "الدخان", "Ad-Dukhaan", "The Smoke", "Meccan"], 108 | [4473, 37, 65, 4, "الجاثية", "Al-Jaathiya", "Crouching", "Meccan"], 109 | [4510, 35, 66, 4, "الأحقاف", "Al-Ahqaf", "The Dunes", "Meccan"], 110 | [4545, 38, 95, 4, "محمد", "Muhammad", "Muhammad", "Medinan"], 111 | [4583, 29, 111, 4, "الفتح", "Al-Fath", "The Victory", "Medinan"], 112 | [ 113 | 4612, 114 | 18, 115 | 106, 116 | 2, 117 | "الحجرات", 118 | "Al-Hujuraat", 119 | "The Inner Apartments", 120 | "Medinan", 121 | ], 122 | [4630, 45, 34, 3, "Ù‚", "Qaaf", "The letter Qaaf", "Meccan"], 123 | [ 124 | 4675, 125 | 60, 126 | 67, 127 | 3, 128 | "الذاريات", 129 | "Adh-Dhaariyat", 130 | "The Winnowing Winds", 131 | "Meccan", 132 | ], 133 | [4735, 49, 76, 2, "الطور", "At-Tur", "The Mount", "Meccan"], 134 | [4784, 62, 23, 3, "النجم", "An-Najm", "The Star", "Meccan"], 135 | [4846, 55, 37, 3, "القمر", "Al-Qamar", "The Moon", "Meccan"], 136 | [4901, 78, 97, 3, "الرحمن", "Ar-Rahmaan", "The Beneficent", "Medinan"], 137 | [4979, 96, 46, 3, "الواقعة", "Al-Waaqia", "The Inevitable", "Meccan"], 138 | [5075, 29, 94, 4, "الحديد", "Al-Hadid", "The Iron", "Medinan"], 139 | [ 140 | 5104, 141 | 22, 142 | 105, 143 | 3, 144 | "المجادلة", 145 | "Al-Mujaadila", 146 | "The Pleading Woman", 147 | "Medinan", 148 | ], 149 | [5126, 24, 101, 3, "الحشر", "Al-Hashr", "The Exile", "Medinan"], 150 | [ 151 | 5150, 152 | 13, 153 | 91, 154 | 2, 155 | "الممتحنة", 156 | "Al-Mumtahana", 157 | "She that is to be examined", 158 | "Medinan", 159 | ], 160 | [5163, 14, 109, 2, "الصف", "As-Saff", "The Ranks", "Medinan"], 161 | [5177, 11, 110, 2, "الجمعة", "Al-Jumu'a", "Friday", "Medinan"], 162 | [ 163 | 5188, 164 | 11, 165 | 104, 166 | 2, 167 | "المنافقون", 168 | "Al-Munaafiqoon", 169 | "The Hypocrites", 170 | "Medinan", 171 | ], 172 | [ 173 | 5199, 174 | 18, 175 | 108, 176 | 2, 177 | "التغابن", 178 | "At-Taghaabun", 179 | "Mutual Disillusion", 180 | "Medinan", 181 | ], 182 | [5217, 12, 99, 2, "الطلاق", "At-Talaaq", "Divorce", "Medinan"], 183 | [ 184 | 5229, 185 | 12, 186 | 107, 187 | 2, 188 | "التحريم", 189 | "At-Tahrim", 190 | "The Prohibition", 191 | "Medinan", 192 | ], 193 | [5241, 30, 77, 2, "الملك", "Al-Mulk", "The Sovereignty", "Meccan"], 194 | [5271, 52, 2, 2, "القلم", "Al-Qalam", "The Pen", "Meccan"], 195 | [5323, 52, 78, 2, "الحاقة", "Al-Haaqqa", "The Reality", "Meccan"], 196 | [ 197 | 5375, 198 | 44, 199 | 79, 200 | 2, 201 | "المعارج", 202 | "Al-Ma'aarij", 203 | "The Ascending Stairways", 204 | "Meccan", 205 | ], 206 | [5419, 28, 71, 2, "نوح", "Nooh", "Noah", "Meccan"], 207 | [5447, 28, 40, 2, "الجن", "Al-Jinn", "The Jinn", "Meccan"], 208 | [ 209 | 5475, 210 | 20, 211 | 3, 212 | 2, 213 | "المزمل", 214 | "Al-Muzzammil", 215 | "The Enshrouded One", 216 | "Meccan", 217 | ], 218 | [ 219 | 5495, 220 | 56, 221 | 4, 222 | 2, 223 | "المدثر", 224 | "Al-Muddaththir", 225 | "The Cloaked One", 226 | "Meccan", 227 | ], 228 | [ 229 | 5551, 230 | 40, 231 | 31, 232 | 2, 233 | "القيامة", 234 | "Al-Qiyaama", 235 | "The Resurrection", 236 | "Meccan", 237 | ], 238 | [5591, 31, 98, 2, "الانسان", "Al-Insaan", "Man", "Medinan"], 239 | [ 240 | 5622, 241 | 50, 242 | 33, 243 | 2, 244 | "المرسلات", 245 | "Al-Mursalaat", 246 | "The Emissaries", 247 | "Meccan", 248 | ], 249 | [5672, 40, 80, 2, "النبإ", "An-Naba", "The Announcement", "Meccan"], 250 | [ 251 | 5712, 252 | 46, 253 | 81, 254 | 2, 255 | "النازعات", 256 | "An-Naazi'aat", 257 | "Those who drag forth", 258 | "Meccan", 259 | ], 260 | [5758, 42, 24, 1, "عبس", "Abasa", "He frowned", "Meccan"], 261 | [5800, 29, 7, 1, "التكوير", "At-Takwir", "The Overthrowing", "Meccan"], 262 | [5829, 19, 82, 1, "الإنفطار", "Al-Infitaar", "The Cleaving", "Meccan"], 263 | [5848, 36, 86, 1, "المطففين", "Al-Mutaffifin", "Defrauding", "Meccan"], 264 | [ 265 | 5884, 266 | 25, 267 | 83, 268 | 1, 269 | "الإنشقاق", 270 | "Al-Inshiqaaq", 271 | "The Splitting Open", 272 | "Meccan", 273 | ], 274 | [ 275 | 5909, 276 | 22, 277 | 27, 278 | 1, 279 | "البروج", 280 | "Al-Burooj", 281 | "The Constellations", 282 | "Meccan", 283 | ], 284 | [5931, 17, 36, 1, "الطارق", "At-Taariq", "The Morning Star", "Meccan"], 285 | [5948, 19, 8, 1, "الأعلى", "Al-A'laa", "The Most High", "Meccan"], 286 | [ 287 | 5967, 288 | 26, 289 | 68, 290 | 1, 291 | "الغاشية", 292 | "Al-Ghaashiya", 293 | "The Overwhelming", 294 | "Meccan", 295 | ], 296 | [5993, 30, 10, 1, "الفجر", "Al-Fajr", "The Dawn", "Meccan"], 297 | [6023, 20, 35, 1, "البلد", "Al-Balad", "The City", "Meccan"], 298 | [6043, 15, 26, 1, "الشمس", "Ash-Shams", "The Sun", "Meccan"], 299 | [6058, 21, 9, 1, "الليل", "Al-Lail", "The Night", "Meccan"], 300 | [6079, 11, 11, 1, "الضحى", "Ad-Dhuhaa", "The Morning Hours", "Meccan"], 301 | [6090, 8, 12, 1, "الشرح", "Ash-Sharh", "The Consolation", "Meccan"], 302 | [6098, 8, 28, 1, "التين", "At-Tin", "The Fig", "Meccan"], 303 | [6106, 19, 1, 1, "العلق", "Al-Alaq", "The Clot", "Meccan"], 304 | [6125, 5, 25, 1, "القدر", "Al-Qadr", "The Power, Fate", "Meccan"], 305 | [6130, 8, 100, 1, "البينة", "Al-Bayyina", "The Evidence", "Medinan"], 306 | [6138, 8, 93, 1, "الزلزلة", "Az-Zalzala", "The Earthquake", "Medinan"], 307 | [ 308 | 6146, 309 | 11, 310 | 14, 311 | 1, 312 | "العاديات", 313 | "Al-Aadiyaat", 314 | "The Chargers", 315 | "Meccan", 316 | ], 317 | [6157, 11, 30, 1, "القارعة", "Al-Qaari'a", "The Calamity", "Meccan"], 318 | [6168, 8, 16, 1, "التكاثر", "At-Takaathur", "Competition", "Meccan"], 319 | [ 320 | 6176, 321 | 3, 322 | 13, 323 | 1, 324 | "العصر", 325 | "Al-Asr", 326 | "The Declining Day, Epoch", 327 | "Meccan", 328 | ], 329 | [6179, 9, 32, 1, "الهمزة", "Al-Humaza", "The Traducer", "Meccan"], 330 | [6188, 5, 19, 1, "الفيل", "Al-Fil", "The Elephant", "Meccan"], 331 | [6193, 4, 29, 1, "قريش", "Quraish", "Quraysh", "Meccan"], 332 | [6197, 7, 17, 1, "الماعون", "Al-Maa'un", "Almsgiving", "Meccan"], 333 | [6204, 3, 15, 1, "الكوثر", "Al-Kawthar", "Abundance", "Meccan"], 334 | [ 335 | 6207, 336 | 6, 337 | 18, 338 | 1, 339 | "الكافرون", 340 | "Al-Kaafiroon", 341 | "The Disbelievers", 342 | "Meccan", 343 | ], 344 | [6213, 3, 114, 1, "النصر", "An-Nasr", "Divine Support", "Medinan"], 345 | [6216, 5, 6, 1, "المسد", "Al-Masad", "The Palm Fibre", "Meccan"], 346 | [6221, 4, 22, 1, "الإخلاص", "Al-Ikhlaas", "Sincerity", "Meccan"], 347 | [6225, 5, 20, 1, "الفلق", "Al-Falaq", "The Dawn", "Meccan"], 348 | [6230, 6, 21, 1, "الناس", "An-Naas", "Mankind", "Meccan"], 349 | [6236, 1], 350 | ]; 351 | 352 | //------------------ Juz Data --------------------- 353 | 354 | export const Juz = [ 355 | // [sura, aya] 356 | [], 357 | [1, 1], 358 | [2, 142], 359 | [2, 253], 360 | [3, 93], 361 | [4, 24], 362 | [4, 148], 363 | [5, 82], 364 | [6, 111], 365 | [7, 88], 366 | [8, 41], 367 | [9, 93], 368 | [11, 6], 369 | [12, 53], 370 | [15, 1], 371 | [17, 1], 372 | [18, 75], 373 | [21, 1], 374 | [23, 1], 375 | [25, 21], 376 | [27, 56], 377 | [29, 46], 378 | [33, 31], 379 | [36, 28], 380 | [39, 32], 381 | [41, 47], 382 | [46, 1], 383 | [51, 31], 384 | [58, 1], 385 | [67, 1], 386 | [78, 1], 387 | [115, 1], 388 | ]; 389 | 390 | //------------------ Hizb Data --------------------- 391 | 392 | export const HizbQaurter = [ 393 | // [sura, aya] 394 | [], 395 | [1, 1], 396 | [2, 26], 397 | [2, 44], 398 | [2, 60], 399 | [2, 75], 400 | [2, 92], 401 | [2, 106], 402 | [2, 124], 403 | [2, 142], 404 | [2, 158], 405 | [2, 177], 406 | [2, 189], 407 | [2, 203], 408 | [2, 219], 409 | [2, 233], 410 | [2, 243], 411 | [2, 253], 412 | [2, 263], 413 | [2, 272], 414 | [2, 283], 415 | [3, 15], 416 | [3, 33], 417 | [3, 52], 418 | [3, 75], 419 | [3, 93], 420 | [3, 113], 421 | [3, 133], 422 | [3, 153], 423 | [3, 171], 424 | [3, 186], 425 | [4, 1], 426 | [4, 12], 427 | [4, 24], 428 | [4, 36], 429 | [4, 58], 430 | [4, 74], 431 | [4, 88], 432 | [4, 100], 433 | [4, 114], 434 | [4, 135], 435 | [4, 148], 436 | [4, 163], 437 | [5, 1], 438 | [5, 12], 439 | [5, 27], 440 | [5, 41], 441 | [5, 51], 442 | [5, 67], 443 | [5, 82], 444 | [5, 97], 445 | [5, 109], 446 | [6, 13], 447 | [6, 36], 448 | [6, 59], 449 | [6, 74], 450 | [6, 95], 451 | [6, 111], 452 | [6, 127], 453 | [6, 141], 454 | [6, 151], 455 | [7, 1], 456 | [7, 31], 457 | [7, 47], 458 | [7, 65], 459 | [7, 88], 460 | [7, 117], 461 | [7, 142], 462 | [7, 156], 463 | [7, 171], 464 | [7, 189], 465 | [8, 1], 466 | [8, 22], 467 | [8, 41], 468 | [8, 61], 469 | [9, 1], 470 | [9, 19], 471 | [9, 34], 472 | [9, 46], 473 | [9, 60], 474 | [9, 75], 475 | [9, 93], 476 | [9, 111], 477 | [9, 122], 478 | [10, 11], 479 | [10, 26], 480 | [10, 53], 481 | [10, 71], 482 | [10, 90], 483 | [11, 6], 484 | [11, 24], 485 | [11, 41], 486 | [11, 61], 487 | [11, 84], 488 | [11, 108], 489 | [12, 7], 490 | [12, 30], 491 | [12, 53], 492 | [12, 77], 493 | [12, 101], 494 | [13, 5], 495 | [13, 19], 496 | [13, 35], 497 | [14, 10], 498 | [14, 28], 499 | [15, 1], 500 | [15, 50], 501 | [16, 1], 502 | [16, 30], 503 | [16, 51], 504 | [16, 75], 505 | [16, 90], 506 | [16, 111], 507 | [17, 1], 508 | [17, 23], 509 | [17, 50], 510 | [17, 70], 511 | [17, 99], 512 | [18, 17], 513 | [18, 32], 514 | [18, 51], 515 | [18, 75], 516 | [18, 99], 517 | [19, 22], 518 | [19, 59], 519 | [20, 1], 520 | [20, 55], 521 | [20, 83], 522 | [20, 111], 523 | [21, 1], 524 | [21, 29], 525 | [21, 51], 526 | [21, 83], 527 | [22, 1], 528 | [22, 19], 529 | [22, 38], 530 | [22, 60], 531 | [23, 1], 532 | [23, 36], 533 | [23, 75], 534 | [24, 1], 535 | [24, 21], 536 | [24, 35], 537 | [24, 53], 538 | [25, 1], 539 | [25, 21], 540 | [25, 53], 541 | [26, 1], 542 | [26, 52], 543 | [26, 111], 544 | [26, 181], 545 | [27, 1], 546 | [27, 27], 547 | [27, 56], 548 | [27, 82], 549 | [28, 12], 550 | [28, 29], 551 | [28, 51], 552 | [28, 76], 553 | [29, 1], 554 | [29, 26], 555 | [29, 46], 556 | [30, 1], 557 | [30, 31], 558 | [30, 54], 559 | [31, 22], 560 | [32, 11], 561 | [33, 1], 562 | [33, 18], 563 | [33, 31], 564 | [33, 51], 565 | [33, 60], 566 | [34, 10], 567 | [34, 24], 568 | [34, 46], 569 | [35, 15], 570 | [35, 41], 571 | [36, 28], 572 | [36, 60], 573 | [37, 22], 574 | [37, 83], 575 | [37, 145], 576 | [38, 21], 577 | [38, 52], 578 | [39, 8], 579 | [39, 32], 580 | [39, 53], 581 | [40, 1], 582 | [40, 21], 583 | [40, 41], 584 | [40, 66], 585 | [41, 9], 586 | [41, 25], 587 | [41, 47], 588 | [42, 13], 589 | [42, 27], 590 | [42, 51], 591 | [43, 24], 592 | [43, 57], 593 | [44, 17], 594 | [45, 12], 595 | [46, 1], 596 | [46, 21], 597 | [47, 10], 598 | [47, 33], 599 | [48, 18], 600 | [49, 1], 601 | [49, 14], 602 | [50, 27], 603 | [51, 31], 604 | [52, 24], 605 | [53, 26], 606 | [54, 9], 607 | [55, 1], 608 | [56, 1], 609 | [56, 75], 610 | [57, 16], 611 | [58, 1], 612 | [58, 14], 613 | [59, 11], 614 | [60, 7], 615 | [62, 1], 616 | [63, 4], 617 | [65, 1], 618 | [66, 1], 619 | [67, 1], 620 | [68, 1], 621 | [69, 1], 622 | [70, 19], 623 | [72, 1], 624 | [73, 20], 625 | [75, 1], 626 | [76, 19], 627 | [78, 1], 628 | [80, 1], 629 | [82, 1], 630 | [84, 1], 631 | [87, 1], 632 | [90, 1], 633 | [94, 1], 634 | [100, 9], 635 | [115, 1], 636 | ]; 637 | 638 | //------------------ Manzil Data --------------------- 639 | 640 | export const Manzil = [ 641 | // [sura, aya] 642 | [], 643 | [1, 1], 644 | [5, 1], 645 | [10, 1], 646 | [17, 1], 647 | [26, 1], 648 | [37, 1], 649 | [50, 1], 650 | ]; 651 | 652 | //------------------ Ruku Data --------------------- 653 | 654 | export const Ruku = [ 655 | // [sura, aya] 656 | [], 657 | [1, 1], 658 | [2, 1], 659 | [2, 8], 660 | [2, 21], 661 | [2, 30], 662 | [2, 40], 663 | [2, 47], 664 | [2, 60], 665 | [2, 62], 666 | [2, 72], 667 | [2, 83], 668 | [2, 87], 669 | [2, 97], 670 | [2, 104], 671 | [2, 113], 672 | [2, 122], 673 | [2, 130], 674 | [2, 142], 675 | [2, 148], 676 | [2, 153], 677 | [2, 164], 678 | [2, 168], 679 | [2, 177], 680 | [2, 183], 681 | [2, 189], 682 | [2, 197], 683 | [2, 211], 684 | [2, 217], 685 | [2, 222], 686 | [2, 229], 687 | [2, 232], 688 | [2, 236], 689 | [2, 243], 690 | [2, 249], 691 | [2, 254], 692 | [2, 258], 693 | [2, 261], 694 | [2, 267], 695 | [2, 274], 696 | [2, 282], 697 | [2, 284], 698 | [3, 1], 699 | [3, 10], 700 | [3, 21], 701 | [3, 31], 702 | [3, 42], 703 | [3, 55], 704 | [3, 64], 705 | [3, 72], 706 | [3, 81], 707 | [3, 92], 708 | [3, 102], 709 | [3, 110], 710 | [3, 121], 711 | [3, 130], 712 | [3, 144], 713 | [3, 149], 714 | [3, 156], 715 | [3, 172], 716 | [3, 181], 717 | [3, 190], 718 | [4, 1], 719 | [4, 11], 720 | [4, 15], 721 | [4, 23], 722 | [4, 26], 723 | [4, 34], 724 | [4, 43], 725 | [4, 51], 726 | [4, 60], 727 | [4, 71], 728 | [4, 77], 729 | [4, 88], 730 | [4, 92], 731 | [4, 97], 732 | [4, 101], 733 | [4, 105], 734 | [4, 113], 735 | [4, 116], 736 | [4, 127], 737 | [4, 135], 738 | [4, 142], 739 | [4, 153], 740 | [4, 163], 741 | [4, 172], 742 | [5, 1], 743 | [5, 6], 744 | [5, 12], 745 | [5, 20], 746 | [5, 27], 747 | [5, 35], 748 | [5, 44], 749 | [5, 51], 750 | [5, 57], 751 | [5, 67], 752 | [5, 78], 753 | [5, 87], 754 | [5, 94], 755 | [5, 101], 756 | [5, 109], 757 | [5, 116], 758 | [6, 1], 759 | [6, 11], 760 | [6, 21], 761 | [6, 31], 762 | [6, 42], 763 | [6, 51], 764 | [6, 56], 765 | [6, 61], 766 | [6, 71], 767 | [6, 83], 768 | [6, 91], 769 | [6, 95], 770 | [6, 101], 771 | [6, 111], 772 | [6, 122], 773 | [6, 130], 774 | [6, 141], 775 | [6, 145], 776 | [6, 151], 777 | [6, 155], 778 | [7, 1], 779 | [7, 11], 780 | [7, 26], 781 | [7, 32], 782 | [7, 40], 783 | [7, 48], 784 | [7, 54], 785 | [7, 59], 786 | [7, 65], 787 | [7, 73], 788 | [7, 85], 789 | [7, 94], 790 | [7, 100], 791 | [7, 109], 792 | [7, 127], 793 | [7, 130], 794 | [7, 142], 795 | [7, 148], 796 | [7, 152], 797 | [7, 158], 798 | [7, 163], 799 | [7, 172], 800 | [7, 182], 801 | [7, 189], 802 | [8, 1], 803 | [8, 11], 804 | [8, 20], 805 | [8, 29], 806 | [8, 38], 807 | [8, 45], 808 | [8, 49], 809 | [8, 59], 810 | [8, 65], 811 | [8, 70], 812 | [9, 1], 813 | [9, 7], 814 | [9, 17], 815 | [9, 25], 816 | [9, 30], 817 | [9, 38], 818 | [9, 43], 819 | [9, 60], 820 | [9, 67], 821 | [9, 73], 822 | [9, 81], 823 | [9, 90], 824 | [9, 100], 825 | [9, 111], 826 | [9, 119], 827 | [9, 123], 828 | [10, 1], 829 | [10, 11], 830 | [10, 21], 831 | [10, 31], 832 | [10, 41], 833 | [10, 54], 834 | [10, 61], 835 | [10, 71], 836 | [10, 83], 837 | [10, 93], 838 | [10, 104], 839 | [11, 1], 840 | [11, 9], 841 | [11, 25], 842 | [11, 36], 843 | [11, 50], 844 | [11, 61], 845 | [11, 69], 846 | [11, 84], 847 | [11, 96], 848 | [11, 110], 849 | [12, 1], 850 | [12, 7], 851 | [12, 21], 852 | [12, 30], 853 | [12, 36], 854 | [12, 43], 855 | [12, 50], 856 | [12, 58], 857 | [12, 69], 858 | [12, 80], 859 | [12, 94], 860 | [12, 105], 861 | [13, 1], 862 | [13, 8], 863 | [13, 19], 864 | [13, 27], 865 | [13, 32], 866 | [13, 38], 867 | [14, 1], 868 | [14, 7], 869 | [14, 13], 870 | [14, 22], 871 | [14, 28], 872 | [14, 35], 873 | [14, 42], 874 | [15, 1], 875 | [15, 16], 876 | [15, 26], 877 | [15, 45], 878 | [15, 61], 879 | [15, 80], 880 | [16, 1], 881 | [16, 10], 882 | [16, 22], 883 | [16, 26], 884 | [16, 35], 885 | [16, 41], 886 | [16, 51], 887 | [16, 61], 888 | [16, 66], 889 | [16, 71], 890 | [16, 77], 891 | [16, 84], 892 | [16, 90], 893 | [16, 101], 894 | [16, 111], 895 | [16, 120], 896 | [17, 1], 897 | [17, 11], 898 | [17, 23], 899 | [17, 31], 900 | [17, 41], 901 | [17, 53], 902 | [17, 61], 903 | [17, 71], 904 | [17, 78], 905 | [17, 85], 906 | [17, 94], 907 | [17, 101], 908 | [18, 1], 909 | [18, 13], 910 | [18, 18], 911 | [18, 23], 912 | [18, 32], 913 | [18, 45], 914 | [18, 50], 915 | [18, 54], 916 | [18, 60], 917 | [18, 71], 918 | [18, 83], 919 | [18, 102], 920 | [19, 1], 921 | [19, 16], 922 | [19, 41], 923 | [19, 51], 924 | [19, 66], 925 | [19, 83], 926 | [20, 1], 927 | [20, 25], 928 | [20, 55], 929 | [20, 77], 930 | [20, 90], 931 | [20, 105], 932 | [20, 116], 933 | [20, 129], 934 | [21, 1], 935 | [21, 11], 936 | [21, 30], 937 | [21, 42], 938 | [21, 51], 939 | [21, 76], 940 | [21, 94], 941 | [22, 1], 942 | [22, 11], 943 | [22, 23], 944 | [22, 26], 945 | [22, 34], 946 | [22, 39], 947 | [22, 49], 948 | [22, 58], 949 | [22, 65], 950 | [22, 73], 951 | [23, 1], 952 | [23, 23], 953 | [23, 33], 954 | [23, 51], 955 | [23, 78], 956 | [23, 93], 957 | [24, 1], 958 | [24, 11], 959 | [24, 21], 960 | [24, 27], 961 | [24, 35], 962 | [24, 41], 963 | [24, 51], 964 | [24, 58], 965 | [24, 62], 966 | [25, 1], 967 | [25, 10], 968 | [25, 21], 969 | [25, 35], 970 | [25, 45], 971 | [25, 61], 972 | [26, 1], 973 | [26, 10], 974 | [26, 34], 975 | [26, 53], 976 | [26, 70], 977 | [26, 105], 978 | [26, 123], 979 | [26, 141], 980 | [26, 160], 981 | [26, 176], 982 | [26, 192], 983 | [27, 1], 984 | [27, 15], 985 | [27, 32], 986 | [27, 45], 987 | [27, 59], 988 | [27, 67], 989 | [27, 83], 990 | [28, 1], 991 | [28, 14], 992 | [28, 22], 993 | [28, 29], 994 | [28, 43], 995 | [28, 51], 996 | [28, 61], 997 | [28, 76], 998 | [29, 1], 999 | [29, 14], 1000 | [29, 23], 1001 | [29, 31], 1002 | [29, 45], 1003 | [29, 52], 1004 | [29, 64], 1005 | [30, 1], 1006 | [30, 11], 1007 | [30, 20], 1008 | [30, 28], 1009 | [30, 41], 1010 | [30, 54], 1011 | [31, 1], 1012 | [31, 12], 1013 | [31, 20], 1014 | [32, 1], 1015 | [32, 12], 1016 | [32, 23], 1017 | [33, 1], 1018 | [33, 9], 1019 | [33, 21], 1020 | [33, 28], 1021 | [33, 35], 1022 | [33, 41], 1023 | [33, 53], 1024 | [33, 59], 1025 | [33, 69], 1026 | [34, 1], 1027 | [34, 10], 1028 | [34, 22], 1029 | [34, 31], 1030 | [34, 37], 1031 | [34, 46], 1032 | [35, 1], 1033 | [35, 8], 1034 | [35, 15], 1035 | [35, 27], 1036 | [35, 38], 1037 | [36, 1], 1038 | [36, 13], 1039 | [36, 33], 1040 | [36, 51], 1041 | [36, 68], 1042 | [37, 1], 1043 | [37, 22], 1044 | [37, 75], 1045 | [37, 114], 1046 | [37, 139], 1047 | [38, 1], 1048 | [38, 15], 1049 | [38, 27], 1050 | [38, 41], 1051 | [38, 65], 1052 | [39, 1], 1053 | [39, 10], 1054 | [39, 22], 1055 | [39, 32], 1056 | [39, 42], 1057 | [39, 53], 1058 | [39, 64], 1059 | [39, 71], 1060 | [40, 1], 1061 | [40, 10], 1062 | [40, 21], 1063 | [40, 28], 1064 | [40, 38], 1065 | [40, 51], 1066 | [40, 61], 1067 | [40, 69], 1068 | [40, 79], 1069 | [41, 1], 1070 | [41, 9], 1071 | [41, 19], 1072 | [41, 26], 1073 | [41, 33], 1074 | [41, 45], 1075 | [42, 1], 1076 | [42, 10], 1077 | [42, 20], 1078 | [42, 30], 1079 | [42, 44], 1080 | [43, 1], 1081 | [43, 16], 1082 | [43, 26], 1083 | [43, 36], 1084 | [43, 46], 1085 | [43, 57], 1086 | [43, 68], 1087 | [44, 1], 1088 | [44, 30], 1089 | [44, 43], 1090 | [45, 1], 1091 | [45, 12], 1092 | [45, 22], 1093 | [45, 27], 1094 | [46, 1], 1095 | [46, 11], 1096 | [46, 21], 1097 | [46, 27], 1098 | [47, 1], 1099 | [47, 12], 1100 | [47, 20], 1101 | [47, 29], 1102 | [48, 1], 1103 | [48, 11], 1104 | [48, 18], 1105 | [48, 27], 1106 | [49, 1], 1107 | [49, 11], 1108 | [50, 1], 1109 | [50, 16], 1110 | [50, 30], 1111 | [51, 1], 1112 | [51, 24], 1113 | [51, 47], 1114 | [52, 1], 1115 | [52, 29], 1116 | [53, 1], 1117 | [53, 26], 1118 | [53, 33], 1119 | [54, 1], 1120 | [54, 23], 1121 | [54, 41], 1122 | [55, 1], 1123 | [55, 26], 1124 | [55, 46], 1125 | [56, 1], 1126 | [56, 39], 1127 | [56, 75], 1128 | [57, 1], 1129 | [57, 11], 1130 | [57, 20], 1131 | [57, 26], 1132 | [58, 1], 1133 | [58, 7], 1134 | [58, 14], 1135 | [59, 1], 1136 | [59, 11], 1137 | [59, 18], 1138 | [60, 1], 1139 | [60, 7], 1140 | [61, 1], 1141 | [61, 10], 1142 | [62, 1], 1143 | [62, 9], 1144 | [63, 1], 1145 | [63, 9], 1146 | [64, 1], 1147 | [64, 11], 1148 | [65, 1], 1149 | [65, 8], 1150 | [66, 1], 1151 | [66, 8], 1152 | [67, 1], 1153 | [67, 15], 1154 | [68, 1], 1155 | [68, 34], 1156 | [69, 1], 1157 | [69, 38], 1158 | [70, 1], 1159 | [70, 36], 1160 | [71, 1], 1161 | [71, 21], 1162 | [72, 1], 1163 | [72, 20], 1164 | [73, 1], 1165 | [73, 20], 1166 | [74, 1], 1167 | [74, 32], 1168 | [75, 1], 1169 | [75, 31], 1170 | [76, 1], 1171 | [76, 23], 1172 | [77, 1], 1173 | [77, 41], 1174 | [78, 1], 1175 | [78, 31], 1176 | [79, 1], 1177 | [79, 27], 1178 | [80, 1], 1179 | [81, 1], 1180 | [82, 1], 1181 | [83, 1], 1182 | [84, 1], 1183 | [85, 1], 1184 | [86, 1], 1185 | [87, 1], 1186 | [88, 1], 1187 | [89, 1], 1188 | [90, 1], 1189 | [91, 1], 1190 | [92, 1], 1191 | [93, 1], 1192 | [94, 1], 1193 | [95, 1], 1194 | [96, 1], 1195 | [97, 1], 1196 | [98, 1], 1197 | [99, 1], 1198 | [100, 1], 1199 | [101, 1], 1200 | [102, 1], 1201 | [103, 1], 1202 | [104, 1], 1203 | [105, 1], 1204 | [106, 1], 1205 | [107, 1], 1206 | [108, 1], 1207 | [109, 1], 1208 | [110, 1], 1209 | [111, 1], 1210 | [112, 1], 1211 | [113, 1], 1212 | [114, 1], 1213 | ]; 1214 | 1215 | //------------------ Page Data --------------------- 1216 | 1217 | export const Page = [ 1218 | // [sura, aya] 1219 | [], 1220 | [1, 1], 1221 | [2, 1], 1222 | [2, 6], 1223 | [2, 17], 1224 | [2, 25], 1225 | [2, 30], 1226 | [2, 38], 1227 | [2, 49], 1228 | [2, 58], 1229 | [2, 62], 1230 | [2, 70], 1231 | [2, 77], 1232 | [2, 84], 1233 | [2, 89], 1234 | [2, 94], 1235 | [2, 102], 1236 | [2, 106], 1237 | [2, 113], 1238 | [2, 120], 1239 | [2, 127], 1240 | [2, 135], 1241 | [2, 142], 1242 | [2, 146], 1243 | [2, 154], 1244 | [2, 164], 1245 | [2, 170], 1246 | [2, 177], 1247 | [2, 182], 1248 | [2, 187], 1249 | [2, 191], 1250 | [2, 197], 1251 | [2, 203], 1252 | [2, 211], 1253 | [2, 216], 1254 | [2, 220], 1255 | [2, 225], 1256 | [2, 231], 1257 | [2, 234], 1258 | [2, 238], 1259 | [2, 246], 1260 | [2, 249], 1261 | [2, 253], 1262 | [2, 257], 1263 | [2, 260], 1264 | [2, 265], 1265 | [2, 270], 1266 | [2, 275], 1267 | [2, 282], 1268 | [2, 283], 1269 | [3, 1], 1270 | [3, 10], 1271 | [3, 16], 1272 | [3, 23], 1273 | [3, 30], 1274 | [3, 38], 1275 | [3, 46], 1276 | [3, 53], 1277 | [3, 62], 1278 | [3, 71], 1279 | [3, 78], 1280 | [3, 84], 1281 | [3, 92], 1282 | [3, 101], 1283 | [3, 109], 1284 | [3, 116], 1285 | [3, 122], 1286 | [3, 133], 1287 | [3, 141], 1288 | [3, 149], 1289 | [3, 154], 1290 | [3, 158], 1291 | [3, 166], 1292 | [3, 174], 1293 | [3, 181], 1294 | [3, 187], 1295 | [3, 195], 1296 | [4, 1], 1297 | [4, 7], 1298 | [4, 12], 1299 | [4, 15], 1300 | [4, 20], 1301 | [4, 24], 1302 | [4, 27], 1303 | [4, 34], 1304 | [4, 38], 1305 | [4, 45], 1306 | [4, 52], 1307 | [4, 60], 1308 | [4, 66], 1309 | [4, 75], 1310 | [4, 80], 1311 | [4, 87], 1312 | [4, 92], 1313 | [4, 95], 1314 | [4, 102], 1315 | [4, 106], 1316 | [4, 114], 1317 | [4, 122], 1318 | [4, 128], 1319 | [4, 135], 1320 | [4, 141], 1321 | [4, 148], 1322 | [4, 155], 1323 | [4, 163], 1324 | [4, 171], 1325 | [4, 176], 1326 | [5, 3], 1327 | [5, 6], 1328 | [5, 10], 1329 | [5, 14], 1330 | [5, 18], 1331 | [5, 24], 1332 | [5, 32], 1333 | [5, 37], 1334 | [5, 42], 1335 | [5, 46], 1336 | [5, 51], 1337 | [5, 58], 1338 | [5, 65], 1339 | [5, 71], 1340 | [5, 77], 1341 | [5, 83], 1342 | [5, 90], 1343 | [5, 96], 1344 | [5, 104], 1345 | [5, 109], 1346 | [5, 114], 1347 | [6, 1], 1348 | [6, 9], 1349 | [6, 19], 1350 | [6, 28], 1351 | [6, 36], 1352 | [6, 45], 1353 | [6, 53], 1354 | [6, 60], 1355 | [6, 69], 1356 | [6, 74], 1357 | [6, 82], 1358 | [6, 91], 1359 | [6, 95], 1360 | [6, 102], 1361 | [6, 111], 1362 | [6, 119], 1363 | [6, 125], 1364 | [6, 132], 1365 | [6, 138], 1366 | [6, 143], 1367 | [6, 147], 1368 | [6, 152], 1369 | [6, 158], 1370 | [7, 1], 1371 | [7, 12], 1372 | [7, 23], 1373 | [7, 31], 1374 | [7, 38], 1375 | [7, 44], 1376 | [7, 52], 1377 | [7, 58], 1378 | [7, 68], 1379 | [7, 74], 1380 | [7, 82], 1381 | [7, 88], 1382 | [7, 96], 1383 | [7, 105], 1384 | [7, 121], 1385 | [7, 131], 1386 | [7, 138], 1387 | [7, 144], 1388 | [7, 150], 1389 | [7, 156], 1390 | [7, 160], 1391 | [7, 164], 1392 | [7, 171], 1393 | [7, 179], 1394 | [7, 188], 1395 | [7, 196], 1396 | [8, 1], 1397 | [8, 9], 1398 | [8, 17], 1399 | [8, 26], 1400 | [8, 34], 1401 | [8, 41], 1402 | [8, 46], 1403 | [8, 53], 1404 | [8, 62], 1405 | [8, 70], 1406 | [9, 1], 1407 | [9, 7], 1408 | [9, 14], 1409 | [9, 21], 1410 | [9, 27], 1411 | [9, 32], 1412 | [9, 37], 1413 | [9, 41], 1414 | [9, 48], 1415 | [9, 55], 1416 | [9, 62], 1417 | [9, 69], 1418 | [9, 73], 1419 | [9, 80], 1420 | [9, 87], 1421 | [9, 94], 1422 | [9, 100], 1423 | [9, 107], 1424 | [9, 112], 1425 | [9, 118], 1426 | [9, 123], 1427 | [10, 1], 1428 | [10, 7], 1429 | [10, 15], 1430 | [10, 21], 1431 | [10, 26], 1432 | [10, 34], 1433 | [10, 43], 1434 | [10, 54], 1435 | [10, 62], 1436 | [10, 71], 1437 | [10, 79], 1438 | [10, 89], 1439 | [10, 98], 1440 | [10, 107], 1441 | [11, 6], 1442 | [11, 13], 1443 | [11, 20], 1444 | [11, 29], 1445 | [11, 38], 1446 | [11, 46], 1447 | [11, 54], 1448 | [11, 63], 1449 | [11, 72], 1450 | [11, 82], 1451 | [11, 89], 1452 | [11, 98], 1453 | [11, 109], 1454 | [11, 118], 1455 | [12, 5], 1456 | [12, 15], 1457 | [12, 23], 1458 | [12, 31], 1459 | [12, 38], 1460 | [12, 44], 1461 | [12, 53], 1462 | [12, 64], 1463 | [12, 70], 1464 | [12, 79], 1465 | [12, 87], 1466 | [12, 96], 1467 | [12, 104], 1468 | [13, 1], 1469 | [13, 6], 1470 | [13, 14], 1471 | [13, 19], 1472 | [13, 29], 1473 | [13, 35], 1474 | [13, 43], 1475 | [14, 6], 1476 | [14, 11], 1477 | [14, 19], 1478 | [14, 25], 1479 | [14, 34], 1480 | [14, 43], 1481 | [15, 1], 1482 | [15, 16], 1483 | [15, 32], 1484 | [15, 52], 1485 | [15, 71], 1486 | [15, 91], 1487 | [16, 7], 1488 | [16, 15], 1489 | [16, 27], 1490 | [16, 35], 1491 | [16, 43], 1492 | [16, 55], 1493 | [16, 65], 1494 | [16, 73], 1495 | [16, 80], 1496 | [16, 88], 1497 | [16, 94], 1498 | [16, 103], 1499 | [16, 111], 1500 | [16, 119], 1501 | [17, 1], 1502 | [17, 8], 1503 | [17, 18], 1504 | [17, 28], 1505 | [17, 39], 1506 | [17, 50], 1507 | [17, 59], 1508 | [17, 67], 1509 | [17, 76], 1510 | [17, 87], 1511 | [17, 97], 1512 | [17, 105], 1513 | [18, 5], 1514 | [18, 16], 1515 | [18, 21], 1516 | [18, 28], 1517 | [18, 35], 1518 | [18, 46], 1519 | [18, 54], 1520 | [18, 62], 1521 | [18, 75], 1522 | [18, 84], 1523 | [18, 98], 1524 | [19, 1], 1525 | [19, 12], 1526 | [19, 26], 1527 | [19, 39], 1528 | [19, 52], 1529 | [19, 65], 1530 | [19, 77], 1531 | [19, 96], 1532 | [20, 13], 1533 | [20, 38], 1534 | [20, 52], 1535 | [20, 65], 1536 | [20, 77], 1537 | [20, 88], 1538 | [20, 99], 1539 | [20, 114], 1540 | [20, 126], 1541 | [21, 1], 1542 | [21, 11], 1543 | [21, 25], 1544 | [21, 36], 1545 | [21, 45], 1546 | [21, 58], 1547 | [21, 73], 1548 | [21, 82], 1549 | [21, 91], 1550 | [21, 102], 1551 | [22, 1], 1552 | [22, 6], 1553 | [22, 16], 1554 | [22, 24], 1555 | [22, 31], 1556 | [22, 39], 1557 | [22, 47], 1558 | [22, 56], 1559 | [22, 65], 1560 | [22, 73], 1561 | [23, 1], 1562 | [23, 18], 1563 | [23, 28], 1564 | [23, 43], 1565 | [23, 60], 1566 | [23, 75], 1567 | [23, 90], 1568 | [23, 105], 1569 | [24, 1], 1570 | [24, 11], 1571 | [24, 21], 1572 | [24, 28], 1573 | [24, 32], 1574 | [24, 37], 1575 | [24, 44], 1576 | [24, 54], 1577 | [24, 59], 1578 | [24, 62], 1579 | [25, 3], 1580 | [25, 12], 1581 | [25, 21], 1582 | [25, 33], 1583 | [25, 44], 1584 | [25, 56], 1585 | [25, 68], 1586 | [26, 1], 1587 | [26, 20], 1588 | [26, 40], 1589 | [26, 61], 1590 | [26, 84], 1591 | [26, 112], 1592 | [26, 137], 1593 | [26, 160], 1594 | [26, 184], 1595 | [26, 207], 1596 | [27, 1], 1597 | [27, 14], 1598 | [27, 23], 1599 | [27, 36], 1600 | [27, 45], 1601 | [27, 56], 1602 | [27, 64], 1603 | [27, 77], 1604 | [27, 89], 1605 | [28, 6], 1606 | [28, 14], 1607 | [28, 22], 1608 | [28, 29], 1609 | [28, 36], 1610 | [28, 44], 1611 | [28, 51], 1612 | [28, 60], 1613 | [28, 71], 1614 | [28, 78], 1615 | [28, 85], 1616 | [29, 7], 1617 | [29, 15], 1618 | [29, 24], 1619 | [29, 31], 1620 | [29, 39], 1621 | [29, 46], 1622 | [29, 53], 1623 | [29, 64], 1624 | [30, 6], 1625 | [30, 16], 1626 | [30, 25], 1627 | [30, 33], 1628 | [30, 42], 1629 | [30, 51], 1630 | [31, 1], 1631 | [31, 12], 1632 | [31, 20], 1633 | [31, 29], 1634 | [32, 1], 1635 | [32, 12], 1636 | [32, 21], 1637 | [33, 1], 1638 | [33, 7], 1639 | [33, 16], 1640 | [33, 23], 1641 | [33, 31], 1642 | [33, 36], 1643 | [33, 44], 1644 | [33, 51], 1645 | [33, 55], 1646 | [33, 63], 1647 | [34, 1], 1648 | [34, 8], 1649 | [34, 15], 1650 | [34, 23], 1651 | [34, 32], 1652 | [34, 40], 1653 | [34, 49], 1654 | [35, 4], 1655 | [35, 12], 1656 | [35, 19], 1657 | [35, 31], 1658 | [35, 39], 1659 | [35, 45], 1660 | [36, 13], 1661 | [36, 28], 1662 | [36, 41], 1663 | [36, 55], 1664 | [36, 71], 1665 | [37, 1], 1666 | [37, 25], 1667 | [37, 52], 1668 | [37, 77], 1669 | [37, 103], 1670 | [37, 127], 1671 | [37, 154], 1672 | [38, 1], 1673 | [38, 17], 1674 | [38, 27], 1675 | [38, 43], 1676 | [38, 62], 1677 | [38, 84], 1678 | [39, 6], 1679 | [39, 11], 1680 | [39, 22], 1681 | [39, 32], 1682 | [39, 41], 1683 | [39, 48], 1684 | [39, 57], 1685 | [39, 68], 1686 | [39, 75], 1687 | [40, 8], 1688 | [40, 17], 1689 | [40, 26], 1690 | [40, 34], 1691 | [40, 41], 1692 | [40, 50], 1693 | [40, 59], 1694 | [40, 67], 1695 | [40, 78], 1696 | [41, 1], 1697 | [41, 12], 1698 | [41, 21], 1699 | [41, 30], 1700 | [41, 39], 1701 | [41, 47], 1702 | [42, 1], 1703 | [42, 11], 1704 | [42, 16], 1705 | [42, 23], 1706 | [42, 32], 1707 | [42, 45], 1708 | [42, 52], 1709 | [43, 11], 1710 | [43, 23], 1711 | [43, 34], 1712 | [43, 48], 1713 | [43, 61], 1714 | [43, 74], 1715 | [44, 1], 1716 | [44, 19], 1717 | [44, 40], 1718 | [45, 1], 1719 | [45, 14], 1720 | [45, 23], 1721 | [45, 33], 1722 | [46, 6], 1723 | [46, 15], 1724 | [46, 21], 1725 | [46, 29], 1726 | [47, 1], 1727 | [47, 12], 1728 | [47, 20], 1729 | [47, 30], 1730 | [48, 1], 1731 | [48, 10], 1732 | [48, 16], 1733 | [48, 24], 1734 | [48, 29], 1735 | [49, 5], 1736 | [49, 12], 1737 | [50, 1], 1738 | [50, 16], 1739 | [50, 36], 1740 | [51, 7], 1741 | [51, 31], 1742 | [51, 52], 1743 | [52, 15], 1744 | [52, 32], 1745 | [53, 1], 1746 | [53, 27], 1747 | [53, 45], 1748 | [54, 7], 1749 | [54, 28], 1750 | [54, 50], 1751 | [55, 17], 1752 | [55, 41], 1753 | [55, 68], 1754 | [56, 17], 1755 | [56, 51], 1756 | [56, 77], 1757 | [57, 4], 1758 | [57, 12], 1759 | [57, 19], 1760 | [57, 25], 1761 | [58, 1], 1762 | [58, 7], 1763 | [58, 12], 1764 | [58, 22], 1765 | [59, 4], 1766 | [59, 10], 1767 | [59, 17], 1768 | [60, 1], 1769 | [60, 6], 1770 | [60, 12], 1771 | [61, 6], 1772 | [62, 1], 1773 | [62, 9], 1774 | [63, 5], 1775 | [64, 1], 1776 | [64, 10], 1777 | [65, 1], 1778 | [65, 6], 1779 | [66, 1], 1780 | [66, 8], 1781 | [67, 1], 1782 | [67, 13], 1783 | [67, 27], 1784 | [68, 16], 1785 | [68, 43], 1786 | [69, 9], 1787 | [69, 35], 1788 | [70, 11], 1789 | [70, 40], 1790 | [71, 11], 1791 | [72, 1], 1792 | [72, 14], 1793 | [73, 1], 1794 | [73, 20], 1795 | [74, 18], 1796 | [74, 48], 1797 | [75, 20], 1798 | [76, 6], 1799 | [76, 26], 1800 | [77, 20], 1801 | [78, 1], 1802 | [78, 31], 1803 | [79, 16], 1804 | [80, 1], 1805 | [81, 1], 1806 | [82, 1], 1807 | [83, 7], 1808 | [83, 35], 1809 | [85, 1], 1810 | [86, 1], 1811 | [87, 16], 1812 | [89, 1], 1813 | [89, 24], 1814 | [91, 1], 1815 | [92, 15], 1816 | [95, 1], 1817 | [97, 1], 1818 | [98, 8], 1819 | [100, 10], 1820 | [103, 1], 1821 | [106, 1], 1822 | [109, 1], 1823 | [112, 1], 1824 | [115, 1], 1825 | ]; 1826 | 1827 | //------------------ Sajda Data --------------------- 1828 | 1829 | export const Sajda = [ 1830 | // [sura, aya, type] 1831 | [], 1832 | [7, 206, "recommended"], 1833 | [13, 15, "recommended"], 1834 | [16, 50, "recommended"], 1835 | [17, 109, "recommended"], 1836 | [19, 58, "recommended"], 1837 | [22, 18, "recommended"], 1838 | [22, 77, "recommended"], 1839 | [25, 60, "recommended"], 1840 | [27, 26, "recommended"], 1841 | [32, 15, "obligatory"], 1842 | [38, 24, "recommended"], 1843 | [41, 38, "obligatory"], 1844 | [53, 62, "obligatory"], 1845 | [84, 21, "recommended"], 1846 | [96, 19, "obligatory"], 1847 | ]; 1848 | --------------------------------------------------------------------------------