From 1ac1fc9ca0df185f145a4f1e30a2b5a4b413162e Mon Sep 17 00:00:00 2001 From: Torsten Schulz Date: Fri, 30 Aug 2024 11:50:54 +0200 Subject: [PATCH] =?UTF-8?q?=C3=84nderungen=20am=20TAgebuch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + backend/.env | 5 +- backend/config.js | 7 +- backend/controllers/clubsController.js | 83 +- backend/controllers/diaryController.js | 54 + backend/controllers/memberController.js | 33 +- backend/database.js | 2 +- backend/exceptions/HttpError.js | 10 + backend/middleware/authMiddleware.js | 20 +- backend/models/Club.js | 4 + backend/models/DiaryDates.js | 34 + backend/models/Log.js | 14 +- backend/models/Member.js | 79 +- backend/models/User.js | 25 +- backend/models/UserClub.js | 4 +- backend/models/index.js | 4 + backend/node_modules/.bin/color-support | 17 +- backend/node_modules/.bin/color-support.cmd | 17 - backend/node_modules/.bin/color-support.ps1 | 28 - backend/node_modules/.bin/mime | 17 +- backend/node_modules/.bin/mime.cmd | 17 - backend/node_modules/.bin/mime.ps1 | 28 - backend/node_modules/.bin/mkdirp | 17 +- backend/node_modules/.bin/mkdirp.cmd | 17 - backend/node_modules/.bin/mkdirp.ps1 | 28 - backend/node_modules/.bin/node-pre-gyp | 17 +- backend/node_modules/.bin/node-pre-gyp.cmd | 17 - backend/node_modules/.bin/node-pre-gyp.ps1 | 28 - backend/node_modules/.bin/nodemon | 17 +- backend/node_modules/.bin/nodemon.cmd | 17 - backend/node_modules/.bin/nodemon.ps1 | 28 - backend/node_modules/.bin/nodetouch | 17 +- backend/node_modules/.bin/nodetouch.cmd | 17 - backend/node_modules/.bin/nodetouch.ps1 | 28 - backend/node_modules/.bin/nopt | 17 +- backend/node_modules/.bin/nopt.cmd | 17 - backend/node_modules/.bin/nopt.ps1 | 28 - backend/node_modules/.bin/rimraf | 17 +- backend/node_modules/.bin/rimraf.cmd | 17 - backend/node_modules/.bin/rimraf.ps1 | 28 - backend/node_modules/.bin/semver | 17 +- backend/node_modules/.bin/semver.cmd | 17 - backend/node_modules/.bin/semver.ps1 | 28 - backend/node_modules/.bin/uuid | 17 +- backend/node_modules/.bin/uuid.cmd | 17 - backend/node_modules/.bin/uuid.ps1 | 28 - .../@mapbox/node-pre-gyp/bin/node-pre-gyp | 0 backend/node_modules/@types/debug/README.md | 38 +- backend/node_modules/@types/ms/README.md | 38 +- backend/node_modules/@types/node/README.md | 30 +- .../node_modules/@types/validator/README.md | 30 +- .../aws-ssl-profiles/package.json | 0 backend/node_modules/bcrypt/appveyor.yml | 78 +- .../lib/binding/napi-v3/bcrypt_lib.node | Bin 190464 -> 102128 bytes backend/node_modules/bcrypt/test-docker.sh | 0 backend/node_modules/color-support/bin.js | 0 .../make-dir/node_modules/.bin/semver | 17 +- .../make-dir/node_modules/.bin/semver.cmd | 17 - .../make-dir/node_modules/.bin/semver.ps1 | 28 - .../node_modules/semver/bin/semver.js | 0 backend/node_modules/mime/cli.js | 0 backend/node_modules/mime/src/build.js | 0 backend/node_modules/mkdirp/bin/cmd.js | 0 .../node-addon-api/tools/conversion.js | 0 backend/node_modules/nodemon/bin/nodemon.js | 0 backend/node_modules/nopt/bin/nopt.js | 0 backend/node_modules/rimraf/bin.js | 0 backend/node_modules/semver/bin/semver.js | 0 backend/node_modules/sequelize/lib/utils.js | 6 - .../simple-update-notifier/build/index.js | 106 +- backend/node_modules/touch/bin/nodetouch.js | 0 backend/node_modules/uuid/dist/bin/uuid | 0 .../validator/es/lib/isCurrency.js | 0 .../node_modules/validator/es/lib/isVAT.js | 12 +- .../node_modules/validator/lib/isCurrency.js | 0 backend/node_modules/validator/lib/isVAT.js | 12 +- backend/node_modules/validator/validator.js | 12 +- .../whatwg-url/lib/url-state-machine.js | 2594 +++++----- backend/node_modules/wide-align/LICENSE | 0 backend/node_modules/wide-align/README.md | 0 backend/node_modules/wide-align/align.js | 0 backend/node_modules/wide-align/package.json | 0 backend/node_modules/wkx/LICENSE.txt | 40 +- backend/node_modules/wkx/README.md | 184 +- backend/node_modules/wkx/dist/wkx.js | 4208 ++++++++--------- backend/node_modules/wkx/lib/binaryreader.js | 94 +- backend/node_modules/wkx/lib/binarywriter.js | 130 +- backend/node_modules/wkx/lib/geometry.js | 768 +-- .../wkx/lib/geometrycollection.js | 338 +- backend/node_modules/wkx/lib/linestring.js | 356 +- .../node_modules/wkx/lib/multilinestring.js | 378 +- backend/node_modules/wkx/lib/multipoint.js | 344 +- backend/node_modules/wkx/lib/multipolygon.js | 452 +- backend/node_modules/wkx/lib/point.js | 434 +- backend/node_modules/wkx/lib/polygon.js | 576 +-- backend/node_modules/wkx/lib/types.js | 58 +- backend/node_modules/wkx/lib/wktparser.js | 248 +- backend/node_modules/wkx/lib/wkx.d.ts | 198 +- backend/node_modules/wkx/lib/wkx.js | 16 +- backend/node_modules/wkx/lib/zigzag.js | 16 +- backend/node_modules/wkx/package.json | 98 +- backend/routes/diaryRoutes.js | 11 + backend/routes/memberRoutes.js | 5 +- backend/server.js | 31 +- backend/services/authService.js | 20 +- backend/services/diaryService.js | 70 + backend/services/emailService.js | 8 +- backend/services/memberService.js | 72 +- backend/utils/encrypt.js | 19 +- backend/utils/userUtils.js | 49 +- frontend/src/App.vue | 37 +- frontend/src/router.js | 4 + frontend/src/store.js | 1 + frontend/src/views/ClubView.vue | 10 +- frontend/src/views/DiaryView.vue | 158 + frontend/src/views/MembersView.vue | 175 + 116 files changed, 6859 insertions(+), 6765 deletions(-) create mode 100644 backend/controllers/diaryController.js create mode 100644 backend/exceptions/HttpError.js create mode 100644 backend/models/DiaryDates.js mode change 100644 => 120000 backend/node_modules/.bin/color-support delete mode 100644 backend/node_modules/.bin/color-support.cmd delete mode 100644 backend/node_modules/.bin/color-support.ps1 mode change 100644 => 120000 backend/node_modules/.bin/mime delete mode 100644 backend/node_modules/.bin/mime.cmd delete mode 100644 backend/node_modules/.bin/mime.ps1 mode change 100644 => 120000 backend/node_modules/.bin/mkdirp delete mode 100644 backend/node_modules/.bin/mkdirp.cmd delete mode 100644 backend/node_modules/.bin/mkdirp.ps1 mode change 100644 => 120000 backend/node_modules/.bin/node-pre-gyp delete mode 100644 backend/node_modules/.bin/node-pre-gyp.cmd delete mode 100644 backend/node_modules/.bin/node-pre-gyp.ps1 mode change 100644 => 120000 backend/node_modules/.bin/nodemon delete mode 100644 backend/node_modules/.bin/nodemon.cmd delete mode 100644 backend/node_modules/.bin/nodemon.ps1 mode change 100644 => 120000 backend/node_modules/.bin/nodetouch delete mode 100644 backend/node_modules/.bin/nodetouch.cmd delete mode 100644 backend/node_modules/.bin/nodetouch.ps1 mode change 100644 => 120000 backend/node_modules/.bin/nopt delete mode 100644 backend/node_modules/.bin/nopt.cmd delete mode 100644 backend/node_modules/.bin/nopt.ps1 mode change 100644 => 120000 backend/node_modules/.bin/rimraf delete mode 100644 backend/node_modules/.bin/rimraf.cmd delete mode 100644 backend/node_modules/.bin/rimraf.ps1 mode change 100644 => 120000 backend/node_modules/.bin/semver delete mode 100644 backend/node_modules/.bin/semver.cmd delete mode 100644 backend/node_modules/.bin/semver.ps1 mode change 100644 => 120000 backend/node_modules/.bin/uuid delete mode 100644 backend/node_modules/.bin/uuid.cmd delete mode 100644 backend/node_modules/.bin/uuid.ps1 mode change 100644 => 100755 backend/node_modules/@mapbox/node-pre-gyp/bin/node-pre-gyp mode change 100644 => 100755 backend/node_modules/aws-ssl-profiles/package.json mode change 100644 => 100755 backend/node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node mode change 100644 => 100755 backend/node_modules/bcrypt/test-docker.sh mode change 100644 => 100755 backend/node_modules/color-support/bin.js mode change 100644 => 120000 backend/node_modules/make-dir/node_modules/.bin/semver delete mode 100644 backend/node_modules/make-dir/node_modules/.bin/semver.cmd delete mode 100644 backend/node_modules/make-dir/node_modules/.bin/semver.ps1 mode change 100644 => 100755 backend/node_modules/make-dir/node_modules/semver/bin/semver.js mode change 100644 => 100755 backend/node_modules/mime/cli.js mode change 100644 => 100755 backend/node_modules/mime/src/build.js mode change 100644 => 100755 backend/node_modules/mkdirp/bin/cmd.js mode change 100644 => 100755 backend/node_modules/node-addon-api/tools/conversion.js mode change 100644 => 100755 backend/node_modules/nodemon/bin/nodemon.js mode change 100644 => 100755 backend/node_modules/nopt/bin/nopt.js mode change 100644 => 100755 backend/node_modules/rimraf/bin.js mode change 100644 => 100755 backend/node_modules/semver/bin/semver.js mode change 100644 => 100755 backend/node_modules/touch/bin/nodetouch.js mode change 100644 => 100755 backend/node_modules/uuid/dist/bin/uuid mode change 100644 => 100755 backend/node_modules/validator/es/lib/isCurrency.js mode change 100644 => 100755 backend/node_modules/validator/lib/isCurrency.js mode change 100644 => 100755 backend/node_modules/wide-align/LICENSE mode change 100644 => 100755 backend/node_modules/wide-align/README.md mode change 100644 => 100755 backend/node_modules/wide-align/align.js mode change 100644 => 100755 backend/node_modules/wide-align/package.json create mode 100644 backend/routes/diaryRoutes.js create mode 100644 backend/services/diaryService.js create mode 100644 frontend/src/views/DiaryView.vue create mode 100644 frontend/src/views/MembersView.vue diff --git a/.gitignore b/.gitignore index 3c3629e..a152627 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules +frontend/node_modules +backend/node_modules \ No newline at end of file diff --git a/backend/.env b/backend/.env index ab6d3c9..0c0a68a 100644 --- a/backend/.env +++ b/backend/.env @@ -4,4 +4,7 @@ DB_PASSWORD=hitomisan DB_NAME=trainingsdiary DB_DIALECT=mysql JWT_SECRET=x9H7ggzio13P3DF -ENCRYPTION_KEY=x9H7ggzio13P3DF \ No newline at end of file +ENCRYPTION_KEY=daa9cf7ef5b8c5021b455721fedaf10bc1739897c6d9c6d40e4fa3013c4ac83b +EMAIL_USER=tsschulz2001@gmail.com +EMAIL_PASS=wiuo rhxq vmxe eyaj +BASE_URL=http://localhost:3000 \ No newline at end of file diff --git a/backend/config.js b/backend/config.js index 4809704..3910300 100644 --- a/backend/config.js +++ b/backend/config.js @@ -3,9 +3,9 @@ import dotenv from 'dotenv'; dotenv.config(); export const development = { - username: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.DB_NAME, + username: process.env.DB_USER || 'root', + password: process.env.DB_PASSWORD || 'hitomisan', + database: process.env.DB_NAME || 'trainingdiary', host: process.env.DB_HOST, dialect: process.env.DB_DIALECT, define: { @@ -14,3 +14,4 @@ export const development = { underscoredAll: true, }, }; + \ No newline at end of file diff --git a/backend/controllers/clubsController.js b/backend/controllers/clubsController.js index 6bd30fd..b33e62c 100644 --- a/backend/controllers/clubsController.js +++ b/backend/controllers/clubsController.js @@ -1,52 +1,77 @@ import Club from '../models/Club.js'; import UserClub from '../models/UserClub.js'; import User from '../models/User.js'; +import Member from '../models/Member.js'; import { Op, fn, where, col } from 'sequelize'; import { getUserByToken } from '../utils/userUtils.js'; const getClubs = async (req, res) => { - const clubs = await Club.findAll(); - res.status(200).json(clubs); + try { + console.log('[getClubs] - get clubs'); + const clubs = await Club.findAll(); + console.log('[getClubs] - prepare response'); + res.status(200).json(clubs); + console.log('[getClubs] - done'); + } catch (error) { + console.log('[getClubs] - error'); + console.log(error); + res.status(500).json({ error: "internalerror" }); + } }; const addClub = async (req, res) => { + console.log('[addClub] - Read out parameters'); const { authcode: token } = req.headers; const { name: clubName } = req.body; + console.log('[addClub] - find club by name'); const club = await Club.findOne({ where: where(fn('LOWER', col('name')), 'LIKE', `%${clubName.toLowerCase()}%`) }); + console.log('[addClub] - get user'); const user = await getUserByToken(token); + console.log('[addClub] - check if club already exists'); if (club) { res.status(409).json({ error: "alreadyexists" }); return; } - const newClub = Club.create({ name: clubName }); + console.log('[addClub] - create club'); + const newClub = await Club.create({ name: clubName }); + console.log('[addClub] - add user to new club'); UserClub.create({ userId: user.id, clubId: newClub.id, approved: true }); + console.log('[addClub] - prepare response'); res.status(200).json(newClub); + console.log('[addClub] - done'); } const getClub = async (req, res) => { - const { authcode: token } = req.headers; - const { clubid: clubId } = req.params; - console.log('load club', token) - const user = await getUserByToken(token); - console.log(user); - const access = await UserClub.findAll({ - where: { - userId: user.id, - clubId: clubId, - } - }); - if (access.length === 0 || !access[0].approved) { - res.status(403).json({ error: "noaccess", status: access.length === 0 ? "notrequested" : "requested" }); - return; - } + console.log('[getClub] - start'); try { + const { authcode: token } = req.headers; + const { clubid: clubId } = req.params; + console.log('[getClub] - get user'); + const user = await getUserByToken(token); + console.log('[getClub] - get users club'); + const access = await UserClub.findAll({ + where: { + userId: user.id, + clubId: clubId, + } + }); + console.log('[getClub] - check access'); + if (access.length === 0 || !access[0].approved) { + res.status(403).json({ error: "noaccess", status: access.length === 0 ? "notrequested" : "requested" }); + return; + } + console.log('[getClub] - get club'); const club = await Club.findByPk(clubId, { include: [ { model: Member, - as: 'Members', + as: 'members', + order: [ + ['lastName', 'ASC'], // Sortiere nach Nachname aufsteigend + ['firstName', 'ASC'] // Sortiere nach Vorname aufsteigend + ], }, { model: User, @@ -57,13 +82,15 @@ const getClub = async (req, res) => { } ] }); - + console.log('[getClub] - check club exists'); if (!club) { return res.status(404).json({ message: 'Club not found' }); } + console.log('[getClub] - set response'); res.status(200).json(club); + console.log('[getClub] - done'); } catch (error) { - console.error('err', error); + console.log(error); res.status(500).json({ message: 'Server error' }); } } @@ -106,7 +133,7 @@ const approveClubAccess = async (req, res) => { res.status(200).json({ status: 'ok' }); } -const requestClubAccess = async(req, res) => { +const requestClubAccess = async (req, res) => { const { authcode: token } = req.headers; const { clubid: clubId } = req.params; const user = await getUserByToken(token); @@ -114,16 +141,18 @@ const requestClubAccess = async(req, res) => { const access = await UserClub.findAll({ where: { userId: user.id, - clubId: clubId, + clubId: clubId, } }); if (access.length > 0) { - res.status(409).json({ err: "alreadyrequested"}); + res.status(409).json({ err: "alreadyrequested" }); return; } - const club = Club.findOne({ where: { - id: clubId - }}); + const club = Club.findOne({ + where: { + id: clubId + } + }); if (!club) { res.status(404).json({ err: "clubnotfound" }); return; diff --git a/backend/controllers/diaryController.js b/backend/controllers/diaryController.js new file mode 100644 index 0000000..d65c084 --- /dev/null +++ b/backend/controllers/diaryController.js @@ -0,0 +1,54 @@ +import DiaryService from '../services/diaryService.js'; +import HttpError from '../exceptions/HttpError.js'; + +const diaryService = new DiaryService(); + +const getDatesForClub = async (req, res) => { + try { + const { clubId } = req.params; + const { authcode: userToken } = req.headers; + const dates = await diaryService.getDatesForClub(userToken, clubId); + res.status(200).json(dates); + } catch (error) { + console.error('[getDatesForClub] - Error:', error); + res.status(error.statusCode || 500).json({ error: error.message }); + } +}; + +const createDateForClub = async (req, res) => { + try { + const { clubId } = req.params; + const { authcode: userToken } = req.headers; + const { date, trainingStart, trainingEnd } = req.body; + if (!date) { + throw new HttpError('The date field is required', 400); + } + if (isNaN(new Date(date).getTime())) { + throw new HttpError('Invalid date format', 400); + } + const newDate = await diaryService.createDateForClub(userToken, clubId, date, trainingStart, trainingEnd); + res.status(201).json(newDate); + } catch (error) { + console.error('[createDateForClub] - Error:', error); + res.status(error.statusCode || 500).json({ error: error.message }); + } +}; + + +const updateTrainingTimes = async (req, res) => { + try { + const { clubId } = req.params; + const { authcode: userToken } = req.headers; + const { date, trainingStart, trainingEnd } = req.body; + if (!date || !trainingStart || !trainingEnd) { + throw new HttpError('All fields (date, trainingStart, trainingEnd) are required', 400); + } + const updatedDate = await diaryService.updateTrainingTimes(userToken, clubId, date, trainingStart, trainingEnd); + res.status(200).json(updatedDate); + } catch (error) { + console.error('[updateTrainingTimes] - Error:', error); + res.status(error.statusCode || 500).json({ error: error.message }); + } +}; + +export { getDatesForClub, createDateForClub, updateTrainingTimes }; \ No newline at end of file diff --git a/backend/controllers/memberController.js b/backend/controllers/memberController.js index f4e7bbb..40a0833 100644 --- a/backend/controllers/memberController.js +++ b/backend/controllers/memberController.js @@ -1,19 +1,40 @@ import MemberService from "../services/memberService.js"; const getClubMembers = async(req, res) => { - const { clubid: clubId } = req.body; - res.status(200).json(MemberService.getClubMembers(clubId)); + try { + const { authcode: userToken } = req.headers; + const { id: clubId } = req.params; + console.log('[getClubMembers]', userToken, clubId); + res.status(200).json(await MemberService.getClubMembers(userToken, clubId)); + } catch(error) { + console.log('[getClubMembers] - Error: ', error); + res.status(500).json({ error: 'systemerror' }); + } } const getWaitingApprovals = async(req, res) => { try { - const { clubid: clubId } = req.params; - const { authcode: userToken} = req.headers; - const waitingApprovals = MemberService.getApprovalRequests(userToken, clubId); + console.log('[getWaitingApprovals] - Start'); + const { id: clubId } = req.params; + console.log('[getWaitingApprovals] - get token'); + const { authcode: userToken } = req.headers; + console.log('[getWaitingApprovals] - load for waiting approvals'); + const waitingApprovals = await MemberService.getApprovalRequests(userToken, clubId); + console.log('[getWaitingApprovals] - set response'); res.status(200).json(waitingApprovals); + console.log('[getWaitingApprovals] - done'); } catch(error) { + console.log('[getWaitingApprovals] - Error: ', error); res.status(403).json({ error: error }); } +} + +const setClubMembers = async(req, res) => { + const { id: memberId, firstname: firstName, lastname: lastName, street, city, birthdate, phone, email} = req.body; + const { id: clubId } = req.params; + const { authcode: userToken } = req.headers; + const addResult = await MemberService.setClubMember(userToken, clubId, memberId, firstName, lastName, street, city, birthdate, phone, email); + res.status(addResult.status || 500).json(addResult.response); } -export { getClubMembers, getWaitingApprovals }; \ No newline at end of file +export { getClubMembers, getWaitingApprovals, setClubMembers }; \ No newline at end of file diff --git a/backend/database.js b/backend/database.js index 7a9fd4b..babeab2 100644 --- a/backend/database.js +++ b/backend/database.js @@ -2,7 +2,7 @@ import { Sequelize } from 'sequelize'; import { development } from './config.js'; const sequelize = new Sequelize( - development.database, + development.database, development.username, development.password, { diff --git a/backend/exceptions/HttpError.js b/backend/exceptions/HttpError.js new file mode 100644 index 0000000..1592d88 --- /dev/null +++ b/backend/exceptions/HttpError.js @@ -0,0 +1,10 @@ +class HttpError extends Error { + constructor(message, statusCode) { + super(message); + this.name = this.constructor.name; + this.statusCode = statusCode; + Error.captureStackTrace(this, this.constructor); + } +} + +export default HttpError; diff --git a/backend/middleware/authMiddleware.js b/backend/middleware/authMiddleware.js index 4d7a961..6f23479 100644 --- a/backend/middleware/authMiddleware.js +++ b/backend/middleware/authMiddleware.js @@ -1,13 +1,17 @@ import User from '../models/User.js'; export const authenticate = async (req, res, next) => { - const { userid: userId, authcode: authCode } = req.headers; - if (!userId || !authCode) { - return res.status(401).json({ error: 'Unauthorized: Missing credentials' }); + try { + const { userid: userId, authcode: authCode } = req.headers; + if (!userId || !authCode) { + return res.status(401).json({ error: 'Unauthorized: Missing credentials' }); + } + const user = await User.findOne({ where: { email: userId, authCode: authCode } }); + if (!user) { + return res.status(401).json({ error: 'Unauthorized: Invalid credentials' }); + } + next(); + } catch(error) { + return res.status(500).json({ error: 'Internal Server Error at auth' }); } - const user = await User.findOne({ where: { email: userId, hashedId: authCode } }); - if (!user) { - return res.status(401).json({ error: 'Unauthorized: Invalid credentials' }); - } - next(); }; \ No newline at end of file diff --git a/backend/models/Club.js b/backend/models/Club.js index 3d60998..303125c 100644 --- a/backend/models/Club.js +++ b/backend/models/Club.js @@ -7,6 +7,10 @@ const Club = sequelize.define('Club', { allowNull: false, unique: true, }, +}, { + tableName: 'clubs', + underscored: true, + timestamps: true }); export default Club; diff --git a/backend/models/DiaryDates.js b/backend/models/DiaryDates.js new file mode 100644 index 0000000..b586365 --- /dev/null +++ b/backend/models/DiaryDates.js @@ -0,0 +1,34 @@ +import { DataTypes } from 'sequelize'; +import sequelize from '../database.js'; +import Club from './Club.js'; // Importiere das Club-Modell + +const DiaryDate = sequelize.define('DiaryDate', { + date: { + type: DataTypes.DATEONLY, + allowNull: false, + }, + clubId: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: Club, + key: 'id' + }, + onDelete: 'CASCADE', + }, + trainingStart: { + type: DataTypes.TIME, + allowNull: true, + }, + trainingEnd: { + type: DataTypes.TIME, + allowNull: true, + } +}, { + tableName: 'diary_dates', + underscored: true, + timestamps: true +}); + + +export default DiaryDate; diff --git a/backend/models/Log.js b/backend/models/Log.js index e428aa9..7a6fcb6 100644 --- a/backend/models/Log.js +++ b/backend/models/Log.js @@ -7,20 +7,18 @@ const Log = sequelize.define('Log', { type: DataTypes.STRING, allowNull: false, }, - timestamp: { - type: DataTypes.DATE, - defaultValue: DataTypes.NOW, - }, userId: { type: DataTypes.INTEGER, + allowNull: false, references: { - model: User, + model: 'user', key: 'id', }, }, -}, -{ - underscored: true +}, { + underscored: true, + tableName: 'log', + timestamps: true }); export default Log; diff --git a/backend/models/Member.js b/backend/models/Member.js index 12beb5e..ada4ac6 100644 --- a/backend/models/Member.js +++ b/backend/models/Member.js @@ -1,12 +1,10 @@ -const { DataTypes, Model } = require('sequelize'); -const crypto = require('crypto'); -const sequelize = require('../database'); -const Club = require('./Club'); -const { encryptData, decryptData } = require('../utils/encrypt'); +import { DataTypes, Model } from 'sequelize'; +import crypto from 'crypto'; +import sequelize from '../database.js'; +import Club from './Club.js'; +import { encryptData, decryptData } from '../utils/encrypt.js'; -class Member extends Model {} - -Member.init({ +const Member = sequelize.define('User', { id: { type: DataTypes.INTEGER, primaryKey: true, @@ -18,18 +16,30 @@ Member.init({ unique: true, allowNull: false, defaultValue() { - return crypto.randomBytes(16).toString('hex'); + return crypto.randomBytes(64).toString('hex'); } }, - name: { + firstName: { type: DataTypes.STRING, allowNull: false, set(value) { const encryptedValue = encryptData(value); - this.setDataValue('name', encryptedValue); + this.setDataValue('firstName', encryptedValue); }, get() { - const encryptedValue = this.getDataValue('name'); + const encryptedValue = this.getDataValue('firstName'); + return decryptData(encryptedValue); + } + }, + lastName: { + type: DataTypes.STRING, + allowNull: false, + set(value) { + const encryptedValue = encryptData(value); + this.setDataValue('lastName', encryptedValue); + }, + get() { + const encryptedValue = this.getDataValue('lastName'); return decryptData(encryptedValue); } }, @@ -80,27 +90,50 @@ Member.init({ const encryptedValue = this.getDataValue('city'); return decryptData(encryptedValue); } + }, + email: { + type: DataTypes.STRING, + allowNull: false, + set(value) { + const encryptedValue = encryptData(value); + this.setDataValue('email', encryptedValue); + }, + get() { + const encryptedValue = this.getDataValue('email'); + return decryptData(encryptedValue); + } + }, + clubId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + active: { + type: DataTypes.BOOLEAN, + allowNull: false, + default: true, } }, { underscored: true, sequelize, modelName: 'Member', - tableName: 'members', + tableName: 'member', timestamps: true, hooks: { - beforeCreate: (member) => { + afterCreate: (member) => { member.hashedId = crypto.createHash('sha256').update(String(member.id)).digest('hex'); + member.save(); }, - beforeUpdate: (member) => { - if (member.changed('id')) { - member.hashedId = crypto.createHash('sha256').update(String(member.id)).digest('hex'); - } - } } -}); +}, + { + underscored: true, + tableName: 'log', + timestamps: true + } +); -Member.belongsTo(Club); -Club.hasMany(Member); +Member.belongsTo(Club, { as: 'club' }); +Club.hasMany(Member, { as: 'members' }); -module.exports = Member; +export default Member; diff --git a/backend/models/User.js b/backend/models/User.js index 0aebccc..44fd973 100644 --- a/backend/models/User.js +++ b/backend/models/User.js @@ -3,6 +3,12 @@ import sequelize from '../database.js'; import bcrypt from 'bcrypt'; const User = sequelize.define('User', { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true, + allowNull: false + }, hashedId: { type: DataTypes.STRING(1024), allowNull: true, @@ -16,6 +22,10 @@ const User = sequelize.define('User', { type: DataTypes.STRING, allowNull: false, }, + salt: { + type: DataTypes.STRING, + allowNull: true, + }, activationCode: { type: DataTypes.STRING, allowNull: true, @@ -30,20 +40,27 @@ const User = sequelize.define('User', { } }, { underscored: true, - table: 'user', + tableName: 'user', + timestamps: true, hooks: { beforeCreate: async (user) => { const salt = await bcrypt.genSalt(10); + user.salt = salt; + console.log(user); user.password = await bcrypt.hash(user.password, salt); }, beforeUpdate: async (user) => { if (user.changed('password')) { - const salt = await bcrypt.genSalt(10); - user.password = await bcrypt.hash(user.password, salt); + if (!user.password.startsWith('$2b$') && !user.password.startsWith('$2a$')) { + const salt = user.salt; + user.password = await bcrypt.hash(user.password, salt); + } } }, afterCreate: async (user) => { - user.hashedId = bcrypt.hash(user.id.toString()); + const salt = await bcrypt.genSalt(10); + user.hashedId = await bcrypt.hash(user.id.toString(), salt); + await user.save(); } }, }); diff --git a/backend/models/UserClub.js b/backend/models/UserClub.js index 1efecec..2bef85d 100644 --- a/backend/models/UserClub.js +++ b/backend/models/UserClub.js @@ -23,7 +23,9 @@ const UserClub = sequelize.define('UserClub', { defaultValue: false, }, }, { - underscored: true + underscored: true, + tableName: 'user_club', + timestamps: true }); User.belongsToMany(Club, { through: UserClub, foreignKey: 'userId' }); diff --git a/backend/models/index.js b/backend/models/index.js index a39efd9..7e7b66a 100644 --- a/backend/models/index.js +++ b/backend/models/index.js @@ -2,6 +2,7 @@ import User from './User.js'; import Log from './Log.js'; import Club from './Club.js'; import UserClub from './UserClub.js'; +import DiaryDate from './DiaryDates.js'; User.hasMany(Log, { foreignKey: 'userId' }); Log.belongsTo(User, { foreignKey: 'userId' }); @@ -9,4 +10,7 @@ Log.belongsTo(User, { foreignKey: 'userId' }); User.belongsToMany(Club, { through: UserClub, foreignKey: 'userId' }); Club.belongsToMany(User, { through: UserClub, foreignKey: 'clubId' }); +DiaryDate.belongsTo(Club, { foreignKey: 'clubId' }); +Club.hasMany(DiaryDate, { foreignKey: 'clubId' }); + export { User, Log, Club, UserClub }; diff --git a/backend/node_modules/.bin/color-support b/backend/node_modules/.bin/color-support deleted file mode 100644 index f77f9d5..0000000 --- a/backend/node_modules/.bin/color-support +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") - -case `uname` in - *CYGWIN*|*MINGW*|*MSYS*) - if command -v cygpath > /dev/null 2>&1; then - basedir=`cygpath -w "$basedir"` - fi - ;; -esac - -if [ -x "$basedir/node" ]; then - exec "$basedir/node" "$basedir/../color-support/bin.js" "$@" -else - exec node "$basedir/../color-support/bin.js" "$@" -fi diff --git a/backend/node_modules/.bin/color-support b/backend/node_modules/.bin/color-support new file mode 120000 index 0000000..fcbcb28 --- /dev/null +++ b/backend/node_modules/.bin/color-support @@ -0,0 +1 @@ +../color-support/bin.js \ No newline at end of file diff --git a/backend/node_modules/.bin/color-support.cmd b/backend/node_modules/.bin/color-support.cmd deleted file mode 100644 index 005f9a5..0000000 --- a/backend/node_modules/.bin/color-support.cmd +++ /dev/null @@ -1,17 +0,0 @@ -@ECHO off -GOTO start -:find_dp0 -SET dp0=%~dp0 -EXIT /b -:start -SETLOCAL -CALL :find_dp0 - -IF EXIST "%dp0%\node.exe" ( - SET "_prog=%dp0%\node.exe" -) ELSE ( - SET "_prog=node" - SET PATHEXT=%PATHEXT:;.JS;=;% -) - -endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\color-support\bin.js" %* diff --git a/backend/node_modules/.bin/color-support.ps1 b/backend/node_modules/.bin/color-support.ps1 deleted file mode 100644 index f5c9fe4..0000000 --- a/backend/node_modules/.bin/color-support.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env pwsh -$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent - -$exe="" -if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { - # Fix case when both the Windows and Linux builds of Node - # are installed in the same directory - $exe=".exe" -} -$ret=0 -if (Test-Path "$basedir/node$exe") { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "$basedir/node$exe" "$basedir/../color-support/bin.js" $args - } else { - & "$basedir/node$exe" "$basedir/../color-support/bin.js" $args - } - $ret=$LASTEXITCODE -} else { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "node$exe" "$basedir/../color-support/bin.js" $args - } else { - & "node$exe" "$basedir/../color-support/bin.js" $args - } - $ret=$LASTEXITCODE -} -exit $ret diff --git a/backend/node_modules/.bin/mime b/backend/node_modules/.bin/mime deleted file mode 100644 index 7751de3..0000000 --- a/backend/node_modules/.bin/mime +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") - -case `uname` in - *CYGWIN*|*MINGW*|*MSYS*) - if command -v cygpath > /dev/null 2>&1; then - basedir=`cygpath -w "$basedir"` - fi - ;; -esac - -if [ -x "$basedir/node" ]; then - exec "$basedir/node" "$basedir/../mime/cli.js" "$@" -else - exec node "$basedir/../mime/cli.js" "$@" -fi diff --git a/backend/node_modules/.bin/mime b/backend/node_modules/.bin/mime new file mode 120000 index 0000000..fbb7ee0 --- /dev/null +++ b/backend/node_modules/.bin/mime @@ -0,0 +1 @@ +../mime/cli.js \ No newline at end of file diff --git a/backend/node_modules/.bin/mime.cmd b/backend/node_modules/.bin/mime.cmd deleted file mode 100644 index 54491f1..0000000 --- a/backend/node_modules/.bin/mime.cmd +++ /dev/null @@ -1,17 +0,0 @@ -@ECHO off -GOTO start -:find_dp0 -SET dp0=%~dp0 -EXIT /b -:start -SETLOCAL -CALL :find_dp0 - -IF EXIST "%dp0%\node.exe" ( - SET "_prog=%dp0%\node.exe" -) ELSE ( - SET "_prog=node" - SET PATHEXT=%PATHEXT:;.JS;=;% -) - -endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\mime\cli.js" %* diff --git a/backend/node_modules/.bin/mime.ps1 b/backend/node_modules/.bin/mime.ps1 deleted file mode 100644 index 2222f40..0000000 --- a/backend/node_modules/.bin/mime.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env pwsh -$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent - -$exe="" -if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { - # Fix case when both the Windows and Linux builds of Node - # are installed in the same directory - $exe=".exe" -} -$ret=0 -if (Test-Path "$basedir/node$exe") { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "$basedir/node$exe" "$basedir/../mime/cli.js" $args - } else { - & "$basedir/node$exe" "$basedir/../mime/cli.js" $args - } - $ret=$LASTEXITCODE -} else { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "node$exe" "$basedir/../mime/cli.js" $args - } else { - & "node$exe" "$basedir/../mime/cli.js" $args - } - $ret=$LASTEXITCODE -} -exit $ret diff --git a/backend/node_modules/.bin/mkdirp b/backend/node_modules/.bin/mkdirp deleted file mode 100644 index 1ab9c81..0000000 --- a/backend/node_modules/.bin/mkdirp +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") - -case `uname` in - *CYGWIN*|*MINGW*|*MSYS*) - if command -v cygpath > /dev/null 2>&1; then - basedir=`cygpath -w "$basedir"` - fi - ;; -esac - -if [ -x "$basedir/node" ]; then - exec "$basedir/node" "$basedir/../mkdirp/bin/cmd.js" "$@" -else - exec node "$basedir/../mkdirp/bin/cmd.js" "$@" -fi diff --git a/backend/node_modules/.bin/mkdirp b/backend/node_modules/.bin/mkdirp new file mode 120000 index 0000000..017896c --- /dev/null +++ b/backend/node_modules/.bin/mkdirp @@ -0,0 +1 @@ +../mkdirp/bin/cmd.js \ No newline at end of file diff --git a/backend/node_modules/.bin/mkdirp.cmd b/backend/node_modules/.bin/mkdirp.cmd deleted file mode 100644 index a865dd9..0000000 --- a/backend/node_modules/.bin/mkdirp.cmd +++ /dev/null @@ -1,17 +0,0 @@ -@ECHO off -GOTO start -:find_dp0 -SET dp0=%~dp0 -EXIT /b -:start -SETLOCAL -CALL :find_dp0 - -IF EXIST "%dp0%\node.exe" ( - SET "_prog=%dp0%\node.exe" -) ELSE ( - SET "_prog=node" - SET PATHEXT=%PATHEXT:;.JS;=;% -) - -endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\mkdirp\bin\cmd.js" %* diff --git a/backend/node_modules/.bin/mkdirp.ps1 b/backend/node_modules/.bin/mkdirp.ps1 deleted file mode 100644 index 911e854..0000000 --- a/backend/node_modules/.bin/mkdirp.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env pwsh -$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent - -$exe="" -if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { - # Fix case when both the Windows and Linux builds of Node - # are installed in the same directory - $exe=".exe" -} -$ret=0 -if (Test-Path "$basedir/node$exe") { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "$basedir/node$exe" "$basedir/../mkdirp/bin/cmd.js" $args - } else { - & "$basedir/node$exe" "$basedir/../mkdirp/bin/cmd.js" $args - } - $ret=$LASTEXITCODE -} else { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "node$exe" "$basedir/../mkdirp/bin/cmd.js" $args - } else { - & "node$exe" "$basedir/../mkdirp/bin/cmd.js" $args - } - $ret=$LASTEXITCODE -} -exit $ret diff --git a/backend/node_modules/.bin/node-pre-gyp b/backend/node_modules/.bin/node-pre-gyp deleted file mode 100644 index d1619e4..0000000 --- a/backend/node_modules/.bin/node-pre-gyp +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") - -case `uname` in - *CYGWIN*|*MINGW*|*MSYS*) - if command -v cygpath > /dev/null 2>&1; then - basedir=`cygpath -w "$basedir"` - fi - ;; -esac - -if [ -x "$basedir/node" ]; then - exec "$basedir/node" "$basedir/../@mapbox/node-pre-gyp/bin/node-pre-gyp" "$@" -else - exec node "$basedir/../@mapbox/node-pre-gyp/bin/node-pre-gyp" "$@" -fi diff --git a/backend/node_modules/.bin/node-pre-gyp b/backend/node_modules/.bin/node-pre-gyp new file mode 120000 index 0000000..2946e6a --- /dev/null +++ b/backend/node_modules/.bin/node-pre-gyp @@ -0,0 +1 @@ +../@mapbox/node-pre-gyp/bin/node-pre-gyp \ No newline at end of file diff --git a/backend/node_modules/.bin/node-pre-gyp.cmd b/backend/node_modules/.bin/node-pre-gyp.cmd deleted file mode 100644 index a2fc508..0000000 --- a/backend/node_modules/.bin/node-pre-gyp.cmd +++ /dev/null @@ -1,17 +0,0 @@ -@ECHO off -GOTO start -:find_dp0 -SET dp0=%~dp0 -EXIT /b -:start -SETLOCAL -CALL :find_dp0 - -IF EXIST "%dp0%\node.exe" ( - SET "_prog=%dp0%\node.exe" -) ELSE ( - SET "_prog=node" - SET PATHEXT=%PATHEXT:;.JS;=;% -) - -endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\@mapbox\node-pre-gyp\bin\node-pre-gyp" %* diff --git a/backend/node_modules/.bin/node-pre-gyp.ps1 b/backend/node_modules/.bin/node-pre-gyp.ps1 deleted file mode 100644 index ed297ff..0000000 --- a/backend/node_modules/.bin/node-pre-gyp.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env pwsh -$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent - -$exe="" -if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { - # Fix case when both the Windows and Linux builds of Node - # are installed in the same directory - $exe=".exe" -} -$ret=0 -if (Test-Path "$basedir/node$exe") { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "$basedir/node$exe" "$basedir/../@mapbox/node-pre-gyp/bin/node-pre-gyp" $args - } else { - & "$basedir/node$exe" "$basedir/../@mapbox/node-pre-gyp/bin/node-pre-gyp" $args - } - $ret=$LASTEXITCODE -} else { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "node$exe" "$basedir/../@mapbox/node-pre-gyp/bin/node-pre-gyp" $args - } else { - & "node$exe" "$basedir/../@mapbox/node-pre-gyp/bin/node-pre-gyp" $args - } - $ret=$LASTEXITCODE -} -exit $ret diff --git a/backend/node_modules/.bin/nodemon b/backend/node_modules/.bin/nodemon deleted file mode 100644 index c477a18..0000000 --- a/backend/node_modules/.bin/nodemon +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") - -case `uname` in - *CYGWIN*|*MINGW*|*MSYS*) - if command -v cygpath > /dev/null 2>&1; then - basedir=`cygpath -w "$basedir"` - fi - ;; -esac - -if [ -x "$basedir/node" ]; then - exec "$basedir/node" "$basedir/../nodemon/bin/nodemon.js" "$@" -else - exec node "$basedir/../nodemon/bin/nodemon.js" "$@" -fi diff --git a/backend/node_modules/.bin/nodemon b/backend/node_modules/.bin/nodemon new file mode 120000 index 0000000..1056ddc --- /dev/null +++ b/backend/node_modules/.bin/nodemon @@ -0,0 +1 @@ +../nodemon/bin/nodemon.js \ No newline at end of file diff --git a/backend/node_modules/.bin/nodemon.cmd b/backend/node_modules/.bin/nodemon.cmd deleted file mode 100644 index 55acf8a..0000000 --- a/backend/node_modules/.bin/nodemon.cmd +++ /dev/null @@ -1,17 +0,0 @@ -@ECHO off -GOTO start -:find_dp0 -SET dp0=%~dp0 -EXIT /b -:start -SETLOCAL -CALL :find_dp0 - -IF EXIST "%dp0%\node.exe" ( - SET "_prog=%dp0%\node.exe" -) ELSE ( - SET "_prog=node" - SET PATHEXT=%PATHEXT:;.JS;=;% -) - -endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\nodemon\bin\nodemon.js" %* diff --git a/backend/node_modules/.bin/nodemon.ps1 b/backend/node_modules/.bin/nodemon.ps1 deleted file mode 100644 index d4e3f5d..0000000 --- a/backend/node_modules/.bin/nodemon.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env pwsh -$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent - -$exe="" -if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { - # Fix case when both the Windows and Linux builds of Node - # are installed in the same directory - $exe=".exe" -} -$ret=0 -if (Test-Path "$basedir/node$exe") { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "$basedir/node$exe" "$basedir/../nodemon/bin/nodemon.js" $args - } else { - & "$basedir/node$exe" "$basedir/../nodemon/bin/nodemon.js" $args - } - $ret=$LASTEXITCODE -} else { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "node$exe" "$basedir/../nodemon/bin/nodemon.js" $args - } else { - & "node$exe" "$basedir/../nodemon/bin/nodemon.js" $args - } - $ret=$LASTEXITCODE -} -exit $ret diff --git a/backend/node_modules/.bin/nodetouch b/backend/node_modules/.bin/nodetouch deleted file mode 100644 index 3e146b4..0000000 --- a/backend/node_modules/.bin/nodetouch +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") - -case `uname` in - *CYGWIN*|*MINGW*|*MSYS*) - if command -v cygpath > /dev/null 2>&1; then - basedir=`cygpath -w "$basedir"` - fi - ;; -esac - -if [ -x "$basedir/node" ]; then - exec "$basedir/node" "$basedir/../touch/bin/nodetouch.js" "$@" -else - exec node "$basedir/../touch/bin/nodetouch.js" "$@" -fi diff --git a/backend/node_modules/.bin/nodetouch b/backend/node_modules/.bin/nodetouch new file mode 120000 index 0000000..3409fdb --- /dev/null +++ b/backend/node_modules/.bin/nodetouch @@ -0,0 +1 @@ +../touch/bin/nodetouch.js \ No newline at end of file diff --git a/backend/node_modules/.bin/nodetouch.cmd b/backend/node_modules/.bin/nodetouch.cmd deleted file mode 100644 index 8298b91..0000000 --- a/backend/node_modules/.bin/nodetouch.cmd +++ /dev/null @@ -1,17 +0,0 @@ -@ECHO off -GOTO start -:find_dp0 -SET dp0=%~dp0 -EXIT /b -:start -SETLOCAL -CALL :find_dp0 - -IF EXIST "%dp0%\node.exe" ( - SET "_prog=%dp0%\node.exe" -) ELSE ( - SET "_prog=node" - SET PATHEXT=%PATHEXT:;.JS;=;% -) - -endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\touch\bin\nodetouch.js" %* diff --git a/backend/node_modules/.bin/nodetouch.ps1 b/backend/node_modules/.bin/nodetouch.ps1 deleted file mode 100644 index 5f68b4c..0000000 --- a/backend/node_modules/.bin/nodetouch.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env pwsh -$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent - -$exe="" -if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { - # Fix case when both the Windows and Linux builds of Node - # are installed in the same directory - $exe=".exe" -} -$ret=0 -if (Test-Path "$basedir/node$exe") { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "$basedir/node$exe" "$basedir/../touch/bin/nodetouch.js" $args - } else { - & "$basedir/node$exe" "$basedir/../touch/bin/nodetouch.js" $args - } - $ret=$LASTEXITCODE -} else { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "node$exe" "$basedir/../touch/bin/nodetouch.js" $args - } else { - & "node$exe" "$basedir/../touch/bin/nodetouch.js" $args - } - $ret=$LASTEXITCODE -} -exit $ret diff --git a/backend/node_modules/.bin/nopt b/backend/node_modules/.bin/nopt deleted file mode 100644 index 0808130..0000000 --- a/backend/node_modules/.bin/nopt +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") - -case `uname` in - *CYGWIN*|*MINGW*|*MSYS*) - if command -v cygpath > /dev/null 2>&1; then - basedir=`cygpath -w "$basedir"` - fi - ;; -esac - -if [ -x "$basedir/node" ]; then - exec "$basedir/node" "$basedir/../nopt/bin/nopt.js" "$@" -else - exec node "$basedir/../nopt/bin/nopt.js" "$@" -fi diff --git a/backend/node_modules/.bin/nopt b/backend/node_modules/.bin/nopt new file mode 120000 index 0000000..6b6566e --- /dev/null +++ b/backend/node_modules/.bin/nopt @@ -0,0 +1 @@ +../nopt/bin/nopt.js \ No newline at end of file diff --git a/backend/node_modules/.bin/nopt.cmd b/backend/node_modules/.bin/nopt.cmd deleted file mode 100644 index a7f38b3..0000000 --- a/backend/node_modules/.bin/nopt.cmd +++ /dev/null @@ -1,17 +0,0 @@ -@ECHO off -GOTO start -:find_dp0 -SET dp0=%~dp0 -EXIT /b -:start -SETLOCAL -CALL :find_dp0 - -IF EXIST "%dp0%\node.exe" ( - SET "_prog=%dp0%\node.exe" -) ELSE ( - SET "_prog=node" - SET PATHEXT=%PATHEXT:;.JS;=;% -) - -endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\nopt\bin\nopt.js" %* diff --git a/backend/node_modules/.bin/nopt.ps1 b/backend/node_modules/.bin/nopt.ps1 deleted file mode 100644 index 9d6ba56..0000000 --- a/backend/node_modules/.bin/nopt.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env pwsh -$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent - -$exe="" -if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { - # Fix case when both the Windows and Linux builds of Node - # are installed in the same directory - $exe=".exe" -} -$ret=0 -if (Test-Path "$basedir/node$exe") { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "$basedir/node$exe" "$basedir/../nopt/bin/nopt.js" $args - } else { - & "$basedir/node$exe" "$basedir/../nopt/bin/nopt.js" $args - } - $ret=$LASTEXITCODE -} else { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "node$exe" "$basedir/../nopt/bin/nopt.js" $args - } else { - & "node$exe" "$basedir/../nopt/bin/nopt.js" $args - } - $ret=$LASTEXITCODE -} -exit $ret diff --git a/backend/node_modules/.bin/rimraf b/backend/node_modules/.bin/rimraf deleted file mode 100644 index 6d6240a..0000000 --- a/backend/node_modules/.bin/rimraf +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") - -case `uname` in - *CYGWIN*|*MINGW*|*MSYS*) - if command -v cygpath > /dev/null 2>&1; then - basedir=`cygpath -w "$basedir"` - fi - ;; -esac - -if [ -x "$basedir/node" ]; then - exec "$basedir/node" "$basedir/../rimraf/bin.js" "$@" -else - exec node "$basedir/../rimraf/bin.js" "$@" -fi diff --git a/backend/node_modules/.bin/rimraf b/backend/node_modules/.bin/rimraf new file mode 120000 index 0000000..4cd49a4 --- /dev/null +++ b/backend/node_modules/.bin/rimraf @@ -0,0 +1 @@ +../rimraf/bin.js \ No newline at end of file diff --git a/backend/node_modules/.bin/rimraf.cmd b/backend/node_modules/.bin/rimraf.cmd deleted file mode 100644 index 13f45ec..0000000 --- a/backend/node_modules/.bin/rimraf.cmd +++ /dev/null @@ -1,17 +0,0 @@ -@ECHO off -GOTO start -:find_dp0 -SET dp0=%~dp0 -EXIT /b -:start -SETLOCAL -CALL :find_dp0 - -IF EXIST "%dp0%\node.exe" ( - SET "_prog=%dp0%\node.exe" -) ELSE ( - SET "_prog=node" - SET PATHEXT=%PATHEXT:;.JS;=;% -) - -endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\rimraf\bin.js" %* diff --git a/backend/node_modules/.bin/rimraf.ps1 b/backend/node_modules/.bin/rimraf.ps1 deleted file mode 100644 index 1716791..0000000 --- a/backend/node_modules/.bin/rimraf.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env pwsh -$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent - -$exe="" -if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { - # Fix case when both the Windows and Linux builds of Node - # are installed in the same directory - $exe=".exe" -} -$ret=0 -if (Test-Path "$basedir/node$exe") { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "$basedir/node$exe" "$basedir/../rimraf/bin.js" $args - } else { - & "$basedir/node$exe" "$basedir/../rimraf/bin.js" $args - } - $ret=$LASTEXITCODE -} else { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "node$exe" "$basedir/../rimraf/bin.js" $args - } else { - & "node$exe" "$basedir/../rimraf/bin.js" $args - } - $ret=$LASTEXITCODE -} -exit $ret diff --git a/backend/node_modules/.bin/semver b/backend/node_modules/.bin/semver deleted file mode 100644 index 97c5327..0000000 --- a/backend/node_modules/.bin/semver +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") - -case `uname` in - *CYGWIN*|*MINGW*|*MSYS*) - if command -v cygpath > /dev/null 2>&1; then - basedir=`cygpath -w "$basedir"` - fi - ;; -esac - -if [ -x "$basedir/node" ]; then - exec "$basedir/node" "$basedir/../semver/bin/semver.js" "$@" -else - exec node "$basedir/../semver/bin/semver.js" "$@" -fi diff --git a/backend/node_modules/.bin/semver b/backend/node_modules/.bin/semver new file mode 120000 index 0000000..5aaadf4 --- /dev/null +++ b/backend/node_modules/.bin/semver @@ -0,0 +1 @@ +../semver/bin/semver.js \ No newline at end of file diff --git a/backend/node_modules/.bin/semver.cmd b/backend/node_modules/.bin/semver.cmd deleted file mode 100644 index 9913fa9..0000000 --- a/backend/node_modules/.bin/semver.cmd +++ /dev/null @@ -1,17 +0,0 @@ -@ECHO off -GOTO start -:find_dp0 -SET dp0=%~dp0 -EXIT /b -:start -SETLOCAL -CALL :find_dp0 - -IF EXIST "%dp0%\node.exe" ( - SET "_prog=%dp0%\node.exe" -) ELSE ( - SET "_prog=node" - SET PATHEXT=%PATHEXT:;.JS;=;% -) - -endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\semver\bin\semver.js" %* diff --git a/backend/node_modules/.bin/semver.ps1 b/backend/node_modules/.bin/semver.ps1 deleted file mode 100644 index 314717a..0000000 --- a/backend/node_modules/.bin/semver.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env pwsh -$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent - -$exe="" -if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { - # Fix case when both the Windows and Linux builds of Node - # are installed in the same directory - $exe=".exe" -} -$ret=0 -if (Test-Path "$basedir/node$exe") { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "$basedir/node$exe" "$basedir/../semver/bin/semver.js" $args - } else { - & "$basedir/node$exe" "$basedir/../semver/bin/semver.js" $args - } - $ret=$LASTEXITCODE -} else { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "node$exe" "$basedir/../semver/bin/semver.js" $args - } else { - & "node$exe" "$basedir/../semver/bin/semver.js" $args - } - $ret=$LASTEXITCODE -} -exit $ret diff --git a/backend/node_modules/.bin/uuid b/backend/node_modules/.bin/uuid deleted file mode 100644 index 0c2d469..0000000 --- a/backend/node_modules/.bin/uuid +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") - -case `uname` in - *CYGWIN*|*MINGW*|*MSYS*) - if command -v cygpath > /dev/null 2>&1; then - basedir=`cygpath -w "$basedir"` - fi - ;; -esac - -if [ -x "$basedir/node" ]; then - exec "$basedir/node" "$basedir/../uuid/dist/bin/uuid" "$@" -else - exec node "$basedir/../uuid/dist/bin/uuid" "$@" -fi diff --git a/backend/node_modules/.bin/uuid b/backend/node_modules/.bin/uuid new file mode 120000 index 0000000..588f70e --- /dev/null +++ b/backend/node_modules/.bin/uuid @@ -0,0 +1 @@ +../uuid/dist/bin/uuid \ No newline at end of file diff --git a/backend/node_modules/.bin/uuid.cmd b/backend/node_modules/.bin/uuid.cmd deleted file mode 100644 index 0f2376e..0000000 --- a/backend/node_modules/.bin/uuid.cmd +++ /dev/null @@ -1,17 +0,0 @@ -@ECHO off -GOTO start -:find_dp0 -SET dp0=%~dp0 -EXIT /b -:start -SETLOCAL -CALL :find_dp0 - -IF EXIST "%dp0%\node.exe" ( - SET "_prog=%dp0%\node.exe" -) ELSE ( - SET "_prog=node" - SET PATHEXT=%PATHEXT:;.JS;=;% -) - -endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\uuid\dist\bin\uuid" %* diff --git a/backend/node_modules/.bin/uuid.ps1 b/backend/node_modules/.bin/uuid.ps1 deleted file mode 100644 index 7804628..0000000 --- a/backend/node_modules/.bin/uuid.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env pwsh -$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent - -$exe="" -if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { - # Fix case when both the Windows and Linux builds of Node - # are installed in the same directory - $exe=".exe" -} -$ret=0 -if (Test-Path "$basedir/node$exe") { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "$basedir/node$exe" "$basedir/../uuid/dist/bin/uuid" $args - } else { - & "$basedir/node$exe" "$basedir/../uuid/dist/bin/uuid" $args - } - $ret=$LASTEXITCODE -} else { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "node$exe" "$basedir/../uuid/dist/bin/uuid" $args - } else { - & "node$exe" "$basedir/../uuid/dist/bin/uuid" $args - } - $ret=$LASTEXITCODE -} -exit $ret diff --git a/backend/node_modules/@mapbox/node-pre-gyp/bin/node-pre-gyp b/backend/node_modules/@mapbox/node-pre-gyp/bin/node-pre-gyp old mode 100644 new mode 100755 diff --git a/backend/node_modules/@types/debug/README.md b/backend/node_modules/@types/debug/README.md index b67a4dc..e9563de 100644 --- a/backend/node_modules/@types/debug/README.md +++ b/backend/node_modules/@types/debug/README.md @@ -1,13 +1,13 @@ -# Installation -> `npm install --save @types/debug` - -# Summary -This package contains type definitions for debug (https://github.com/debug-js/debug). - -# Details -Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/debug. -## [index.d.ts](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/debug/index.d.ts) -````ts +# Installation +> `npm install --save @types/debug` + +# Summary +This package contains type definitions for debug (https://github.com/debug-js/debug). + +# Details +Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/debug. +## [index.d.ts](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/debug/index.d.ts) +````ts declare var debug: debug.Debug & { debug: debug.Debug; default: debug.Debug }; export = debug; @@ -58,12 +58,12 @@ declare namespace debug { extend: (namespace: string, delimiter?: string) => Debugger; } } - -```` - -### Additional Details - * Last updated: Thu, 09 Nov 2023 03:06:57 GMT - * Dependencies: [@types/ms](https://npmjs.com/package/@types/ms) - -# Credits -These definitions were written by [Seon-Wook Park](https://github.com/swook), [Gal Talmor](https://github.com/galtalmor), [John McLaughlin](https://github.com/zamb3zi), [Brasten Sager](https://github.com/brasten), [Nicolas Penin](https://github.com/npenin), [Kristian Brünn](https://github.com/kristianmitk), and [Caleb Gregory](https://github.com/calebgregory). + +```` + +### Additional Details + * Last updated: Thu, 09 Nov 2023 03:06:57 GMT + * Dependencies: [@types/ms](https://npmjs.com/package/@types/ms) + +# Credits +These definitions were written by [Seon-Wook Park](https://github.com/swook), [Gal Talmor](https://github.com/galtalmor), [John McLaughlin](https://github.com/zamb3zi), [Brasten Sager](https://github.com/brasten), [Nicolas Penin](https://github.com/npenin), [Kristian Brünn](https://github.com/kristianmitk), and [Caleb Gregory](https://github.com/calebgregory). diff --git a/backend/node_modules/@types/ms/README.md b/backend/node_modules/@types/ms/README.md index e2354c3..6512928 100644 --- a/backend/node_modules/@types/ms/README.md +++ b/backend/node_modules/@types/ms/README.md @@ -1,13 +1,13 @@ -# Installation -> `npm install --save @types/ms` - -# Summary -This package contains type definitions for ms (https://github.com/zeit/ms). - -# Details -Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ms. -## [index.d.ts](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ms/index.d.ts) -````ts +# Installation +> `npm install --save @types/ms` + +# Summary +This package contains type definitions for ms (https://github.com/zeit/ms). + +# Details +Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ms. +## [index.d.ts](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ms/index.d.ts) +````ts /** * Short/Long format for `value`. * @@ -26,12 +26,12 @@ declare function ms(value: number, options?: { long: boolean }): string; declare function ms(value: string): number; export = ms; - -```` - -### Additional Details - * Last updated: Tue, 07 Nov 2023 09:09:39 GMT - * Dependencies: none - -# Credits -These definitions were written by [Zhiyuan Wang](https://github.com/danny8002). + +```` + +### Additional Details + * Last updated: Tue, 07 Nov 2023 09:09:39 GMT + * Dependencies: none + +# Credits +These definitions were written by [Zhiyuan Wang](https://github.com/danny8002). diff --git a/backend/node_modules/@types/node/README.md b/backend/node_modules/@types/node/README.md index 317aecd..7d75f1c 100644 --- a/backend/node_modules/@types/node/README.md +++ b/backend/node_modules/@types/node/README.md @@ -1,15 +1,15 @@ -# Installation -> `npm install --save @types/node` - -# Summary -This package contains type definitions for node (https://nodejs.org/). - -# Details -Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node. - -### Additional Details - * Last updated: Tue, 23 Jul 2024 18:09:25 GMT - * Dependencies: [undici-types](https://npmjs.com/package/undici-types) - -# Credits -These definitions were written by [Microsoft TypeScript](https://github.com/Microsoft), [Alberto Schiabel](https://github.com/jkomyno), [Alvis HT Tang](https://github.com/alvis), [Andrew Makarov](https://github.com/r3nya), [Benjamin Toueg](https://github.com/btoueg), [Chigozirim C.](https://github.com/smac89), [David Junger](https://github.com/touffy), [Deividas Bakanas](https://github.com/DeividasBakanas), [Eugene Y. Q. Shen](https://github.com/eyqs), [Hannes Magnusson](https://github.com/Hannes-Magnusson-CK), [Huw](https://github.com/hoo29), [Kelvin Jin](https://github.com/kjin), [Klaus Meinhardt](https://github.com/ajafff), [Lishude](https://github.com/islishude), [Mariusz Wiktorczyk](https://github.com/mwiktorczyk), [Mohsen Azimi](https://github.com/mohsen1), [Nikita Galkin](https://github.com/galkin), [Parambir Singh](https://github.com/parambirs), [Sebastian Silbermann](https://github.com/eps1lon), [Thomas den Hollander](https://github.com/ThomasdenH), [Wilco Bakker](https://github.com/WilcoBakker), [wwwy3y3](https://github.com/wwwy3y3), [Samuel Ainsworth](https://github.com/samuela), [Kyle Uehlein](https://github.com/kuehlein), [Thanik Bhongbhibhat](https://github.com/bhongy), [Marcin Kopacz](https://github.com/chyzwar), [Trivikram Kamat](https://github.com/trivikr), [Junxiao Shi](https://github.com/yoursunny), [Ilia Baryshnikov](https://github.com/qwelias), [ExE Boss](https://github.com/ExE-Boss), [Piotr Błażejewicz](https://github.com/peterblazejewicz), [Anna Henningsen](https://github.com/addaleax), [Victor Perin](https://github.com/victorperin), [Yongsheng Zhang](https://github.com/ZYSzys), [NodeJS Contributors](https://github.com/NodeJS), [Linus Unnebäck](https://github.com/LinusU), [wafuwafu13](https://github.com/wafuwafu13), [Matteo Collina](https://github.com/mcollina), and [Dmitry Semigradsky](https://github.com/Semigradsky). +# Installation +> `npm install --save @types/node` + +# Summary +This package contains type definitions for node (https://nodejs.org/). + +# Details +Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node. + +### Additional Details + * Last updated: Tue, 23 Jul 2024 18:09:25 GMT + * Dependencies: [undici-types](https://npmjs.com/package/undici-types) + +# Credits +These definitions were written by [Microsoft TypeScript](https://github.com/Microsoft), [Alberto Schiabel](https://github.com/jkomyno), [Alvis HT Tang](https://github.com/alvis), [Andrew Makarov](https://github.com/r3nya), [Benjamin Toueg](https://github.com/btoueg), [Chigozirim C.](https://github.com/smac89), [David Junger](https://github.com/touffy), [Deividas Bakanas](https://github.com/DeividasBakanas), [Eugene Y. Q. Shen](https://github.com/eyqs), [Hannes Magnusson](https://github.com/Hannes-Magnusson-CK), [Huw](https://github.com/hoo29), [Kelvin Jin](https://github.com/kjin), [Klaus Meinhardt](https://github.com/ajafff), [Lishude](https://github.com/islishude), [Mariusz Wiktorczyk](https://github.com/mwiktorczyk), [Mohsen Azimi](https://github.com/mohsen1), [Nikita Galkin](https://github.com/galkin), [Parambir Singh](https://github.com/parambirs), [Sebastian Silbermann](https://github.com/eps1lon), [Thomas den Hollander](https://github.com/ThomasdenH), [Wilco Bakker](https://github.com/WilcoBakker), [wwwy3y3](https://github.com/wwwy3y3), [Samuel Ainsworth](https://github.com/samuela), [Kyle Uehlein](https://github.com/kuehlein), [Thanik Bhongbhibhat](https://github.com/bhongy), [Marcin Kopacz](https://github.com/chyzwar), [Trivikram Kamat](https://github.com/trivikr), [Junxiao Shi](https://github.com/yoursunny), [Ilia Baryshnikov](https://github.com/qwelias), [ExE Boss](https://github.com/ExE-Boss), [Piotr Błażejewicz](https://github.com/peterblazejewicz), [Anna Henningsen](https://github.com/addaleax), [Victor Perin](https://github.com/victorperin), [Yongsheng Zhang](https://github.com/ZYSzys), [NodeJS Contributors](https://github.com/NodeJS), [Linus Unnebäck](https://github.com/LinusU), [wafuwafu13](https://github.com/wafuwafu13), [Matteo Collina](https://github.com/mcollina), and [Dmitry Semigradsky](https://github.com/Semigradsky). diff --git a/backend/node_modules/@types/validator/README.md b/backend/node_modules/@types/validator/README.md index d86ef04..5a9c5be 100644 --- a/backend/node_modules/@types/validator/README.md +++ b/backend/node_modules/@types/validator/README.md @@ -1,15 +1,15 @@ -# Installation -> `npm install --save @types/validator` - -# Summary -This package contains type definitions for validator (https://github.com/validatorjs/validator.js). - -# Details -Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/validator. - -### Additional Details - * Last updated: Sun, 16 Jun 2024 11:35:49 GMT - * Dependencies: none - -# Credits -These definitions were written by [tgfjt](https://github.com/tgfjt), [Ilya Mochalov](https://github.com/chrootsu), [Ayman Nedjmeddine](https://github.com/IOAyman), [Louay Alakkad](https://github.com/louy), [Bonggyun Lee](https://github.com/deptno), [Naoto Yokoyama](https://github.com/builtinnya), [Philipp Katz](https://github.com/qqilihq), [Jace Warren](https://github.com/keatz55), [Munif Tanjim](https://github.com/MunifTanjim), [Vlad Poluch](https://github.com/vlapo), [Piotr Błażejewicz](https://github.com/peterblazejewicz), [Matteo Nista](https://github.com/Mattewn99), [Roman Babiak](https://github.com/Almost-Infinity), and [Daniel Freire](https://github.com/dcfreire). +# Installation +> `npm install --save @types/validator` + +# Summary +This package contains type definitions for validator (https://github.com/validatorjs/validator.js). + +# Details +Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/validator. + +### Additional Details + * Last updated: Sun, 16 Jun 2024 11:35:49 GMT + * Dependencies: none + +# Credits +These definitions were written by [tgfjt](https://github.com/tgfjt), [Ilya Mochalov](https://github.com/chrootsu), [Ayman Nedjmeddine](https://github.com/IOAyman), [Louay Alakkad](https://github.com/louy), [Bonggyun Lee](https://github.com/deptno), [Naoto Yokoyama](https://github.com/builtinnya), [Philipp Katz](https://github.com/qqilihq), [Jace Warren](https://github.com/keatz55), [Munif Tanjim](https://github.com/MunifTanjim), [Vlad Poluch](https://github.com/vlapo), [Piotr Błażejewicz](https://github.com/peterblazejewicz), [Matteo Nista](https://github.com/Mattewn99), [Roman Babiak](https://github.com/Almost-Infinity), and [Daniel Freire](https://github.com/dcfreire). diff --git a/backend/node_modules/aws-ssl-profiles/package.json b/backend/node_modules/aws-ssl-profiles/package.json old mode 100644 new mode 100755 diff --git a/backend/node_modules/bcrypt/appveyor.yml b/backend/node_modules/bcrypt/appveyor.yml index 795d3f6..d9b4ebb 100644 --- a/backend/node_modules/bcrypt/appveyor.yml +++ b/backend/node_modules/bcrypt/appveyor.yml @@ -1,39 +1,39 @@ -environment: - matrix: - - nodejs_version: "14" - platform: x64 - - nodejs_version: "14" - platform: x86 - - nodejs_version: "16" - platform: x64 - - nodejs_version: "16" - platform: x86 - - nodejs_version: "18" - platform: x64 - -install: - - where npm - - where node - - ps: Install-Product node $env:nodejs_version $env:platform - -build: off - -artifacts: - - path: 'build/stage/**/bcrypt*.tar.gz' - -test_script: - - node --version - - npm --version - - npm test - -after_test: - - .\node_modules\.bin\node-pre-gyp package - -on_success: - - ps: > - if ($env:NODE_PRE_GYP_GITHUB_TOKEN -ne $null -and $env:APPVEYOR_REPO_TAG_NAME -match '^v(0|[1-9]+)\.(0|[1-9]+)\.(0|[1-9]+)(-\w)?$') { - echo "Publishing $env:APPVEYOR_REPO_TAG_NAME" - npm install node-pre-gyp-github@1.4.3 - ./node_modules/.bin/node-pre-gyp-github publish --release - } - +environment: + matrix: + - nodejs_version: "14" + platform: x64 + - nodejs_version: "14" + platform: x86 + - nodejs_version: "16" + platform: x64 + - nodejs_version: "16" + platform: x86 + - nodejs_version: "18" + platform: x64 + +install: + - where npm + - where node + - ps: Install-Product node $env:nodejs_version $env:platform + +build: off + +artifacts: + - path: 'build/stage/**/bcrypt*.tar.gz' + +test_script: + - node --version + - npm --version + - npm test + +after_test: + - .\node_modules\.bin\node-pre-gyp package + +on_success: + - ps: > + if ($env:NODE_PRE_GYP_GITHUB_TOKEN -ne $null -and $env:APPVEYOR_REPO_TAG_NAME -match '^v(0|[1-9]+)\.(0|[1-9]+)\.(0|[1-9]+)(-\w)?$') { + echo "Publishing $env:APPVEYOR_REPO_TAG_NAME" + npm install node-pre-gyp-github@1.4.3 + ./node_modules/.bin/node-pre-gyp-github publish --release + } + diff --git a/backend/node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node b/backend/node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node old mode 100644 new mode 100755 index ba87d282512b984efb464d9a7403b11747317040..74302aede4747b06495213ac7c96ddbc8535e58c GIT binary patch literal 102128 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

Bo%tW({voZD**0xr`r=# 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

4OeU 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 W7ShZ8^lrz$Y#i(>1781++Wucx6{ofU diff --git a/backend/node_modules/bcrypt/test-docker.sh b/backend/node_modules/bcrypt/test-docker.sh old mode 100644 new mode 100755 diff --git a/backend/node_modules/color-support/bin.js b/backend/node_modules/color-support/bin.js old mode 100644 new mode 100755 diff --git a/backend/node_modules/make-dir/node_modules/.bin/semver b/backend/node_modules/make-dir/node_modules/.bin/semver deleted file mode 100644 index 97c5327..0000000 --- a/backend/node_modules/make-dir/node_modules/.bin/semver +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") - -case `uname` in - *CYGWIN*|*MINGW*|*MSYS*) - if command -v cygpath > /dev/null 2>&1; then - basedir=`cygpath -w "$basedir"` - fi - ;; -esac - -if [ -x "$basedir/node" ]; then - exec "$basedir/node" "$basedir/../semver/bin/semver.js" "$@" -else - exec node "$basedir/../semver/bin/semver.js" "$@" -fi diff --git a/backend/node_modules/make-dir/node_modules/.bin/semver b/backend/node_modules/make-dir/node_modules/.bin/semver new file mode 120000 index 0000000..5aaadf4 --- /dev/null +++ b/backend/node_modules/make-dir/node_modules/.bin/semver @@ -0,0 +1 @@ +../semver/bin/semver.js \ No newline at end of file diff --git a/backend/node_modules/make-dir/node_modules/.bin/semver.cmd b/backend/node_modules/make-dir/node_modules/.bin/semver.cmd deleted file mode 100644 index 9913fa9..0000000 --- a/backend/node_modules/make-dir/node_modules/.bin/semver.cmd +++ /dev/null @@ -1,17 +0,0 @@ -@ECHO off -GOTO start -:find_dp0 -SET dp0=%~dp0 -EXIT /b -:start -SETLOCAL -CALL :find_dp0 - -IF EXIST "%dp0%\node.exe" ( - SET "_prog=%dp0%\node.exe" -) ELSE ( - SET "_prog=node" - SET PATHEXT=%PATHEXT:;.JS;=;% -) - -endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\semver\bin\semver.js" %* diff --git a/backend/node_modules/make-dir/node_modules/.bin/semver.ps1 b/backend/node_modules/make-dir/node_modules/.bin/semver.ps1 deleted file mode 100644 index 314717a..0000000 --- a/backend/node_modules/make-dir/node_modules/.bin/semver.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env pwsh -$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent - -$exe="" -if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { - # Fix case when both the Windows and Linux builds of Node - # are installed in the same directory - $exe=".exe" -} -$ret=0 -if (Test-Path "$basedir/node$exe") { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "$basedir/node$exe" "$basedir/../semver/bin/semver.js" $args - } else { - & "$basedir/node$exe" "$basedir/../semver/bin/semver.js" $args - } - $ret=$LASTEXITCODE -} else { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & "node$exe" "$basedir/../semver/bin/semver.js" $args - } else { - & "node$exe" "$basedir/../semver/bin/semver.js" $args - } - $ret=$LASTEXITCODE -} -exit $ret diff --git a/backend/node_modules/make-dir/node_modules/semver/bin/semver.js b/backend/node_modules/make-dir/node_modules/semver/bin/semver.js old mode 100644 new mode 100755 diff --git a/backend/node_modules/mime/cli.js b/backend/node_modules/mime/cli.js old mode 100644 new mode 100755 diff --git a/backend/node_modules/mime/src/build.js b/backend/node_modules/mime/src/build.js old mode 100644 new mode 100755 diff --git a/backend/node_modules/mkdirp/bin/cmd.js b/backend/node_modules/mkdirp/bin/cmd.js old mode 100644 new mode 100755 diff --git a/backend/node_modules/node-addon-api/tools/conversion.js b/backend/node_modules/node-addon-api/tools/conversion.js old mode 100644 new mode 100755 diff --git a/backend/node_modules/nodemon/bin/nodemon.js b/backend/node_modules/nodemon/bin/nodemon.js old mode 100644 new mode 100755 diff --git a/backend/node_modules/nopt/bin/nopt.js b/backend/node_modules/nopt/bin/nopt.js old mode 100644 new mode 100755 diff --git a/backend/node_modules/rimraf/bin.js b/backend/node_modules/rimraf/bin.js old mode 100644 new mode 100755 diff --git a/backend/node_modules/semver/bin/semver.js b/backend/node_modules/semver/bin/semver.js old mode 100644 new mode 100755 diff --git a/backend/node_modules/sequelize/lib/utils.js b/backend/node_modules/sequelize/lib/utils.js index 4cce60e..bee014e 100644 --- a/backend/node_modules/sequelize/lib/utils.js +++ b/backend/node_modules/sequelize/lib/utils.js @@ -272,17 +272,11 @@ exports.now = now; const TICK_CHAR = "`"; exports.TICK_CHAR = TICK_CHAR; function addTicks(s, tickChar) { - if (typeof s !== 'string') { - return s; - } tickChar = tickChar || TICK_CHAR; return tickChar + removeTicks(s, tickChar) + tickChar; } exports.addTicks = addTicks; function removeTicks(s, tickChar) { - if (typeof s !== 'string') { - return s; - } tickChar = tickChar || TICK_CHAR; return s.replace(new RegExp(tickChar, "g"), ""); } diff --git a/backend/node_modules/simple-update-notifier/build/index.js b/backend/node_modules/simple-update-notifier/build/index.js index 090f9df..d7c3cde 100644 --- a/backend/node_modules/simple-update-notifier/build/index.js +++ b/backend/node_modules/simple-update-notifier/build/index.js @@ -7,59 +7,59 @@ var path = require('path'); var fs = require('fs'); var https = require('https'); -/****************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */ -/* global Reflect, Promise */ - - -function __awaiter(thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -} - -function __generator(thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (g && (g = 0, op[0] && (_ = 0)), _) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ +/* global Reflect, Promise */ + + +function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +function __generator(thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } } var packageJson = process$1.env.npm_package_json; diff --git a/backend/node_modules/touch/bin/nodetouch.js b/backend/node_modules/touch/bin/nodetouch.js old mode 100644 new mode 100755 diff --git a/backend/node_modules/uuid/dist/bin/uuid b/backend/node_modules/uuid/dist/bin/uuid old mode 100644 new mode 100755 diff --git a/backend/node_modules/validator/es/lib/isCurrency.js b/backend/node_modules/validator/es/lib/isCurrency.js old mode 100644 new mode 100755 diff --git a/backend/node_modules/validator/es/lib/isVAT.js b/backend/node_modules/validator/es/lib/isVAT.js index 30a2f2d..df83ec7 100644 --- a/backend/node_modules/validator/es/lib/isVAT.js +++ b/backend/node_modules/validator/es/lib/isVAT.js @@ -46,8 +46,8 @@ var PT = function PT(str) { return checksum === parseInt(tin[8], 10); }; export var vatMatchers = { - /** - * European Union VAT identification numbers + /** + * European Union VAT identification numbers */ AT: function AT(str) { return /^(AT)?U\d{8}$/.test(str); @@ -128,8 +128,8 @@ export var vatMatchers = { SE: function SE(str) { return /^(SE)?\d{12}$/.test(str); }, - /** - * VAT numbers of non-EU countries + /** + * VAT numbers of non-EU countries */ AL: function AL(str) { return /^(AL)?\w{9}[A-Z]$/.test(str); @@ -196,8 +196,8 @@ export var vatMatchers = { UZ: function UZ(str) { return /^(UZ)?\d{9}$/.test(str); }, - /** - * VAT numbers of Latin American countries + /** + * VAT numbers of Latin American countries */ AR: function AR(str) { return /^(AR)?\d{11}$/.test(str); diff --git a/backend/node_modules/validator/lib/isCurrency.js b/backend/node_modules/validator/lib/isCurrency.js old mode 100644 new mode 100755 diff --git a/backend/node_modules/validator/lib/isVAT.js b/backend/node_modules/validator/lib/isVAT.js index f4e008c..8d475cb 100644 --- a/backend/node_modules/validator/lib/isVAT.js +++ b/backend/node_modules/validator/lib/isVAT.js @@ -57,8 +57,8 @@ var PT = function PT(str) { return checksum === parseInt(tin[8], 10); }; var vatMatchers = exports.vatMatchers = { - /** - * European Union VAT identification numbers + /** + * European Union VAT identification numbers */ AT: function AT(str) { return /^(AT)?U\d{8}$/.test(str); @@ -139,8 +139,8 @@ var vatMatchers = exports.vatMatchers = { SE: function SE(str) { return /^(SE)?\d{12}$/.test(str); }, - /** - * VAT numbers of non-EU countries + /** + * VAT numbers of non-EU countries */ AL: function AL(str) { return /^(AL)?\w{9}[A-Z]$/.test(str); @@ -207,8 +207,8 @@ var vatMatchers = exports.vatMatchers = { UZ: function UZ(str) { return /^(UZ)?\d{9}$/.test(str); }, - /** - * VAT numbers of Latin American countries + /** + * VAT numbers of Latin American countries */ AR: function AR(str) { return /^(AR)?\d{11}$/.test(str); diff --git a/backend/node_modules/validator/validator.js b/backend/node_modules/validator/validator.js index b01f91f..8b00bd3 100644 --- a/backend/node_modules/validator/validator.js +++ b/backend/node_modules/validator/validator.js @@ -5228,8 +5228,8 @@ var PT = function PT(str) { return checksum === parseInt(tin[8], 10); }; var vatMatchers = { - /** - * European Union VAT identification numbers + /** + * European Union VAT identification numbers */ AT: function AT(str) { return /^(AT)?U\d{8}$/.test(str); @@ -5310,8 +5310,8 @@ var vatMatchers = { SE: function SE(str) { return /^(SE)?\d{12}$/.test(str); }, - /** - * VAT numbers of non-EU countries + /** + * VAT numbers of non-EU countries */ AL: function AL(str) { return /^(AL)?\w{9}[A-Z]$/.test(str); @@ -5378,8 +5378,8 @@ var vatMatchers = { UZ: function UZ(str) { return /^(UZ)?\d{9}$/.test(str); }, - /** - * VAT numbers of Latin American countries + /** + * VAT numbers of Latin American countries */ AR: function AR(str) { return /^(AR)?\d{11}$/.test(str); diff --git a/backend/node_modules/whatwg-url/lib/url-state-machine.js b/backend/node_modules/whatwg-url/lib/url-state-machine.js index 27d977a..c25dbc2 100644 --- a/backend/node_modules/whatwg-url/lib/url-state-machine.js +++ b/backend/node_modules/whatwg-url/lib/url-state-machine.js @@ -1,1297 +1,1297 @@ -"use strict"; -const punycode = require("punycode"); -const tr46 = require("tr46"); - -const specialSchemes = { - ftp: 21, - file: null, - gopher: 70, - http: 80, - https: 443, - ws: 80, - wss: 443 -}; - -const failure = Symbol("failure"); - -function countSymbols(str) { - return punycode.ucs2.decode(str).length; -} - -function at(input, idx) { - const c = input[idx]; - return isNaN(c) ? undefined : String.fromCodePoint(c); -} - -function isASCIIDigit(c) { - return c >= 0x30 && c <= 0x39; -} - -function isASCIIAlpha(c) { - return (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A); -} - -function isASCIIAlphanumeric(c) { - return isASCIIAlpha(c) || isASCIIDigit(c); -} - -function isASCIIHex(c) { - return isASCIIDigit(c) || (c >= 0x41 && c <= 0x46) || (c >= 0x61 && c <= 0x66); -} - -function isSingleDot(buffer) { - return buffer === "." || buffer.toLowerCase() === "%2e"; -} - -function isDoubleDot(buffer) { - buffer = buffer.toLowerCase(); - return buffer === ".." || buffer === "%2e." || buffer === ".%2e" || buffer === "%2e%2e"; -} - -function isWindowsDriveLetterCodePoints(cp1, cp2) { - return isASCIIAlpha(cp1) && (cp2 === 58 || cp2 === 124); -} - -function isWindowsDriveLetterString(string) { - return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && (string[1] === ":" || string[1] === "|"); -} - -function isNormalizedWindowsDriveLetterString(string) { - return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && string[1] === ":"; -} - -function containsForbiddenHostCodePoint(string) { - return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|%|\/|:|\?|@|\[|\\|\]/) !== -1; -} - -function containsForbiddenHostCodePointExcludingPercent(string) { - return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|\/|:|\?|@|\[|\\|\]/) !== -1; -} - -function isSpecialScheme(scheme) { - return specialSchemes[scheme] !== undefined; -} - -function isSpecial(url) { - return isSpecialScheme(url.scheme); -} - -function defaultPort(scheme) { - return specialSchemes[scheme]; -} - -function percentEncode(c) { - let hex = c.toString(16).toUpperCase(); - if (hex.length === 1) { - hex = "0" + hex; - } - - return "%" + hex; -} - -function utf8PercentEncode(c) { - const buf = new Buffer(c); - - let str = ""; - - for (let i = 0; i < buf.length; ++i) { - str += percentEncode(buf[i]); - } - - return str; -} - -function utf8PercentDecode(str) { - const input = new Buffer(str); - const output = []; - for (let i = 0; i < input.length; ++i) { - if (input[i] !== 37) { - output.push(input[i]); - } else if (input[i] === 37 && isASCIIHex(input[i + 1]) && isASCIIHex(input[i + 2])) { - output.push(parseInt(input.slice(i + 1, i + 3).toString(), 16)); - i += 2; - } else { - output.push(input[i]); - } - } - return new Buffer(output).toString(); -} - -function isC0ControlPercentEncode(c) { - return c <= 0x1F || c > 0x7E; -} - -const extraPathPercentEncodeSet = new Set([32, 34, 35, 60, 62, 63, 96, 123, 125]); -function isPathPercentEncode(c) { - return isC0ControlPercentEncode(c) || extraPathPercentEncodeSet.has(c); -} - -const extraUserinfoPercentEncodeSet = - new Set([47, 58, 59, 61, 64, 91, 92, 93, 94, 124]); -function isUserinfoPercentEncode(c) { - return isPathPercentEncode(c) || extraUserinfoPercentEncodeSet.has(c); -} - -function percentEncodeChar(c, encodeSetPredicate) { - const cStr = String.fromCodePoint(c); - - if (encodeSetPredicate(c)) { - return utf8PercentEncode(cStr); - } - - return cStr; -} - -function parseIPv4Number(input) { - let R = 10; - - if (input.length >= 2 && input.charAt(0) === "0" && input.charAt(1).toLowerCase() === "x") { - input = input.substring(2); - R = 16; - } else if (input.length >= 2 && input.charAt(0) === "0") { - input = input.substring(1); - R = 8; - } - - if (input === "") { - return 0; - } - - const regex = R === 10 ? /[^0-9]/ : (R === 16 ? /[^0-9A-Fa-f]/ : /[^0-7]/); - if (regex.test(input)) { - return failure; - } - - return parseInt(input, R); -} - -function parseIPv4(input) { - const parts = input.split("."); - if (parts[parts.length - 1] === "") { - if (parts.length > 1) { - parts.pop(); - } - } - - if (parts.length > 4) { - return input; - } - - const numbers = []; - for (const part of parts) { - if (part === "") { - return input; - } - const n = parseIPv4Number(part); - if (n === failure) { - return input; - } - - numbers.push(n); - } - - for (let i = 0; i < numbers.length - 1; ++i) { - if (numbers[i] > 255) { - return failure; - } - } - if (numbers[numbers.length - 1] >= Math.pow(256, 5 - numbers.length)) { - return failure; - } - - let ipv4 = numbers.pop(); - let counter = 0; - - for (const n of numbers) { - ipv4 += n * Math.pow(256, 3 - counter); - ++counter; - } - - return ipv4; -} - -function serializeIPv4(address) { - let output = ""; - let n = address; - - for (let i = 1; i <= 4; ++i) { - output = String(n % 256) + output; - if (i !== 4) { - output = "." + output; - } - n = Math.floor(n / 256); - } - - return output; -} - -function parseIPv6(input) { - const address = [0, 0, 0, 0, 0, 0, 0, 0]; - let pieceIndex = 0; - let compress = null; - let pointer = 0; - - input = punycode.ucs2.decode(input); - - if (input[pointer] === 58) { - if (input[pointer + 1] !== 58) { - return failure; - } - - pointer += 2; - ++pieceIndex; - compress = pieceIndex; - } - - while (pointer < input.length) { - if (pieceIndex === 8) { - return failure; - } - - if (input[pointer] === 58) { - if (compress !== null) { - return failure; - } - ++pointer; - ++pieceIndex; - compress = pieceIndex; - continue; - } - - let value = 0; - let length = 0; - - while (length < 4 && isASCIIHex(input[pointer])) { - value = value * 0x10 + parseInt(at(input, pointer), 16); - ++pointer; - ++length; - } - - if (input[pointer] === 46) { - if (length === 0) { - return failure; - } - - pointer -= length; - - if (pieceIndex > 6) { - return failure; - } - - let numbersSeen = 0; - - while (input[pointer] !== undefined) { - let ipv4Piece = null; - - if (numbersSeen > 0) { - if (input[pointer] === 46 && numbersSeen < 4) { - ++pointer; - } else { - return failure; - } - } - - if (!isASCIIDigit(input[pointer])) { - return failure; - } - - while (isASCIIDigit(input[pointer])) { - const number = parseInt(at(input, pointer)); - if (ipv4Piece === null) { - ipv4Piece = number; - } else if (ipv4Piece === 0) { - return failure; - } else { - ipv4Piece = ipv4Piece * 10 + number; - } - if (ipv4Piece > 255) { - return failure; - } - ++pointer; - } - - address[pieceIndex] = address[pieceIndex] * 0x100 + ipv4Piece; - - ++numbersSeen; - - if (numbersSeen === 2 || numbersSeen === 4) { - ++pieceIndex; - } - } - - if (numbersSeen !== 4) { - return failure; - } - - break; - } else if (input[pointer] === 58) { - ++pointer; - if (input[pointer] === undefined) { - return failure; - } - } else if (input[pointer] !== undefined) { - return failure; - } - - address[pieceIndex] = value; - ++pieceIndex; - } - - if (compress !== null) { - let swaps = pieceIndex - compress; - pieceIndex = 7; - while (pieceIndex !== 0 && swaps > 0) { - const temp = address[compress + swaps - 1]; - address[compress + swaps - 1] = address[pieceIndex]; - address[pieceIndex] = temp; - --pieceIndex; - --swaps; - } - } else if (compress === null && pieceIndex !== 8) { - return failure; - } - - return address; -} - -function serializeIPv6(address) { - let output = ""; - const seqResult = findLongestZeroSequence(address); - const compress = seqResult.idx; - let ignore0 = false; - - for (let pieceIndex = 0; pieceIndex <= 7; ++pieceIndex) { - if (ignore0 && address[pieceIndex] === 0) { - continue; - } else if (ignore0) { - ignore0 = false; - } - - if (compress === pieceIndex) { - const separator = pieceIndex === 0 ? "::" : ":"; - output += separator; - ignore0 = true; - continue; - } - - output += address[pieceIndex].toString(16); - - if (pieceIndex !== 7) { - output += ":"; - } - } - - return output; -} - -function parseHost(input, isSpecialArg) { - if (input[0] === "[") { - if (input[input.length - 1] !== "]") { - return failure; - } - - return parseIPv6(input.substring(1, input.length - 1)); - } - - if (!isSpecialArg) { - return parseOpaqueHost(input); - } - - const domain = utf8PercentDecode(input); - const asciiDomain = tr46.toASCII(domain, false, tr46.PROCESSING_OPTIONS.NONTRANSITIONAL, false); - if (asciiDomain === null) { - return failure; - } - - if (containsForbiddenHostCodePoint(asciiDomain)) { - return failure; - } - - const ipv4Host = parseIPv4(asciiDomain); - if (typeof ipv4Host === "number" || ipv4Host === failure) { - return ipv4Host; - } - - return asciiDomain; -} - -function parseOpaqueHost(input) { - if (containsForbiddenHostCodePointExcludingPercent(input)) { - return failure; - } - - let output = ""; - const decoded = punycode.ucs2.decode(input); - for (let i = 0; i < decoded.length; ++i) { - output += percentEncodeChar(decoded[i], isC0ControlPercentEncode); - } - return output; -} - -function findLongestZeroSequence(arr) { - let maxIdx = null; - let maxLen = 1; // only find elements > 1 - let currStart = null; - let currLen = 0; - - for (let i = 0; i < arr.length; ++i) { - if (arr[i] !== 0) { - if (currLen > maxLen) { - maxIdx = currStart; - maxLen = currLen; - } - - currStart = null; - currLen = 0; - } else { - if (currStart === null) { - currStart = i; - } - ++currLen; - } - } - - // if trailing zeros - if (currLen > maxLen) { - maxIdx = currStart; - maxLen = currLen; - } - - return { - idx: maxIdx, - len: maxLen - }; -} - -function serializeHost(host) { - if (typeof host === "number") { - return serializeIPv4(host); - } - - // IPv6 serializer - if (host instanceof Array) { - return "[" + serializeIPv6(host) + "]"; - } - - return host; -} - -function trimControlChars(url) { - return url.replace(/^[\u0000-\u001F\u0020]+|[\u0000-\u001F\u0020]+$/g, ""); -} - -function trimTabAndNewline(url) { - return url.replace(/\u0009|\u000A|\u000D/g, ""); -} - -function shortenPath(url) { - const path = url.path; - if (path.length === 0) { - return; - } - if (url.scheme === "file" && path.length === 1 && isNormalizedWindowsDriveLetter(path[0])) { - return; - } - - path.pop(); -} - -function includesCredentials(url) { - return url.username !== "" || url.password !== ""; -} - -function cannotHaveAUsernamePasswordPort(url) { - return url.host === null || url.host === "" || url.cannotBeABaseURL || url.scheme === "file"; -} - -function isNormalizedWindowsDriveLetter(string) { - return /^[A-Za-z]:$/.test(string); -} - -function URLStateMachine(input, base, encodingOverride, url, stateOverride) { - this.pointer = 0; - this.input = input; - this.base = base || null; - this.encodingOverride = encodingOverride || "utf-8"; - this.stateOverride = stateOverride; - this.url = url; - this.failure = false; - this.parseError = false; - - if (!this.url) { - this.url = { - scheme: "", - username: "", - password: "", - host: null, - port: null, - path: [], - query: null, - fragment: null, - - cannotBeABaseURL: false - }; - - const res = trimControlChars(this.input); - if (res !== this.input) { - this.parseError = true; - } - this.input = res; - } - - const res = trimTabAndNewline(this.input); - if (res !== this.input) { - this.parseError = true; - } - this.input = res; - - this.state = stateOverride || "scheme start"; - - this.buffer = ""; - this.atFlag = false; - this.arrFlag = false; - this.passwordTokenSeenFlag = false; - - this.input = punycode.ucs2.decode(this.input); - - for (; this.pointer <= this.input.length; ++this.pointer) { - const c = this.input[this.pointer]; - const cStr = isNaN(c) ? undefined : String.fromCodePoint(c); - - // exec state machine - const ret = this["parse " + this.state](c, cStr); - if (!ret) { - break; // terminate algorithm - } else if (ret === failure) { - this.failure = true; - break; - } - } -} - -URLStateMachine.prototype["parse scheme start"] = function parseSchemeStart(c, cStr) { - if (isASCIIAlpha(c)) { - this.buffer += cStr.toLowerCase(); - this.state = "scheme"; - } else if (!this.stateOverride) { - this.state = "no scheme"; - --this.pointer; - } else { - this.parseError = true; - return failure; - } - - return true; -}; - -URLStateMachine.prototype["parse scheme"] = function parseScheme(c, cStr) { - if (isASCIIAlphanumeric(c) || c === 43 || c === 45 || c === 46) { - this.buffer += cStr.toLowerCase(); - } else if (c === 58) { - if (this.stateOverride) { - if (isSpecial(this.url) && !isSpecialScheme(this.buffer)) { - return false; - } - - if (!isSpecial(this.url) && isSpecialScheme(this.buffer)) { - return false; - } - - if ((includesCredentials(this.url) || this.url.port !== null) && this.buffer === "file") { - return false; - } - - if (this.url.scheme === "file" && (this.url.host === "" || this.url.host === null)) { - return false; - } - } - this.url.scheme = this.buffer; - this.buffer = ""; - if (this.stateOverride) { - return false; - } - if (this.url.scheme === "file") { - if (this.input[this.pointer + 1] !== 47 || this.input[this.pointer + 2] !== 47) { - this.parseError = true; - } - this.state = "file"; - } else if (isSpecial(this.url) && this.base !== null && this.base.scheme === this.url.scheme) { - this.state = "special relative or authority"; - } else if (isSpecial(this.url)) { - this.state = "special authority slashes"; - } else if (this.input[this.pointer + 1] === 47) { - this.state = "path or authority"; - ++this.pointer; - } else { - this.url.cannotBeABaseURL = true; - this.url.path.push(""); - this.state = "cannot-be-a-base-URL path"; - } - } else if (!this.stateOverride) { - this.buffer = ""; - this.state = "no scheme"; - this.pointer = -1; - } else { - this.parseError = true; - return failure; - } - - return true; -}; - -URLStateMachine.prototype["parse no scheme"] = function parseNoScheme(c) { - if (this.base === null || (this.base.cannotBeABaseURL && c !== 35)) { - return failure; - } else if (this.base.cannotBeABaseURL && c === 35) { - this.url.scheme = this.base.scheme; - this.url.path = this.base.path.slice(); - this.url.query = this.base.query; - this.url.fragment = ""; - this.url.cannotBeABaseURL = true; - this.state = "fragment"; - } else if (this.base.scheme === "file") { - this.state = "file"; - --this.pointer; - } else { - this.state = "relative"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse special relative or authority"] = function parseSpecialRelativeOrAuthority(c) { - if (c === 47 && this.input[this.pointer + 1] === 47) { - this.state = "special authority ignore slashes"; - ++this.pointer; - } else { - this.parseError = true; - this.state = "relative"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse path or authority"] = function parsePathOrAuthority(c) { - if (c === 47) { - this.state = "authority"; - } else { - this.state = "path"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse relative"] = function parseRelative(c) { - this.url.scheme = this.base.scheme; - if (isNaN(c)) { - this.url.username = this.base.username; - this.url.password = this.base.password; - this.url.host = this.base.host; - this.url.port = this.base.port; - this.url.path = this.base.path.slice(); - this.url.query = this.base.query; - } else if (c === 47) { - this.state = "relative slash"; - } else if (c === 63) { - this.url.username = this.base.username; - this.url.password = this.base.password; - this.url.host = this.base.host; - this.url.port = this.base.port; - this.url.path = this.base.path.slice(); - this.url.query = ""; - this.state = "query"; - } else if (c === 35) { - this.url.username = this.base.username; - this.url.password = this.base.password; - this.url.host = this.base.host; - this.url.port = this.base.port; - this.url.path = this.base.path.slice(); - this.url.query = this.base.query; - this.url.fragment = ""; - this.state = "fragment"; - } else if (isSpecial(this.url) && c === 92) { - this.parseError = true; - this.state = "relative slash"; - } else { - this.url.username = this.base.username; - this.url.password = this.base.password; - this.url.host = this.base.host; - this.url.port = this.base.port; - this.url.path = this.base.path.slice(0, this.base.path.length - 1); - - this.state = "path"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse relative slash"] = function parseRelativeSlash(c) { - if (isSpecial(this.url) && (c === 47 || c === 92)) { - if (c === 92) { - this.parseError = true; - } - this.state = "special authority ignore slashes"; - } else if (c === 47) { - this.state = "authority"; - } else { - this.url.username = this.base.username; - this.url.password = this.base.password; - this.url.host = this.base.host; - this.url.port = this.base.port; - this.state = "path"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse special authority slashes"] = function parseSpecialAuthoritySlashes(c) { - if (c === 47 && this.input[this.pointer + 1] === 47) { - this.state = "special authority ignore slashes"; - ++this.pointer; - } else { - this.parseError = true; - this.state = "special authority ignore slashes"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse special authority ignore slashes"] = function parseSpecialAuthorityIgnoreSlashes(c) { - if (c !== 47 && c !== 92) { - this.state = "authority"; - --this.pointer; - } else { - this.parseError = true; - } - - return true; -}; - -URLStateMachine.prototype["parse authority"] = function parseAuthority(c, cStr) { - if (c === 64) { - this.parseError = true; - if (this.atFlag) { - this.buffer = "%40" + this.buffer; - } - this.atFlag = true; - - // careful, this is based on buffer and has its own pointer (this.pointer != pointer) and inner chars - const len = countSymbols(this.buffer); - for (let pointer = 0; pointer < len; ++pointer) { - const codePoint = this.buffer.codePointAt(pointer); - - if (codePoint === 58 && !this.passwordTokenSeenFlag) { - this.passwordTokenSeenFlag = true; - continue; - } - const encodedCodePoints = percentEncodeChar(codePoint, isUserinfoPercentEncode); - if (this.passwordTokenSeenFlag) { - this.url.password += encodedCodePoints; - } else { - this.url.username += encodedCodePoints; - } - } - this.buffer = ""; - } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || - (isSpecial(this.url) && c === 92)) { - if (this.atFlag && this.buffer === "") { - this.parseError = true; - return failure; - } - this.pointer -= countSymbols(this.buffer) + 1; - this.buffer = ""; - this.state = "host"; - } else { - this.buffer += cStr; - } - - return true; -}; - -URLStateMachine.prototype["parse hostname"] = -URLStateMachine.prototype["parse host"] = function parseHostName(c, cStr) { - if (this.stateOverride && this.url.scheme === "file") { - --this.pointer; - this.state = "file host"; - } else if (c === 58 && !this.arrFlag) { - if (this.buffer === "") { - this.parseError = true; - return failure; - } - - const host = parseHost(this.buffer, isSpecial(this.url)); - if (host === failure) { - return failure; - } - - this.url.host = host; - this.buffer = ""; - this.state = "port"; - if (this.stateOverride === "hostname") { - return false; - } - } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || - (isSpecial(this.url) && c === 92)) { - --this.pointer; - if (isSpecial(this.url) && this.buffer === "") { - this.parseError = true; - return failure; - } else if (this.stateOverride && this.buffer === "" && - (includesCredentials(this.url) || this.url.port !== null)) { - this.parseError = true; - return false; - } - - const host = parseHost(this.buffer, isSpecial(this.url)); - if (host === failure) { - return failure; - } - - this.url.host = host; - this.buffer = ""; - this.state = "path start"; - if (this.stateOverride) { - return false; - } - } else { - if (c === 91) { - this.arrFlag = true; - } else if (c === 93) { - this.arrFlag = false; - } - this.buffer += cStr; - } - - return true; -}; - -URLStateMachine.prototype["parse port"] = function parsePort(c, cStr) { - if (isASCIIDigit(c)) { - this.buffer += cStr; - } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || - (isSpecial(this.url) && c === 92) || - this.stateOverride) { - if (this.buffer !== "") { - const port = parseInt(this.buffer); - if (port > Math.pow(2, 16) - 1) { - this.parseError = true; - return failure; - } - this.url.port = port === defaultPort(this.url.scheme) ? null : port; - this.buffer = ""; - } - if (this.stateOverride) { - return false; - } - this.state = "path start"; - --this.pointer; - } else { - this.parseError = true; - return failure; - } - - return true; -}; - -const fileOtherwiseCodePoints = new Set([47, 92, 63, 35]); - -URLStateMachine.prototype["parse file"] = function parseFile(c) { - this.url.scheme = "file"; - - if (c === 47 || c === 92) { - if (c === 92) { - this.parseError = true; - } - this.state = "file slash"; - } else if (this.base !== null && this.base.scheme === "file") { - if (isNaN(c)) { - this.url.host = this.base.host; - this.url.path = this.base.path.slice(); - this.url.query = this.base.query; - } else if (c === 63) { - this.url.host = this.base.host; - this.url.path = this.base.path.slice(); - this.url.query = ""; - this.state = "query"; - } else if (c === 35) { - this.url.host = this.base.host; - this.url.path = this.base.path.slice(); - this.url.query = this.base.query; - this.url.fragment = ""; - this.state = "fragment"; - } else { - if (this.input.length - this.pointer - 1 === 0 || // remaining consists of 0 code points - !isWindowsDriveLetterCodePoints(c, this.input[this.pointer + 1]) || - (this.input.length - this.pointer - 1 >= 2 && // remaining has at least 2 code points - !fileOtherwiseCodePoints.has(this.input[this.pointer + 2]))) { - this.url.host = this.base.host; - this.url.path = this.base.path.slice(); - shortenPath(this.url); - } else { - this.parseError = true; - } - - this.state = "path"; - --this.pointer; - } - } else { - this.state = "path"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse file slash"] = function parseFileSlash(c) { - if (c === 47 || c === 92) { - if (c === 92) { - this.parseError = true; - } - this.state = "file host"; - } else { - if (this.base !== null && this.base.scheme === "file") { - if (isNormalizedWindowsDriveLetterString(this.base.path[0])) { - this.url.path.push(this.base.path[0]); - } else { - this.url.host = this.base.host; - } - } - this.state = "path"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse file host"] = function parseFileHost(c, cStr) { - if (isNaN(c) || c === 47 || c === 92 || c === 63 || c === 35) { - --this.pointer; - if (!this.stateOverride && isWindowsDriveLetterString(this.buffer)) { - this.parseError = true; - this.state = "path"; - } else if (this.buffer === "") { - this.url.host = ""; - if (this.stateOverride) { - return false; - } - this.state = "path start"; - } else { - let host = parseHost(this.buffer, isSpecial(this.url)); - if (host === failure) { - return failure; - } - if (host === "localhost") { - host = ""; - } - this.url.host = host; - - if (this.stateOverride) { - return false; - } - - this.buffer = ""; - this.state = "path start"; - } - } else { - this.buffer += cStr; - } - - return true; -}; - -URLStateMachine.prototype["parse path start"] = function parsePathStart(c) { - if (isSpecial(this.url)) { - if (c === 92) { - this.parseError = true; - } - this.state = "path"; - - if (c !== 47 && c !== 92) { - --this.pointer; - } - } else if (!this.stateOverride && c === 63) { - this.url.query = ""; - this.state = "query"; - } else if (!this.stateOverride && c === 35) { - this.url.fragment = ""; - this.state = "fragment"; - } else if (c !== undefined) { - this.state = "path"; - if (c !== 47) { - --this.pointer; - } - } - - return true; -}; - -URLStateMachine.prototype["parse path"] = function parsePath(c) { - if (isNaN(c) || c === 47 || (isSpecial(this.url) && c === 92) || - (!this.stateOverride && (c === 63 || c === 35))) { - if (isSpecial(this.url) && c === 92) { - this.parseError = true; - } - - if (isDoubleDot(this.buffer)) { - shortenPath(this.url); - if (c !== 47 && !(isSpecial(this.url) && c === 92)) { - this.url.path.push(""); - } - } else if (isSingleDot(this.buffer) && c !== 47 && - !(isSpecial(this.url) && c === 92)) { - this.url.path.push(""); - } else if (!isSingleDot(this.buffer)) { - if (this.url.scheme === "file" && this.url.path.length === 0 && isWindowsDriveLetterString(this.buffer)) { - if (this.url.host !== "" && this.url.host !== null) { - this.parseError = true; - this.url.host = ""; - } - this.buffer = this.buffer[0] + ":"; - } - this.url.path.push(this.buffer); - } - this.buffer = ""; - if (this.url.scheme === "file" && (c === undefined || c === 63 || c === 35)) { - while (this.url.path.length > 1 && this.url.path[0] === "") { - this.parseError = true; - this.url.path.shift(); - } - } - if (c === 63) { - this.url.query = ""; - this.state = "query"; - } - if (c === 35) { - this.url.fragment = ""; - this.state = "fragment"; - } - } else { - // TODO: If c is not a URL code point and not "%", parse error. - - if (c === 37 && - (!isASCIIHex(this.input[this.pointer + 1]) || - !isASCIIHex(this.input[this.pointer + 2]))) { - this.parseError = true; - } - - this.buffer += percentEncodeChar(c, isPathPercentEncode); - } - - return true; -}; - -URLStateMachine.prototype["parse cannot-be-a-base-URL path"] = function parseCannotBeABaseURLPath(c) { - if (c === 63) { - this.url.query = ""; - this.state = "query"; - } else if (c === 35) { - this.url.fragment = ""; - this.state = "fragment"; - } else { - // TODO: Add: not a URL code point - if (!isNaN(c) && c !== 37) { - this.parseError = true; - } - - if (c === 37 && - (!isASCIIHex(this.input[this.pointer + 1]) || - !isASCIIHex(this.input[this.pointer + 2]))) { - this.parseError = true; - } - - if (!isNaN(c)) { - this.url.path[0] = this.url.path[0] + percentEncodeChar(c, isC0ControlPercentEncode); - } - } - - return true; -}; - -URLStateMachine.prototype["parse query"] = function parseQuery(c, cStr) { - if (isNaN(c) || (!this.stateOverride && c === 35)) { - if (!isSpecial(this.url) || this.url.scheme === "ws" || this.url.scheme === "wss") { - this.encodingOverride = "utf-8"; - } - - const buffer = new Buffer(this.buffer); // TODO: Use encoding override instead - for (let i = 0; i < buffer.length; ++i) { - if (buffer[i] < 0x21 || buffer[i] > 0x7E || buffer[i] === 0x22 || buffer[i] === 0x23 || - buffer[i] === 0x3C || buffer[i] === 0x3E) { - this.url.query += percentEncode(buffer[i]); - } else { - this.url.query += String.fromCodePoint(buffer[i]); - } - } - - this.buffer = ""; - if (c === 35) { - this.url.fragment = ""; - this.state = "fragment"; - } - } else { - // TODO: If c is not a URL code point and not "%", parse error. - if (c === 37 && - (!isASCIIHex(this.input[this.pointer + 1]) || - !isASCIIHex(this.input[this.pointer + 2]))) { - this.parseError = true; - } - - this.buffer += cStr; - } - - return true; -}; - -URLStateMachine.prototype["parse fragment"] = function parseFragment(c) { - if (isNaN(c)) { // do nothing - } else if (c === 0x0) { - this.parseError = true; - } else { - // TODO: If c is not a URL code point and not "%", parse error. - if (c === 37 && - (!isASCIIHex(this.input[this.pointer + 1]) || - !isASCIIHex(this.input[this.pointer + 2]))) { - this.parseError = true; - } - - this.url.fragment += percentEncodeChar(c, isC0ControlPercentEncode); - } - - return true; -}; - -function serializeURL(url, excludeFragment) { - let output = url.scheme + ":"; - if (url.host !== null) { - output += "//"; - - if (url.username !== "" || url.password !== "") { - output += url.username; - if (url.password !== "") { - output += ":" + url.password; - } - output += "@"; - } - - output += serializeHost(url.host); - - if (url.port !== null) { - output += ":" + url.port; - } - } else if (url.host === null && url.scheme === "file") { - output += "//"; - } - - if (url.cannotBeABaseURL) { - output += url.path[0]; - } else { - for (const string of url.path) { - output += "/" + string; - } - } - - if (url.query !== null) { - output += "?" + url.query; - } - - if (!excludeFragment && url.fragment !== null) { - output += "#" + url.fragment; - } - - return output; -} - -function serializeOrigin(tuple) { - let result = tuple.scheme + "://"; - result += serializeHost(tuple.host); - - if (tuple.port !== null) { - result += ":" + tuple.port; - } - - return result; -} - -module.exports.serializeURL = serializeURL; - -module.exports.serializeURLOrigin = function (url) { - // https://url.spec.whatwg.org/#concept-url-origin - switch (url.scheme) { - case "blob": - try { - return module.exports.serializeURLOrigin(module.exports.parseURL(url.path[0])); - } catch (e) { - // serializing an opaque origin returns "null" - return "null"; - } - case "ftp": - case "gopher": - case "http": - case "https": - case "ws": - case "wss": - return serializeOrigin({ - scheme: url.scheme, - host: url.host, - port: url.port - }); - case "file": - // spec says "exercise to the reader", chrome says "file://" - return "file://"; - default: - // serializing an opaque origin returns "null" - return "null"; - } -}; - -module.exports.basicURLParse = function (input, options) { - if (options === undefined) { - options = {}; - } - - const usm = new URLStateMachine(input, options.baseURL, options.encodingOverride, options.url, options.stateOverride); - if (usm.failure) { - return "failure"; - } - - return usm.url; -}; - -module.exports.setTheUsername = function (url, username) { - url.username = ""; - const decoded = punycode.ucs2.decode(username); - for (let i = 0; i < decoded.length; ++i) { - url.username += percentEncodeChar(decoded[i], isUserinfoPercentEncode); - } -}; - -module.exports.setThePassword = function (url, password) { - url.password = ""; - const decoded = punycode.ucs2.decode(password); - for (let i = 0; i < decoded.length; ++i) { - url.password += percentEncodeChar(decoded[i], isUserinfoPercentEncode); - } -}; - -module.exports.serializeHost = serializeHost; - -module.exports.cannotHaveAUsernamePasswordPort = cannotHaveAUsernamePasswordPort; - -module.exports.serializeInteger = function (integer) { - return String(integer); -}; - -module.exports.parseURL = function (input, options) { - if (options === undefined) { - options = {}; - } - - // We don't handle blobs, so this just delegates: - return module.exports.basicURLParse(input, { baseURL: options.baseURL, encodingOverride: options.encodingOverride }); -}; +"use strict"; +const punycode = require("punycode"); +const tr46 = require("tr46"); + +const specialSchemes = { + ftp: 21, + file: null, + gopher: 70, + http: 80, + https: 443, + ws: 80, + wss: 443 +}; + +const failure = Symbol("failure"); + +function countSymbols(str) { + return punycode.ucs2.decode(str).length; +} + +function at(input, idx) { + const c = input[idx]; + return isNaN(c) ? undefined : String.fromCodePoint(c); +} + +function isASCIIDigit(c) { + return c >= 0x30 && c <= 0x39; +} + +function isASCIIAlpha(c) { + return (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A); +} + +function isASCIIAlphanumeric(c) { + return isASCIIAlpha(c) || isASCIIDigit(c); +} + +function isASCIIHex(c) { + return isASCIIDigit(c) || (c >= 0x41 && c <= 0x46) || (c >= 0x61 && c <= 0x66); +} + +function isSingleDot(buffer) { + return buffer === "." || buffer.toLowerCase() === "%2e"; +} + +function isDoubleDot(buffer) { + buffer = buffer.toLowerCase(); + return buffer === ".." || buffer === "%2e." || buffer === ".%2e" || buffer === "%2e%2e"; +} + +function isWindowsDriveLetterCodePoints(cp1, cp2) { + return isASCIIAlpha(cp1) && (cp2 === 58 || cp2 === 124); +} + +function isWindowsDriveLetterString(string) { + return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && (string[1] === ":" || string[1] === "|"); +} + +function isNormalizedWindowsDriveLetterString(string) { + return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && string[1] === ":"; +} + +function containsForbiddenHostCodePoint(string) { + return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|%|\/|:|\?|@|\[|\\|\]/) !== -1; +} + +function containsForbiddenHostCodePointExcludingPercent(string) { + return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|\/|:|\?|@|\[|\\|\]/) !== -1; +} + +function isSpecialScheme(scheme) { + return specialSchemes[scheme] !== undefined; +} + +function isSpecial(url) { + return isSpecialScheme(url.scheme); +} + +function defaultPort(scheme) { + return specialSchemes[scheme]; +} + +function percentEncode(c) { + let hex = c.toString(16).toUpperCase(); + if (hex.length === 1) { + hex = "0" + hex; + } + + return "%" + hex; +} + +function utf8PercentEncode(c) { + const buf = new Buffer(c); + + let str = ""; + + for (let i = 0; i < buf.length; ++i) { + str += percentEncode(buf[i]); + } + + return str; +} + +function utf8PercentDecode(str) { + const input = new Buffer(str); + const output = []; + for (let i = 0; i < input.length; ++i) { + if (input[i] !== 37) { + output.push(input[i]); + } else if (input[i] === 37 && isASCIIHex(input[i + 1]) && isASCIIHex(input[i + 2])) { + output.push(parseInt(input.slice(i + 1, i + 3).toString(), 16)); + i += 2; + } else { + output.push(input[i]); + } + } + return new Buffer(output).toString(); +} + +function isC0ControlPercentEncode(c) { + return c <= 0x1F || c > 0x7E; +} + +const extraPathPercentEncodeSet = new Set([32, 34, 35, 60, 62, 63, 96, 123, 125]); +function isPathPercentEncode(c) { + return isC0ControlPercentEncode(c) || extraPathPercentEncodeSet.has(c); +} + +const extraUserinfoPercentEncodeSet = + new Set([47, 58, 59, 61, 64, 91, 92, 93, 94, 124]); +function isUserinfoPercentEncode(c) { + return isPathPercentEncode(c) || extraUserinfoPercentEncodeSet.has(c); +} + +function percentEncodeChar(c, encodeSetPredicate) { + const cStr = String.fromCodePoint(c); + + if (encodeSetPredicate(c)) { + return utf8PercentEncode(cStr); + } + + return cStr; +} + +function parseIPv4Number(input) { + let R = 10; + + if (input.length >= 2 && input.charAt(0) === "0" && input.charAt(1).toLowerCase() === "x") { + input = input.substring(2); + R = 16; + } else if (input.length >= 2 && input.charAt(0) === "0") { + input = input.substring(1); + R = 8; + } + + if (input === "") { + return 0; + } + + const regex = R === 10 ? /[^0-9]/ : (R === 16 ? /[^0-9A-Fa-f]/ : /[^0-7]/); + if (regex.test(input)) { + return failure; + } + + return parseInt(input, R); +} + +function parseIPv4(input) { + const parts = input.split("."); + if (parts[parts.length - 1] === "") { + if (parts.length > 1) { + parts.pop(); + } + } + + if (parts.length > 4) { + return input; + } + + const numbers = []; + for (const part of parts) { + if (part === "") { + return input; + } + const n = parseIPv4Number(part); + if (n === failure) { + return input; + } + + numbers.push(n); + } + + for (let i = 0; i < numbers.length - 1; ++i) { + if (numbers[i] > 255) { + return failure; + } + } + if (numbers[numbers.length - 1] >= Math.pow(256, 5 - numbers.length)) { + return failure; + } + + let ipv4 = numbers.pop(); + let counter = 0; + + for (const n of numbers) { + ipv4 += n * Math.pow(256, 3 - counter); + ++counter; + } + + return ipv4; +} + +function serializeIPv4(address) { + let output = ""; + let n = address; + + for (let i = 1; i <= 4; ++i) { + output = String(n % 256) + output; + if (i !== 4) { + output = "." + output; + } + n = Math.floor(n / 256); + } + + return output; +} + +function parseIPv6(input) { + const address = [0, 0, 0, 0, 0, 0, 0, 0]; + let pieceIndex = 0; + let compress = null; + let pointer = 0; + + input = punycode.ucs2.decode(input); + + if (input[pointer] === 58) { + if (input[pointer + 1] !== 58) { + return failure; + } + + pointer += 2; + ++pieceIndex; + compress = pieceIndex; + } + + while (pointer < input.length) { + if (pieceIndex === 8) { + return failure; + } + + if (input[pointer] === 58) { + if (compress !== null) { + return failure; + } + ++pointer; + ++pieceIndex; + compress = pieceIndex; + continue; + } + + let value = 0; + let length = 0; + + while (length < 4 && isASCIIHex(input[pointer])) { + value = value * 0x10 + parseInt(at(input, pointer), 16); + ++pointer; + ++length; + } + + if (input[pointer] === 46) { + if (length === 0) { + return failure; + } + + pointer -= length; + + if (pieceIndex > 6) { + return failure; + } + + let numbersSeen = 0; + + while (input[pointer] !== undefined) { + let ipv4Piece = null; + + if (numbersSeen > 0) { + if (input[pointer] === 46 && numbersSeen < 4) { + ++pointer; + } else { + return failure; + } + } + + if (!isASCIIDigit(input[pointer])) { + return failure; + } + + while (isASCIIDigit(input[pointer])) { + const number = parseInt(at(input, pointer)); + if (ipv4Piece === null) { + ipv4Piece = number; + } else if (ipv4Piece === 0) { + return failure; + } else { + ipv4Piece = ipv4Piece * 10 + number; + } + if (ipv4Piece > 255) { + return failure; + } + ++pointer; + } + + address[pieceIndex] = address[pieceIndex] * 0x100 + ipv4Piece; + + ++numbersSeen; + + if (numbersSeen === 2 || numbersSeen === 4) { + ++pieceIndex; + } + } + + if (numbersSeen !== 4) { + return failure; + } + + break; + } else if (input[pointer] === 58) { + ++pointer; + if (input[pointer] === undefined) { + return failure; + } + } else if (input[pointer] !== undefined) { + return failure; + } + + address[pieceIndex] = value; + ++pieceIndex; + } + + if (compress !== null) { + let swaps = pieceIndex - compress; + pieceIndex = 7; + while (pieceIndex !== 0 && swaps > 0) { + const temp = address[compress + swaps - 1]; + address[compress + swaps - 1] = address[pieceIndex]; + address[pieceIndex] = temp; + --pieceIndex; + --swaps; + } + } else if (compress === null && pieceIndex !== 8) { + return failure; + } + + return address; +} + +function serializeIPv6(address) { + let output = ""; + const seqResult = findLongestZeroSequence(address); + const compress = seqResult.idx; + let ignore0 = false; + + for (let pieceIndex = 0; pieceIndex <= 7; ++pieceIndex) { + if (ignore0 && address[pieceIndex] === 0) { + continue; + } else if (ignore0) { + ignore0 = false; + } + + if (compress === pieceIndex) { + const separator = pieceIndex === 0 ? "::" : ":"; + output += separator; + ignore0 = true; + continue; + } + + output += address[pieceIndex].toString(16); + + if (pieceIndex !== 7) { + output += ":"; + } + } + + return output; +} + +function parseHost(input, isSpecialArg) { + if (input[0] === "[") { + if (input[input.length - 1] !== "]") { + return failure; + } + + return parseIPv6(input.substring(1, input.length - 1)); + } + + if (!isSpecialArg) { + return parseOpaqueHost(input); + } + + const domain = utf8PercentDecode(input); + const asciiDomain = tr46.toASCII(domain, false, tr46.PROCESSING_OPTIONS.NONTRANSITIONAL, false); + if (asciiDomain === null) { + return failure; + } + + if (containsForbiddenHostCodePoint(asciiDomain)) { + return failure; + } + + const ipv4Host = parseIPv4(asciiDomain); + if (typeof ipv4Host === "number" || ipv4Host === failure) { + return ipv4Host; + } + + return asciiDomain; +} + +function parseOpaqueHost(input) { + if (containsForbiddenHostCodePointExcludingPercent(input)) { + return failure; + } + + let output = ""; + const decoded = punycode.ucs2.decode(input); + for (let i = 0; i < decoded.length; ++i) { + output += percentEncodeChar(decoded[i], isC0ControlPercentEncode); + } + return output; +} + +function findLongestZeroSequence(arr) { + let maxIdx = null; + let maxLen = 1; // only find elements > 1 + let currStart = null; + let currLen = 0; + + for (let i = 0; i < arr.length; ++i) { + if (arr[i] !== 0) { + if (currLen > maxLen) { + maxIdx = currStart; + maxLen = currLen; + } + + currStart = null; + currLen = 0; + } else { + if (currStart === null) { + currStart = i; + } + ++currLen; + } + } + + // if trailing zeros + if (currLen > maxLen) { + maxIdx = currStart; + maxLen = currLen; + } + + return { + idx: maxIdx, + len: maxLen + }; +} + +function serializeHost(host) { + if (typeof host === "number") { + return serializeIPv4(host); + } + + // IPv6 serializer + if (host instanceof Array) { + return "[" + serializeIPv6(host) + "]"; + } + + return host; +} + +function trimControlChars(url) { + return url.replace(/^[\u0000-\u001F\u0020]+|[\u0000-\u001F\u0020]+$/g, ""); +} + +function trimTabAndNewline(url) { + return url.replace(/\u0009|\u000A|\u000D/g, ""); +} + +function shortenPath(url) { + const path = url.path; + if (path.length === 0) { + return; + } + if (url.scheme === "file" && path.length === 1 && isNormalizedWindowsDriveLetter(path[0])) { + return; + } + + path.pop(); +} + +function includesCredentials(url) { + return url.username !== "" || url.password !== ""; +} + +function cannotHaveAUsernamePasswordPort(url) { + return url.host === null || url.host === "" || url.cannotBeABaseURL || url.scheme === "file"; +} + +function isNormalizedWindowsDriveLetter(string) { + return /^[A-Za-z]:$/.test(string); +} + +function URLStateMachine(input, base, encodingOverride, url, stateOverride) { + this.pointer = 0; + this.input = input; + this.base = base || null; + this.encodingOverride = encodingOverride || "utf-8"; + this.stateOverride = stateOverride; + this.url = url; + this.failure = false; + this.parseError = false; + + if (!this.url) { + this.url = { + scheme: "", + username: "", + password: "", + host: null, + port: null, + path: [], + query: null, + fragment: null, + + cannotBeABaseURL: false + }; + + const res = trimControlChars(this.input); + if (res !== this.input) { + this.parseError = true; + } + this.input = res; + } + + const res = trimTabAndNewline(this.input); + if (res !== this.input) { + this.parseError = true; + } + this.input = res; + + this.state = stateOverride || "scheme start"; + + this.buffer = ""; + this.atFlag = false; + this.arrFlag = false; + this.passwordTokenSeenFlag = false; + + this.input = punycode.ucs2.decode(this.input); + + for (; this.pointer <= this.input.length; ++this.pointer) { + const c = this.input[this.pointer]; + const cStr = isNaN(c) ? undefined : String.fromCodePoint(c); + + // exec state machine + const ret = this["parse " + this.state](c, cStr); + if (!ret) { + break; // terminate algorithm + } else if (ret === failure) { + this.failure = true; + break; + } + } +} + +URLStateMachine.prototype["parse scheme start"] = function parseSchemeStart(c, cStr) { + if (isASCIIAlpha(c)) { + this.buffer += cStr.toLowerCase(); + this.state = "scheme"; + } else if (!this.stateOverride) { + this.state = "no scheme"; + --this.pointer; + } else { + this.parseError = true; + return failure; + } + + return true; +}; + +URLStateMachine.prototype["parse scheme"] = function parseScheme(c, cStr) { + if (isASCIIAlphanumeric(c) || c === 43 || c === 45 || c === 46) { + this.buffer += cStr.toLowerCase(); + } else if (c === 58) { + if (this.stateOverride) { + if (isSpecial(this.url) && !isSpecialScheme(this.buffer)) { + return false; + } + + if (!isSpecial(this.url) && isSpecialScheme(this.buffer)) { + return false; + } + + if ((includesCredentials(this.url) || this.url.port !== null) && this.buffer === "file") { + return false; + } + + if (this.url.scheme === "file" && (this.url.host === "" || this.url.host === null)) { + return false; + } + } + this.url.scheme = this.buffer; + this.buffer = ""; + if (this.stateOverride) { + return false; + } + if (this.url.scheme === "file") { + if (this.input[this.pointer + 1] !== 47 || this.input[this.pointer + 2] !== 47) { + this.parseError = true; + } + this.state = "file"; + } else if (isSpecial(this.url) && this.base !== null && this.base.scheme === this.url.scheme) { + this.state = "special relative or authority"; + } else if (isSpecial(this.url)) { + this.state = "special authority slashes"; + } else if (this.input[this.pointer + 1] === 47) { + this.state = "path or authority"; + ++this.pointer; + } else { + this.url.cannotBeABaseURL = true; + this.url.path.push(""); + this.state = "cannot-be-a-base-URL path"; + } + } else if (!this.stateOverride) { + this.buffer = ""; + this.state = "no scheme"; + this.pointer = -1; + } else { + this.parseError = true; + return failure; + } + + return true; +}; + +URLStateMachine.prototype["parse no scheme"] = function parseNoScheme(c) { + if (this.base === null || (this.base.cannotBeABaseURL && c !== 35)) { + return failure; + } else if (this.base.cannotBeABaseURL && c === 35) { + this.url.scheme = this.base.scheme; + this.url.path = this.base.path.slice(); + this.url.query = this.base.query; + this.url.fragment = ""; + this.url.cannotBeABaseURL = true; + this.state = "fragment"; + } else if (this.base.scheme === "file") { + this.state = "file"; + --this.pointer; + } else { + this.state = "relative"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse special relative or authority"] = function parseSpecialRelativeOrAuthority(c) { + if (c === 47 && this.input[this.pointer + 1] === 47) { + this.state = "special authority ignore slashes"; + ++this.pointer; + } else { + this.parseError = true; + this.state = "relative"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse path or authority"] = function parsePathOrAuthority(c) { + if (c === 47) { + this.state = "authority"; + } else { + this.state = "path"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse relative"] = function parseRelative(c) { + this.url.scheme = this.base.scheme; + if (isNaN(c)) { + this.url.username = this.base.username; + this.url.password = this.base.password; + this.url.host = this.base.host; + this.url.port = this.base.port; + this.url.path = this.base.path.slice(); + this.url.query = this.base.query; + } else if (c === 47) { + this.state = "relative slash"; + } else if (c === 63) { + this.url.username = this.base.username; + this.url.password = this.base.password; + this.url.host = this.base.host; + this.url.port = this.base.port; + this.url.path = this.base.path.slice(); + this.url.query = ""; + this.state = "query"; + } else if (c === 35) { + this.url.username = this.base.username; + this.url.password = this.base.password; + this.url.host = this.base.host; + this.url.port = this.base.port; + this.url.path = this.base.path.slice(); + this.url.query = this.base.query; + this.url.fragment = ""; + this.state = "fragment"; + } else if (isSpecial(this.url) && c === 92) { + this.parseError = true; + this.state = "relative slash"; + } else { + this.url.username = this.base.username; + this.url.password = this.base.password; + this.url.host = this.base.host; + this.url.port = this.base.port; + this.url.path = this.base.path.slice(0, this.base.path.length - 1); + + this.state = "path"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse relative slash"] = function parseRelativeSlash(c) { + if (isSpecial(this.url) && (c === 47 || c === 92)) { + if (c === 92) { + this.parseError = true; + } + this.state = "special authority ignore slashes"; + } else if (c === 47) { + this.state = "authority"; + } else { + this.url.username = this.base.username; + this.url.password = this.base.password; + this.url.host = this.base.host; + this.url.port = this.base.port; + this.state = "path"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse special authority slashes"] = function parseSpecialAuthoritySlashes(c) { + if (c === 47 && this.input[this.pointer + 1] === 47) { + this.state = "special authority ignore slashes"; + ++this.pointer; + } else { + this.parseError = true; + this.state = "special authority ignore slashes"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse special authority ignore slashes"] = function parseSpecialAuthorityIgnoreSlashes(c) { + if (c !== 47 && c !== 92) { + this.state = "authority"; + --this.pointer; + } else { + this.parseError = true; + } + + return true; +}; + +URLStateMachine.prototype["parse authority"] = function parseAuthority(c, cStr) { + if (c === 64) { + this.parseError = true; + if (this.atFlag) { + this.buffer = "%40" + this.buffer; + } + this.atFlag = true; + + // careful, this is based on buffer and has its own pointer (this.pointer != pointer) and inner chars + const len = countSymbols(this.buffer); + for (let pointer = 0; pointer < len; ++pointer) { + const codePoint = this.buffer.codePointAt(pointer); + + if (codePoint === 58 && !this.passwordTokenSeenFlag) { + this.passwordTokenSeenFlag = true; + continue; + } + const encodedCodePoints = percentEncodeChar(codePoint, isUserinfoPercentEncode); + if (this.passwordTokenSeenFlag) { + this.url.password += encodedCodePoints; + } else { + this.url.username += encodedCodePoints; + } + } + this.buffer = ""; + } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || + (isSpecial(this.url) && c === 92)) { + if (this.atFlag && this.buffer === "") { + this.parseError = true; + return failure; + } + this.pointer -= countSymbols(this.buffer) + 1; + this.buffer = ""; + this.state = "host"; + } else { + this.buffer += cStr; + } + + return true; +}; + +URLStateMachine.prototype["parse hostname"] = +URLStateMachine.prototype["parse host"] = function parseHostName(c, cStr) { + if (this.stateOverride && this.url.scheme === "file") { + --this.pointer; + this.state = "file host"; + } else if (c === 58 && !this.arrFlag) { + if (this.buffer === "") { + this.parseError = true; + return failure; + } + + const host = parseHost(this.buffer, isSpecial(this.url)); + if (host === failure) { + return failure; + } + + this.url.host = host; + this.buffer = ""; + this.state = "port"; + if (this.stateOverride === "hostname") { + return false; + } + } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || + (isSpecial(this.url) && c === 92)) { + --this.pointer; + if (isSpecial(this.url) && this.buffer === "") { + this.parseError = true; + return failure; + } else if (this.stateOverride && this.buffer === "" && + (includesCredentials(this.url) || this.url.port !== null)) { + this.parseError = true; + return false; + } + + const host = parseHost(this.buffer, isSpecial(this.url)); + if (host === failure) { + return failure; + } + + this.url.host = host; + this.buffer = ""; + this.state = "path start"; + if (this.stateOverride) { + return false; + } + } else { + if (c === 91) { + this.arrFlag = true; + } else if (c === 93) { + this.arrFlag = false; + } + this.buffer += cStr; + } + + return true; +}; + +URLStateMachine.prototype["parse port"] = function parsePort(c, cStr) { + if (isASCIIDigit(c)) { + this.buffer += cStr; + } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || + (isSpecial(this.url) && c === 92) || + this.stateOverride) { + if (this.buffer !== "") { + const port = parseInt(this.buffer); + if (port > Math.pow(2, 16) - 1) { + this.parseError = true; + return failure; + } + this.url.port = port === defaultPort(this.url.scheme) ? null : port; + this.buffer = ""; + } + if (this.stateOverride) { + return false; + } + this.state = "path start"; + --this.pointer; + } else { + this.parseError = true; + return failure; + } + + return true; +}; + +const fileOtherwiseCodePoints = new Set([47, 92, 63, 35]); + +URLStateMachine.prototype["parse file"] = function parseFile(c) { + this.url.scheme = "file"; + + if (c === 47 || c === 92) { + if (c === 92) { + this.parseError = true; + } + this.state = "file slash"; + } else if (this.base !== null && this.base.scheme === "file") { + if (isNaN(c)) { + this.url.host = this.base.host; + this.url.path = this.base.path.slice(); + this.url.query = this.base.query; + } else if (c === 63) { + this.url.host = this.base.host; + this.url.path = this.base.path.slice(); + this.url.query = ""; + this.state = "query"; + } else if (c === 35) { + this.url.host = this.base.host; + this.url.path = this.base.path.slice(); + this.url.query = this.base.query; + this.url.fragment = ""; + this.state = "fragment"; + } else { + if (this.input.length - this.pointer - 1 === 0 || // remaining consists of 0 code points + !isWindowsDriveLetterCodePoints(c, this.input[this.pointer + 1]) || + (this.input.length - this.pointer - 1 >= 2 && // remaining has at least 2 code points + !fileOtherwiseCodePoints.has(this.input[this.pointer + 2]))) { + this.url.host = this.base.host; + this.url.path = this.base.path.slice(); + shortenPath(this.url); + } else { + this.parseError = true; + } + + this.state = "path"; + --this.pointer; + } + } else { + this.state = "path"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse file slash"] = function parseFileSlash(c) { + if (c === 47 || c === 92) { + if (c === 92) { + this.parseError = true; + } + this.state = "file host"; + } else { + if (this.base !== null && this.base.scheme === "file") { + if (isNormalizedWindowsDriveLetterString(this.base.path[0])) { + this.url.path.push(this.base.path[0]); + } else { + this.url.host = this.base.host; + } + } + this.state = "path"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse file host"] = function parseFileHost(c, cStr) { + if (isNaN(c) || c === 47 || c === 92 || c === 63 || c === 35) { + --this.pointer; + if (!this.stateOverride && isWindowsDriveLetterString(this.buffer)) { + this.parseError = true; + this.state = "path"; + } else if (this.buffer === "") { + this.url.host = ""; + if (this.stateOverride) { + return false; + } + this.state = "path start"; + } else { + let host = parseHost(this.buffer, isSpecial(this.url)); + if (host === failure) { + return failure; + } + if (host === "localhost") { + host = ""; + } + this.url.host = host; + + if (this.stateOverride) { + return false; + } + + this.buffer = ""; + this.state = "path start"; + } + } else { + this.buffer += cStr; + } + + return true; +}; + +URLStateMachine.prototype["parse path start"] = function parsePathStart(c) { + if (isSpecial(this.url)) { + if (c === 92) { + this.parseError = true; + } + this.state = "path"; + + if (c !== 47 && c !== 92) { + --this.pointer; + } + } else if (!this.stateOverride && c === 63) { + this.url.query = ""; + this.state = "query"; + } else if (!this.stateOverride && c === 35) { + this.url.fragment = ""; + this.state = "fragment"; + } else if (c !== undefined) { + this.state = "path"; + if (c !== 47) { + --this.pointer; + } + } + + return true; +}; + +URLStateMachine.prototype["parse path"] = function parsePath(c) { + if (isNaN(c) || c === 47 || (isSpecial(this.url) && c === 92) || + (!this.stateOverride && (c === 63 || c === 35))) { + if (isSpecial(this.url) && c === 92) { + this.parseError = true; + } + + if (isDoubleDot(this.buffer)) { + shortenPath(this.url); + if (c !== 47 && !(isSpecial(this.url) && c === 92)) { + this.url.path.push(""); + } + } else if (isSingleDot(this.buffer) && c !== 47 && + !(isSpecial(this.url) && c === 92)) { + this.url.path.push(""); + } else if (!isSingleDot(this.buffer)) { + if (this.url.scheme === "file" && this.url.path.length === 0 && isWindowsDriveLetterString(this.buffer)) { + if (this.url.host !== "" && this.url.host !== null) { + this.parseError = true; + this.url.host = ""; + } + this.buffer = this.buffer[0] + ":"; + } + this.url.path.push(this.buffer); + } + this.buffer = ""; + if (this.url.scheme === "file" && (c === undefined || c === 63 || c === 35)) { + while (this.url.path.length > 1 && this.url.path[0] === "") { + this.parseError = true; + this.url.path.shift(); + } + } + if (c === 63) { + this.url.query = ""; + this.state = "query"; + } + if (c === 35) { + this.url.fragment = ""; + this.state = "fragment"; + } + } else { + // TODO: If c is not a URL code point and not "%", parse error. + + if (c === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2]))) { + this.parseError = true; + } + + this.buffer += percentEncodeChar(c, isPathPercentEncode); + } + + return true; +}; + +URLStateMachine.prototype["parse cannot-be-a-base-URL path"] = function parseCannotBeABaseURLPath(c) { + if (c === 63) { + this.url.query = ""; + this.state = "query"; + } else if (c === 35) { + this.url.fragment = ""; + this.state = "fragment"; + } else { + // TODO: Add: not a URL code point + if (!isNaN(c) && c !== 37) { + this.parseError = true; + } + + if (c === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2]))) { + this.parseError = true; + } + + if (!isNaN(c)) { + this.url.path[0] = this.url.path[0] + percentEncodeChar(c, isC0ControlPercentEncode); + } + } + + return true; +}; + +URLStateMachine.prototype["parse query"] = function parseQuery(c, cStr) { + if (isNaN(c) || (!this.stateOverride && c === 35)) { + if (!isSpecial(this.url) || this.url.scheme === "ws" || this.url.scheme === "wss") { + this.encodingOverride = "utf-8"; + } + + const buffer = new Buffer(this.buffer); // TODO: Use encoding override instead + for (let i = 0; i < buffer.length; ++i) { + if (buffer[i] < 0x21 || buffer[i] > 0x7E || buffer[i] === 0x22 || buffer[i] === 0x23 || + buffer[i] === 0x3C || buffer[i] === 0x3E) { + this.url.query += percentEncode(buffer[i]); + } else { + this.url.query += String.fromCodePoint(buffer[i]); + } + } + + this.buffer = ""; + if (c === 35) { + this.url.fragment = ""; + this.state = "fragment"; + } + } else { + // TODO: If c is not a URL code point and not "%", parse error. + if (c === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2]))) { + this.parseError = true; + } + + this.buffer += cStr; + } + + return true; +}; + +URLStateMachine.prototype["parse fragment"] = function parseFragment(c) { + if (isNaN(c)) { // do nothing + } else if (c === 0x0) { + this.parseError = true; + } else { + // TODO: If c is not a URL code point and not "%", parse error. + if (c === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2]))) { + this.parseError = true; + } + + this.url.fragment += percentEncodeChar(c, isC0ControlPercentEncode); + } + + return true; +}; + +function serializeURL(url, excludeFragment) { + let output = url.scheme + ":"; + if (url.host !== null) { + output += "//"; + + if (url.username !== "" || url.password !== "") { + output += url.username; + if (url.password !== "") { + output += ":" + url.password; + } + output += "@"; + } + + output += serializeHost(url.host); + + if (url.port !== null) { + output += ":" + url.port; + } + } else if (url.host === null && url.scheme === "file") { + output += "//"; + } + + if (url.cannotBeABaseURL) { + output += url.path[0]; + } else { + for (const string of url.path) { + output += "/" + string; + } + } + + if (url.query !== null) { + output += "?" + url.query; + } + + if (!excludeFragment && url.fragment !== null) { + output += "#" + url.fragment; + } + + return output; +} + +function serializeOrigin(tuple) { + let result = tuple.scheme + "://"; + result += serializeHost(tuple.host); + + if (tuple.port !== null) { + result += ":" + tuple.port; + } + + return result; +} + +module.exports.serializeURL = serializeURL; + +module.exports.serializeURLOrigin = function (url) { + // https://url.spec.whatwg.org/#concept-url-origin + switch (url.scheme) { + case "blob": + try { + return module.exports.serializeURLOrigin(module.exports.parseURL(url.path[0])); + } catch (e) { + // serializing an opaque origin returns "null" + return "null"; + } + case "ftp": + case "gopher": + case "http": + case "https": + case "ws": + case "wss": + return serializeOrigin({ + scheme: url.scheme, + host: url.host, + port: url.port + }); + case "file": + // spec says "exercise to the reader", chrome says "file://" + return "file://"; + default: + // serializing an opaque origin returns "null" + return "null"; + } +}; + +module.exports.basicURLParse = function (input, options) { + if (options === undefined) { + options = {}; + } + + const usm = new URLStateMachine(input, options.baseURL, options.encodingOverride, options.url, options.stateOverride); + if (usm.failure) { + return "failure"; + } + + return usm.url; +}; + +module.exports.setTheUsername = function (url, username) { + url.username = ""; + const decoded = punycode.ucs2.decode(username); + for (let i = 0; i < decoded.length; ++i) { + url.username += percentEncodeChar(decoded[i], isUserinfoPercentEncode); + } +}; + +module.exports.setThePassword = function (url, password) { + url.password = ""; + const decoded = punycode.ucs2.decode(password); + for (let i = 0; i < decoded.length; ++i) { + url.password += percentEncodeChar(decoded[i], isUserinfoPercentEncode); + } +}; + +module.exports.serializeHost = serializeHost; + +module.exports.cannotHaveAUsernamePasswordPort = cannotHaveAUsernamePasswordPort; + +module.exports.serializeInteger = function (integer) { + return String(integer); +}; + +module.exports.parseURL = function (input, options) { + if (options === undefined) { + options = {}; + } + + // We don't handle blobs, so this just delegates: + return module.exports.basicURLParse(input, { baseURL: options.baseURL, encodingOverride: options.encodingOverride }); +}; diff --git a/backend/node_modules/wide-align/LICENSE b/backend/node_modules/wide-align/LICENSE old mode 100644 new mode 100755 diff --git a/backend/node_modules/wide-align/README.md b/backend/node_modules/wide-align/README.md old mode 100644 new mode 100755 diff --git a/backend/node_modules/wide-align/align.js b/backend/node_modules/wide-align/align.js old mode 100644 new mode 100755 diff --git a/backend/node_modules/wide-align/package.json b/backend/node_modules/wide-align/package.json old mode 100644 new mode 100755 diff --git a/backend/node_modules/wkx/LICENSE.txt b/backend/node_modules/wkx/LICENSE.txt index 394e47a..2659446 100644 --- a/backend/node_modules/wkx/LICENSE.txt +++ b/backend/node_modules/wkx/LICENSE.txt @@ -1,20 +1,20 @@ -The MIT License (MIT) - -Copyright (c) 2013 Christian Schwarz - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +The MIT License (MIT) + +Copyright (c) 2013 Christian Schwarz + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/backend/node_modules/wkx/README.md b/backend/node_modules/wkx/README.md index 378c023..1d3a353 100644 --- a/backend/node_modules/wkx/README.md +++ b/backend/node_modules/wkx/README.md @@ -1,92 +1,92 @@ -wkx [![Build Status](https://travis-ci.org/cschwarz/wkx.svg?branch=master)](https://travis-ci.org/cschwarz/wkx) [![Coverage Status](https://coveralls.io/repos/cschwarz/wkx/badge.svg?branch=master)](https://coveralls.io/r/cschwarz/wkx?branch=master) -======== - -A WKT/WKB/EWKT/EWKB/TWKB/GeoJSON parser and serializer with support for - -- Point -- LineString -- Polygon -- MultiPoint -- MultiLineString -- MultiPolygon -- GeometryCollection - -Examples --------- - -The following examples show you how to work with wkx. - -```javascript -var wkx = require('wkx'); - -//Parsing a WKT string -var geometry = wkx.Geometry.parse('POINT(1 2)'); - -//Parsing an EWKT string -var geometry = wkx.Geometry.parse('SRID=4326;POINT(1 2)'); - -//Parsing a node Buffer containing a WKB object -var geometry = wkx.Geometry.parse(wkbBuffer); - -//Parsing a node Buffer containing an EWKB object -var geometry = wkx.Geometry.parse(ewkbBuffer); - -//Parsing a node Buffer containing a TWKB object -var geometry = wkx.Geometry.parseTwkb(twkbBuffer); - -//Parsing a GeoJSON object -var geometry = wkx.Geometry.parseGeoJSON({ type: 'Point', coordinates: [1, 2] }); - -//Serializing a Point geometry to WKT -var wktString = new wkx.Point(1, 2).toWkt(); - -//Serializing a Point geometry to WKB -var wkbBuffer = new wkx.Point(1, 2).toWkb(); - -//Serializing a Point geometry to EWKT -var ewktString = new wkx.Point(1, 2, undefined, undefined, 4326).toEwkt(); - -//Serializing a Point geometry to EWKB -var ewkbBuffer = new wkx.Point(1, 2, undefined, undefined, 4326).toEwkb(); - -//Serializing a Point geometry to TWKB -var twkbBuffer = new wkx.Point(1, 2).toTwkb(); - -//Serializing a Point geometry to GeoJSON -var geoJSONObject = new wkx.Point(1, 2).toGeoJSON(); -``` - -Browser -------- - -To use `wkx` in a webpage, simply copy a built browser version from `dist/` into your project, and use a `script` tag -to include it: -```html - -``` - -If you use [browserify][] for your project, you can simply `npm install wkx --save`, and just require `wkx` as usual in -your code. - ----- - -Regardless of which of the preceeding options you choose, using `wkx` in the browser will look the same: -```javascript -var wkx = require('wkx'); - -var geometry = wkx.Geometry.parse('POINT(1 2)'); - -console.log(geometry.toGeoJSON()); -``` - -In addition to the `wkx` module, the browser versions also export `buffer`, which is useful for parsing WKB: -```javascript -var Buffer = require('buffer').Buffer; -var wkx = require('wkx'); - -var wkbBuffer = new Buffer('0101000000000000000000f03f0000000000000040', 'hex'); -var geometry = wkx.Geometry.parse(wkbBuffer); - -console.log(geometry.toGeoJSON()); -``` -[browserify]: http://browserify.org/ +wkx [![Build Status](https://travis-ci.org/cschwarz/wkx.svg?branch=master)](https://travis-ci.org/cschwarz/wkx) [![Coverage Status](https://coveralls.io/repos/cschwarz/wkx/badge.svg?branch=master)](https://coveralls.io/r/cschwarz/wkx?branch=master) +======== + +A WKT/WKB/EWKT/EWKB/TWKB/GeoJSON parser and serializer with support for + +- Point +- LineString +- Polygon +- MultiPoint +- MultiLineString +- MultiPolygon +- GeometryCollection + +Examples +-------- + +The following examples show you how to work with wkx. + +```javascript +var wkx = require('wkx'); + +//Parsing a WKT string +var geometry = wkx.Geometry.parse('POINT(1 2)'); + +//Parsing an EWKT string +var geometry = wkx.Geometry.parse('SRID=4326;POINT(1 2)'); + +//Parsing a node Buffer containing a WKB object +var geometry = wkx.Geometry.parse(wkbBuffer); + +//Parsing a node Buffer containing an EWKB object +var geometry = wkx.Geometry.parse(ewkbBuffer); + +//Parsing a node Buffer containing a TWKB object +var geometry = wkx.Geometry.parseTwkb(twkbBuffer); + +//Parsing a GeoJSON object +var geometry = wkx.Geometry.parseGeoJSON({ type: 'Point', coordinates: [1, 2] }); + +//Serializing a Point geometry to WKT +var wktString = new wkx.Point(1, 2).toWkt(); + +//Serializing a Point geometry to WKB +var wkbBuffer = new wkx.Point(1, 2).toWkb(); + +//Serializing a Point geometry to EWKT +var ewktString = new wkx.Point(1, 2, undefined, undefined, 4326).toEwkt(); + +//Serializing a Point geometry to EWKB +var ewkbBuffer = new wkx.Point(1, 2, undefined, undefined, 4326).toEwkb(); + +//Serializing a Point geometry to TWKB +var twkbBuffer = new wkx.Point(1, 2).toTwkb(); + +//Serializing a Point geometry to GeoJSON +var geoJSONObject = new wkx.Point(1, 2).toGeoJSON(); +``` + +Browser +------- + +To use `wkx` in a webpage, simply copy a built browser version from `dist/` into your project, and use a `script` tag +to include it: +```html + +``` + +If you use [browserify][] for your project, you can simply `npm install wkx --save`, and just require `wkx` as usual in +your code. + +---- + +Regardless of which of the preceeding options you choose, using `wkx` in the browser will look the same: +```javascript +var wkx = require('wkx'); + +var geometry = wkx.Geometry.parse('POINT(1 2)'); + +console.log(geometry.toGeoJSON()); +``` + +In addition to the `wkx` module, the browser versions also export `buffer`, which is useful for parsing WKB: +```javascript +var Buffer = require('buffer').Buffer; +var wkx = require('wkx'); + +var wkbBuffer = new Buffer('0101000000000000000000f03f0000000000000040', 'hex'); +var geometry = wkx.Geometry.parse(wkbBuffer); + +console.log(geometry.toGeoJSON()); +``` +[browserify]: http://browserify.org/ diff --git a/backend/node_modules/wkx/dist/wkx.js b/backend/node_modules/wkx/dist/wkx.js index 4346c59..0dcb697 100644 --- a/backend/node_modules/wkx/dist/wkx.js +++ b/backend/node_modules/wkx/dist/wkx.js @@ -1,2130 +1,2130 @@ require=(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i= 0x80); - - this.position += bytesRead; - - return result; -}; +module.exports = BinaryReader; + +function BinaryReader(buffer, isBigEndian) { + this.buffer = buffer; + this.position = 0; + this.isBigEndian = isBigEndian || false; +} + +function _read(readLE, readBE, size) { + return function () { + var value; + + if (this.isBigEndian) + value = readBE.call(this.buffer, this.position); + else + value = readLE.call(this.buffer, this.position); + + this.position += size; + + return value; + }; +} + +BinaryReader.prototype.readUInt8 = _read(Buffer.prototype.readUInt8, Buffer.prototype.readUInt8, 1); +BinaryReader.prototype.readUInt16 = _read(Buffer.prototype.readUInt16LE, Buffer.prototype.readUInt16BE, 2); +BinaryReader.prototype.readUInt32 = _read(Buffer.prototype.readUInt32LE, Buffer.prototype.readUInt32BE, 4); +BinaryReader.prototype.readInt8 = _read(Buffer.prototype.readInt8, Buffer.prototype.readInt8, 1); +BinaryReader.prototype.readInt16 = _read(Buffer.prototype.readInt16LE, Buffer.prototype.readInt16BE, 2); +BinaryReader.prototype.readInt32 = _read(Buffer.prototype.readInt32LE, Buffer.prototype.readInt32BE, 4); +BinaryReader.prototype.readFloat = _read(Buffer.prototype.readFloatLE, Buffer.prototype.readFloatBE, 4); +BinaryReader.prototype.readDouble = _read(Buffer.prototype.readDoubleLE, Buffer.prototype.readDoubleBE, 8); + +BinaryReader.prototype.readVarInt = function () { + var nextByte, + result = 0, + bytesRead = 0; + + do { + nextByte = this.buffer[this.position + bytesRead]; + result += (nextByte & 0x7F) << (7 * bytesRead); + bytesRead++; + } while (nextByte >= 0x80); + + this.position += bytesRead; + + return result; +}; }).call(this,require("buffer").Buffer) },{"buffer":"buffer"}],2:[function(require,module,exports){ (function (Buffer){ -module.exports = BinaryWriter; - -function BinaryWriter(size, allowResize) { - this.buffer = new Buffer(size); - this.position = 0; - this.allowResize = allowResize; -} - -function _write(write, size) { - return function (value, noAssert) { - this.ensureSize(size); - - write.call(this.buffer, value, this.position, noAssert); - this.position += size; - }; -} - -BinaryWriter.prototype.writeUInt8 = _write(Buffer.prototype.writeUInt8, 1); -BinaryWriter.prototype.writeUInt16LE = _write(Buffer.prototype.writeUInt16LE, 2); -BinaryWriter.prototype.writeUInt16BE = _write(Buffer.prototype.writeUInt16BE, 2); -BinaryWriter.prototype.writeUInt32LE = _write(Buffer.prototype.writeUInt32LE, 4); -BinaryWriter.prototype.writeUInt32BE = _write(Buffer.prototype.writeUInt32BE, 4); -BinaryWriter.prototype.writeInt8 = _write(Buffer.prototype.writeInt8, 1); -BinaryWriter.prototype.writeInt16LE = _write(Buffer.prototype.writeInt16LE, 2); -BinaryWriter.prototype.writeInt16BE = _write(Buffer.prototype.writeInt16BE, 2); -BinaryWriter.prototype.writeInt32LE = _write(Buffer.prototype.writeInt32LE, 4); -BinaryWriter.prototype.writeInt32BE = _write(Buffer.prototype.writeInt32BE, 4); -BinaryWriter.prototype.writeFloatLE = _write(Buffer.prototype.writeFloatLE, 4); -BinaryWriter.prototype.writeFloatBE = _write(Buffer.prototype.writeFloatBE, 4); -BinaryWriter.prototype.writeDoubleLE = _write(Buffer.prototype.writeDoubleLE, 8); -BinaryWriter.prototype.writeDoubleBE = _write(Buffer.prototype.writeDoubleBE, 8); - -BinaryWriter.prototype.writeBuffer = function (buffer) { - this.ensureSize(buffer.length); - - buffer.copy(this.buffer, this.position, 0, buffer.length); - this.position += buffer.length; -}; - -BinaryWriter.prototype.writeVarInt = function (value) { - var length = 1; - - while ((value & 0xFFFFFF80) !== 0) { - this.writeUInt8((value & 0x7F) | 0x80); - value >>>= 7; - length++; - } - - this.writeUInt8(value & 0x7F); - - return length; -}; - -BinaryWriter.prototype.ensureSize = function (size) { - if (this.buffer.length < this.position + size) { - if (this.allowResize) { - var tempBuffer = new Buffer(this.position + size); - this.buffer.copy(tempBuffer, 0, 0, this.buffer.length); - this.buffer = tempBuffer; - } - else { - throw new RangeError('index out of range'); - } - } -}; +module.exports = BinaryWriter; + +function BinaryWriter(size, allowResize) { + this.buffer = new Buffer(size); + this.position = 0; + this.allowResize = allowResize; +} + +function _write(write, size) { + return function (value, noAssert) { + this.ensureSize(size); + + write.call(this.buffer, value, this.position, noAssert); + this.position += size; + }; +} + +BinaryWriter.prototype.writeUInt8 = _write(Buffer.prototype.writeUInt8, 1); +BinaryWriter.prototype.writeUInt16LE = _write(Buffer.prototype.writeUInt16LE, 2); +BinaryWriter.prototype.writeUInt16BE = _write(Buffer.prototype.writeUInt16BE, 2); +BinaryWriter.prototype.writeUInt32LE = _write(Buffer.prototype.writeUInt32LE, 4); +BinaryWriter.prototype.writeUInt32BE = _write(Buffer.prototype.writeUInt32BE, 4); +BinaryWriter.prototype.writeInt8 = _write(Buffer.prototype.writeInt8, 1); +BinaryWriter.prototype.writeInt16LE = _write(Buffer.prototype.writeInt16LE, 2); +BinaryWriter.prototype.writeInt16BE = _write(Buffer.prototype.writeInt16BE, 2); +BinaryWriter.prototype.writeInt32LE = _write(Buffer.prototype.writeInt32LE, 4); +BinaryWriter.prototype.writeInt32BE = _write(Buffer.prototype.writeInt32BE, 4); +BinaryWriter.prototype.writeFloatLE = _write(Buffer.prototype.writeFloatLE, 4); +BinaryWriter.prototype.writeFloatBE = _write(Buffer.prototype.writeFloatBE, 4); +BinaryWriter.prototype.writeDoubleLE = _write(Buffer.prototype.writeDoubleLE, 8); +BinaryWriter.prototype.writeDoubleBE = _write(Buffer.prototype.writeDoubleBE, 8); + +BinaryWriter.prototype.writeBuffer = function (buffer) { + this.ensureSize(buffer.length); + + buffer.copy(this.buffer, this.position, 0, buffer.length); + this.position += buffer.length; +}; + +BinaryWriter.prototype.writeVarInt = function (value) { + var length = 1; + + while ((value & 0xFFFFFF80) !== 0) { + this.writeUInt8((value & 0x7F) | 0x80); + value >>>= 7; + length++; + } + + this.writeUInt8(value & 0x7F); + + return length; +}; + +BinaryWriter.prototype.ensureSize = function (size) { + if (this.buffer.length < this.position + size) { + if (this.allowResize) { + var tempBuffer = new Buffer(this.position + size); + this.buffer.copy(tempBuffer, 0, 0, this.buffer.length); + this.buffer = tempBuffer; + } + else { + throw new RangeError('index out of range'); + } + } +}; }).call(this,require("buffer").Buffer) },{"buffer":"buffer"}],3:[function(require,module,exports){ (function (Buffer){ -module.exports = Geometry; - -var Types = require('./types'); -var Point = require('./point'); -var LineString = require('./linestring'); -var Polygon = require('./polygon'); -var MultiPoint = require('./multipoint'); -var MultiLineString = require('./multilinestring'); -var MultiPolygon = require('./multipolygon'); -var GeometryCollection = require('./geometrycollection'); -var BinaryReader = require('./binaryreader'); -var BinaryWriter = require('./binarywriter'); -var WktParser = require('./wktparser'); -var ZigZag = require('./zigzag.js'); - -function Geometry() { - this.srid = undefined; - this.hasZ = false; - this.hasM = false; -} - -Geometry.parse = function (value, options) { - var valueType = typeof value; - - if (valueType === 'string' || value instanceof WktParser) - return Geometry._parseWkt(value); - else if (Buffer.isBuffer(value) || value instanceof BinaryReader) - return Geometry._parseWkb(value, options); - else - throw new Error('first argument must be a string or Buffer'); -}; - -Geometry._parseWkt = function (value) { - var wktParser, - srid; - - if (value instanceof WktParser) - wktParser = value; - else - wktParser = new WktParser(value); - - var match = wktParser.matchRegex([/^SRID=(\d+);/]); - if (match) - srid = parseInt(match[1], 10); - - var geometryType = wktParser.matchType(); - var dimension = wktParser.matchDimension(); - - var options = { - srid: srid, - hasZ: dimension.hasZ, - hasM: dimension.hasM - }; - - switch (geometryType) { - case Types.wkt.Point: - return Point._parseWkt(wktParser, options); - case Types.wkt.LineString: - return LineString._parseWkt(wktParser, options); - case Types.wkt.Polygon: - return Polygon._parseWkt(wktParser, options); - case Types.wkt.MultiPoint: - return MultiPoint._parseWkt(wktParser, options); - case Types.wkt.MultiLineString: - return MultiLineString._parseWkt(wktParser, options); - case Types.wkt.MultiPolygon: - return MultiPolygon._parseWkt(wktParser, options); - case Types.wkt.GeometryCollection: - return GeometryCollection._parseWkt(wktParser, options); - } -}; - -Geometry._parseWkb = function (value, parentOptions) { - var binaryReader, - wkbType, - geometryType, - options = {}; - - if (value instanceof BinaryReader) - binaryReader = value; - else - binaryReader = new BinaryReader(value); - - binaryReader.isBigEndian = !binaryReader.readInt8(); - - wkbType = binaryReader.readUInt32(); - - options.hasSrid = (wkbType & 0x20000000) === 0x20000000; - options.isEwkb = (wkbType & 0x20000000) || (wkbType & 0x40000000) || (wkbType & 0x80000000); - - if (options.hasSrid) - options.srid = binaryReader.readUInt32(); - - options.hasZ = false; - options.hasM = false; - - if (!options.isEwkb && (!parentOptions || !parentOptions.isEwkb)) { - if (wkbType >= 1000 && wkbType < 2000) { - options.hasZ = true; - geometryType = wkbType - 1000; - } - else if (wkbType >= 2000 && wkbType < 3000) { - options.hasM = true; - geometryType = wkbType - 2000; - } - else if (wkbType >= 3000 && wkbType < 4000) { - options.hasZ = true; - options.hasM = true; - geometryType = wkbType - 3000; - } - else { - geometryType = wkbType; - } - } - else { - if (wkbType & 0x80000000) - options.hasZ = true; - if (wkbType & 0x40000000) - options.hasM = true; - - geometryType = wkbType & 0xF; - } - - switch (geometryType) { - case Types.wkb.Point: - return Point._parseWkb(binaryReader, options); - case Types.wkb.LineString: - return LineString._parseWkb(binaryReader, options); - case Types.wkb.Polygon: - return Polygon._parseWkb(binaryReader, options); - case Types.wkb.MultiPoint: - return MultiPoint._parseWkb(binaryReader, options); - case Types.wkb.MultiLineString: - return MultiLineString._parseWkb(binaryReader, options); - case Types.wkb.MultiPolygon: - return MultiPolygon._parseWkb(binaryReader, options); - case Types.wkb.GeometryCollection: - return GeometryCollection._parseWkb(binaryReader, options); - default: - throw new Error('GeometryType ' + geometryType + ' not supported'); - } -}; - -Geometry.parseTwkb = function (value) { - var binaryReader, - options = {}; - - if (value instanceof BinaryReader) - binaryReader = value; - else - binaryReader = new BinaryReader(value); - - var type = binaryReader.readUInt8(); - var metadataHeader = binaryReader.readUInt8(); - - var geometryType = type & 0x0F; - options.precision = ZigZag.decode(type >> 4); - options.precisionFactor = Math.pow(10, options.precision); - - options.hasBoundingBox = metadataHeader >> 0 & 1; - options.hasSizeAttribute = metadataHeader >> 1 & 1; - options.hasIdList = metadataHeader >> 2 & 1; - options.hasExtendedPrecision = metadataHeader >> 3 & 1; - options.isEmpty = metadataHeader >> 4 & 1; - - if (options.hasExtendedPrecision) { - var extendedPrecision = binaryReader.readUInt8(); - options.hasZ = (extendedPrecision & 0x01) === 0x01; - options.hasM = (extendedPrecision & 0x02) === 0x02; - - options.zPrecision = ZigZag.decode((extendedPrecision & 0x1C) >> 2); - options.zPrecisionFactor = Math.pow(10, options.zPrecision); - - options.mPrecision = ZigZag.decode((extendedPrecision & 0xE0) >> 5); - options.mPrecisionFactor = Math.pow(10, options.mPrecision); - } - else { - options.hasZ = false; - options.hasM = false; - } - - if (options.hasSizeAttribute) - binaryReader.readVarInt(); - if (options.hasBoundingBox) { - var dimensions = 2; - - if (options.hasZ) - dimensions++; - if (options.hasM) - dimensions++; - - for (var i = 0; i < dimensions; i++) { - binaryReader.readVarInt(); - binaryReader.readVarInt(); - } - } - - switch (geometryType) { - case Types.wkb.Point: - return Point._parseTwkb(binaryReader, options); - case Types.wkb.LineString: - return LineString._parseTwkb(binaryReader, options); - case Types.wkb.Polygon: - return Polygon._parseTwkb(binaryReader, options); - case Types.wkb.MultiPoint: - return MultiPoint._parseTwkb(binaryReader, options); - case Types.wkb.MultiLineString: - return MultiLineString._parseTwkb(binaryReader, options); - case Types.wkb.MultiPolygon: - return MultiPolygon._parseTwkb(binaryReader, options); - case Types.wkb.GeometryCollection: - return GeometryCollection._parseTwkb(binaryReader, options); - default: - throw new Error('GeometryType ' + geometryType + ' not supported'); - } -}; - -Geometry.parseGeoJSON = function (value) { - return Geometry._parseGeoJSON(value); -}; - -Geometry._parseGeoJSON = function (value, isSubGeometry) { - var geometry; - - switch (value.type) { - case Types.geoJSON.Point: - geometry = Point._parseGeoJSON(value); break; - case Types.geoJSON.LineString: - geometry = LineString._parseGeoJSON(value); break; - case Types.geoJSON.Polygon: - geometry = Polygon._parseGeoJSON(value); break; - case Types.geoJSON.MultiPoint: - geometry = MultiPoint._parseGeoJSON(value); break; - case Types.geoJSON.MultiLineString: - geometry = MultiLineString._parseGeoJSON(value); break; - case Types.geoJSON.MultiPolygon: - geometry = MultiPolygon._parseGeoJSON(value); break; - case Types.geoJSON.GeometryCollection: - geometry = GeometryCollection._parseGeoJSON(value); break; - default: - throw new Error('GeometryType ' + value.type + ' not supported'); - } - - if (value.crs && value.crs.type && value.crs.type === 'name' && value.crs.properties && value.crs.properties.name) { - var crs = value.crs.properties.name; - - if (crs.indexOf('EPSG:') === 0) - geometry.srid = parseInt(crs.substring(5)); - else if (crs.indexOf('urn:ogc:def:crs:EPSG::') === 0) - geometry.srid = parseInt(crs.substring(22)); - else - throw new Error('Unsupported crs: ' + crs); - } - else if (!isSubGeometry) { - geometry.srid = 4326; - } - - return geometry; -}; - -Geometry.prototype.toEwkt = function () { - return 'SRID=' + this.srid + ';' + this.toWkt(); -}; - -Geometry.prototype.toEwkb = function () { - var ewkb = new BinaryWriter(this._getWkbSize() + 4); - var wkb = this.toWkb(); - - ewkb.writeInt8(1); - ewkb.writeUInt32LE((wkb.slice(1, 5).readUInt32LE(0) | 0x20000000) >>> 0, true); - ewkb.writeUInt32LE(this.srid); - - ewkb.writeBuffer(wkb.slice(5)); - - return ewkb.buffer; -}; - -Geometry.prototype._getWktType = function (wktType, isEmpty) { - var wkt = wktType; - - if (this.hasZ && this.hasM) - wkt += ' ZM '; - else if (this.hasZ) - wkt += ' Z '; - else if (this.hasM) - wkt += ' M '; - - if (isEmpty && !this.hasZ && !this.hasM) - wkt += ' '; - - if (isEmpty) - wkt += 'EMPTY'; - - return wkt; -}; - -Geometry.prototype._getWktCoordinate = function (point) { - var coordinates = point.x + ' ' + point.y; - - if (this.hasZ) - coordinates += ' ' + point.z; - if (this.hasM) - coordinates += ' ' + point.m; - - return coordinates; -}; - -Geometry.prototype._writeWkbType = function (wkb, geometryType, parentOptions) { - var dimensionType = 0; - - if (typeof this.srid === 'undefined' && (!parentOptions || typeof parentOptions.srid === 'undefined')) { - if (this.hasZ && this.hasM) - dimensionType += 3000; - else if (this.hasZ) - dimensionType += 1000; - else if (this.hasM) - dimensionType += 2000; - } - else { - if (this.hasZ) - dimensionType |= 0x80000000; - if (this.hasM) - dimensionType |= 0x40000000; - } - - wkb.writeUInt32LE((dimensionType + geometryType) >>> 0, true); -}; - -Geometry.getTwkbPrecision = function (xyPrecision, zPrecision, mPrecision) { - return { - xy: xyPrecision, - z: zPrecision, - m: mPrecision, - xyFactor: Math.pow(10, xyPrecision), - zFactor: Math.pow(10, zPrecision), - mFactor: Math.pow(10, mPrecision) - }; -}; - -Geometry.prototype._writeTwkbHeader = function (twkb, geometryType, precision, isEmpty) { - var type = (ZigZag.encode(precision.xy) << 4) + geometryType; - var metadataHeader = (this.hasZ || this.hasM) << 3; - metadataHeader += isEmpty << 4; - - twkb.writeUInt8(type); - twkb.writeUInt8(metadataHeader); - - if (this.hasZ || this.hasM) { - var extendedPrecision = 0; - if (this.hasZ) - extendedPrecision |= 0x1; - if (this.hasM) - extendedPrecision |= 0x2; - - twkb.writeUInt8(extendedPrecision); - } -}; - -Geometry.prototype.toGeoJSON = function (options) { - var geoJSON = {}; - - if (this.srid) { - if (options) { - if (options.shortCrs) { - geoJSON.crs = { - type: 'name', - properties: { - name: 'EPSG:' + this.srid - } - }; - } - else if (options.longCrs) { - geoJSON.crs = { - type: 'name', - properties: { - name: 'urn:ogc:def:crs:EPSG::' + this.srid - } - }; - } - } - } - - return geoJSON; -}; +module.exports = Geometry; + +var Types = require('./types'); +var Point = require('./point'); +var LineString = require('./linestring'); +var Polygon = require('./polygon'); +var MultiPoint = require('./multipoint'); +var MultiLineString = require('./multilinestring'); +var MultiPolygon = require('./multipolygon'); +var GeometryCollection = require('./geometrycollection'); +var BinaryReader = require('./binaryreader'); +var BinaryWriter = require('./binarywriter'); +var WktParser = require('./wktparser'); +var ZigZag = require('./zigzag.js'); + +function Geometry() { + this.srid = undefined; + this.hasZ = false; + this.hasM = false; +} + +Geometry.parse = function (value, options) { + var valueType = typeof value; + + if (valueType === 'string' || value instanceof WktParser) + return Geometry._parseWkt(value); + else if (Buffer.isBuffer(value) || value instanceof BinaryReader) + return Geometry._parseWkb(value, options); + else + throw new Error('first argument must be a string or Buffer'); +}; + +Geometry._parseWkt = function (value) { + var wktParser, + srid; + + if (value instanceof WktParser) + wktParser = value; + else + wktParser = new WktParser(value); + + var match = wktParser.matchRegex([/^SRID=(\d+);/]); + if (match) + srid = parseInt(match[1], 10); + + var geometryType = wktParser.matchType(); + var dimension = wktParser.matchDimension(); + + var options = { + srid: srid, + hasZ: dimension.hasZ, + hasM: dimension.hasM + }; + + switch (geometryType) { + case Types.wkt.Point: + return Point._parseWkt(wktParser, options); + case Types.wkt.LineString: + return LineString._parseWkt(wktParser, options); + case Types.wkt.Polygon: + return Polygon._parseWkt(wktParser, options); + case Types.wkt.MultiPoint: + return MultiPoint._parseWkt(wktParser, options); + case Types.wkt.MultiLineString: + return MultiLineString._parseWkt(wktParser, options); + case Types.wkt.MultiPolygon: + return MultiPolygon._parseWkt(wktParser, options); + case Types.wkt.GeometryCollection: + return GeometryCollection._parseWkt(wktParser, options); + } +}; + +Geometry._parseWkb = function (value, parentOptions) { + var binaryReader, + wkbType, + geometryType, + options = {}; + + if (value instanceof BinaryReader) + binaryReader = value; + else + binaryReader = new BinaryReader(value); + + binaryReader.isBigEndian = !binaryReader.readInt8(); + + wkbType = binaryReader.readUInt32(); + + options.hasSrid = (wkbType & 0x20000000) === 0x20000000; + options.isEwkb = (wkbType & 0x20000000) || (wkbType & 0x40000000) || (wkbType & 0x80000000); + + if (options.hasSrid) + options.srid = binaryReader.readUInt32(); + + options.hasZ = false; + options.hasM = false; + + if (!options.isEwkb && (!parentOptions || !parentOptions.isEwkb)) { + if (wkbType >= 1000 && wkbType < 2000) { + options.hasZ = true; + geometryType = wkbType - 1000; + } + else if (wkbType >= 2000 && wkbType < 3000) { + options.hasM = true; + geometryType = wkbType - 2000; + } + else if (wkbType >= 3000 && wkbType < 4000) { + options.hasZ = true; + options.hasM = true; + geometryType = wkbType - 3000; + } + else { + geometryType = wkbType; + } + } + else { + if (wkbType & 0x80000000) + options.hasZ = true; + if (wkbType & 0x40000000) + options.hasM = true; + + geometryType = wkbType & 0xF; + } + + switch (geometryType) { + case Types.wkb.Point: + return Point._parseWkb(binaryReader, options); + case Types.wkb.LineString: + return LineString._parseWkb(binaryReader, options); + case Types.wkb.Polygon: + return Polygon._parseWkb(binaryReader, options); + case Types.wkb.MultiPoint: + return MultiPoint._parseWkb(binaryReader, options); + case Types.wkb.MultiLineString: + return MultiLineString._parseWkb(binaryReader, options); + case Types.wkb.MultiPolygon: + return MultiPolygon._parseWkb(binaryReader, options); + case Types.wkb.GeometryCollection: + return GeometryCollection._parseWkb(binaryReader, options); + default: + throw new Error('GeometryType ' + geometryType + ' not supported'); + } +}; + +Geometry.parseTwkb = function (value) { + var binaryReader, + options = {}; + + if (value instanceof BinaryReader) + binaryReader = value; + else + binaryReader = new BinaryReader(value); + + var type = binaryReader.readUInt8(); + var metadataHeader = binaryReader.readUInt8(); + + var geometryType = type & 0x0F; + options.precision = ZigZag.decode(type >> 4); + options.precisionFactor = Math.pow(10, options.precision); + + options.hasBoundingBox = metadataHeader >> 0 & 1; + options.hasSizeAttribute = metadataHeader >> 1 & 1; + options.hasIdList = metadataHeader >> 2 & 1; + options.hasExtendedPrecision = metadataHeader >> 3 & 1; + options.isEmpty = metadataHeader >> 4 & 1; + + if (options.hasExtendedPrecision) { + var extendedPrecision = binaryReader.readUInt8(); + options.hasZ = (extendedPrecision & 0x01) === 0x01; + options.hasM = (extendedPrecision & 0x02) === 0x02; + + options.zPrecision = ZigZag.decode((extendedPrecision & 0x1C) >> 2); + options.zPrecisionFactor = Math.pow(10, options.zPrecision); + + options.mPrecision = ZigZag.decode((extendedPrecision & 0xE0) >> 5); + options.mPrecisionFactor = Math.pow(10, options.mPrecision); + } + else { + options.hasZ = false; + options.hasM = false; + } + + if (options.hasSizeAttribute) + binaryReader.readVarInt(); + if (options.hasBoundingBox) { + var dimensions = 2; + + if (options.hasZ) + dimensions++; + if (options.hasM) + dimensions++; + + for (var i = 0; i < dimensions; i++) { + binaryReader.readVarInt(); + binaryReader.readVarInt(); + } + } + + switch (geometryType) { + case Types.wkb.Point: + return Point._parseTwkb(binaryReader, options); + case Types.wkb.LineString: + return LineString._parseTwkb(binaryReader, options); + case Types.wkb.Polygon: + return Polygon._parseTwkb(binaryReader, options); + case Types.wkb.MultiPoint: + return MultiPoint._parseTwkb(binaryReader, options); + case Types.wkb.MultiLineString: + return MultiLineString._parseTwkb(binaryReader, options); + case Types.wkb.MultiPolygon: + return MultiPolygon._parseTwkb(binaryReader, options); + case Types.wkb.GeometryCollection: + return GeometryCollection._parseTwkb(binaryReader, options); + default: + throw new Error('GeometryType ' + geometryType + ' not supported'); + } +}; + +Geometry.parseGeoJSON = function (value) { + return Geometry._parseGeoJSON(value); +}; + +Geometry._parseGeoJSON = function (value, isSubGeometry) { + var geometry; + + switch (value.type) { + case Types.geoJSON.Point: + geometry = Point._parseGeoJSON(value); break; + case Types.geoJSON.LineString: + geometry = LineString._parseGeoJSON(value); break; + case Types.geoJSON.Polygon: + geometry = Polygon._parseGeoJSON(value); break; + case Types.geoJSON.MultiPoint: + geometry = MultiPoint._parseGeoJSON(value); break; + case Types.geoJSON.MultiLineString: + geometry = MultiLineString._parseGeoJSON(value); break; + case Types.geoJSON.MultiPolygon: + geometry = MultiPolygon._parseGeoJSON(value); break; + case Types.geoJSON.GeometryCollection: + geometry = GeometryCollection._parseGeoJSON(value); break; + default: + throw new Error('GeometryType ' + value.type + ' not supported'); + } + + if (value.crs && value.crs.type && value.crs.type === 'name' && value.crs.properties && value.crs.properties.name) { + var crs = value.crs.properties.name; + + if (crs.indexOf('EPSG:') === 0) + geometry.srid = parseInt(crs.substring(5)); + else if (crs.indexOf('urn:ogc:def:crs:EPSG::') === 0) + geometry.srid = parseInt(crs.substring(22)); + else + throw new Error('Unsupported crs: ' + crs); + } + else if (!isSubGeometry) { + geometry.srid = 4326; + } + + return geometry; +}; + +Geometry.prototype.toEwkt = function () { + return 'SRID=' + this.srid + ';' + this.toWkt(); +}; + +Geometry.prototype.toEwkb = function () { + var ewkb = new BinaryWriter(this._getWkbSize() + 4); + var wkb = this.toWkb(); + + ewkb.writeInt8(1); + ewkb.writeUInt32LE((wkb.slice(1, 5).readUInt32LE(0) | 0x20000000) >>> 0, true); + ewkb.writeUInt32LE(this.srid); + + ewkb.writeBuffer(wkb.slice(5)); + + return ewkb.buffer; +}; + +Geometry.prototype._getWktType = function (wktType, isEmpty) { + var wkt = wktType; + + if (this.hasZ && this.hasM) + wkt += ' ZM '; + else if (this.hasZ) + wkt += ' Z '; + else if (this.hasM) + wkt += ' M '; + + if (isEmpty && !this.hasZ && !this.hasM) + wkt += ' '; + + if (isEmpty) + wkt += 'EMPTY'; + + return wkt; +}; + +Geometry.prototype._getWktCoordinate = function (point) { + var coordinates = point.x + ' ' + point.y; + + if (this.hasZ) + coordinates += ' ' + point.z; + if (this.hasM) + coordinates += ' ' + point.m; + + return coordinates; +}; + +Geometry.prototype._writeWkbType = function (wkb, geometryType, parentOptions) { + var dimensionType = 0; + + if (typeof this.srid === 'undefined' && (!parentOptions || typeof parentOptions.srid === 'undefined')) { + if (this.hasZ && this.hasM) + dimensionType += 3000; + else if (this.hasZ) + dimensionType += 1000; + else if (this.hasM) + dimensionType += 2000; + } + else { + if (this.hasZ) + dimensionType |= 0x80000000; + if (this.hasM) + dimensionType |= 0x40000000; + } + + wkb.writeUInt32LE((dimensionType + geometryType) >>> 0, true); +}; + +Geometry.getTwkbPrecision = function (xyPrecision, zPrecision, mPrecision) { + return { + xy: xyPrecision, + z: zPrecision, + m: mPrecision, + xyFactor: Math.pow(10, xyPrecision), + zFactor: Math.pow(10, zPrecision), + mFactor: Math.pow(10, mPrecision) + }; +}; + +Geometry.prototype._writeTwkbHeader = function (twkb, geometryType, precision, isEmpty) { + var type = (ZigZag.encode(precision.xy) << 4) + geometryType; + var metadataHeader = (this.hasZ || this.hasM) << 3; + metadataHeader += isEmpty << 4; + + twkb.writeUInt8(type); + twkb.writeUInt8(metadataHeader); + + if (this.hasZ || this.hasM) { + var extendedPrecision = 0; + if (this.hasZ) + extendedPrecision |= 0x1; + if (this.hasM) + extendedPrecision |= 0x2; + + twkb.writeUInt8(extendedPrecision); + } +}; + +Geometry.prototype.toGeoJSON = function (options) { + var geoJSON = {}; + + if (this.srid) { + if (options) { + if (options.shortCrs) { + geoJSON.crs = { + type: 'name', + properties: { + name: 'EPSG:' + this.srid + } + }; + } + else if (options.longCrs) { + geoJSON.crs = { + type: 'name', + properties: { + name: 'urn:ogc:def:crs:EPSG::' + this.srid + } + }; + } + } + } + + return geoJSON; +}; }).call(this,{"isBuffer":require("../node_modules/is-buffer/index.js")}) },{"../node_modules/is-buffer/index.js":17,"./binaryreader":1,"./binarywriter":2,"./geometrycollection":4,"./linestring":5,"./multilinestring":6,"./multipoint":7,"./multipolygon":8,"./point":9,"./polygon":10,"./types":11,"./wktparser":12,"./zigzag.js":13}],4:[function(require,module,exports){ -module.exports = GeometryCollection; - -var util = require('util'); - -var Types = require('./types'); -var Geometry = require('./geometry'); -var BinaryWriter = require('./binarywriter'); - -function GeometryCollection(geometries, srid) { - Geometry.call(this); - - this.geometries = geometries || []; - this.srid = srid; - - if (this.geometries.length > 0) { - this.hasZ = this.geometries[0].hasZ; - this.hasM = this.geometries[0].hasM; - } -} - -util.inherits(GeometryCollection, Geometry); - -GeometryCollection.Z = function (geometries, srid) { - var geometryCollection = new GeometryCollection(geometries, srid); - geometryCollection.hasZ = true; - return geometryCollection; -}; - -GeometryCollection.M = function (geometries, srid) { - var geometryCollection = new GeometryCollection(geometries, srid); - geometryCollection.hasM = true; - return geometryCollection; -}; - -GeometryCollection.ZM = function (geometries, srid) { - var geometryCollection = new GeometryCollection(geometries, srid); - geometryCollection.hasZ = true; - geometryCollection.hasM = true; - return geometryCollection; -}; - -GeometryCollection._parseWkt = function (value, options) { - var geometryCollection = new GeometryCollection(); - geometryCollection.srid = options.srid; - geometryCollection.hasZ = options.hasZ; - geometryCollection.hasM = options.hasM; - - if (value.isMatch(['EMPTY'])) - return geometryCollection; - - value.expectGroupStart(); - - do { - geometryCollection.geometries.push(Geometry.parse(value)); - } while (value.isMatch([','])); - - value.expectGroupEnd(); - - return geometryCollection; -}; - -GeometryCollection._parseWkb = function (value, options) { - var geometryCollection = new GeometryCollection(); - geometryCollection.srid = options.srid; - geometryCollection.hasZ = options.hasZ; - geometryCollection.hasM = options.hasM; - - var geometryCount = value.readUInt32(); - - for (var i = 0; i < geometryCount; i++) - geometryCollection.geometries.push(Geometry.parse(value, options)); - - return geometryCollection; -}; - -GeometryCollection._parseTwkb = function (value, options) { - var geometryCollection = new GeometryCollection(); - geometryCollection.hasZ = options.hasZ; - geometryCollection.hasM = options.hasM; - - if (options.isEmpty) - return geometryCollection; - - var geometryCount = value.readVarInt(); - - for (var i = 0; i < geometryCount; i++) - geometryCollection.geometries.push(Geometry.parseTwkb(value)); - - return geometryCollection; -}; - -GeometryCollection._parseGeoJSON = function (value) { - var geometryCollection = new GeometryCollection(); - - for (var i = 0; i < value.geometries.length; i++) - geometryCollection.geometries.push(Geometry._parseGeoJSON(value.geometries[i], true)); - - if (geometryCollection.geometries.length > 0) - geometryCollection.hasZ = geometryCollection.geometries[0].hasZ; - - return geometryCollection; -}; - -GeometryCollection.prototype.toWkt = function () { - if (this.geometries.length === 0) - return this._getWktType(Types.wkt.GeometryCollection, true); - - var wkt = this._getWktType(Types.wkt.GeometryCollection, false) + '('; - - for (var i = 0; i < this.geometries.length; i++) - wkt += this.geometries[i].toWkt() + ','; - - wkt = wkt.slice(0, -1); - wkt += ')'; - - return wkt; -}; - -GeometryCollection.prototype.toWkb = function () { - var wkb = new BinaryWriter(this._getWkbSize()); - - wkb.writeInt8(1); - - this._writeWkbType(wkb, Types.wkb.GeometryCollection); - wkb.writeUInt32LE(this.geometries.length); - - for (var i = 0; i < this.geometries.length; i++) - wkb.writeBuffer(this.geometries[i].toWkb({ srid: this.srid })); - - return wkb.buffer; -}; - -GeometryCollection.prototype.toTwkb = function () { - var twkb = new BinaryWriter(0, true); - - var precision = Geometry.getTwkbPrecision(5, 0, 0); - var isEmpty = this.geometries.length === 0; - - this._writeTwkbHeader(twkb, Types.wkb.GeometryCollection, precision, isEmpty); - - if (this.geometries.length > 0) { - twkb.writeVarInt(this.geometries.length); - - for (var i = 0; i < this.geometries.length; i++) - twkb.writeBuffer(this.geometries[i].toTwkb()); - } - - return twkb.buffer; -}; - -GeometryCollection.prototype._getWkbSize = function () { - var size = 1 + 4 + 4; - - for (var i = 0; i < this.geometries.length; i++) - size += this.geometries[i]._getWkbSize(); - - return size; -}; - -GeometryCollection.prototype.toGeoJSON = function (options) { - var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); - geoJSON.type = Types.geoJSON.GeometryCollection; - geoJSON.geometries = []; - - for (var i = 0; i < this.geometries.length; i++) - geoJSON.geometries.push(this.geometries[i].toGeoJSON()); - - return geoJSON; -}; +module.exports = GeometryCollection; + +var util = require('util'); + +var Types = require('./types'); +var Geometry = require('./geometry'); +var BinaryWriter = require('./binarywriter'); + +function GeometryCollection(geometries, srid) { + Geometry.call(this); + + this.geometries = geometries || []; + this.srid = srid; + + if (this.geometries.length > 0) { + this.hasZ = this.geometries[0].hasZ; + this.hasM = this.geometries[0].hasM; + } +} + +util.inherits(GeometryCollection, Geometry); + +GeometryCollection.Z = function (geometries, srid) { + var geometryCollection = new GeometryCollection(geometries, srid); + geometryCollection.hasZ = true; + return geometryCollection; +}; + +GeometryCollection.M = function (geometries, srid) { + var geometryCollection = new GeometryCollection(geometries, srid); + geometryCollection.hasM = true; + return geometryCollection; +}; + +GeometryCollection.ZM = function (geometries, srid) { + var geometryCollection = new GeometryCollection(geometries, srid); + geometryCollection.hasZ = true; + geometryCollection.hasM = true; + return geometryCollection; +}; + +GeometryCollection._parseWkt = function (value, options) { + var geometryCollection = new GeometryCollection(); + geometryCollection.srid = options.srid; + geometryCollection.hasZ = options.hasZ; + geometryCollection.hasM = options.hasM; + + if (value.isMatch(['EMPTY'])) + return geometryCollection; + + value.expectGroupStart(); + + do { + geometryCollection.geometries.push(Geometry.parse(value)); + } while (value.isMatch([','])); + + value.expectGroupEnd(); + + return geometryCollection; +}; + +GeometryCollection._parseWkb = function (value, options) { + var geometryCollection = new GeometryCollection(); + geometryCollection.srid = options.srid; + geometryCollection.hasZ = options.hasZ; + geometryCollection.hasM = options.hasM; + + var geometryCount = value.readUInt32(); + + for (var i = 0; i < geometryCount; i++) + geometryCollection.geometries.push(Geometry.parse(value, options)); + + return geometryCollection; +}; + +GeometryCollection._parseTwkb = function (value, options) { + var geometryCollection = new GeometryCollection(); + geometryCollection.hasZ = options.hasZ; + geometryCollection.hasM = options.hasM; + + if (options.isEmpty) + return geometryCollection; + + var geometryCount = value.readVarInt(); + + for (var i = 0; i < geometryCount; i++) + geometryCollection.geometries.push(Geometry.parseTwkb(value)); + + return geometryCollection; +}; + +GeometryCollection._parseGeoJSON = function (value) { + var geometryCollection = new GeometryCollection(); + + for (var i = 0; i < value.geometries.length; i++) + geometryCollection.geometries.push(Geometry._parseGeoJSON(value.geometries[i], true)); + + if (geometryCollection.geometries.length > 0) + geometryCollection.hasZ = geometryCollection.geometries[0].hasZ; + + return geometryCollection; +}; + +GeometryCollection.prototype.toWkt = function () { + if (this.geometries.length === 0) + return this._getWktType(Types.wkt.GeometryCollection, true); + + var wkt = this._getWktType(Types.wkt.GeometryCollection, false) + '('; + + for (var i = 0; i < this.geometries.length; i++) + wkt += this.geometries[i].toWkt() + ','; + + wkt = wkt.slice(0, -1); + wkt += ')'; + + return wkt; +}; + +GeometryCollection.prototype.toWkb = function () { + var wkb = new BinaryWriter(this._getWkbSize()); + + wkb.writeInt8(1); + + this._writeWkbType(wkb, Types.wkb.GeometryCollection); + wkb.writeUInt32LE(this.geometries.length); + + for (var i = 0; i < this.geometries.length; i++) + wkb.writeBuffer(this.geometries[i].toWkb({ srid: this.srid })); + + return wkb.buffer; +}; + +GeometryCollection.prototype.toTwkb = function () { + var twkb = new BinaryWriter(0, true); + + var precision = Geometry.getTwkbPrecision(5, 0, 0); + var isEmpty = this.geometries.length === 0; + + this._writeTwkbHeader(twkb, Types.wkb.GeometryCollection, precision, isEmpty); + + if (this.geometries.length > 0) { + twkb.writeVarInt(this.geometries.length); + + for (var i = 0; i < this.geometries.length; i++) + twkb.writeBuffer(this.geometries[i].toTwkb()); + } + + return twkb.buffer; +}; + +GeometryCollection.prototype._getWkbSize = function () { + var size = 1 + 4 + 4; + + for (var i = 0; i < this.geometries.length; i++) + size += this.geometries[i]._getWkbSize(); + + return size; +}; + +GeometryCollection.prototype.toGeoJSON = function (options) { + var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); + geoJSON.type = Types.geoJSON.GeometryCollection; + geoJSON.geometries = []; + + for (var i = 0; i < this.geometries.length; i++) + geoJSON.geometries.push(this.geometries[i].toGeoJSON()); + + return geoJSON; +}; },{"./binarywriter":2,"./geometry":3,"./types":11,"util":20}],5:[function(require,module,exports){ -module.exports = LineString; - -var util = require('util'); - -var Geometry = require('./geometry'); -var Types = require('./types'); -var Point = require('./point'); -var BinaryWriter = require('./binarywriter'); - -function LineString(points, srid) { - Geometry.call(this); - - this.points = points || []; - this.srid = srid; - - if (this.points.length > 0) { - this.hasZ = this.points[0].hasZ; - this.hasM = this.points[0].hasM; - } -} - -util.inherits(LineString, Geometry); - -LineString.Z = function (points, srid) { - var lineString = new LineString(points, srid); - lineString.hasZ = true; - return lineString; -}; - -LineString.M = function (points, srid) { - var lineString = new LineString(points, srid); - lineString.hasM = true; - return lineString; -}; - -LineString.ZM = function (points, srid) { - var lineString = new LineString(points, srid); - lineString.hasZ = true; - lineString.hasM = true; - return lineString; -}; - -LineString._parseWkt = function (value, options) { - var lineString = new LineString(); - lineString.srid = options.srid; - lineString.hasZ = options.hasZ; - lineString.hasM = options.hasM; - - if (value.isMatch(['EMPTY'])) - return lineString; - - value.expectGroupStart(); - lineString.points.push.apply(lineString.points, value.matchCoordinates(options)); - value.expectGroupEnd(); - - return lineString; -}; - -LineString._parseWkb = function (value, options) { - var lineString = new LineString(); - lineString.srid = options.srid; - lineString.hasZ = options.hasZ; - lineString.hasM = options.hasM; - - var pointCount = value.readUInt32(); - - for (var i = 0; i < pointCount; i++) - lineString.points.push(Point._readWkbPoint(value, options)); - - return lineString; -}; - -LineString._parseTwkb = function (value, options) { - var lineString = new LineString(); - lineString.hasZ = options.hasZ; - lineString.hasM = options.hasM; - - if (options.isEmpty) - return lineString; - - var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); - var pointCount = value.readVarInt(); - - for (var i = 0; i < pointCount; i++) - lineString.points.push(Point._readTwkbPoint(value, options, previousPoint)); - - return lineString; -}; - -LineString._parseGeoJSON = function (value) { - var lineString = new LineString(); - - if (value.coordinates.length > 0) - lineString.hasZ = value.coordinates[0].length > 2; - - for (var i = 0; i < value.coordinates.length; i++) - lineString.points.push(Point._readGeoJSONPoint(value.coordinates[i])); - - return lineString; -}; - -LineString.prototype.toWkt = function () { - if (this.points.length === 0) - return this._getWktType(Types.wkt.LineString, true); - - return this._getWktType(Types.wkt.LineString, false) + this._toInnerWkt(); -}; - -LineString.prototype._toInnerWkt = function () { - var innerWkt = '('; - - for (var i = 0; i < this.points.length; i++) - innerWkt += this._getWktCoordinate(this.points[i]) + ','; - - innerWkt = innerWkt.slice(0, -1); - innerWkt += ')'; - - return innerWkt; -}; - -LineString.prototype.toWkb = function (parentOptions) { - var wkb = new BinaryWriter(this._getWkbSize()); - - wkb.writeInt8(1); - - this._writeWkbType(wkb, Types.wkb.LineString, parentOptions); - wkb.writeUInt32LE(this.points.length); - - for (var i = 0; i < this.points.length; i++) - this.points[i]._writeWkbPoint(wkb); - - return wkb.buffer; -}; - -LineString.prototype.toTwkb = function () { - var twkb = new BinaryWriter(0, true); - - var precision = Geometry.getTwkbPrecision(5, 0, 0); - var isEmpty = this.points.length === 0; - - this._writeTwkbHeader(twkb, Types.wkb.LineString, precision, isEmpty); - - if (this.points.length > 0) { - twkb.writeVarInt(this.points.length); - - var previousPoint = new Point(0, 0, 0, 0); - for (var i = 0; i < this.points.length; i++) - this.points[i]._writeTwkbPoint(twkb, precision, previousPoint); - } - - return twkb.buffer; -}; - -LineString.prototype._getWkbSize = function () { - var coordinateSize = 16; - - if (this.hasZ) - coordinateSize += 8; - if (this.hasM) - coordinateSize += 8; - - return 1 + 4 + 4 + (this.points.length * coordinateSize); -}; - -LineString.prototype.toGeoJSON = function (options) { - var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); - geoJSON.type = Types.geoJSON.LineString; - geoJSON.coordinates = []; - - for (var i = 0; i < this.points.length; i++) { - if (this.hasZ) - geoJSON.coordinates.push([this.points[i].x, this.points[i].y, this.points[i].z]); - else - geoJSON.coordinates.push([this.points[i].x, this.points[i].y]); - } - - return geoJSON; -}; +module.exports = LineString; + +var util = require('util'); + +var Geometry = require('./geometry'); +var Types = require('./types'); +var Point = require('./point'); +var BinaryWriter = require('./binarywriter'); + +function LineString(points, srid) { + Geometry.call(this); + + this.points = points || []; + this.srid = srid; + + if (this.points.length > 0) { + this.hasZ = this.points[0].hasZ; + this.hasM = this.points[0].hasM; + } +} + +util.inherits(LineString, Geometry); + +LineString.Z = function (points, srid) { + var lineString = new LineString(points, srid); + lineString.hasZ = true; + return lineString; +}; + +LineString.M = function (points, srid) { + var lineString = new LineString(points, srid); + lineString.hasM = true; + return lineString; +}; + +LineString.ZM = function (points, srid) { + var lineString = new LineString(points, srid); + lineString.hasZ = true; + lineString.hasM = true; + return lineString; +}; + +LineString._parseWkt = function (value, options) { + var lineString = new LineString(); + lineString.srid = options.srid; + lineString.hasZ = options.hasZ; + lineString.hasM = options.hasM; + + if (value.isMatch(['EMPTY'])) + return lineString; + + value.expectGroupStart(); + lineString.points.push.apply(lineString.points, value.matchCoordinates(options)); + value.expectGroupEnd(); + + return lineString; +}; + +LineString._parseWkb = function (value, options) { + var lineString = new LineString(); + lineString.srid = options.srid; + lineString.hasZ = options.hasZ; + lineString.hasM = options.hasM; + + var pointCount = value.readUInt32(); + + for (var i = 0; i < pointCount; i++) + lineString.points.push(Point._readWkbPoint(value, options)); + + return lineString; +}; + +LineString._parseTwkb = function (value, options) { + var lineString = new LineString(); + lineString.hasZ = options.hasZ; + lineString.hasM = options.hasM; + + if (options.isEmpty) + return lineString; + + var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); + var pointCount = value.readVarInt(); + + for (var i = 0; i < pointCount; i++) + lineString.points.push(Point._readTwkbPoint(value, options, previousPoint)); + + return lineString; +}; + +LineString._parseGeoJSON = function (value) { + var lineString = new LineString(); + + if (value.coordinates.length > 0) + lineString.hasZ = value.coordinates[0].length > 2; + + for (var i = 0; i < value.coordinates.length; i++) + lineString.points.push(Point._readGeoJSONPoint(value.coordinates[i])); + + return lineString; +}; + +LineString.prototype.toWkt = function () { + if (this.points.length === 0) + return this._getWktType(Types.wkt.LineString, true); + + return this._getWktType(Types.wkt.LineString, false) + this._toInnerWkt(); +}; + +LineString.prototype._toInnerWkt = function () { + var innerWkt = '('; + + for (var i = 0; i < this.points.length; i++) + innerWkt += this._getWktCoordinate(this.points[i]) + ','; + + innerWkt = innerWkt.slice(0, -1); + innerWkt += ')'; + + return innerWkt; +}; + +LineString.prototype.toWkb = function (parentOptions) { + var wkb = new BinaryWriter(this._getWkbSize()); + + wkb.writeInt8(1); + + this._writeWkbType(wkb, Types.wkb.LineString, parentOptions); + wkb.writeUInt32LE(this.points.length); + + for (var i = 0; i < this.points.length; i++) + this.points[i]._writeWkbPoint(wkb); + + return wkb.buffer; +}; + +LineString.prototype.toTwkb = function () { + var twkb = new BinaryWriter(0, true); + + var precision = Geometry.getTwkbPrecision(5, 0, 0); + var isEmpty = this.points.length === 0; + + this._writeTwkbHeader(twkb, Types.wkb.LineString, precision, isEmpty); + + if (this.points.length > 0) { + twkb.writeVarInt(this.points.length); + + var previousPoint = new Point(0, 0, 0, 0); + for (var i = 0; i < this.points.length; i++) + this.points[i]._writeTwkbPoint(twkb, precision, previousPoint); + } + + return twkb.buffer; +}; + +LineString.prototype._getWkbSize = function () { + var coordinateSize = 16; + + if (this.hasZ) + coordinateSize += 8; + if (this.hasM) + coordinateSize += 8; + + return 1 + 4 + 4 + (this.points.length * coordinateSize); +}; + +LineString.prototype.toGeoJSON = function (options) { + var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); + geoJSON.type = Types.geoJSON.LineString; + geoJSON.coordinates = []; + + for (var i = 0; i < this.points.length; i++) { + if (this.hasZ) + geoJSON.coordinates.push([this.points[i].x, this.points[i].y, this.points[i].z]); + else + geoJSON.coordinates.push([this.points[i].x, this.points[i].y]); + } + + return geoJSON; +}; },{"./binarywriter":2,"./geometry":3,"./point":9,"./types":11,"util":20}],6:[function(require,module,exports){ -module.exports = MultiLineString; - -var util = require('util'); - -var Types = require('./types'); -var Geometry = require('./geometry'); -var Point = require('./point'); -var LineString = require('./linestring'); -var BinaryWriter = require('./binarywriter'); - -function MultiLineString(lineStrings, srid) { - Geometry.call(this); - - this.lineStrings = lineStrings || []; - this.srid = srid; - - if (this.lineStrings.length > 0) { - this.hasZ = this.lineStrings[0].hasZ; - this.hasM = this.lineStrings[0].hasM; - } -} - -util.inherits(MultiLineString, Geometry); - -MultiLineString.Z = function (lineStrings, srid) { - var multiLineString = new MultiLineString(lineStrings, srid); - multiLineString.hasZ = true; - return multiLineString; -}; - -MultiLineString.M = function (lineStrings, srid) { - var multiLineString = new MultiLineString(lineStrings, srid); - multiLineString.hasM = true; - return multiLineString; -}; - -MultiLineString.ZM = function (lineStrings, srid) { - var multiLineString = new MultiLineString(lineStrings, srid); - multiLineString.hasZ = true; - multiLineString.hasM = true; - return multiLineString; -}; - -MultiLineString._parseWkt = function (value, options) { - var multiLineString = new MultiLineString(); - multiLineString.srid = options.srid; - multiLineString.hasZ = options.hasZ; - multiLineString.hasM = options.hasM; - - if (value.isMatch(['EMPTY'])) - return multiLineString; - - value.expectGroupStart(); - - do { - value.expectGroupStart(); - multiLineString.lineStrings.push(new LineString(value.matchCoordinates(options))); - value.expectGroupEnd(); - } while (value.isMatch([','])); - - value.expectGroupEnd(); - - return multiLineString; -}; - -MultiLineString._parseWkb = function (value, options) { - var multiLineString = new MultiLineString(); - multiLineString.srid = options.srid; - multiLineString.hasZ = options.hasZ; - multiLineString.hasM = options.hasM; - - var lineStringCount = value.readUInt32(); - - for (var i = 0; i < lineStringCount; i++) - multiLineString.lineStrings.push(Geometry.parse(value, options)); - - return multiLineString; -}; - -MultiLineString._parseTwkb = function (value, options) { - var multiLineString = new MultiLineString(); - multiLineString.hasZ = options.hasZ; - multiLineString.hasM = options.hasM; - - if (options.isEmpty) - return multiLineString; - - var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); - var lineStringCount = value.readVarInt(); - - for (var i = 0; i < lineStringCount; i++) { - var lineString = new LineString(); - lineString.hasZ = options.hasZ; - lineString.hasM = options.hasM; - - var pointCount = value.readVarInt(); - - for (var j = 0; j < pointCount; j++) - lineString.points.push(Point._readTwkbPoint(value, options, previousPoint)); - - multiLineString.lineStrings.push(lineString); - } - - return multiLineString; -}; - -MultiLineString._parseGeoJSON = function (value) { - var multiLineString = new MultiLineString(); - - if (value.coordinates.length > 0 && value.coordinates[0].length > 0) - multiLineString.hasZ = value.coordinates[0][0].length > 2; - - for (var i = 0; i < value.coordinates.length; i++) - multiLineString.lineStrings.push(LineString._parseGeoJSON({ coordinates: value.coordinates[i] })); - - return multiLineString; -}; - -MultiLineString.prototype.toWkt = function () { - if (this.lineStrings.length === 0) - return this._getWktType(Types.wkt.MultiLineString, true); - - var wkt = this._getWktType(Types.wkt.MultiLineString, false) + '('; - - for (var i = 0; i < this.lineStrings.length; i++) - wkt += this.lineStrings[i]._toInnerWkt() + ','; - - wkt = wkt.slice(0, -1); - wkt += ')'; - - return wkt; -}; - -MultiLineString.prototype.toWkb = function () { - var wkb = new BinaryWriter(this._getWkbSize()); - - wkb.writeInt8(1); - - this._writeWkbType(wkb, Types.wkb.MultiLineString); - wkb.writeUInt32LE(this.lineStrings.length); - - for (var i = 0; i < this.lineStrings.length; i++) - wkb.writeBuffer(this.lineStrings[i].toWkb({ srid: this.srid })); - - return wkb.buffer; -}; - -MultiLineString.prototype.toTwkb = function () { - var twkb = new BinaryWriter(0, true); - - var precision = Geometry.getTwkbPrecision(5, 0, 0); - var isEmpty = this.lineStrings.length === 0; - - this._writeTwkbHeader(twkb, Types.wkb.MultiLineString, precision, isEmpty); - - if (this.lineStrings.length > 0) { - twkb.writeVarInt(this.lineStrings.length); - - var previousPoint = new Point(0, 0, 0, 0); - for (var i = 0; i < this.lineStrings.length; i++) { - twkb.writeVarInt(this.lineStrings[i].points.length); - - for (var j = 0; j < this.lineStrings[i].points.length; j++) - this.lineStrings[i].points[j]._writeTwkbPoint(twkb, precision, previousPoint); - } - } - - return twkb.buffer; -}; - -MultiLineString.prototype._getWkbSize = function () { - var size = 1 + 4 + 4; - - for (var i = 0; i < this.lineStrings.length; i++) - size += this.lineStrings[i]._getWkbSize(); - - return size; -}; - -MultiLineString.prototype.toGeoJSON = function (options) { - var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); - geoJSON.type = Types.geoJSON.MultiLineString; - geoJSON.coordinates = []; - - for (var i = 0; i < this.lineStrings.length; i++) - geoJSON.coordinates.push(this.lineStrings[i].toGeoJSON().coordinates); - - return geoJSON; -}; +module.exports = MultiLineString; + +var util = require('util'); + +var Types = require('./types'); +var Geometry = require('./geometry'); +var Point = require('./point'); +var LineString = require('./linestring'); +var BinaryWriter = require('./binarywriter'); + +function MultiLineString(lineStrings, srid) { + Geometry.call(this); + + this.lineStrings = lineStrings || []; + this.srid = srid; + + if (this.lineStrings.length > 0) { + this.hasZ = this.lineStrings[0].hasZ; + this.hasM = this.lineStrings[0].hasM; + } +} + +util.inherits(MultiLineString, Geometry); + +MultiLineString.Z = function (lineStrings, srid) { + var multiLineString = new MultiLineString(lineStrings, srid); + multiLineString.hasZ = true; + return multiLineString; +}; + +MultiLineString.M = function (lineStrings, srid) { + var multiLineString = new MultiLineString(lineStrings, srid); + multiLineString.hasM = true; + return multiLineString; +}; + +MultiLineString.ZM = function (lineStrings, srid) { + var multiLineString = new MultiLineString(lineStrings, srid); + multiLineString.hasZ = true; + multiLineString.hasM = true; + return multiLineString; +}; + +MultiLineString._parseWkt = function (value, options) { + var multiLineString = new MultiLineString(); + multiLineString.srid = options.srid; + multiLineString.hasZ = options.hasZ; + multiLineString.hasM = options.hasM; + + if (value.isMatch(['EMPTY'])) + return multiLineString; + + value.expectGroupStart(); + + do { + value.expectGroupStart(); + multiLineString.lineStrings.push(new LineString(value.matchCoordinates(options))); + value.expectGroupEnd(); + } while (value.isMatch([','])); + + value.expectGroupEnd(); + + return multiLineString; +}; + +MultiLineString._parseWkb = function (value, options) { + var multiLineString = new MultiLineString(); + multiLineString.srid = options.srid; + multiLineString.hasZ = options.hasZ; + multiLineString.hasM = options.hasM; + + var lineStringCount = value.readUInt32(); + + for (var i = 0; i < lineStringCount; i++) + multiLineString.lineStrings.push(Geometry.parse(value, options)); + + return multiLineString; +}; + +MultiLineString._parseTwkb = function (value, options) { + var multiLineString = new MultiLineString(); + multiLineString.hasZ = options.hasZ; + multiLineString.hasM = options.hasM; + + if (options.isEmpty) + return multiLineString; + + var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); + var lineStringCount = value.readVarInt(); + + for (var i = 0; i < lineStringCount; i++) { + var lineString = new LineString(); + lineString.hasZ = options.hasZ; + lineString.hasM = options.hasM; + + var pointCount = value.readVarInt(); + + for (var j = 0; j < pointCount; j++) + lineString.points.push(Point._readTwkbPoint(value, options, previousPoint)); + + multiLineString.lineStrings.push(lineString); + } + + return multiLineString; +}; + +MultiLineString._parseGeoJSON = function (value) { + var multiLineString = new MultiLineString(); + + if (value.coordinates.length > 0 && value.coordinates[0].length > 0) + multiLineString.hasZ = value.coordinates[0][0].length > 2; + + for (var i = 0; i < value.coordinates.length; i++) + multiLineString.lineStrings.push(LineString._parseGeoJSON({ coordinates: value.coordinates[i] })); + + return multiLineString; +}; + +MultiLineString.prototype.toWkt = function () { + if (this.lineStrings.length === 0) + return this._getWktType(Types.wkt.MultiLineString, true); + + var wkt = this._getWktType(Types.wkt.MultiLineString, false) + '('; + + for (var i = 0; i < this.lineStrings.length; i++) + wkt += this.lineStrings[i]._toInnerWkt() + ','; + + wkt = wkt.slice(0, -1); + wkt += ')'; + + return wkt; +}; + +MultiLineString.prototype.toWkb = function () { + var wkb = new BinaryWriter(this._getWkbSize()); + + wkb.writeInt8(1); + + this._writeWkbType(wkb, Types.wkb.MultiLineString); + wkb.writeUInt32LE(this.lineStrings.length); + + for (var i = 0; i < this.lineStrings.length; i++) + wkb.writeBuffer(this.lineStrings[i].toWkb({ srid: this.srid })); + + return wkb.buffer; +}; + +MultiLineString.prototype.toTwkb = function () { + var twkb = new BinaryWriter(0, true); + + var precision = Geometry.getTwkbPrecision(5, 0, 0); + var isEmpty = this.lineStrings.length === 0; + + this._writeTwkbHeader(twkb, Types.wkb.MultiLineString, precision, isEmpty); + + if (this.lineStrings.length > 0) { + twkb.writeVarInt(this.lineStrings.length); + + var previousPoint = new Point(0, 0, 0, 0); + for (var i = 0; i < this.lineStrings.length; i++) { + twkb.writeVarInt(this.lineStrings[i].points.length); + + for (var j = 0; j < this.lineStrings[i].points.length; j++) + this.lineStrings[i].points[j]._writeTwkbPoint(twkb, precision, previousPoint); + } + } + + return twkb.buffer; +}; + +MultiLineString.prototype._getWkbSize = function () { + var size = 1 + 4 + 4; + + for (var i = 0; i < this.lineStrings.length; i++) + size += this.lineStrings[i]._getWkbSize(); + + return size; +}; + +MultiLineString.prototype.toGeoJSON = function (options) { + var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); + geoJSON.type = Types.geoJSON.MultiLineString; + geoJSON.coordinates = []; + + for (var i = 0; i < this.lineStrings.length; i++) + geoJSON.coordinates.push(this.lineStrings[i].toGeoJSON().coordinates); + + return geoJSON; +}; },{"./binarywriter":2,"./geometry":3,"./linestring":5,"./point":9,"./types":11,"util":20}],7:[function(require,module,exports){ -module.exports = MultiPoint; - -var util = require('util'); - -var Types = require('./types'); -var Geometry = require('./geometry'); -var Point = require('./point'); -var BinaryWriter = require('./binarywriter'); - -function MultiPoint(points, srid) { - Geometry.call(this); - - this.points = points || []; - this.srid = srid; - - if (this.points.length > 0) { - this.hasZ = this.points[0].hasZ; - this.hasM = this.points[0].hasM; - } -} - -util.inherits(MultiPoint, Geometry); - -MultiPoint.Z = function (points, srid) { - var multiPoint = new MultiPoint(points, srid); - multiPoint.hasZ = true; - return multiPoint; -}; - -MultiPoint.M = function (points, srid) { - var multiPoint = new MultiPoint(points, srid); - multiPoint.hasM = true; - return multiPoint; -}; - -MultiPoint.ZM = function (points, srid) { - var multiPoint = new MultiPoint(points, srid); - multiPoint.hasZ = true; - multiPoint.hasM = true; - return multiPoint; -}; - -MultiPoint._parseWkt = function (value, options) { - var multiPoint = new MultiPoint(); - multiPoint.srid = options.srid; - multiPoint.hasZ = options.hasZ; - multiPoint.hasM = options.hasM; - - if (value.isMatch(['EMPTY'])) - return multiPoint; - - value.expectGroupStart(); - multiPoint.points.push.apply(multiPoint.points, value.matchCoordinates(options)); - value.expectGroupEnd(); - - return multiPoint; -}; - -MultiPoint._parseWkb = function (value, options) { - var multiPoint = new MultiPoint(); - multiPoint.srid = options.srid; - multiPoint.hasZ = options.hasZ; - multiPoint.hasM = options.hasM; - - var pointCount = value.readUInt32(); - - for (var i = 0; i < pointCount; i++) - multiPoint.points.push(Geometry.parse(value, options)); - - return multiPoint; -}; - -MultiPoint._parseTwkb = function (value, options) { - var multiPoint = new MultiPoint(); - multiPoint.hasZ = options.hasZ; - multiPoint.hasM = options.hasM; - - if (options.isEmpty) - return multiPoint; - - var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); - var pointCount = value.readVarInt(); - - for (var i = 0; i < pointCount; i++) - multiPoint.points.push(Point._readTwkbPoint(value, options, previousPoint)); - - return multiPoint; -}; - -MultiPoint._parseGeoJSON = function (value) { - var multiPoint = new MultiPoint(); - - if (value.coordinates.length > 0) - multiPoint.hasZ = value.coordinates[0].length > 2; - - for (var i = 0; i < value.coordinates.length; i++) - multiPoint.points.push(Point._parseGeoJSON({ coordinates: value.coordinates[i] })); - - return multiPoint; -}; - -MultiPoint.prototype.toWkt = function () { - if (this.points.length === 0) - return this._getWktType(Types.wkt.MultiPoint, true); - - var wkt = this._getWktType(Types.wkt.MultiPoint, false) + '('; - - for (var i = 0; i < this.points.length; i++) - wkt += this._getWktCoordinate(this.points[i]) + ','; - - wkt = wkt.slice(0, -1); - wkt += ')'; - - return wkt; -}; - -MultiPoint.prototype.toWkb = function () { - var wkb = new BinaryWriter(this._getWkbSize()); - - wkb.writeInt8(1); - - this._writeWkbType(wkb, Types.wkb.MultiPoint); - wkb.writeUInt32LE(this.points.length); - - for (var i = 0; i < this.points.length; i++) - wkb.writeBuffer(this.points[i].toWkb({ srid: this.srid })); - - return wkb.buffer; -}; - -MultiPoint.prototype.toTwkb = function () { - var twkb = new BinaryWriter(0, true); - - var precision = Geometry.getTwkbPrecision(5, 0, 0); - var isEmpty = this.points.length === 0; - - this._writeTwkbHeader(twkb, Types.wkb.MultiPoint, precision, isEmpty); - - if (this.points.length > 0) { - twkb.writeVarInt(this.points.length); - - var previousPoint = new Point(0, 0, 0, 0); - for (var i = 0; i < this.points.length; i++) - this.points[i]._writeTwkbPoint(twkb, precision, previousPoint); - } - - return twkb.buffer; -}; - -MultiPoint.prototype._getWkbSize = function () { - var coordinateSize = 16; - - if (this.hasZ) - coordinateSize += 8; - if (this.hasM) - coordinateSize += 8; - - coordinateSize += 5; - - return 1 + 4 + 4 + (this.points.length * coordinateSize); -}; - -MultiPoint.prototype.toGeoJSON = function (options) { - var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); - geoJSON.type = Types.geoJSON.MultiPoint; - geoJSON.coordinates = []; - - for (var i = 0; i < this.points.length; i++) - geoJSON.coordinates.push(this.points[i].toGeoJSON().coordinates); - - return geoJSON; -}; +module.exports = MultiPoint; + +var util = require('util'); + +var Types = require('./types'); +var Geometry = require('./geometry'); +var Point = require('./point'); +var BinaryWriter = require('./binarywriter'); + +function MultiPoint(points, srid) { + Geometry.call(this); + + this.points = points || []; + this.srid = srid; + + if (this.points.length > 0) { + this.hasZ = this.points[0].hasZ; + this.hasM = this.points[0].hasM; + } +} + +util.inherits(MultiPoint, Geometry); + +MultiPoint.Z = function (points, srid) { + var multiPoint = new MultiPoint(points, srid); + multiPoint.hasZ = true; + return multiPoint; +}; + +MultiPoint.M = function (points, srid) { + var multiPoint = new MultiPoint(points, srid); + multiPoint.hasM = true; + return multiPoint; +}; + +MultiPoint.ZM = function (points, srid) { + var multiPoint = new MultiPoint(points, srid); + multiPoint.hasZ = true; + multiPoint.hasM = true; + return multiPoint; +}; + +MultiPoint._parseWkt = function (value, options) { + var multiPoint = new MultiPoint(); + multiPoint.srid = options.srid; + multiPoint.hasZ = options.hasZ; + multiPoint.hasM = options.hasM; + + if (value.isMatch(['EMPTY'])) + return multiPoint; + + value.expectGroupStart(); + multiPoint.points.push.apply(multiPoint.points, value.matchCoordinates(options)); + value.expectGroupEnd(); + + return multiPoint; +}; + +MultiPoint._parseWkb = function (value, options) { + var multiPoint = new MultiPoint(); + multiPoint.srid = options.srid; + multiPoint.hasZ = options.hasZ; + multiPoint.hasM = options.hasM; + + var pointCount = value.readUInt32(); + + for (var i = 0; i < pointCount; i++) + multiPoint.points.push(Geometry.parse(value, options)); + + return multiPoint; +}; + +MultiPoint._parseTwkb = function (value, options) { + var multiPoint = new MultiPoint(); + multiPoint.hasZ = options.hasZ; + multiPoint.hasM = options.hasM; + + if (options.isEmpty) + return multiPoint; + + var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); + var pointCount = value.readVarInt(); + + for (var i = 0; i < pointCount; i++) + multiPoint.points.push(Point._readTwkbPoint(value, options, previousPoint)); + + return multiPoint; +}; + +MultiPoint._parseGeoJSON = function (value) { + var multiPoint = new MultiPoint(); + + if (value.coordinates.length > 0) + multiPoint.hasZ = value.coordinates[0].length > 2; + + for (var i = 0; i < value.coordinates.length; i++) + multiPoint.points.push(Point._parseGeoJSON({ coordinates: value.coordinates[i] })); + + return multiPoint; +}; + +MultiPoint.prototype.toWkt = function () { + if (this.points.length === 0) + return this._getWktType(Types.wkt.MultiPoint, true); + + var wkt = this._getWktType(Types.wkt.MultiPoint, false) + '('; + + for (var i = 0; i < this.points.length; i++) + wkt += this._getWktCoordinate(this.points[i]) + ','; + + wkt = wkt.slice(0, -1); + wkt += ')'; + + return wkt; +}; + +MultiPoint.prototype.toWkb = function () { + var wkb = new BinaryWriter(this._getWkbSize()); + + wkb.writeInt8(1); + + this._writeWkbType(wkb, Types.wkb.MultiPoint); + wkb.writeUInt32LE(this.points.length); + + for (var i = 0; i < this.points.length; i++) + wkb.writeBuffer(this.points[i].toWkb({ srid: this.srid })); + + return wkb.buffer; +}; + +MultiPoint.prototype.toTwkb = function () { + var twkb = new BinaryWriter(0, true); + + var precision = Geometry.getTwkbPrecision(5, 0, 0); + var isEmpty = this.points.length === 0; + + this._writeTwkbHeader(twkb, Types.wkb.MultiPoint, precision, isEmpty); + + if (this.points.length > 0) { + twkb.writeVarInt(this.points.length); + + var previousPoint = new Point(0, 0, 0, 0); + for (var i = 0; i < this.points.length; i++) + this.points[i]._writeTwkbPoint(twkb, precision, previousPoint); + } + + return twkb.buffer; +}; + +MultiPoint.prototype._getWkbSize = function () { + var coordinateSize = 16; + + if (this.hasZ) + coordinateSize += 8; + if (this.hasM) + coordinateSize += 8; + + coordinateSize += 5; + + return 1 + 4 + 4 + (this.points.length * coordinateSize); +}; + +MultiPoint.prototype.toGeoJSON = function (options) { + var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); + geoJSON.type = Types.geoJSON.MultiPoint; + geoJSON.coordinates = []; + + for (var i = 0; i < this.points.length; i++) + geoJSON.coordinates.push(this.points[i].toGeoJSON().coordinates); + + return geoJSON; +}; },{"./binarywriter":2,"./geometry":3,"./point":9,"./types":11,"util":20}],8:[function(require,module,exports){ -module.exports = MultiPolygon; - -var util = require('util'); - -var Types = require('./types'); -var Geometry = require('./geometry'); -var Point = require('./point'); -var Polygon = require('./polygon'); -var BinaryWriter = require('./binarywriter'); - -function MultiPolygon(polygons, srid) { - Geometry.call(this); - - this.polygons = polygons || []; - this.srid = srid; - - if (this.polygons.length > 0) { - this.hasZ = this.polygons[0].hasZ; - this.hasM = this.polygons[0].hasM; - } -} - -util.inherits(MultiPolygon, Geometry); - -MultiPolygon.Z = function (polygons, srid) { - var multiPolygon = new MultiPolygon(polygons, srid); - multiPolygon.hasZ = true; - return multiPolygon; -}; - -MultiPolygon.M = function (polygons, srid) { - var multiPolygon = new MultiPolygon(polygons, srid); - multiPolygon.hasM = true; - return multiPolygon; -}; - -MultiPolygon.ZM = function (polygons, srid) { - var multiPolygon = new MultiPolygon(polygons, srid); - multiPolygon.hasZ = true; - multiPolygon.hasM = true; - return multiPolygon; -}; - -MultiPolygon._parseWkt = function (value, options) { - var multiPolygon = new MultiPolygon(); - multiPolygon.srid = options.srid; - multiPolygon.hasZ = options.hasZ; - multiPolygon.hasM = options.hasM; - - if (value.isMatch(['EMPTY'])) - return multiPolygon; - - value.expectGroupStart(); - - do { - value.expectGroupStart(); - - var exteriorRing = []; - var interiorRings = []; - - value.expectGroupStart(); - exteriorRing.push.apply(exteriorRing, value.matchCoordinates(options)); - value.expectGroupEnd(); - - while (value.isMatch([','])) { - value.expectGroupStart(); - interiorRings.push(value.matchCoordinates(options)); - value.expectGroupEnd(); - } - - multiPolygon.polygons.push(new Polygon(exteriorRing, interiorRings)); - - value.expectGroupEnd(); - - } while (value.isMatch([','])); - - value.expectGroupEnd(); - - return multiPolygon; -}; - -MultiPolygon._parseWkb = function (value, options) { - var multiPolygon = new MultiPolygon(); - multiPolygon.srid = options.srid; - multiPolygon.hasZ = options.hasZ; - multiPolygon.hasM = options.hasM; - - var polygonCount = value.readUInt32(); - - for (var i = 0; i < polygonCount; i++) - multiPolygon.polygons.push(Geometry.parse(value, options)); - - return multiPolygon; -}; - -MultiPolygon._parseTwkb = function (value, options) { - var multiPolygon = new MultiPolygon(); - multiPolygon.hasZ = options.hasZ; - multiPolygon.hasM = options.hasM; - - if (options.isEmpty) - return multiPolygon; - - var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); - var polygonCount = value.readVarInt(); - - for (var i = 0; i < polygonCount; i++) { - var polygon = new Polygon(); - polygon.hasZ = options.hasZ; - polygon.hasM = options.hasM; - - var ringCount = value.readVarInt(); - var exteriorRingCount = value.readVarInt(); - - for (var j = 0; j < exteriorRingCount; j++) - polygon.exteriorRing.push(Point._readTwkbPoint(value, options, previousPoint)); - - for (j = 1; j < ringCount; j++) { - var interiorRing = []; - - var interiorRingCount = value.readVarInt(); - - for (var k = 0; k < interiorRingCount; k++) - interiorRing.push(Point._readTwkbPoint(value, options, previousPoint)); - - polygon.interiorRings.push(interiorRing); - } - - multiPolygon.polygons.push(polygon); - } - - return multiPolygon; -}; - -MultiPolygon._parseGeoJSON = function (value) { - var multiPolygon = new MultiPolygon(); - - if (value.coordinates.length > 0 && value.coordinates[0].length > 0 && value.coordinates[0][0].length > 0) - multiPolygon.hasZ = value.coordinates[0][0][0].length > 2; - - for (var i = 0; i < value.coordinates.length; i++) - multiPolygon.polygons.push(Polygon._parseGeoJSON({ coordinates: value.coordinates[i] })); - - return multiPolygon; -}; - -MultiPolygon.prototype.toWkt = function () { - if (this.polygons.length === 0) - return this._getWktType(Types.wkt.MultiPolygon, true); - - var wkt = this._getWktType(Types.wkt.MultiPolygon, false) + '('; - - for (var i = 0; i < this.polygons.length; i++) - wkt += this.polygons[i]._toInnerWkt() + ','; - - wkt = wkt.slice(0, -1); - wkt += ')'; - - return wkt; -}; - -MultiPolygon.prototype.toWkb = function () { - var wkb = new BinaryWriter(this._getWkbSize()); - - wkb.writeInt8(1); - - this._writeWkbType(wkb, Types.wkb.MultiPolygon); - wkb.writeUInt32LE(this.polygons.length); - - for (var i = 0; i < this.polygons.length; i++) - wkb.writeBuffer(this.polygons[i].toWkb({ srid: this.srid })); - - return wkb.buffer; -}; - -MultiPolygon.prototype.toTwkb = function () { - var twkb = new BinaryWriter(0, true); - - var precision = Geometry.getTwkbPrecision(5, 0, 0); - var isEmpty = this.polygons.length === 0; - - this._writeTwkbHeader(twkb, Types.wkb.MultiPolygon, precision, isEmpty); - - if (this.polygons.length > 0) { - twkb.writeVarInt(this.polygons.length); - - var previousPoint = new Point(0, 0, 0, 0); - for (var i = 0; i < this.polygons.length; i++) { - twkb.writeVarInt(1 + this.polygons[i].interiorRings.length); - - twkb.writeVarInt(this.polygons[i].exteriorRing.length); - - for (var j = 0; j < this.polygons[i].exteriorRing.length; j++) - this.polygons[i].exteriorRing[j]._writeTwkbPoint(twkb, precision, previousPoint); - - for (j = 0; j < this.polygons[i].interiorRings.length; j++) { - twkb.writeVarInt(this.polygons[i].interiorRings[j].length); - - for (var k = 0; k < this.polygons[i].interiorRings[j].length; k++) - this.polygons[i].interiorRings[j][k]._writeTwkbPoint(twkb, precision, previousPoint); - } - } - } - - return twkb.buffer; -}; - -MultiPolygon.prototype._getWkbSize = function () { - var size = 1 + 4 + 4; - - for (var i = 0; i < this.polygons.length; i++) - size += this.polygons[i]._getWkbSize(); - - return size; -}; - -MultiPolygon.prototype.toGeoJSON = function (options) { - var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); - geoJSON.type = Types.geoJSON.MultiPolygon; - geoJSON.coordinates = []; - - for (var i = 0; i < this.polygons.length; i++) - geoJSON.coordinates.push(this.polygons[i].toGeoJSON().coordinates); - - return geoJSON; -}; +module.exports = MultiPolygon; + +var util = require('util'); + +var Types = require('./types'); +var Geometry = require('./geometry'); +var Point = require('./point'); +var Polygon = require('./polygon'); +var BinaryWriter = require('./binarywriter'); + +function MultiPolygon(polygons, srid) { + Geometry.call(this); + + this.polygons = polygons || []; + this.srid = srid; + + if (this.polygons.length > 0) { + this.hasZ = this.polygons[0].hasZ; + this.hasM = this.polygons[0].hasM; + } +} + +util.inherits(MultiPolygon, Geometry); + +MultiPolygon.Z = function (polygons, srid) { + var multiPolygon = new MultiPolygon(polygons, srid); + multiPolygon.hasZ = true; + return multiPolygon; +}; + +MultiPolygon.M = function (polygons, srid) { + var multiPolygon = new MultiPolygon(polygons, srid); + multiPolygon.hasM = true; + return multiPolygon; +}; + +MultiPolygon.ZM = function (polygons, srid) { + var multiPolygon = new MultiPolygon(polygons, srid); + multiPolygon.hasZ = true; + multiPolygon.hasM = true; + return multiPolygon; +}; + +MultiPolygon._parseWkt = function (value, options) { + var multiPolygon = new MultiPolygon(); + multiPolygon.srid = options.srid; + multiPolygon.hasZ = options.hasZ; + multiPolygon.hasM = options.hasM; + + if (value.isMatch(['EMPTY'])) + return multiPolygon; + + value.expectGroupStart(); + + do { + value.expectGroupStart(); + + var exteriorRing = []; + var interiorRings = []; + + value.expectGroupStart(); + exteriorRing.push.apply(exteriorRing, value.matchCoordinates(options)); + value.expectGroupEnd(); + + while (value.isMatch([','])) { + value.expectGroupStart(); + interiorRings.push(value.matchCoordinates(options)); + value.expectGroupEnd(); + } + + multiPolygon.polygons.push(new Polygon(exteriorRing, interiorRings)); + + value.expectGroupEnd(); + + } while (value.isMatch([','])); + + value.expectGroupEnd(); + + return multiPolygon; +}; + +MultiPolygon._parseWkb = function (value, options) { + var multiPolygon = new MultiPolygon(); + multiPolygon.srid = options.srid; + multiPolygon.hasZ = options.hasZ; + multiPolygon.hasM = options.hasM; + + var polygonCount = value.readUInt32(); + + for (var i = 0; i < polygonCount; i++) + multiPolygon.polygons.push(Geometry.parse(value, options)); + + return multiPolygon; +}; + +MultiPolygon._parseTwkb = function (value, options) { + var multiPolygon = new MultiPolygon(); + multiPolygon.hasZ = options.hasZ; + multiPolygon.hasM = options.hasM; + + if (options.isEmpty) + return multiPolygon; + + var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); + var polygonCount = value.readVarInt(); + + for (var i = 0; i < polygonCount; i++) { + var polygon = new Polygon(); + polygon.hasZ = options.hasZ; + polygon.hasM = options.hasM; + + var ringCount = value.readVarInt(); + var exteriorRingCount = value.readVarInt(); + + for (var j = 0; j < exteriorRingCount; j++) + polygon.exteriorRing.push(Point._readTwkbPoint(value, options, previousPoint)); + + for (j = 1; j < ringCount; j++) { + var interiorRing = []; + + var interiorRingCount = value.readVarInt(); + + for (var k = 0; k < interiorRingCount; k++) + interiorRing.push(Point._readTwkbPoint(value, options, previousPoint)); + + polygon.interiorRings.push(interiorRing); + } + + multiPolygon.polygons.push(polygon); + } + + return multiPolygon; +}; + +MultiPolygon._parseGeoJSON = function (value) { + var multiPolygon = new MultiPolygon(); + + if (value.coordinates.length > 0 && value.coordinates[0].length > 0 && value.coordinates[0][0].length > 0) + multiPolygon.hasZ = value.coordinates[0][0][0].length > 2; + + for (var i = 0; i < value.coordinates.length; i++) + multiPolygon.polygons.push(Polygon._parseGeoJSON({ coordinates: value.coordinates[i] })); + + return multiPolygon; +}; + +MultiPolygon.prototype.toWkt = function () { + if (this.polygons.length === 0) + return this._getWktType(Types.wkt.MultiPolygon, true); + + var wkt = this._getWktType(Types.wkt.MultiPolygon, false) + '('; + + for (var i = 0; i < this.polygons.length; i++) + wkt += this.polygons[i]._toInnerWkt() + ','; + + wkt = wkt.slice(0, -1); + wkt += ')'; + + return wkt; +}; + +MultiPolygon.prototype.toWkb = function () { + var wkb = new BinaryWriter(this._getWkbSize()); + + wkb.writeInt8(1); + + this._writeWkbType(wkb, Types.wkb.MultiPolygon); + wkb.writeUInt32LE(this.polygons.length); + + for (var i = 0; i < this.polygons.length; i++) + wkb.writeBuffer(this.polygons[i].toWkb({ srid: this.srid })); + + return wkb.buffer; +}; + +MultiPolygon.prototype.toTwkb = function () { + var twkb = new BinaryWriter(0, true); + + var precision = Geometry.getTwkbPrecision(5, 0, 0); + var isEmpty = this.polygons.length === 0; + + this._writeTwkbHeader(twkb, Types.wkb.MultiPolygon, precision, isEmpty); + + if (this.polygons.length > 0) { + twkb.writeVarInt(this.polygons.length); + + var previousPoint = new Point(0, 0, 0, 0); + for (var i = 0; i < this.polygons.length; i++) { + twkb.writeVarInt(1 + this.polygons[i].interiorRings.length); + + twkb.writeVarInt(this.polygons[i].exteriorRing.length); + + for (var j = 0; j < this.polygons[i].exteriorRing.length; j++) + this.polygons[i].exteriorRing[j]._writeTwkbPoint(twkb, precision, previousPoint); + + for (j = 0; j < this.polygons[i].interiorRings.length; j++) { + twkb.writeVarInt(this.polygons[i].interiorRings[j].length); + + for (var k = 0; k < this.polygons[i].interiorRings[j].length; k++) + this.polygons[i].interiorRings[j][k]._writeTwkbPoint(twkb, precision, previousPoint); + } + } + } + + return twkb.buffer; +}; + +MultiPolygon.prototype._getWkbSize = function () { + var size = 1 + 4 + 4; + + for (var i = 0; i < this.polygons.length; i++) + size += this.polygons[i]._getWkbSize(); + + return size; +}; + +MultiPolygon.prototype.toGeoJSON = function (options) { + var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); + geoJSON.type = Types.geoJSON.MultiPolygon; + geoJSON.coordinates = []; + + for (var i = 0; i < this.polygons.length; i++) + geoJSON.coordinates.push(this.polygons[i].toGeoJSON().coordinates); + + return geoJSON; +}; },{"./binarywriter":2,"./geometry":3,"./point":9,"./polygon":10,"./types":11,"util":20}],9:[function(require,module,exports){ -module.exports = Point; - -var util = require('util'); - -var Geometry = require('./geometry'); -var Types = require('./types'); -var BinaryWriter = require('./binarywriter'); -var ZigZag = require('./zigzag.js'); - -function Point(x, y, z, m, srid) { - Geometry.call(this); - - this.x = x; - this.y = y; - this.z = z; - this.m = m; - this.srid = srid; - - this.hasZ = typeof this.z !== 'undefined'; - this.hasM = typeof this.m !== 'undefined'; -} - -util.inherits(Point, Geometry); - -Point.Z = function (x, y, z, srid) { - var point = new Point(x, y, z, undefined, srid); - point.hasZ = true; - return point; -}; - -Point.M = function (x, y, m, srid) { - var point = new Point(x, y, undefined, m, srid); - point.hasM = true; - return point; -}; - -Point.ZM = function (x, y, z, m, srid) { - var point = new Point(x, y, z, m, srid); - point.hasZ = true; - point.hasM = true; - return point; -}; - -Point._parseWkt = function (value, options) { - var point = new Point(); - point.srid = options.srid; - point.hasZ = options.hasZ; - point.hasM = options.hasM; - - if (value.isMatch(['EMPTY'])) - return point; - - value.expectGroupStart(); - - var coordinate = value.matchCoordinate(options); - - point.x = coordinate.x; - point.y = coordinate.y; - point.z = coordinate.z; - point.m = coordinate.m; - - value.expectGroupEnd(); - - return point; -}; - -Point._parseWkb = function (value, options) { - var point = Point._readWkbPoint(value, options); - point.srid = options.srid; - return point; -}; - -Point._readWkbPoint = function (value, options) { - return new Point(value.readDouble(), value.readDouble(), - options.hasZ ? value.readDouble() : undefined, - options.hasM ? value.readDouble() : undefined); -}; - -Point._parseTwkb = function (value, options) { - var point = new Point(); - point.hasZ = options.hasZ; - point.hasM = options.hasM; - - if (options.isEmpty) - return point; - - point.x = ZigZag.decode(value.readVarInt()) / options.precisionFactor; - point.y = ZigZag.decode(value.readVarInt()) / options.precisionFactor; - point.z = options.hasZ ? ZigZag.decode(value.readVarInt()) / options.zPrecisionFactor : undefined; - point.m = options.hasM ? ZigZag.decode(value.readVarInt()) / options.mPrecisionFactor : undefined; - - return point; -}; - -Point._readTwkbPoint = function (value, options, previousPoint) { - previousPoint.x += ZigZag.decode(value.readVarInt()) / options.precisionFactor; - previousPoint.y += ZigZag.decode(value.readVarInt()) / options.precisionFactor; - - if (options.hasZ) - previousPoint.z += ZigZag.decode(value.readVarInt()) / options.zPrecisionFactor; - if (options.hasM) - previousPoint.m += ZigZag.decode(value.readVarInt()) / options.mPrecisionFactor; - - return new Point(previousPoint.x, previousPoint.y, previousPoint.z, previousPoint.m); -}; - -Point._parseGeoJSON = function (value) { - return Point._readGeoJSONPoint(value.coordinates); -}; - -Point._readGeoJSONPoint = function (coordinates) { - if (coordinates.length === 0) - return new Point(); - - if (coordinates.length > 2) - return new Point(coordinates[0], coordinates[1], coordinates[2]); - - return new Point(coordinates[0], coordinates[1]); -}; - -Point.prototype.toWkt = function () { - if (typeof this.x === 'undefined' && typeof this.y === 'undefined' && - typeof this.z === 'undefined' && typeof this.m === 'undefined') - return this._getWktType(Types.wkt.Point, true); - - return this._getWktType(Types.wkt.Point, false) + '(' + this._getWktCoordinate(this) + ')'; -}; - -Point.prototype.toWkb = function (parentOptions) { - var wkb = new BinaryWriter(this._getWkbSize()); - - wkb.writeInt8(1); - this._writeWkbType(wkb, Types.wkb.Point, parentOptions); - - if (typeof this.x === 'undefined' && typeof this.y === 'undefined') { - wkb.writeDoubleLE(NaN); - wkb.writeDoubleLE(NaN); - - if (this.hasZ) - wkb.writeDoubleLE(NaN); - if (this.hasM) - wkb.writeDoubleLE(NaN); - } - else { - this._writeWkbPoint(wkb); - } - - return wkb.buffer; -}; - -Point.prototype._writeWkbPoint = function (wkb) { - wkb.writeDoubleLE(this.x); - wkb.writeDoubleLE(this.y); - - if (this.hasZ) - wkb.writeDoubleLE(this.z); - if (this.hasM) - wkb.writeDoubleLE(this.m); -}; - -Point.prototype.toTwkb = function () { - var twkb = new BinaryWriter(0, true); - - var precision = Geometry.getTwkbPrecision(5, 0, 0); - var isEmpty = typeof this.x === 'undefined' && typeof this.y === 'undefined'; - - this._writeTwkbHeader(twkb, Types.wkb.Point, precision, isEmpty); - - if (!isEmpty) - this._writeTwkbPoint(twkb, precision, new Point(0, 0, 0, 0)); - - return twkb.buffer; -}; - -Point.prototype._writeTwkbPoint = function (twkb, precision, previousPoint) { - var x = this.x * precision.xyFactor; - var y = this.y * precision.xyFactor; - var z = this.z * precision.zFactor; - var m = this.m * precision.mFactor; - - twkb.writeVarInt(ZigZag.encode(x - previousPoint.x)); - twkb.writeVarInt(ZigZag.encode(y - previousPoint.y)); - if (this.hasZ) - twkb.writeVarInt(ZigZag.encode(z - previousPoint.z)); - if (this.hasM) - twkb.writeVarInt(ZigZag.encode(m - previousPoint.m)); - - previousPoint.x = x; - previousPoint.y = y; - previousPoint.z = z; - previousPoint.m = m; -}; - -Point.prototype._getWkbSize = function () { - var size = 1 + 4 + 8 + 8; - - if (this.hasZ) - size += 8; - if (this.hasM) - size += 8; - - return size; -}; - -Point.prototype.toGeoJSON = function (options) { - var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); - geoJSON.type = Types.geoJSON.Point; - - if (typeof this.x === 'undefined' && typeof this.y === 'undefined') - geoJSON.coordinates = []; - else if (typeof this.z !== 'undefined') - geoJSON.coordinates = [this.x, this.y, this.z]; - else - geoJSON.coordinates = [this.x, this.y]; - - return geoJSON; -}; +module.exports = Point; + +var util = require('util'); + +var Geometry = require('./geometry'); +var Types = require('./types'); +var BinaryWriter = require('./binarywriter'); +var ZigZag = require('./zigzag.js'); + +function Point(x, y, z, m, srid) { + Geometry.call(this); + + this.x = x; + this.y = y; + this.z = z; + this.m = m; + this.srid = srid; + + this.hasZ = typeof this.z !== 'undefined'; + this.hasM = typeof this.m !== 'undefined'; +} + +util.inherits(Point, Geometry); + +Point.Z = function (x, y, z, srid) { + var point = new Point(x, y, z, undefined, srid); + point.hasZ = true; + return point; +}; + +Point.M = function (x, y, m, srid) { + var point = new Point(x, y, undefined, m, srid); + point.hasM = true; + return point; +}; + +Point.ZM = function (x, y, z, m, srid) { + var point = new Point(x, y, z, m, srid); + point.hasZ = true; + point.hasM = true; + return point; +}; + +Point._parseWkt = function (value, options) { + var point = new Point(); + point.srid = options.srid; + point.hasZ = options.hasZ; + point.hasM = options.hasM; + + if (value.isMatch(['EMPTY'])) + return point; + + value.expectGroupStart(); + + var coordinate = value.matchCoordinate(options); + + point.x = coordinate.x; + point.y = coordinate.y; + point.z = coordinate.z; + point.m = coordinate.m; + + value.expectGroupEnd(); + + return point; +}; + +Point._parseWkb = function (value, options) { + var point = Point._readWkbPoint(value, options); + point.srid = options.srid; + return point; +}; + +Point._readWkbPoint = function (value, options) { + return new Point(value.readDouble(), value.readDouble(), + options.hasZ ? value.readDouble() : undefined, + options.hasM ? value.readDouble() : undefined); +}; + +Point._parseTwkb = function (value, options) { + var point = new Point(); + point.hasZ = options.hasZ; + point.hasM = options.hasM; + + if (options.isEmpty) + return point; + + point.x = ZigZag.decode(value.readVarInt()) / options.precisionFactor; + point.y = ZigZag.decode(value.readVarInt()) / options.precisionFactor; + point.z = options.hasZ ? ZigZag.decode(value.readVarInt()) / options.zPrecisionFactor : undefined; + point.m = options.hasM ? ZigZag.decode(value.readVarInt()) / options.mPrecisionFactor : undefined; + + return point; +}; + +Point._readTwkbPoint = function (value, options, previousPoint) { + previousPoint.x += ZigZag.decode(value.readVarInt()) / options.precisionFactor; + previousPoint.y += ZigZag.decode(value.readVarInt()) / options.precisionFactor; + + if (options.hasZ) + previousPoint.z += ZigZag.decode(value.readVarInt()) / options.zPrecisionFactor; + if (options.hasM) + previousPoint.m += ZigZag.decode(value.readVarInt()) / options.mPrecisionFactor; + + return new Point(previousPoint.x, previousPoint.y, previousPoint.z, previousPoint.m); +}; + +Point._parseGeoJSON = function (value) { + return Point._readGeoJSONPoint(value.coordinates); +}; + +Point._readGeoJSONPoint = function (coordinates) { + if (coordinates.length === 0) + return new Point(); + + if (coordinates.length > 2) + return new Point(coordinates[0], coordinates[1], coordinates[2]); + + return new Point(coordinates[0], coordinates[1]); +}; + +Point.prototype.toWkt = function () { + if (typeof this.x === 'undefined' && typeof this.y === 'undefined' && + typeof this.z === 'undefined' && typeof this.m === 'undefined') + return this._getWktType(Types.wkt.Point, true); + + return this._getWktType(Types.wkt.Point, false) + '(' + this._getWktCoordinate(this) + ')'; +}; + +Point.prototype.toWkb = function (parentOptions) { + var wkb = new BinaryWriter(this._getWkbSize()); + + wkb.writeInt8(1); + this._writeWkbType(wkb, Types.wkb.Point, parentOptions); + + if (typeof this.x === 'undefined' && typeof this.y === 'undefined') { + wkb.writeDoubleLE(NaN); + wkb.writeDoubleLE(NaN); + + if (this.hasZ) + wkb.writeDoubleLE(NaN); + if (this.hasM) + wkb.writeDoubleLE(NaN); + } + else { + this._writeWkbPoint(wkb); + } + + return wkb.buffer; +}; + +Point.prototype._writeWkbPoint = function (wkb) { + wkb.writeDoubleLE(this.x); + wkb.writeDoubleLE(this.y); + + if (this.hasZ) + wkb.writeDoubleLE(this.z); + if (this.hasM) + wkb.writeDoubleLE(this.m); +}; + +Point.prototype.toTwkb = function () { + var twkb = new BinaryWriter(0, true); + + var precision = Geometry.getTwkbPrecision(5, 0, 0); + var isEmpty = typeof this.x === 'undefined' && typeof this.y === 'undefined'; + + this._writeTwkbHeader(twkb, Types.wkb.Point, precision, isEmpty); + + if (!isEmpty) + this._writeTwkbPoint(twkb, precision, new Point(0, 0, 0, 0)); + + return twkb.buffer; +}; + +Point.prototype._writeTwkbPoint = function (twkb, precision, previousPoint) { + var x = this.x * precision.xyFactor; + var y = this.y * precision.xyFactor; + var z = this.z * precision.zFactor; + var m = this.m * precision.mFactor; + + twkb.writeVarInt(ZigZag.encode(x - previousPoint.x)); + twkb.writeVarInt(ZigZag.encode(y - previousPoint.y)); + if (this.hasZ) + twkb.writeVarInt(ZigZag.encode(z - previousPoint.z)); + if (this.hasM) + twkb.writeVarInt(ZigZag.encode(m - previousPoint.m)); + + previousPoint.x = x; + previousPoint.y = y; + previousPoint.z = z; + previousPoint.m = m; +}; + +Point.prototype._getWkbSize = function () { + var size = 1 + 4 + 8 + 8; + + if (this.hasZ) + size += 8; + if (this.hasM) + size += 8; + + return size; +}; + +Point.prototype.toGeoJSON = function (options) { + var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); + geoJSON.type = Types.geoJSON.Point; + + if (typeof this.x === 'undefined' && typeof this.y === 'undefined') + geoJSON.coordinates = []; + else if (typeof this.z !== 'undefined') + geoJSON.coordinates = [this.x, this.y, this.z]; + else + geoJSON.coordinates = [this.x, this.y]; + + return geoJSON; +}; },{"./binarywriter":2,"./geometry":3,"./types":11,"./zigzag.js":13,"util":20}],10:[function(require,module,exports){ -module.exports = Polygon; - -var util = require('util'); - -var Geometry = require('./geometry'); -var Types = require('./types'); -var Point = require('./point'); -var BinaryWriter = require('./binarywriter'); - -function Polygon(exteriorRing, interiorRings, srid) { - Geometry.call(this); - - this.exteriorRing = exteriorRing || []; - this.interiorRings = interiorRings || []; - this.srid = srid; - - if (this.exteriorRing.length > 0) { - this.hasZ = this.exteriorRing[0].hasZ; - this.hasM = this.exteriorRing[0].hasM; - } -} - -util.inherits(Polygon, Geometry); - -Polygon.Z = function (exteriorRing, interiorRings, srid) { - var polygon = new Polygon(exteriorRing, interiorRings, srid); - polygon.hasZ = true; - return polygon; -}; - -Polygon.M = function (exteriorRing, interiorRings, srid) { - var polygon = new Polygon(exteriorRing, interiorRings, srid); - polygon.hasM = true; - return polygon; -}; - -Polygon.ZM = function (exteriorRing, interiorRings, srid) { - var polygon = new Polygon(exteriorRing, interiorRings, srid); - polygon.hasZ = true; - polygon.hasM = true; - return polygon; -}; - -Polygon._parseWkt = function (value, options) { - var polygon = new Polygon(); - polygon.srid = options.srid; - polygon.hasZ = options.hasZ; - polygon.hasM = options.hasM; - - if (value.isMatch(['EMPTY'])) - return polygon; - - value.expectGroupStart(); - - value.expectGroupStart(); - polygon.exteriorRing.push.apply(polygon.exteriorRing, value.matchCoordinates(options)); - value.expectGroupEnd(); - - while (value.isMatch([','])) { - value.expectGroupStart(); - polygon.interiorRings.push(value.matchCoordinates(options)); - value.expectGroupEnd(); - } - - value.expectGroupEnd(); - - return polygon; -}; - -Polygon._parseWkb = function (value, options) { - var polygon = new Polygon(); - polygon.srid = options.srid; - polygon.hasZ = options.hasZ; - polygon.hasM = options.hasM; - - var ringCount = value.readUInt32(); - - if (ringCount > 0) { - var exteriorRingCount = value.readUInt32(); - - for (var i = 0; i < exteriorRingCount; i++) - polygon.exteriorRing.push(Point._readWkbPoint(value, options)); - - for (i = 1; i < ringCount; i++) { - var interiorRing = []; - - var interiorRingCount = value.readUInt32(); - - for (var j = 0; j < interiorRingCount; j++) - interiorRing.push(Point._readWkbPoint(value, options)); - - polygon.interiorRings.push(interiorRing); - } - } - - return polygon; -}; - -Polygon._parseTwkb = function (value, options) { - var polygon = new Polygon(); - polygon.hasZ = options.hasZ; - polygon.hasM = options.hasM; - - if (options.isEmpty) - return polygon; - - var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); - var ringCount = value.readVarInt(); - var exteriorRingCount = value.readVarInt(); - - for (var i = 0; i < exteriorRingCount; i++) - polygon.exteriorRing.push(Point._readTwkbPoint(value, options, previousPoint)); - - for (i = 1; i < ringCount; i++) { - var interiorRing = []; - - var interiorRingCount = value.readVarInt(); - - for (var j = 0; j < interiorRingCount; j++) - interiorRing.push(Point._readTwkbPoint(value, options, previousPoint)); - - polygon.interiorRings.push(interiorRing); - } - - return polygon; -}; - -Polygon._parseGeoJSON = function (value) { - var polygon = new Polygon(); - - if (value.coordinates.length > 0 && value.coordinates[0].length > 0) - polygon.hasZ = value.coordinates[0][0].length > 2; - - for (var i = 0; i < value.coordinates.length; i++) { - if (i > 0) - polygon.interiorRings.push([]); - - for (var j = 0; j < value.coordinates[i].length; j++) { - if (i === 0) - polygon.exteriorRing.push(Point._readGeoJSONPoint(value.coordinates[i][j])); - else - polygon.interiorRings[i - 1].push(Point._readGeoJSONPoint(value.coordinates[i][j])); - } - } - - return polygon; -}; - -Polygon.prototype.toWkt = function () { - if (this.exteriorRing.length === 0) - return this._getWktType(Types.wkt.Polygon, true); - - return this._getWktType(Types.wkt.Polygon, false) + this._toInnerWkt(); -}; - -Polygon.prototype._toInnerWkt = function () { - var innerWkt = '(('; - - for (var i = 0; i < this.exteriorRing.length; i++) - innerWkt += this._getWktCoordinate(this.exteriorRing[i]) + ','; - - innerWkt = innerWkt.slice(0, -1); - innerWkt += ')'; - - for (i = 0; i < this.interiorRings.length; i++) { - innerWkt += ',('; - - for (var j = 0; j < this.interiorRings[i].length; j++) { - innerWkt += this._getWktCoordinate(this.interiorRings[i][j]) + ','; - } - - innerWkt = innerWkt.slice(0, -1); - innerWkt += ')'; - } - - innerWkt += ')'; - - return innerWkt; -}; - -Polygon.prototype.toWkb = function (parentOptions) { - var wkb = new BinaryWriter(this._getWkbSize()); - - wkb.writeInt8(1); - - this._writeWkbType(wkb, Types.wkb.Polygon, parentOptions); - - if (this.exteriorRing.length > 0) { - wkb.writeUInt32LE(1 + this.interiorRings.length); - wkb.writeUInt32LE(this.exteriorRing.length); - } - else { - wkb.writeUInt32LE(0); - } - - for (var i = 0; i < this.exteriorRing.length; i++) - this.exteriorRing[i]._writeWkbPoint(wkb); - - for (i = 0; i < this.interiorRings.length; i++) { - wkb.writeUInt32LE(this.interiorRings[i].length); - - for (var j = 0; j < this.interiorRings[i].length; j++) - this.interiorRings[i][j]._writeWkbPoint(wkb); - } - - return wkb.buffer; -}; - -Polygon.prototype.toTwkb = function () { - var twkb = new BinaryWriter(0, true); - - var precision = Geometry.getTwkbPrecision(5, 0, 0); - var isEmpty = this.exteriorRing.length === 0; - - this._writeTwkbHeader(twkb, Types.wkb.Polygon, precision, isEmpty); - - if (this.exteriorRing.length > 0) { - twkb.writeVarInt(1 + this.interiorRings.length); - - twkb.writeVarInt(this.exteriorRing.length); - - var previousPoint = new Point(0, 0, 0, 0); - for (var i = 0; i < this.exteriorRing.length; i++) - this.exteriorRing[i]._writeTwkbPoint(twkb, precision, previousPoint); - - for (i = 0; i < this.interiorRings.length; i++) { - twkb.writeVarInt(this.interiorRings[i].length); - - for (var j = 0; j < this.interiorRings[i].length; j++) - this.interiorRings[i][j]._writeTwkbPoint(twkb, precision, previousPoint); - } - } - - return twkb.buffer; -}; - -Polygon.prototype._getWkbSize = function () { - var coordinateSize = 16; - - if (this.hasZ) - coordinateSize += 8; - if (this.hasM) - coordinateSize += 8; - - var size = 1 + 4 + 4; - - if (this.exteriorRing.length > 0) - size += 4 + (this.exteriorRing.length * coordinateSize); - - for (var i = 0; i < this.interiorRings.length; i++) - size += 4 + (this.interiorRings[i].length * coordinateSize); - - return size; -}; - -Polygon.prototype.toGeoJSON = function (options) { - var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); - geoJSON.type = Types.geoJSON.Polygon; - geoJSON.coordinates = []; - - if (this.exteriorRing.length > 0) { - var exteriorRing = []; - - for (var i = 0; i < this.exteriorRing.length; i++) { - if (this.hasZ) - exteriorRing.push([this.exteriorRing[i].x, this.exteriorRing[i].y, this.exteriorRing[i].z]); - else - exteriorRing.push([this.exteriorRing[i].x, this.exteriorRing[i].y]); - } - - geoJSON.coordinates.push(exteriorRing); - } - - for (var j = 0; j < this.interiorRings.length; j++) { - var interiorRing = []; - - for (var k = 0; k < this.interiorRings[j].length; k++) { - if (this.hasZ) - interiorRing.push([this.interiorRings[j][k].x, this.interiorRings[j][k].y, this.interiorRings[j][k].z]); - else - interiorRing.push([this.interiorRings[j][k].x, this.interiorRings[j][k].y]); - } - - geoJSON.coordinates.push(interiorRing); - } - - return geoJSON; -}; +module.exports = Polygon; + +var util = require('util'); + +var Geometry = require('./geometry'); +var Types = require('./types'); +var Point = require('./point'); +var BinaryWriter = require('./binarywriter'); + +function Polygon(exteriorRing, interiorRings, srid) { + Geometry.call(this); + + this.exteriorRing = exteriorRing || []; + this.interiorRings = interiorRings || []; + this.srid = srid; + + if (this.exteriorRing.length > 0) { + this.hasZ = this.exteriorRing[0].hasZ; + this.hasM = this.exteriorRing[0].hasM; + } +} + +util.inherits(Polygon, Geometry); + +Polygon.Z = function (exteriorRing, interiorRings, srid) { + var polygon = new Polygon(exteriorRing, interiorRings, srid); + polygon.hasZ = true; + return polygon; +}; + +Polygon.M = function (exteriorRing, interiorRings, srid) { + var polygon = new Polygon(exteriorRing, interiorRings, srid); + polygon.hasM = true; + return polygon; +}; + +Polygon.ZM = function (exteriorRing, interiorRings, srid) { + var polygon = new Polygon(exteriorRing, interiorRings, srid); + polygon.hasZ = true; + polygon.hasM = true; + return polygon; +}; + +Polygon._parseWkt = function (value, options) { + var polygon = new Polygon(); + polygon.srid = options.srid; + polygon.hasZ = options.hasZ; + polygon.hasM = options.hasM; + + if (value.isMatch(['EMPTY'])) + return polygon; + + value.expectGroupStart(); + + value.expectGroupStart(); + polygon.exteriorRing.push.apply(polygon.exteriorRing, value.matchCoordinates(options)); + value.expectGroupEnd(); + + while (value.isMatch([','])) { + value.expectGroupStart(); + polygon.interiorRings.push(value.matchCoordinates(options)); + value.expectGroupEnd(); + } + + value.expectGroupEnd(); + + return polygon; +}; + +Polygon._parseWkb = function (value, options) { + var polygon = new Polygon(); + polygon.srid = options.srid; + polygon.hasZ = options.hasZ; + polygon.hasM = options.hasM; + + var ringCount = value.readUInt32(); + + if (ringCount > 0) { + var exteriorRingCount = value.readUInt32(); + + for (var i = 0; i < exteriorRingCount; i++) + polygon.exteriorRing.push(Point._readWkbPoint(value, options)); + + for (i = 1; i < ringCount; i++) { + var interiorRing = []; + + var interiorRingCount = value.readUInt32(); + + for (var j = 0; j < interiorRingCount; j++) + interiorRing.push(Point._readWkbPoint(value, options)); + + polygon.interiorRings.push(interiorRing); + } + } + + return polygon; +}; + +Polygon._parseTwkb = function (value, options) { + var polygon = new Polygon(); + polygon.hasZ = options.hasZ; + polygon.hasM = options.hasM; + + if (options.isEmpty) + return polygon; + + var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); + var ringCount = value.readVarInt(); + var exteriorRingCount = value.readVarInt(); + + for (var i = 0; i < exteriorRingCount; i++) + polygon.exteriorRing.push(Point._readTwkbPoint(value, options, previousPoint)); + + for (i = 1; i < ringCount; i++) { + var interiorRing = []; + + var interiorRingCount = value.readVarInt(); + + for (var j = 0; j < interiorRingCount; j++) + interiorRing.push(Point._readTwkbPoint(value, options, previousPoint)); + + polygon.interiorRings.push(interiorRing); + } + + return polygon; +}; + +Polygon._parseGeoJSON = function (value) { + var polygon = new Polygon(); + + if (value.coordinates.length > 0 && value.coordinates[0].length > 0) + polygon.hasZ = value.coordinates[0][0].length > 2; + + for (var i = 0; i < value.coordinates.length; i++) { + if (i > 0) + polygon.interiorRings.push([]); + + for (var j = 0; j < value.coordinates[i].length; j++) { + if (i === 0) + polygon.exteriorRing.push(Point._readGeoJSONPoint(value.coordinates[i][j])); + else + polygon.interiorRings[i - 1].push(Point._readGeoJSONPoint(value.coordinates[i][j])); + } + } + + return polygon; +}; + +Polygon.prototype.toWkt = function () { + if (this.exteriorRing.length === 0) + return this._getWktType(Types.wkt.Polygon, true); + + return this._getWktType(Types.wkt.Polygon, false) + this._toInnerWkt(); +}; + +Polygon.prototype._toInnerWkt = function () { + var innerWkt = '(('; + + for (var i = 0; i < this.exteriorRing.length; i++) + innerWkt += this._getWktCoordinate(this.exteriorRing[i]) + ','; + + innerWkt = innerWkt.slice(0, -1); + innerWkt += ')'; + + for (i = 0; i < this.interiorRings.length; i++) { + innerWkt += ',('; + + for (var j = 0; j < this.interiorRings[i].length; j++) { + innerWkt += this._getWktCoordinate(this.interiorRings[i][j]) + ','; + } + + innerWkt = innerWkt.slice(0, -1); + innerWkt += ')'; + } + + innerWkt += ')'; + + return innerWkt; +}; + +Polygon.prototype.toWkb = function (parentOptions) { + var wkb = new BinaryWriter(this._getWkbSize()); + + wkb.writeInt8(1); + + this._writeWkbType(wkb, Types.wkb.Polygon, parentOptions); + + if (this.exteriorRing.length > 0) { + wkb.writeUInt32LE(1 + this.interiorRings.length); + wkb.writeUInt32LE(this.exteriorRing.length); + } + else { + wkb.writeUInt32LE(0); + } + + for (var i = 0; i < this.exteriorRing.length; i++) + this.exteriorRing[i]._writeWkbPoint(wkb); + + for (i = 0; i < this.interiorRings.length; i++) { + wkb.writeUInt32LE(this.interiorRings[i].length); + + for (var j = 0; j < this.interiorRings[i].length; j++) + this.interiorRings[i][j]._writeWkbPoint(wkb); + } + + return wkb.buffer; +}; + +Polygon.prototype.toTwkb = function () { + var twkb = new BinaryWriter(0, true); + + var precision = Geometry.getTwkbPrecision(5, 0, 0); + var isEmpty = this.exteriorRing.length === 0; + + this._writeTwkbHeader(twkb, Types.wkb.Polygon, precision, isEmpty); + + if (this.exteriorRing.length > 0) { + twkb.writeVarInt(1 + this.interiorRings.length); + + twkb.writeVarInt(this.exteriorRing.length); + + var previousPoint = new Point(0, 0, 0, 0); + for (var i = 0; i < this.exteriorRing.length; i++) + this.exteriorRing[i]._writeTwkbPoint(twkb, precision, previousPoint); + + for (i = 0; i < this.interiorRings.length; i++) { + twkb.writeVarInt(this.interiorRings[i].length); + + for (var j = 0; j < this.interiorRings[i].length; j++) + this.interiorRings[i][j]._writeTwkbPoint(twkb, precision, previousPoint); + } + } + + return twkb.buffer; +}; + +Polygon.prototype._getWkbSize = function () { + var coordinateSize = 16; + + if (this.hasZ) + coordinateSize += 8; + if (this.hasM) + coordinateSize += 8; + + var size = 1 + 4 + 4; + + if (this.exteriorRing.length > 0) + size += 4 + (this.exteriorRing.length * coordinateSize); + + for (var i = 0; i < this.interiorRings.length; i++) + size += 4 + (this.interiorRings[i].length * coordinateSize); + + return size; +}; + +Polygon.prototype.toGeoJSON = function (options) { + var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); + geoJSON.type = Types.geoJSON.Polygon; + geoJSON.coordinates = []; + + if (this.exteriorRing.length > 0) { + var exteriorRing = []; + + for (var i = 0; i < this.exteriorRing.length; i++) { + if (this.hasZ) + exteriorRing.push([this.exteriorRing[i].x, this.exteriorRing[i].y, this.exteriorRing[i].z]); + else + exteriorRing.push([this.exteriorRing[i].x, this.exteriorRing[i].y]); + } + + geoJSON.coordinates.push(exteriorRing); + } + + for (var j = 0; j < this.interiorRings.length; j++) { + var interiorRing = []; + + for (var k = 0; k < this.interiorRings[j].length; k++) { + if (this.hasZ) + interiorRing.push([this.interiorRings[j][k].x, this.interiorRings[j][k].y, this.interiorRings[j][k].z]); + else + interiorRing.push([this.interiorRings[j][k].x, this.interiorRings[j][k].y]); + } + + geoJSON.coordinates.push(interiorRing); + } + + return geoJSON; +}; },{"./binarywriter":2,"./geometry":3,"./point":9,"./types":11,"util":20}],11:[function(require,module,exports){ -module.exports = { - wkt: { - Point: 'POINT', - LineString: 'LINESTRING', - Polygon: 'POLYGON', - MultiPoint: 'MULTIPOINT', - MultiLineString: 'MULTILINESTRING', - MultiPolygon: 'MULTIPOLYGON', - GeometryCollection: 'GEOMETRYCOLLECTION' - }, - wkb: { - Point: 1, - LineString: 2, - Polygon: 3, - MultiPoint: 4, - MultiLineString: 5, - MultiPolygon: 6, - GeometryCollection: 7 - }, - geoJSON: { - Point: 'Point', - LineString: 'LineString', - Polygon: 'Polygon', - MultiPoint: 'MultiPoint', - MultiLineString: 'MultiLineString', - MultiPolygon: 'MultiPolygon', - GeometryCollection: 'GeometryCollection' - } -}; +module.exports = { + wkt: { + Point: 'POINT', + LineString: 'LINESTRING', + Polygon: 'POLYGON', + MultiPoint: 'MULTIPOINT', + MultiLineString: 'MULTILINESTRING', + MultiPolygon: 'MULTIPOLYGON', + GeometryCollection: 'GEOMETRYCOLLECTION' + }, + wkb: { + Point: 1, + LineString: 2, + Polygon: 3, + MultiPoint: 4, + MultiLineString: 5, + MultiPolygon: 6, + GeometryCollection: 7 + }, + geoJSON: { + Point: 'Point', + LineString: 'LineString', + Polygon: 'Polygon', + MultiPoint: 'MultiPoint', + MultiLineString: 'MultiLineString', + MultiPolygon: 'MultiPolygon', + GeometryCollection: 'GeometryCollection' + } +}; },{}],12:[function(require,module,exports){ -module.exports = WktParser; - -var Types = require('./types'); -var Point = require('./point'); - -function WktParser(value) { - this.value = value; - this.position = 0; -} - -WktParser.prototype.match = function (tokens) { - this.skipWhitespaces(); - - for (var i = 0; i < tokens.length; i++) { - if (this.value.substring(this.position).indexOf(tokens[i]) === 0) { - this.position += tokens[i].length; - return tokens[i]; - } - } - - return null; -}; - -WktParser.prototype.matchRegex = function (tokens) { - this.skipWhitespaces(); - - for (var i = 0; i < tokens.length; i++) { - var match = this.value.substring(this.position).match(tokens[i]); - - if (match) { - this.position += match[0].length; - return match; - } - } - - return null; -}; - -WktParser.prototype.isMatch = function (tokens) { - this.skipWhitespaces(); - - for (var i = 0; i < tokens.length; i++) { - if (this.value.substring(this.position).indexOf(tokens[i]) === 0) { - this.position += tokens[i].length; - return true; - } - } - - return false; -}; - -WktParser.prototype.matchType = function () { - var geometryType = this.match([Types.wkt.Point, Types.wkt.LineString, Types.wkt.Polygon, Types.wkt.MultiPoint, - Types.wkt.MultiLineString, Types.wkt.MultiPolygon, Types.wkt.GeometryCollection]); - - if (!geometryType) - throw new Error('Expected geometry type'); - - return geometryType; -}; - -WktParser.prototype.matchDimension = function () { - var dimension = this.match(['ZM', 'Z', 'M']); - - switch (dimension) { - case 'ZM': return { hasZ: true, hasM: true }; - case 'Z': return { hasZ: true, hasM: false }; - case 'M': return { hasZ: false, hasM: true }; - default: return { hasZ: false, hasM: false }; - } -}; - -WktParser.prototype.expectGroupStart = function () { - if (!this.isMatch(['('])) - throw new Error('Expected group start'); -}; - -WktParser.prototype.expectGroupEnd = function () { - if (!this.isMatch([')'])) - throw new Error('Expected group end'); -}; - -WktParser.prototype.matchCoordinate = function (options) { - var match; - - if (options.hasZ && options.hasM) - match = this.matchRegex([/^(\S*)\s+(\S*)\s+(\S*)\s+([^\s,)]*)/]); - else if (options.hasZ || options.hasM) - match = this.matchRegex([/^(\S*)\s+(\S*)\s+([^\s,)]*)/]); - else - match = this.matchRegex([/^(\S*)\s+([^\s,)]*)/]); - - if (!match) - throw new Error('Expected coordinates'); - - if (options.hasZ && options.hasM) - return new Point(parseFloat(match[1]), parseFloat(match[2]), parseFloat(match[3]), parseFloat(match[4])); - else if (options.hasZ) - return new Point(parseFloat(match[1]), parseFloat(match[2]), parseFloat(match[3])); - else if (options.hasM) - return new Point(parseFloat(match[1]), parseFloat(match[2]), undefined, parseFloat(match[3])); - else - return new Point(parseFloat(match[1]), parseFloat(match[2])); -}; - -WktParser.prototype.matchCoordinates = function (options) { - var coordinates = []; - - do { - var startsWithBracket = this.isMatch(['(']); - - coordinates.push(this.matchCoordinate(options)); - - if (startsWithBracket) - this.expectGroupEnd(); - } while (this.isMatch([','])); - - return coordinates; -}; - -WktParser.prototype.skipWhitespaces = function () { - while (this.position < this.value.length && this.value[this.position] === ' ') - this.position++; -}; +module.exports = WktParser; + +var Types = require('./types'); +var Point = require('./point'); + +function WktParser(value) { + this.value = value; + this.position = 0; +} + +WktParser.prototype.match = function (tokens) { + this.skipWhitespaces(); + + for (var i = 0; i < tokens.length; i++) { + if (this.value.substring(this.position).indexOf(tokens[i]) === 0) { + this.position += tokens[i].length; + return tokens[i]; + } + } + + return null; +}; + +WktParser.prototype.matchRegex = function (tokens) { + this.skipWhitespaces(); + + for (var i = 0; i < tokens.length; i++) { + var match = this.value.substring(this.position).match(tokens[i]); + + if (match) { + this.position += match[0].length; + return match; + } + } + + return null; +}; + +WktParser.prototype.isMatch = function (tokens) { + this.skipWhitespaces(); + + for (var i = 0; i < tokens.length; i++) { + if (this.value.substring(this.position).indexOf(tokens[i]) === 0) { + this.position += tokens[i].length; + return true; + } + } + + return false; +}; + +WktParser.prototype.matchType = function () { + var geometryType = this.match([Types.wkt.Point, Types.wkt.LineString, Types.wkt.Polygon, Types.wkt.MultiPoint, + Types.wkt.MultiLineString, Types.wkt.MultiPolygon, Types.wkt.GeometryCollection]); + + if (!geometryType) + throw new Error('Expected geometry type'); + + return geometryType; +}; + +WktParser.prototype.matchDimension = function () { + var dimension = this.match(['ZM', 'Z', 'M']); + + switch (dimension) { + case 'ZM': return { hasZ: true, hasM: true }; + case 'Z': return { hasZ: true, hasM: false }; + case 'M': return { hasZ: false, hasM: true }; + default: return { hasZ: false, hasM: false }; + } +}; + +WktParser.prototype.expectGroupStart = function () { + if (!this.isMatch(['('])) + throw new Error('Expected group start'); +}; + +WktParser.prototype.expectGroupEnd = function () { + if (!this.isMatch([')'])) + throw new Error('Expected group end'); +}; + +WktParser.prototype.matchCoordinate = function (options) { + var match; + + if (options.hasZ && options.hasM) + match = this.matchRegex([/^(\S*)\s+(\S*)\s+(\S*)\s+([^\s,)]*)/]); + else if (options.hasZ || options.hasM) + match = this.matchRegex([/^(\S*)\s+(\S*)\s+([^\s,)]*)/]); + else + match = this.matchRegex([/^(\S*)\s+([^\s,)]*)/]); + + if (!match) + throw new Error('Expected coordinates'); + + if (options.hasZ && options.hasM) + return new Point(parseFloat(match[1]), parseFloat(match[2]), parseFloat(match[3]), parseFloat(match[4])); + else if (options.hasZ) + return new Point(parseFloat(match[1]), parseFloat(match[2]), parseFloat(match[3])); + else if (options.hasM) + return new Point(parseFloat(match[1]), parseFloat(match[2]), undefined, parseFloat(match[3])); + else + return new Point(parseFloat(match[1]), parseFloat(match[2])); +}; + +WktParser.prototype.matchCoordinates = function (options) { + var coordinates = []; + + do { + var startsWithBracket = this.isMatch(['(']); + + coordinates.push(this.matchCoordinate(options)); + + if (startsWithBracket) + this.expectGroupEnd(); + } while (this.isMatch([','])); + + return coordinates; +}; + +WktParser.prototype.skipWhitespaces = function () { + while (this.position < this.value.length && this.value[this.position] === ' ') + this.position++; +}; },{"./point":9,"./types":11}],13:[function(require,module,exports){ -module.exports = { - encode: function (value) { - return (value << 1) ^ (value >> 31); - }, - decode: function (value) { - return (value >> 1) ^ (-(value & 1)); - } -}; +module.exports = { + encode: function (value) { + return (value << 1) ^ (value >> 31); + }, + decode: function (value) { + return (value >> 1) ^ (-(value & 1)); + } +}; },{}],14:[function(require,module,exports){ 'use strict' @@ -5007,13 +5007,13 @@ var hexSliceLookupTable = (function () { }).call(this,require("buffer").Buffer) },{"base64-js":14,"buffer":"buffer","ieee754":15}],"wkx":[function(require,module,exports){ -exports.Types = require('./types'); -exports.Geometry = require('./geometry'); -exports.Point = require('./point'); -exports.LineString = require('./linestring'); -exports.Polygon = require('./polygon'); -exports.MultiPoint = require('./multipoint'); -exports.MultiLineString = require('./multilinestring'); -exports.MultiPolygon = require('./multipolygon'); +exports.Types = require('./types'); +exports.Geometry = require('./geometry'); +exports.Point = require('./point'); +exports.LineString = require('./linestring'); +exports.Polygon = require('./polygon'); +exports.MultiPoint = require('./multipoint'); +exports.MultiLineString = require('./multilinestring'); +exports.MultiPolygon = require('./multipolygon'); exports.GeometryCollection = require('./geometrycollection'); },{"./geometry":3,"./geometrycollection":4,"./linestring":5,"./multilinestring":6,"./multipoint":7,"./multipolygon":8,"./point":9,"./polygon":10,"./types":11}]},{},["wkx"]); diff --git a/backend/node_modules/wkx/lib/binaryreader.js b/backend/node_modules/wkx/lib/binaryreader.js index 4bb9115..1675337 100644 --- a/backend/node_modules/wkx/lib/binaryreader.js +++ b/backend/node_modules/wkx/lib/binaryreader.js @@ -1,47 +1,47 @@ -module.exports = BinaryReader; - -function BinaryReader(buffer, isBigEndian) { - this.buffer = buffer; - this.position = 0; - this.isBigEndian = isBigEndian || false; -} - -function _read(readLE, readBE, size) { - return function () { - var value; - - if (this.isBigEndian) - value = readBE.call(this.buffer, this.position); - else - value = readLE.call(this.buffer, this.position); - - this.position += size; - - return value; - }; -} - -BinaryReader.prototype.readUInt8 = _read(Buffer.prototype.readUInt8, Buffer.prototype.readUInt8, 1); -BinaryReader.prototype.readUInt16 = _read(Buffer.prototype.readUInt16LE, Buffer.prototype.readUInt16BE, 2); -BinaryReader.prototype.readUInt32 = _read(Buffer.prototype.readUInt32LE, Buffer.prototype.readUInt32BE, 4); -BinaryReader.prototype.readInt8 = _read(Buffer.prototype.readInt8, Buffer.prototype.readInt8, 1); -BinaryReader.prototype.readInt16 = _read(Buffer.prototype.readInt16LE, Buffer.prototype.readInt16BE, 2); -BinaryReader.prototype.readInt32 = _read(Buffer.prototype.readInt32LE, Buffer.prototype.readInt32BE, 4); -BinaryReader.prototype.readFloat = _read(Buffer.prototype.readFloatLE, Buffer.prototype.readFloatBE, 4); -BinaryReader.prototype.readDouble = _read(Buffer.prototype.readDoubleLE, Buffer.prototype.readDoubleBE, 8); - -BinaryReader.prototype.readVarInt = function () { - var nextByte, - result = 0, - bytesRead = 0; - - do { - nextByte = this.buffer[this.position + bytesRead]; - result += (nextByte & 0x7F) << (7 * bytesRead); - bytesRead++; - } while (nextByte >= 0x80); - - this.position += bytesRead; - - return result; -}; +module.exports = BinaryReader; + +function BinaryReader(buffer, isBigEndian) { + this.buffer = buffer; + this.position = 0; + this.isBigEndian = isBigEndian || false; +} + +function _read(readLE, readBE, size) { + return function () { + var value; + + if (this.isBigEndian) + value = readBE.call(this.buffer, this.position); + else + value = readLE.call(this.buffer, this.position); + + this.position += size; + + return value; + }; +} + +BinaryReader.prototype.readUInt8 = _read(Buffer.prototype.readUInt8, Buffer.prototype.readUInt8, 1); +BinaryReader.prototype.readUInt16 = _read(Buffer.prototype.readUInt16LE, Buffer.prototype.readUInt16BE, 2); +BinaryReader.prototype.readUInt32 = _read(Buffer.prototype.readUInt32LE, Buffer.prototype.readUInt32BE, 4); +BinaryReader.prototype.readInt8 = _read(Buffer.prototype.readInt8, Buffer.prototype.readInt8, 1); +BinaryReader.prototype.readInt16 = _read(Buffer.prototype.readInt16LE, Buffer.prototype.readInt16BE, 2); +BinaryReader.prototype.readInt32 = _read(Buffer.prototype.readInt32LE, Buffer.prototype.readInt32BE, 4); +BinaryReader.prototype.readFloat = _read(Buffer.prototype.readFloatLE, Buffer.prototype.readFloatBE, 4); +BinaryReader.prototype.readDouble = _read(Buffer.prototype.readDoubleLE, Buffer.prototype.readDoubleBE, 8); + +BinaryReader.prototype.readVarInt = function () { + var nextByte, + result = 0, + bytesRead = 0; + + do { + nextByte = this.buffer[this.position + bytesRead]; + result += (nextByte & 0x7F) << (7 * bytesRead); + bytesRead++; + } while (nextByte >= 0x80); + + this.position += bytesRead; + + return result; +}; diff --git a/backend/node_modules/wkx/lib/binarywriter.js b/backend/node_modules/wkx/lib/binarywriter.js index 0ce052b..99dc454 100644 --- a/backend/node_modules/wkx/lib/binarywriter.js +++ b/backend/node_modules/wkx/lib/binarywriter.js @@ -1,65 +1,65 @@ -module.exports = BinaryWriter; - -function BinaryWriter(size, allowResize) { - this.buffer = new Buffer(size); - this.position = 0; - this.allowResize = allowResize; -} - -function _write(write, size) { - return function (value, noAssert) { - this.ensureSize(size); - - write.call(this.buffer, value, this.position, noAssert); - this.position += size; - }; -} - -BinaryWriter.prototype.writeUInt8 = _write(Buffer.prototype.writeUInt8, 1); -BinaryWriter.prototype.writeUInt16LE = _write(Buffer.prototype.writeUInt16LE, 2); -BinaryWriter.prototype.writeUInt16BE = _write(Buffer.prototype.writeUInt16BE, 2); -BinaryWriter.prototype.writeUInt32LE = _write(Buffer.prototype.writeUInt32LE, 4); -BinaryWriter.prototype.writeUInt32BE = _write(Buffer.prototype.writeUInt32BE, 4); -BinaryWriter.prototype.writeInt8 = _write(Buffer.prototype.writeInt8, 1); -BinaryWriter.prototype.writeInt16LE = _write(Buffer.prototype.writeInt16LE, 2); -BinaryWriter.prototype.writeInt16BE = _write(Buffer.prototype.writeInt16BE, 2); -BinaryWriter.prototype.writeInt32LE = _write(Buffer.prototype.writeInt32LE, 4); -BinaryWriter.prototype.writeInt32BE = _write(Buffer.prototype.writeInt32BE, 4); -BinaryWriter.prototype.writeFloatLE = _write(Buffer.prototype.writeFloatLE, 4); -BinaryWriter.prototype.writeFloatBE = _write(Buffer.prototype.writeFloatBE, 4); -BinaryWriter.prototype.writeDoubleLE = _write(Buffer.prototype.writeDoubleLE, 8); -BinaryWriter.prototype.writeDoubleBE = _write(Buffer.prototype.writeDoubleBE, 8); - -BinaryWriter.prototype.writeBuffer = function (buffer) { - this.ensureSize(buffer.length); - - buffer.copy(this.buffer, this.position, 0, buffer.length); - this.position += buffer.length; -}; - -BinaryWriter.prototype.writeVarInt = function (value) { - var length = 1; - - while ((value & 0xFFFFFF80) !== 0) { - this.writeUInt8((value & 0x7F) | 0x80); - value >>>= 7; - length++; - } - - this.writeUInt8(value & 0x7F); - - return length; -}; - -BinaryWriter.prototype.ensureSize = function (size) { - if (this.buffer.length < this.position + size) { - if (this.allowResize) { - var tempBuffer = new Buffer(this.position + size); - this.buffer.copy(tempBuffer, 0, 0, this.buffer.length); - this.buffer = tempBuffer; - } - else { - throw new RangeError('index out of range'); - } - } -}; +module.exports = BinaryWriter; + +function BinaryWriter(size, allowResize) { + this.buffer = new Buffer(size); + this.position = 0; + this.allowResize = allowResize; +} + +function _write(write, size) { + return function (value, noAssert) { + this.ensureSize(size); + + write.call(this.buffer, value, this.position, noAssert); + this.position += size; + }; +} + +BinaryWriter.prototype.writeUInt8 = _write(Buffer.prototype.writeUInt8, 1); +BinaryWriter.prototype.writeUInt16LE = _write(Buffer.prototype.writeUInt16LE, 2); +BinaryWriter.prototype.writeUInt16BE = _write(Buffer.prototype.writeUInt16BE, 2); +BinaryWriter.prototype.writeUInt32LE = _write(Buffer.prototype.writeUInt32LE, 4); +BinaryWriter.prototype.writeUInt32BE = _write(Buffer.prototype.writeUInt32BE, 4); +BinaryWriter.prototype.writeInt8 = _write(Buffer.prototype.writeInt8, 1); +BinaryWriter.prototype.writeInt16LE = _write(Buffer.prototype.writeInt16LE, 2); +BinaryWriter.prototype.writeInt16BE = _write(Buffer.prototype.writeInt16BE, 2); +BinaryWriter.prototype.writeInt32LE = _write(Buffer.prototype.writeInt32LE, 4); +BinaryWriter.prototype.writeInt32BE = _write(Buffer.prototype.writeInt32BE, 4); +BinaryWriter.prototype.writeFloatLE = _write(Buffer.prototype.writeFloatLE, 4); +BinaryWriter.prototype.writeFloatBE = _write(Buffer.prototype.writeFloatBE, 4); +BinaryWriter.prototype.writeDoubleLE = _write(Buffer.prototype.writeDoubleLE, 8); +BinaryWriter.prototype.writeDoubleBE = _write(Buffer.prototype.writeDoubleBE, 8); + +BinaryWriter.prototype.writeBuffer = function (buffer) { + this.ensureSize(buffer.length); + + buffer.copy(this.buffer, this.position, 0, buffer.length); + this.position += buffer.length; +}; + +BinaryWriter.prototype.writeVarInt = function (value) { + var length = 1; + + while ((value & 0xFFFFFF80) !== 0) { + this.writeUInt8((value & 0x7F) | 0x80); + value >>>= 7; + length++; + } + + this.writeUInt8(value & 0x7F); + + return length; +}; + +BinaryWriter.prototype.ensureSize = function (size) { + if (this.buffer.length < this.position + size) { + if (this.allowResize) { + var tempBuffer = new Buffer(this.position + size); + this.buffer.copy(tempBuffer, 0, 0, this.buffer.length); + this.buffer = tempBuffer; + } + else { + throw new RangeError('index out of range'); + } + } +}; diff --git a/backend/node_modules/wkx/lib/geometry.js b/backend/node_modules/wkx/lib/geometry.js index a20a0d6..37d1bef 100644 --- a/backend/node_modules/wkx/lib/geometry.js +++ b/backend/node_modules/wkx/lib/geometry.js @@ -1,384 +1,384 @@ -module.exports = Geometry; - -var Types = require('./types'); -var Point = require('./point'); -var LineString = require('./linestring'); -var Polygon = require('./polygon'); -var MultiPoint = require('./multipoint'); -var MultiLineString = require('./multilinestring'); -var MultiPolygon = require('./multipolygon'); -var GeometryCollection = require('./geometrycollection'); -var BinaryReader = require('./binaryreader'); -var BinaryWriter = require('./binarywriter'); -var WktParser = require('./wktparser'); -var ZigZag = require('./zigzag.js'); - -function Geometry() { - this.srid = undefined; - this.hasZ = false; - this.hasM = false; -} - -Geometry.parse = function (value, options) { - var valueType = typeof value; - - if (valueType === 'string' || value instanceof WktParser) - return Geometry._parseWkt(value); - else if (Buffer.isBuffer(value) || value instanceof BinaryReader) - return Geometry._parseWkb(value, options); - else - throw new Error('first argument must be a string or Buffer'); -}; - -Geometry._parseWkt = function (value) { - var wktParser, - srid; - - if (value instanceof WktParser) - wktParser = value; - else - wktParser = new WktParser(value); - - var match = wktParser.matchRegex([/^SRID=(\d+);/]); - if (match) - srid = parseInt(match[1], 10); - - var geometryType = wktParser.matchType(); - var dimension = wktParser.matchDimension(); - - var options = { - srid: srid, - hasZ: dimension.hasZ, - hasM: dimension.hasM - }; - - switch (geometryType) { - case Types.wkt.Point: - return Point._parseWkt(wktParser, options); - case Types.wkt.LineString: - return LineString._parseWkt(wktParser, options); - case Types.wkt.Polygon: - return Polygon._parseWkt(wktParser, options); - case Types.wkt.MultiPoint: - return MultiPoint._parseWkt(wktParser, options); - case Types.wkt.MultiLineString: - return MultiLineString._parseWkt(wktParser, options); - case Types.wkt.MultiPolygon: - return MultiPolygon._parseWkt(wktParser, options); - case Types.wkt.GeometryCollection: - return GeometryCollection._parseWkt(wktParser, options); - } -}; - -Geometry._parseWkb = function (value, parentOptions) { - var binaryReader, - wkbType, - geometryType, - options = {}; - - if (value instanceof BinaryReader) - binaryReader = value; - else - binaryReader = new BinaryReader(value); - - binaryReader.isBigEndian = !binaryReader.readInt8(); - - wkbType = binaryReader.readUInt32(); - - options.hasSrid = (wkbType & 0x20000000) === 0x20000000; - options.isEwkb = (wkbType & 0x20000000) || (wkbType & 0x40000000) || (wkbType & 0x80000000); - - if (options.hasSrid) - options.srid = binaryReader.readUInt32(); - - options.hasZ = false; - options.hasM = false; - - if (!options.isEwkb && (!parentOptions || !parentOptions.isEwkb)) { - if (wkbType >= 1000 && wkbType < 2000) { - options.hasZ = true; - geometryType = wkbType - 1000; - } - else if (wkbType >= 2000 && wkbType < 3000) { - options.hasM = true; - geometryType = wkbType - 2000; - } - else if (wkbType >= 3000 && wkbType < 4000) { - options.hasZ = true; - options.hasM = true; - geometryType = wkbType - 3000; - } - else { - geometryType = wkbType; - } - } - else { - if (wkbType & 0x80000000) - options.hasZ = true; - if (wkbType & 0x40000000) - options.hasM = true; - - geometryType = wkbType & 0xF; - } - - switch (geometryType) { - case Types.wkb.Point: - return Point._parseWkb(binaryReader, options); - case Types.wkb.LineString: - return LineString._parseWkb(binaryReader, options); - case Types.wkb.Polygon: - return Polygon._parseWkb(binaryReader, options); - case Types.wkb.MultiPoint: - return MultiPoint._parseWkb(binaryReader, options); - case Types.wkb.MultiLineString: - return MultiLineString._parseWkb(binaryReader, options); - case Types.wkb.MultiPolygon: - return MultiPolygon._parseWkb(binaryReader, options); - case Types.wkb.GeometryCollection: - return GeometryCollection._parseWkb(binaryReader, options); - default: - throw new Error('GeometryType ' + geometryType + ' not supported'); - } -}; - -Geometry.parseTwkb = function (value) { - var binaryReader, - options = {}; - - if (value instanceof BinaryReader) - binaryReader = value; - else - binaryReader = new BinaryReader(value); - - var type = binaryReader.readUInt8(); - var metadataHeader = binaryReader.readUInt8(); - - var geometryType = type & 0x0F; - options.precision = ZigZag.decode(type >> 4); - options.precisionFactor = Math.pow(10, options.precision); - - options.hasBoundingBox = metadataHeader >> 0 & 1; - options.hasSizeAttribute = metadataHeader >> 1 & 1; - options.hasIdList = metadataHeader >> 2 & 1; - options.hasExtendedPrecision = metadataHeader >> 3 & 1; - options.isEmpty = metadataHeader >> 4 & 1; - - if (options.hasExtendedPrecision) { - var extendedPrecision = binaryReader.readUInt8(); - options.hasZ = (extendedPrecision & 0x01) === 0x01; - options.hasM = (extendedPrecision & 0x02) === 0x02; - - options.zPrecision = ZigZag.decode((extendedPrecision & 0x1C) >> 2); - options.zPrecisionFactor = Math.pow(10, options.zPrecision); - - options.mPrecision = ZigZag.decode((extendedPrecision & 0xE0) >> 5); - options.mPrecisionFactor = Math.pow(10, options.mPrecision); - } - else { - options.hasZ = false; - options.hasM = false; - } - - if (options.hasSizeAttribute) - binaryReader.readVarInt(); - if (options.hasBoundingBox) { - var dimensions = 2; - - if (options.hasZ) - dimensions++; - if (options.hasM) - dimensions++; - - for (var i = 0; i < dimensions; i++) { - binaryReader.readVarInt(); - binaryReader.readVarInt(); - } - } - - switch (geometryType) { - case Types.wkb.Point: - return Point._parseTwkb(binaryReader, options); - case Types.wkb.LineString: - return LineString._parseTwkb(binaryReader, options); - case Types.wkb.Polygon: - return Polygon._parseTwkb(binaryReader, options); - case Types.wkb.MultiPoint: - return MultiPoint._parseTwkb(binaryReader, options); - case Types.wkb.MultiLineString: - return MultiLineString._parseTwkb(binaryReader, options); - case Types.wkb.MultiPolygon: - return MultiPolygon._parseTwkb(binaryReader, options); - case Types.wkb.GeometryCollection: - return GeometryCollection._parseTwkb(binaryReader, options); - default: - throw new Error('GeometryType ' + geometryType + ' not supported'); - } -}; - -Geometry.parseGeoJSON = function (value) { - return Geometry._parseGeoJSON(value); -}; - -Geometry._parseGeoJSON = function (value, isSubGeometry) { - var geometry; - - switch (value.type) { - case Types.geoJSON.Point: - geometry = Point._parseGeoJSON(value); break; - case Types.geoJSON.LineString: - geometry = LineString._parseGeoJSON(value); break; - case Types.geoJSON.Polygon: - geometry = Polygon._parseGeoJSON(value); break; - case Types.geoJSON.MultiPoint: - geometry = MultiPoint._parseGeoJSON(value); break; - case Types.geoJSON.MultiLineString: - geometry = MultiLineString._parseGeoJSON(value); break; - case Types.geoJSON.MultiPolygon: - geometry = MultiPolygon._parseGeoJSON(value); break; - case Types.geoJSON.GeometryCollection: - geometry = GeometryCollection._parseGeoJSON(value); break; - default: - throw new Error('GeometryType ' + value.type + ' not supported'); - } - - if (value.crs && value.crs.type && value.crs.type === 'name' && value.crs.properties && value.crs.properties.name) { - var crs = value.crs.properties.name; - - if (crs.indexOf('EPSG:') === 0) - geometry.srid = parseInt(crs.substring(5)); - else if (crs.indexOf('urn:ogc:def:crs:EPSG::') === 0) - geometry.srid = parseInt(crs.substring(22)); - else - throw new Error('Unsupported crs: ' + crs); - } - else if (!isSubGeometry) { - geometry.srid = 4326; - } - - return geometry; -}; - -Geometry.prototype.toEwkt = function () { - return 'SRID=' + this.srid + ';' + this.toWkt(); -}; - -Geometry.prototype.toEwkb = function () { - var ewkb = new BinaryWriter(this._getWkbSize() + 4); - var wkb = this.toWkb(); - - ewkb.writeInt8(1); - ewkb.writeUInt32LE((wkb.slice(1, 5).readUInt32LE(0) | 0x20000000) >>> 0, true); - ewkb.writeUInt32LE(this.srid); - - ewkb.writeBuffer(wkb.slice(5)); - - return ewkb.buffer; -}; - -Geometry.prototype._getWktType = function (wktType, isEmpty) { - var wkt = wktType; - - if (this.hasZ && this.hasM) - wkt += ' ZM '; - else if (this.hasZ) - wkt += ' Z '; - else if (this.hasM) - wkt += ' M '; - - if (isEmpty && !this.hasZ && !this.hasM) - wkt += ' '; - - if (isEmpty) - wkt += 'EMPTY'; - - return wkt; -}; - -Geometry.prototype._getWktCoordinate = function (point) { - var coordinates = point.x + ' ' + point.y; - - if (this.hasZ) - coordinates += ' ' + point.z; - if (this.hasM) - coordinates += ' ' + point.m; - - return coordinates; -}; - -Geometry.prototype._writeWkbType = function (wkb, geometryType, parentOptions) { - var dimensionType = 0; - - if (typeof this.srid === 'undefined' && (!parentOptions || typeof parentOptions.srid === 'undefined')) { - if (this.hasZ && this.hasM) - dimensionType += 3000; - else if (this.hasZ) - dimensionType += 1000; - else if (this.hasM) - dimensionType += 2000; - } - else { - if (this.hasZ) - dimensionType |= 0x80000000; - if (this.hasM) - dimensionType |= 0x40000000; - } - - wkb.writeUInt32LE((dimensionType + geometryType) >>> 0, true); -}; - -Geometry.getTwkbPrecision = function (xyPrecision, zPrecision, mPrecision) { - return { - xy: xyPrecision, - z: zPrecision, - m: mPrecision, - xyFactor: Math.pow(10, xyPrecision), - zFactor: Math.pow(10, zPrecision), - mFactor: Math.pow(10, mPrecision) - }; -}; - -Geometry.prototype._writeTwkbHeader = function (twkb, geometryType, precision, isEmpty) { - var type = (ZigZag.encode(precision.xy) << 4) + geometryType; - var metadataHeader = (this.hasZ || this.hasM) << 3; - metadataHeader += isEmpty << 4; - - twkb.writeUInt8(type); - twkb.writeUInt8(metadataHeader); - - if (this.hasZ || this.hasM) { - var extendedPrecision = 0; - if (this.hasZ) - extendedPrecision |= 0x1; - if (this.hasM) - extendedPrecision |= 0x2; - - twkb.writeUInt8(extendedPrecision); - } -}; - -Geometry.prototype.toGeoJSON = function (options) { - var geoJSON = {}; - - if (this.srid) { - if (options) { - if (options.shortCrs) { - geoJSON.crs = { - type: 'name', - properties: { - name: 'EPSG:' + this.srid - } - }; - } - else if (options.longCrs) { - geoJSON.crs = { - type: 'name', - properties: { - name: 'urn:ogc:def:crs:EPSG::' + this.srid - } - }; - } - } - } - - return geoJSON; -}; +module.exports = Geometry; + +var Types = require('./types'); +var Point = require('./point'); +var LineString = require('./linestring'); +var Polygon = require('./polygon'); +var MultiPoint = require('./multipoint'); +var MultiLineString = require('./multilinestring'); +var MultiPolygon = require('./multipolygon'); +var GeometryCollection = require('./geometrycollection'); +var BinaryReader = require('./binaryreader'); +var BinaryWriter = require('./binarywriter'); +var WktParser = require('./wktparser'); +var ZigZag = require('./zigzag.js'); + +function Geometry() { + this.srid = undefined; + this.hasZ = false; + this.hasM = false; +} + +Geometry.parse = function (value, options) { + var valueType = typeof value; + + if (valueType === 'string' || value instanceof WktParser) + return Geometry._parseWkt(value); + else if (Buffer.isBuffer(value) || value instanceof BinaryReader) + return Geometry._parseWkb(value, options); + else + throw new Error('first argument must be a string or Buffer'); +}; + +Geometry._parseWkt = function (value) { + var wktParser, + srid; + + if (value instanceof WktParser) + wktParser = value; + else + wktParser = new WktParser(value); + + var match = wktParser.matchRegex([/^SRID=(\d+);/]); + if (match) + srid = parseInt(match[1], 10); + + var geometryType = wktParser.matchType(); + var dimension = wktParser.matchDimension(); + + var options = { + srid: srid, + hasZ: dimension.hasZ, + hasM: dimension.hasM + }; + + switch (geometryType) { + case Types.wkt.Point: + return Point._parseWkt(wktParser, options); + case Types.wkt.LineString: + return LineString._parseWkt(wktParser, options); + case Types.wkt.Polygon: + return Polygon._parseWkt(wktParser, options); + case Types.wkt.MultiPoint: + return MultiPoint._parseWkt(wktParser, options); + case Types.wkt.MultiLineString: + return MultiLineString._parseWkt(wktParser, options); + case Types.wkt.MultiPolygon: + return MultiPolygon._parseWkt(wktParser, options); + case Types.wkt.GeometryCollection: + return GeometryCollection._parseWkt(wktParser, options); + } +}; + +Geometry._parseWkb = function (value, parentOptions) { + var binaryReader, + wkbType, + geometryType, + options = {}; + + if (value instanceof BinaryReader) + binaryReader = value; + else + binaryReader = new BinaryReader(value); + + binaryReader.isBigEndian = !binaryReader.readInt8(); + + wkbType = binaryReader.readUInt32(); + + options.hasSrid = (wkbType & 0x20000000) === 0x20000000; + options.isEwkb = (wkbType & 0x20000000) || (wkbType & 0x40000000) || (wkbType & 0x80000000); + + if (options.hasSrid) + options.srid = binaryReader.readUInt32(); + + options.hasZ = false; + options.hasM = false; + + if (!options.isEwkb && (!parentOptions || !parentOptions.isEwkb)) { + if (wkbType >= 1000 && wkbType < 2000) { + options.hasZ = true; + geometryType = wkbType - 1000; + } + else if (wkbType >= 2000 && wkbType < 3000) { + options.hasM = true; + geometryType = wkbType - 2000; + } + else if (wkbType >= 3000 && wkbType < 4000) { + options.hasZ = true; + options.hasM = true; + geometryType = wkbType - 3000; + } + else { + geometryType = wkbType; + } + } + else { + if (wkbType & 0x80000000) + options.hasZ = true; + if (wkbType & 0x40000000) + options.hasM = true; + + geometryType = wkbType & 0xF; + } + + switch (geometryType) { + case Types.wkb.Point: + return Point._parseWkb(binaryReader, options); + case Types.wkb.LineString: + return LineString._parseWkb(binaryReader, options); + case Types.wkb.Polygon: + return Polygon._parseWkb(binaryReader, options); + case Types.wkb.MultiPoint: + return MultiPoint._parseWkb(binaryReader, options); + case Types.wkb.MultiLineString: + return MultiLineString._parseWkb(binaryReader, options); + case Types.wkb.MultiPolygon: + return MultiPolygon._parseWkb(binaryReader, options); + case Types.wkb.GeometryCollection: + return GeometryCollection._parseWkb(binaryReader, options); + default: + throw new Error('GeometryType ' + geometryType + ' not supported'); + } +}; + +Geometry.parseTwkb = function (value) { + var binaryReader, + options = {}; + + if (value instanceof BinaryReader) + binaryReader = value; + else + binaryReader = new BinaryReader(value); + + var type = binaryReader.readUInt8(); + var metadataHeader = binaryReader.readUInt8(); + + var geometryType = type & 0x0F; + options.precision = ZigZag.decode(type >> 4); + options.precisionFactor = Math.pow(10, options.precision); + + options.hasBoundingBox = metadataHeader >> 0 & 1; + options.hasSizeAttribute = metadataHeader >> 1 & 1; + options.hasIdList = metadataHeader >> 2 & 1; + options.hasExtendedPrecision = metadataHeader >> 3 & 1; + options.isEmpty = metadataHeader >> 4 & 1; + + if (options.hasExtendedPrecision) { + var extendedPrecision = binaryReader.readUInt8(); + options.hasZ = (extendedPrecision & 0x01) === 0x01; + options.hasM = (extendedPrecision & 0x02) === 0x02; + + options.zPrecision = ZigZag.decode((extendedPrecision & 0x1C) >> 2); + options.zPrecisionFactor = Math.pow(10, options.zPrecision); + + options.mPrecision = ZigZag.decode((extendedPrecision & 0xE0) >> 5); + options.mPrecisionFactor = Math.pow(10, options.mPrecision); + } + else { + options.hasZ = false; + options.hasM = false; + } + + if (options.hasSizeAttribute) + binaryReader.readVarInt(); + if (options.hasBoundingBox) { + var dimensions = 2; + + if (options.hasZ) + dimensions++; + if (options.hasM) + dimensions++; + + for (var i = 0; i < dimensions; i++) { + binaryReader.readVarInt(); + binaryReader.readVarInt(); + } + } + + switch (geometryType) { + case Types.wkb.Point: + return Point._parseTwkb(binaryReader, options); + case Types.wkb.LineString: + return LineString._parseTwkb(binaryReader, options); + case Types.wkb.Polygon: + return Polygon._parseTwkb(binaryReader, options); + case Types.wkb.MultiPoint: + return MultiPoint._parseTwkb(binaryReader, options); + case Types.wkb.MultiLineString: + return MultiLineString._parseTwkb(binaryReader, options); + case Types.wkb.MultiPolygon: + return MultiPolygon._parseTwkb(binaryReader, options); + case Types.wkb.GeometryCollection: + return GeometryCollection._parseTwkb(binaryReader, options); + default: + throw new Error('GeometryType ' + geometryType + ' not supported'); + } +}; + +Geometry.parseGeoJSON = function (value) { + return Geometry._parseGeoJSON(value); +}; + +Geometry._parseGeoJSON = function (value, isSubGeometry) { + var geometry; + + switch (value.type) { + case Types.geoJSON.Point: + geometry = Point._parseGeoJSON(value); break; + case Types.geoJSON.LineString: + geometry = LineString._parseGeoJSON(value); break; + case Types.geoJSON.Polygon: + geometry = Polygon._parseGeoJSON(value); break; + case Types.geoJSON.MultiPoint: + geometry = MultiPoint._parseGeoJSON(value); break; + case Types.geoJSON.MultiLineString: + geometry = MultiLineString._parseGeoJSON(value); break; + case Types.geoJSON.MultiPolygon: + geometry = MultiPolygon._parseGeoJSON(value); break; + case Types.geoJSON.GeometryCollection: + geometry = GeometryCollection._parseGeoJSON(value); break; + default: + throw new Error('GeometryType ' + value.type + ' not supported'); + } + + if (value.crs && value.crs.type && value.crs.type === 'name' && value.crs.properties && value.crs.properties.name) { + var crs = value.crs.properties.name; + + if (crs.indexOf('EPSG:') === 0) + geometry.srid = parseInt(crs.substring(5)); + else if (crs.indexOf('urn:ogc:def:crs:EPSG::') === 0) + geometry.srid = parseInt(crs.substring(22)); + else + throw new Error('Unsupported crs: ' + crs); + } + else if (!isSubGeometry) { + geometry.srid = 4326; + } + + return geometry; +}; + +Geometry.prototype.toEwkt = function () { + return 'SRID=' + this.srid + ';' + this.toWkt(); +}; + +Geometry.prototype.toEwkb = function () { + var ewkb = new BinaryWriter(this._getWkbSize() + 4); + var wkb = this.toWkb(); + + ewkb.writeInt8(1); + ewkb.writeUInt32LE((wkb.slice(1, 5).readUInt32LE(0) | 0x20000000) >>> 0, true); + ewkb.writeUInt32LE(this.srid); + + ewkb.writeBuffer(wkb.slice(5)); + + return ewkb.buffer; +}; + +Geometry.prototype._getWktType = function (wktType, isEmpty) { + var wkt = wktType; + + if (this.hasZ && this.hasM) + wkt += ' ZM '; + else if (this.hasZ) + wkt += ' Z '; + else if (this.hasM) + wkt += ' M '; + + if (isEmpty && !this.hasZ && !this.hasM) + wkt += ' '; + + if (isEmpty) + wkt += 'EMPTY'; + + return wkt; +}; + +Geometry.prototype._getWktCoordinate = function (point) { + var coordinates = point.x + ' ' + point.y; + + if (this.hasZ) + coordinates += ' ' + point.z; + if (this.hasM) + coordinates += ' ' + point.m; + + return coordinates; +}; + +Geometry.prototype._writeWkbType = function (wkb, geometryType, parentOptions) { + var dimensionType = 0; + + if (typeof this.srid === 'undefined' && (!parentOptions || typeof parentOptions.srid === 'undefined')) { + if (this.hasZ && this.hasM) + dimensionType += 3000; + else if (this.hasZ) + dimensionType += 1000; + else if (this.hasM) + dimensionType += 2000; + } + else { + if (this.hasZ) + dimensionType |= 0x80000000; + if (this.hasM) + dimensionType |= 0x40000000; + } + + wkb.writeUInt32LE((dimensionType + geometryType) >>> 0, true); +}; + +Geometry.getTwkbPrecision = function (xyPrecision, zPrecision, mPrecision) { + return { + xy: xyPrecision, + z: zPrecision, + m: mPrecision, + xyFactor: Math.pow(10, xyPrecision), + zFactor: Math.pow(10, zPrecision), + mFactor: Math.pow(10, mPrecision) + }; +}; + +Geometry.prototype._writeTwkbHeader = function (twkb, geometryType, precision, isEmpty) { + var type = (ZigZag.encode(precision.xy) << 4) + geometryType; + var metadataHeader = (this.hasZ || this.hasM) << 3; + metadataHeader += isEmpty << 4; + + twkb.writeUInt8(type); + twkb.writeUInt8(metadataHeader); + + if (this.hasZ || this.hasM) { + var extendedPrecision = 0; + if (this.hasZ) + extendedPrecision |= 0x1; + if (this.hasM) + extendedPrecision |= 0x2; + + twkb.writeUInt8(extendedPrecision); + } +}; + +Geometry.prototype.toGeoJSON = function (options) { + var geoJSON = {}; + + if (this.srid) { + if (options) { + if (options.shortCrs) { + geoJSON.crs = { + type: 'name', + properties: { + name: 'EPSG:' + this.srid + } + }; + } + else if (options.longCrs) { + geoJSON.crs = { + type: 'name', + properties: { + name: 'urn:ogc:def:crs:EPSG::' + this.srid + } + }; + } + } + } + + return geoJSON; +}; diff --git a/backend/node_modules/wkx/lib/geometrycollection.js b/backend/node_modules/wkx/lib/geometrycollection.js index 393c16a..a886111 100644 --- a/backend/node_modules/wkx/lib/geometrycollection.js +++ b/backend/node_modules/wkx/lib/geometrycollection.js @@ -1,169 +1,169 @@ -module.exports = GeometryCollection; - -var util = require('util'); - -var Types = require('./types'); -var Geometry = require('./geometry'); -var BinaryWriter = require('./binarywriter'); - -function GeometryCollection(geometries, srid) { - Geometry.call(this); - - this.geometries = geometries || []; - this.srid = srid; - - if (this.geometries.length > 0) { - this.hasZ = this.geometries[0].hasZ; - this.hasM = this.geometries[0].hasM; - } -} - -util.inherits(GeometryCollection, Geometry); - -GeometryCollection.Z = function (geometries, srid) { - var geometryCollection = new GeometryCollection(geometries, srid); - geometryCollection.hasZ = true; - return geometryCollection; -}; - -GeometryCollection.M = function (geometries, srid) { - var geometryCollection = new GeometryCollection(geometries, srid); - geometryCollection.hasM = true; - return geometryCollection; -}; - -GeometryCollection.ZM = function (geometries, srid) { - var geometryCollection = new GeometryCollection(geometries, srid); - geometryCollection.hasZ = true; - geometryCollection.hasM = true; - return geometryCollection; -}; - -GeometryCollection._parseWkt = function (value, options) { - var geometryCollection = new GeometryCollection(); - geometryCollection.srid = options.srid; - geometryCollection.hasZ = options.hasZ; - geometryCollection.hasM = options.hasM; - - if (value.isMatch(['EMPTY'])) - return geometryCollection; - - value.expectGroupStart(); - - do { - geometryCollection.geometries.push(Geometry.parse(value)); - } while (value.isMatch([','])); - - value.expectGroupEnd(); - - return geometryCollection; -}; - -GeometryCollection._parseWkb = function (value, options) { - var geometryCollection = new GeometryCollection(); - geometryCollection.srid = options.srid; - geometryCollection.hasZ = options.hasZ; - geometryCollection.hasM = options.hasM; - - var geometryCount = value.readUInt32(); - - for (var i = 0; i < geometryCount; i++) - geometryCollection.geometries.push(Geometry.parse(value, options)); - - return geometryCollection; -}; - -GeometryCollection._parseTwkb = function (value, options) { - var geometryCollection = new GeometryCollection(); - geometryCollection.hasZ = options.hasZ; - geometryCollection.hasM = options.hasM; - - if (options.isEmpty) - return geometryCollection; - - var geometryCount = value.readVarInt(); - - for (var i = 0; i < geometryCount; i++) - geometryCollection.geometries.push(Geometry.parseTwkb(value)); - - return geometryCollection; -}; - -GeometryCollection._parseGeoJSON = function (value) { - var geometryCollection = new GeometryCollection(); - - for (var i = 0; i < value.geometries.length; i++) - geometryCollection.geometries.push(Geometry._parseGeoJSON(value.geometries[i], true)); - - if (geometryCollection.geometries.length > 0) - geometryCollection.hasZ = geometryCollection.geometries[0].hasZ; - - return geometryCollection; -}; - -GeometryCollection.prototype.toWkt = function () { - if (this.geometries.length === 0) - return this._getWktType(Types.wkt.GeometryCollection, true); - - var wkt = this._getWktType(Types.wkt.GeometryCollection, false) + '('; - - for (var i = 0; i < this.geometries.length; i++) - wkt += this.geometries[i].toWkt() + ','; - - wkt = wkt.slice(0, -1); - wkt += ')'; - - return wkt; -}; - -GeometryCollection.prototype.toWkb = function () { - var wkb = new BinaryWriter(this._getWkbSize()); - - wkb.writeInt8(1); - - this._writeWkbType(wkb, Types.wkb.GeometryCollection); - wkb.writeUInt32LE(this.geometries.length); - - for (var i = 0; i < this.geometries.length; i++) - wkb.writeBuffer(this.geometries[i].toWkb({ srid: this.srid })); - - return wkb.buffer; -}; - -GeometryCollection.prototype.toTwkb = function () { - var twkb = new BinaryWriter(0, true); - - var precision = Geometry.getTwkbPrecision(5, 0, 0); - var isEmpty = this.geometries.length === 0; - - this._writeTwkbHeader(twkb, Types.wkb.GeometryCollection, precision, isEmpty); - - if (this.geometries.length > 0) { - twkb.writeVarInt(this.geometries.length); - - for (var i = 0; i < this.geometries.length; i++) - twkb.writeBuffer(this.geometries[i].toTwkb()); - } - - return twkb.buffer; -}; - -GeometryCollection.prototype._getWkbSize = function () { - var size = 1 + 4 + 4; - - for (var i = 0; i < this.geometries.length; i++) - size += this.geometries[i]._getWkbSize(); - - return size; -}; - -GeometryCollection.prototype.toGeoJSON = function (options) { - var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); - geoJSON.type = Types.geoJSON.GeometryCollection; - geoJSON.geometries = []; - - for (var i = 0; i < this.geometries.length; i++) - geoJSON.geometries.push(this.geometries[i].toGeoJSON()); - - return geoJSON; -}; +module.exports = GeometryCollection; + +var util = require('util'); + +var Types = require('./types'); +var Geometry = require('./geometry'); +var BinaryWriter = require('./binarywriter'); + +function GeometryCollection(geometries, srid) { + Geometry.call(this); + + this.geometries = geometries || []; + this.srid = srid; + + if (this.geometries.length > 0) { + this.hasZ = this.geometries[0].hasZ; + this.hasM = this.geometries[0].hasM; + } +} + +util.inherits(GeometryCollection, Geometry); + +GeometryCollection.Z = function (geometries, srid) { + var geometryCollection = new GeometryCollection(geometries, srid); + geometryCollection.hasZ = true; + return geometryCollection; +}; + +GeometryCollection.M = function (geometries, srid) { + var geometryCollection = new GeometryCollection(geometries, srid); + geometryCollection.hasM = true; + return geometryCollection; +}; + +GeometryCollection.ZM = function (geometries, srid) { + var geometryCollection = new GeometryCollection(geometries, srid); + geometryCollection.hasZ = true; + geometryCollection.hasM = true; + return geometryCollection; +}; + +GeometryCollection._parseWkt = function (value, options) { + var geometryCollection = new GeometryCollection(); + geometryCollection.srid = options.srid; + geometryCollection.hasZ = options.hasZ; + geometryCollection.hasM = options.hasM; + + if (value.isMatch(['EMPTY'])) + return geometryCollection; + + value.expectGroupStart(); + + do { + geometryCollection.geometries.push(Geometry.parse(value)); + } while (value.isMatch([','])); + + value.expectGroupEnd(); + + return geometryCollection; +}; + +GeometryCollection._parseWkb = function (value, options) { + var geometryCollection = new GeometryCollection(); + geometryCollection.srid = options.srid; + geometryCollection.hasZ = options.hasZ; + geometryCollection.hasM = options.hasM; + + var geometryCount = value.readUInt32(); + + for (var i = 0; i < geometryCount; i++) + geometryCollection.geometries.push(Geometry.parse(value, options)); + + return geometryCollection; +}; + +GeometryCollection._parseTwkb = function (value, options) { + var geometryCollection = new GeometryCollection(); + geometryCollection.hasZ = options.hasZ; + geometryCollection.hasM = options.hasM; + + if (options.isEmpty) + return geometryCollection; + + var geometryCount = value.readVarInt(); + + for (var i = 0; i < geometryCount; i++) + geometryCollection.geometries.push(Geometry.parseTwkb(value)); + + return geometryCollection; +}; + +GeometryCollection._parseGeoJSON = function (value) { + var geometryCollection = new GeometryCollection(); + + for (var i = 0; i < value.geometries.length; i++) + geometryCollection.geometries.push(Geometry._parseGeoJSON(value.geometries[i], true)); + + if (geometryCollection.geometries.length > 0) + geometryCollection.hasZ = geometryCollection.geometries[0].hasZ; + + return geometryCollection; +}; + +GeometryCollection.prototype.toWkt = function () { + if (this.geometries.length === 0) + return this._getWktType(Types.wkt.GeometryCollection, true); + + var wkt = this._getWktType(Types.wkt.GeometryCollection, false) + '('; + + for (var i = 0; i < this.geometries.length; i++) + wkt += this.geometries[i].toWkt() + ','; + + wkt = wkt.slice(0, -1); + wkt += ')'; + + return wkt; +}; + +GeometryCollection.prototype.toWkb = function () { + var wkb = new BinaryWriter(this._getWkbSize()); + + wkb.writeInt8(1); + + this._writeWkbType(wkb, Types.wkb.GeometryCollection); + wkb.writeUInt32LE(this.geometries.length); + + for (var i = 0; i < this.geometries.length; i++) + wkb.writeBuffer(this.geometries[i].toWkb({ srid: this.srid })); + + return wkb.buffer; +}; + +GeometryCollection.prototype.toTwkb = function () { + var twkb = new BinaryWriter(0, true); + + var precision = Geometry.getTwkbPrecision(5, 0, 0); + var isEmpty = this.geometries.length === 0; + + this._writeTwkbHeader(twkb, Types.wkb.GeometryCollection, precision, isEmpty); + + if (this.geometries.length > 0) { + twkb.writeVarInt(this.geometries.length); + + for (var i = 0; i < this.geometries.length; i++) + twkb.writeBuffer(this.geometries[i].toTwkb()); + } + + return twkb.buffer; +}; + +GeometryCollection.prototype._getWkbSize = function () { + var size = 1 + 4 + 4; + + for (var i = 0; i < this.geometries.length; i++) + size += this.geometries[i]._getWkbSize(); + + return size; +}; + +GeometryCollection.prototype.toGeoJSON = function (options) { + var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); + geoJSON.type = Types.geoJSON.GeometryCollection; + geoJSON.geometries = []; + + for (var i = 0; i < this.geometries.length; i++) + geoJSON.geometries.push(this.geometries[i].toGeoJSON()); + + return geoJSON; +}; diff --git a/backend/node_modules/wkx/lib/linestring.js b/backend/node_modules/wkx/lib/linestring.js index 86ca088..fd245d9 100644 --- a/backend/node_modules/wkx/lib/linestring.js +++ b/backend/node_modules/wkx/lib/linestring.js @@ -1,178 +1,178 @@ -module.exports = LineString; - -var util = require('util'); - -var Geometry = require('./geometry'); -var Types = require('./types'); -var Point = require('./point'); -var BinaryWriter = require('./binarywriter'); - -function LineString(points, srid) { - Geometry.call(this); - - this.points = points || []; - this.srid = srid; - - if (this.points.length > 0) { - this.hasZ = this.points[0].hasZ; - this.hasM = this.points[0].hasM; - } -} - -util.inherits(LineString, Geometry); - -LineString.Z = function (points, srid) { - var lineString = new LineString(points, srid); - lineString.hasZ = true; - return lineString; -}; - -LineString.M = function (points, srid) { - var lineString = new LineString(points, srid); - lineString.hasM = true; - return lineString; -}; - -LineString.ZM = function (points, srid) { - var lineString = new LineString(points, srid); - lineString.hasZ = true; - lineString.hasM = true; - return lineString; -}; - -LineString._parseWkt = function (value, options) { - var lineString = new LineString(); - lineString.srid = options.srid; - lineString.hasZ = options.hasZ; - lineString.hasM = options.hasM; - - if (value.isMatch(['EMPTY'])) - return lineString; - - value.expectGroupStart(); - lineString.points.push.apply(lineString.points, value.matchCoordinates(options)); - value.expectGroupEnd(); - - return lineString; -}; - -LineString._parseWkb = function (value, options) { - var lineString = new LineString(); - lineString.srid = options.srid; - lineString.hasZ = options.hasZ; - lineString.hasM = options.hasM; - - var pointCount = value.readUInt32(); - - for (var i = 0; i < pointCount; i++) - lineString.points.push(Point._readWkbPoint(value, options)); - - return lineString; -}; - -LineString._parseTwkb = function (value, options) { - var lineString = new LineString(); - lineString.hasZ = options.hasZ; - lineString.hasM = options.hasM; - - if (options.isEmpty) - return lineString; - - var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); - var pointCount = value.readVarInt(); - - for (var i = 0; i < pointCount; i++) - lineString.points.push(Point._readTwkbPoint(value, options, previousPoint)); - - return lineString; -}; - -LineString._parseGeoJSON = function (value) { - var lineString = new LineString(); - - if (value.coordinates.length > 0) - lineString.hasZ = value.coordinates[0].length > 2; - - for (var i = 0; i < value.coordinates.length; i++) - lineString.points.push(Point._readGeoJSONPoint(value.coordinates[i])); - - return lineString; -}; - -LineString.prototype.toWkt = function () { - if (this.points.length === 0) - return this._getWktType(Types.wkt.LineString, true); - - return this._getWktType(Types.wkt.LineString, false) + this._toInnerWkt(); -}; - -LineString.prototype._toInnerWkt = function () { - var innerWkt = '('; - - for (var i = 0; i < this.points.length; i++) - innerWkt += this._getWktCoordinate(this.points[i]) + ','; - - innerWkt = innerWkt.slice(0, -1); - innerWkt += ')'; - - return innerWkt; -}; - -LineString.prototype.toWkb = function (parentOptions) { - var wkb = new BinaryWriter(this._getWkbSize()); - - wkb.writeInt8(1); - - this._writeWkbType(wkb, Types.wkb.LineString, parentOptions); - wkb.writeUInt32LE(this.points.length); - - for (var i = 0; i < this.points.length; i++) - this.points[i]._writeWkbPoint(wkb); - - return wkb.buffer; -}; - -LineString.prototype.toTwkb = function () { - var twkb = new BinaryWriter(0, true); - - var precision = Geometry.getTwkbPrecision(5, 0, 0); - var isEmpty = this.points.length === 0; - - this._writeTwkbHeader(twkb, Types.wkb.LineString, precision, isEmpty); - - if (this.points.length > 0) { - twkb.writeVarInt(this.points.length); - - var previousPoint = new Point(0, 0, 0, 0); - for (var i = 0; i < this.points.length; i++) - this.points[i]._writeTwkbPoint(twkb, precision, previousPoint); - } - - return twkb.buffer; -}; - -LineString.prototype._getWkbSize = function () { - var coordinateSize = 16; - - if (this.hasZ) - coordinateSize += 8; - if (this.hasM) - coordinateSize += 8; - - return 1 + 4 + 4 + (this.points.length * coordinateSize); -}; - -LineString.prototype.toGeoJSON = function (options) { - var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); - geoJSON.type = Types.geoJSON.LineString; - geoJSON.coordinates = []; - - for (var i = 0; i < this.points.length; i++) { - if (this.hasZ) - geoJSON.coordinates.push([this.points[i].x, this.points[i].y, this.points[i].z]); - else - geoJSON.coordinates.push([this.points[i].x, this.points[i].y]); - } - - return geoJSON; -}; +module.exports = LineString; + +var util = require('util'); + +var Geometry = require('./geometry'); +var Types = require('./types'); +var Point = require('./point'); +var BinaryWriter = require('./binarywriter'); + +function LineString(points, srid) { + Geometry.call(this); + + this.points = points || []; + this.srid = srid; + + if (this.points.length > 0) { + this.hasZ = this.points[0].hasZ; + this.hasM = this.points[0].hasM; + } +} + +util.inherits(LineString, Geometry); + +LineString.Z = function (points, srid) { + var lineString = new LineString(points, srid); + lineString.hasZ = true; + return lineString; +}; + +LineString.M = function (points, srid) { + var lineString = new LineString(points, srid); + lineString.hasM = true; + return lineString; +}; + +LineString.ZM = function (points, srid) { + var lineString = new LineString(points, srid); + lineString.hasZ = true; + lineString.hasM = true; + return lineString; +}; + +LineString._parseWkt = function (value, options) { + var lineString = new LineString(); + lineString.srid = options.srid; + lineString.hasZ = options.hasZ; + lineString.hasM = options.hasM; + + if (value.isMatch(['EMPTY'])) + return lineString; + + value.expectGroupStart(); + lineString.points.push.apply(lineString.points, value.matchCoordinates(options)); + value.expectGroupEnd(); + + return lineString; +}; + +LineString._parseWkb = function (value, options) { + var lineString = new LineString(); + lineString.srid = options.srid; + lineString.hasZ = options.hasZ; + lineString.hasM = options.hasM; + + var pointCount = value.readUInt32(); + + for (var i = 0; i < pointCount; i++) + lineString.points.push(Point._readWkbPoint(value, options)); + + return lineString; +}; + +LineString._parseTwkb = function (value, options) { + var lineString = new LineString(); + lineString.hasZ = options.hasZ; + lineString.hasM = options.hasM; + + if (options.isEmpty) + return lineString; + + var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); + var pointCount = value.readVarInt(); + + for (var i = 0; i < pointCount; i++) + lineString.points.push(Point._readTwkbPoint(value, options, previousPoint)); + + return lineString; +}; + +LineString._parseGeoJSON = function (value) { + var lineString = new LineString(); + + if (value.coordinates.length > 0) + lineString.hasZ = value.coordinates[0].length > 2; + + for (var i = 0; i < value.coordinates.length; i++) + lineString.points.push(Point._readGeoJSONPoint(value.coordinates[i])); + + return lineString; +}; + +LineString.prototype.toWkt = function () { + if (this.points.length === 0) + return this._getWktType(Types.wkt.LineString, true); + + return this._getWktType(Types.wkt.LineString, false) + this._toInnerWkt(); +}; + +LineString.prototype._toInnerWkt = function () { + var innerWkt = '('; + + for (var i = 0; i < this.points.length; i++) + innerWkt += this._getWktCoordinate(this.points[i]) + ','; + + innerWkt = innerWkt.slice(0, -1); + innerWkt += ')'; + + return innerWkt; +}; + +LineString.prototype.toWkb = function (parentOptions) { + var wkb = new BinaryWriter(this._getWkbSize()); + + wkb.writeInt8(1); + + this._writeWkbType(wkb, Types.wkb.LineString, parentOptions); + wkb.writeUInt32LE(this.points.length); + + for (var i = 0; i < this.points.length; i++) + this.points[i]._writeWkbPoint(wkb); + + return wkb.buffer; +}; + +LineString.prototype.toTwkb = function () { + var twkb = new BinaryWriter(0, true); + + var precision = Geometry.getTwkbPrecision(5, 0, 0); + var isEmpty = this.points.length === 0; + + this._writeTwkbHeader(twkb, Types.wkb.LineString, precision, isEmpty); + + if (this.points.length > 0) { + twkb.writeVarInt(this.points.length); + + var previousPoint = new Point(0, 0, 0, 0); + for (var i = 0; i < this.points.length; i++) + this.points[i]._writeTwkbPoint(twkb, precision, previousPoint); + } + + return twkb.buffer; +}; + +LineString.prototype._getWkbSize = function () { + var coordinateSize = 16; + + if (this.hasZ) + coordinateSize += 8; + if (this.hasM) + coordinateSize += 8; + + return 1 + 4 + 4 + (this.points.length * coordinateSize); +}; + +LineString.prototype.toGeoJSON = function (options) { + var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); + geoJSON.type = Types.geoJSON.LineString; + geoJSON.coordinates = []; + + for (var i = 0; i < this.points.length; i++) { + if (this.hasZ) + geoJSON.coordinates.push([this.points[i].x, this.points[i].y, this.points[i].z]); + else + geoJSON.coordinates.push([this.points[i].x, this.points[i].y]); + } + + return geoJSON; +}; diff --git a/backend/node_modules/wkx/lib/multilinestring.js b/backend/node_modules/wkx/lib/multilinestring.js index 42f8ff4..c417666 100644 --- a/backend/node_modules/wkx/lib/multilinestring.js +++ b/backend/node_modules/wkx/lib/multilinestring.js @@ -1,189 +1,189 @@ -module.exports = MultiLineString; - -var util = require('util'); - -var Types = require('./types'); -var Geometry = require('./geometry'); -var Point = require('./point'); -var LineString = require('./linestring'); -var BinaryWriter = require('./binarywriter'); - -function MultiLineString(lineStrings, srid) { - Geometry.call(this); - - this.lineStrings = lineStrings || []; - this.srid = srid; - - if (this.lineStrings.length > 0) { - this.hasZ = this.lineStrings[0].hasZ; - this.hasM = this.lineStrings[0].hasM; - } -} - -util.inherits(MultiLineString, Geometry); - -MultiLineString.Z = function (lineStrings, srid) { - var multiLineString = new MultiLineString(lineStrings, srid); - multiLineString.hasZ = true; - return multiLineString; -}; - -MultiLineString.M = function (lineStrings, srid) { - var multiLineString = new MultiLineString(lineStrings, srid); - multiLineString.hasM = true; - return multiLineString; -}; - -MultiLineString.ZM = function (lineStrings, srid) { - var multiLineString = new MultiLineString(lineStrings, srid); - multiLineString.hasZ = true; - multiLineString.hasM = true; - return multiLineString; -}; - -MultiLineString._parseWkt = function (value, options) { - var multiLineString = new MultiLineString(); - multiLineString.srid = options.srid; - multiLineString.hasZ = options.hasZ; - multiLineString.hasM = options.hasM; - - if (value.isMatch(['EMPTY'])) - return multiLineString; - - value.expectGroupStart(); - - do { - value.expectGroupStart(); - multiLineString.lineStrings.push(new LineString(value.matchCoordinates(options))); - value.expectGroupEnd(); - } while (value.isMatch([','])); - - value.expectGroupEnd(); - - return multiLineString; -}; - -MultiLineString._parseWkb = function (value, options) { - var multiLineString = new MultiLineString(); - multiLineString.srid = options.srid; - multiLineString.hasZ = options.hasZ; - multiLineString.hasM = options.hasM; - - var lineStringCount = value.readUInt32(); - - for (var i = 0; i < lineStringCount; i++) - multiLineString.lineStrings.push(Geometry.parse(value, options)); - - return multiLineString; -}; - -MultiLineString._parseTwkb = function (value, options) { - var multiLineString = new MultiLineString(); - multiLineString.hasZ = options.hasZ; - multiLineString.hasM = options.hasM; - - if (options.isEmpty) - return multiLineString; - - var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); - var lineStringCount = value.readVarInt(); - - for (var i = 0; i < lineStringCount; i++) { - var lineString = new LineString(); - lineString.hasZ = options.hasZ; - lineString.hasM = options.hasM; - - var pointCount = value.readVarInt(); - - for (var j = 0; j < pointCount; j++) - lineString.points.push(Point._readTwkbPoint(value, options, previousPoint)); - - multiLineString.lineStrings.push(lineString); - } - - return multiLineString; -}; - -MultiLineString._parseGeoJSON = function (value) { - var multiLineString = new MultiLineString(); - - if (value.coordinates.length > 0 && value.coordinates[0].length > 0) - multiLineString.hasZ = value.coordinates[0][0].length > 2; - - for (var i = 0; i < value.coordinates.length; i++) - multiLineString.lineStrings.push(LineString._parseGeoJSON({ coordinates: value.coordinates[i] })); - - return multiLineString; -}; - -MultiLineString.prototype.toWkt = function () { - if (this.lineStrings.length === 0) - return this._getWktType(Types.wkt.MultiLineString, true); - - var wkt = this._getWktType(Types.wkt.MultiLineString, false) + '('; - - for (var i = 0; i < this.lineStrings.length; i++) - wkt += this.lineStrings[i]._toInnerWkt() + ','; - - wkt = wkt.slice(0, -1); - wkt += ')'; - - return wkt; -}; - -MultiLineString.prototype.toWkb = function () { - var wkb = new BinaryWriter(this._getWkbSize()); - - wkb.writeInt8(1); - - this._writeWkbType(wkb, Types.wkb.MultiLineString); - wkb.writeUInt32LE(this.lineStrings.length); - - for (var i = 0; i < this.lineStrings.length; i++) - wkb.writeBuffer(this.lineStrings[i].toWkb({ srid: this.srid })); - - return wkb.buffer; -}; - -MultiLineString.prototype.toTwkb = function () { - var twkb = new BinaryWriter(0, true); - - var precision = Geometry.getTwkbPrecision(5, 0, 0); - var isEmpty = this.lineStrings.length === 0; - - this._writeTwkbHeader(twkb, Types.wkb.MultiLineString, precision, isEmpty); - - if (this.lineStrings.length > 0) { - twkb.writeVarInt(this.lineStrings.length); - - var previousPoint = new Point(0, 0, 0, 0); - for (var i = 0; i < this.lineStrings.length; i++) { - twkb.writeVarInt(this.lineStrings[i].points.length); - - for (var j = 0; j < this.lineStrings[i].points.length; j++) - this.lineStrings[i].points[j]._writeTwkbPoint(twkb, precision, previousPoint); - } - } - - return twkb.buffer; -}; - -MultiLineString.prototype._getWkbSize = function () { - var size = 1 + 4 + 4; - - for (var i = 0; i < this.lineStrings.length; i++) - size += this.lineStrings[i]._getWkbSize(); - - return size; -}; - -MultiLineString.prototype.toGeoJSON = function (options) { - var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); - geoJSON.type = Types.geoJSON.MultiLineString; - geoJSON.coordinates = []; - - for (var i = 0; i < this.lineStrings.length; i++) - geoJSON.coordinates.push(this.lineStrings[i].toGeoJSON().coordinates); - - return geoJSON; -}; +module.exports = MultiLineString; + +var util = require('util'); + +var Types = require('./types'); +var Geometry = require('./geometry'); +var Point = require('./point'); +var LineString = require('./linestring'); +var BinaryWriter = require('./binarywriter'); + +function MultiLineString(lineStrings, srid) { + Geometry.call(this); + + this.lineStrings = lineStrings || []; + this.srid = srid; + + if (this.lineStrings.length > 0) { + this.hasZ = this.lineStrings[0].hasZ; + this.hasM = this.lineStrings[0].hasM; + } +} + +util.inherits(MultiLineString, Geometry); + +MultiLineString.Z = function (lineStrings, srid) { + var multiLineString = new MultiLineString(lineStrings, srid); + multiLineString.hasZ = true; + return multiLineString; +}; + +MultiLineString.M = function (lineStrings, srid) { + var multiLineString = new MultiLineString(lineStrings, srid); + multiLineString.hasM = true; + return multiLineString; +}; + +MultiLineString.ZM = function (lineStrings, srid) { + var multiLineString = new MultiLineString(lineStrings, srid); + multiLineString.hasZ = true; + multiLineString.hasM = true; + return multiLineString; +}; + +MultiLineString._parseWkt = function (value, options) { + var multiLineString = new MultiLineString(); + multiLineString.srid = options.srid; + multiLineString.hasZ = options.hasZ; + multiLineString.hasM = options.hasM; + + if (value.isMatch(['EMPTY'])) + return multiLineString; + + value.expectGroupStart(); + + do { + value.expectGroupStart(); + multiLineString.lineStrings.push(new LineString(value.matchCoordinates(options))); + value.expectGroupEnd(); + } while (value.isMatch([','])); + + value.expectGroupEnd(); + + return multiLineString; +}; + +MultiLineString._parseWkb = function (value, options) { + var multiLineString = new MultiLineString(); + multiLineString.srid = options.srid; + multiLineString.hasZ = options.hasZ; + multiLineString.hasM = options.hasM; + + var lineStringCount = value.readUInt32(); + + for (var i = 0; i < lineStringCount; i++) + multiLineString.lineStrings.push(Geometry.parse(value, options)); + + return multiLineString; +}; + +MultiLineString._parseTwkb = function (value, options) { + var multiLineString = new MultiLineString(); + multiLineString.hasZ = options.hasZ; + multiLineString.hasM = options.hasM; + + if (options.isEmpty) + return multiLineString; + + var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); + var lineStringCount = value.readVarInt(); + + for (var i = 0; i < lineStringCount; i++) { + var lineString = new LineString(); + lineString.hasZ = options.hasZ; + lineString.hasM = options.hasM; + + var pointCount = value.readVarInt(); + + for (var j = 0; j < pointCount; j++) + lineString.points.push(Point._readTwkbPoint(value, options, previousPoint)); + + multiLineString.lineStrings.push(lineString); + } + + return multiLineString; +}; + +MultiLineString._parseGeoJSON = function (value) { + var multiLineString = new MultiLineString(); + + if (value.coordinates.length > 0 && value.coordinates[0].length > 0) + multiLineString.hasZ = value.coordinates[0][0].length > 2; + + for (var i = 0; i < value.coordinates.length; i++) + multiLineString.lineStrings.push(LineString._parseGeoJSON({ coordinates: value.coordinates[i] })); + + return multiLineString; +}; + +MultiLineString.prototype.toWkt = function () { + if (this.lineStrings.length === 0) + return this._getWktType(Types.wkt.MultiLineString, true); + + var wkt = this._getWktType(Types.wkt.MultiLineString, false) + '('; + + for (var i = 0; i < this.lineStrings.length; i++) + wkt += this.lineStrings[i]._toInnerWkt() + ','; + + wkt = wkt.slice(0, -1); + wkt += ')'; + + return wkt; +}; + +MultiLineString.prototype.toWkb = function () { + var wkb = new BinaryWriter(this._getWkbSize()); + + wkb.writeInt8(1); + + this._writeWkbType(wkb, Types.wkb.MultiLineString); + wkb.writeUInt32LE(this.lineStrings.length); + + for (var i = 0; i < this.lineStrings.length; i++) + wkb.writeBuffer(this.lineStrings[i].toWkb({ srid: this.srid })); + + return wkb.buffer; +}; + +MultiLineString.prototype.toTwkb = function () { + var twkb = new BinaryWriter(0, true); + + var precision = Geometry.getTwkbPrecision(5, 0, 0); + var isEmpty = this.lineStrings.length === 0; + + this._writeTwkbHeader(twkb, Types.wkb.MultiLineString, precision, isEmpty); + + if (this.lineStrings.length > 0) { + twkb.writeVarInt(this.lineStrings.length); + + var previousPoint = new Point(0, 0, 0, 0); + for (var i = 0; i < this.lineStrings.length; i++) { + twkb.writeVarInt(this.lineStrings[i].points.length); + + for (var j = 0; j < this.lineStrings[i].points.length; j++) + this.lineStrings[i].points[j]._writeTwkbPoint(twkb, precision, previousPoint); + } + } + + return twkb.buffer; +}; + +MultiLineString.prototype._getWkbSize = function () { + var size = 1 + 4 + 4; + + for (var i = 0; i < this.lineStrings.length; i++) + size += this.lineStrings[i]._getWkbSize(); + + return size; +}; + +MultiLineString.prototype.toGeoJSON = function (options) { + var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); + geoJSON.type = Types.geoJSON.MultiLineString; + geoJSON.coordinates = []; + + for (var i = 0; i < this.lineStrings.length; i++) + geoJSON.coordinates.push(this.lineStrings[i].toGeoJSON().coordinates); + + return geoJSON; +}; diff --git a/backend/node_modules/wkx/lib/multipoint.js b/backend/node_modules/wkx/lib/multipoint.js index ab50f53..7d1a887 100644 --- a/backend/node_modules/wkx/lib/multipoint.js +++ b/backend/node_modules/wkx/lib/multipoint.js @@ -1,172 +1,172 @@ -module.exports = MultiPoint; - -var util = require('util'); - -var Types = require('./types'); -var Geometry = require('./geometry'); -var Point = require('./point'); -var BinaryWriter = require('./binarywriter'); - -function MultiPoint(points, srid) { - Geometry.call(this); - - this.points = points || []; - this.srid = srid; - - if (this.points.length > 0) { - this.hasZ = this.points[0].hasZ; - this.hasM = this.points[0].hasM; - } -} - -util.inherits(MultiPoint, Geometry); - -MultiPoint.Z = function (points, srid) { - var multiPoint = new MultiPoint(points, srid); - multiPoint.hasZ = true; - return multiPoint; -}; - -MultiPoint.M = function (points, srid) { - var multiPoint = new MultiPoint(points, srid); - multiPoint.hasM = true; - return multiPoint; -}; - -MultiPoint.ZM = function (points, srid) { - var multiPoint = new MultiPoint(points, srid); - multiPoint.hasZ = true; - multiPoint.hasM = true; - return multiPoint; -}; - -MultiPoint._parseWkt = function (value, options) { - var multiPoint = new MultiPoint(); - multiPoint.srid = options.srid; - multiPoint.hasZ = options.hasZ; - multiPoint.hasM = options.hasM; - - if (value.isMatch(['EMPTY'])) - return multiPoint; - - value.expectGroupStart(); - multiPoint.points.push.apply(multiPoint.points, value.matchCoordinates(options)); - value.expectGroupEnd(); - - return multiPoint; -}; - -MultiPoint._parseWkb = function (value, options) { - var multiPoint = new MultiPoint(); - multiPoint.srid = options.srid; - multiPoint.hasZ = options.hasZ; - multiPoint.hasM = options.hasM; - - var pointCount = value.readUInt32(); - - for (var i = 0; i < pointCount; i++) - multiPoint.points.push(Geometry.parse(value, options)); - - return multiPoint; -}; - -MultiPoint._parseTwkb = function (value, options) { - var multiPoint = new MultiPoint(); - multiPoint.hasZ = options.hasZ; - multiPoint.hasM = options.hasM; - - if (options.isEmpty) - return multiPoint; - - var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); - var pointCount = value.readVarInt(); - - for (var i = 0; i < pointCount; i++) - multiPoint.points.push(Point._readTwkbPoint(value, options, previousPoint)); - - return multiPoint; -}; - -MultiPoint._parseGeoJSON = function (value) { - var multiPoint = new MultiPoint(); - - if (value.coordinates.length > 0) - multiPoint.hasZ = value.coordinates[0].length > 2; - - for (var i = 0; i < value.coordinates.length; i++) - multiPoint.points.push(Point._parseGeoJSON({ coordinates: value.coordinates[i] })); - - return multiPoint; -}; - -MultiPoint.prototype.toWkt = function () { - if (this.points.length === 0) - return this._getWktType(Types.wkt.MultiPoint, true); - - var wkt = this._getWktType(Types.wkt.MultiPoint, false) + '('; - - for (var i = 0; i < this.points.length; i++) - wkt += this._getWktCoordinate(this.points[i]) + ','; - - wkt = wkt.slice(0, -1); - wkt += ')'; - - return wkt; -}; - -MultiPoint.prototype.toWkb = function () { - var wkb = new BinaryWriter(this._getWkbSize()); - - wkb.writeInt8(1); - - this._writeWkbType(wkb, Types.wkb.MultiPoint); - wkb.writeUInt32LE(this.points.length); - - for (var i = 0; i < this.points.length; i++) - wkb.writeBuffer(this.points[i].toWkb({ srid: this.srid })); - - return wkb.buffer; -}; - -MultiPoint.prototype.toTwkb = function () { - var twkb = new BinaryWriter(0, true); - - var precision = Geometry.getTwkbPrecision(5, 0, 0); - var isEmpty = this.points.length === 0; - - this._writeTwkbHeader(twkb, Types.wkb.MultiPoint, precision, isEmpty); - - if (this.points.length > 0) { - twkb.writeVarInt(this.points.length); - - var previousPoint = new Point(0, 0, 0, 0); - for (var i = 0; i < this.points.length; i++) - this.points[i]._writeTwkbPoint(twkb, precision, previousPoint); - } - - return twkb.buffer; -}; - -MultiPoint.prototype._getWkbSize = function () { - var coordinateSize = 16; - - if (this.hasZ) - coordinateSize += 8; - if (this.hasM) - coordinateSize += 8; - - coordinateSize += 5; - - return 1 + 4 + 4 + (this.points.length * coordinateSize); -}; - -MultiPoint.prototype.toGeoJSON = function (options) { - var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); - geoJSON.type = Types.geoJSON.MultiPoint; - geoJSON.coordinates = []; - - for (var i = 0; i < this.points.length; i++) - geoJSON.coordinates.push(this.points[i].toGeoJSON().coordinates); - - return geoJSON; -}; +module.exports = MultiPoint; + +var util = require('util'); + +var Types = require('./types'); +var Geometry = require('./geometry'); +var Point = require('./point'); +var BinaryWriter = require('./binarywriter'); + +function MultiPoint(points, srid) { + Geometry.call(this); + + this.points = points || []; + this.srid = srid; + + if (this.points.length > 0) { + this.hasZ = this.points[0].hasZ; + this.hasM = this.points[0].hasM; + } +} + +util.inherits(MultiPoint, Geometry); + +MultiPoint.Z = function (points, srid) { + var multiPoint = new MultiPoint(points, srid); + multiPoint.hasZ = true; + return multiPoint; +}; + +MultiPoint.M = function (points, srid) { + var multiPoint = new MultiPoint(points, srid); + multiPoint.hasM = true; + return multiPoint; +}; + +MultiPoint.ZM = function (points, srid) { + var multiPoint = new MultiPoint(points, srid); + multiPoint.hasZ = true; + multiPoint.hasM = true; + return multiPoint; +}; + +MultiPoint._parseWkt = function (value, options) { + var multiPoint = new MultiPoint(); + multiPoint.srid = options.srid; + multiPoint.hasZ = options.hasZ; + multiPoint.hasM = options.hasM; + + if (value.isMatch(['EMPTY'])) + return multiPoint; + + value.expectGroupStart(); + multiPoint.points.push.apply(multiPoint.points, value.matchCoordinates(options)); + value.expectGroupEnd(); + + return multiPoint; +}; + +MultiPoint._parseWkb = function (value, options) { + var multiPoint = new MultiPoint(); + multiPoint.srid = options.srid; + multiPoint.hasZ = options.hasZ; + multiPoint.hasM = options.hasM; + + var pointCount = value.readUInt32(); + + for (var i = 0; i < pointCount; i++) + multiPoint.points.push(Geometry.parse(value, options)); + + return multiPoint; +}; + +MultiPoint._parseTwkb = function (value, options) { + var multiPoint = new MultiPoint(); + multiPoint.hasZ = options.hasZ; + multiPoint.hasM = options.hasM; + + if (options.isEmpty) + return multiPoint; + + var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); + var pointCount = value.readVarInt(); + + for (var i = 0; i < pointCount; i++) + multiPoint.points.push(Point._readTwkbPoint(value, options, previousPoint)); + + return multiPoint; +}; + +MultiPoint._parseGeoJSON = function (value) { + var multiPoint = new MultiPoint(); + + if (value.coordinates.length > 0) + multiPoint.hasZ = value.coordinates[0].length > 2; + + for (var i = 0; i < value.coordinates.length; i++) + multiPoint.points.push(Point._parseGeoJSON({ coordinates: value.coordinates[i] })); + + return multiPoint; +}; + +MultiPoint.prototype.toWkt = function () { + if (this.points.length === 0) + return this._getWktType(Types.wkt.MultiPoint, true); + + var wkt = this._getWktType(Types.wkt.MultiPoint, false) + '('; + + for (var i = 0; i < this.points.length; i++) + wkt += this._getWktCoordinate(this.points[i]) + ','; + + wkt = wkt.slice(0, -1); + wkt += ')'; + + return wkt; +}; + +MultiPoint.prototype.toWkb = function () { + var wkb = new BinaryWriter(this._getWkbSize()); + + wkb.writeInt8(1); + + this._writeWkbType(wkb, Types.wkb.MultiPoint); + wkb.writeUInt32LE(this.points.length); + + for (var i = 0; i < this.points.length; i++) + wkb.writeBuffer(this.points[i].toWkb({ srid: this.srid })); + + return wkb.buffer; +}; + +MultiPoint.prototype.toTwkb = function () { + var twkb = new BinaryWriter(0, true); + + var precision = Geometry.getTwkbPrecision(5, 0, 0); + var isEmpty = this.points.length === 0; + + this._writeTwkbHeader(twkb, Types.wkb.MultiPoint, precision, isEmpty); + + if (this.points.length > 0) { + twkb.writeVarInt(this.points.length); + + var previousPoint = new Point(0, 0, 0, 0); + for (var i = 0; i < this.points.length; i++) + this.points[i]._writeTwkbPoint(twkb, precision, previousPoint); + } + + return twkb.buffer; +}; + +MultiPoint.prototype._getWkbSize = function () { + var coordinateSize = 16; + + if (this.hasZ) + coordinateSize += 8; + if (this.hasM) + coordinateSize += 8; + + coordinateSize += 5; + + return 1 + 4 + 4 + (this.points.length * coordinateSize); +}; + +MultiPoint.prototype.toGeoJSON = function (options) { + var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); + geoJSON.type = Types.geoJSON.MultiPoint; + geoJSON.coordinates = []; + + for (var i = 0; i < this.points.length; i++) + geoJSON.coordinates.push(this.points[i].toGeoJSON().coordinates); + + return geoJSON; +}; diff --git a/backend/node_modules/wkx/lib/multipolygon.js b/backend/node_modules/wkx/lib/multipolygon.js index 099e8c4..5c03ed2 100644 --- a/backend/node_modules/wkx/lib/multipolygon.js +++ b/backend/node_modules/wkx/lib/multipolygon.js @@ -1,226 +1,226 @@ -module.exports = MultiPolygon; - -var util = require('util'); - -var Types = require('./types'); -var Geometry = require('./geometry'); -var Point = require('./point'); -var Polygon = require('./polygon'); -var BinaryWriter = require('./binarywriter'); - -function MultiPolygon(polygons, srid) { - Geometry.call(this); - - this.polygons = polygons || []; - this.srid = srid; - - if (this.polygons.length > 0) { - this.hasZ = this.polygons[0].hasZ; - this.hasM = this.polygons[0].hasM; - } -} - -util.inherits(MultiPolygon, Geometry); - -MultiPolygon.Z = function (polygons, srid) { - var multiPolygon = new MultiPolygon(polygons, srid); - multiPolygon.hasZ = true; - return multiPolygon; -}; - -MultiPolygon.M = function (polygons, srid) { - var multiPolygon = new MultiPolygon(polygons, srid); - multiPolygon.hasM = true; - return multiPolygon; -}; - -MultiPolygon.ZM = function (polygons, srid) { - var multiPolygon = new MultiPolygon(polygons, srid); - multiPolygon.hasZ = true; - multiPolygon.hasM = true; - return multiPolygon; -}; - -MultiPolygon._parseWkt = function (value, options) { - var multiPolygon = new MultiPolygon(); - multiPolygon.srid = options.srid; - multiPolygon.hasZ = options.hasZ; - multiPolygon.hasM = options.hasM; - - if (value.isMatch(['EMPTY'])) - return multiPolygon; - - value.expectGroupStart(); - - do { - value.expectGroupStart(); - - var exteriorRing = []; - var interiorRings = []; - - value.expectGroupStart(); - exteriorRing.push.apply(exteriorRing, value.matchCoordinates(options)); - value.expectGroupEnd(); - - while (value.isMatch([','])) { - value.expectGroupStart(); - interiorRings.push(value.matchCoordinates(options)); - value.expectGroupEnd(); - } - - multiPolygon.polygons.push(new Polygon(exteriorRing, interiorRings)); - - value.expectGroupEnd(); - - } while (value.isMatch([','])); - - value.expectGroupEnd(); - - return multiPolygon; -}; - -MultiPolygon._parseWkb = function (value, options) { - var multiPolygon = new MultiPolygon(); - multiPolygon.srid = options.srid; - multiPolygon.hasZ = options.hasZ; - multiPolygon.hasM = options.hasM; - - var polygonCount = value.readUInt32(); - - for (var i = 0; i < polygonCount; i++) - multiPolygon.polygons.push(Geometry.parse(value, options)); - - return multiPolygon; -}; - -MultiPolygon._parseTwkb = function (value, options) { - var multiPolygon = new MultiPolygon(); - multiPolygon.hasZ = options.hasZ; - multiPolygon.hasM = options.hasM; - - if (options.isEmpty) - return multiPolygon; - - var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); - var polygonCount = value.readVarInt(); - - for (var i = 0; i < polygonCount; i++) { - var polygon = new Polygon(); - polygon.hasZ = options.hasZ; - polygon.hasM = options.hasM; - - var ringCount = value.readVarInt(); - var exteriorRingCount = value.readVarInt(); - - for (var j = 0; j < exteriorRingCount; j++) - polygon.exteriorRing.push(Point._readTwkbPoint(value, options, previousPoint)); - - for (j = 1; j < ringCount; j++) { - var interiorRing = []; - - var interiorRingCount = value.readVarInt(); - - for (var k = 0; k < interiorRingCount; k++) - interiorRing.push(Point._readTwkbPoint(value, options, previousPoint)); - - polygon.interiorRings.push(interiorRing); - } - - multiPolygon.polygons.push(polygon); - } - - return multiPolygon; -}; - -MultiPolygon._parseGeoJSON = function (value) { - var multiPolygon = new MultiPolygon(); - - if (value.coordinates.length > 0 && value.coordinates[0].length > 0 && value.coordinates[0][0].length > 0) - multiPolygon.hasZ = value.coordinates[0][0][0].length > 2; - - for (var i = 0; i < value.coordinates.length; i++) - multiPolygon.polygons.push(Polygon._parseGeoJSON({ coordinates: value.coordinates[i] })); - - return multiPolygon; -}; - -MultiPolygon.prototype.toWkt = function () { - if (this.polygons.length === 0) - return this._getWktType(Types.wkt.MultiPolygon, true); - - var wkt = this._getWktType(Types.wkt.MultiPolygon, false) + '('; - - for (var i = 0; i < this.polygons.length; i++) - wkt += this.polygons[i]._toInnerWkt() + ','; - - wkt = wkt.slice(0, -1); - wkt += ')'; - - return wkt; -}; - -MultiPolygon.prototype.toWkb = function () { - var wkb = new BinaryWriter(this._getWkbSize()); - - wkb.writeInt8(1); - - this._writeWkbType(wkb, Types.wkb.MultiPolygon); - wkb.writeUInt32LE(this.polygons.length); - - for (var i = 0; i < this.polygons.length; i++) - wkb.writeBuffer(this.polygons[i].toWkb({ srid: this.srid })); - - return wkb.buffer; -}; - -MultiPolygon.prototype.toTwkb = function () { - var twkb = new BinaryWriter(0, true); - - var precision = Geometry.getTwkbPrecision(5, 0, 0); - var isEmpty = this.polygons.length === 0; - - this._writeTwkbHeader(twkb, Types.wkb.MultiPolygon, precision, isEmpty); - - if (this.polygons.length > 0) { - twkb.writeVarInt(this.polygons.length); - - var previousPoint = new Point(0, 0, 0, 0); - for (var i = 0; i < this.polygons.length; i++) { - twkb.writeVarInt(1 + this.polygons[i].interiorRings.length); - - twkb.writeVarInt(this.polygons[i].exteriorRing.length); - - for (var j = 0; j < this.polygons[i].exteriorRing.length; j++) - this.polygons[i].exteriorRing[j]._writeTwkbPoint(twkb, precision, previousPoint); - - for (j = 0; j < this.polygons[i].interiorRings.length; j++) { - twkb.writeVarInt(this.polygons[i].interiorRings[j].length); - - for (var k = 0; k < this.polygons[i].interiorRings[j].length; k++) - this.polygons[i].interiorRings[j][k]._writeTwkbPoint(twkb, precision, previousPoint); - } - } - } - - return twkb.buffer; -}; - -MultiPolygon.prototype._getWkbSize = function () { - var size = 1 + 4 + 4; - - for (var i = 0; i < this.polygons.length; i++) - size += this.polygons[i]._getWkbSize(); - - return size; -}; - -MultiPolygon.prototype.toGeoJSON = function (options) { - var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); - geoJSON.type = Types.geoJSON.MultiPolygon; - geoJSON.coordinates = []; - - for (var i = 0; i < this.polygons.length; i++) - geoJSON.coordinates.push(this.polygons[i].toGeoJSON().coordinates); - - return geoJSON; -}; +module.exports = MultiPolygon; + +var util = require('util'); + +var Types = require('./types'); +var Geometry = require('./geometry'); +var Point = require('./point'); +var Polygon = require('./polygon'); +var BinaryWriter = require('./binarywriter'); + +function MultiPolygon(polygons, srid) { + Geometry.call(this); + + this.polygons = polygons || []; + this.srid = srid; + + if (this.polygons.length > 0) { + this.hasZ = this.polygons[0].hasZ; + this.hasM = this.polygons[0].hasM; + } +} + +util.inherits(MultiPolygon, Geometry); + +MultiPolygon.Z = function (polygons, srid) { + var multiPolygon = new MultiPolygon(polygons, srid); + multiPolygon.hasZ = true; + return multiPolygon; +}; + +MultiPolygon.M = function (polygons, srid) { + var multiPolygon = new MultiPolygon(polygons, srid); + multiPolygon.hasM = true; + return multiPolygon; +}; + +MultiPolygon.ZM = function (polygons, srid) { + var multiPolygon = new MultiPolygon(polygons, srid); + multiPolygon.hasZ = true; + multiPolygon.hasM = true; + return multiPolygon; +}; + +MultiPolygon._parseWkt = function (value, options) { + var multiPolygon = new MultiPolygon(); + multiPolygon.srid = options.srid; + multiPolygon.hasZ = options.hasZ; + multiPolygon.hasM = options.hasM; + + if (value.isMatch(['EMPTY'])) + return multiPolygon; + + value.expectGroupStart(); + + do { + value.expectGroupStart(); + + var exteriorRing = []; + var interiorRings = []; + + value.expectGroupStart(); + exteriorRing.push.apply(exteriorRing, value.matchCoordinates(options)); + value.expectGroupEnd(); + + while (value.isMatch([','])) { + value.expectGroupStart(); + interiorRings.push(value.matchCoordinates(options)); + value.expectGroupEnd(); + } + + multiPolygon.polygons.push(new Polygon(exteriorRing, interiorRings)); + + value.expectGroupEnd(); + + } while (value.isMatch([','])); + + value.expectGroupEnd(); + + return multiPolygon; +}; + +MultiPolygon._parseWkb = function (value, options) { + var multiPolygon = new MultiPolygon(); + multiPolygon.srid = options.srid; + multiPolygon.hasZ = options.hasZ; + multiPolygon.hasM = options.hasM; + + var polygonCount = value.readUInt32(); + + for (var i = 0; i < polygonCount; i++) + multiPolygon.polygons.push(Geometry.parse(value, options)); + + return multiPolygon; +}; + +MultiPolygon._parseTwkb = function (value, options) { + var multiPolygon = new MultiPolygon(); + multiPolygon.hasZ = options.hasZ; + multiPolygon.hasM = options.hasM; + + if (options.isEmpty) + return multiPolygon; + + var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); + var polygonCount = value.readVarInt(); + + for (var i = 0; i < polygonCount; i++) { + var polygon = new Polygon(); + polygon.hasZ = options.hasZ; + polygon.hasM = options.hasM; + + var ringCount = value.readVarInt(); + var exteriorRingCount = value.readVarInt(); + + for (var j = 0; j < exteriorRingCount; j++) + polygon.exteriorRing.push(Point._readTwkbPoint(value, options, previousPoint)); + + for (j = 1; j < ringCount; j++) { + var interiorRing = []; + + var interiorRingCount = value.readVarInt(); + + for (var k = 0; k < interiorRingCount; k++) + interiorRing.push(Point._readTwkbPoint(value, options, previousPoint)); + + polygon.interiorRings.push(interiorRing); + } + + multiPolygon.polygons.push(polygon); + } + + return multiPolygon; +}; + +MultiPolygon._parseGeoJSON = function (value) { + var multiPolygon = new MultiPolygon(); + + if (value.coordinates.length > 0 && value.coordinates[0].length > 0 && value.coordinates[0][0].length > 0) + multiPolygon.hasZ = value.coordinates[0][0][0].length > 2; + + for (var i = 0; i < value.coordinates.length; i++) + multiPolygon.polygons.push(Polygon._parseGeoJSON({ coordinates: value.coordinates[i] })); + + return multiPolygon; +}; + +MultiPolygon.prototype.toWkt = function () { + if (this.polygons.length === 0) + return this._getWktType(Types.wkt.MultiPolygon, true); + + var wkt = this._getWktType(Types.wkt.MultiPolygon, false) + '('; + + for (var i = 0; i < this.polygons.length; i++) + wkt += this.polygons[i]._toInnerWkt() + ','; + + wkt = wkt.slice(0, -1); + wkt += ')'; + + return wkt; +}; + +MultiPolygon.prototype.toWkb = function () { + var wkb = new BinaryWriter(this._getWkbSize()); + + wkb.writeInt8(1); + + this._writeWkbType(wkb, Types.wkb.MultiPolygon); + wkb.writeUInt32LE(this.polygons.length); + + for (var i = 0; i < this.polygons.length; i++) + wkb.writeBuffer(this.polygons[i].toWkb({ srid: this.srid })); + + return wkb.buffer; +}; + +MultiPolygon.prototype.toTwkb = function () { + var twkb = new BinaryWriter(0, true); + + var precision = Geometry.getTwkbPrecision(5, 0, 0); + var isEmpty = this.polygons.length === 0; + + this._writeTwkbHeader(twkb, Types.wkb.MultiPolygon, precision, isEmpty); + + if (this.polygons.length > 0) { + twkb.writeVarInt(this.polygons.length); + + var previousPoint = new Point(0, 0, 0, 0); + for (var i = 0; i < this.polygons.length; i++) { + twkb.writeVarInt(1 + this.polygons[i].interiorRings.length); + + twkb.writeVarInt(this.polygons[i].exteriorRing.length); + + for (var j = 0; j < this.polygons[i].exteriorRing.length; j++) + this.polygons[i].exteriorRing[j]._writeTwkbPoint(twkb, precision, previousPoint); + + for (j = 0; j < this.polygons[i].interiorRings.length; j++) { + twkb.writeVarInt(this.polygons[i].interiorRings[j].length); + + for (var k = 0; k < this.polygons[i].interiorRings[j].length; k++) + this.polygons[i].interiorRings[j][k]._writeTwkbPoint(twkb, precision, previousPoint); + } + } + } + + return twkb.buffer; +}; + +MultiPolygon.prototype._getWkbSize = function () { + var size = 1 + 4 + 4; + + for (var i = 0; i < this.polygons.length; i++) + size += this.polygons[i]._getWkbSize(); + + return size; +}; + +MultiPolygon.prototype.toGeoJSON = function (options) { + var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); + geoJSON.type = Types.geoJSON.MultiPolygon; + geoJSON.coordinates = []; + + for (var i = 0; i < this.polygons.length; i++) + geoJSON.coordinates.push(this.polygons[i].toGeoJSON().coordinates); + + return geoJSON; +}; diff --git a/backend/node_modules/wkx/lib/point.js b/backend/node_modules/wkx/lib/point.js index 20bb1f8..a425a8e 100644 --- a/backend/node_modules/wkx/lib/point.js +++ b/backend/node_modules/wkx/lib/point.js @@ -1,217 +1,217 @@ -module.exports = Point; - -var util = require('util'); - -var Geometry = require('./geometry'); -var Types = require('./types'); -var BinaryWriter = require('./binarywriter'); -var ZigZag = require('./zigzag.js'); - -function Point(x, y, z, m, srid) { - Geometry.call(this); - - this.x = x; - this.y = y; - this.z = z; - this.m = m; - this.srid = srid; - - this.hasZ = typeof this.z !== 'undefined'; - this.hasM = typeof this.m !== 'undefined'; -} - -util.inherits(Point, Geometry); - -Point.Z = function (x, y, z, srid) { - var point = new Point(x, y, z, undefined, srid); - point.hasZ = true; - return point; -}; - -Point.M = function (x, y, m, srid) { - var point = new Point(x, y, undefined, m, srid); - point.hasM = true; - return point; -}; - -Point.ZM = function (x, y, z, m, srid) { - var point = new Point(x, y, z, m, srid); - point.hasZ = true; - point.hasM = true; - return point; -}; - -Point._parseWkt = function (value, options) { - var point = new Point(); - point.srid = options.srid; - point.hasZ = options.hasZ; - point.hasM = options.hasM; - - if (value.isMatch(['EMPTY'])) - return point; - - value.expectGroupStart(); - - var coordinate = value.matchCoordinate(options); - - point.x = coordinate.x; - point.y = coordinate.y; - point.z = coordinate.z; - point.m = coordinate.m; - - value.expectGroupEnd(); - - return point; -}; - -Point._parseWkb = function (value, options) { - var point = Point._readWkbPoint(value, options); - point.srid = options.srid; - return point; -}; - -Point._readWkbPoint = function (value, options) { - return new Point(value.readDouble(), value.readDouble(), - options.hasZ ? value.readDouble() : undefined, - options.hasM ? value.readDouble() : undefined); -}; - -Point._parseTwkb = function (value, options) { - var point = new Point(); - point.hasZ = options.hasZ; - point.hasM = options.hasM; - - if (options.isEmpty) - return point; - - point.x = ZigZag.decode(value.readVarInt()) / options.precisionFactor; - point.y = ZigZag.decode(value.readVarInt()) / options.precisionFactor; - point.z = options.hasZ ? ZigZag.decode(value.readVarInt()) / options.zPrecisionFactor : undefined; - point.m = options.hasM ? ZigZag.decode(value.readVarInt()) / options.mPrecisionFactor : undefined; - - return point; -}; - -Point._readTwkbPoint = function (value, options, previousPoint) { - previousPoint.x += ZigZag.decode(value.readVarInt()) / options.precisionFactor; - previousPoint.y += ZigZag.decode(value.readVarInt()) / options.precisionFactor; - - if (options.hasZ) - previousPoint.z += ZigZag.decode(value.readVarInt()) / options.zPrecisionFactor; - if (options.hasM) - previousPoint.m += ZigZag.decode(value.readVarInt()) / options.mPrecisionFactor; - - return new Point(previousPoint.x, previousPoint.y, previousPoint.z, previousPoint.m); -}; - -Point._parseGeoJSON = function (value) { - return Point._readGeoJSONPoint(value.coordinates); -}; - -Point._readGeoJSONPoint = function (coordinates) { - if (coordinates.length === 0) - return new Point(); - - if (coordinates.length > 2) - return new Point(coordinates[0], coordinates[1], coordinates[2]); - - return new Point(coordinates[0], coordinates[1]); -}; - -Point.prototype.toWkt = function () { - if (typeof this.x === 'undefined' && typeof this.y === 'undefined' && - typeof this.z === 'undefined' && typeof this.m === 'undefined') - return this._getWktType(Types.wkt.Point, true); - - return this._getWktType(Types.wkt.Point, false) + '(' + this._getWktCoordinate(this) + ')'; -}; - -Point.prototype.toWkb = function (parentOptions) { - var wkb = new BinaryWriter(this._getWkbSize()); - - wkb.writeInt8(1); - this._writeWkbType(wkb, Types.wkb.Point, parentOptions); - - if (typeof this.x === 'undefined' && typeof this.y === 'undefined') { - wkb.writeDoubleLE(NaN); - wkb.writeDoubleLE(NaN); - - if (this.hasZ) - wkb.writeDoubleLE(NaN); - if (this.hasM) - wkb.writeDoubleLE(NaN); - } - else { - this._writeWkbPoint(wkb); - } - - return wkb.buffer; -}; - -Point.prototype._writeWkbPoint = function (wkb) { - wkb.writeDoubleLE(this.x); - wkb.writeDoubleLE(this.y); - - if (this.hasZ) - wkb.writeDoubleLE(this.z); - if (this.hasM) - wkb.writeDoubleLE(this.m); -}; - -Point.prototype.toTwkb = function () { - var twkb = new BinaryWriter(0, true); - - var precision = Geometry.getTwkbPrecision(5, 0, 0); - var isEmpty = typeof this.x === 'undefined' && typeof this.y === 'undefined'; - - this._writeTwkbHeader(twkb, Types.wkb.Point, precision, isEmpty); - - if (!isEmpty) - this._writeTwkbPoint(twkb, precision, new Point(0, 0, 0, 0)); - - return twkb.buffer; -}; - -Point.prototype._writeTwkbPoint = function (twkb, precision, previousPoint) { - var x = this.x * precision.xyFactor; - var y = this.y * precision.xyFactor; - var z = this.z * precision.zFactor; - var m = this.m * precision.mFactor; - - twkb.writeVarInt(ZigZag.encode(x - previousPoint.x)); - twkb.writeVarInt(ZigZag.encode(y - previousPoint.y)); - if (this.hasZ) - twkb.writeVarInt(ZigZag.encode(z - previousPoint.z)); - if (this.hasM) - twkb.writeVarInt(ZigZag.encode(m - previousPoint.m)); - - previousPoint.x = x; - previousPoint.y = y; - previousPoint.z = z; - previousPoint.m = m; -}; - -Point.prototype._getWkbSize = function () { - var size = 1 + 4 + 8 + 8; - - if (this.hasZ) - size += 8; - if (this.hasM) - size += 8; - - return size; -}; - -Point.prototype.toGeoJSON = function (options) { - var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); - geoJSON.type = Types.geoJSON.Point; - - if (typeof this.x === 'undefined' && typeof this.y === 'undefined') - geoJSON.coordinates = []; - else if (typeof this.z !== 'undefined') - geoJSON.coordinates = [this.x, this.y, this.z]; - else - geoJSON.coordinates = [this.x, this.y]; - - return geoJSON; -}; +module.exports = Point; + +var util = require('util'); + +var Geometry = require('./geometry'); +var Types = require('./types'); +var BinaryWriter = require('./binarywriter'); +var ZigZag = require('./zigzag.js'); + +function Point(x, y, z, m, srid) { + Geometry.call(this); + + this.x = x; + this.y = y; + this.z = z; + this.m = m; + this.srid = srid; + + this.hasZ = typeof this.z !== 'undefined'; + this.hasM = typeof this.m !== 'undefined'; +} + +util.inherits(Point, Geometry); + +Point.Z = function (x, y, z, srid) { + var point = new Point(x, y, z, undefined, srid); + point.hasZ = true; + return point; +}; + +Point.M = function (x, y, m, srid) { + var point = new Point(x, y, undefined, m, srid); + point.hasM = true; + return point; +}; + +Point.ZM = function (x, y, z, m, srid) { + var point = new Point(x, y, z, m, srid); + point.hasZ = true; + point.hasM = true; + return point; +}; + +Point._parseWkt = function (value, options) { + var point = new Point(); + point.srid = options.srid; + point.hasZ = options.hasZ; + point.hasM = options.hasM; + + if (value.isMatch(['EMPTY'])) + return point; + + value.expectGroupStart(); + + var coordinate = value.matchCoordinate(options); + + point.x = coordinate.x; + point.y = coordinate.y; + point.z = coordinate.z; + point.m = coordinate.m; + + value.expectGroupEnd(); + + return point; +}; + +Point._parseWkb = function (value, options) { + var point = Point._readWkbPoint(value, options); + point.srid = options.srid; + return point; +}; + +Point._readWkbPoint = function (value, options) { + return new Point(value.readDouble(), value.readDouble(), + options.hasZ ? value.readDouble() : undefined, + options.hasM ? value.readDouble() : undefined); +}; + +Point._parseTwkb = function (value, options) { + var point = new Point(); + point.hasZ = options.hasZ; + point.hasM = options.hasM; + + if (options.isEmpty) + return point; + + point.x = ZigZag.decode(value.readVarInt()) / options.precisionFactor; + point.y = ZigZag.decode(value.readVarInt()) / options.precisionFactor; + point.z = options.hasZ ? ZigZag.decode(value.readVarInt()) / options.zPrecisionFactor : undefined; + point.m = options.hasM ? ZigZag.decode(value.readVarInt()) / options.mPrecisionFactor : undefined; + + return point; +}; + +Point._readTwkbPoint = function (value, options, previousPoint) { + previousPoint.x += ZigZag.decode(value.readVarInt()) / options.precisionFactor; + previousPoint.y += ZigZag.decode(value.readVarInt()) / options.precisionFactor; + + if (options.hasZ) + previousPoint.z += ZigZag.decode(value.readVarInt()) / options.zPrecisionFactor; + if (options.hasM) + previousPoint.m += ZigZag.decode(value.readVarInt()) / options.mPrecisionFactor; + + return new Point(previousPoint.x, previousPoint.y, previousPoint.z, previousPoint.m); +}; + +Point._parseGeoJSON = function (value) { + return Point._readGeoJSONPoint(value.coordinates); +}; + +Point._readGeoJSONPoint = function (coordinates) { + if (coordinates.length === 0) + return new Point(); + + if (coordinates.length > 2) + return new Point(coordinates[0], coordinates[1], coordinates[2]); + + return new Point(coordinates[0], coordinates[1]); +}; + +Point.prototype.toWkt = function () { + if (typeof this.x === 'undefined' && typeof this.y === 'undefined' && + typeof this.z === 'undefined' && typeof this.m === 'undefined') + return this._getWktType(Types.wkt.Point, true); + + return this._getWktType(Types.wkt.Point, false) + '(' + this._getWktCoordinate(this) + ')'; +}; + +Point.prototype.toWkb = function (parentOptions) { + var wkb = new BinaryWriter(this._getWkbSize()); + + wkb.writeInt8(1); + this._writeWkbType(wkb, Types.wkb.Point, parentOptions); + + if (typeof this.x === 'undefined' && typeof this.y === 'undefined') { + wkb.writeDoubleLE(NaN); + wkb.writeDoubleLE(NaN); + + if (this.hasZ) + wkb.writeDoubleLE(NaN); + if (this.hasM) + wkb.writeDoubleLE(NaN); + } + else { + this._writeWkbPoint(wkb); + } + + return wkb.buffer; +}; + +Point.prototype._writeWkbPoint = function (wkb) { + wkb.writeDoubleLE(this.x); + wkb.writeDoubleLE(this.y); + + if (this.hasZ) + wkb.writeDoubleLE(this.z); + if (this.hasM) + wkb.writeDoubleLE(this.m); +}; + +Point.prototype.toTwkb = function () { + var twkb = new BinaryWriter(0, true); + + var precision = Geometry.getTwkbPrecision(5, 0, 0); + var isEmpty = typeof this.x === 'undefined' && typeof this.y === 'undefined'; + + this._writeTwkbHeader(twkb, Types.wkb.Point, precision, isEmpty); + + if (!isEmpty) + this._writeTwkbPoint(twkb, precision, new Point(0, 0, 0, 0)); + + return twkb.buffer; +}; + +Point.prototype._writeTwkbPoint = function (twkb, precision, previousPoint) { + var x = this.x * precision.xyFactor; + var y = this.y * precision.xyFactor; + var z = this.z * precision.zFactor; + var m = this.m * precision.mFactor; + + twkb.writeVarInt(ZigZag.encode(x - previousPoint.x)); + twkb.writeVarInt(ZigZag.encode(y - previousPoint.y)); + if (this.hasZ) + twkb.writeVarInt(ZigZag.encode(z - previousPoint.z)); + if (this.hasM) + twkb.writeVarInt(ZigZag.encode(m - previousPoint.m)); + + previousPoint.x = x; + previousPoint.y = y; + previousPoint.z = z; + previousPoint.m = m; +}; + +Point.prototype._getWkbSize = function () { + var size = 1 + 4 + 8 + 8; + + if (this.hasZ) + size += 8; + if (this.hasM) + size += 8; + + return size; +}; + +Point.prototype.toGeoJSON = function (options) { + var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); + geoJSON.type = Types.geoJSON.Point; + + if (typeof this.x === 'undefined' && typeof this.y === 'undefined') + geoJSON.coordinates = []; + else if (typeof this.z !== 'undefined') + geoJSON.coordinates = [this.x, this.y, this.z]; + else + geoJSON.coordinates = [this.x, this.y]; + + return geoJSON; +}; diff --git a/backend/node_modules/wkx/lib/polygon.js b/backend/node_modules/wkx/lib/polygon.js index f54b878..1fccafb 100644 --- a/backend/node_modules/wkx/lib/polygon.js +++ b/backend/node_modules/wkx/lib/polygon.js @@ -1,288 +1,288 @@ -module.exports = Polygon; - -var util = require('util'); - -var Geometry = require('./geometry'); -var Types = require('./types'); -var Point = require('./point'); -var BinaryWriter = require('./binarywriter'); - -function Polygon(exteriorRing, interiorRings, srid) { - Geometry.call(this); - - this.exteriorRing = exteriorRing || []; - this.interiorRings = interiorRings || []; - this.srid = srid; - - if (this.exteriorRing.length > 0) { - this.hasZ = this.exteriorRing[0].hasZ; - this.hasM = this.exteriorRing[0].hasM; - } -} - -util.inherits(Polygon, Geometry); - -Polygon.Z = function (exteriorRing, interiorRings, srid) { - var polygon = new Polygon(exteriorRing, interiorRings, srid); - polygon.hasZ = true; - return polygon; -}; - -Polygon.M = function (exteriorRing, interiorRings, srid) { - var polygon = new Polygon(exteriorRing, interiorRings, srid); - polygon.hasM = true; - return polygon; -}; - -Polygon.ZM = function (exteriorRing, interiorRings, srid) { - var polygon = new Polygon(exteriorRing, interiorRings, srid); - polygon.hasZ = true; - polygon.hasM = true; - return polygon; -}; - -Polygon._parseWkt = function (value, options) { - var polygon = new Polygon(); - polygon.srid = options.srid; - polygon.hasZ = options.hasZ; - polygon.hasM = options.hasM; - - if (value.isMatch(['EMPTY'])) - return polygon; - - value.expectGroupStart(); - - value.expectGroupStart(); - polygon.exteriorRing.push.apply(polygon.exteriorRing, value.matchCoordinates(options)); - value.expectGroupEnd(); - - while (value.isMatch([','])) { - value.expectGroupStart(); - polygon.interiorRings.push(value.matchCoordinates(options)); - value.expectGroupEnd(); - } - - value.expectGroupEnd(); - - return polygon; -}; - -Polygon._parseWkb = function (value, options) { - var polygon = new Polygon(); - polygon.srid = options.srid; - polygon.hasZ = options.hasZ; - polygon.hasM = options.hasM; - - var ringCount = value.readUInt32(); - - if (ringCount > 0) { - var exteriorRingCount = value.readUInt32(); - - for (var i = 0; i < exteriorRingCount; i++) - polygon.exteriorRing.push(Point._readWkbPoint(value, options)); - - for (i = 1; i < ringCount; i++) { - var interiorRing = []; - - var interiorRingCount = value.readUInt32(); - - for (var j = 0; j < interiorRingCount; j++) - interiorRing.push(Point._readWkbPoint(value, options)); - - polygon.interiorRings.push(interiorRing); - } - } - - return polygon; -}; - -Polygon._parseTwkb = function (value, options) { - var polygon = new Polygon(); - polygon.hasZ = options.hasZ; - polygon.hasM = options.hasM; - - if (options.isEmpty) - return polygon; - - var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); - var ringCount = value.readVarInt(); - var exteriorRingCount = value.readVarInt(); - - for (var i = 0; i < exteriorRingCount; i++) - polygon.exteriorRing.push(Point._readTwkbPoint(value, options, previousPoint)); - - for (i = 1; i < ringCount; i++) { - var interiorRing = []; - - var interiorRingCount = value.readVarInt(); - - for (var j = 0; j < interiorRingCount; j++) - interiorRing.push(Point._readTwkbPoint(value, options, previousPoint)); - - polygon.interiorRings.push(interiorRing); - } - - return polygon; -}; - -Polygon._parseGeoJSON = function (value) { - var polygon = new Polygon(); - - if (value.coordinates.length > 0 && value.coordinates[0].length > 0) - polygon.hasZ = value.coordinates[0][0].length > 2; - - for (var i = 0; i < value.coordinates.length; i++) { - if (i > 0) - polygon.interiorRings.push([]); - - for (var j = 0; j < value.coordinates[i].length; j++) { - if (i === 0) - polygon.exteriorRing.push(Point._readGeoJSONPoint(value.coordinates[i][j])); - else - polygon.interiorRings[i - 1].push(Point._readGeoJSONPoint(value.coordinates[i][j])); - } - } - - return polygon; -}; - -Polygon.prototype.toWkt = function () { - if (this.exteriorRing.length === 0) - return this._getWktType(Types.wkt.Polygon, true); - - return this._getWktType(Types.wkt.Polygon, false) + this._toInnerWkt(); -}; - -Polygon.prototype._toInnerWkt = function () { - var innerWkt = '(('; - - for (var i = 0; i < this.exteriorRing.length; i++) - innerWkt += this._getWktCoordinate(this.exteriorRing[i]) + ','; - - innerWkt = innerWkt.slice(0, -1); - innerWkt += ')'; - - for (i = 0; i < this.interiorRings.length; i++) { - innerWkt += ',('; - - for (var j = 0; j < this.interiorRings[i].length; j++) { - innerWkt += this._getWktCoordinate(this.interiorRings[i][j]) + ','; - } - - innerWkt = innerWkt.slice(0, -1); - innerWkt += ')'; - } - - innerWkt += ')'; - - return innerWkt; -}; - -Polygon.prototype.toWkb = function (parentOptions) { - var wkb = new BinaryWriter(this._getWkbSize()); - - wkb.writeInt8(1); - - this._writeWkbType(wkb, Types.wkb.Polygon, parentOptions); - - if (this.exteriorRing.length > 0) { - wkb.writeUInt32LE(1 + this.interiorRings.length); - wkb.writeUInt32LE(this.exteriorRing.length); - } - else { - wkb.writeUInt32LE(0); - } - - for (var i = 0; i < this.exteriorRing.length; i++) - this.exteriorRing[i]._writeWkbPoint(wkb); - - for (i = 0; i < this.interiorRings.length; i++) { - wkb.writeUInt32LE(this.interiorRings[i].length); - - for (var j = 0; j < this.interiorRings[i].length; j++) - this.interiorRings[i][j]._writeWkbPoint(wkb); - } - - return wkb.buffer; -}; - -Polygon.prototype.toTwkb = function () { - var twkb = new BinaryWriter(0, true); - - var precision = Geometry.getTwkbPrecision(5, 0, 0); - var isEmpty = this.exteriorRing.length === 0; - - this._writeTwkbHeader(twkb, Types.wkb.Polygon, precision, isEmpty); - - if (this.exteriorRing.length > 0) { - twkb.writeVarInt(1 + this.interiorRings.length); - - twkb.writeVarInt(this.exteriorRing.length); - - var previousPoint = new Point(0, 0, 0, 0); - for (var i = 0; i < this.exteriorRing.length; i++) - this.exteriorRing[i]._writeTwkbPoint(twkb, precision, previousPoint); - - for (i = 0; i < this.interiorRings.length; i++) { - twkb.writeVarInt(this.interiorRings[i].length); - - for (var j = 0; j < this.interiorRings[i].length; j++) - this.interiorRings[i][j]._writeTwkbPoint(twkb, precision, previousPoint); - } - } - - return twkb.buffer; -}; - -Polygon.prototype._getWkbSize = function () { - var coordinateSize = 16; - - if (this.hasZ) - coordinateSize += 8; - if (this.hasM) - coordinateSize += 8; - - var size = 1 + 4 + 4; - - if (this.exteriorRing.length > 0) - size += 4 + (this.exteriorRing.length * coordinateSize); - - for (var i = 0; i < this.interiorRings.length; i++) - size += 4 + (this.interiorRings[i].length * coordinateSize); - - return size; -}; - -Polygon.prototype.toGeoJSON = function (options) { - var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); - geoJSON.type = Types.geoJSON.Polygon; - geoJSON.coordinates = []; - - if (this.exteriorRing.length > 0) { - var exteriorRing = []; - - for (var i = 0; i < this.exteriorRing.length; i++) { - if (this.hasZ) - exteriorRing.push([this.exteriorRing[i].x, this.exteriorRing[i].y, this.exteriorRing[i].z]); - else - exteriorRing.push([this.exteriorRing[i].x, this.exteriorRing[i].y]); - } - - geoJSON.coordinates.push(exteriorRing); - } - - for (var j = 0; j < this.interiorRings.length; j++) { - var interiorRing = []; - - for (var k = 0; k < this.interiorRings[j].length; k++) { - if (this.hasZ) - interiorRing.push([this.interiorRings[j][k].x, this.interiorRings[j][k].y, this.interiorRings[j][k].z]); - else - interiorRing.push([this.interiorRings[j][k].x, this.interiorRings[j][k].y]); - } - - geoJSON.coordinates.push(interiorRing); - } - - return geoJSON; -}; +module.exports = Polygon; + +var util = require('util'); + +var Geometry = require('./geometry'); +var Types = require('./types'); +var Point = require('./point'); +var BinaryWriter = require('./binarywriter'); + +function Polygon(exteriorRing, interiorRings, srid) { + Geometry.call(this); + + this.exteriorRing = exteriorRing || []; + this.interiorRings = interiorRings || []; + this.srid = srid; + + if (this.exteriorRing.length > 0) { + this.hasZ = this.exteriorRing[0].hasZ; + this.hasM = this.exteriorRing[0].hasM; + } +} + +util.inherits(Polygon, Geometry); + +Polygon.Z = function (exteriorRing, interiorRings, srid) { + var polygon = new Polygon(exteriorRing, interiorRings, srid); + polygon.hasZ = true; + return polygon; +}; + +Polygon.M = function (exteriorRing, interiorRings, srid) { + var polygon = new Polygon(exteriorRing, interiorRings, srid); + polygon.hasM = true; + return polygon; +}; + +Polygon.ZM = function (exteriorRing, interiorRings, srid) { + var polygon = new Polygon(exteriorRing, interiorRings, srid); + polygon.hasZ = true; + polygon.hasM = true; + return polygon; +}; + +Polygon._parseWkt = function (value, options) { + var polygon = new Polygon(); + polygon.srid = options.srid; + polygon.hasZ = options.hasZ; + polygon.hasM = options.hasM; + + if (value.isMatch(['EMPTY'])) + return polygon; + + value.expectGroupStart(); + + value.expectGroupStart(); + polygon.exteriorRing.push.apply(polygon.exteriorRing, value.matchCoordinates(options)); + value.expectGroupEnd(); + + while (value.isMatch([','])) { + value.expectGroupStart(); + polygon.interiorRings.push(value.matchCoordinates(options)); + value.expectGroupEnd(); + } + + value.expectGroupEnd(); + + return polygon; +}; + +Polygon._parseWkb = function (value, options) { + var polygon = new Polygon(); + polygon.srid = options.srid; + polygon.hasZ = options.hasZ; + polygon.hasM = options.hasM; + + var ringCount = value.readUInt32(); + + if (ringCount > 0) { + var exteriorRingCount = value.readUInt32(); + + for (var i = 0; i < exteriorRingCount; i++) + polygon.exteriorRing.push(Point._readWkbPoint(value, options)); + + for (i = 1; i < ringCount; i++) { + var interiorRing = []; + + var interiorRingCount = value.readUInt32(); + + for (var j = 0; j < interiorRingCount; j++) + interiorRing.push(Point._readWkbPoint(value, options)); + + polygon.interiorRings.push(interiorRing); + } + } + + return polygon; +}; + +Polygon._parseTwkb = function (value, options) { + var polygon = new Polygon(); + polygon.hasZ = options.hasZ; + polygon.hasM = options.hasM; + + if (options.isEmpty) + return polygon; + + var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); + var ringCount = value.readVarInt(); + var exteriorRingCount = value.readVarInt(); + + for (var i = 0; i < exteriorRingCount; i++) + polygon.exteriorRing.push(Point._readTwkbPoint(value, options, previousPoint)); + + for (i = 1; i < ringCount; i++) { + var interiorRing = []; + + var interiorRingCount = value.readVarInt(); + + for (var j = 0; j < interiorRingCount; j++) + interiorRing.push(Point._readTwkbPoint(value, options, previousPoint)); + + polygon.interiorRings.push(interiorRing); + } + + return polygon; +}; + +Polygon._parseGeoJSON = function (value) { + var polygon = new Polygon(); + + if (value.coordinates.length > 0 && value.coordinates[0].length > 0) + polygon.hasZ = value.coordinates[0][0].length > 2; + + for (var i = 0; i < value.coordinates.length; i++) { + if (i > 0) + polygon.interiorRings.push([]); + + for (var j = 0; j < value.coordinates[i].length; j++) { + if (i === 0) + polygon.exteriorRing.push(Point._readGeoJSONPoint(value.coordinates[i][j])); + else + polygon.interiorRings[i - 1].push(Point._readGeoJSONPoint(value.coordinates[i][j])); + } + } + + return polygon; +}; + +Polygon.prototype.toWkt = function () { + if (this.exteriorRing.length === 0) + return this._getWktType(Types.wkt.Polygon, true); + + return this._getWktType(Types.wkt.Polygon, false) + this._toInnerWkt(); +}; + +Polygon.prototype._toInnerWkt = function () { + var innerWkt = '(('; + + for (var i = 0; i < this.exteriorRing.length; i++) + innerWkt += this._getWktCoordinate(this.exteriorRing[i]) + ','; + + innerWkt = innerWkt.slice(0, -1); + innerWkt += ')'; + + for (i = 0; i < this.interiorRings.length; i++) { + innerWkt += ',('; + + for (var j = 0; j < this.interiorRings[i].length; j++) { + innerWkt += this._getWktCoordinate(this.interiorRings[i][j]) + ','; + } + + innerWkt = innerWkt.slice(0, -1); + innerWkt += ')'; + } + + innerWkt += ')'; + + return innerWkt; +}; + +Polygon.prototype.toWkb = function (parentOptions) { + var wkb = new BinaryWriter(this._getWkbSize()); + + wkb.writeInt8(1); + + this._writeWkbType(wkb, Types.wkb.Polygon, parentOptions); + + if (this.exteriorRing.length > 0) { + wkb.writeUInt32LE(1 + this.interiorRings.length); + wkb.writeUInt32LE(this.exteriorRing.length); + } + else { + wkb.writeUInt32LE(0); + } + + for (var i = 0; i < this.exteriorRing.length; i++) + this.exteriorRing[i]._writeWkbPoint(wkb); + + for (i = 0; i < this.interiorRings.length; i++) { + wkb.writeUInt32LE(this.interiorRings[i].length); + + for (var j = 0; j < this.interiorRings[i].length; j++) + this.interiorRings[i][j]._writeWkbPoint(wkb); + } + + return wkb.buffer; +}; + +Polygon.prototype.toTwkb = function () { + var twkb = new BinaryWriter(0, true); + + var precision = Geometry.getTwkbPrecision(5, 0, 0); + var isEmpty = this.exteriorRing.length === 0; + + this._writeTwkbHeader(twkb, Types.wkb.Polygon, precision, isEmpty); + + if (this.exteriorRing.length > 0) { + twkb.writeVarInt(1 + this.interiorRings.length); + + twkb.writeVarInt(this.exteriorRing.length); + + var previousPoint = new Point(0, 0, 0, 0); + for (var i = 0; i < this.exteriorRing.length; i++) + this.exteriorRing[i]._writeTwkbPoint(twkb, precision, previousPoint); + + for (i = 0; i < this.interiorRings.length; i++) { + twkb.writeVarInt(this.interiorRings[i].length); + + for (var j = 0; j < this.interiorRings[i].length; j++) + this.interiorRings[i][j]._writeTwkbPoint(twkb, precision, previousPoint); + } + } + + return twkb.buffer; +}; + +Polygon.prototype._getWkbSize = function () { + var coordinateSize = 16; + + if (this.hasZ) + coordinateSize += 8; + if (this.hasM) + coordinateSize += 8; + + var size = 1 + 4 + 4; + + if (this.exteriorRing.length > 0) + size += 4 + (this.exteriorRing.length * coordinateSize); + + for (var i = 0; i < this.interiorRings.length; i++) + size += 4 + (this.interiorRings[i].length * coordinateSize); + + return size; +}; + +Polygon.prototype.toGeoJSON = function (options) { + var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); + geoJSON.type = Types.geoJSON.Polygon; + geoJSON.coordinates = []; + + if (this.exteriorRing.length > 0) { + var exteriorRing = []; + + for (var i = 0; i < this.exteriorRing.length; i++) { + if (this.hasZ) + exteriorRing.push([this.exteriorRing[i].x, this.exteriorRing[i].y, this.exteriorRing[i].z]); + else + exteriorRing.push([this.exteriorRing[i].x, this.exteriorRing[i].y]); + } + + geoJSON.coordinates.push(exteriorRing); + } + + for (var j = 0; j < this.interiorRings.length; j++) { + var interiorRing = []; + + for (var k = 0; k < this.interiorRings[j].length; k++) { + if (this.hasZ) + interiorRing.push([this.interiorRings[j][k].x, this.interiorRings[j][k].y, this.interiorRings[j][k].z]); + else + interiorRing.push([this.interiorRings[j][k].x, this.interiorRings[j][k].y]); + } + + geoJSON.coordinates.push(interiorRing); + } + + return geoJSON; +}; diff --git a/backend/node_modules/wkx/lib/types.js b/backend/node_modules/wkx/lib/types.js index 5d9f0b0..b21ee16 100644 --- a/backend/node_modules/wkx/lib/types.js +++ b/backend/node_modules/wkx/lib/types.js @@ -1,29 +1,29 @@ -module.exports = { - wkt: { - Point: 'POINT', - LineString: 'LINESTRING', - Polygon: 'POLYGON', - MultiPoint: 'MULTIPOINT', - MultiLineString: 'MULTILINESTRING', - MultiPolygon: 'MULTIPOLYGON', - GeometryCollection: 'GEOMETRYCOLLECTION' - }, - wkb: { - Point: 1, - LineString: 2, - Polygon: 3, - MultiPoint: 4, - MultiLineString: 5, - MultiPolygon: 6, - GeometryCollection: 7 - }, - geoJSON: { - Point: 'Point', - LineString: 'LineString', - Polygon: 'Polygon', - MultiPoint: 'MultiPoint', - MultiLineString: 'MultiLineString', - MultiPolygon: 'MultiPolygon', - GeometryCollection: 'GeometryCollection' - } -}; +module.exports = { + wkt: { + Point: 'POINT', + LineString: 'LINESTRING', + Polygon: 'POLYGON', + MultiPoint: 'MULTIPOINT', + MultiLineString: 'MULTILINESTRING', + MultiPolygon: 'MULTIPOLYGON', + GeometryCollection: 'GEOMETRYCOLLECTION' + }, + wkb: { + Point: 1, + LineString: 2, + Polygon: 3, + MultiPoint: 4, + MultiLineString: 5, + MultiPolygon: 6, + GeometryCollection: 7 + }, + geoJSON: { + Point: 'Point', + LineString: 'LineString', + Polygon: 'Polygon', + MultiPoint: 'MultiPoint', + MultiLineString: 'MultiLineString', + MultiPolygon: 'MultiPolygon', + GeometryCollection: 'GeometryCollection' + } +}; diff --git a/backend/node_modules/wkx/lib/wktparser.js b/backend/node_modules/wkx/lib/wktparser.js index 5d0b0df..ffb8a93 100644 --- a/backend/node_modules/wkx/lib/wktparser.js +++ b/backend/node_modules/wkx/lib/wktparser.js @@ -1,124 +1,124 @@ -module.exports = WktParser; - -var Types = require('./types'); -var Point = require('./point'); - -function WktParser(value) { - this.value = value; - this.position = 0; -} - -WktParser.prototype.match = function (tokens) { - this.skipWhitespaces(); - - for (var i = 0; i < tokens.length; i++) { - if (this.value.substring(this.position).indexOf(tokens[i]) === 0) { - this.position += tokens[i].length; - return tokens[i]; - } - } - - return null; -}; - -WktParser.prototype.matchRegex = function (tokens) { - this.skipWhitespaces(); - - for (var i = 0; i < tokens.length; i++) { - var match = this.value.substring(this.position).match(tokens[i]); - - if (match) { - this.position += match[0].length; - return match; - } - } - - return null; -}; - -WktParser.prototype.isMatch = function (tokens) { - this.skipWhitespaces(); - - for (var i = 0; i < tokens.length; i++) { - if (this.value.substring(this.position).indexOf(tokens[i]) === 0) { - this.position += tokens[i].length; - return true; - } - } - - return false; -}; - -WktParser.prototype.matchType = function () { - var geometryType = this.match([Types.wkt.Point, Types.wkt.LineString, Types.wkt.Polygon, Types.wkt.MultiPoint, - Types.wkt.MultiLineString, Types.wkt.MultiPolygon, Types.wkt.GeometryCollection]); - - if (!geometryType) - throw new Error('Expected geometry type'); - - return geometryType; -}; - -WktParser.prototype.matchDimension = function () { - var dimension = this.match(['ZM', 'Z', 'M']); - - switch (dimension) { - case 'ZM': return { hasZ: true, hasM: true }; - case 'Z': return { hasZ: true, hasM: false }; - case 'M': return { hasZ: false, hasM: true }; - default: return { hasZ: false, hasM: false }; - } -}; - -WktParser.prototype.expectGroupStart = function () { - if (!this.isMatch(['('])) - throw new Error('Expected group start'); -}; - -WktParser.prototype.expectGroupEnd = function () { - if (!this.isMatch([')'])) - throw new Error('Expected group end'); -}; - -WktParser.prototype.matchCoordinate = function (options) { - var match; - - if (options.hasZ && options.hasM) - match = this.matchRegex([/^(\S*)\s+(\S*)\s+(\S*)\s+([^\s,)]*)/]); - else if (options.hasZ || options.hasM) - match = this.matchRegex([/^(\S*)\s+(\S*)\s+([^\s,)]*)/]); - else - match = this.matchRegex([/^(\S*)\s+([^\s,)]*)/]); - - if (!match) - throw new Error('Expected coordinates'); - - if (options.hasZ && options.hasM) - return new Point(parseFloat(match[1]), parseFloat(match[2]), parseFloat(match[3]), parseFloat(match[4])); - else if (options.hasZ) - return new Point(parseFloat(match[1]), parseFloat(match[2]), parseFloat(match[3])); - else if (options.hasM) - return new Point(parseFloat(match[1]), parseFloat(match[2]), undefined, parseFloat(match[3])); - else - return new Point(parseFloat(match[1]), parseFloat(match[2])); -}; - -WktParser.prototype.matchCoordinates = function (options) { - var coordinates = []; - - do { - var startsWithBracket = this.isMatch(['(']); - - coordinates.push(this.matchCoordinate(options)); - - if (startsWithBracket) - this.expectGroupEnd(); - } while (this.isMatch([','])); - - return coordinates; -}; - -WktParser.prototype.skipWhitespaces = function () { - while (this.position < this.value.length && this.value[this.position] === ' ') - this.position++; -}; +module.exports = WktParser; + +var Types = require('./types'); +var Point = require('./point'); + +function WktParser(value) { + this.value = value; + this.position = 0; +} + +WktParser.prototype.match = function (tokens) { + this.skipWhitespaces(); + + for (var i = 0; i < tokens.length; i++) { + if (this.value.substring(this.position).indexOf(tokens[i]) === 0) { + this.position += tokens[i].length; + return tokens[i]; + } + } + + return null; +}; + +WktParser.prototype.matchRegex = function (tokens) { + this.skipWhitespaces(); + + for (var i = 0; i < tokens.length; i++) { + var match = this.value.substring(this.position).match(tokens[i]); + + if (match) { + this.position += match[0].length; + return match; + } + } + + return null; +}; + +WktParser.prototype.isMatch = function (tokens) { + this.skipWhitespaces(); + + for (var i = 0; i < tokens.length; i++) { + if (this.value.substring(this.position).indexOf(tokens[i]) === 0) { + this.position += tokens[i].length; + return true; + } + } + + return false; +}; + +WktParser.prototype.matchType = function () { + var geometryType = this.match([Types.wkt.Point, Types.wkt.LineString, Types.wkt.Polygon, Types.wkt.MultiPoint, + Types.wkt.MultiLineString, Types.wkt.MultiPolygon, Types.wkt.GeometryCollection]); + + if (!geometryType) + throw new Error('Expected geometry type'); + + return geometryType; +}; + +WktParser.prototype.matchDimension = function () { + var dimension = this.match(['ZM', 'Z', 'M']); + + switch (dimension) { + case 'ZM': return { hasZ: true, hasM: true }; + case 'Z': return { hasZ: true, hasM: false }; + case 'M': return { hasZ: false, hasM: true }; + default: return { hasZ: false, hasM: false }; + } +}; + +WktParser.prototype.expectGroupStart = function () { + if (!this.isMatch(['('])) + throw new Error('Expected group start'); +}; + +WktParser.prototype.expectGroupEnd = function () { + if (!this.isMatch([')'])) + throw new Error('Expected group end'); +}; + +WktParser.prototype.matchCoordinate = function (options) { + var match; + + if (options.hasZ && options.hasM) + match = this.matchRegex([/^(\S*)\s+(\S*)\s+(\S*)\s+([^\s,)]*)/]); + else if (options.hasZ || options.hasM) + match = this.matchRegex([/^(\S*)\s+(\S*)\s+([^\s,)]*)/]); + else + match = this.matchRegex([/^(\S*)\s+([^\s,)]*)/]); + + if (!match) + throw new Error('Expected coordinates'); + + if (options.hasZ && options.hasM) + return new Point(parseFloat(match[1]), parseFloat(match[2]), parseFloat(match[3]), parseFloat(match[4])); + else if (options.hasZ) + return new Point(parseFloat(match[1]), parseFloat(match[2]), parseFloat(match[3])); + else if (options.hasM) + return new Point(parseFloat(match[1]), parseFloat(match[2]), undefined, parseFloat(match[3])); + else + return new Point(parseFloat(match[1]), parseFloat(match[2])); +}; + +WktParser.prototype.matchCoordinates = function (options) { + var coordinates = []; + + do { + var startsWithBracket = this.isMatch(['(']); + + coordinates.push(this.matchCoordinate(options)); + + if (startsWithBracket) + this.expectGroupEnd(); + } while (this.isMatch([','])); + + return coordinates; +}; + +WktParser.prototype.skipWhitespaces = function () { + while (this.position < this.value.length && this.value[this.position] === ' ') + this.position++; +}; diff --git a/backend/node_modules/wkx/lib/wkx.d.ts b/backend/node_modules/wkx/lib/wkx.d.ts index 7c97c66..cfe7469 100644 --- a/backend/node_modules/wkx/lib/wkx.d.ts +++ b/backend/node_modules/wkx/lib/wkx.d.ts @@ -1,100 +1,100 @@ -/// - -declare module "wkx" { - - export class Geometry { - srid: number; - hasZ: boolean; - hasM: boolean; - - static parse(value: string | Buffer): Geometry; - static parseTwkb(value: Buffer): Geometry; - static parseGeoJSON(value: {}): Geometry; - - toWkt(): string; - toEwkt(): string; - toWkb(): Buffer; - toEwkb(): Buffer; - toTwkb(): Buffer; - toGeoJSON(options?: GeoJSONOptions): {}; - } - - export interface GeoJSONOptions { - shortCrs?: boolean; - longCrs?: boolean; - } - - export class Point extends Geometry { - x: number; - y: number; - z: number; - m: number; - - constructor(x?: number, y?: number, z?: number, m?: number, srid?: number); - - static Z(x: number, y: number, z: number, srid?: number): Point; - static M(x: number, y: number, m: number, srid?: number): Point; - static ZM(x: number, y: number, z: number, m: number, srid?: number): Point; - } - - export class LineString extends Geometry { - points: Point[]; - - constructor(points?: Point[], srid?: number); - - static Z(points?: Point[], srid?: number): LineString; - static M(points?: Point[], srid?: number): LineString; - static ZM(points?: Point[], srid?: number): LineString; - } - - export class Polygon extends Geometry { - exteriorRing: Point[]; - interiorRings: Point[][]; - - constructor(exteriorRing?: Point[], interiorRings?: Point[][], srid?: number); - - static Z(exteriorRing?: Point[], interiorRings?: Point[][], srid?: number): Polygon; - static M(exteriorRing?: Point[], interiorRings?: Point[][], srid?: number): Polygon; - static ZM(exteriorRing?: Point[], interiorRings?: Point[][], srid?: number): Polygon; - } - - export class MultiPoint extends Geometry { - points: Point[]; - - constructor(points?: Point[], srid?: number); - - static Z(points?: Point[], srid?: number): MultiPoint; - static M(points?: Point[], srid?: number): MultiPoint; - static ZM(points?: Point[], srid?: number): MultiPoint; - } - - export class MultiLineString extends Geometry { - lineStrings: LineString[]; - - constructor(lineStrings?: LineString[], srid?: number); - - static Z(lineStrings?: LineString[], srid?: number): MultiLineString; - static M(lineStrings?: LineString[], srid?: number): MultiLineString; - static ZM(lineStrings?: LineString[], srid?: number): MultiLineString; - } - - export class MultiPolygon extends Geometry { - polygons: Polygon[]; - - constructor(polygons?: Polygon[], srid?: number); - - static Z(polygons?: Polygon[], srid?: number): MultiPolygon; - static M(polygons?: Polygon[], srid?: number): MultiPolygon; - static ZM(polygons?: Polygon[], srid?: number): MultiPolygon; - } - - export class GeometryCollection extends Geometry { - geometries: Geometry[]; - - constructor(geometries?: Geometry[], srid?: number); - - static Z(geometries?: Geometry[], srid?: number): GeometryCollection; - static M(geometries?: Geometry[], srid?: number): GeometryCollection; - static ZM(geometries?: Geometry[], srid?: number): GeometryCollection; - } +/// + +declare module "wkx" { + + export class Geometry { + srid: number; + hasZ: boolean; + hasM: boolean; + + static parse(value: string | Buffer): Geometry; + static parseTwkb(value: Buffer): Geometry; + static parseGeoJSON(value: {}): Geometry; + + toWkt(): string; + toEwkt(): string; + toWkb(): Buffer; + toEwkb(): Buffer; + toTwkb(): Buffer; + toGeoJSON(options?: GeoJSONOptions): {}; + } + + export interface GeoJSONOptions { + shortCrs?: boolean; + longCrs?: boolean; + } + + export class Point extends Geometry { + x: number; + y: number; + z: number; + m: number; + + constructor(x?: number, y?: number, z?: number, m?: number, srid?: number); + + static Z(x: number, y: number, z: number, srid?: number): Point; + static M(x: number, y: number, m: number, srid?: number): Point; + static ZM(x: number, y: number, z: number, m: number, srid?: number): Point; + } + + export class LineString extends Geometry { + points: Point[]; + + constructor(points?: Point[], srid?: number); + + static Z(points?: Point[], srid?: number): LineString; + static M(points?: Point[], srid?: number): LineString; + static ZM(points?: Point[], srid?: number): LineString; + } + + export class Polygon extends Geometry { + exteriorRing: Point[]; + interiorRings: Point[][]; + + constructor(exteriorRing?: Point[], interiorRings?: Point[][], srid?: number); + + static Z(exteriorRing?: Point[], interiorRings?: Point[][], srid?: number): Polygon; + static M(exteriorRing?: Point[], interiorRings?: Point[][], srid?: number): Polygon; + static ZM(exteriorRing?: Point[], interiorRings?: Point[][], srid?: number): Polygon; + } + + export class MultiPoint extends Geometry { + points: Point[]; + + constructor(points?: Point[], srid?: number); + + static Z(points?: Point[], srid?: number): MultiPoint; + static M(points?: Point[], srid?: number): MultiPoint; + static ZM(points?: Point[], srid?: number): MultiPoint; + } + + export class MultiLineString extends Geometry { + lineStrings: LineString[]; + + constructor(lineStrings?: LineString[], srid?: number); + + static Z(lineStrings?: LineString[], srid?: number): MultiLineString; + static M(lineStrings?: LineString[], srid?: number): MultiLineString; + static ZM(lineStrings?: LineString[], srid?: number): MultiLineString; + } + + export class MultiPolygon extends Geometry { + polygons: Polygon[]; + + constructor(polygons?: Polygon[], srid?: number); + + static Z(polygons?: Polygon[], srid?: number): MultiPolygon; + static M(polygons?: Polygon[], srid?: number): MultiPolygon; + static ZM(polygons?: Polygon[], srid?: number): MultiPolygon; + } + + export class GeometryCollection extends Geometry { + geometries: Geometry[]; + + constructor(geometries?: Geometry[], srid?: number); + + static Z(geometries?: Geometry[], srid?: number): GeometryCollection; + static M(geometries?: Geometry[], srid?: number): GeometryCollection; + static ZM(geometries?: Geometry[], srid?: number): GeometryCollection; + } } \ No newline at end of file diff --git a/backend/node_modules/wkx/lib/wkx.js b/backend/node_modules/wkx/lib/wkx.js index e04ae06..48ba61e 100644 --- a/backend/node_modules/wkx/lib/wkx.js +++ b/backend/node_modules/wkx/lib/wkx.js @@ -1,9 +1,9 @@ -exports.Types = require('./types'); -exports.Geometry = require('./geometry'); -exports.Point = require('./point'); -exports.LineString = require('./linestring'); -exports.Polygon = require('./polygon'); -exports.MultiPoint = require('./multipoint'); -exports.MultiLineString = require('./multilinestring'); -exports.MultiPolygon = require('./multipolygon'); +exports.Types = require('./types'); +exports.Geometry = require('./geometry'); +exports.Point = require('./point'); +exports.LineString = require('./linestring'); +exports.Polygon = require('./polygon'); +exports.MultiPoint = require('./multipoint'); +exports.MultiLineString = require('./multilinestring'); +exports.MultiPolygon = require('./multipolygon'); exports.GeometryCollection = require('./geometrycollection'); \ No newline at end of file diff --git a/backend/node_modules/wkx/lib/zigzag.js b/backend/node_modules/wkx/lib/zigzag.js index b4dfeea..aceb238 100644 --- a/backend/node_modules/wkx/lib/zigzag.js +++ b/backend/node_modules/wkx/lib/zigzag.js @@ -1,8 +1,8 @@ -module.exports = { - encode: function (value) { - return (value << 1) ^ (value >> 31); - }, - decode: function (value) { - return (value >> 1) ^ (-(value & 1)); - } -}; +module.exports = { + encode: function (value) { + return (value << 1) ^ (value >> 31); + }, + decode: function (value) { + return (value >> 1) ^ (-(value & 1)); + } +}; diff --git a/backend/node_modules/wkx/package.json b/backend/node_modules/wkx/package.json index 7d2958e..cf663a5 100644 --- a/backend/node_modules/wkx/package.json +++ b/backend/node_modules/wkx/package.json @@ -1,50 +1,50 @@ -{ - "name": "wkx", - "version": "0.5.0", - "description": "A WKT/WKB/EWKT/EWKB/TWKB/GeoJSON parser and serializer", - "main": "lib/wkx.js", - "types": "lib/wkx.d.ts", - "files": [ - "dist/", - "lib/" - ], - "scripts": { - "test": "jshint . && nyc mocha", - "build": "mkdirp ./dist && browserify -r buffer -r ./lib/wkx.js:wkx ./lib/wkx.js > ./dist/wkx.js && uglifyjs -c -m -- ./dist/wkx.js > ./dist/wkx.min.js", - "coverage": "nyc report --reporter=text-lcov | coveralls" - }, - "author": "Christian Schwarz", - "license": "MIT", - "devDependencies": { - "async": "^3.2.0", - "browserify": "^16.5.0", - "coveralls": "^3.0.11", - "deep-eql": "^4.0.0", - "jshint": "^2.11.0", - "json-stringify-pretty-compact": "^2.0.0", - "mkdirp": "^1.0.3", - "mocha": "^7.1.1", - "nyc": "^15.0.0", - "pg": "^7.18.2", - "uglify-js": "^3.8.0" - }, - "repository": { - "type": "git", - "url": "http://github.com/cschwarz/wkx.git" - }, - "keywords": [ - "wkt", - "wkb", - "ewkt", - "ewkb", - "twkb", - "geojson", - "ogc", - "geometry", - "geography", - "spatial" - ], - "dependencies": { - "@types/node": "*" - } +{ + "name": "wkx", + "version": "0.5.0", + "description": "A WKT/WKB/EWKT/EWKB/TWKB/GeoJSON parser and serializer", + "main": "lib/wkx.js", + "types": "lib/wkx.d.ts", + "files": [ + "dist/", + "lib/" + ], + "scripts": { + "test": "jshint . && nyc mocha", + "build": "mkdirp ./dist && browserify -r buffer -r ./lib/wkx.js:wkx ./lib/wkx.js > ./dist/wkx.js && uglifyjs -c -m -- ./dist/wkx.js > ./dist/wkx.min.js", + "coverage": "nyc report --reporter=text-lcov | coveralls" + }, + "author": "Christian Schwarz", + "license": "MIT", + "devDependencies": { + "async": "^3.2.0", + "browserify": "^16.5.0", + "coveralls": "^3.0.11", + "deep-eql": "^4.0.0", + "jshint": "^2.11.0", + "json-stringify-pretty-compact": "^2.0.0", + "mkdirp": "^1.0.3", + "mocha": "^7.1.1", + "nyc": "^15.0.0", + "pg": "^7.18.2", + "uglify-js": "^3.8.0" + }, + "repository": { + "type": "git", + "url": "http://github.com/cschwarz/wkx.git" + }, + "keywords": [ + "wkt", + "wkb", + "ewkt", + "ewkb", + "twkb", + "geojson", + "ogc", + "geometry", + "geography", + "spatial" + ], + "dependencies": { + "@types/node": "*" + } } \ No newline at end of file diff --git a/backend/routes/diaryRoutes.js b/backend/routes/diaryRoutes.js new file mode 100644 index 0000000..f63dec9 --- /dev/null +++ b/backend/routes/diaryRoutes.js @@ -0,0 +1,11 @@ +import express from 'express'; +import { authenticate } from '../middleware/authMiddleware.js'; +import { getDatesForClub, createDateForClub, updateTrainingTimes } from '../controllers/diaryController.js'; + +const router = express.Router(); + +router.get('/:clubId', authenticate, getDatesForClub); +router.post('/:clubId', authenticate, createDateForClub); +router.put('/:clubId', authenticate, updateTrainingTimes); + +export default router; diff --git a/backend/routes/memberRoutes.js b/backend/routes/memberRoutes.js index 9ffd7da..b0e5010 100644 --- a/backend/routes/memberRoutes.js +++ b/backend/routes/memberRoutes.js @@ -1,10 +1,11 @@ -import { getClubMembers, getWaitingApprovals } from '../controllers/memberController.js'; +import { getClubMembers, getWaitingApprovals, setClubMembers } from '../controllers/memberController.js'; import express from 'express'; import { authenticate } from '../middleware/authMiddleware.js'; const router = express.Router(); -router.post('/', authenticate, getClubMembers); +router.get('/:id', authenticate, getClubMembers); +router.post('/:id', authenticate, setClubMembers); router.get('/notapproved/:id', authenticate, getWaitingApprovals); export default router; diff --git a/backend/server.js b/backend/server.js index cd6b60c..005414e 100644 --- a/backend/server.js +++ b/backend/server.js @@ -2,10 +2,13 @@ import express from 'express'; import path from 'path'; import { fileURLToPath } from 'url'; import sequelize from './database.js'; -import './models/index.js'; // Stellt sicher, dass die Modelle und Beziehungen geladen werden +import { User, Log, Club, UserClub } from './models/index.js'; import authRoutes from './routes/authRoutes.js'; -import clubRoutes from './routes/clubRoutes.js' +import clubRoutes from './routes/clubRoutes.js'; +import diaryRoutes from './routes/diaryRoutes.js'; import memberRoutes from './routes/memberRoutes.js'; +import Member from './models/Member.js'; +import DiaryDate from './models/DiaryDates.js'; const app = express(); const port = process.env.PORT || 3000; @@ -17,6 +20,7 @@ app.use(express.json()); app.use('/api/auth', authRoutes); app.use('/api/clubs', clubRoutes); app.use('/api/clubmembers', memberRoutes); +app.use('/api/diary', diaryRoutes); app.use(express.static(path.join(__dirname, '../frontend/dist'))); @@ -24,10 +28,19 @@ app.get('*', (req, res) => { res.sendFile(path.join(__dirname, '../frontend/dist/index.html')); }); -sequelize.sync({ alter: true }).then(() => { - console.log('Database synchronized'); -}); - -app.listen(port, () => { - console.log(`Server is running on http://localhost:${port}`); -}); +(async () => { + try { + await sequelize.authenticate(); + await User.sync({ alter: true }); + await Club.sync({ alter: true }); + await UserClub.sync({ alter: true }); + await Log.sync({ alter: true }); + await Member.sync({ alter: true }); + await DiaryDate.sync({ alter: true }); + app.listen(port, () => { + console.log(`Server is running on http://localhost:${port}`); + }); + } catch (err) { + console.error('Unable to synchronize the database:', err); + } +})(); diff --git a/backend/services/authService.js b/backend/services/authService.js index 2c48b47..bdaab8a 100644 --- a/backend/services/authService.js +++ b/backend/services/authService.js @@ -4,10 +4,15 @@ import User from '../models/User.js'; import { sendActivationEmail } from './emailService.js'; const register = async (email, password) => { - const activationCode = Math.random().toString(36).substring(2, 15); - const user = await User.create({ email, password, activationCode }); - await sendActivationEmail(email, activationCode); - return user; + try { + const activationCode = Math.random().toString(36).substring(2, 15); + const user = await User.create({ email, password, activationCode }); + await sendActivationEmail(email, activationCode); + return user; + } catch (error) { + console.log(error); + return null; + } }; const activateUser = async (activationCode) => { @@ -21,11 +26,12 @@ const activateUser = async (activationCode) => { const login = async (email, password) => { const user = await User.findOne({ where: { email } }); - if (!user || !user.isActive) throw new Error('Invalid email or password'); + if (!user || !user.isActive) throw new Error('Invalid email or password.'); const isPasswordValid = await bcrypt.compare(password, user.password); - if (!isPasswordValid) throw new Error('Invalid email or password'); + if (!isPasswordValid) throw new Error('Invalid email or password!'); const token = jwt.sign({ userId: user.hashedId }, process.env.JWT_SECRET, { expiresIn: '1h' }); - await user.update({ hashedId: token }); + user.authCode = token; + await user.save(); return { token }; }; diff --git a/backend/services/diaryService.js b/backend/services/diaryService.js new file mode 100644 index 0000000..8a7a55f --- /dev/null +++ b/backend/services/diaryService.js @@ -0,0 +1,70 @@ +import DiaryDate from '../models/DiaryDates.js'; +import Club from '../models/Club.js'; +import { checkAccess } from '../utils/userUtils.js'; +import HttpError from '../exceptions/HttpError.js'; + +class DiaryService { + async getDatesForClub(userToken, clubId) { + console.log('[DiaryService::getDatesForClub] - Check user access'); + await checkAccess(userToken, clubId); + console.log('[DiaryService::getDatesForClub] - Validate club existence'); + const club = await Club.findByPk(clubId); + if (!club) { + throw new HttpError('Club not found', 404); + } + console.log('[DiaryService::getDatesForClub] - Load diary dates'); + const dates = await DiaryDate.findAll({ + where: { clubId }, + order: [['date', 'ASC'], ['trainingStart', 'ASC']] + }); + + return dates; + } + + async createDateForClub(userToken, clubId, date, trainingStart, trainingEnd) { + console.log('[DiaryService::createDateForClub] - Check user access'); + await checkAccess(userToken, clubId); + console.log('[DiaryService::createDateForClub] - Validate club existence'); + const club = await Club.findByPk(clubId); + if (!club) { + throw new HttpError('Club not found', 404); + } + console.log('[DiaryService::createDateForClub] - Validate date'); + const parsedDate = new Date(date); + if (isNaN(parsedDate.getTime())) { + throw new HttpError('Invalid date format', 400); + } + if (trainingStart && trainingEnd && trainingStart >= trainingEnd) { + throw new HttpError('Training start time must be before training end time', 400); + } + console.log('[DiaryService::createDateForClub] - Create new diary date'); + const newDate = await DiaryDate.create({ + date: parsedDate, + clubId, + trainingStart: trainingStart || null, + trainingEnd: trainingEnd || null, + }); + + return newDate; + } + + async updateTrainingTimes(userToken, clubId, date, trainingStart, trainingEnd) { + console.log('[DiaryService::updateTrainingTimes] - Check user access'); + await checkAccess(userToken, clubId); + console.log('[DiaryService::updateTrainingTimes] - Validate date'); + const diaryDate = await DiaryDate.findOne({ where: { clubId, date } }); + if (!diaryDate) { + throw new HttpError('Diary entry not found', 404); + } + if (trainingStart && trainingEnd && trainingStart >= trainingEnd) { + throw new HttpError('Training start time must be before training end time', 400); + } + console.log('[DiaryService::updateTrainingTimes] - Update training times'); + diaryDate.trainingStart = trainingStart || null; + diaryDate.trainingEnd = trainingEnd || null; + await diaryDate.save(); + return diaryDate; + } +} + +export default DiaryService; diff --git a/backend/services/emailService.js b/backend/services/emailService.js index 1fcdf52..793740c 100644 --- a/backend/services/emailService.js +++ b/backend/services/emailService.js @@ -3,17 +3,17 @@ import nodemailer from 'nodemailer'; const transporter = nodemailer.createTransport({ service: 'Gmail', auth: { - user: process.env.EMAIL_USER, - pass: process.env.EMAIL_PASS, + user: process.env.EMAIL_USER, + pass: process.env.EMAIL_PASS, }, }); - + const sendActivationEmail = async (email, activationCode) => { const mailOptions = { from: process.env.EMAIL_USER, to: email, subject: 'Account Activation', - text: `Activate your account by clicking the following link: ${process.env.BASE_URL}/api/auth/activate/${activationCode}`, + text: `Activate your account by clicking the following link: ${process.env.BASE_URL}/activate/${activationCode}`, }; await transporter.sendMail(mailOptions); }; diff --git a/backend/services/memberService.js b/backend/services/memberService.js index 0e11ba9..2f82f2c 100644 --- a/backend/services/memberService.js +++ b/backend/services/memberService.js @@ -1,19 +1,81 @@ import UserClub from "../models/UserClub.js"; import { checkAccess } from "../utils/userUtils.js"; +import { getUserByToken } from "../utils/userUtils.js"; +import HttpError from "../exceptions/HttpError.js"; +import Member from "../models/Member.js"; +import { response } from "express"; class MemberService { async getApprovalRequests(userToken, clubId) { - checkAccess(userToken, clubId); - return UserClub.findAll({ + console.log('[MemberService::getApprovalRequest] - Check user access'); + await checkAccess(userToken, clubId); + console.log('[MemberService::getApprovalRequest] - Load user'); + const user = await getUserByToken(userToken); + console.log('[MemberService::getApprovalRequest] - Load userclub'); + return await UserClub.findAll({ where: { clubId: clubId, - approved: false + approved: false, + userId: user.id } }); } - async getClubMembers(clubId) { - + async getClubMembers(userToken, clubId) { + console.log('[getClubMembers] - Check access'); + await checkAccess(userToken, clubId); + console.log('[getClubMembers] - Find members'); + const members = await Member.findAll({ where: { clubId: clubId }}); + console.log('[getClubMembers] - return members'); + return members; + } + + async setClubMember(userToken, clubId, memberId, firstName, lastName, street, city, birthdate, phone, email) { + try { + console.log('[setClubMembers] - Check access'); + await checkAccess(userToken, clubId); + console.log('[setClubMembers] - set default member'); + let member = null; + console.log('[setClubMembers] - load member if possible'); + if (memberId) { + member = await Member.findOne({ where: { id: memberId }}); + } + console.log('[setClubMembers] - set member'); + if (member) { + member.firstName = firstName; + member.lastName = lastName; + member.street = street; + member.city = city; + member.birthDate = birthdate; + member.phone = phone; + member.email = email; + await member.save(); + } else { + await Member.create({ + firstName: firstName, + lastName: lastName, + street: street, + city: city, + birthDate: birthdate, + phone: phone, + email: email, + clubId: clubId, + }); + } + console.log('[setClubMembers] - load club members'); + const members = await this.getClubMembers(userToken, clubId); + console.log('[setClubMembers] - return response'); + return { + status: 200, + response: members, + } + } catch (error) { + console.log(error); + return { + status: error.statusCode || 500, + response: { error: "nocreation" } + } + } } } diff --git a/backend/utils/encrypt.js b/backend/utils/encrypt.js index 91ece5c..f4f2f5a 100644 --- a/backend/utils/encrypt.js +++ b/backend/utils/encrypt.js @@ -5,12 +5,17 @@ const createHash = (value) => { } function encryptData(data) { - const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(process.env.ENCRYPTION_KEY, 'hex'), Buffer.alloc(16, 0)); - let encrypted = cipher.update(data, 'utf8', 'hex'); - encrypted += cipher.final('hex'); - return encrypted; -} - + try { + const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(process.env.ENCRYPTION_KEY, 'hex'), Buffer.alloc(16, 0)); + let encrypted = cipher.update(data, 'utf8', 'hex'); + encrypted += cipher.final('hex'); + return encrypted; + } catch (error) { + console.log(error, data, process.env.ENCRYPTION_KEY, typeof data, process.env.ENCRYPTION_KEY.length); + return ''; + } +} + function decryptData(data) { const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(process.env.ENCRYPTION_KEY, 'hex'), Buffer.alloc(16, 0)); let decrypted = decipher.update(data, 'hex', 'utf8'); @@ -18,4 +23,4 @@ function decryptData(data) { return decrypted; } -export default { createHash, encryptData, decryptData }; \ No newline at end of file +export { createHash, encryptData, decryptData }; \ No newline at end of file diff --git a/backend/utils/userUtils.js b/backend/utils/userUtils.js index 17e572a..13655b8 100644 --- a/backend/utils/userUtils.js +++ b/backend/utils/userUtils.js @@ -1,29 +1,44 @@ import User from '../models/User.js' import UserClub from '../models/UserClub.js'; +import HttpError from '../exceptions/HttpError.js'; export const getUserByToken = async(token) => { - const user = await User.findOne({ - where: [ - {hashed_id: token} - ] - }); - return user; + try { + const user = await User.findOne({ + where: [ + {auth_code: token} + ] + }); + return user; + } catch (error) { + console.log(error); + const err = new HttpError('noaccess', 403); + throw err; + } } export const hasUserClubAccess = async(userId, clubId) => { - const userClub = UserClub.findOne({ - where: { - userId: userId, - clubId: clubId, - approved: true - } - }); - return userClub !== null; + try { + console.log('[hasUserClubAccess]'); + const userClub = await UserClub.findOne({ + where: { + user_id: userId, + club_id: clubId, + approved: true + } + }); + return userClub !== null; + } catch(error) { + console.log(error); + throw new HttpError('notfound', 500); + } } export const checkAccess = async(userToken, clubId) => { - const user = getUserByToken(userToken); - if (!hasUserClubAccess(user.id, clubId)) { - throw new Error('noaccess'); + const user = await getUserByToken(userToken); + if (!await hasUserClubAccess(user.id, clubId)) { + console.log('no club access'); + const err = new HttpError('noaccess', 403); + throw err; } } \ No newline at end of file diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 4764f73..1b27110 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,15 +1,29 @@ @@ -40,7 +54,7 @@ export default { } }, methods: { - ...mapActions(['setCurrentClub', 'setClubs']), + ...mapActions(['setCurrentClub', 'setClubs', 'logout']), loadClub() { this.setCurrentClub(this.currentClub); this.$router.push(`/showclub/${this.currentClub}`); @@ -61,13 +75,14 @@ export default { display: flex; height: 100%; overflow: hidden; - flex: 1; } .navigation { width: 10em; background-color: #e0e0e0; + display: flex; + flex-direction: column; } -router-view { +.content { flex: 1; } diff --git a/frontend/src/router.js b/frontend/src/router.js index 87fc874..77acc08 100644 --- a/frontend/src/router.js +++ b/frontend/src/router.js @@ -5,6 +5,8 @@ import Activate from './views/Activate.vue'; import Home from './views/Home.vue'; import CreateClub from './views/CreateClub.vue'; import ClubView from './views/ClubView.vue'; +import MembersView from './views/MembersView.vue'; +import DiaryView from './views/DiaryView.vue'; const routes = [ { path: '/register', component: Register }, @@ -13,6 +15,8 @@ const routes = [ { path: '/', component: Home }, { path: '/createclub', component: CreateClub }, { path: '/showclub/:1', component: ClubView }, + { path: '/members', component: MembersView }, + { path: '/diary', component: DiaryView }, ]; const router = createRouter({ diff --git a/frontend/src/store.js b/frontend/src/store.js index a5477b4..2270908 100644 --- a/frontend/src/store.js +++ b/frontend/src/store.js @@ -44,6 +44,7 @@ const store = createStore({ logout({ commit }) { commit('clearToken'); commit('clearUsername'); + router.push("/"); }, setCurrentClub({ commit }, club) { console.log('action', club); diff --git a/frontend/src/views/ClubView.vue b/frontend/src/views/ClubView.vue index dc820ca..54b7492 100644 --- a/frontend/src/views/ClubView.vue +++ b/frontend/src/views/ClubView.vue @@ -8,7 +8,9 @@

Trainingstagebuch

@@ -78,4 +80,10 @@ export default { h2 { display: block; } + +ul { + list-style-type: none; + padding: 0; + margin: 0; +} diff --git a/frontend/src/views/DiaryView.vue b/frontend/src/views/DiaryView.vue new file mode 100644 index 0000000..ab355a5 --- /dev/null +++ b/frontend/src/views/DiaryView.vue @@ -0,0 +1,158 @@ + + + + + diff --git a/frontend/src/views/MembersView.vue b/frontend/src/views/MembersView.vue new file mode 100644 index 0000000..f15e688 --- /dev/null +++ b/frontend/src/views/MembersView.vue @@ -0,0 +1,175 @@ + + + + + \ No newline at end of file