Skip to content
Suresoft-GLaDOS edited this page May 26, 2023 · 9 revisions

#1

Link : https://github.com/OSGeo/PROJ/commit/00dffd7ace356d7cb39e2c515237d4351f5b5666
Description: Avoid division by zero when |lat_0|=90

At src/projections/omerc.cpp

@@ -191,9 +191,6 @@ PJ *PROJECTION(omerc) {
                 gamma = alpha_c;
         } else
             alpha_c = aasin(P->ctx, D*sin(gamma0 = gamma));
+        if( fabs(fabs(P->phi0) - M_HALFPI) <= TOL ) {
+            return pj_default_destructor(P, PJD_ERR_LAT_0_OR_ALPHA_EQ_90);
+        }
         P->lam0 = lamc - aasin(P->ctx, .5 * (F - 1. / F) *
            tan(gamma0)) / Q->B;
     } else {

Tags
#Division-by-zero #Omission #Multi-line #Added

#2

Link : https://github.com/OSGeo/PROJ/commit/1b0c6fbc8b90522983b18772303ff517dec21cd5
Description: Avoid division by zero

At src/projections/airy.cpp

@@ -79,10 +79,6 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) {           /* Spheroidal, forward */
         }
         if (fabs(s = 1. - cosz) > EPS) {
             t = 0.5 * (1. + cosz);
+            if(t == 0) {
+                proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION);
+                return xy;
+            }
             Krho = -log(t)/s - Q->Cb / t;
         } else
             Krho = 0.5 - Q->Cb;

Tags
#Division-by-zero #Omission #Multi-line #Added

#3

Link : https://github.com/OSGeo/PROJ/commit/4c8a5cb8c7f69dd227f03f32eb99b53ea0586aba
Description: Avoid invalid integer shift

At src/projections/isea.cpp

@@ -898,10 +898,6 @@ static int isea_hex(struct isea_dgg *g, int tri,
     quad = isea_ptdi(g, tri, pt, &v);
+    if( v.x < (INT_MIN >> 4) || v.x > (INT_MAX >> 4) )
+    {
+        throw "Invalid shift";
+    }
     hex->x = ((int)v.x << 4) + quad;
     hex->y = v.y;

Tags
#Omission #Multi-line #Added

#4

Link : https://github.com/OSGeo/PROJ/commit/004e26293e258a9144e6e1d33049eb1753b82b89
Description: Fix identification of GeodeticCRS expressed by PROJ string for EPSG authority

At src/iso19111/io.cpp

@@ -6899,7 +6899,6 @@ PROJStringParser::Private::buildGeographicCRS(int iStep, int iUnitConvert,
          getNumericValue(getParamValue(step, "lon_0")) != 0.0)) {
         props.set("EXTENSION_PROJ4", projString_);
     }
+    props.set("IMPLICIT_CS", true);
     return GeographicCRS::create(props, datum, cs);
 }
@@ -7390,8 +7389,7 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS(
         props.set("EXTENSION_PROJ4", projString_);
     }
+    props.set("IMPLICIT_CS", true);
     CRSNNPtr crs = ProjectedCRS::create(props, geogCRS, NN_NO_CHECK(conv), cs);
     if (!hasParamValue(step, "geoidgrids") &&

Tags
#Omission #Multi-line #Added

#5

Link : https://github.com/OSGeo/PROJ/commit/5aa3d9fce2e29f7a20d68708d06c55685efe3d5a
Description: Fix when there are only operations without area of use

At src/iso19111/c_api.cpp

@@ -7664,9 +7664,6 @@ int proj_get_suggested_operation(PJ_CONTEXT *ctx, PJ_OBJ_LIST *operations,
     int iExcluded[2] = {-1, -1};
     const auto &preparedOps = opList->getPreparedOperations(ctx);
+    if (preparedOps.empty() && !opList->objects.empty()) {
+        return 0;
+    }
     int idx = pj_get_suggested_operation(ctx, preparedOps, iExcluded, direction,
                                          coord);
     if (idx >= 0) {

Tags
#Omission #Multi-line #Added

#6

Link : https://github.com/OSGeo/PROJ/commit/6cc83a2c80dec40f15d58dc335449aabddca4743
Description: Fix wrong identification of some ESRI WKT linked to units

At src/iso19111/crs.cpp

@@ -3728,15 +3728,6 @@ ProjectedCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const {
                         res.emplace_back(crsNN, eqName ? 90 : 70);
                     } else if (crs->nameStr() == thisName &&
                                CRS::getPrivate()->implicitCS_ &&
+                               coordinateSystem()
+                                   ->axisList()[0]
+                                   ->unit()
+                                   ._isEquivalentTo(
+                                       crs->coordinateSystem()
+                                           ->axisList()[0]
+                                           ->unit(),
+                                       util::IComparable::Criterion::
+                                           EQUIVALENT) &&
                                l_baseCRS->_isEquivalentTo(
                                    crs->baseCRS().get(),
                                    util::IComparable::Criterion::

Tags
#Omission #Multi-line #Added

#7

Link : https://github.com/OSGeo/PROJ/commit/6ef286ec69e7f6e3b1fba55e14aed209fbf705c0
Description: Fix for GDAL test failure

At src/iso19111/metadata.cpp

@@ -1124,7 +1124,7 @@ void Identifier::_exportToJSON(JSONFormatter *formatter) const {
 //! @cond Doxygen_Suppress
 static bool isIgnoredChar(char ch) {
     return ch == ' ' || ch == '_' || ch == '-' || ch == '/' || ch == '(' ||
+           ch == ')' || ch == '.' || ch == '&' || ch == ',';
-           ch == ')' || ch == '.' || ch == '&';
 }
 //! @endcond

Tags
#Etc #Single-line #Modified

#8

Link : https://github.com/OSGeo/PROJ/commit/7dd1a2ee6bfb33807594f115c59548f8cf1d3475
Description: Validate |lat_1| and |lat_2| <= 90

At src/projections/aea.cpp

@@ -155,8 +155,6 @@ static PJ *setup(PJ *P) {
     P->inv = e_inverse;
     P->fwd = e_forward;
+    if (fabs(Q->phi1) > M_HALFPI || fabs(Q->phi2) > M_HALFPI)
+        return destructor(P, PJD_ERR_LAT_LARGER_THAN_90);
     if (fabs(Q->phi1 + Q->phi2) < EPS10)
         return destructor(P, PJD_ERR_CONIC_LAT_EQUAL);
     Q->n = sinphi = sin(Q->phi1);

At src/strerrno.cpp

@@ -30,7 +30,7 @@ pj_err_list[] = {
     "acos/asin: |arg| >1.+1e-14",                                      /* -19 */
     "tolerance condition error",                                       /* -20 */
     "conic lat_1 = -lat_2",                                            /* -21 */
+    "lat_0, lat_1 or lat_2 >= 90",                                     /* -22 */
-    "lat_1 >= 90",                                                     /* -22 */
     "lat_1 = 0",                                                       /* -23 */
     "lat_ts >= 90",                                                    /* -24 */
     "no distance between control points",                              /* -25 */

Tags
#Omission #Invalid-condition #Multi-line #Modified

#9

Link : https://github.com/OSGeo/PROJ/commit/8f22c17b2ef9c1e216a1da0206acea41587f67ce
Description: Avoid division by zero

At src/projections/urm5.cpp

@@ -45,11 +45,7 @@ PJ *PROJECTION(urm5) {
     Q->q3 = pj_param(P->ctx, P->params, "dq").f / 3.;
     alpha = pj_param(P->ctx, P->params, "ralpha").f;
     t = Q->n * sin (alpha);
+    const double denom = sqrt (1. - t * t);
+    if( denom == 0 ) {
+        return pj_default_destructor(P, PJD_ERR_LAT_0_OR_ALPHA_EQ_90);
+    }
+    Q->m = cos (alpha) / denom;
-    Q->m = cos (alpha) / sqrt (1. - t * t);
     Q->rmn = 1. / (Q->m * Q->n);
     P->es = 0.;

Tags
#Division-by-zero #Omission #Single-line #Modified

#10

Link : https://github.com/OSGeo/PROJ/commit/9b561406e1ddcde02e868bef908e5cd5140745c7
Description: Azimuthal Equidistant spherical not as accurate as ellipsoidal

At src/projections/aeqd.cpp

@@ -151,7 +151,7 @@ oblcon:
                 return xy;
             }
             else
+                return aeqd_e_forward(lp, P);
-                xy.x = xy.y = 0.;
         else {
             xy.y = acos(xy.y);
             xy.y /= sin(xy.y);

Tags
#Logical-error #Single-line #Modified

#11

Link : https://github.com/OSGeo/PROJ/commit/17f2f7cf8bcaa5a4edc9e94d2bd6d8e633455c03
Description: Avoid division by zero

At src/projections/lcc.cpp

@@ -108,10 +108,6 @@ PJ *PROJECTION(lcc) {
         if (secant) { /* secant cone */
             sinphi = sin(Q->phi2);
             Q->n = log(m1 / pj_msfn(sinphi, cos(Q->phi2), P->es));
+            if (Q->n == 0) {
+                // Not quite, but es is very close to 1...
+                return pj_default_destructor(P, PJD_ERR_ECCENTRICITY_IS_ONE_OR_GREATER);
+            }
             Q->n /= log(ml1 / pj_tsfn(Q->phi2, sinphi, P->e));
         }
         Q->c = (Q->rho0 = m1 * pow(ml1, -Q->n) / Q->n);

Tags
#Division-by-zero #Omission #Multi-line #Added

#12

Link : https://github.com/OSGeo/PROJ/commit/20b1fac56fc23950790b2f46761b8308d455daa9
Description: Avoid division by zero

At src/projections/sterea.cpp

@@ -53,12 +53,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) {          /* Ellipsoidal, forward */
     sinc = sin(lp.phi);
     cosc = cos(lp.phi);
     cosl = cos(lp.lam);
+    const double denom = 1. + Q->sinc0 * sinc + Q->cosc0 * cosc * cosl;
+    if( denom == 0.0 ) {
+        proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION);
+        return proj_coord_error().xy;
+    }
+    k = P->k0 * Q->R2 / denom;
-    k = P->k0 * Q->R2 / (1. + Q->sinc0 * sinc + Q->cosc0 * cosc * cosl);
     xy.x = k * cosc * sin(lp.lam);
     xy.y = k * (Q->cosc0 * sinc - Q->sinc0 * cosc * cosl);
     return xy;

Tags
#Division-by-zero #Omission #Multi-line #Modified

#13

Link : https://github.com/OSGeo/PROJ/commit/44fc7dda9fc411f7c2f052c2271d563bc52f2518
Description: Detect invalid semi-major axis value

At src/ell_set.cpp

@@ -399,10 +399,7 @@ static int ellps_spherification (PJ *P) {
         break;
     }
+    if (P->a <= 0.) {
+        return proj_errno_set(P, PJD_ERR_MAJOR_AXIS_NOT_GIVEN);
+    }
     /* Clean up the ellipsoidal parameters to reflect the sphere */
     P->es = P->e = P->f = 0;
     P->rf = HUGE_VAL;

Tags
#Omission #Multi-line #Added

#14

Link : https://github.com/OSGeo/PROJ/commit/56bacd3dc9ecb650bbe509758f785e5c319aa004
Description: Fix to be able to identify EPSG:2154

At src/iso19111/factory.cpp

@@ -5642,7 +5642,7 @@ AuthorityFactory::createObjectsFromNameEx(
             sql += "AND deprecated = 1 ";
         }
         if (!approximateMatch) {
+            sql += "AND name = ? ";
-            sql += "AND name LIKE ? ";
             params.push_back(searchedNameWithoutDeprecated);
         }
         if (d->hasAuthorityRestriction()) {
@@ -5672,7 +5672,7 @@ AuthorityFactory::createObjectsFromNameEx(
             sql += "AND ov.deprecated = 1 ";
         }
         if (!approximateMatch) {
+            sql += "AND a.alt_name = ? ";
-            sql += "AND a.alt_name LIKE ? ";
             params.push_back(searchedNameWithoutDeprecated);
         }
         if (d->hasAuthorityRestriction()) {

Tags
#Invalid-format-string #Multi-line #Modified

#15

Link : https://github.com/OSGeo/PROJ/commit/93d8fccd51a704c4accd535743a963ad0ca5a274
Description: Accept leading white space

At src/iso19111/io.cpp

@@ -6132,12 +6132,7 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text,
                                            const DatabaseContextPtr &dbContext,
                                            bool usePROJ4InitRules,
                                            PJ_CONTEXT *ctx) {
+    std::size_t idxFirstCharNotSpace = text.find_first_not_of(" \t\r\n");
+    if (idxFirstCharNotSpace > 0 && idxFirstCharNotSpace != std::string::npos) {
+        return createFromUserInput(text.substr(idxFirstCharNotSpace), dbContext,
+                                   usePROJ4InitRules, ctx);
+    }
     if (!text.empty() && text[0] == '{') {
         json j;
         try {

Tags
#Omission #Multi-line #Added

#16

Link : https://github.com/OSGeo/PROJ/commit/97de772e16281fad460a1469c34cd37ff42bcefb
Description: Avoid division by zero

At src/projections/lcc.cpp

@@ -125,9 +125,6 @@ PJ *PROJECTION(lcc) {
         Q->rho0 *= (fabs(fabs(P->phi0) - M_HALFPI) < EPS10) ? 0. :
             pow(pj_tsfn(P->phi0, sin(P->phi0), P->e), Q->n);
     } else {
+        if( fabs(cosphi) < EPS10 || fabs(cos(Q->phi2)) < EPS10 ) {
+            return pj_default_destructor(P, PJD_ERR_LAT_1_OR_2_ZERO_OR_90);
+        }
         if (secant)
             Q->n = log(cosphi / cos(Q->phi2)) /
                log(tan(M_FORTPI + .5 * Q->phi2) /

Tags
#Division-by-zero #Omission #Multi-line #Added

#17

Link : https://github.com/OSGeo/PROJ/commit/318dab0d074a7bfd9d0724e674777aa10422d4e6
Description: Validate lat_1 and lat_2 to avoid divison by zero

At src/projections/omerc.cpp

@@ -154,8 +154,6 @@ PJ *PROJECTION(omerc) {
         phi1 = pj_param(P->ctx, P->params, "rlat_1").f;
         lam2 = pj_param(P->ctx, P->params, "rlon_2").f;
         phi2 = pj_param(P->ctx, P->params, "rlat_2").f;
+        if (fabs(phi1) > M_HALFPI || fabs(phi2) > M_HALFPI)
+            return pj_default_destructor(P, PJD_ERR_LAT_LARGER_THAN_90);
         if (fabs(phi1 - phi2) <= TOL ||
             (con = fabs(phi1)) <= TOL ||
             fabs(con - M_HALFPI) <= TOL ||

Tags
#Division-by-zero #Omission #Multi-line #Added

#18

Link : https://github.com/OSGeo/PROJ/commit/0529b07f81d3c027e101c6e1eddb4685e957934d
Description: Avoid division by zero

At src/projections/tmerc.cpp

@@ -188,10 +188,6 @@ static PJ_LP approx_s_inv (PJ_XY xy, PJ *P) {
     double h, g;
     h = exp(xy.x / static_cast<struct pj_opaque_approx*>(P->opaque)->esp);
+    if( h == 0 ) {
+        proj_errno_set(P, PJD_ERR_INVALID_X_OR_Y);
+        return proj_coord_error().lp;
+    }
     g = .5 * (h - 1. / h);
     h = cos (P->phi0 + xy.y / static_cast<struct pj_opaque_approx*>(P->opaque)->esp);
     lp.phi = asin(sqrt((1. - h * h) / (1. + g * g)));

Tags
#Division-by-zero #Omission #Multi-line #Added

#19

Link : https://github.com/OSGeo/PROJ/commit/9350d9ee2ebbc4a68e2682a999cd08d91ea2c8b1
Description: Properly set coordinate time to HUGE_VAL when no value is passed to the function

At src/4D_api.cpp

@@ -362,7 +362,6 @@ size_t proj_trans_generic (
     PJ_COORD coord = {{0,0,0,0}};
     size_t i, nmin;
     double null_broadcast = 0;
+    double invalid_time = HUGE_VAL;
     if (nullptr==P)
         return 0;
@@ -380,7 +379,7 @@ size_t proj_trans_generic (
     if (0==nx) x = &null_broadcast;
     if (0==ny) y = &null_broadcast;
     if (0==nz) z = &null_broadcast;
+    if (0==nt) t = &invalid_time;
-    if (0==nt) t = &null_broadcast;
     /* nothing to do? */
     if (0==nx+ny+nz+nt)

Tags
#Logical-error #Multi-line #Modified

#20

Link : https://github.com/OSGeo/PROJ/commit/86530f3146ec091c26652e60067088dc3e067fae
Description: Fix wrong byte-swapping for NTv2 grids

At src/grids.cpp

@@ -1899,10 +1899,7 @@ std::unique_ptr<NTv2GridSet> NTv2GridSet::open(PJ_CONTEXT *ctx,
         if (must_swap) {
             // 6 double values: southLat, northLat, eastLon, westLon, resLat,
             // resLon
+            for (int i = 0; i < 6; i++) {
+                swap_words(header + OFFSET_SOUTH_LAT + 16 * i, sizeof(double),
+                           1);
+            }
-            swap_words(header + OFFSET_SOUTH_LAT, sizeof(double), 6);
             swap_words(header + OFFSET_GS_COUNT, sizeof(int), 1);
         }

Tags
#Logical-error #Multi-line #Modified

#21

Link : https://github.com/OSGeo/PROJ/commit/61166380276a0e99b980dfdc6b43ea4656846c08
Description: Error out if |lat_0|>90

At src/projections/laea.cpp

@@ -248,9 +248,6 @@ PJ *PROJECTION(laea) {
     P->destructor = destructor;
     t = fabs(P->phi0);
+    if (t > M_HALFPI + EPS10 ) {
+        return destructor(P, PJD_ERR_LAT_LARGER_THAN_90);
+    }
     if (fabs(t - M_HALFPI) < EPS10)
         Q->mode = P->phi0 < 0. ? S_POLE : N_POLE;
     else if (fabs(t) < EPS10)

Tags
#Invalid-condition #Omission #Multi-line #Added

#22

Link : https://github.com/OSGeo/PROJ/commit/ab19f0d7aec223b89537d07d5f5f3f2e1f5db822
Description: Avoid division by zero

At src/projections/aea.cpp

@@ -180,10 +180,6 @@ static PJ *setup(PJ *P) {
                 return destructor(P, 0);
             Q->n = (m1 * m1 - m2 * m2) / (ml2 - ml1);
+            if (Q->n == 0) {
+                // Not quite, but es is very close to 1...
+                return destructor(P, PJD_ERR_ECCENTRICITY_IS_ONE_OR_GREATER);
+            }
         }
         Q->ec = 1. - .5 * P->one_es * log((1. - P->e) /
             (1. + P->e)) / P->e;

Tags
#Division-by-zero #Omission #Multi-line #Added

#23

Link : https://github.com/OSGeo/PROJ/commit/adeca911c16bc783963ee98d075a75b70d46b110
Description: Fix access violation in proj_context_get_database_metadata

At src/iso19111/c_api.cpp

@@ -348,10 +348,6 @@ const char *proj_context_get_database_metadata(PJ_CONTEXT *ctx,
         // temporary variable must be used as getDBcontext() might create
         // ctx->cpp_context
         auto osVal(getDBcontext(ctx)->getMetadata(key));
+        if (osVal == nullptr) {
+            ctx->cpp_context->autoCloseDbIfNeeded();
+            return nullptr;
+        }
         ctx->cpp_context->lastDbMetadataItem_ = osVal;
         ctx->cpp_context->autoCloseDbIfNeeded();
         return ctx->cpp_context->lastDbMetadataItem_.c_str();

Tags
#Omission #Multi-line #Added

#24

Link : https://github.com/OSGeo/PROJ/commit/b30ed5cba50688cea9ac2af90855177f84efea5a
Description: Avoid floating point division by zero.

At src/projections/labrd.cpp

@@ -108,10 +108,7 @@ PJ *PROJECTION(labrd) {
         return pj_default_destructor (P, ENOMEM);
     P->opaque = Q;
+    if (P->phi0 == 0.) {
+        return pj_default_destructor(P, PJD_ERR_LAT_0_IS_ZERO);
+    }
     Az = pj_param(P->ctx, P->params, "razi").f;
     sinp = sin(P->phi0);
     t = 1. - P->es * sinp * sinp;

Tags
#Division-by-zero #Omission #Multi-line #Added

#25

Link : https://github.com/OSGeo/PROJ/commit/be83b7dd836a94ce7cba999716f8bff1c2effac0
Description: Fix SourceTargetCRSExtentUse::NONE mode

At src/iso19111/operation/coordinateoperationfactory.cpp

@@ -5346,12 +5346,6 @@ CoordinateOperationFactory::createOperations(
     metadata::ExtentPtr targetCRSExtent;
     auto l_resolvedTargetCRS =
         crs::CRS::getResolvedCRS(l_targetCRS, authFactory, targetCRSExtent);
+    if (context->getSourceAndTargetCRSExtentUse() ==
+        CoordinateOperationContext::SourceTargetCRSExtentUse::NONE) {
+        // Make sure *not* to use CRS extent if requested to ignore it
+        sourceCRSExtent.reset();
+        targetCRSExtent.reset();
+    }
     Private::Context contextPrivate(sourceCRSExtent, targetCRSExtent, context);
     if (context->getSourceAndTargetCRSExtentUse() ==

Tags
#Omission #Multi-line #Added

#26

Link : https://github.com/OSGeo/PROJ/commit/dedd2916926f1e7b0e9e774918faf6d1a7bcafbb
Description: Fix export of transformation to PROJ string in a particular situation

At src/iso19111/operation/transformation.cpp

@@ -2806,14 +2806,14 @@ void Transformation::_exportToPROJString(
                                   common::UnitOfMeasure::ARC_SECOND);
         auto sourceCRSGeog =
+            extractGeographicCRSIfGeographicCRSOrEquivalent(sourceCRS());
-            dynamic_cast<const crs::GeographicCRS *>(sourceCRS().get());
         if (!sourceCRSGeog) {
             throw io::FormattingException(
                 "Can apply Geographic 2D offsets only to GeographicCRS");
         }
         auto targetCRSGeog =
+            extractGeographicCRSIfGeographicCRSOrEquivalent(targetCRS());
-            dynamic_cast<const crs::GeographicCRS *>(targetCRS().get());
         if (!targetCRSGeog) {
             throw io::FormattingException(
                 "Can apply Geographic 2D offsets only to GeographicCRS");

Tags
#Etc #Multi-line #Modified

#27

Link : https://github.com/OSGeo/PROJ/commit/f4827e0a3b5c5b07ccf82fc6cd3334079e75e02c
Description: Make sure that importing a Projected 3D CRS from WKT

At src/iso19111/io.cpp

@@ -3839,12 +3839,7 @@ WKTParser::Private::buildProjectedCRS(const WKTNodeNNPtr &node) {
         ThrowNotExpectedCSType("Cartesian");
     }
+    if (cartesianCS->axisList().size() == 3 &&
+        baseGeodCRS->coordinateSystem()->axisList().size() == 2) {
+        baseGeodCRS = NN_NO_CHECK(util::nn_dynamic_pointer_cast<GeodeticCRS>(
+            baseGeodCRS->promoteTo3D(std::string(), dbContext_)));
+    }
     addExtensionProj4ToProp(nodeP, props);
     return ProjectedCRS::create(props, baseGeodCRS, conversion,

Tags
#Omission #Multi-line #Added

#28

Link : https://github.com/OSGeo/PROJ/commit/b38d0143a65fff72635b95a61ed6c4c41802889e
Description: Polar stereographic at pole: make it return (0,0)

At src/projections/stere.cpp

@@ -86,10 +86,7 @@ static PJ_XY stere_e_forward (PJ_LP lp, PJ *P) {          /* Ellipsoidal, forwar
         sinphi = -sinphi;
         /*-fallthrough*/
     case N_POLE:
+        if( fabs(lp.phi - M_HALFPI) < 1e-15 )
+            xy.x = 0;
+        else
+            xy.x = Q->akm1 * pj_tsfn (lp.phi, sinphi, P->e);
-        xy.x = Q->akm1 * pj_tsfn (lp.phi, sinphi, P->e);
         xy.y = - xy.x * coslam;
         break;
     }

Tags
#Invalid-condition #Multi-line #Modified

Clone this wiki locally