<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Bogdan Alexandru Militaru</title>
    <description>The latest articles on Forem by Bogdan Alexandru Militaru (@boobo94).</description>
    <link>https://forem.com/boobo94</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F186168%2F80a4d978-9d43-41a6-afb0-15c6dea98b6c.jpeg</url>
      <title>Forem: Bogdan Alexandru Militaru</title>
      <link>https://forem.com/boobo94</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/boobo94"/>
    <language>en</language>
    <item>
      <title>How to find the size of a table in SQL?</title>
      <dc:creator>Bogdan Alexandru Militaru</dc:creator>
      <pubDate>Tue, 08 Aug 2023 09:09:09 +0000</pubDate>
      <link>https://forem.com/boobo94/how-to-find-the-size-of-a-table-in-sql-4ic8</link>
      <guid>https://forem.com/boobo94/how-to-find-the-size-of-a-table-in-sql-4ic8</guid>
      <description>&lt;p&gt;As a SQL developer or database administrator, it is essential to have a good understanding of the size of your database tables. Knowing the size of a table can help you optimize your database performance, plan for storage requirements, and troubleshoot issues related to database performance. In this blog post, we will guide you through the process of finding the size of a table in SQL.&lt;/p&gt;

&lt;p&gt;Here’s how you can see the size table sizes for &lt;strong&gt;public&lt;/strong&gt; schema&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT
    table_name,
    pg_size_pretty(pg_relation_size(quote_ident(table_name))),
    pg_relation_size(quote_ident(table_name))
FROM
    information_schema.tables
WHERE
    table_schema = 'public'
ORDER BY
    3 DESC;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See sizes of tables of all schemas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT
    schema_name,
    relname,
    pg_size_pretty(table_size) AS size,
    table_size
FROM (
    SELECT
        pg_catalog.pg_namespace.nspname AS schema_name,
        relname,
        pg_relation_size(pg_catalog.pg_class.oid) AS table_size
    FROM
        pg_catalog.pg_class
        JOIN pg_catalog.pg_namespace ON relnamespace = pg_catalog.pg_namespace.oid) t
WHERE
    schema_name NOT LIKE 'pg_%'
ORDER BY
    table_size DESC;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>sql</category>
      <category>postgres</category>
      <category>database</category>
    </item>
    <item>
      <title>MongoDB Query date by _id field</title>
      <dc:creator>Bogdan Alexandru Militaru</dc:creator>
      <pubDate>Tue, 08 Aug 2023 09:09:09 +0000</pubDate>
      <link>https://forem.com/boobo94/mongodb-query-date-by-id-field-1hjl</link>
      <guid>https://forem.com/boobo94/mongodb-query-date-by-id-field-1hjl</guid>
      <description>&lt;p&gt;In order to make a query based on _id, comparing dates, you can use &lt;code&gt;$convert&lt;/code&gt; function to extract the date from &lt;code&gt;ObjectId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$convert: { input: "$_id", to: "date" } 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To query dates comparing between start and end time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.collection.find({
  "$expr":{
    "$and":[
      {"$gte":[{"$convert":{"input":"$_id","to":"date"}}, ISODate("2023-08-01T00:00:00.000Z")]},
      {"$lte":[{"$convert":{"input":"$_id","to":"date"}}, ISODate("2023-08-02T11:59:59.999Z")]}
    ]
  }
})

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shorthand version using &lt;code&gt;$toDate&lt;/code&gt; function helps you achieve the same result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.collection.find({
  "$expr":{
    "$and":[
      {"$gte":[{"$toDate":"$_id"}, ISODate("2023-08-01T00:00:00.000Z")]},
      {"$lte":[{"$toDate":"$_id"},ISODate("2023-08-02T11:59:59.999Z")]}
    ]
  }
})

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://stackoverflow.com/a/51165575/4471897"&gt;Source&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image by &lt;a href="https://pixabay.com/users/vikashkr50-35301037/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=8167272"&gt;Vikash Kr Singh&lt;/a&gt; from &lt;a href="https://pixabay.com//?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=8167272"&gt;Pixabay&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>database</category>
    </item>
    <item>
      <title>Netopiajs library for nodejs</title>
      <dc:creator>Bogdan Alexandru Militaru</dc:creator>
      <pubDate>Thu, 06 Apr 2023 09:09:09 +0000</pubDate>
      <link>https://forem.com/boobo94/netopiajs-library-for-nodejs-4el0</link>
      <guid>https://forem.com/boobo94/netopiajs-library-for-nodejs-4el0</guid>
      <description>&lt;p&gt;Check the nodejs library module I wrote for the integration with Netopia Payments, an European Payment provider.&lt;/p&gt;

&lt;p&gt;You can find the repository on Github &lt;a href="https://github.com/boobo94/netopia-js"&gt;boobo94/netopia-js&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Initial setup
&lt;/h1&gt;

&lt;p&gt;Copy the package to modules/netopia and install dependencies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  npm i ./modules/netopia-js

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set the environment variables&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# or something else, for example local, staging
ENVIRONMENT=production
# your fallback url, after the payment is made the user will be redirected to this screen
NETOPIA_BASE_URL=http://localhost
 # your webhook url where Netopia sends confirmation messages
NETOPIA_WEBHOOK_URL=http://localhost:8000/api/v1/webhooks/netopia
# the seller account id found in Admin &amp;gt; Seller Accounts &amp;gt; in the table press edit near the seller account &amp;gt;
# &amp;gt; Security Settings (4th tab) &amp;gt; is under Seller account id having format XXXX-XXXX-XXXX-XXXX-XXXX
NETOPIA_SELLER_ID=123456789
# under seller account there is Digital Certificate Netopia Payments (the public key)
# download the certificate then copy an paste the certificate inside quotes
# for those who use dotenv library, you need at least v15
NETOPIA_PUBLIC_KEY="change_me"
# under the public key there is Seller Account Certificate (the private key)
# download the certificate then copy an paste the certificate inside quotes
NETOPIA_PRIVATE_KEY="change_me"
# If your implementation requires an user go to Admin &amp;gt; Users &amp;gt; Create a new one (you should talk with Netopia about your needs)
# but here you find the username and the password that you picked
NETOPIA_ACCOUNT_USERNAME=change_me
NETOPIA_ACCOUNT_PASSWORD=change_me
NETOPIA_CURRENCY=RON

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the settings of account &lt;a href="https://admin.mobilpay.ro/ro/login"&gt;login into Netopia&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Usage
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Import
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Netopia from '../../../modules/netopia'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  IPN using Express
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Netopia from '../../../modules/netopia'
import { urlencoded } from 'express';

// ...

.post(
  '/api/v1/webhooks/netopia',
  urlencoded({ extended: false }),
  async (req, res) =&amp;gt; {
    const ipnResponse = await Netopia.parseIPNResponse(req.body)

    // action = status only if the associated error code is zero
    if (ipnResponse.success) {
      switch (ipnResponse.decoded.order.mobilpay.action) {
        // every action has an error code and an error message
        case 'confirmed': {
          // confirmed actions means that the payment was successful and
          // the money was transferred from custtomers account to the merchant account and you can deliver the goods

          break
        }
        case 'confirmed_pending': {
          // confirmed pending action means that the transaction pending for antifraud validation
          // you should not deliver the goods to the customer until a confirmed or canceled action is received

          break
        }
        case 'paid_pending': {
          // confirmed paid pending action means that the transaction pending validation
          // you should not deliver the goods to the customer until a confirmed or canceled action is received

          break
        }
        case 'paid': {
          // paid action means that the transaction pre-authorized
          // you should not deliver the goods to the customer until a confirmed or canceled action is received

          break
        }
        case 'canceled': {
          // canceled action means that the payment was canceled
          // you should not deliver the goods to the customer

          break
        }
        case 'credit': {
          // credit action means that the payment was refund

          break
        }
        default:
          throw Error('action parameter is not supported')
      }
    } else {
      console.error('error ipn', ipnResponse.decoded.order.mobilpay.error)
    }

    return res.status(200).send(ipnResponse.response)
  }
)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(#ipn-response)&lt;/p&gt;

&lt;h3&gt;
  
  
  IPN response example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "decoded": {
    "order": {
      "$": {
        "id": "l1or6vvj25sw9uxlae0g",
        "timestamp": "1649321087455",
        "type": "card"
      },
      "signature": "87Y7-EA62-UDK4-8EW2-4PQE",
      "url": {
        "return": "http://localhost:8000",
        "confirm": "http://localhost:8000/api/v1/webhooks/netopia"
      },
      "invoice": {
        "$": {
          "currency": "RON",
          "amount": "1"
        },
        "details": "test plata",
        "contact_info": {
          "billing": {
            "$": {
              "type": "person"
            },
            "first_name": "John",
            "last_name": "Doe",
            "address": "my street",
            "email": "contact@cmevo.com",
            "mobile_phone": "071034782"
          },
          "shipping": {
            "$": {
              "type": "person"
            },
            "first_name": "John",
            "last_name": "Doe",
            "address": "my street",
            "email": "contact@cmevo.com",
            "mobile_phone": "071034782"
          }
        }
      },
      "mobilpay": {
        "$": {
          "timestamp": "20220407115352",
          "crc": "536ef5f26486b6071161bc0ad4a2263b"
        },
        "action": "paid",
        "customer": {
          "$": {
            "type": "person"
          },
          "first_name": "John",
          "last_name": "Doe",
          "address": "my+street",
          "email": "contact%40cmevo.com",
          "mobile_phone": "071034782"
        },
        "purchase": "1334168",
        "original_amount": "1.00",
        "processed_amount": "1.00",
        "current_payment_count": "1",
        "pan_masked": "9 **** 5098",
        "rrn": "9991649",
        "payment_instrument_id": "41679",
        "token_id": "MTUyOTI0OsFnpdPjsR3KzdyA1KKC5BHlVdHDrqbizsPYR39SlVuRrVbR6sBfr0tQPx5YxImCEIrIPShZ8nKcdsw/TFQR86c=",
        "token_expiration_date": "2024-04-07 11:53:52",
        "error": {
          "_": "Tranzactie aprobata",
          "$": {
            "code": "0"
          }
        }
      }
    }
  },
  "response": "&amp;lt;?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?&amp;gt;\n&amp;lt;crc&amp;gt;success&amp;lt;/crc&amp;gt;",
  "success": true
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use IPN webhook from localhost
&lt;/h3&gt;

&lt;p&gt;In order to connect Netopia with your local API, you need to expose your server running locally to the internat. To do that you can simply use SSH tunneling. &lt;a href="https://dev.to/boobo94/connect-localhost-to-the-internet-1l42-temp-slug-99230"&gt;Connect localhost to the internet&lt;/a&gt; is an article which describes how to do that.&lt;/p&gt;

&lt;p&gt;If you’re hurry use localhost.run, &lt;a href="https://localhost.run/docs/"&gt;documentation here&lt;/a&gt; by simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -R 80:localhost:8000 nokey@localhost.run

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pay attention which port your server is running, in my example the server is running on port 8000. Just change with your port and hit the ENTER button to get something like this in the console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;de3a810e7aa2b9.lhrtunnel.link tunneled with tls termination, https://de3a810e7aa2b9.lhrtunnel.link

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just copy that base url and set the environment variable &lt;code&gt;NETOPIA_WEBHOOK_URL&lt;/code&gt;, now it should looks like &lt;code&gt;NETOPIA_WEBHOOK_URL=https://de3a810e7aa2b9.lhrtunnel.link/api/v1/webhooks/netopia&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;NOTE!!!&lt;/p&gt;

&lt;p&gt;Very important to know, after few minutes/hour the ssh tunnel url is changed, you need to copy paste the url again.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to create a simple payment or add the card in Netopia
&lt;/h2&gt;

&lt;p&gt;To create simple payments where the user insert the card. This method returns an html form that submits automatically, simulating the redirect to Netopia’s payment page, where the customer has to fill the card details.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const response = await Netopia.createSimplePayment(
  "10", // the price in RON, in string format
  {
    type: 'person', // optional, options: 'person' or 'company', default = 'person'
    firstName: 'John', // required
    lastName: 'Doe', // required
    address: "my street", // required
    email: "contact@cmevo.com", // required
    phone: "071034782", // required
    description: "the product or service description", // required
  },
  {
    // pass custom params that will be returned to you on IPN later
    "userId": 1,
    "internalPaymentId": "3sad3",
    "foo": "bar"
  }
);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method can be used to register a card using the alias &lt;code&gt;registerCard(amount, billing, params)&lt;/code&gt;. Is the same function. Create a symbolic transaction of 1 RON. If your seller account has an user which is activated for token usage, you’ll receive on IPN a token. Save it for further payments. &lt;strong&gt;Very important&lt;/strong&gt; , if your account is set with pre-authorization, when the IPN response confirm the card addition you should capture that transaction of 1 RON.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await Netopia.capture(ipnResponse.decoded.order.$.id,1)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Save the token for further payments
&lt;/h3&gt;

&lt;p&gt;The token can be saved from the IPN response from path &lt;code&gt;decoded.order.mobilpay.token_id&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create payment based on tokens or authorize a payment
&lt;/h2&gt;

&lt;p&gt;If your seller account doesn’t have pre-authorization active, by default all payments are captured instantly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const response = await Netopia.captureWithoutAuthorization(
  "10", // the price in RON, in string format
  "the token stored previously",
  {
    type: 'person', // optional, options: 'person' or 'company', default = 'person'
    firstName: 'John', // required
    lastName: 'Doe', // required
    address: "my street", // required
    email: "contact@cmevo.com", // required
    phone: "071034782", // required
    description: "the product or service description", // required
    country: "Romania", // optional, default = 'Romania'
    county: "Bucharest", // optional, default = 'Bucharest'
    city: "Bucharest", // optional, default = 'Bucharest'
    postalCode: "123456", // optional, default = '123456'
  },
  {
    // pass custom params that will be returned to you on IPN later
    "userId": 1,
    "internalPaymentId": "3sad3",
    "foo": "bar"
  });

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I created an alias of this function for pre-authorization (if your seller account supports), only to be easier for you with the name. Instead of &lt;code&gt;captureWithoutAuthorization(...)&lt;/code&gt; use &lt;code&gt;authorize(...)&lt;/code&gt;. Pre-authorization means the money are locked in the customer’s account, but are not transferred to your account until you don’t execute the capture method. If you use have pre-authorization, save for later the order id created from &lt;code&gt;response.order.id&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Capture a pre-authorized payment
&lt;/h2&gt;

&lt;p&gt;Execute this function to transfer the money from customer to your account.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const response = await Netopia.capture(
  "previous order id pre-authorized", // response.order.id, where response = Netopia.authorize(...), in string format
  "5", // the price in RON, in string format
  )

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can capture the pre-authorize value or a smaller amount and the difference will remain in the customer. Is not a refund, because the money didn’t leave his account yet. You only capture partially. You cannot capture more than the pre-authorized value.&lt;/p&gt;

&lt;p&gt;Netopia has a limitation when you have pre-authorization active on you seller account and you need to do both payments with pre-authorizations and instant capture. The are unable to do it using a single customer account. I implemented this functionality using an workaround by doing authorize and capture. Use function &lt;code&gt;authorizeAndCapture(amount, token, billing, params)&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cancel pre-authorized payment
&lt;/h2&gt;

&lt;p&gt;If you decide at any moment to cancel a payment, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const response = await Netopia.cancel(
  "previous order id pre-authorized", // response.order.id, where response = Netopia.authorize(...), in string format
)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Refund payment
&lt;/h2&gt;

&lt;p&gt;If you decide to refund a payment&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const response = await Netopia.refund(
  "previous order id pre-authorized", // response.order.id, where response = Netopia.authorize(...), in string format
  "5", // the price in RON, in string format
  )

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The amount you refund can be different that the value you captured. For example if you captured 5 lei, you can refund only 2, maximum 5.&lt;/p&gt;

&lt;h2&gt;
  
  
  Delete card by removing the token
&lt;/h2&gt;

&lt;p&gt;To delete a card and make the token inactive for further payments do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const response = await Netopia.deleteCard(
  "the token stored previously",
)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to check the SOAP documentation
&lt;/h2&gt;

&lt;p&gt;Install Wizdler browser extension and check &lt;a href="https://secure.mobilpay.ro/api/payment2/?wsdl"&gt;https://secure.mobilpay.ro/api/payment2/?wsdl&lt;/a&gt; There you’ll find all methods available.&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing
&lt;/h1&gt;

&lt;p&gt;You can find a &lt;a href="https://github.com/mobilpay/Node.js"&gt;simple payment example&lt;/a&gt; and &lt;a href="https://github.com/mobilpay/"&gt;Netopia’s Github&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cards
&lt;/h2&gt;

&lt;p&gt;9900004810225098 - card accepted, CVV = 111&lt;/p&gt;

&lt;p&gt;9900541631437790 - card expired&lt;/p&gt;

&lt;p&gt;9900518572831942 - insufficinet funds&lt;/p&gt;

&lt;p&gt;9900827979991500 - CVV2/CCV incorect&lt;/p&gt;

&lt;p&gt;9900576270414197 - transaction declined&lt;/p&gt;

&lt;p&gt;9900334791085173 - high risk card (for example is a stolen card)&lt;/p&gt;

&lt;p&gt;9900130597497640 - error from the bank (connection with the bank cannot be established)&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>software</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Managerflota idea validation</title>
      <dc:creator>Bogdan Alexandru Militaru</dc:creator>
      <pubDate>Sat, 25 Mar 2023 09:09:09 +0000</pubDate>
      <link>https://forem.com/boobo94/managerflota-idea-validation-37j3</link>
      <guid>https://forem.com/boobo94/managerflota-idea-validation-37j3</guid>
      <description>&lt;p&gt;Managerflota.ro idea validation thread&lt;/p&gt;

&lt;p&gt;Manage the car hailing business in one web app.&lt;/p&gt;

&lt;p&gt;Features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;instant payment reports&lt;/li&gt;
&lt;li&gt;employee management&lt;/li&gt;
&lt;li&gt;financial management&lt;/li&gt;
&lt;li&gt;car management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simple, clean and safe!&lt;/p&gt;

&lt;p&gt;Recently I figure out that the car hailing fleet managers in Romania spend a lot of time with the administration part of their business.&lt;/p&gt;

&lt;p&gt;The idea: create a simple app that manage their money, expensive, presenting weekly payment reports for each individual driver First thing first I need to validate this idea.&lt;/p&gt;

&lt;p&gt;So is very important to make it official and looks very professional. Create a simple landing page which describes the app. After I talk with the potential client, I can share with him the link.&lt;/p&gt;

&lt;p&gt;Look here (yes it’s in Romanian only)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://managerflota.ro"&gt;Manager Flotă pentru Transport Alternativ&lt;/a&gt;​ - Cmevo Digital Singura platformă web de administrare a flotelor de transport alternativ. Poți gestiona șoferii, plățile săptămânale, contracte de închiriere mașini și &lt;a href="https://cmevo.com/ro/manager-flota-pentru-transport-alternativ/"&gt;https://cmevo.com/ro/manager-flota-pentru-transport-alternativ/&lt;/a&gt; For easier understanding of the platform, created some mock-ups using diagrams.net&lt;/p&gt;

&lt;p&gt;The flow of the app is complete. This helped me to understand what is the initial proposal and get some initial screens of the app (presented in the landing page as well) &lt;a href="http://diagrams.net"&gt;http://diagrams.net&lt;/a&gt; Next I need to contact potential customers.&lt;/p&gt;

&lt;p&gt;Where can I find them?&lt;/p&gt;

&lt;p&gt;Easy.. let’s search and see.&lt;/p&gt;

&lt;p&gt;Options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ads websites who post job offers&lt;/li&gt;
&lt;li&gt;An Romanian authority who manage and regulate this industry&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;First option seems very hard to follow so I decided to go with second. I searched if there’s any place where I can find all the authorized fleets, and surprise .. they exists and is even public information. One issue, I need the contact info of each fleet.&lt;/p&gt;

&lt;p&gt;There are many pages with tables with name of the company and authorization number.&lt;/p&gt;

&lt;p&gt;If you click on the row of the table, a new page is opened and there are many info like: phone number, company name, number of drivers But the public info cannot be downloaded.&lt;/p&gt;

&lt;p&gt;I can do manual work, and yes I don’t do it, because I’m an engineer and I want an automated way to handle it.&lt;/p&gt;

&lt;p&gt;So I used webscraper .io, spend 1-2h to figure out how to figure out how to configure it with the website, but I succeed. Now I have all the details about companies. Open the spreadsheet, sort descending by number of drivers and let’s go!&lt;/p&gt;

&lt;p&gt;Prepared the message that will be sent to each fleet. I don’t want to call each one because is very time consuming, sms is not an option. But people use WhatsApp a lot here, so guess what I did?!&lt;/p&gt;

&lt;p&gt;Use the api.whatsapp .com?phone=the-number-here&amp;amp;mesaage=your-message-url-encoded Place the message in spreadsheet and use a concatenation formula between previous url and message&lt;/p&gt;

&lt;p&gt;repeat formula for all lines in the table and that’s all..&lt;/p&gt;

&lt;p&gt;we have a full prefilled list of messages All I have to do is to click on each link and then the WhatsApp will automatically open&lt;/p&gt;

&lt;p&gt;I just have to press the “send” button&lt;/p&gt;

&lt;p&gt;WIP 🚧 How I organized to send messages.&lt;/p&gt;

&lt;p&gt;Create the excel, put all the api messages in trellis checklist.&lt;/p&gt;

&lt;p&gt;From phone, with the first click I open the WhatsApp, the message is already prefilled so I only need to send the message. The third click complete checkbox in trellis list. Sent 14 WhatsApp messages to fleet managers today, Just to test.&lt;/p&gt;

&lt;p&gt;Only 3 were interested to quick reply at 3 questions.&lt;/p&gt;

&lt;p&gt;Only 2 replied as interested. I had a phone call with one of them who provided a lot of very useful informations.&lt;/p&gt;

&lt;p&gt;They already use an excel template and was trying to find someone and build a custom solution.&lt;/p&gt;

&lt;p&gt;This was very helpful to hear. I don’t want to hear “I have a problem, didn’t tried a solutions yet This first batch was only to see how they respond to the idea and how interact with my message.&lt;/p&gt;

&lt;p&gt;Next I’ll sent more messages&lt;/p&gt;

&lt;p&gt;2 out of 14 means 14% interest, which is satisfying&lt;/p&gt;

&lt;p&gt;This week I have to contact most of them and next one decide if the dev starts or drop the idea. New day, new updates&lt;/p&gt;

&lt;p&gt;Today I contacted more fleet managers and it seems a promising app.&lt;/p&gt;

&lt;p&gt;Here’s a big pain, many of them don’t want to go to work each Monday, because that’s the day when they have to do manual work and prepare the payments for their drivers. This means my app is exactly what they need.&lt;/p&gt;

&lt;p&gt;The interest percentage dropped to 13, but I’m still satisfied. There’s no market here so they don’t have a comparative solution.&lt;/p&gt;

&lt;p&gt;I’m pretty sure more will want after they see a real demo. I found some interesting perspective and ideas shared.&lt;/p&gt;

&lt;p&gt;Some of them already tried to develop apps for internal use, but without full support for all requirements. This means a proper validation to me. But I continue to ask them.&lt;/p&gt;

&lt;p&gt;I have 160 more to ask, because is a validation and a presale round as well.&lt;/p&gt;

&lt;p&gt;I want to find at least 20 customers at least. The market share is around 6900 companies. But only 200 have a minimum of 20 employees (drivers). And they are the relevant audience. I had even a partnership proposal.&lt;/p&gt;

&lt;p&gt;A big company tried to create a similar app, but only for internal use.&lt;/p&gt;

&lt;p&gt;They didn’t completed with all the necessary features and proposed me to work together and do this app. Currently we have an open proposal, but probably is better to wait until I talk with more potential customers.&lt;/p&gt;

&lt;p&gt;This company was very control freaked, tried a similar partnership, and block it because the other side wanted to have full ownership. Partners are good, but I have already most of the features on the table, I have all the contacts, they don’t offer anything too much.&lt;/p&gt;

&lt;p&gt;They want only to use the app and build it around their own requirements. I contacted fleet managers to validate my idea&lt;/p&gt;

&lt;p&gt;• more than 100 contacted • 9 were interested to buy • 4 wants to try a demo • 7 unfinished discussion • 5 not interested at all • 40 seen&lt;/p&gt;

&lt;p&gt;I have 70 more to contact. They hate Mondays, because they have to do all the maths.&lt;/p&gt;

&lt;p&gt;It sounds like a good idea after all and probably many will come later, after the app is released.&lt;/p&gt;

&lt;p&gt;One came today to ask me if the platform is available. So probably they talk between themselves. Today I had a look over the weekly payment reports, csv export, of car-hailing platforms: Uber, Bolt, Splash. I need to figure out how much time should be invested to aggregate all the data. Uber seems pretty messy and error-prone. Bolt and Splash are ok for the moment. Each driver can have accounts on multiple platforms and their weekly activity has to be aggregated in one place (the manager flota app that I want to build). The only unique identifier found is the name. Is not the best option, because I already know that existing fleets have more drivers with the same name.&lt;/p&gt;

&lt;p&gt;Not all carhailing platforms offer the phone number in their exports, so this was a better option. Is pretty insane that some people are so happy to share info with you. And spent time explaining what problems they have, how they can be solved, and many more. Even one of them shared with me their Excel, to present how they automated the calculus with Excel, the structure, and all the needed info. Another great discovery was that a few of them had the idea of building this app, for internal use or exactly the same product I want to build.&lt;/p&gt;

&lt;p&gt;Is this proper validation?&lt;/p&gt;

</description>
      <category>startup</category>
      <category>ridesharing</category>
      <category>management</category>
      <category>saas</category>
    </item>
    <item>
      <title>Generate hexagons in JS based on center coordinates and radius</title>
      <dc:creator>Bogdan Alexandru Militaru</dc:creator>
      <pubDate>Fri, 17 Mar 2023 09:09:09 +0000</pubDate>
      <link>https://forem.com/boobo94/generate-hexagons-in-js-based-on-center-coordinates-and-radius-18hg</link>
      <guid>https://forem.com/boobo94/generate-hexagons-in-js-based-on-center-coordinates-and-radius-18hg</guid>
      <description>&lt;p&gt;How to generate hexagons in javascript based on the center point coordinates and radius length&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function drawHexagon (centerPointLatitude, centerPointLongitude, radiusLength) {
  const radius = radiusLength / 6371

  const angle = 2 * Math.PI / 6 // 2PI (360 degree) divded by 6 points of the hexagon shape

  const hexagon = []
  for (var i = 0; i &amp;lt; 6; i++) {
    const longitude = centerPointLongitude + (radius * Math.cos(angle * i))
    const latitude = centerPointLatitude + (radius * Math.sin(angle * i))

    hexagon.push([longitude, latitude])
  }

  // close the polygon adding the initial point
  hexagon.push(hexagon[0])

  return hexagon
}

drawHexagon(44.4268, 26.1024, 10)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Image credits &lt;a href="https://pixabay.com/images/id-6406639/"&gt;Pixabay&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Get your Jenkins Passwords from secrets</title>
      <dc:creator>Bogdan Alexandru Militaru</dc:creator>
      <pubDate>Wed, 14 Sep 2022 09:09:09 +0000</pubDate>
      <link>https://forem.com/boobo94/get-your-jenkins-passwords-from-secrets-4j0i</link>
      <guid>https://forem.com/boobo94/get-your-jenkins-passwords-from-secrets-4j0i</guid>
      <description>&lt;p&gt;Demo&lt;/p&gt;

&lt;p&gt;Check SEO meta: &lt;a href="https://metadescriptiontool.com/"&gt;https://metadescriptiontool.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First of all, if you have access to your Jenkins server the credentials are stored at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vi /var/lib/jenkins/credentials.xml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order tot get your credentials go to &lt;a href="http://YOUR%5C_IP:8080/script"&gt;http://YOUR\_IP:8080/script&lt;/a&gt; and copy and paste the content below the hit RUN.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;com.cloudbees.plugins.credentials.SystemCredentialsProvider.getInstance().getCredentials().forEach{
  it.properties.each { prop, val -&amp;gt;
    if (prop == "secretBytes") {
      println(prop + "=&amp;gt;\n" + new String(com.cloudbees.plugins.credentials.SecretBytes.fromString("${val}").getPlainData()) + "\n")
    } else {
      println(prop + ' = "' + val + '"')
    }
  }
  println("-----------------------")
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Source: &lt;a href="https://devops.stackexchange.com/questions/2191/how-to-decrypt-jenkins-passwords-from-credentials-xml/8692#8692?newreg=9197ac19da1b457fb643798bcfa94e05"&gt;https://devops.stackexchange.com/questions/2191/how-to-decrypt-jenkins-passwords-from-credentials-xml/8692#8692?newreg=9197ac19da1b457fb643798bcfa94e05&lt;/a&gt;&lt;/p&gt;

</description>
      <category>jenkins</category>
      <category>devops</category>
      <category>credentials</category>
    </item>
    <item>
      <title>Linode Object Storage usage in NodeJS</title>
      <dc:creator>Bogdan Alexandru Militaru</dc:creator>
      <pubDate>Mon, 15 Nov 2021 09:09:09 +0000</pubDate>
      <link>https://forem.com/boobo94/linode-object-storage-usage-in-nodejs-24bk</link>
      <guid>https://forem.com/boobo94/linode-object-storage-usage-in-nodejs-24bk</guid>
      <description>&lt;p&gt;Simple use case of Linode Object storage in NodeJS with AWS-SDK for S3. Learn how to handle Linode Objects in plain Javascript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Credentials } from 'aws-sdk';
import S3 from 'aws-sdk/clients/s3';

const s3Client = new S3({
  region: process.env.LINODE_OBJECT_STORAGE_REGION,
  endpoint: process.env.LINODE_OBJECT_STORAGE_ENDPOINT,
  sslEnabled: true,
  s3ForcePathStyle: false,
  credentials: new Credentials({
    accessKeyId: process.env.LINODE_OBJECT_STORAGE_ACCESS_KEY_ID,
    secretAccessKey: process.env.LINODE_OBJECT_STORAGE_SECRET_ACCESS_KEY,
  }),
});

export async function uploadFileToObjectStorage(base64Data, path, fileName, fileType, extension) {
  const params = {
    Bucket: process.env.LINODE_OBJECT_BUCKET,
    Key: `${path}/${fileName}`,
    Body: base64Data,
    ACL: 'public-read',
    ContentEncoding: 'base64',
    ContentType: `${fileType}/${extension}`,
  };

  // see: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#upload-property
  const { Location } = await s3Client.upload(params).promise();
  return Location;
}

export async function deleteFileFromObjectStorage(url) {
  const Key = url.split(`${process.env.LINODE_OBJECT_STORAGE_ENDPOINT}/`)[1];
  const params = {
    Bucket: process.env.LINODE_OBJECT_BUCKET,
    Key,
  };

  // see: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#deleteObject-property
  // eslint-disable-next-line consistent-return
  return s3Client.deleteObject(params).promise();
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>node</category>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Hosting providers - free &amp; paid</title>
      <dc:creator>Bogdan Alexandru Militaru</dc:creator>
      <pubDate>Mon, 01 Nov 2021 09:09:09 +0000</pubDate>
      <link>https://forem.com/boobo94/hosting-providers-free-paid-2jp2</link>
      <guid>https://forem.com/boobo94/hosting-providers-free-paid-2jp2</guid>
      <description>&lt;h2&gt;
  
  
  Freemium Resources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://heroku.com"&gt;Heroku&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vercel.com"&gt;Vercel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://firebase.com"&gt;Firebase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://surge.sh"&gt;Surge&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://render.com"&gt;Render&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hostman.com"&gt;Hostman&lt;/a&gt; - free for frontend always, pay only for backend apps.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://glitch.com"&gt;Glitch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fly.io"&gt;Fly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fleek.co"&gt;Fleek&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://begin.com"&gt;Begin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stormkit.io"&gt;Stormkit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://deta.sh"&gt;Deta&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://commons.host"&gt;Commonshot&lt;/a&gt; -  Static web hosting and CDN.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://heliohost.org"&gt;Heliohost&lt;/a&gt; - PHP, Ruby on rails, perl, django, java(jsp)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fast.io"&gt;Fast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kintohub.com"&gt;kintohub&lt;/a&gt; - supports the static site, web app, backend apps.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://torus.host"&gt;Torus.host&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://bip.sh"&gt;Bip&lt;/a&gt; - Static web hosting provider&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pages.cloudflare.com"&gt;Cloudflare pages&lt;/a&gt; - Static web hosting provider&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://guides.github.com/features/pages/"&gt;GitHub Pages&lt;/a&gt; - Static web hosting provider&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.gitlab.com/ee/user/project/pages/"&gt;GitLab Pages&lt;/a&gt; - Static web hosting provider&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Paid providers
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/"&gt;AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linode.com/"&gt;Linode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://console.cloud.google.com"&gt;Google Cloud Platform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.digitalocean.com"&gt;Digitalocean&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/en-us/"&gt;Microsoft Azure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.vultr.com/"&gt;Vultr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://eu.alibabacloud.com/"&gt;Alibaba Cloud&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/vuelancer/free-deployment-providers-bk0"&gt;Free hosting providers for front-end &amp;amp; back-end applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/parik36/status/1454817956282650630"&gt;https://twitter.com/parik36/status/1454817956282650630&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Unserialize php in Javascript Nodejs</title>
      <dc:creator>Bogdan Alexandru Militaru</dc:creator>
      <pubDate>Thu, 28 Oct 2021 09:09:09 +0000</pubDate>
      <link>https://forem.com/boobo94/unserialize-php-in-javascript-nodejs-2boo</link>
      <guid>https://forem.com/boobo94/unserialize-php-in-javascript-nodejs-2boo</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import PhpUnserialize from 'php-unserialize';

const serialized = 'a:0:{}'
const jsObject = PhpUnserialize.unserialize(serialized);
console.log(jsObject) // {}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NPM Library: &lt;a href="https://www.npmjs.com/package/php-unserialize"&gt;https://www.npmjs.com/package/php-unserialize&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What happens if your serialized string contains special characters ? yeah, it fails!&lt;/p&gt;

&lt;p&gt;In order to solve that we can use&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import encoding from 'encoding';

export function convertToUtf8Win1252(str) {
  return encoding.convert(str, 'WINDOWS-1252').toString();
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So mixing both functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function unserializePhp(str) {
  return PhpUnserialize
    .unserialize(convertToUtf8Win1252(str));
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NPM Library: &lt;a href="https://www.npmjs.com/package/encoding"&gt;https://www.npmjs.com/package/encoding&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>node</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Create kml/kmz files in Nodejs</title>
      <dc:creator>Bogdan Alexandru Militaru</dc:creator>
      <pubDate>Thu, 28 Oct 2021 09:09:09 +0000</pubDate>
      <link>https://forem.com/boobo94/create-kmlkmz-files-in-nodejs-3kek</link>
      <guid>https://forem.com/boobo94/create-kmlkmz-files-in-nodejs-3kek</guid>
      <description>&lt;p&gt;Libraries used:&lt;/p&gt;

&lt;p&gt;Create kml file - &lt;a href="https://www.npmjs.com/package/@maphubs/tokml"&gt;https://www.npmjs.com/package/@maphubs/tokml&lt;/a&gt; Create geojson - &lt;a href="https://www.npmjs.com/package/geojson"&gt;https://www.npmjs.com/package/geojson&lt;/a&gt; Create kmz using zip - &lt;a href="https://www.npmjs.com/package/jszip"&gt;https://www.npmjs.com/package/jszip&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create KML File
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
const points = [
    {latitude: 39.984, longitude: -75.343},
    {latitude: 39.284, longitude: -75.833},
    {latitude: 39.123, longitude: -74.534},
    {line: [[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]],}
]

const geojsonObject = geojson.parse(points, {
    Point: ['latitude', 'longitude'],
    LineString: 'line',
}), {
    documentName: 'Document Name',
    documentDescription: 'KML Export'
}

  const response = tokml(geojsonObject);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Content-type for kml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'Content-Type': 'application/vnd.google-earth.kml+xml',

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create KMZ File
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const zip = new JSZip();
  zip.file('doc.kml', kmlFile);

  return zip.generateAsync({ type: 'nodebuffer' });

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Content-type for kml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'Content-Type': 'application/vnd.google-earth.kmz',

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Free ideas for the next startup</title>
      <dc:creator>Bogdan Alexandru Militaru</dc:creator>
      <pubDate>Wed, 08 Sep 2021 09:09:09 +0000</pubDate>
      <link>https://forem.com/boobo94/free-ideas-for-the-next-startup-5b10</link>
      <guid>https://forem.com/boobo94/free-ideas-for-the-next-startup-5b10</guid>
      <description>&lt;p&gt;I would like to share with you boys some places where you can find ideas, share ideas and why not validate ideas.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.indiehackers.com/group/ideas-and-validation"&gt;Ideas and Validation Group from IH&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://needgap.com/"&gt;needgap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kern.al/"&gt;Kern.al&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;PS: This would be updated&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Twilio Proxy for masked phone numbers in Node.js</title>
      <dc:creator>Bogdan Alexandru Militaru</dc:creator>
      <pubDate>Fri, 02 Jul 2021 09:09:09 +0000</pubDate>
      <link>https://forem.com/boobo94/twilio-proxy-for-masked-phone-numbers-in-node-js-4742</link>
      <guid>https://forem.com/boobo94/twilio-proxy-for-masked-phone-numbers-in-node-js-4742</guid>
      <description>&lt;h1&gt;
  
  
  Twilio Proxy for masked phone numbers in Node.js
&lt;/h1&gt;

&lt;p&gt;Twilio offers a service called &lt;a href="https://www.twilio.com/proxy"&gt;Proxy&lt;/a&gt; to allow masked phone numbers. What that means? You know when you call an Uber and the number shown to you is not the phone number of your driver?! Exactly that means &lt;em&gt;masked phone number&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Proxy API connects two parties together, allowing them to communicate and keep personal information private.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--e_wF4G05--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.twilio.com/docs/static/proxy/img/phone-number-pooling.a6ec80587.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e_wF4G05--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.twilio.com/docs/static/proxy/img/phone-number-pooling.a6ec80587.png" alt="masked phone numbers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to make a call in Node.js
&lt;/h2&gt;

&lt;p&gt;Let’s get to the point. I’ve made a &lt;code&gt;twilio-service.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Twilio from 'twilio'

const TWILIO_SERVICE_ID = 'YOUR_SERVICE_ID' // create a service here: https://console.twilio.com/us1/develop/proxy/services
const TWILIO_ACCOUNT_SID= 'YOUR_ACCOUNT_ID'
const TWILIO_AUTH_TOKEN = 'YOUR_AUTH_TOKEN'

const twilioService = function () {
  let client
  if (!client) {
    client = new Twilio(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, {
      logLevel: 'debug'
    })
    delete client.constructor
  }

  return {
    _client: client,

    /**
     * Creates new session to prepare a call
     * docs: https://www.twilio.com/docs/proxy/api/session
     * @returns
     */
    createSession: async function () {
      return client.proxy.services(TWILIO_SERVICE_ID).sessions.create({
        mode: 'voice-only'
      })
    },

    /**
     * Delete a call sesion
     * @param {string} sessionId The id of session
     * docs: https://www.twilio.com/docs/proxy/api/session#delete-a-session-resource
     * @returns
     */
    deleteSession: async function (sessionId) {
      return client
        .proxy
        .services(TWILIO_SERVICE_ID)
        .sessions(sessionId)
        .remove()
    },

    /**
     * Add new participant to the call
     * Maximum 2 participants per call are allowed
     * docs: https://www.twilio.com/docs/proxy/api/participant
     *
     * @param {string} sessionId The id of session
     * @param {string} phoneNumber The phone number of participant to call
     * @returns
     */
    addParticipantToSession: async function (sessionId, phoneNumber) {
      return client
        .proxy
        .services(TWILIO_SERVICE_ID)
        .sessions(sessionId)
        .participants
        .create({
          identifier: phoneNumber
        })
    }

  }
}

export default twilioService()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make a call only need 3 steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new proxy session&lt;/li&gt;
&lt;li&gt;Add participants to the session created previously. We have two participants. Each of them has a property &lt;code&gt;identifier&lt;/code&gt; (their real phone number) and has assigned a new property &lt;code&gt;proxyIdentifier&lt;/code&gt; (the masked phone number).&lt;/li&gt;
&lt;li&gt;Now each of them can call their own &lt;code&gt;proxyIdentifier&lt;/code&gt;, Twilio match their masked number with the masked number of the recipient, and call then the real number of the recipient.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  import TwilioService from '../services/twilio';

  const participant1Number = '+14156789012';
  const participant2Number = '+17012345678';

  const session = await TwilioService.createSession()
  // session = {
  // ...
  // "sid": "KCaa270143d7a1ef87f743313a07d4069d",
  // ...
  // }
  const participantFrom = await TwilioService.addParticipantToSession(session.sid,participant1Number)
  // participantFrom = {
  // "sid": "KPa4947c3d7b8ca7b0138dbc8181f12e16",
  // "sessionSid": "KCaa270143d7a1ef87f743313a07d4069d",
  // "identifier": "+14156789012",
  // "proxyIdentifier": "+14153749231",
  // }
  const participantTo = await TwilioService.addParticipantToSession(session.sid, participant2Number)  
  participantTo = {
  // "sid": "KP48f197284b3f50c5b31891ecc8377c20",
  // "sessionSid": "KCaa270143d7a1ef87f743313a07d4069d",
  // "identifier": "+17012345678",
  // "proxyIdentifier": "+40371246711",
  // }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What is next?
&lt;/h3&gt;

&lt;p&gt;Let’s say you are &lt;strong&gt;+14156789012&lt;/strong&gt; and you need to connect with &lt;strong&gt;+17012345678&lt;/strong&gt;. You’ve run the previous code, now Twilio created a proxy between these two numbers. But you don’t know the number of &lt;strong&gt;+17012345678&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Take your phone, make a call to your &lt;code&gt;proxyIdentifier&lt;/code&gt;, &lt;strong&gt;+14153749231&lt;/strong&gt; , Twilio identifies your identity and match your masked phone number with the other paticipant, and call their real name &lt;strong&gt;+17012345678&lt;/strong&gt; , but you never know which is the real number of your companion speaker. To make the call from the other side, do the same.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do you wanna cancel the proxy between two of them?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; await TwilioService.deleteSession(session.sid);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is all boys. For further questions send me an email or message on Twitter. Do you like the article? Share it!&lt;/p&gt;

</description>
      <category>node</category>
      <category>webdev</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
