Rodney Vg

Rodney Vg

1573633153

How to Build a Single-Page Sales Funnel App using Vue.js

A sales funnel is an online marketing tool that is built and designed to capture leads from traffic and convert them into customers. They tend to convert 20% to 50% higher than ordinary web pages. A sales funnel typically consists of opt-in pages, order forms, shopping carts, checkout pages and email marketing software. Building such a system is not a walk in the park.

The common way of building a sales funnel today is by purchasing a monthly subscription plan from a sales funnel builder platform. The most popular provider currently charges about $100 to $300. There are other affordable options. However, you may encounter limitations or technical challenges with any provider you work with — some more severe than others.

If you don’t want to pay for a subscription plan, then you will have to build one yourself. Historically, coding your own funnel has been more expensive and time-consuming. However, we are living in 2019. The technology used by web developers today has improved immensely in the last 10 years.

It’s easier and faster to build and deploy a web application. We have tons of third-party providers that allow integrations to their platforms via remote APIs. This allows us to easily implement heavy-duty features without having to write the code ourselves.

The benefits of owning your own funnel code means your business will be more resilient. You can easily switch servers if something doesn’t work out with your provider. You can also easily scale up your online business without meeting major obstacles.

In this tutorial, I’ll show you how to code your own simple sales funnel with Vue that will help you promote a product or service that you are selling to consumers. We’ll build a simple squeeze page funnel for collecting leads for your email list.

Prerequisites

This article assumes that you have at least a solid grasp in:

You’ll need to have a modern version of Node.js and the Vue CLI tool installed in your system. At the time of writing this article, Node v10.15.1 was the current LTS. The current Vue CLI version tool is v3.4.1. My personal recommendation is to use nvm to keep your Node.js environment up-to-date. To install the Vue.js CLI tool, execute the command:

npm install @vue/cli

About the Project

You can access the full source for this project onGitHub. There is also a live demo of this project. We’ll be using Bootstrap-vue as our primary CSS framework. Please make sure to read the docs if you are new to this framework.

For this project, we are going to build a two page funnel consisting of an opt-in page — a.k.a squeeze page — and a thank you page. The setup will look something like this:

Sales Funnel with Vue - Squeeze Page

The opt-in page captures a visitor’s email address and saves it to an email list. At the same time, it moves the visitor to the next page. It is that simple. You can even do it using just plain HTML, CSS and JavaScript. Why are we even doing it in Vue.js?

The reason is because we could want to build different types of funnels promoting the same product, or different products. We wouldn’t want to repeat the same code we implemented earlier in another funnel.

Vue.js is the perfect solution that will allow us to build re-usable components that will be easy to maintain and update. In addition, we can package our components and publish it to a npm registry, making it available to all our future funnel projects.

To publish our funnel, we will have to do it in a framework like Nuxt.js. This is because Vue.js is mostly a view layer technology. We can install our sales funnel library in a Nuxt.js project. Nuxt.js is more of a full framework in that it allows code to run both on the server and the client side. It also supports a ton of useful features such as SEO.

Unfortunately, it won’t be possible to perform most of the steps mentioned above in a single tutorial. What we’ll do instead is build the two page funnel. I’ll show you how to design the components such that they are easy to re-use.

This way you can package the project later and install it in another funnel project. I’ll also provide additional links in regards to packaging a Vue.js project and deploying it to a private npm server.

With this plan in mind, let’s move on and start building our funnel library project!

Project Setup

Open a console terminal and create a new Vue project.

vue create vue-sales-funnel

Use the following settings:

  • Features: Babel, Router, Linter(optional)
  • Router History Mode: Yes
  • Linter: ESlint + Prettier, Lint on Save, Lint and fix on commit (or choose your preferred options)
  • config files : In dedicated config files

Next, install Bootstrap-Vue:

cd vue-sales-funnel
npm install vue bootstrap-vue bootstrap

Next open the project in your favorite editor. If you have Visual Studio Code, you can launch it like this:

code .

Update src\main.js as follows:

import Vue from "vue";
import BootstrapVue from "bootstrap-vue";
import App from "./App.vue";
import router from "./router";

import "bootstrap/dist/css/bootstrap.css";
import "bootstrap-vue/dist/bootstrap-vue.css";

Vue.config.productionTip = false;
Vue.use(BootstrapVue);

new Vue({
  router,
  render: h => h(App)
}).$mount("#app");

This should set up the Bootstrap CSS framework in your project. Next, update src\App.js as follows:

<template>
  <div id="app">
    <router-view />
  </div>
</template>

Rename the following files as follows:

  • src/views/Home.vue => Optin.vue
  • src/views/About.vue => Thank-you.vue

Replace the existing code in src/views/Optin.vue as follows:

<template>
  <div class="optin">
    <b-row>
      <b-col>
        <p>Squeeze Funnel Page</p>
      </b-col>
    </b-row>
  </div>
</template>

<script>
export default {
  name: "optin"
};
</script>

Update the code in src\router.js as follows:

import Vue from "vue";
import Router from "vue-router";
import Optin from "./views/Optin.vue";
import ThankYou from "./views/Thank-you.vue";

Vue.use(Router);

export default new Router({
  mode: "history",
  base: process.env.BASE_URL,
  routes: [
    {
      path: "/",
      name: "optin",
      component: Optin
    },
    {
      path: "/thank-you",
      name: "thank-you",
      component: ThankYou
    }
  ]
});

You can now fire up your project server using the command npm run serve. Open the browser and check the links localhost:8080 and localhost:8080/thank-you are working as expected. If so, you can proceed to the next section. If not, check your work.

Text Content

The first component that we will build is a Text component. We can easily use <h1> and <p> tags. However, we need preset elements that already have a style applied to them. We need to quickly build a page in 10 minutes or less without thinking about styling.

Delete the component src/components/HelloWorld.vue and create TextComponent.vue in its place. Copy the following code:

<template>
  <div class="text-content" v-bind:style="{ marginTop: topMargin }">
    <h1 class="header" v-if="variant === 'header'">{{ content }}</h1>
    <h2 class="subheader" v-if="variant === 'subheader'">{{ content }}</h2>
    <p class="paragraph" v-if="variant === 'paragraph'" v-html="content"></p>
  </div>
</template>

<script>
export default {
  name: "TextContent",
  props: {
    variant: String,
    content: String,
    topMargin: String
  }
};
</script>

<style scoped>
.header {
  color: rgb(50, 50, 50);
  text-align: center;
}
.subheader {
  font-size: 1.5rem;
  color: rgb(100, 100, 100);
  text-align: center;
}
p {
  color: rgb(124, 124, 124);
}
</style>

Let’s test it out by making the following changes in src/views/Optin.vue:

<template>
  <div class="optin container">
    <b-row>
      <b-col>
        <TextContent
          variant="header"
          content="Here’s Your Attention Getting Headline"
          topMargin="50px"
        />
        <TextContent
          variant="subheader"
          content="This is your sub-headline to increase credibility or curiosity"
        />
      </b-col>
    </b-row>
    <b-row>
      <b-col>
        put image here
      </b-col>
      <b-col>
        <TextContent
          variant="paragraph"
          content="Here’s where you write your compelling message, keep your sentences and paragraphs short."
        />
      </b-col>
    </b-row>
  </div>
</template>

<script>
import TextContent from "../components/TextComponent";

export default {
  name: "optin",
  components: {
    TextContent
  }
};
</script>

Refresh your page. You should have something like this:

Sales Funnel with Vue Text Content

You may have noticed the paragraph tag will render content differently. We are using the v-html attribute to allow users to pass HTML styling such as <strong> and <u>. You can test it out by adding this snippet:

<TextContent
  variant="paragraph"
  content="Use <strong>*bold*</strong>, <u>underline</u> and <i>italics</i> to emphasize important points."
/>

We have built a simple Text Component that comes with pre-built styling. The prop variant is used to determine the type of text tag that needs to be rendered. We also have the prop topMargin which will allow us to easily space the text elements.

Assuming that test has worked out for you, let’s move on to the next challenge. Let’s assume we need to have different styles for the header and sub-header. We need a way to instruct the TextContent component to change the style. Update the OptinForm.vue code as follows:

<TextContent
  variant="header"
  content="Here’s Your Attention Getting Headline"
  topMargin="50px"
  theme="red"
/>

We have added a new prop called theme. We need to declare this new prop in TextComponent.vue. Update the code as follows:

<template>
  <h1
    class="header"
    v-bind:style="getStyle()"
    v-if="variant === 'header'"
  >
    {{ content }}
  </h1>
</template>

<script>
export default {
  ...
  props: {
    ...
    theme: String
  },
  data: function() {
    return {
      red: { // style object
        color: "red"
      },
      blue: { // style object
        color: "blue"
      }
    };
  },
  methods: {
    getStyle() {
      switch (this.$props.theme) {
        case "red":
          return this.red;
        case "blue":
          return this.blue;
        default:
          break;
      }
    }
  }
};

</script>

When you refresh your page, you should have something like this:

Sales funnel with Vue text content red

In this example, we have declared multiple style objects, red and blue. Users can specify which theme they want to use. Feel free to add more properties to the style objects and create more style objects.

If you want to go further, you can externalize the style objects so that it’s separate from the code. You can create something like a theme.css file that will be easier to customize.

Let’s now look at the next component.

Opt-in Form

The opt-in form is where the lead capture action happens. We ask visitors to give us their email address in exchange for a valuable resource that will help them.

Create the file src/components/OptinForm.vue and insert the following code:

<template>
  <div class="optin-form">
    <form @submit.prevent="onSubmit">
      <b-form-group>
        <b-form-input
          type="email"
          v-model="form.email"
          size="lg"
          required
          placeholder="Enter email"
        />
      </b-form-group>
      <b-button type="submit" v-bind:variant="submitColor" size="lg" block>{{
        submitText
      }}</b-button>
    </form>
  </div>
</template>

<script>
export default {
  name: "optin-form",
  props: {
    submitText: String,
    submitColor: String
  },
  data() {
    return {
      form: {
        email: ""
      }
    };
  },
  methods: {
    onSubmit() {
      this.$emit("submit", this.form);
    }
  }
};
</script>

<style scoped>
.btn {
  font-weight: bold;
  font-size: 1.5rem;
}
</style>

Go through the code, pay special attention to the props used. To demonstrate how this component is used, simply update src/views/Optin.vue as follows:

<template>
  <b-row style="marginTop:20px">
      <b-col>
        <b-img
          src="https://images.unsplash.com/photo-1483032469466-b937c425697b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=600&q=80"
          fluid
        />
      </b-col>
      <b-col>
        <TextContent
          variant="paragraph"
          content="Here’s where you write your compelling message, keep your sentences and paragraphs short."
        />
        <OptinForm
          submitText="Free Download!"
          submitColor="warning"
          @submit="handleSubmit"
        />
      </b-col>
    </b-row>
</template>

<script>
import TextContent from "../components/TextContent";
import OptinForm from "../components/OptinForm";

export default {
  name: "optin",
  components: {
    TextContent,
    OptinForm
  },
  methods: {
    handleSubmit(form) {
      console.log("Add New Subscriber", form.email);
      this.$router.push({ path: '/thank-you'})
    }
  }
};
</script>

Do note we’ve replaced the “put image here” text with an actual image tag. We’ve also specified a @submit event on the OptinForm component which will be handled by the handleSubmit function. If you look back at the OptinForm.vue code, you’ll notice that an event is fired through this code: this.$emit("submit", this.form);.

And that is how we’ve decoupled the OptinForm.vue component. We can easily write custom code that sends an email address to any email marketing platform of your choice. My current favorite is MailerLite. Here is their API documentation on how to add a new subscriber.

You can use a library like Fetch or Axios to send the information via the REST API. If you are new to this, check out the tutorial Introducing Axios, a Popular, Promise-based HTTP Client.

Refresh your browser and confirm that the opt-in page is working:

Sales funnel with Vue opt-in form

At the moment, we are using HTML validation. Entering a valid email address should quickly navigate you to the thank-you page. At the moment, it doesn’t look like one. Let’s fix that in the next section.

Video Content

Before we populate the Thank-You.vue page, we need to create the src/components/VideoContent.vue component. Insert the following code:

<template>
  <div class="video-content" v-bind:style="{ marginTop: topMargin }">
    <b-embed type="iframe" aspect="16by9" :src="link" allowfullscreen />
  </div>
</template>

<script>
export default {
  name: "video-content",
  props: {
    link: String,
    topMargin: String
  }
};
</script>

The VideoContent component will allow us to embed any video from sites such as YouTube and Vimeo. You’ll have to get an embed link for it to work. The embed URL for YouTube looks something like this:

https://www.youtube.com/embed/xxxxxxxxx

Once you have saved the component, we can now start working on src/views/Thank-you.vue. Replace all existing code with this:

<template>
  <div class="thank-you container">
    <b-row>
      <b-col>
        <TextContent
          variant="header"
          content="Here’s Your Thank You Headline"
          topMargin="50px"
          theme="red"
        />
        <TextContent
          variant="subheader"
          content="This is your sub-headline to increase credibility or curiosity"
        />
      </b-col>
    </b-row>
    <b-row>
      <b-col>
        <VideoContent
          link="https://www.youtube.com/embed/m9q58hSppds"
          topMargin="30px"
        />
      </b-col>
    </b-row>
  </div>
</template>

<script>
import TextContent from "../components/TextContent.vue";
import VideoContent from "../components/VideoContent";

export default {
  name: "thank-you",
  components: {
    TextContent,
    VideoContent
  }
};
</script>

If you refresh the http://localhost:8080/thank-you page, you should have the following view:

Sales funnel with Vue thank you page

Since we are done with that, let’s create one more component that is a bit complicated. This one will go to our Optin page.

Countdown Timer Component

A countdown timer is a popular marketing tool used to create a sense of urgency. It encourages the visitor to take action now before the opportunity expires. There are mainly two types of countdown timers:

  1. Deadline to a specified date
  2. A fixed time (usually in an hour or a few minutes) that resets itself everyday or when the session is new

In this case, we’ll focus on building the first use case. We are not going to actually code this timer itself, but grab one from the npm registry. You’ll need to exit the Vue.js server first. Install it as follows:

npm install vuejs-countdown

Next create the file src/components/Countdowntimer.vue and insert the following code:

<template>
  <div class="countdown-timer">
    <Countdown :deadline="endDate"></Countdown>
  </div>
</template>

<script>
import Countdown from "vuejs-countdown";

export default {
  name: "countdown-timer",
  components: { Countdown },
  props: {
    endDate: String
  }
};
</script>

<style>
.countdown-timer {
  padding: 15px;
  text-align: center;
}
.countdown-section {
  display: inline-block;
  margin-right: 25px;
}
.vuejs-countdown .digit {
  display: block;
  border: 4px solid orange;
  color: darkorange;
  padding: 10px;
  border-radius: 100px;
  width: 72px;
  margin-bottom: 10px;
}
.text {
  font-size: 0.7rem;
  font-weight: bold;
  color: gray;
}
</style>

Next, add the CountdownTimer component to the src/views/Optin.vue page:

<template>
  ...
  <b-row>
    <b-col>
      <CountdownTimer endDate="March 3, 2020e" />
      <TextContent
        variant="subheader"
        content="This is offer will soon expire"
      />
    </b-col>
  </b-row>
  ...
</template>

<script>
  import CountdownTimer from "../components/CountdownTimer";
  ...
  components: {
    ...
    CountdownTimer
  },
</script>

After making the changes, you can now start the server. Your page should look like this:

Sales funnel with Vue countdown timer

In case yours is not counting down, change the date and make sure it’s set in the future. Let’s now finalize the tutorial.

Packaging and Publishing

So far we’ve made a good base for a sales funnel library. You can keep on adding more components, each with more customizable options. Now is a good time to talk about packaging and launching a production-ready funnel. While it’s possible to run the funnel we just created from our Vue project, it’s best we launch it in a Nuxt.js project.

Summary

I hope you have learned something useful from this tutorial. As a developer, you have an advantage over non-technical people. You can build and launch your funnels at a fraction of the cost most marketers pay for the entire lifetime when using a funnel building service. This will result in thousands of dollars in savings every year.

In addition, you will be able to sell more of your software products and services as opposed to using a standard website. Let us know via social media if you plan to create an open-source version of a sales funnel builder that will benefit the community.

#vuejs #vue #javascript

What is GEEK

Buddha Community

How to Build a Single-Page Sales Funnel App using Vue.js
Chloe  Butler

Chloe Butler

1667425440

Pdf2gerb: Perl Script Converts PDF Files to Gerber format

pdf2gerb

Perl script converts PDF files to Gerber format

Pdf2Gerb generates Gerber 274X photoplotting and Excellon drill files from PDFs of a PCB. Up to three PDFs are used: the top copper layer, the bottom copper layer (for 2-sided PCBs), and an optional silk screen layer. The PDFs can be created directly from any PDF drawing software, or a PDF print driver can be used to capture the Print output if the drawing software does not directly support output to PDF.

The general workflow is as follows:

  1. Design the PCB using your favorite CAD or drawing software.
  2. Print the top and bottom copper and top silk screen layers to a PDF file.
  3. Run Pdf2Gerb on the PDFs to create Gerber and Excellon files.
  4. Use a Gerber viewer to double-check the output against the original PCB design.
  5. Make adjustments as needed.
  6. Submit the files to a PCB manufacturer.

Please note that Pdf2Gerb does NOT perform DRC (Design Rule Checks), as these will vary according to individual PCB manufacturer conventions and capabilities. Also note that Pdf2Gerb is not perfect, so the output files must always be checked before submitting them. As of version 1.6, Pdf2Gerb supports most PCB elements, such as round and square pads, round holes, traces, SMD pads, ground planes, no-fill areas, and panelization. However, because it interprets the graphical output of a Print function, there are limitations in what it can recognize (or there may be bugs).

See docs/Pdf2Gerb.pdf for install/setup, config, usage, and other info.


pdf2gerb_cfg.pm

#Pdf2Gerb config settings:
#Put this file in same folder/directory as pdf2gerb.pl itself (global settings),
#or copy to another folder/directory with PDFs if you want PCB-specific settings.
#There is only one user of this file, so we don't need a custom package or namespace.
#NOTE: all constants defined in here will be added to main namespace.
#package pdf2gerb_cfg;

use strict; #trap undef vars (easier debug)
use warnings; #other useful info (easier debug)


##############################################################################################
#configurable settings:
#change values here instead of in main pfg2gerb.pl file

use constant WANT_COLORS => ($^O !~ m/Win/); #ANSI colors no worky on Windows? this must be set < first DebugPrint() call

#just a little warning; set realistic expectations:
#DebugPrint("${\(CYAN)}Pdf2Gerb.pl ${\(VERSION)}, $^O O/S\n${\(YELLOW)}${\(BOLD)}${\(ITALIC)}This is EXPERIMENTAL software.  \nGerber files MAY CONTAIN ERRORS.  Please CHECK them before fabrication!${\(RESET)}", 0); #if WANT_DEBUG

use constant METRIC => FALSE; #set to TRUE for metric units (only affect final numbers in output files, not internal arithmetic)
use constant APERTURE_LIMIT => 0; #34; #max #apertures to use; generate warnings if too many apertures are used (0 to not check)
use constant DRILL_FMT => '2.4'; #'2.3'; #'2.4' is the default for PCB fab; change to '2.3' for CNC

use constant WANT_DEBUG => 0; #10; #level of debug wanted; higher == more, lower == less, 0 == none
use constant GERBER_DEBUG => 0; #level of debug to include in Gerber file; DON'T USE FOR FABRICATION
use constant WANT_STREAMS => FALSE; #TRUE; #save decompressed streams to files (for debug)
use constant WANT_ALLINPUT => FALSE; #TRUE; #save entire input stream (for debug ONLY)

#DebugPrint(sprintf("${\(CYAN)}DEBUG: stdout %d, gerber %d, want streams? %d, all input? %d, O/S: $^O, Perl: $]${\(RESET)}\n", WANT_DEBUG, GERBER_DEBUG, WANT_STREAMS, WANT_ALLINPUT), 1);
#DebugPrint(sprintf("max int = %d, min int = %d\n", MAXINT, MININT), 1); 

#define standard trace and pad sizes to reduce scaling or PDF rendering errors:
#This avoids weird aperture settings and replaces them with more standardized values.
#(I'm not sure how photoplotters handle strange sizes).
#Fewer choices here gives more accurate mapping in the final Gerber files.
#units are in inches
use constant TOOL_SIZES => #add more as desired
(
#round or square pads (> 0) and drills (< 0):
    .010, -.001,  #tiny pads for SMD; dummy drill size (too small for practical use, but needed so StandardTool will use this entry)
    .031, -.014,  #used for vias
    .041, -.020,  #smallest non-filled plated hole
    .051, -.025,
    .056, -.029,  #useful for IC pins
    .070, -.033,
    .075, -.040,  #heavier leads
#    .090, -.043,  #NOTE: 600 dpi is not high enough resolution to reliably distinguish between .043" and .046", so choose 1 of the 2 here
    .100, -.046,
    .115, -.052,
    .130, -.061,
    .140, -.067,
    .150, -.079,
    .175, -.088,
    .190, -.093,
    .200, -.100,
    .220, -.110,
    .160, -.125,  #useful for mounting holes
#some additional pad sizes without holes (repeat a previous hole size if you just want the pad size):
    .090, -.040,  #want a .090 pad option, but use dummy hole size
    .065, -.040, #.065 x .065 rect pad
    .035, -.040, #.035 x .065 rect pad
#traces:
    .001,  #too thin for real traces; use only for board outlines
    .006,  #minimum real trace width; mainly used for text
    .008,  #mainly used for mid-sized text, not traces
    .010,  #minimum recommended trace width for low-current signals
    .012,
    .015,  #moderate low-voltage current
    .020,  #heavier trace for power, ground (even if a lighter one is adequate)
    .025,
    .030,  #heavy-current traces; be careful with these ones!
    .040,
    .050,
    .060,
    .080,
    .100,
    .120,
);
#Areas larger than the values below will be filled with parallel lines:
#This cuts down on the number of aperture sizes used.
#Set to 0 to always use an aperture or drill, regardless of size.
use constant { MAX_APERTURE => max((TOOL_SIZES)) + .004, MAX_DRILL => -min((TOOL_SIZES)) + .004 }; #max aperture and drill sizes (plus a little tolerance)
#DebugPrint(sprintf("using %d standard tool sizes: %s, max aper %.3f, max drill %.3f\n", scalar((TOOL_SIZES)), join(", ", (TOOL_SIZES)), MAX_APERTURE, MAX_DRILL), 1);

#NOTE: Compare the PDF to the original CAD file to check the accuracy of the PDF rendering and parsing!
#for example, the CAD software I used generated the following circles for holes:
#CAD hole size:   parsed PDF diameter:      error:
#  .014                .016                +.002
#  .020                .02267              +.00267
#  .025                .026                +.001
#  .029                .03167              +.00267
#  .033                .036                +.003
#  .040                .04267              +.00267
#This was usually ~ .002" - .003" too big compared to the hole as displayed in the CAD software.
#To compensate for PDF rendering errors (either during CAD Print function or PDF parsing logic), adjust the values below as needed.
#units are pixels; for example, a value of 2.4 at 600 dpi = .0004 inch, 2 at 600 dpi = .0033"
use constant
{
    HOLE_ADJUST => -0.004 * 600, #-2.6, #holes seemed to be slightly oversized (by .002" - .004"), so shrink them a little
    RNDPAD_ADJUST => -0.003 * 600, #-2, #-2.4, #round pads seemed to be slightly oversized, so shrink them a little
    SQRPAD_ADJUST => +0.001 * 600, #+.5, #square pads are sometimes too small by .00067, so bump them up a little
    RECTPAD_ADJUST => 0, #(pixels) rectangular pads seem to be okay? (not tested much)
    TRACE_ADJUST => 0, #(pixels) traces seemed to be okay?
    REDUCE_TOLERANCE => .001, #(inches) allow this much variation when reducing circles and rects
};

#Also, my CAD's Print function or the PDF print driver I used was a little off for circles, so define some additional adjustment values here:
#Values are added to X/Y coordinates; units are pixels; for example, a value of 1 at 600 dpi would be ~= .002 inch
use constant
{
    CIRCLE_ADJUST_MINX => 0,
    CIRCLE_ADJUST_MINY => -0.001 * 600, #-1, #circles were a little too high, so nudge them a little lower
    CIRCLE_ADJUST_MAXX => +0.001 * 600, #+1, #circles were a little too far to the left, so nudge them a little to the right
    CIRCLE_ADJUST_MAXY => 0,
    SUBST_CIRCLE_CLIPRECT => FALSE, #generate circle and substitute for clip rects (to compensate for the way some CAD software draws circles)
    WANT_CLIPRECT => TRUE, #FALSE, #AI doesn't need clip rect at all? should be on normally?
    RECT_COMPLETION => FALSE, #TRUE, #fill in 4th side of rect when 3 sides found
};

#allow .012 clearance around pads for solder mask:
#This value effectively adjusts pad sizes in the TOOL_SIZES list above (only for solder mask layers).
use constant SOLDER_MARGIN => +.012; #units are inches

#line join/cap styles:
use constant
{
    CAP_NONE => 0, #butt (none); line is exact length
    CAP_ROUND => 1, #round cap/join; line overhangs by a semi-circle at either end
    CAP_SQUARE => 2, #square cap/join; line overhangs by a half square on either end
    CAP_OVERRIDE => FALSE, #cap style overrides drawing logic
};
    
#number of elements in each shape type:
use constant
{
    RECT_SHAPELEN => 6, #x0, y0, x1, y1, count, "rect" (start, end corners)
    LINE_SHAPELEN => 6, #x0, y0, x1, y1, count, "line" (line seg)
    CURVE_SHAPELEN => 10, #xstart, ystart, x0, y0, x1, y1, xend, yend, count, "curve" (bezier 2 points)
    CIRCLE_SHAPELEN => 5, #x, y, 5, count, "circle" (center + radius)
};
#const my %SHAPELEN =
#Readonly my %SHAPELEN =>
our %SHAPELEN =
(
    rect => RECT_SHAPELEN,
    line => LINE_SHAPELEN,
    curve => CURVE_SHAPELEN,
    circle => CIRCLE_SHAPELEN,
);

#panelization:
#This will repeat the entire body the number of times indicated along the X or Y axes (files grow accordingly).
#Display elements that overhang PCB boundary can be squashed or left as-is (typically text or other silk screen markings).
#Set "overhangs" TRUE to allow overhangs, FALSE to truncate them.
#xpad and ypad allow margins to be added around outer edge of panelized PCB.
use constant PANELIZE => {'x' => 1, 'y' => 1, 'xpad' => 0, 'ypad' => 0, 'overhangs' => TRUE}; #number of times to repeat in X and Y directions

# Set this to 1 if you need TurboCAD support.
#$turboCAD = FALSE; #is this still needed as an option?

#CIRCAD pad generation uses an appropriate aperture, then moves it (stroke) "a little" - we use this to find pads and distinguish them from PCB holes. 
use constant PAD_STROKE => 0.3; #0.0005 * 600; #units are pixels
#convert very short traces to pads or holes:
use constant TRACE_MINLEN => .001; #units are inches
#use constant ALWAYS_XY => TRUE; #FALSE; #force XY even if X or Y doesn't change; NOTE: needs to be TRUE for all pads to show in FlatCAM and ViewPlot
use constant REMOVE_POLARITY => FALSE; #TRUE; #set to remove subtractive (negative) polarity; NOTE: must be FALSE for ground planes

#PDF uses "points", each point = 1/72 inch
#combined with a PDF scale factor of .12, this gives 600 dpi resolution (1/72 * .12 = 600 dpi)
use constant INCHES_PER_POINT => 1/72; #0.0138888889; #multiply point-size by this to get inches

# The precision used when computing a bezier curve. Higher numbers are more precise but slower (and generate larger files).
#$bezierPrecision = 100;
use constant BEZIER_PRECISION => 36; #100; #use const; reduced for faster rendering (mainly used for silk screen and thermal pads)

# Ground planes and silk screen or larger copper rectangles or circles are filled line-by-line using this resolution.
use constant FILL_WIDTH => .01; #fill at most 0.01 inch at a time

# The max number of characters to read into memory
use constant MAX_BYTES => 10 * M; #bumped up to 10 MB, use const

use constant DUP_DRILL1 => TRUE; #FALSE; #kludge: ViewPlot doesn't load drill files that are too small so duplicate first tool

my $runtime = time(); #Time::HiRes::gettimeofday(); #measure my execution time

print STDERR "Loaded config settings from '${\(__FILE__)}'.\n";
1; #last value must be truthful to indicate successful load


#############################################################################################
#junk/experiment:

#use Package::Constants;
#use Exporter qw(import); #https://perldoc.perl.org/Exporter.html

#my $caller = "pdf2gerb::";

#sub cfg
#{
#    my $proto = shift;
#    my $class = ref($proto) || $proto;
#    my $settings =
#    {
#        $WANT_DEBUG => 990, #10; #level of debug wanted; higher == more, lower == less, 0 == none
#    };
#    bless($settings, $class);
#    return $settings;
#}

#use constant HELLO => "hi there2"; #"main::HELLO" => "hi there";
#use constant GOODBYE => 14; #"main::GOODBYE" => 12;

#print STDERR "read cfg file\n";

#our @EXPORT_OK = Package::Constants->list(__PACKAGE__); #https://www.perlmonks.org/?node_id=1072691; NOTE: "_OK" skips short/common names

#print STDERR scalar(@EXPORT_OK) . " consts exported:\n";
#foreach(@EXPORT_OK) { print STDERR "$_\n"; }
#my $val = main::thing("xyz");
#print STDERR "caller gave me $val\n";
#foreach my $arg (@ARGV) { print STDERR "arg $arg\n"; }

Download Details:

Author: swannman
Source Code: https://github.com/swannman/pdf2gerb

License: GPL-3.0 license

#perl 

Carmen  Grimes

Carmen Grimes

1595491178

Best Electric Bikes and Scooters for Rental Business or Campus Facility

The electric scooter revolution has caught on super-fast taking many cities across the globe by storm. eScooters, a renovated version of old-school scooters now turned into electric vehicles are an environmentally friendly solution to current on-demand commute problems. They work on engines, like cars, enabling short traveling distances without hassle. The result is that these groundbreaking electric machines can now provide faster transport for less — cheaper than Uber and faster than Metro.

Since they are durable, fast, easy to operate and maintain, and are more convenient to park compared to four-wheelers, the eScooters trend has and continues to spike interest as a promising growth area. Several companies and universities are increasingly setting up shop to provide eScooter services realizing a would-be profitable business model and a ready customer base that is university students or residents in need of faster and cheap travel going about their business in school, town, and other surrounding areas.

Electric Scooters Trends and Statistics

In many countries including the U.S., Canada, Mexico, U.K., Germany, France, China, Japan, India, Brazil and Mexico and more, a growing number of eScooter users both locals and tourists can now be seen effortlessly passing lines of drivers stuck in the endless and unmoving traffic.

A recent report by McKinsey revealed that the E-Scooter industry will be worth― $200 billion to $300 billion in the United States, $100 billion to $150 billion in Europe, and $30 billion to $50 billion in China in 2030. The e-Scooter revenue model will also spike and is projected to rise by more than 20% amounting to approximately $5 billion.

And, with a necessity to move people away from high carbon prints, traffic and congestion issues brought about by car-centric transport systems in cities, more and more city planners are developing more bike/scooter lanes and adopting zero-emission plans. This is the force behind the booming electric scooter market and the numbers will only go higher and higher.

Companies that have taken advantage of the growing eScooter trend develop an appthat allows them to provide efficient eScooter services. Such an app enables them to be able to locate bike pick-up and drop points through fully integrated google maps.

List of Best Electric Bikes for Rental Business or Campus Facility 2020:

It’s clear that e scooters will increasingly become more common and the e-scooter business model will continue to grab the attention of manufacturers, investors, entrepreneurs. All this should go ahead with a quest to know what are some of the best electric bikes in the market especially for anyone who would want to get started in the electric bikes/scooters rental business.

We have done a comprehensive list of the best electric bikes! Each bike has been reviewed in depth and includes a full list of specs and a photo.

Billy eBike

mobile-best-electric-bikes-scooters https://www.kickstarter.com/projects/enkicycles/billy-were-redefining-joyrides

To start us off is the Billy eBike, a powerful go-anywhere urban electric bike that’s specially designed to offer an exciting ride like no other whether you want to ride to the grocery store, cafe, work or school. The Billy eBike comes in 4 color options – Billy Blue, Polished aluminium, Artic white, and Stealth black.

Price: $2490

Available countries

Available in the USA, Europe, Asia, South Africa and Australia.This item ships from the USA. Buyers are therefore responsible for any taxes and/or customs duties incurred once it arrives in your country.

Features

  • Control – Ride with confidence with our ultra-wide BMX bars and a hyper-responsive twist throttle.
  • Stealth- Ride like a ninja with our Gates carbon drive that’s as smooth as butter and maintenance-free.
  • Drive – Ride further with our high torque fat bike motor, giving a better climbing performance.
  • Accelerate – Ride quicker with our 20-inch lightweight cutout rims for improved acceleration.
  • Customize – Ride your own way with 5 levels of power control. Each level determines power and speed.
  • Flickable – Ride harder with our BMX /MotoX inspired geometry and lightweight aluminum package

Specifications

  • Maximum speed: 20 mph (32 km/h)
  • Range per charge: 41 miles (66 km)
  • Maximum Power: 500W
  • Motor type: Fat Bike Motor: Bafang RM G060.500.DC
  • Load capacity: 300lbs (136kg)
  • Battery type: 13.6Ah Samsung lithium-ion,
  • Battery capacity: On/off-bike charging available
  • Weight: w/o batt. 48.5lbs (22kg), w/ batt. 54lbs (24.5kg)
  • Front Suspension: Fully adjustable air shock, preload/compression damping /lockout
  • Rear Suspension: spring, preload adjustment
  • Built-in GPS

Why Should You Buy This?

  • Riding fun and excitement
  • Better climbing ability and faster acceleration.
  • Ride with confidence
  • Billy folds for convenient storage and transportation.
  • Shorty levers connect to disc brakes ensuring you stop on a dime
  • belt drives are maintenance-free and clean (no oil or lubrication needed)

**Who Should Ride Billy? **

Both new and experienced riders

**Where to Buy? **Local distributors or ships from the USA.

Genze 200 series e-Bike

genze-best-electric-bikes-scooters https://www.genze.com/fleet/

Featuring a sleek and lightweight aluminum frame design, the 200-Series ebike takes your riding experience to greater heights. Available in both black and white this ebike comes with a connected app, which allows you to plan activities, map distances and routes while also allowing connections with fellow riders.

Price: $2099.00

Available countries

The Genze 200 series e-Bike is available at GenZe retail locations across the U.S or online via GenZe.com website. Customers from outside the US can ship the product while incurring the relevant charges.

Features

  • 2 Frame Options
  • 2 Sizes
  • Integrated/Removable Battery
  • Throttle and Pedal Assist Ride Modes
  • Integrated LCD Display
  • Connected App
  • 24 month warranty
  • GPS navigation
  • Bluetooth connectivity

Specifications

  • Maximum speed: 20 mph with throttle
  • Range per charge: 15-18 miles w/ throttle and 30-50 miles w/ pedal assist
  • Charging time: 3.5 hours
  • Motor type: Brushless Rear Hub Motor
  • Gears: Microshift Thumb Shifter
  • Battery type: Removable Samsung 36V, 9.6AH Li-Ion battery pack
  • Battery capacity: 36V and 350 Wh
  • Weight: 46 pounds
  • Derailleur: 8-speed Shimano
  • Brakes: Dual classic
  • Wheels: 26 x 20 inches
  • Frame: 16, and 18 inches
  • Operating Mode: Analog mode 5 levels of Pedal Assist Thrott­le Mode

Norco from eBikestore

norco-best-electric-bikes-scooters https://ebikestore.com/shop/norco-vlt-s2/

The Norco VLT S2 is a front suspension e-Bike with solid components alongside the reliable Bosch Performance Line Power systems that offer precise pedal assistance during any riding situation.

Price: $2,699.00

Available countries

This item is available via the various Norco bikes international distributors.

Features

  • VLT aluminum frame- for stiffness and wheel security.
  • Bosch e-bike system – for their reliability and performance.
  • E-bike components – for added durability.
  • Hydraulic disc brakes – offer riders more stopping power for safety and control at higher speeds.
  • Practical design features – to add convenience and versatility.

Specifications

  • Maximum speed: KMC X9 9spd
  • Motor type: Bosch Active Line
  • Gears: Shimano Altus RD-M2000, SGS, 9 Speed
  • Battery type: Power Pack 400
  • Battery capacity: 396Wh
  • Suspension: SR Suntour suspension fork
  • Frame: Norco VLT, Aluminum, 12x142mm TA Dropouts

Bodo EV

bodo-best-electric-bikes-scootershttp://www.bodoevs.com/bodoev/products_show.asp?product_id=13

Manufactured by Bodo Vehicle Group Limited, the Bodo EV is specially designed for strong power and extraordinary long service to facilitate super amazing rides. The Bodo Vehicle Company is a striking top in electric vehicles brand field in China and across the globe. Their Bodo EV will no doubt provide your riders with high-level riding satisfaction owing to its high-quality design, strength, breaking stability and speed.

Price: $799

Available countries

This item ships from China with buyers bearing the shipping costs and other variables prior to delivery.

Features

  • Reliable
  • Environment friendly
  • Comfortable riding
  • Fashionable
  • Economical
  • Durable – long service life
  • Braking stability
  • LED lighting technology

Specifications

  • Maximum speed: 45km/h
  • Range per charge: 50km per person
  • Charging time: 8 hours
  • Maximum Power: 3000W
  • Motor type: Brushless DC Motor
  • Load capacity: 100kg
  • Battery type: Lead-acid battery
  • Battery capacity: 60V 20AH
  • Weight: w/o battery 47kg

#android app #autorent #entrepreneurship #ios app #minimum viable product (mvp) #mobile app development #news #app like bird #app like bounce #app like lime #autorent #best electric bikes 2020 #best electric bikes for rental business #best electric kick scooters 2020 #best electric kickscooters for rental business #best electric scooters 2020 #best electric scooters for rental business #bird scooter business model #bird scooter rental #bird scooter rental cost #bird scooter rental price #clone app like bird #clone app like bounce #clone app like lime #electric rental scooters #electric scooter company #electric scooter rental business #how do you start a moped #how to start a moped #how to start a scooter rental business #how to start an electric company #how to start electric scooterrental business #lime scooter business model #scooter franchise #scooter rental business #scooter rental business for sale #scooter rental business insurance #scooters franchise cost #white label app like bird #white label app like bounce #white label app like lime

Carmen  Grimes

Carmen Grimes

1595494844

How to start an electric scooter facility/fleet in a university campus/IT park

Are you leading an organization that has a large campus, e.g., a large university? You are probably thinking of introducing an electric scooter/bicycle fleet on the campus, and why wouldn’t you?

Introducing micro-mobility in your campus with the help of such a fleet would help the people on the campus significantly. People would save money since they don’t need to use a car for a short distance. Your campus will see a drastic reduction in congestion, moreover, its carbon footprint will reduce.

Micro-mobility is relatively new though and you would need help. You would need to select an appropriate fleet of vehicles. The people on your campus would need to find electric scooters or electric bikes for commuting, and you need to provide a solution for this.

To be more specific, you need a short-term electric bike rental app. With such an app, you will be able to easily offer micro-mobility to the people on the campus. We at Devathon have built Autorent exactly for this.

What does Autorent do and how can it help you? How does it enable you to introduce micro-mobility on your campus? We explain these in this article, however, we will touch upon a few basics first.

Micro-mobility: What it is

micro-mobility

You are probably thinking about micro-mobility relatively recently, aren’t you? A few relevant insights about it could help you to better appreciate its importance.

Micro-mobility is a new trend in transportation, and it uses vehicles that are considerably smaller than cars. Electric scooters (e-scooters) and electric bikes (e-bikes) are the most popular forms of micro-mobility, however, there are also e-unicycles and e-skateboards.

You might have already seen e-scooters, which are kick scooters that come with a motor. Thanks to its motor, an e-scooter can achieve a speed of up to 20 km/h. On the other hand, e-bikes are popular in China and Japan, and they come with a motor, and you can reach a speed of 40 km/h.

You obviously can’t use these vehicles for very long commutes, however, what if you need to travel a short distance? Even if you have a reasonable public transport facility in the city, it might not cover the route you need to take. Take the example of a large university campus. Such a campus is often at a considerable distance from the central business district of the city where it’s located. While public transport facilities may serve the central business district, they wouldn’t serve this large campus. Currently, many people drive their cars even for short distances.

As you know, that brings its own set of challenges. Vehicular traffic adds significantly to pollution, moreover, finding a parking spot can be hard in crowded urban districts.

Well, you can reduce your carbon footprint if you use an electric car. However, electric cars are still new, and many countries are still building the necessary infrastructure for them. Your large campus might not have the necessary infrastructure for them either. Presently, electric cars don’t represent a viable option in most geographies.

As a result, you need to buy and maintain a car even if your commute is short. In addition to dealing with parking problems, you need to spend significantly on your car.

All of these factors have combined to make people sit up and think seriously about cars. Many people are now seriously considering whether a car is really the best option even if they have to commute only a short distance.

This is where micro-mobility enters the picture. When you commute a short distance regularly, e-scooters or e-bikes are viable options. You limit your carbon footprints and you cut costs!

Businesses have seen this shift in thinking, and e-scooter companies like Lime and Bird have entered this field in a big way. They let you rent e-scooters by the minute. On the other hand, start-ups like Jump and Lyft have entered the e-bike market.

Think of your campus now! The people there might need to travel short distances within the campus, and e-scooters can really help them.

How micro-mobility can benefit you

benefits-micromobility

What advantages can you get from micro-mobility? Let’s take a deeper look into this question.

Micro-mobility can offer several advantages to the people on your campus, e.g.:

  • Affordability: Shared e-scooters are cheaper than other mass transportation options. Remember that the people on your campus will use them on a shared basis, and they will pay for their short commutes only. Well, depending on your operating model, you might even let them use shared e-scooters or e-bikes for free!
  • Convenience: Users don’t need to worry about finding parking spots for shared e-scooters since these are small. They can easily travel from point A to point B on your campus with the help of these e-scooters.
  • Environmentally sustainable: Shared e-scooters reduce the carbon footprint, moreover, they decongest the roads. Statistics from the pilot programs in cities like Portland and Denver showimpressive gains around this key aspect.
  • Safety: This one’s obvious, isn’t it? When people on your campus use small e-scooters or e-bikes instead of cars, the problem of overspeeding will disappear. you will see fewer accidents.

#android app #autorent #ios app #mobile app development #app like bird #app like bounce #app like lime #autorent #bird scooter business model #bird scooter rental #bird scooter rental cost #bird scooter rental price #clone app like bird #clone app like bounce #clone app like lime #electric rental scooters #electric scooter company #electric scooter rental business #how do you start a moped #how to start a moped #how to start a scooter rental business #how to start an electric company #how to start electric scooterrental business #lime scooter business model #scooter franchise #scooter rental business #scooter rental business for sale #scooter rental business insurance #scooters franchise cost #white label app like bird #white label app like bounce #white label app like lime

NBB: Ad-hoc CLJS Scripting on Node.js

Nbb

Not babashka. Node.js babashka!?

Ad-hoc CLJS scripting on Node.js.

Status

Experimental. Please report issues here.

Goals and features

Nbb's main goal is to make it easy to get started with ad hoc CLJS scripting on Node.js.

Additional goals and features are:

  • Fast startup without relying on a custom version of Node.js.
  • Small artifact (current size is around 1.2MB).
  • First class macros.
  • Support building small TUI apps using Reagent.
  • Complement babashka with libraries from the Node.js ecosystem.

Requirements

Nbb requires Node.js v12 or newer.

How does this tool work?

CLJS code is evaluated through SCI, the same interpreter that powers babashka. Because SCI works with advanced compilation, the bundle size, especially when combined with other dependencies, is smaller than what you get with self-hosted CLJS. That makes startup faster. The trade-off is that execution is less performant and that only a subset of CLJS is available (e.g. no deftype, yet).

Usage

Install nbb from NPM:

$ npm install nbb -g

Omit -g for a local install.

Try out an expression:

$ nbb -e '(+ 1 2 3)'
6

And then install some other NPM libraries to use in the script. E.g.:

$ npm install csv-parse shelljs zx

Create a script which uses the NPM libraries:

(ns script
  (:require ["csv-parse/lib/sync$default" :as csv-parse]
            ["fs" :as fs]
            ["path" :as path]
            ["shelljs$default" :as sh]
            ["term-size$default" :as term-size]
            ["zx$default" :as zx]
            ["zx$fs" :as zxfs]
            [nbb.core :refer [*file*]]))

(prn (path/resolve "."))

(prn (term-size))

(println (count (str (fs/readFileSync *file*))))

(prn (sh/ls "."))

(prn (csv-parse "foo,bar"))

(prn (zxfs/existsSync *file*))

(zx/$ #js ["ls"])

Call the script:

$ nbb script.cljs
"/private/tmp/test-script"
#js {:columns 216, :rows 47}
510
#js ["node_modules" "package-lock.json" "package.json" "script.cljs"]
#js [#js ["foo" "bar"]]
true
$ ls
node_modules
package-lock.json
package.json
script.cljs

Macros

Nbb has first class support for macros: you can define them right inside your .cljs file, like you are used to from JVM Clojure. Consider the plet macro to make working with promises more palatable:

(defmacro plet
  [bindings & body]
  (let [binding-pairs (reverse (partition 2 bindings))
        body (cons 'do body)]
    (reduce (fn [body [sym expr]]
              (let [expr (list '.resolve 'js/Promise expr)]
                (list '.then expr (list 'clojure.core/fn (vector sym)
                                        body))))
            body
            binding-pairs)))

Using this macro we can look async code more like sync code. Consider this puppeteer example:

(-> (.launch puppeteer)
      (.then (fn [browser]
               (-> (.newPage browser)
                   (.then (fn [page]
                            (-> (.goto page "https://clojure.org")
                                (.then #(.screenshot page #js{:path "screenshot.png"}))
                                (.catch #(js/console.log %))
                                (.then #(.close browser)))))))))

Using plet this becomes:

(plet [browser (.launch puppeteer)
       page (.newPage browser)
       _ (.goto page "https://clojure.org")
       _ (-> (.screenshot page #js{:path "screenshot.png"})
             (.catch #(js/console.log %)))]
      (.close browser))

See the puppeteer example for the full code.

Since v0.0.36, nbb includes promesa which is a library to deal with promises. The above plet macro is similar to promesa.core/let.

Startup time

$ time nbb -e '(+ 1 2 3)'
6
nbb -e '(+ 1 2 3)'   0.17s  user 0.02s system 109% cpu 0.168 total

The baseline startup time for a script is about 170ms seconds on my laptop. When invoked via npx this adds another 300ms or so, so for faster startup, either use a globally installed nbb or use $(npm bin)/nbb script.cljs to bypass npx.

Dependencies

NPM dependencies

Nbb does not depend on any NPM dependencies. All NPM libraries loaded by a script are resolved relative to that script. When using the Reagent module, React is resolved in the same way as any other NPM library.

Classpath

To load .cljs files from local paths or dependencies, you can use the --classpath argument. The current dir is added to the classpath automatically. So if there is a file foo/bar.cljs relative to your current dir, then you can load it via (:require [foo.bar :as fb]). Note that nbb uses the same naming conventions for namespaces and directories as other Clojure tools: foo-bar in the namespace name becomes foo_bar in the directory name.

To load dependencies from the Clojure ecosystem, you can use the Clojure CLI or babashka to download them and produce a classpath:

$ classpath="$(clojure -A:nbb -Spath -Sdeps '{:aliases {:nbb {:replace-deps {com.github.seancorfield/honeysql {:git/tag "v2.0.0-rc5" :git/sha "01c3a55"}}}}}')"

and then feed it to the --classpath argument:

$ nbb --classpath "$classpath" -e "(require '[honey.sql :as sql]) (sql/format {:select :foo :from :bar :where [:= :baz 2]})"
["SELECT foo FROM bar WHERE baz = ?" 2]

Currently nbb only reads from directories, not jar files, so you are encouraged to use git libs. Support for .jar files will be added later.

Current file

The name of the file that is currently being executed is available via nbb.core/*file* or on the metadata of vars:

(ns foo
  (:require [nbb.core :refer [*file*]]))

(prn *file*) ;; "/private/tmp/foo.cljs"

(defn f [])
(prn (:file (meta #'f))) ;; "/private/tmp/foo.cljs"

Reagent

Nbb includes reagent.core which will be lazily loaded when required. You can use this together with ink to create a TUI application:

$ npm install ink

ink-demo.cljs:

(ns ink-demo
  (:require ["ink" :refer [render Text]]
            [reagent.core :as r]))

(defonce state (r/atom 0))

(doseq [n (range 1 11)]
  (js/setTimeout #(swap! state inc) (* n 500)))

(defn hello []
  [:> Text {:color "green"} "Hello, world! " @state])

(render (r/as-element [hello]))

Promesa

Working with callbacks and promises can become tedious. Since nbb v0.0.36 the promesa.core namespace is included with the let and do! macros. An example:

(ns prom
  (:require [promesa.core :as p]))

(defn sleep [ms]
  (js/Promise.
   (fn [resolve _]
     (js/setTimeout resolve ms))))

(defn do-stuff
  []
  (p/do!
   (println "Doing stuff which takes a while")
   (sleep 1000)
   1))

(p/let [a (do-stuff)
        b (inc a)
        c (do-stuff)
        d (+ b c)]
  (prn d))
$ nbb prom.cljs
Doing stuff which takes a while
Doing stuff which takes a while
3

Also see API docs.

Js-interop

Since nbb v0.0.75 applied-science/js-interop is available:

(ns example
  (:require [applied-science.js-interop :as j]))

(def o (j/lit {:a 1 :b 2 :c {:d 1}}))

(prn (j/select-keys o [:a :b])) ;; #js {:a 1, :b 2}
(prn (j/get-in o [:c :d])) ;; 1

Most of this library is supported in nbb, except the following:

  • destructuring using :syms
  • property access using .-x notation. In nbb, you must use keywords.

See the example of what is currently supported.

Examples

See the examples directory for small examples.

Also check out these projects built with nbb:

API

See API documentation.

Migrating to shadow-cljs

See this gist on how to convert an nbb script or project to shadow-cljs.

Build

Prequisites:

  • babashka >= 0.4.0
  • Clojure CLI >= 1.10.3.933
  • Node.js 16.5.0 (lower version may work, but this is the one I used to build)

To build:

  • Clone and cd into this repo
  • bb release

Run bb tasks for more project-related tasks.

Download Details:
Author: borkdude
Download Link: Download The Source Code
Official Website: https://github.com/borkdude/nbb 
License: EPL-1.0

#node #javascript

Fredy  Larson

Fredy Larson

1595059664

How long does it take to develop/build an app?

With more of us using smartphones, the popularity of mobile applications has exploded. In the digital era, the number of people looking for products and services online is growing rapidly. Smartphone owners look for mobile applications that give them quick access to companies’ products and services. As a result, mobile apps provide customers with a lot of benefits in just one device.

Likewise, companies use mobile apps to increase customer loyalty and improve their services. Mobile Developers are in high demand as companies use apps not only to create brand awareness but also to gather information. For that reason, mobile apps are used as tools to collect valuable data from customers to help companies improve their offer.

There are many types of mobile applications, each with its own advantages. For example, native apps perform better, while web apps don’t need to be customized for the platform or operating system (OS). Likewise, hybrid apps provide users with comfortable user experience. However, you may be wondering how long it takes to develop an app.

To give you an idea of how long the app development process takes, here’s a short guide.

App Idea & Research

app-idea-research

_Average time spent: two to five weeks _

This is the initial stage and a crucial step in setting the project in the right direction. In this stage, you brainstorm ideas and select the best one. Apart from that, you’ll need to do some research to see if your idea is viable. Remember that coming up with an idea is easy; the hard part is to make it a reality.

All your ideas may seem viable, but you still have to run some tests to keep it as real as possible. For that reason, when Web Developers are building a web app, they analyze the available ideas to see which one is the best match for the targeted audience.

Targeting the right audience is crucial when you are developing an app. It saves time when shaping the app in the right direction as you have a clear set of objectives. Likewise, analyzing how the app affects the market is essential. During the research process, App Developers must gather information about potential competitors and threats. This helps the app owners develop strategies to tackle difficulties that come up after the launch.

The research process can take several weeks, but it determines how successful your app can be. For that reason, you must take your time to know all the weaknesses and strengths of the competitors, possible app strategies, and targeted audience.

The outcomes of this stage are app prototypes and the minimum feasible product.

#android app #frontend #ios app #minimum viable product (mvp) #mobile app development #web development #android app development #app development #app development for ios and android #app development process #ios and android app development #ios app development #stages in app development