text:
<file_sep>{% extends 'base.html.twig' %}

{% block title %}Edit Company
{% endblock %}

{% block body %}{% endblock %}

{% block main %}

Are you sure you want to delete?

This change is
            permanent
            and cannot be undone.

        <form method="post" action="{{ path('company_delete', {'id': company.id}) }}">
            <input type="hidden" name="_method" value="DELETE">
            <input type="hidden" name="_token" value="{{ csrf_token('delete' ~ company.id) }}">
            <button class="btn btn-danger">Delete</button>
        </form>

            <button class="btn btn-success">
                Cancel</button>

        {% endblock %}
<file_sep># Symfony Project

Atrinium Technical Test Project

### Start the project

In order to initialize the project for the first time, the init script must be executed.

```
./docker/scripts/init.sh
```

### Build the data

Builds the data once it has been initially installed

```
./docker/scripts/up.sh
```

### Deploy

When we lift the project we are going to have a series of lifted containers:

- php - PHP-FPM container
- mysql - Database manager container
- adminer - Client for the connection to the database container
- nginx - Web server container

### Database manager

Adminer is a thin client for database management systems, if for any reason
you wish to access the database, you can access it through this client.

- http://localhost:8085
- user: root
- password: <PASSWORD>
- db: symfony_projects

## Run the application

- http://localhost

## Author

- <NAME>
<file_sep><?php

namespace App\Services;

use App\Entity\Sector;
use App\Repository\SectorRepositoryInterface;
use App\Factories\FactoryInterface;
use App\Factories\EntityFactory;
use App\Exceptions\SectorException;

class SectorService
{
    public function __construct(
        SectorRepositoryInterface $sectorRepository,
        FactoryInterface $entityFactory
    ) {
        $this->sectorRepository = $sectorRepository;
        $this->entityFactory = $entityFactory;
    }

    public function get(): array
    {
        return $this->sectorRepository->get();
    }

    public function save(string $name)
    {
        $sector = $this->findByName($name);

        if ($sector) {
            $name = $sector->getName();
            throw new SectorException('The entity ' . $name . ' already exists');
        }

        $sector = $this->entityFactory->getInstance('sector');
        $this->sectorRepository->save($sector);
    }

    public function update(Sector $sector): void
    {
        $id = $sector->getId();
        $sectorCollection = $this->getCurrentSector($id);

        if (empty($sectorCollection)) {
            throw new SectorException('The entity ' . $id . ' does not exist');
        }

        $this->sectorRepository->update($sector);
    }

    public function remove(Sector $sector): void
    {
        $id = $sector->getId();
        $sectorCollection = $this->getCurrentsector($id);

        if (empty($sectorCollection)) {
            throw new SectorException('The entity ' . $id . ' does not exist');
        }

        $this->sectorRepository->remove($sector);
    }

    private function getCurrentSector(string $id): ?Sector
    {
        return $this->findById($id);
    }

    private function findById(string $id): ?Sector
    {
        return $this->sectorRepository->findById($id);
    }

    private function findByName(string $name): ?Sector
    {
        return $this->sectorRepository->findByName($name);
    }
}
<file_sep>#!/bin/bash

cd symfony_project

echo "Hacemos la actualización del composer"
composer update
sleep 5

echo "Hacemos la instalación del composer"
composer install
sleep 5

echo "Hacemos la instalacion de npm"
npm install
sleep 5

echo "Levantamos los dockers"
cd ..
docker-compose up
sleep 5
<file_sep><?php

namespace App\Controller;

use App\Entity\Sector;
use App\Form\SectorType;
use App\Repository\SectorRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Services\SectorService;
use App\Factories\FactoryInterface;
use App\Factories\EntityFactory;

/**
 * @Route("/sector")
 */
class SectorController extends AbstractController
{
    public function __construct(SectorService $sectorService, FactoryInterface $entityFactory)
    {
        $this->sectorService = $sectorService;
        $this->entityFactory = $entityFactory;
    }
    /**
     * @Route("/", name="sector_index", methods={"GET"})
     */
    public function index(SectorRepository $sectorRepository): Response
    {
        $sectors = $this->sectorService->get();
        return $this->render('sector/index.html.twig', [
            'sectors' => $sectors,
        ]);
    }

    /**
     * @Route("/new", name="sector_new", methods={"GET","POST"})
     */
    public function new(Request $request): Response
    {
        $sector = $this->entityFactory->getInstance('sector');
        $form = $this->createForm(SectorType::class, $sector);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $name = $this->getRequestEntityName($request);
            $this->sectorService->save($name);
            return $this->redirectToRoute('sector_index');
        }

        return $this->render('sector/new.html.twig', [
            'sector' => $sector,
            'form' => $form->createView(),
        ]);
    }

    /**
     * @Route("/{id}", name="sector_show", methods={"GET"})
     */
    public function show(Sector $sector): Response
    {
        return $this->render('sector/show.html.twig', [
            'sector' => $sector,
        ]);
    }

    /**
     * @Route("/{id}/edit", name="sector_edit", methods={"GET","POST"})
     */
    public function edit(Request $request, Sector $sector): Response
    {
        $form = $this->createForm(SectorType::class, $sector);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $this->sectorService->update($sector);
            return $this->redirectToRoute('sector_index');
        }

        return $this->render('sector/edit.html.twig', [
            'sector' => $sector,
            'form' => $form->createView(),
        ]);
    }

    /**
     * @Route("/{id}", name="sector_delete", methods={"DELETE"})
     */
    public function delete(Request $request, Sector $sector): Response
    {
        if ($this->isCsrfTokenValid('delete'.$sector->getId(), $request->request->get('_token'))) {
            $this->sectorService->remove($sector);
        }

        return $this->redirectToRoute('sector_index');
    }

    /**
    * @Route("/{id}/delete", name="sector_form_render", methods={"GET","POST"})
    */
    public function renderFormDelete(Sector $sector)
    {
        return $this->render('sector/_delete_form.html.twig', ['sector' => $sector]);
    }

    private function getRequestEntityName(Request $request): string
    {
        return $request->request->get('sector')['name'];
    }
}
<file_sep>#!/bin/bash

cd symfony_project

# echo "Entramos en el docker"
# docker exec -it php_symfony_project /bin/sh
# sleep 3

echo "Creamos nuestra base de datos"
docker exec -it php_symfony_project php bin/console doctrine:database:create

echo "Creamos las migraciones necesarias"
docker exec -it php_symfony_project php bin/console make:migration
sleep 3

echo "Ejecutamos las migraciones"
docker exec -it php_symfony_project php bin/console doctrine:migrations:migrate
sleep 3

echo "Rellenamos la base de datos"
docker exec -it php_symfony_project php bin/console doctrine:fixtures:load
<file_sep><?php

namespace App\Controller;

use App\Entity\Company;
use App\Form\CompanyType;
use App\Repository\CompanyRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Services\CompanyService;
use App\Factories\FactoryInterface;
use App\Factories\EntityFactory;

/**
 * @Route("/company")
 */
class CompanyController extends AbstractController
{
    public function __construct(CompanyService $CompanyService, FactoryInterface $entityFactory)
    {
        $this->companyService = $CompanyService;
        $this->entityFactory = $entityFactory;
    }
    /**
     * @Route("/", name="company_index", methods={"GET"})
     */
    public function index(CompanyRepository $companyRepository): Response
    {
        $companies = $this->companyService->get();
        $sectorArray = $this->buildSectorArray($companies);
        return $this->render('company/index.html.twig', [
            'companies' => $companies,
            'sector' => $sectorArray
        ]);
    }

    /**
     * @Route("/new", name="company_new", methods={"GET","POST"})
     */
    public function new(Request $request): Response
    {
        $company = $this->entityFactory->getInstance('company');
        $form = $this->createForm(CompanyType::class, $company);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $name = $this->getRequestEntityName($request);
            $this->companyService->save($name);
            return $this->redirectToRoute('company_index');
        }

        return $this->render('company/new.html.twig', [
            'company' => $company,
            'form' => $form->createView(),
        ]);
    }

    /**
     * @Route("/{id}", name="company_show", methods={"GET"})
     */
    public function show(Company $company): Response
    {
        return $this->render('company/show.html.twig', [
            'company' => $company,
        ]);
    }

    /**
     * @Route("/{id}/edit", name="company_edit", methods={"GET","POST"})
     */
    public function edit(Request $request, Company $company): Response
    {
        $form = $this->createForm(CompanyType::class, $company);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $this->companyService->update($company);
            return $this->redirectToRoute('company_index');
        }

        return $this->render('company/edit.html.twig', [
            'company' => $company,
            'form' => $form->createView(),
        ]);
    }

    /**
     * @Route("/{id}", name="company_delete", methods={"DELETE"})
     */
    public function delete(Request $request, Company $company): Response
    {
        if ($this->isCsrfTokenValid('delete'.$company->getId(), $request->request->get('_token'))) {
            $this->companyService->remove($company);
        }

        return $this->redirectToRoute('company_index');
    }

    /**
     * @Route("/{id}/delete", name="company_form_render", methods={"GET","POST"})
     */
    public function renderFormDelete(Company $company)
    {
        return $this->render('company/_delete_form.html.twig', ['company' => $company,]);
    }

    private function buildSectorArray(array $companies)
    {
        return array_map(function ($company) {
            return $company->getSector()->getName();
        }, $companies);
    }

    private function getRequestEntityName(Request $request): string
    {
        return $request->request->get('company')['name'];
    }
}
<file_sep>{% extends 'base.html.twig' %}

{% block title %}Company index
{% endblock %}

{% block body %}{% endblock %}

{% block main %}

            <button class="btn btn-success">
                New</button>

    {{ include('components/table/table-companies/table-companies.html.twig') }}
{% endblock %}
<file_sep>{% extends "components/table/table.html.twig" %}

{% block thead %}

        Id
        Name
        Phone number
        Email
        Sector
        Actions

{% endblock %}

{% block tbody %}
    {% for id, company in companies %}

            {{ company.id }}
            {{ company.name }}
            {{ company.phone }}
            {{ company.email }}
            {{ sector[id] }}

                    <button class="btn btn-secondary">
                        Edit</button>

                    <button class="btn btn-danger">
                        Delete</button>

    {% endfor %}
{% endblock %}
<file_sep><?php

namespace App\Factories;

use App\Entity\Company;
use App\Entity\Sector;

class EntityFactory implements FactoryInterface
{
    public function __construct(string $message = '')
    {
        $this->instancesArray = $this->loadInstancesArray();
    }

    private function loadInstancesArray(): array
    {
        return ['company' => new Company(),
                'sector' => new Sector()];
    }

    public function getInstance(string $instanceName): object
    {
        return $this->instancesArray[$instanceName];
    }
}
<file_sep><?php

namespace App\Repository;

use App\Entity\Sector;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Persistence\ManagerRegistry;

/**
 * @method Sector|null find($id, $lockMode = null, $lockVersion = null)
 * @method Sector|null findOneBy(array $criteria, array $orderBy = null)
 * @method Sector[]    findAll()
 * @method Sector[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
 */
class SectorRepository extends ServiceEntityRepository implements SectorRepositoryInterface
{
    public function __construct(ManagerRegistry $em)
    {
        parent::__construct($em, Sector::class);

        $this->managerRegistry = $em;
    }

    public function get(): array
    {
        return $this->findAll();
    }

    public function findById(string $id): ?Sector
    {
        return $this->find($id);
    }

    public function findByName(string $name): ?Sector
    {
        return $this->findOneBy([
            'name' => $name
        ]);
    }

    public function save(Sector $sector): void
    {
        $entityManager = $this->managerRegistry->getManagerForClass(get_class($sector));
        $entityManager->persist($sector);
        $entityManager->flush();
    }

    public function update(Sector $sector): void
    {
        $entityManager = $this->managerRegistry->getManagerForClass(get_class($sector));
        $entityManager->flush();
    }

    public function remove(Sector $sector): void
    {
        $entityManager = $this->managerRegistry->getManagerForClass(get_class($sector));
        $entityManager->remove($sector);
        $entityManager->flush();
    }
}
<file_sep>{% extends 'base.html.twig' %}

{% block title %}Edit Company
{% endblock %}

{% block body %}{% endblock %}

{% block main %}

Edit Sector

    {{ include('sector/_form.html.twig', {'button_label': 'Update'}) }}

        <button class="btn btn-success">
            Cancel</button>

{% endblock %}
<file_sep><?php

namespace App\Factories;

interface FactoryInterface
{
    public function getInstance(string $instanceName): object;
}
<file_sep>{% extends "components/table/table.html.twig" %}

{% block thead %}

        Id
        Name
        Actions

{% endblock %}

{% block tbody %}
    {% for sector in sectors %}

            {{ sector.id }}
            {{ sector.name }}

                    <button class="btn btn-secondary">
                        Edit</button>

                    <button class="btn btn-danger">
                        Delete</button>

    {% endfor %}
{% endblock %}
<file_sep><?php

namespace App\Services;

use App\Entity\Company;
use App\Repository\CompanyRepositoryInterface;
use App\Factories\FactoryInterface;
use App\Factories\EntityFactory;
use App\Exceptions\CompanyException;

class CompanyService
{
    public function __construct(
        CompanyRepositoryInterface $companyRepository,
        FactoryInterface $entityFactory
    ) {
        $this->companyRepository = $companyRepository;
        $this->entityFactory = $entityFactory;
    }

    public function get(): array
    {
        return $this->companyRepository->get();
    }

    public function save(string $name)
    {
        $company = $this->findByName($name);

        if ($company) {
            $name = $company->getName();
            throw new CompanyException('The entity ' . $name . ' already exists');
        }

        $company = $this->entityFactory->getInstance('company');
        $this->companyRepository->save($company);
    }

    public function update(Company $company): void
    {
        $id = $company->getId();
        $companyCollection = $this->getCurrentCompany($id);

        if (empty($companyCollection)) {
            throw new CompanyException('The entity ' . $id . ' does not exist');
        }

        $this->companyRepository->update($company);
    }

    public function remove(Company $company): void
    {
        $id = $company->getId();
        $companyCollection = $this->getCurrentCompany($id);

        if (empty($companyCollection)) {
            throw new CompanyException('The entity ' . $id . ' does not exist');
        }

        $this->companyRepository->remove($company);
    }

    private function getCurrentCompany(string $id): ?Company
    {
        return $this->findById($id);
    }

    private function findById(string $id): ?Company
    {
        return $this->companyRepository->findById($id);
    }

    private function findByName(string $name): ?Company
    {
        return $this->companyRepository->findByName($name);
    }
}
<file_sep><?php

namespace App\Repository;

use App\Entity\Company;

interface CompanyRepositoryInterface
{
    public function get(): array;
    public function findById(string $id): ?Company;
    public function findByName(string $name): ?Company;
    public function save(Company $company): void;
    public function update(Company $company): void;
    public function remove(Company $company): void;
}
<file_sep> #!/bin/bash

docker exec -d  php_symfony_project php bin/console $1

exit

<file_sep>{% extends 'base.html.twig' %}

{% block title %}Hello InitialController!
{% endblock %}

{% block body %}{% endblock %}

{% block main %}

Welcome to the atrinium technical test

{% endblock %}
<file_sep><?php

namespace App\Repository;

use App\Entity\Sector;

interface SectorRepositoryInterface
{
    public function get(): array;
    public function findById(string $id): ?Sector;
    public function findByName(string $name): ?Sector;
    public function save(Sector $company): void;
    public function update(Sector $company): void;
    public function remove(Sector $company): void;
}
<file_sep>{% extends 'base.html.twig' %}

{% block title %}Company index
{% endblock %}

{% block body %}{% endblock %}

{% block main %}

Create new Sector

    {{ include('sector/_form.html.twig') }}

    back to list
{% endblock %}
<file_sep><?php

namespace App\DataFixtures;

use App\Entity\Company;
use App\Entity\Sector;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;

class AppFixtures extends Fixture
{
    public function load(ObjectManager $manager)
    {
        $sectorIntances = [];
        $sectorCollection = $this->loadSectors();
        $companyCollection = $this->loadCompanies();

        foreach ($sectorCollection as $sector) {
            $sectorEntity = new Sector();
            $sectorEntity->setName($sector['name']);
            $manager->persist($sectorEntity);
            $sectorIntances[] = $sectorEntity;
        }

        foreach ($companyCollection as $key => $company) {
            $companyEntity = new Company();
            $companyEntity->setName($company['name']);
            $companyEntity->setPhone($company['phone']);
            $companyEntity->setEmail($company['email']);

            ($key <= 7)
            ? $companyEntity->setSector($sectorIntances[0])
            : $companyEntity->setSector($sectorIntances[1]);

            $manager->persist($companyEntity);
        }

        $manager->flush();
    }

    private function loadSectors()
    {
        return [
            ['name' => 'IT'],
            ['name' => 'Marketing']
        ];
    }

    private function loadCompanies()
    {
        return [
            ['name' => 'Atrinium', 'phone' => '951204565','email' => '<EMAIL> '],
            ['name' => 'OnePlus', 'phone' => '951235665','email' => '<EMAIL> '],
            ['name' => 'Oracle', 'phone' => '958364565','email' => '<EMAIL> '],
            ['name' => 'VoiceWork', 'phone' => '951672139','email' => '<EMAIL> '],
            ['name' => 'Accenture', 'phone' => '951612565','email' => '<EMAIL> '],
            ['name' => 'Pramerica', 'phone' => '953454895','email' => '<EMAIL> '],
            ['name' => 'Indra', 'phone' => '951223565','email' => '<EMAIL> '],
            ['name' => 'Archer', 'phone' => '953878265','email' => '<EMAIL> '],
            ['name' => 'Deloitte', 'phone' => '951567124','email' => '<EMAIL> '],
            ['name' => 'RealWorld', 'phone' => '954564565','email' => '<EMAIL> '],
            ['name' => 'Osborne', 'phone' => '954564892','email' => '<EMAIL> '],
            ['name' => 'Glandore', 'phone' => '953124765','email' => '<EMAIL> '],
            ['name' => 'Prosperiry', 'phone' => '957844325','email' => '<EMAIL> '],
            ['name' => 'Pharma', 'phone' => '955874249','email' => '<EMAIL> '],
            ['name' => 'PeGlobal', 'phone' => '956734823','email' => '<EMAIL> '],
        ];
    }
}

languages: Twig Markdown Shell PHP

repo_language: Twig

repo_name: Antoniojesusv/atrinium-technial-test


text:
<repo_name>wisegrowth/wisebot-button<file_sep>/index.js
const wpi = require('wiringpi-node')
wpi.setup('wpi')
const configPin = 25

wpi.pinMode(configPin, wpi.INPUT);
wpi.pullUpDnControl(configPin, wpi.PUD_UP);

const Led = require('./led')
const axios = require('axios')
const Logger = require('wg-logger')

const homedir = require('os').homedir
const join = require('path').join

//TODO: check below line for use absolute path instead homedir method
// const logPath = join(homedir(), '.wisebot', 'logs', 'button.log')
const logPath = '/home/pi/.wisebot/logs/button.log'
Logger.config(logPath)

Logger.info('running service')

const OPERATOR_URL = 'http://localhost:5000'
const BLE_URL = 'http://localhost:5010'

const STOP_OPERATOR_PATH = 'service-stop'
const START_OPERATOR_PATH = 'service-start'
const HEALTHZ_PATH = 'healthz'
const START_ADVERTISING_PATH = 'start'
const STOP_ADVERTISING_PATH = 'stop'

const WISEBOT_CORE_SERVICE = 'wisebot-core'
const BLE_SERVICE = 'wisebot-ble'

const RUNNING_STATUS = 'running'
const SUCCEED_STATUS = 'succeed'

function bluetoothMode () {
  return new Promise((resolve, reject) => {
    let healthzData = null

    Logger.info('loading bluetooth mode')
    axios.get(`${OPERATOR_URL}/${HEALTHZ_PATH}`).catch((err) => Logger.warn(`error in Operator [GET] ${OPERATOR_URL}/${HEALTHZ_PATH} path`))
      .then(({data}) => healthzData = data)
      .then(() => {
        Logger.info('3E')
        const core = healthzData.data.services.find((service) => service.name === WISEBOT_CORE_SERVICE)

        if (core === undefined) {
          Logger.info('wisebot-core service is not found')
        }

        if (core && (core.status === RUNNING_STATUS || core.status === SUCCEED_STATUS)) {
          return axios.post(`${OPERATOR_URL}/${STOP_OPERATOR_PATH}`, {name: WISEBOT_CORE_SERVICE}).catch((err) => Logger.warn(`error in operator [POST] ${OPERATOR_URL}/${STOP_OPERATOR_PATH} path with ${WISEBOT_CORE_SERVICE} service`))
        } else {
          Logger.warn('core service status when get operator healthz', {status: core.status})
        }

        Logger.info('here in pushButton.watch', {status: core.status})
        return
      })
      // .then(() => {Logger.info('4E') return Led.disconnected({lock: false}).catch((err) => console.error(err))})
      .then(() => {
        Logger.info('6E')
        const ble = healthzData.data.services.find((service) => service.name === BLE_SERVICE)

        if (ble === undefined) {
          Logger.info('wisebot-ble service is not found')
        }

        if (ble && (ble.status === RUNNING_STATUS || ble.status === SUCCEED_STATUS)) {
          Logger.info('1111 fuck the police')
          return axios.post(`${BLE_URL}/${START_ADVERTISING_PATH}`).catch((err) => Logger.warn('Error in start advertising POST in ble service', {error: err}))
        } else {
          Logger.warn('BLE service status when get operator healthz', {status: ble.status})
        }
      })
      // .then(() => {Logger.info('8E') return Led.connected({lock: false}).catch((err) => Logger.error(err))})
      .then(() => resolve())
      .catch((err) => {
        Led.error({lock: false}).catch((err) => Logger.warn('Error in led error color', {error: err}))
        reject(err)
      })
  })
}

function revertBluetoothMode () {
  console.log(333222)
  return new Promise((resolve, reject) => axios.post(`${BLE_URL}/${STOP_ADVERTISING_PATH}`)
    .then(() => axios.post(`${OPERATOR_URL}/${START_OPERATOR_PATH}`, {name: WISEBOT_CORE_SERVICE}))
    .then(resolve)
    .catch((err) => {
      Logger.info('error revertBluetoothMode', {error: err})
      Led.error({lock: false}).catch((err) => Logger.warn('Error in led error color', {error: err}))
      reject(err)
    })
  )
}

//TODO: get pin value from wisebot config.json file
//var configPin = 25 //equivalent to GPIO26 or PIN37 in RaspberyPI 2 B+

let blocked = false
let delta = 0
let startTimestamp = new Date()
let bluetoothModeFlag = false
let state = false

wpi.wiringPiISR(configPin, wpi.INT_EDGE_FALLING, (delta) => {
  Logger.info('lalalal', delta)
  return

  if (blocked) {
    Logger.info('blocked button interaction')
    return
  }

  blocked = true

  if (wpi.digitalRead(configPin)) {
     Logger.info(111)
    startTimestamp = new Date()
  } else {
    Logger.info(222)
    endTimestamp = new Date()
    delta = endTimestamp.getTime() - startTimestamp.getTime()

    const threshold = 30
    if (delta < threshold) {
      blocked = false
      return Logger.info('repetition button interaction', {delta, threshold})
    }

    const bluetoothDelay = 10000
    const revertDelay = 15000

    if (!bluetoothModeFlag) {
      if (delta >= bluetoothDelay) {
        return bluetoothMode()
          .then(() => {
            Logger.info('bluetooth mode is succefull', {delta, bluetoothDelay})
            blocked = false
            bluetoothModeFlag = true
          })
          .catch((err) => {
            Logger.info('catch at call bluetoothMode method', {delta, bluetoothDelay})
            blocked = false
            bluetoothModeFlag = false
          })
      } else if (delta < bluetoothDelay) {
        Logger.info(`pressed button ${delta} milliseconds`, {delta, bluetoothDelay})
      }
    } else {
      if (delta >= revertDelay) {
        return revertBluetoothMode()
          .then(() => {
            Logger.info('revert bluetooth mode is succefull', {delta, revertDelay})
            blocked = false
            bluetoothModeFlag = false
          })
          .catch(() => {
            Logger.info('catch at call revertBluetoothMode method', {delta, revertDelay})
            blocked = false
            bluetoothModeFlag = true
          })
      } else {
        Logger.info('wisebot-button is already in bluetooth mode, press and hold button 5 seconds for revert mode', {delta, revertDelay})
      }
    }
  }

  blocked = false
})

//process event listener for SIGTERM and SIGINT events
process.on('SIGTERM', () => Logger.warn('SIGTERM received'))
process.on('SIGINT', () => {
  Logger.debug('SIGINT received')
  wpi.wiringPiISRCancel(configPin)
})
<file_sep>/Makefile
APP=wisebot-button

VERSION=1.1.0
TEST_WISEBOT_IP=wisebot.local
TEST_WISEBOT_SSH_PORT=5555

GO ?= go

pi: clean
	@echo "[pi] Building..."
	@GOOS=linux GOARM=7 GOARCH=arm $(GO) build -o $(APP)\
		-ldflags "-X github.com/WiseGrowth/go-wisebot/logger.environment=production"

build b: clean
	@echo "[pi] Building..."
	@$(GO) build -o $(APP)-darwin \
		-ldflags "-X github.com/WiseGrowth/go-wisebot/logger.environment=production"

run r: build
	@echo "[run] Running..."
	@$(APP)

clean:
	@echo "[clean] Removing $(APP)..."
	@rm -rf $(APP)

upload:
	@echo "[upload] Starting..."
	@scp -P $(TEST_WISEBOT_SSH_PORT) $(APP) pi@$(TEST_WISEBOT_IP):~/$(APP)
	@echo "[upload] Done"

deploy: pi upload

.PHONY: pi build clean upload deploy run
<file_sep>/led.js
const axios = require('axios')
const Logger = require('wg-logger')

const {join} = require('path')
const {homedir} = require('os')

const configPath = join('/home', 'pi', '.config', 'wisebot', 'config')
const config = require(configPath)

const DEFAULT_RETRIES = 100
const TIMEOUT = 5000
const DELAY = 2000

const FAILED_AFTER_RETRIES_ERROR = new Error('could not deliver message after all retries')
const FAILED_ERROR = new Error('Request failed but did not timed out')

const LedClient = {
  connected (params = {}, retries = DEFAULT_RETRIES) { return this.sendStatus('connected', params, retries) },
  disconnected (params = {}, retries = DEFAULT_RETRIES) { return this.sendStatus('disconnected', retries) },
  reconnecting (retries = DEFAULT_RETRIES) { return this.sendStatus('reconnecting', retries) },
  ready (retries = DEFAULT_RETRIES) { return this.sendStatus('ready', retries) },
  error (retries = DEFAULT_RETRIES) { return this.sendStatus('error', retries) },
  action (retries = DEFAULT_RETRIES) { return this.sendStatus('action', retries) },

  sendStatus (status, params, retries) {
    return new Promise((resolve, reject) => {
      let interval
      let response
      let currentTry = 1

      const {lock} = params
      const lockValue = (lock !== undefined) ? params.lock : false

      const payload = {
        status,
        timestamp: new Date().toISOString(),
        lock: lockValue,
      }

      const perform = () => axios.create(this.defaultOpts()).post('/ble-status', payload)

      perform()
        .then((res) => response = res)
        .then(() => clearInterval(interval))
        .then(() => resolve(response))
        .catch((err) => {
          if (err) {
            if (err.code !== 'ECONNREFUSED') {
              Logger.warn(`Led service not up when trying to send status: ${status} - ${err.message}`)
            } else if (err.code !== 'ECONNABORTED') {
              Logger.warn(`Led service timed out for the first time - ${err.message}`)
            } else {
              Logger.error('Error in promise catch on perform#Led', {error: err})
              return reject(FAILED_ERROR)
            }
          }

          const retry = () => {
            perform()
              .then((res) => response = res)
              .then(() => clearInterval(interval))
              .then(() => resolve(response))
              .catch((err) => {
                if (err) {
                  if (err.code !== 'ECONNREFUSED') {
                    Logger.warn(`Led service not up when trying to send status: ${status} - ${err.message}`)
                  } else if (err.code !== 'ECONNABORTED') {
                    Logger.warn(`Led service timed out for ${currentTry} time - ${err.message}`)
                  } else {
                    Logger.error('Error in promise catch on perform#Led', {error: err})
                    clearInterval(interval)
                    return reject(FAILED_ERROR)
                  }
                }

                if (currentTry > retries) {
                  Logger.debug(`Stop retrying after ${currentTry} times`)
                  clearInterval(interval)
                  return reject(FAILED_AFTER_RETRIES_ERROR)
                }

                currentTry++
                Logger.debug(`Retrying '${status}' request for the ${currentTry} time`)
              })
          }

          interval = setInterval(retry, TIMEOUT + DELAY)
        })
    })
  },

  defaultOpts () {
    return {
      baseURL: config.led_api_url,
      timeout: TIMEOUT,
      headers: {'Content-Type': 'application/json'},
    }
  },
}

module.exports = LedClient
<file_sep>/main.go
package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"syscall"
	"time"

	"github.com/WiseGrowth/go-wisebot/config"
	"github.com/WiseGrowth/go-wisebot/logger"
	"github.com/brian-armstrong/gpio"
	homedir "github.com/mitchellh/go-homedir"
)

const (
	basePath             = "/home/pi/"
	wisebotConfigPath    = basePath + ".config/wisebot/config.json"
	wisebotButtonLogPath = basePath + ".wisebot/logs/button.log"

	bluetoothDelay = 4000

	operatorURL          = "http://localhost:5000/"
	operatorHealthz      = operatorURL + "healthz"
	operatorStartService = operatorURL + "service-start"
	operatorStopService  = operatorURL + "service-stop"

	bleService          = "wisebot-ble"
	bleURL              = "http://localhost:5010/"
	bleStartAdvertising = bleURL + "start"
	bleStopAdvertising  = bleURL + "stop"

	coreService = "wisebot-core"

	//get from operator command
	runningStatus = "running"
	succeedStatus = "succeed"
	errorStatus   = "error"
	crashedStatus = "crashed"
	stoppedStatus = "stopped"
)

var (
	wisebotLogger   io.WriteCloser
	wisebotConfig   *config.Config
	watcher         *gpio.Watcher
	start           time.Time
	blocked         bool
	isBluetoothMode bool
)

type operatorHealthzResponse struct {
	Data operatorHealthzData `json:"data"`
}

type operatorHealthzData struct {
	Services []*operatorHealthzServices `json:"services"`
}
type operatorHealthzServices struct {
	Name   string `json:"name"`
	Status string `json:"status"`
}

type operatorService struct {
	Name string `json:"name"`
}

func main() {
	var err error

	// ----- Load logger
	wisebotLogger, err = NewFile(wisebotButtonLogPath)
	check(err)
	defer wisebotLogger.Close()

	// ----- Load wisebot config
	wisebotConfig, err = config.LoadConfig(wisebotConfigPath)
	check(err)

	// ----- Init logger
	err = logger.Init(wisebotLogger, wisebotConfig.WisebotID, wisebotConfig.SentryDSN)
	if err != nil {
		check(err)
	}

	fmt.Println("lalalalal")

	watcher = gpio.NewWatcher()
	watcher.AddPin(26)

	// 99 number was used as a number that refers to the first case, nil would
	// be used but the watcher.Watch () method returns a value of type uint
	lastValue := uint(99)

	blocked = false
	isBluetoothMode = false
	quit := make(chan struct{})

	go func() {
		for {
			if blocked {
				logger.GetLogger().Info("wisebot-button is blocked")
				continue
			}
			blocked = true

			// ----- Load wisebot config
			wisebotConfig, err = config.LoadConfig(wisebotConfigPath)
			if err != nil {
				logger.GetLogger().Error("error at read wisebot config")
				blocked = false
				continue
			}

			firstTime := wisebotConfig.FirstTime
			if firstTime {
				logger.GetLogger().Info("wisebot has firstTime value with true")
				blocked = false
				continue
			}

			//get value from gpio pin
			_, value := watcher.Watch()

			//first time situation
			if lastValue == 99 {
				lastValue = value
			}

			//use cases of button
			if lastValue == 0 && value == 0 {
				logger.GetLogger().Info("omit error situation 0-0")
			} else if lastValue == 1 && value == 1 {
				logger.GetLogger().Info("omit error situation 1-1")
			} else if lastValue == 0 && value == 1 {
				logger.GetLogger().Info("situation 0-1")
				start = time.Now()
			} else if lastValue == 1 && value == 0 {
				logger.GetLogger().Info("situation 1-0")

				d2 := int64(time.Since(start)) / int64(time.Millisecond)
				logger.GetLogger().Info("pushed elapsed time ", d2)

				if d2 > bluetoothDelay {
					logger.GetLogger().Info("fetch to operator service ", d2, "ms")

					healthz := new(operatorHealthzResponse)
					err := getHTTP(operatorHealthz, healthz)
					if err != nil {
						//TODO: check this problem
						logger.GetLogger().Error(err)
						// return
					}

					if !isBluetoothMode {
						err := bluetoothMode(healthz.Data)
						if err != nil {
							logger.GetLogger().Error(err)
						} else {
							isBluetoothMode = true
						}
					} else {
						err := normalMode(healthz.Data)
						if err != nil {
							logger.GetLogger().Error(err)
						} else {
							isBluetoothMode = false
						}
					}
				}
			}

			lastValue = value
			blocked = false
		}
	}()

	listenInterrupt(quit)
	<-quit
	gracefullShutdown()
}

func bluetoothMode(healthz operatorHealthzData) error {
	var coreStatus string

	var bleStatus string

	//found wisebot-core service and get our status
	for _, value := range healthz.Services {
		logger.GetLogger().Info("service ", value.Name, value.Status)

		if value.Name == coreService {
			coreStatus = value.Status
			break
		}
	}

	// TODO: should not happen this
	if coreStatus == "" {
		err := errors.New(coreService + " is not found in operator healthz services")
		logger.GetLogger().Error(err)
		return err
	}

	//stop wisebot-core service
	if coreStatus == runningStatus || coreStatus == succeedStatus {
		stopServicePayload := new(operatorService)
		stopServicePayload.Name = coreService
		err := postHTTP(operatorStopService, stopServicePayload)
		if err != nil {
			//TODO: wrong behavior, maybe should be reset operator service
			logger.GetLogger().Error(err)
			return err
		}
	} else {
		//TODO: wrong behavior, maybe should be reset operator service
		err := errors.New(coreService + " service could not be stopped. status: " + coreStatus)
		logger.GetLogger().Warn(err)
		//return err
	}

	//found wisebot-ble service and get our status
	for _, value := range healthz.Services {
		logger.GetLogger().Info("service ", value.Name, value.Status)

		if value.Name == bleService {
			bleStatus = value.Status
			break
		}
	}

	// TODO: should not happen this
	if bleStatus == "" {
		err := errors.New(bleService + " is not found in operator healthz services")
		logger.GetLogger().Error(err)
		return err
	}

	// start ble advertising
	if bleStatus == runningStatus || bleStatus == succeedStatus {
		err := postHTTP(bleStartAdvertising, struct{}{})
		if err != nil {
			//TODO: wrong behavior, maybe should be reset operator service
			logger.GetLogger().Error(err)
			return err
		}
	} else {
		//TODO: wrong behavior, maybe should be reset operator service
		err := errors.New(bleService + " service could not be stopped. status: " + bleStatus)
		logger.GetLogger().Warn(err)
		//return err
	}

	return nil
}

func normalMode(healthz operatorHealthzData) error {
	var coreStatus string
	var bleStatus string

	//found wisebot-ble service and get our status
	for _, value := range healthz.Services {
		logger.GetLogger().Info("service ", value.Name, value.Status)

		if value.Name == bleService {
			bleStatus = value.Status
			break
		}
	}

	// TODO: should not happen this
	if bleStatus == "" {
		err := errors.New(coreService + " is not found in operator healthz services")
		logger.GetLogger().Error(err)
		return err
	}

	// stop ble advertising
	if bleStatus == runningStatus || bleStatus == succeedStatus {
		err := postHTTP(bleStopAdvertising, struct{}{})
		if err != nil {
			//TODO: wrong behavior, maybe should be reset operator service
			logger.GetLogger().Error(err)
			return err
		}
	} else {
		//TODO: wrong behavior, maybe should be reset operator service
		err := errors.New(bleService + " service could not be stopped. status: " + bleStatus)
		logger.GetLogger().Warn(err)
		//return err
	}

	//found wisebot-core service and get our status
	for _, value := range healthz.Services {
		logger.GetLogger().Info("service ", value.Name, value.Status)

		if value.Name == coreService {
			coreStatus = value.Status
			break
		}
	}

	// start core service
	if coreStatus == stoppedStatus || coreStatus == succeedStatus {
		stopServicePayload := new(operatorService)
		stopServicePayload.Name = coreService
		err := postHTTP(operatorStartService, stopServicePayload)
		if err != nil {
			//TODO: wrong behavior, maybe should be reset operator service
			logger.GetLogger().Error(err)
			return err
		}
	} else {
		//TODO: wrong behavior, maybe should be reset operator service
		err := errors.New(coreService + " service could not be stopped. status: " + coreStatus)
		logger.GetLogger().Warn(err)
		//return err
	}

	return nil
}

func listenInterrupt(quit chan struct{}) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		s := <-c
		logger.GetLogger().WithField("signal", s.String()).Debug("Signal received")
		quit <- struct{}{}
	}()
}

func gracefullShutdown() {
	watcher.Close()

	log := logger.GetLogger()
	log.Debug("Gracefully shutdown")
	// if err := httpServer.Shutdown(nil); err != nil {
	// 	log.Error(err.Error())
	// }
}

// NewFile load file
func NewFile(name string) (*os.File, error) {
	expanded, err := homedir.Expand(name)
	if err != nil {
		return nil, err
	}
	file, err := os.OpenFile(expanded, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0744)
	if err != nil {
		if os.IsNotExist(err) {
			file, err = os.Create(name)
			if err != nil {
				return nil, err
			}
		} else {
			return nil, err
		}
	}

	return file, err
}

func check(err error) {
	if err != nil {
		log := logger.GetLogger()

		switch (err).(type) {
		case *exec.ExitError:
			e, _ := (err).(*exec.ExitError)
			stderr := bytes.TrimSpace(e.Stderr)
			log.WithField("stderr", string(stderr)).Fatal(err)
		default:
			log.Fatal(err)
		}
	}
}

func getHTTP(url string, data interface{}) error {
	res, err := http.Get(url)
	if err != nil {
		return err
	}

	defer res.Body.Close()
	if res.StatusCode != 200 {
		return errors.New("invalid status code")
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return err
	}

	// fmt.Printf("%s", body)

	err = json.Unmarshal(body, &data)
	if err != nil {
		return err
	}

	return nil
}

func postHTTP(url string, data interface{}) error {
	dataStr, err := json.Marshal(data)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(dataStr))
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	return nil
}

branch_name: refs/heads/master

languages: Makefile JavaScript Go

repo_language: Makefile

repo_name: wisegrowth/wisebot-button


text:
<repo_name>wasmachien75/suggest-offer<file_sep>/print.py
import sys
import traceback

import mast
import control_unit

def main():
    try:
        m = mast.Mast()
        m.getType()
        m.getCable()
        m.getPrint()
        if m.type == "XE":
            c = control_unit.ControlUnit(m.voltage)
            if m.print == "1":
                c.setType()
            c.getCat(m.print)
            s = ""
            if m.print != "1":
                s += " - "+str(m.lines)+"L"
            if c.deadman == True:
                s += " /DF"
            m.acc["Control Unit " + str(m.voltage) + "V" + s] = c.cat

        m.addAccs()

        if m.model == "RRTM-EL":
            if m.cable == "J" and m.print == "1":
                print('{0}'.format(m.cat))
            else:
                print('{0}/{1}{2}L0SG'.format(m.cat,m.cable,m.print))
        elif m.model == "RRTM-ES":
            print('{0}/{1}{2}H0SG'.format(m.cat,m.cable,m.print))
        else:
            if m.cable != "J":
                print('{0}/{1}'.format(m.cat,m.cable)+ " - Mast")
            else:
                print(m.cat, "- Mast")
        for key,value in m.acc.items():
            print(value,"-",key)
        input("When in doubt, ask...")
    except Exception as e:
        print("Error:", e, "\nResetting...\n")
        traceback.print_exc()
        main()
if __name__ == "__main__":
    main()

<file_sep>/lampset.py
class Lampset:
    def __init__(self):
        self.voltage = 0
        self.watts = 0

    def getWatts(self):
        self.voltage = [12,24,230][int(input("Lamp voltage?\n1. 12V\n2. 24V\n3. 230V\n"))-1]
        numOfLamps = int(input("How many lamps?"))
        lampPower = int(input("Power per lamp (W)?"))
        self.watts = numOfLamps * lampPower
        self.amps = (self.watts / self.voltage)
<file_sep>/control_unit.py
class ControlUnit:
    def __init__(self, voltage):
        self.type = "bp"
        self.deadman = False
        self.voltage = voltage

    def setType(self):
        self.type = ["bp","c"][int(input("Type?\n1. Basic Plus\n2. Comfort\n"))-1]
        if input("Deadman?\n1. Yes\n2. No") == "1":
            self.deadman = True

    def getCat(self, prnt):
        print(prnt)
        if prnt == "1":
            if self.type == "bp":
                if self.voltage == 12:
                    self.cat = "27719"
                elif self.voltage == 24:
                    self.cat = "27720"
            elif self.type == "c":
                if self.voltage == 12:
                    self.cat = "27715"
                elif self.voltage == 24:
                    self.cat = "27716"
        else:
            if self.voltage == 12:
                self.cat = cUnit12[int(prnt)-2]
            elif self.voltage == 24:
                self.cat = cUnit24[int(prnt)-2]
        if self.deadman == True:
            self.cat += "/DF"
<file_sep>/mast.py
import lampset
import math
import data

class Mast:
    def __init__(self):
        self.type = None
        self.model = None
        self.cat = None
        self.lines = 0
        self.cable ="J"
        self.print = "1"
        self.rf = False
        self.europe = True
        self.voltage = 0
        self.amps = 0
        self.acc = {}

    def getVoltage(self):
        self.voltage = [12,24][int(input("Vehicle voltage?\n1. 12V\n2. 24V\n"))-1]

    def getCat(self):
        self.cat = input("P/N:")

    def getType(self):
        while self.type == None:
            try:
                self.type = ["XE","RRTM"][int(input("Type of mast?\n1. XE\n2. RRTM\n"))-1]
                if self.type == "RRTM":
                    self.getCat()
                    if self.cat in data.el:
                        self.model = "RRTM-EL"
                    elif self.cat in data.es:
                        self.model = "RRTM-ES"
                    else:
                        print("Model not recognized...")
                        x = input("1. RRTM-EL\n2. RRTM-ES\n")
                        if x == "1":
                            self.model = "RRTM-EL"
                        else:
                            self.model = "RRTM-ES"
                else:
                    self.getCat()
                    self.getVoltage()

            except:
                pass

    def getLines(self):
        l = lampset.Lampset()
        l.getWatts()
        self.lines = math.ceil((l.amps+3)/16)
        if self.lines < 2:
            self.lines = 2
        self.amps = l.amps
        print("\nTotal amps: ",str(round(self.amps)))
        ampsPerLine = round(self.amps/self.lines)
        print("Amps per line: ",str(ampsPerLine)+"\n")
        if ampsPerLine > 9 and self.voltage == 12:
            print("Please check if voltage drop is not too large!")

    def getCable(self):
        if input("S/STP Cable?\n1. Yes\n2. No\n") == "1":
            if input("Is the top section wide enough for a S/STP cable?\n(TF 300XE / RRTM-EL: max. 3 sections, TF 400XE / RRTM-ES: max. 4 sections)\n1. Yes\n2. No\n") == "1":
                self.cable = "C"
            else:
                input("Please choose another mast or don't use S/STP")
                sys.exit()
        else:
            self.getLines()
            if self.lines %2 != 0:
                self.lines += 1
            if self.lines > 2:
                if self.lines < 5 and self.amps / self.lines < 8:
                    self.cable = "L"
                    return
                self.cable = "K"
                self.print = str(self.lines)
            if self.lines > 6:
                print("Too much current. Please use a converter or different lamp unit.")
                sys.exit()

    def getPrint(self):
        if input("RF Remote?\n1. Yes\n2. No\n") == "1":
            self.rf = True
            if input("Europe?\n1. Yes\n2. No\n") == "1":
                self.europe = True
            else:
                self.europe = False

        if self.rf == True and self.europe == False and self.print == "1":
            self.print = "2"

    def addAccs(self):
        cr = "Cable Remote"
        rf = "RF Remote"
        if self.print == "1":
            self.acc[cr] = "27731"
            if self.rf == True:
                self.acc[rf] = "27729"
        else:
            self.acc[cr+" 2L"] = data.cableRemotes[0]
            if self.rf == True:
                self.acc[rf+ " 2L"] = data.rfRemotes[0]
<file_sep>/README.md
# suggest-offer
Create an offer based on intel.
<file_sep>/data.py
el = [str(x) for x in range(38000,38024)]
es = [str(x) for x in range(38275,38299)]
cableRemotes = [str(x) for x in range(35992,35997)]
rfRemotes = [str(x) for x in range(36002,36007)]
cUnit12 = [str(x) for x in range(35972,35981) if x%2 == 0]
cUnit24 = [str(x) for x in range(35973,35982) if x%2 != 0]

languages: Markdown Python

repo_language: Markdown


text:
<file_sep># splitter.js
#### Easy resizable HTML elements with a splitter
Dependency: jQuery
## Support for:
 - Horizontal Splitter
 - Vertical Splitters
 - Both at once
 - min-width is minded

# Horizontal Splitter
![Horizontal Splitter](https://i.imgur.com/OArd5kv.gif)
See: horizontal_example.html
###### Important: Both resizable elements as well as the splitter need to have the css property ``display: inline-block``

##### Example:
```html
<div class="box"></div> <!-- .box gives them a height, width and display: inline-block-->
<div id="splitter"></div>
<div class="box"></div>
<script>initHorizontalSplitter('#splitter'); // jQuery slector</script>
```

# Vertical Splitter
![Vertical Splitter](https://i.imgur.com/iHWwvkI.gif)
###### Important: Both resizable elements as well as the splitter need to have the css property ``display: block``

##### Example:
```html
<div class="box"></div> <!-- .box gives them a height, width and display: block-->
<div id="splitter"></div>
<div class="box"></div>
<script>initVerticalSplitter('#splitter'); // jQuery slector</script>
```

# Horizontal and Vertical Splitters
![Horizontal and Vertical Splitter](https://i.imgur.com/eWKkMOq.gif)

 ##### Example:
```html
<div class="horizontal-wrapper">
    <!-- See: Horizontal Splitter -->
    <div class="box"></div><div id="splitter-horizontal"></div><div class="box"></div>
</div>
<div id="splitter-vertical"></div>
<div class="box-bottom"></div>
```

Thanks for checking out splitter.js! It's coded with simplicity in mind so anyone can understand and use it.

<NAME> 2018
<file_sep>function initHorizontalSplitter(splitterSelector) {
    initSplitter(splitterSelector, 'hor');
}

function initVerticalSplitter(splitterSelector) {
    initSplitter(splitterSelector, 'ver');
}

function initSplitter(splitterSelector, direction) {
    var splitter = $(splitterSelector);
    if (splitter.length != 1) {
        alert('Selector must match exactly one');
        return;
    }
    var left = splitter.prev();
    var right = splitter.next();
    if (left.length != 1 || right.length != 1) {
        alert('Need one previous and one next element');
        return;
    }

    function _initSplitter(splitter, right, left, dir) {
        var dragging = false;
        var start;
        var isOver = false;

        var getKey, minProperty, setter, getter;
        if (dir === 'hor') {
            getKey = function(jsonObject) { return jsonObject.x; };
            minProperty = 'min-width';
            setter = function(jQueryObject, value) { jQueryObject.width(value); };
            getter = function(jQueryObject) { return jQueryObject.width(); };
        } else if (dir === 'ver') {
            getKey = function(jsonObject) { return jsonObject.y; };
            minProperty = 'min-height';
            setter = function(jQueryObject, value) { jQueryObject.height(value); };
            getter = function(jQueryObject) { return jQueryObject.height(); };
        } else {
            alert('Invalid direction');
            return;
        }
        splitter.css('user-select', 'none'); // user could select text while dragging
        splitter.mousedown(function(e) {
            dragging = true;
            start = {x: e.pageX, y: e.pageY};
        });
        splitter.mouseenter(function() {
            isOver = true;
        });
        splitter.mouseout(function() {
            isOver = false;
        })
        var doc = $(document);
        doc.mouseup(function() {
            dragging = false;
            start = null;
        });
        doc.mousemove(function(e) {
            if (dragging) {
                first = splitter.prev();
                second = splitter.next();
                var newPoint = {x: e.pageX, y: e.pageY};
                var delta = {x: start.x - newPoint.x, y: start.y - newPoint.y};

                var newFirst = getter(left) - getKey(delta);
                var newSecond = getter(right) + getKey(delta);
                start = newPoint;
                var minFirst  = parseInt(first.css(minProperty).replace('px', ''))
                var minSecond = parseInt(second.css(minProperty).replace('px', ''))

                function minimize(toMin, toMax, min) {
                    var delta = getter(toMin) - min;
                    setter(toMin, min);
                    setter(toMax, getter(toMax) + delta);
                }

                if (newFirst < minFirst || newSecond < minSecond) {
                    if (newFirst < minFirst) {
                        minimize(first, second, minFirst);
                    } else {
                        minimize(second, first, minSecond);
                    }
                    dragging = false;
                    return;
                }
                if (newFirst < 0 || newSecond < 0) {
                    // avoid weird behavior
                    dragging = false;
                    return;
                }
                setter(first, newFirst);
                setter(second, newSecond);
            }
        });

    }
    _initSplitter(splitter, right, left, direction);
}

languages: Markdown JavaScript