<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Sinisa Drpa]]></title><description><![CDATA[A blog about development stuff. Mostly Swift, Web and Blockchain.]]></description><link>http://tagtaxa.com/</link><generator>Ghost 0.11</generator><lastBuildDate>Wed, 19 Jan 2022 12:46:26 GMT</lastBuildDate><atom:link href="http://tagtaxa.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Designing ATC RDR Exercises Using Familiar Tools]]></title><description><![CDATA[<p>Can we use the tools we're used to at the workplace (QDM, SEP, drag and drop...) to create an ATC RDR exercise? <br>
Can we iterate on the exercise design without having to switch context between a text editor and a simulator; have real-time situation overview and instant feedback whole time</p>]]></description><link>http://tagtaxa.com/designing-atc-rdr-exercises-using-familiar-tools/</link><guid isPermaLink="false">0a9c29e6-9623-4e7c-a413-abf7507a4494</guid><category><![CDATA[ATC]]></category><category><![CDATA[ATC Simulation]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><dc:creator><![CDATA[Sinisa Drpa]]></dc:creator><pubDate>Fri, 24 Apr 2020 11:25:53 GMT</pubDate><content:encoded><![CDATA[<p>Can we use the tools we're used to at the workplace (QDM, SEP, drag and drop...) to create an ATC RDR exercise? <br>
Can we iterate on the exercise design without having to switch context between a text editor and a simulator; have real-time situation overview and instant feedback whole time during the editing?</p>

<h2>The importance of visual feedback</h2>

<p>To create an exercise we start with a plan, depending of training stage, the purpose of the exercise, etc. imagining how it is going to look like. When the goal is defined, initial data prepared; starts the process of running a simulation to validate the data - further refinements to match the initial goal. The goal is a realistic simulation with appropriate sector occupancy matching the training plan. If there's anything wrong, we go back to an editor (it's usually a text one), make necessary adjustments, save, export and re-run the simulation to verify the results. If new ideas come up along the way - we go back to the editor. Most of the time, refining the exercise is spent in the editor working on text without an immediate connection to the impact of the edits. We have to maintain mental mapping and predict the impact of the modifications which can be overwhelming at times, eg. when a simulation includes multiple sectors and a lot of vertical profile changes.<br> <br>
Switching context to edit and run a simulator to validate inputs, interferes with the thought process making a complex simulation time-consuming and imprecise. It causes some of the initial plans to be skipped because of new conflicts occurring; the corners are cut by leaving out some of the elements for the sake of time and resource constraints.</p>

<p><img src="https://www.tagtaxa.com/download/atc0.png" alt="ATCStudio"></p>

<h2>Live editing with an interactive simulator in background</h2>

<p>ATCStudio tests the way of designing simulations with an immediate response without the need of running a simulator to see and validate results. It explores the solution of making the process interactive and focused, using the tools ATCO is already familiar with, avoiding the need for switching context in the edit-reload-run loop.<br><br> <br>
A flight in the app can be created by choosing any location on the display. The clicked location becomes the flight starting position. The pre-populated &quot;New Flight Sheet&quot; will pop up (data can be edited) with the routes sorted by distance from the clicked position, it auto-selects the nearest flight route.<br>As soon as the flight is created, the simulation is updated and can be tested <strong>immediately</strong>. A time slider controlling the simulation time is located at the bottom of the display. Dragging a mouse over the time slider moves the simulation time back and forth displaying the traffic situation changes as you drag over the timeline (or rotate a mouse wheel).</p>

<p style="padding: 2em 0;">  
<video controls width="100%">  
    <source src="https://www.tagtaxa.com/download/atc1.mov" type="video/mp4">
</video>  
<i>Creating FPL and time control</i>  
</p>

<p>After a flight's been created, the flight position can be modified by dragging and dropping the flight symbol to a new location <strong>at any time of the simulation</strong>. When the flight position is changed it's reflected immediately. Seeing the changes instantly is crucial for developing the exercise and carrying out the proposed plan. <br>
If the dragging is started when the flight is at its starting position, dragging the flight symbol is going to change the starting position without changing the flight start time.</p>

<p style="padding: 2em 0;">  
<video controls width="100%">  
    <source src="https://www.tagtaxa.com/download/atc2.mov" type="video/mp4">
</video>  
<i>Changing a flight initial position</i>  
</p>

<p>A flight position can be modified while the flight is somewhere along its route, not just at the initial position. eg. if you realise you want the flight to be slightly further or back along its route, in the middle of the simulation, you can simply drag the flight symbol along the route and drop it at another position on the route. It allows precise positioning of the flight to a new location along its route at any time.<br> <br>
In the example below, we're at time 00:04:28 of the simulation and we notice TCW502 having short separation with another traffic. We can move to the desired time on time slider, grab one of the flights and drag it back or forth along its route to adjust the separation between the flights at a specific time. The current simulation time will stay the same, but TCW502 position is going to change as you drag the mouse. <br>
In the background, the operation is going to re-calculate the flight plan start time, respecting the aircraft type performance, calculating new start time to reach the specified position at the current time on the time slider:</p>

<p style="padding: 2em 0;">  
<video controls width="100%">  
    <source src="https://www.tagtaxa.com/download/atc3.mov" type="video/mp4">
</video>  
<i>Interactive retiming along a flight route</i>  
</p>

<p>A flight plan re-timing can be also performed via Flight List window. The flight list shows the planning map of all the flight plans in the simulation. Sliding a flight strip changes the flight start time/position accordingly. It may be less precise than dragging the flight symbol on the display interactively, but the flight list provides a good overview of all the flights in the simulation and visual overview of the estimated times along the flights' routes and time occupancy. The flights' strips can be arranged vertically or arbitrary sorted. The list is always in sync with the simulation and displays the latest changes. By default, the flights are sorted by the assigned FL, but it can be overridden by drag and drop.</p>

<p style="padding: 2em 0;">  
<video controls width="100%">  
    <source src="https://www.tagtaxa.com/download/atc4.mov" type="video/mp4">
</video>  
<i>Flights list and sectors occupancy overview</i>  
</p>

<p>Re-timing a flight or updating the flight position automatically triggers real-time:  </p>

<ul>  
<li>route recalculation</li>  
<li>safety net analysis</li>  
<li>sector occupancy recalculation</li>  
</ul>  

<p>Making it easier to get an overview of the occupancy of the sectors and conflicts between the flights at any time of the simulation. This way the simulation can be adjusted to match the initial exercise plan without interrupting the design workflow, without leaving the display screen from start to finish, providing immediate feedback of the changes. If necessary, the flight plan route can be edited on the fly. <br>
Changing and analysing vertical profile changes are the same as we do it at a workplace, where the impact on other flights and sectors can be analysed for each second; there is a real-time display of the sectors occupancy. FL change action is recorded and can be undone at any time during a simulation. The unlimited undo/redo is part of the workflow, any destructive operation can be undone (route, FL, position change...) so there is no fear of making mistakes or starting over.</p>

<p style="padding: 2em 0;">  
<video controls width="100%">  
    <source src="https://www.tagtaxa.com/download/atc5.mov" type="video/mp4">
</video>  
<i>Changing a vertical profile, route and unlimited undo/redo</i>  
</p>

<h2>Integration</h2>

<p>Once the exercise plan is fulfilled, the flight plan data can be exported to another format acceptable to another software. For internal use, I wrote <a href="https://www.micronav.co.uk/best-atc-simulator/best-radar/">BEST</a> exporter module, but with plug-in modules, the simulation data can be exported to a format readable to another system. <br>
We tested using Eurocontrol <a href="https://www.eurocontrol.int/model/network-strategic-modelling-tool">NEST</a> output, importing the previous traffic data into the app to capture and replay some of the peak hours. The scenario is useful eg. when creating contingency training exercises.</p>

<h2>Learning</h2>

<p>ATCStudio can be used as a learning tool for both OJTI and ATC students. It takes a minute to create a traffic situation and validate possible results (radar vectoring, wind impact, route network, etc.), Different outcomes can be tested fast, with minimal interference due interactive create, edit, undo/redo support, with a minimal learning curve, in the familiar interface used at a workplace.</p>

<h2>Further Improvements</h2>

<p>Real-time safety net and airspace analysis are computationally expensive. ATCStudio goal is to keep 'close to real-time' interactivity so it doesn't reduce the degree of flexibility or impair thought process during working on an exercise, that is the paramount feature. <br>
Since there can be a lot of elements processing at the same time, offloading a part of the computations to the graphic unit would improve responsiveness since the computational workload would be shared between CPU and GPU. It's significant for RT airspace analysis. I tested it on a small part. <br>
It'd be interesting to connect the app to a real-time system eg. flight-radar to be able to capture and create simulations from real-time data. <br>
Machine learning and analysis can help to automate and prototype new ideas.  </p>

<p>A plan is to publish and maintain ATCStudio free for personal and educational use. If you're interested in supporting the development or have a suggestion, feel free to send me an <a href="mailto:sdrpa@tagtaxa.com">email</a>.</p>

<h2>Technical Details</h2>

<p>ATCScenario is written in <a href="https://swift.org/about/">Swift</a>, <a href="https://developer.apple.com/xcode/swiftui/">SwiftUI</a>, it runs on MacOS 10.15+. It's compatible with iPadOS (tested on iPad Pro, iPadOS 13.4) with minimal changes. For the initial release I focused on the desktop version since when editing a simulation on a smaller screen, the display easily becomes overcrowded. <br>
<a href="https://github.com/OSGeo/PROJ/tree/7.0">PROJ.4</a> is used for cartographic projection and coordinate transformations. <br>
Initially, the idea was born after I attended IANS - 'Design of ATC Simulation Exercises' course and working with different systems at <a href="http://www.smatsa.rs/Eng/Home.aspx">SMATSA</a>.</p>

<h2>Resources</h2>

<p><a href="https://www.skybrary.aero/">SKYbrary</a> <br>
<a href="http://www.edwilliams.org/avform.htm">Aviation Formulary</a></p>]]></content:encoded></item><item><title><![CDATA[Getting an Insight of Blockchain Transactions Flow with Neo4j Graph Database]]></title><description><![CDATA[<p>In the previous <a href="https://tagtaxa.com/sql-on-lisk-blockchain/">post</a> I described how to explore and better understand information on Lisk blockchain by running SQL queries directly on the blockchain database. In this article I'll try to explain how to export the data from Lisk relational database to <a href="https://neo4j.com/">Neo4j</a> graph database in order to be able</p>]]></description><link>http://tagtaxa.com/getting-an-insight-of-blockchain-transactions-with-neo4j-graph-database/</link><guid isPermaLink="false">5deea691-9e5b-46ef-abdb-7b6a76bd404e</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[Lisk]]></category><category><![CDATA[Neo4j]]></category><dc:creator><![CDATA[Sinisa Drpa]]></dc:creator><pubDate>Sun, 22 Dec 2019 18:12:08 GMT</pubDate><content:encoded><![CDATA[<p>In the previous <a href="https://tagtaxa.com/sql-on-lisk-blockchain/">post</a> I described how to explore and better understand information on Lisk blockchain by running SQL queries directly on the blockchain database. In this article I'll try to explain how to export the data from Lisk relational database to <a href="https://neo4j.com/">Neo4j</a> graph database in order to be able to build and visually explore blockchain transactions flow graph.   </p>

<p><img src="https://tagtaxa.com/download/neo4j_1.png" alt="Graph"></p>

<p>Be advised, since we're going to run both Lisk Core and Neo4j in docker (to speed up the process and avoid Lisk and Neo4j installations), the tutorial assumes you have docker installed and running, and you're familiar with terminal. (I'm running macOS but the process should be the same on other operating systems.)</p>

<h3 id="runliskcoreindocker">Run Lisk Core in Docker</h3>

<p>First, we need to run and synchronise Lisk Core to have the latest blockchain data available.</p>

<ol>
<li>Download and unzip this <a href="https://tagtaxa.com/download/docker.zip">archive</a>. The archive contains docker configuration for Lisk Core (mainnet) and <a href="https://www.adminer.org/">Adminer</a>.  </li>
<li>cd to folder where you've downloaded and extracted the archive and run <code>curl --output main_blockchain.db.gz https://downloads.lisk.io/lisk/main/blockchain.db.gz</code> to download the latest Lisk blockchain snapshot. (It'll be used by step 3, otherwise it'll take days to synchronise database from scratch.)  </li>
<li>Run <code>make coldstart</code> (it's necessary only first time) to start Lisk docker container.  </li>
<li>Take a coffee, it will take some time for the script to populate Lisk database from the snapshot...</li>
</ol>

<h3 id="runneo4jindocker">Run Neo4j in Docker</h3>

<p>Once we have Lisk Core synchronised and running, we're going to start Neo4j in docker. Open a terminal window and run:  </p>

<pre><code>docker run \  
    --name testneo4j \
    -p7474:7474 -p7687:7687 \
    -d \
    -v $HOME/Docker/neo4j/data:/data \
    -v $HOME/Docker/neo4j/logs:/logs \
    -v $HOME/Docker/neo4j/import:/var/lib/neo4j/import \
    -v $HOME/Docker/neo4j/plugins:/plugins \
    --env NEO4J_AUTH=neo4j/test \
    neo4j:latest
</code></pre>

<p>Once Neo4j container is up  and running you can start Neo4j browser. Go to <code>http://localhost:7474/</code> in your browser to get feel of  Neo4j browser. </p>

<h3 id="exportdatafrompostgresliskdatabasetocsv">Export data from Postgres (Lisk) database to CSV</h3>

<p>With both Neo4j and Lisk ready, we're ready to export blockchain data to csv files later to imported to Neo4j:</p>

<ol>
<li>Open a termninal window and type: <code>psql -h localhost -p 5432 -U lisk lisk</code> to connect to Lisk Postgres database (enter 'password' when asked for password) .  </li>
<li>Enter commands below in <code>psql</code> shell to export the data as csv:  </li>
</ol>

<pre><code>\COPY (SELECT address, balance FROM mem_accounts) TO '/Users/sdrpa/Downloads/accounts.csv' WITH CSV header;
\COPY (SELECT id, trs."senderId", trs."recipientId", timestamp, amount FROM trs WHERE type = 0) TO '/Users/sdrpa/Downloads/trs.csv' WITH CSV header;
</code></pre>

<p>After that you'll have <code>accounts.csv</code> and <code>trs.csv</code> files ready to be imported to Neo4j.</p>

<h3 id="importcsvdatatoneo4jdatabase">Import CSV data to Neo4j database</h3>

<p>We need to copy <code>accounts.csv</code> and <code>trs.csv</code> to Neo4j container to be able to import the data to Neo4j. <br>
Open a terminal window and run:  </p>

<pre><code>docker cp accounts.csv testneo4j:/var/lib/neo4j/import/accounts.csv  
docker cp accounts.csv testneo4j:/var/lib/neo4j/import/trs.csv  
</code></pre>

<p><em>Alternatively, you can use Finder to copy the files to $HOME/Docker/neo4j/import/ (but it's only applicable to macOS)</em></p>

<p>Now we need to create the nodes and the relationships for Neo4j graph. We'll do it using cypher shell. <br>
Open a terminal window and run <code>cypher-shell -u neo4j -p test</code> to start Neo4j cypher shell. <br>
In cypher shell type:  </p>

<pre><code>```
// Create accounts
USING PERIODIC COMMIT  
LOAD CSV WITH HEADERS FROM "file:///accounts.csv" AS row  
CREATE (:Account {address: row.address, balance: toInteger(row.balance) / 10^8});

// Create transactions
USING PERIODIC COMMIT  
LOAD CSV WITH HEADERS FROM "file:///trs.csv" AS row  
CREATE (:Transaction {tid: row.id, timestamp: date(datetime({epochSeconds: toInteger(row.timestamp) + 1464109200})), amount: toInteger(row.amount) / 10^8});

// Create indexes
CREATE INDEX ON :Account(address);  
CREATE INDEX ON :Transaction(tid);

// Create SEND_TO relationship
USING PERIODIC COMMIT  
LOAD CSV WITH HEADERS FROM "file:///trs.csv" AS row  
MATCH (sender:Account {address: row.senderId})  
MATCH (recipient:Account {address: row.recipientId})  
MERGE (sender)-[:SENT_TO]-&gt;(recipient);  
</code></pre>

<p>It creates Neo4j models (Account, Transaction) and (SENT_TO) relationship.</p>

<h3 id="exploreblockchaintransactionsflow">Explore blockchain transactions flow</h3>

<p>Finally, you're ready to explore Lisk accounts and transactions flow with Neo4j browser. <br>
Open Neo4j browser in your browser <code>http://localhost:7474/</code> and enter initial query:  </p>

<pre><code>MATCH (sender:Account { address: '5055500162731337929L' })-[:SENT_TO]-&gt;(recipient:Account)  
RETURN sender, recipient  
</code></pre>

<p>Maximize graph window and start exploring:  </p>

<video controls="controls" width="800" height="600" name="Graph" src="https://tagtaxa.com/download/neo4j.mov"></video>

<p><br></p>

<h3 id="resources">Resources</h3>

<p><a href="https://tagtaxa.com/sql-on-lisk-blockchain/">SQL on Lisk blockchain via Lisk Docker and Adminer</a> <br>
<a href="https://neo4j.com/developer/docker-run-neo4j/">How-To: Run Neo4j in Docker</a> <br>
<a href="https://neo4j.com/developer/guide-importing-data-and-etl/">Tutorial: Import Relational Data Into Neo4j</a>   </p>]]></content:encoded></item><item><title><![CDATA[Chainstory.art - Experiment with Blockchain and IPFS]]></title><description><![CDATA[<p><a href="https://chainstory.art">Chain Story</a> is a web application which leverages <a href="https://ipfs.io/">IPFS</a> and <a href="https://lisk.io/">Lisk</a> blockchain to permanently link a pixel art to an author's blockchain address. By using decentralized and distributed technology a permanent link is created ensuring the authenticity of the submitted work.
Once submitted, a drawing is saved to IPFS, generating</p>]]></description><link>http://tagtaxa.com/chainstory-art-experiment-with-blockchain-and-ipfs-2/</link><guid isPermaLink="false">d9446307-dd87-491d-9948-3b5cbaa8661f</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[IPFS]]></category><category><![CDATA[Golang]]></category><category><![CDATA[React]]></category><category><![CDATA[Web]]></category><category><![CDATA[Apps]]></category><category><![CDATA[Lisk]]></category><dc:creator><![CDATA[Sinisa Drpa]]></dc:creator><pubDate>Thu, 14 Nov 2019 17:23:36 GMT</pubDate><content:encoded><![CDATA[<p><a href="https://chainstory.art">Chain Story</a> is a web application which leverages <a href="https://ipfs.io/">IPFS</a> and <a href="https://lisk.io/">Lisk</a> blockchain to permanently link a pixel art to an author's blockchain address. By using decentralized and distributed technology a permanent link is created ensuring the authenticity of the submitted work.
Once submitted, a drawing is saved to IPFS, generating a unique content identifier the author can register (by sending transaction) on Lisk blockchain. Chain Story application continually reads blockchain and IPFS data displaying the original pixel art.</p>

<p>Chain Story's client is a React app. The backend interacting with IPFS and Lisk API is written in Golang.</p>

<p><img src="https://raw.githubusercontent.com/sdrpa/chainstory-client/master/screenshot.png" alt="screenshot"></p>

<p>Both the client and server source code are available at: </p>

<p><a href="https://github.com/sdrpa/chainstory-client">https://github.com/sdrpa/chainstory-client</a> <br>
<a href="https://github.com/sdrpa/chainstory-server">https://github.com/sdrpa/chainstory-server</a></p>]]></content:encoded></item><item><title><![CDATA[Photo Light - Lightweight fast image viewer for macOS (Discontinued)]]></title><description><![CDATA[<p>There is several photo management software for macOS. I used to use Aperture to manage my photo collection but since Apple discontinued Aperture for quite a while now, I have struggled to find a macOS app suitable for my requirements. <br>
That was my motivation to write Photo Light.</p>

<p>Major requirements</p>]]></description><link>http://tagtaxa.com/photo-light-lightweight-fast-image-viewer-for-macos/</link><guid isPermaLink="false">42eca6b3-3100-4906-bc5f-ac0f68216168</guid><category><![CDATA[Apps]]></category><category><![CDATA[macOS]]></category><category><![CDATA[Discontinued]]></category><dc:creator><![CDATA[Sinisa Drpa]]></dc:creator><pubDate>Wed, 10 Jul 2019 22:44:24 GMT</pubDate><media:content url="http://tagtaxa.com/content/images/2020/09/Screenshot-2020-09-08-at-22.08.09.jpg" medium="image"/><content:encoded><![CDATA[<img src="http://tagtaxa.com/content/images/2020/09/Screenshot-2020-09-08-at-22.08.09.jpg" alt="Photo Light - Lightweight fast image viewer for macOS (Discontinued)"><p>There is several photo management software for macOS. I used to use Aperture to manage my photo collection but since Apple discontinued Aperture for quite a while now, I have struggled to find a macOS app suitable for my requirements. <br>
That was my motivation to write Photo Light.</p>

<p>Major requirements were: <br>
<strong>Folder based app</strong>, so I'd never need to export end reorganize my photos if an app ceases to exist. <br>
<strong>Fast browsing and rendering</strong>. I remember Aperture being very fast when browsing images but with time it slowed down significantly, basically image loading killed the browsing experience. <br>
<strong>RAW formats support</strong>. <br>
<strong>Non-destructive</strong>.</p>

<p>In Photo Light an image loading is terminated as soon as you select another photo so you can go through big images as quickly as possible. Image previews are generated in the background, cached for future use and whenever possible embedded previews are used to speed up the process. <br>
Photo Light provides fast image rendering and manipulation using <a href="https://en.wikipedia.org/wiki/Metal_(API)">Metal</a>. <br>
The interface is simple and customizable so you can focus on the photos.</p>]]></content:encoded></item><item><title><![CDATA[SQL on Lisk blockchain via Lisk Docker and Adminer]]></title><description><![CDATA[<p><a href="https://explorer.lisk.io">Lisk Explorer</a> is a great tool to view information stored on the Lisk blockchain, but in order to inspect the blockchain data in more detail we'll run SQL queries on Lisk blockchain database.
By querying the database directly, more information can be extracted and the queries can be customized to</p>]]></description><link>http://tagtaxa.com/sql-on-lisk-blockchain/</link><guid isPermaLink="false">db50aa3c-0249-4d02-9dbd-f9ed6b783134</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[Lisk]]></category><dc:creator><![CDATA[Sinisa Drpa]]></dc:creator><pubDate>Sun, 19 Aug 2018 14:56:27 GMT</pubDate><content:encoded><![CDATA[<p><a href="https://explorer.lisk.io">Lisk Explorer</a> is a great tool to view information stored on the Lisk blockchain, but in order to inspect the blockchain data in more detail we'll run SQL queries on Lisk blockchain database.
By querying the database directly, more information can be extracted and the queries can be customized to select and analyze the data we want. E.g. it's easy to find out which delegate paid you the most, show all transactions for an account for the past n days, view lisk distribution and so on.</p>

<p><a href="https://github.com/LiskHQ/lisk-docker/tree/development/examples/mainnet">Lisk Docker</a> will be used to automate the setup of the server, Lisk Core and PostgreSQL web client. <br>
<small>This tutorial assumes you have <a href="https://docs.docker.com">Docker</a> installed and running.</small></p>

<p>First, download and unzip this <a href="https://tagtaxa.com/download/mainnet.zip">archive</a>. <br>
<small>(The archive contains <code>docker-compose.yml</code>, a copy of <a href="https://github.com/LiskHQ/lisk-docker/tree/development/examples/mainnet">Lisk Docker</a> mainnet image with additional postgres port exposed[1] and added <a href="https://www.adminer.org">Adminer</a> image - PostgreSQL web client.)</small></p>

<p>Open Terminal, cd to directory where you unzipped <a href="https://tagtaxa.com/download/mainnet.zip">archive</a> and run:  </p>

<pre><code>make coldstart  
</code></pre>

<p><img src="http://tagtaxa.com/content/images/2018/08/terminal-screen.png" alt=""></p>

<p>Get a coffee and wait until it completes. This can take a few minutes. <br>
<small>(It will download the latest Lisk blockchain snapshot, docker images, create docker containers, start Lisk Core and restore Lisk blockchain database from the snapshot.)</small></p>

<p><img src="http://tagtaxa.com/content/images/2018/08/terminal-screen2.png" alt="Finished"></p>

<p>Once done, it will auto-start synchronizing Lisk Core with main chain. <br>
<small>(You can visit <a href="http://localhost:8000/api/blocks/getHeight">http://localhost:8000/api/blocks/getHeight</a> to check the current block height.)</small></p>

<p><img src="http://tagtaxa.com/content/images/2018/08/safari-screen.png" alt=""></p>

<p>Now open <a href="http://localhost:8080">http://localhost:8080</a> to access <a href="https://www.adminer.org">Adminer</a> login page:</p>

<p><img src="http://tagtaxa.com/content/images/2018/08/adminer-screen.png" alt="Adminer login"></p>

<p>Use:  </p>

<pre><code>System: PostgreSQL  
Server: db  
Username: lisk  
Password: password  
Database: lisk_main  
</code></pre>

<p>Once logged in, click <strong>SQL command</strong> link and you're ready to execute SQL queries!</p>

<p><img src="http://tagtaxa.com/content/images/2018/08/adminer-screen2.png" alt="SQL command panel"></p>

<p>Here are some SQL queries you may find useful:</p>

<h3 id="whichdelegatepaidmethemost">Which delegate paid me the most?</h3>

<pre><code>-- Which delegate paid me the most
WITH xs AS (  
  SELECT "senderId" AS address, username AS delegate
  FROM trs
  JOIN delegates ON delegates."transactionId" = trs."id"
)
SELECT  
  delegate, 
  SUM(trunc(amount::numeric/100000000, 8)) as amount
FROM trs  
JOIN xs ON xs.address = trs."senderId"  
WHERE "recipientId" = '14775206447342278732L' AND amount &gt; 0  
GROUP BY delegate  
ORDER BY amount DESC;  
</code></pre>

<pre><code>-- Which delegate paid me the most in the last n days, months...
WITH xs AS (  
  SELECT "senderId" AS address, username AS delegate
  FROM trs
  JOIN delegates ON delegates."transactionId" = trs."id"
), constants(LISK_EPOCH) AS (
  -- 1464109200 = Lisk Epoch (2016–05–24T17:00:00.000Z)
  VALUES (1464109200)
)
SELECT  
  delegate, 
  SUM(trunc(amount::numeric/100000000, 8)) as amount
FROM constants, trs  
JOIN xs ON xs.address = trs."senderId"  
JOIN blocks ON blocks.id = trs."blockId"  
WHERE to_timestamp(blocks."timestamp" + LISK_EPOCH)  
  BETWEEN (now() - '6 months'::interval) AND now() -- Use '1 day', '2 days', '1 week', '6 months'...
AND amount &gt; 0  
AND "recipientId" = '14775206447342278732L'  
GROUP BY delegate  
ORDER BY amount DESC;  
</code></pre>

<h3 id="liskdistribution">Lisk Distribution</h3>

<pre><code>SELECT t.arange AS amount_range, COUNT(*) AS num_accounts  
FROM (  
  SELECT address, username AS delegate,
    CASE
      WHEN balance/100000000 &lt;= 0                                             THEN '0'
      WHEN balance/100000000 &gt; 0          AND balance/100000000 &lt;= 1          THEN '0-1'
      WHEN balance/100000000 &gt; 1          AND balance/100000000 &lt;= 10         THEN '1-10'
      WHEN balance/100000000 &gt; 10         AND balance/100000000 &lt;= 100        THEN '10-100'
      WHEN balance/100000000 &gt; 100        AND balance/100000000 &lt;= 1000       THEN '100-1000'
      WHEN balance/100000000 &gt; 1000       AND balance/100000000 &lt;= 10000      THEN '1000-10000'
      WHEN balance/100000000 &gt; 10000      AND balance/100000000 &lt;= 100000     THEN '10000-100000'
      WHEN balance/100000000 &gt; 100000     AND balance/100000000 &lt;= 1000000    THEN '100000-1000000'
      WHEN balance/100000000 &gt; 1000000    AND balance/100000000 &lt;= 10000000   THEN '1000000-10000000'
      WHEN balance/100000000 &gt; 10000000   AND balance/100000000 &lt;= 100000000  THEN '10000000-100000000'
      WHEN balance/100000000 &gt; 100000000                                      THEN '100000000+'
      ELSE 'unknown'
    END AS arange
  FROM mem_accounts
) AS t
GROUP BY t.arange  
ORDER BY t.arange DESC;  
</code></pre>

<h3 id="howmuchliskisforgedbyeachdelegate">How much lisk is forged by each delegate</h3>

<pre><code>WITH xs AS (  
  SELECT "senderId" AS address, username AS delegate, "senderPublicKey" AS publicKey
  FROM trs
  JOIN delegates ON delegates."transactionId" = trs."id"
)
SELECT  
  delegate,
  SUM(reward/100000000) as reward
FROM blocks  
JOIN xs ON xs.publicKey = blocks."generatorPublicKey"  
WHERE reward &gt; 0  
GROUP BY delegate  
ORDER BY reward DESC;  
</code></pre>

<h3 id="totalliskfromforgingblockrewards">Total Lisk from forging (block rewards)</h3>

<pre><code>SELECT  
  SUM(reward/100000000) as reward
FROM blocks;  
</code></pre>

<p>Above returns 24,453,036. Current supply according to <a href="https://explorer.lisk.io">Lisk Explorer</a> is 124,453,036. I guess supply is the sum of the block (forging) rewards and 100,000,000 (<a href="https://raw.githubusercontent.com/LiskHQ/lisk/master/genesisBlock.json">premind Lisk</a>)</p>

<h3 id="alloutgoingtransactionsforanaccount">All outgoing transactions for an account</h3>

<pre><code>-- Outgoing transactions
WITH constants(LISK_EPOCH) AS (  
  -- 1464109200 = Lisk Epoch (2016–05–24T17:00:00.000Z)
  VALUES (1464109200)
)
SELECT to_timestamp(blocks."timestamp" + LISK_EPOCH) as datetime,  
  "senderId", trunc(amount::numeric/100000000, 8) as amount
FROM constants, trs  
JOIN blocks ON blocks.id = trs."blockId"  
WHERE "senderId" = '14775206447342278732L' AND amount &gt; 0;  
</code></pre>

<h3 id="allincomingtransactionsforanaccount">All incoming transactions for an account</h3>

<pre><code>-- Incoming transactions
WITH constants(LISK_EPOCH) AS (  
  -- 1464109200 = Lisk Epoch (2016–05–24T17:00:00.000Z)
  VALUES (1464109200)
)
SELECT to_timestamp(blocks."timestamp" + LISK_EPOCH) as datetime,  
  "senderId",
  --"recipientId", 
  trunc(amount::numeric/100000000, 8) as amount
FROM constants, trs  
JOIN blocks ON blocks.id = trs."blockId"  
WHERE "recipientId" = '14775206447342278732L' AND amount &gt; 0  
ORDER BY amount DESC;  
--ORDER BY datetime DESC;
</code></pre>

<p>To clean  </p>

<pre><code>docker-compose down  
</code></pre>

<p>To start again  </p>

<pre><code>docker-compose up  
</code></pre>

<p>[1] Not necessary for this tutorial, it's required if you want to use own PostgreSQL client eg. <a href="https://www.pgadmin.org/">pgAdmin</a></p>]]></content:encoded></item><item><title><![CDATA[How to install Lisk node on testnet]]></title><description><![CDATA[<p>This article is on how to install and run Lisk delegate node on testnet, on <a href="https://www.digitalocean.com">Digitalocean</a> Ubuntu 16.04 droplet. It should help you to set up a new delegate node as easy as possible while still being secure and stable. <br>
Before starting I assume you are already familiar with</p>]]></description><link>http://tagtaxa.com/how-to-install-lisk-node-on-testnet/</link><guid isPermaLink="false">54c7631a-feae-4c9b-9edc-3e918c8b0976</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[Lisk]]></category><dc:creator><![CDATA[Sinisa Drpa]]></dc:creator><pubDate>Fri, 02 Feb 2018 12:20:16 GMT</pubDate><content:encoded><![CDATA[<p>This article is on how to install and run Lisk delegate node on testnet, on <a href="https://www.digitalocean.com">Digitalocean</a> Ubuntu 16.04 droplet. It should help you to set up a new delegate node as easy as possible while still being secure and stable. <br>
Before starting I assume you are already familiar with basic terminal commands and how to access a remote server via SSH. </p>

<h3 id="createatestaccount">Create a test account</h3>

<p>Use <a href="https://lisk.io/download">Lisk Nano</a> to create an account on testnet and register it as delegate. You'll need some test Lisk to register as delegate (the delegate registration costs 25 LSK). I asked on <a href="https://lisk.chat/channel/network">lisk.chat</a> for some test Lisk (thanks <em>@lisksnake</em>).</p>

<p><img src="https://tagtaxa.com/download/testnet.png"></p>

<p><img src="https://tagtaxa.com/download/register.png"></p>

<h3 id="createadropletservernode">Create a droplet (server node)</h3>

<p>For this tutorial, a 4GB - 2vCPUs - 80GB SSD - 16.04.3 x64 droplet is used. </p>

<p><img src="https://tagtaxa.com/download/digitalocean.png"></p>

<p>If you've never created a droplet before, follow <a href="https://www.digitalocean.com/community/tutorials/how-to-create-your-first-digitalocean-droplet">this guide</a>. You can choose a different configuration but be advised I found 2GB of RAM is the minimum when installing Lisk from source (otherwise <code>npm install</code> won't work correctly).</p>

<p>Once you've created the droplet, you will receive an email from digitalocean containing the IP address and the root password required to access the droplet:  </p>

<pre><code>ssh root@123.456.789.012  
</code></pre>

<p>There is a very good tutorial on how to do <a href="https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-16-04">Initial Setup with Ubuntu 16.04</a>, describing each step in detail, I'll focus on what commands you need to execute (in the given order) to setup a delegate node and start forging.</p>

<h3 id="createanewuserandaddtheusertothesudogroup">Create a new user and add the user to the sudo group</h3>

<p>On the server  </p>

<pre><code>adduser sdrpa  
usermod -aG sudo sdrpa  
su - sdrpa  
</code></pre>

<h3 id="disablepasswordauthenticationandrootlogin">Disable Password Authentication and Root Login</h3>

<p>Create <code>~/.ssh/authorized_keys</code> file on the server and paste local machine public key to <code>~/.ssh/authorized_keys</code> file. (If you've never created SSH keys follow this <a href="https://www.digitalocean.com/community/tutorials/how-to-use-ssh-keys-with-digitalocean-droplets">guide</a> to create the RSA key pair):  </p>

<pre><code>mkdir ~/.ssh  
chmod 700 ~/.ssh  
nano ~/.ssh/authorized_keys  
# paste content of ~/.ssh/id_rsa.pub from your local machine and save the file
</code></pre>

<pre><code>chmod 600 ~/.ssh/authorized_keys  
sudo nano /etc/ssh/sshd_config  
</code></pre>

<p>In <code>/etc/ssh/sshd_config</code>, set:  </p>

<pre><code>PasswordAuthentication no  
PermitRootLogin no  
</code></pre>

<p>Reload the SSH daemon and exit  </p>

<pre><code>sudo systemctl reload sshd  
exit  
</code></pre>

<p>Now you should be able to login to the remote server without a password  </p>

<pre><code>$ ssh sdrpa@123.456.789.012

Welcome to Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-112-generic x86_64)  
...
</code></pre>

<h3 id="updateallpackages">Update all packages</h3>

<pre><code>sudo apt-get update &amp;&amp; sudo apt-get dist-upgrade  
</code></pre>

<h3 id="setupufwfirewallandinstallfail2ban">Set up ufw firewall and install fail2ban</h3>

<pre><code>sudo ufw allow OpenSSH  
sudo ufw allow 7000  
sudo ufw enable  
sudo apt-get install fail2ban  
</code></pre>

<h3 id="installntp">Install ntp</h3>

<pre><code>sudo apt-get install ntp  
sudo ufw allow ntp  
sudo service ntp stop  
sudo apt-get install ntpdate  
sudo ntpdate pool.ntp.org  
sudo service ntp start  
</code></pre>

<h3 id="installlisk">Install Lisk</h3>

<pre><code>wget https://downloads.lisk.io/lisk/test/installLisk.sh  
cd lisk-test  
chmod +x installLisk.sh  
./installLisk.sh install
</code></pre>

<p>You'll be asked several questions, choose default location, testnet and when asked if you want to synchronize with genesis account answer <code>no</code>.  </p>

<pre><code>chmod +x lisk.sh  
./lisk.sh stop
</code></pre>

<h3 id="edittlisttestconfigjsontoenableforging">Edit ~/list-test/config.json to enable forging</h3>

<p>Replace <code>secret</code> with your passphrase (passphrase for the testnet account you've created before)  </p>

<pre><code>...
"forging": {
        "force": false,
        "secret": ["first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelfth"],
        "access": {
            "whiteList": [
                "127.0.0.1"
            ]
        }
    },
...
</code></pre>

<h3 id="rebuildwiththelatestliskblockchainsnapshot">Rebuild with the latest Lisk blockchain snapshot</h3>

<pre><code>./lisk.sh rebuild -u https://testnet-snapshot.lisknode.io -f blockchain.db.gz
</code></pre>

<p>Visit <a href="https://testnet-explorer.lisk.io">testnet explorer</a> to check the current block height</p>

<p><img src="https://tagtaxa.com/download/explorer.png"></p>

<p>Wait some time for your node to be fully synchronized with testnet. <br>
You can check your node current height with:  </p>

<pre><code>./lisk.sh status

# output:
√ Lisk is running as PID: 7369
Current Block Height:  4344100  
</code></pre>

<p>Once your node is in sync with testnet, the forging will be activated. Check it with:  </p>

<pre><code>grep Forging logs/lisk.log

# output:
[inf] 2018-01-31 13:41:34 | Forging enabled on account: 5055500162731337929L
</code></pre>

<p>That's it.</p>

<p>I advise you to check <a href="https://www.digitalocean.com/community/questions/best-practices-for-hardening-new-sever-in-2017">Best practices for hardening a new sever</a> for further information regarding the server security, but at this point, you have a solid foundation for your delegate node.</p>

<h3 id="notes">Notes</h3>

<p>I skipped enabling swap space on the server. According to Digitalocean <a href="https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-16-04">recommendation</a>: <br>
"Although swap is generally recommended for systems utilizing traditional spinning hard drives, using swap with SSDs can cause issues with hardware degradation over time. Due to this consideration, we do not recommend enabling swap on DigitalOcean or any other provider that utilizes SSD storage...If you need to improve the performance of your server on DigitalOcean, we recommend upgrading your Droplet...".</p>

<h3 id="resources">Resources</h3>

<p><a href="https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-16-04">Initial server setup with Ubuntu 16.04, Digitalocean</a> <br>
<a href="https://www.digitalocean.com/community/tutorials/how-to-use-ssh-keys-with-digitalocean-droplets">How To Use SSH Keys with DigitalOcean Droplets</a> <br>
<a href="https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-16-04">How to add swap space on Ubuntu 16.04</a> <br>
<a href="https://github.com/LiskHQ/lisk">Lisk GitHub, LiskHQ</a> <br>
<a href="https://docs.lisk.io/docs/">Lisk Documentation, LiskHQ</a> <br>
<a href="https://www.youtube.com/watch?v=OGalnujyDeg">How to setup a Lisk node (on testnet and mainnet), KyleFromOhio</a>   </p>]]></content:encoded></item><item><title><![CDATA[Pay with Lisk Prototype]]></title><description><![CDATA[<p>This is a prototype code exploring how to integrate LSK crypto payments to a webservice. The server side uses <a href="http://www.kitura.io">Kitura framework</a> and <a href="https://docs.lisk.io/docs/lisk-api">Lisk API</a> serving a client app written with <a href="https://reactjs.org">React</a>. <br>
WebSocket API is used for bi-directional communication between the server and the client.</p>

<p>Demo:</p>

<video width="576" height="360" preload="" controls>  
  <source src="https://tagtaxa.com/download/paywithlisk.mov" type="video/mp4">
Your browser does not support</video>]]></description><link>http://tagtaxa.com/pay-with-lisk-prototype/</link><guid isPermaLink="false">6ad12c62-ccdb-42e2-a20e-97532d0ad081</guid><category><![CDATA[Web]]></category><category><![CDATA[Swift]]></category><category><![CDATA[Kitura]]></category><category><![CDATA[React]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[Lisk]]></category><dc:creator><![CDATA[Sinisa Drpa]]></dc:creator><pubDate>Fri, 26 Jan 2018 09:23:42 GMT</pubDate><content:encoded><![CDATA[<p>This is a prototype code exploring how to integrate LSK crypto payments to a webservice. The server side uses <a href="http://www.kitura.io">Kitura framework</a> and <a href="https://docs.lisk.io/docs/lisk-api">Lisk API</a> serving a client app written with <a href="https://reactjs.org">React</a>. <br>
WebSocket API is used for bi-directional communication between the server and the client.</p>

<p>Demo:</p>

<video width="576" height="360" preload="" controls>  
  <source src="https://tagtaxa.com/download/paywithlisk.mov" type="video/mp4">
Your browser does not support the video tag.  
</video>  

<p><br></p>

<p>Payment workflow:</p>

<ul>
<li>When 'Purchase' button is clicked, the user is presented with instructions to send the required amount (1 LSK in our case) to the wallet address of the webstore.
At the same time, in the background, the web client sends a 'new order' message (a message containing user's wallet address and item description) to the server. </li>
</ul>

<p><img src="https://tagtaxa.com/download/paywithlisk-screen1.png"></p>

<ul>
<li><p>The server receives the order message and creates a pending order. It starts waiting for the user's transaction to be completed.</p></li>
<li><p>A user can use Lisk Nano or mobile wallet to send Lisk to the webstore Lisk address. </p></li>
</ul>

<p><img src="https://tagtaxa.com/download/paywithlisk-nano.png"></p>

<p>Since there is no way for the server to be notified when a transaction has been completed (we're not running own Lisk node), we use Lisk <a href="https://docs.lisk.io/docs/lisk-api-080-transactions">Transactions API</a> to fetch the transactions for the store wallet address. <br>
Every 10 seconds (The Lisk network forges blocks in 10s intervals) via Lisk <a href="https://docs.lisk.io/docs/lisk-api-080-transactions">Transactions API</a> the server checks whether the transaction has been completed (whether the user has paid the order).</p>

<ul>
<li>Once the transaction (containing sender address, required amount and our webstore address) is fetched from Lisk blockchain, the store database is updated (order is marked as completed) and a success message is broadcasted to the client.</li>
</ul>

<p><img src="https://tagtaxa.com/download/paywithlisk-screen2.png"></p>

<p>There are several checks skipped for the sake of the code simplicity:</p>

<ul>
<li>It should be checked if the amount paid is equal to the item price, basically the item price should be fetched from a database and compared to the transaction amount.</li>
<li>Transaction reuse should be prevented. A user should not be able to use old transactions for new orders.</li>
</ul>

<p>Lisk payments are very fast, there’s no application to fill out, it'd be great to see online stores using the benefits of Lisk ecosystem.</p>

<p>Download the source code: <a href="https://github.com/sdrpa/PayWithLisk-Server">server</a>, <a href="https://github.com/sdrpa/PayWithLisk-Client">client</a>.</p>

<p>Feel free to ask me anything regarding the source code. You can reach me by <a href="mailto:sdrpa@tagtaxa.com">email</a>, or as <a href="https://twitter.com/sdrpa">sdrpa</a> on Twitter.</p>]]></content:encoded></item><item><title><![CDATA[Coinpricegame]]></title><description><![CDATA[<p><a href="http://coinpricegame.com">Coinpricegame</a> is a weekly Lisk price prediction challenge.
The winners are those whose predictions are closest to Lisk price at the end of the week. </p>

<p>Rules?</p>

<p>The 3 closest predictions win. <br>
One prediction per transaction, the price must be unique. <br>
Predictions must be placed at least 24 hours before the</p>]]></description><link>http://tagtaxa.com/coinpricegame-project-lisk-price-prediction-challenge-web/</link><guid isPermaLink="false">cb07f02a-4d76-44cd-afd4-8aececd0f0af</guid><category><![CDATA[Swift]]></category><category><![CDATA[Kitura]]></category><category><![CDATA[React]]></category><category><![CDATA[Web]]></category><category><![CDATA[Apps]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[Lisk]]></category><dc:creator><![CDATA[Sinisa Drpa]]></dc:creator><pubDate>Mon, 08 Jan 2018 09:17:44 GMT</pubDate><content:encoded><![CDATA[<p><a href="http://coinpricegame.com">Coinpricegame</a> is a weekly Lisk price prediction challenge.
The winners are those whose predictions are closest to Lisk price at the end of the week. </p>

<p>Rules?</p>

<p>The 3 closest predictions win. <br>
One prediction per transaction, the price must be unique. <br>
Predictions must be placed at least 24 hours before the end date. <br>
The winning price is determined according to Lisk's price on Bittrex at midnight on the end date.</p>

<p>How to participate?</p>

<p>Send 1 LSK to 6300871565689347639L. <br>
Copy transaction ID of the transaction from Lisk Nano. <br>
Enter your prediction in USD and the transaction ID. </p>

<p>What’s to win?</p>

<p>1st prize 60% of the Pools Fund. <br>
2nd prize 25% of the Pools Fund. <br>
3rd prize 10% of the Pools Fund.</p>

<p>Pools Fund is the total amount of Lisk raised from all submitted predictions. <br>
Reward payouts will be paid out to winner accounts automatically on the next day.</p>

<p>The source code is available at GitHub: <a href="https://github.com/sdrpa/coinpricegame-server">server app</a>, <a href="https://github.com/sdrpa/coinpricegame-client">client app</a>.</p>]]></content:encoded></item><item><title><![CDATA[Lisk Statistic]]></title><description><![CDATA[<p>While reading about decentralized apps and blockchain I found <a href="https://lisk.io/">Lisk</a> blockchain application platform. I'm trying to learn more about the stock market but real-time market stats are changing to fast for me too read :) In order to provide myself some time to study the patterns I created an app which</p>]]></description><link>http://tagtaxa.com/lisk-statistic/</link><guid isPermaLink="false">e930dd81-9834-4c6d-b730-00deb922f955</guid><category><![CDATA[Swift]]></category><category><![CDATA[React]]></category><category><![CDATA[Kitura]]></category><category><![CDATA[Web]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[Lisk]]></category><dc:creator><![CDATA[Sinisa Drpa]]></dc:creator><pubDate>Tue, 21 Nov 2017 10:26:08 GMT</pubDate><content:encoded><![CDATA[<p>While reading about decentralized apps and blockchain I found <a href="https://lisk.io/">Lisk</a> blockchain application platform. I'm trying to learn more about the stock market but real-time market stats are changing to fast for me too read :) In order to provide myself some time to study the patterns I created an app which pulls Lisk's data from Bittrex API and helps me to analyze the data.</p>

<p>Basically, I want to filter out small transactions in order to see bigger buy/sell orders, check what orders have affected price the most, have longer market history and be able to sort orders and history table by clicking a table header... <br>
Lisk price in Satoshi is with too many decimals for me so I adjusted the presentation towards displaying the values in USD and customized chart presentation to display RSI and MACD.</p>

<p>The project is open source, consisting of two parts: <br>
1. Backend app written in Swift, using Kitura - <a href="https://github.com/sdrpa/lisk-stat-backend">Source</a> <br>
2. Front-end app with React/Bootstrap - <a href="https://github.com/sdrpa/lisk-stat-frontend">Source</a>.</p>]]></content:encoded></item><item><title><![CDATA[Sit Up Straight (macOS)(Discontinued)]]></title><description><![CDATA[<p>Sit Up Straight helps you to maintain a proper posture while working on computer. If you start to slouch, an overlay with sound will remind you to correct your posture. The reminder will stay active until you correct your posture then it will disappear automatically.</p>

<p>The app uses Mac’s</p>]]></description><link>http://tagtaxa.com/sit-up-straight/</link><guid isPermaLink="false">51287329-9f8b-415d-8ca0-726214c66051</guid><category><![CDATA[Apps]]></category><category><![CDATA[OS X]]></category><dc:creator><![CDATA[Sinisa Drpa]]></dc:creator><pubDate>Sun, 09 Jul 2017 09:16:31 GMT</pubDate><content:encoded><![CDATA[<p>Sit Up Straight helps you to maintain a proper posture while working on computer. If you start to slouch, an overlay with sound will remind you to correct your posture. The reminder will stay active until you correct your posture then it will disappear automatically.</p>

<p>The app uses Mac’s camera to set up and assess your posture. Once you set up a "baseline" posture, the app analyzes your posture over time. <br>
You can score your posture over time keeping track of your success.</p>

<p>With three different modes available, you can choose between: <br>
Live - The camera constantly tracks your posture over time, <br>
Custom Intervals - The camera analyzes your posture at predefined time intervals (e.g. every 2 minutes), <br>
Manual - Posture check is triggered manually with a system wide shortcut or from the menu bar.</p>

<p>Sit Up Straight can be disabled or paused at any time and there are various settings (alert sound, reminder color/opacity, time intervals ...) to better control the desired behavior.</p>

<p>Demo Version (7-day trial) <a href="https://tagtaxa.com/download/situpstraight.zip">download →</a> <br>
Mac App Store <a href="https://itunes.apple.com/us/app/sit-up-straight/id1291914091">link →</a></p>

<p>Sit Up Straight requires macOS 10.10+.</p>

<h5 id="preferences">Preferences</h5>

<p><img src="https://tagtaxa.com/download/sus-notifications.png" width="565"></p>

<p><img src="https://tagtaxa.com/download/sus-calibrate.jpg" width="565">  </p>

<h5 id="menubar">Menu bar</h5>

<p><strong>Tip</strong>: <em>Hold ALT while menu is open to display time to next check (when using custom intervals)</em> <br>
<img src="https://tagtaxa.com/download/sus-menubar.png" width="200"></p>

<p>Please feel free to send a <a href="mailto:support@tagtaxa.com?Subject=Sit Up Straight Feedback">feedback</a> or report any bugs you find.</p>]]></content:encoded></item><item><title><![CDATA[Run a server-side Swift app using Perfect framework trough Nginx/Supervisor on Ubuntu 16.04]]></title><description><![CDATA[<p>The steps describe how to setup and run a web app using <a href="https://www.perfect.org">Perfect</a> framework on an existing Ubuntu 16.04 web server. (the web app will run on the same server using a different port).</p>

<p>Download and install <a href="https://swift.org/download/">Swift</a>:</p>

<pre><code>wget https://swift.org/builds/swift-3.1.1-release/ubuntu1604/swift-3.1.</code></pre>]]></description><link>http://tagtaxa.com/run-a-server-side-swift-app-with-perfect-framework-trough-nginx-supervisor-on-ubuntu-16-04/</link><guid isPermaLink="false">e85faa7c-7ab4-4b51-934a-17a95ee37ab7</guid><dc:creator><![CDATA[Sinisa Drpa]]></dc:creator><pubDate>Wed, 05 Jul 2017 23:36:03 GMT</pubDate><content:encoded><![CDATA[<p>The steps describe how to setup and run a web app using <a href="https://www.perfect.org">Perfect</a> framework on an existing Ubuntu 16.04 web server. (the web app will run on the same server using a different port).</p>

<p>Download and install <a href="https://swift.org/download/">Swift</a>:</p>

<pre><code>wget https://swift.org/builds/swift-3.1.1-release/ubuntu1604/swift-3.1.1-RELEASE/swift-3.1.1-RELEASE-ubuntu16.04.tar.gz  
tar xzf swift-3.1.1-RELEASE-ubuntu16.04.tar.gz  
sudo mv swift-3.1.1-RELEASE-ubuntu16.04 /usr/local  
rm swift-3.1.1-RELEASE-ubuntu16.04.tar.gz  
</code></pre>

<p>Install required dependences:  </p>

<pre><code>sudo apt install clang libicu-dev  
sudo apt-get install libcurl3  
sudo apt-get install libsqlite3-dev  
sudo apt-get install uuid-dev  
</code></pre>

<p>Add Swift to system PATH:  </p>

<pre><code>echo 'export PATH=/usr/local/swift-3.1.1-RELEASE-ubuntu16.04/usr/bin:$PATH' ~/.profile  
source .profile  
</code></pre>

<p>I assume you've created your app (eg. webapp) ... If you haven't, below is a 'Hello world' main.swift:  </p>

<pre><code>import Foundation  
import PerfectLib  
import PerfectHTTP  
import PerfectHTTPServer

let server = HTTPServer()  
var routes = Routes()  
routes.add(method: .get, uri: "/", handler: {  
   request, response in
   response.appendBody(string: 'Hello world!')
   response.completed()
})
server.addRoutes(routes) // Add the routes to the server  
server.serverPort = 8181 // Set a listen port of 8181  
// Launch the HTTP server
do {  
   try server.start()
} catch PerfectError.networkError(let error, let msg) {
   print("Network error thrown: \(error) \(msg)")
}
</code></pre>

<p>Copy app directory to a directory on the server (eg. to /var/www/webapp). To compile and test the app:  </p>

<pre><code>cd /var/www/webapp  
swift build -c release  
./.build/release/webapp
</code></pre>

<p>Install supervisor  </p>

<pre><code>apt-get install -y supervisor  
</code></pre>

<p>To setup app running through Supervisor, create:  </p>

<pre><code>/etc/supervisor/conf.d/webapp.conf
</code></pre>

<pre><code>[program:webapp]
command = /var/www/webapp/.build/release/webapp serve --ip=127.0.0.1 --port=8181  
directory = /var/www/webapp/  
user=www-data  
autostart = true  
autorestart = true  
stdout_logfile = /var/log/supervisor/%(program_name)-stdout.log  
stderr_logfile = /var/log/supervisor/%(program_name)-stderr.log  
</code></pre>

<p>Append following to your nginx configuration:  </p>

<pre><code>location ~ ^/webapp(/?)(.*)$ {  
    alias /var/www/webapp;

    proxy_set_header   X-Real-IP $remote_addr;
    proxy_set_header   Host      $http_host;
    proxy_pass         http://127.0.0.1:8181/$2$is_args$args;
}
</code></pre>

<p>Restart nginx  </p>

<pre><code>service nginx restart  
</code></pre>

<p>Register the app with Supervisor:  </p>

<pre><code>supervisorctl reread  
supervisorctl add webapp  
</code></pre>

<p>Visit:  </p>

<pre><code>http://yourserver.com/webapp  
</code></pre>

<p>To start/stop app:  </p>

<pre><code>supervisorctl start webapp  
supervisorctl stop webapp  
</code></pre>

<p>In case if anything goes wrong...  </p>

<pre><code>/var/log/supervisor/webapp-stdout.log
/var/log/supervisor/webapp-stderr.log
/var/log/nginx/access.log;
/var/log/nginx/error.log;
</code></pre>

<h5 id="links">Links:</h5>

<p><a href="https://swift.org/download/#releases">Swift</a> <br>
<a href="http://perfect.org">Perfect</a> <br>
<a href="https://www.solarianprogrammer.com/2016/11/08/getting-started-swift-3-linux/">Getting started with Swift 3 on Linux</a> <br>
<a href="https://github.com/vapor-community/example">Deploying Vapor example</a>   </p>]]></content:encoded></item><item><title><![CDATA[Open ATC]]></title><description><![CDATA[<p>Cross-platform compatible (Linux, OS X and iOS) air traffic simulator. <br>
The source code and sample applications are available under <a href="https://www.gnu.org/licenses/gpl.txt">GPL-3.0</a> license and can be downloaded from <a href="https://github.com/sdrpa/oatc">Github</a> <br>
It was fun to prototype different ideas, play with modular design but it hasn't attracted too much attention.</p>]]></description><link>http://tagtaxa.com/going-open-source-with-open-atc/</link><guid isPermaLink="false">ee4aa5c5-3aca-464d-a35f-2864df7fbe81</guid><category><![CDATA[OATC]]></category><dc:creator><![CDATA[Sinisa Drpa]]></dc:creator><pubDate>Thu, 20 Apr 2017 16:36:01 GMT</pubDate><content:encoded><![CDATA[<p>Cross-platform compatible (Linux, OS X and iOS) air traffic simulator. <br>
The source code and sample applications are available under <a href="https://www.gnu.org/licenses/gpl.txt">GPL-3.0</a> license and can be downloaded from <a href="https://github.com/sdrpa/oatc">Github</a> <br>
It was fun to prototype different ideas, play with modular design but it hasn't attracted too much attention.</p>]]></content:encoded></item><item><title><![CDATA[Notbloko (macOS)(Discontinued)]]></title><description><![CDATA[<p>I've been using <a href="http://tagtaxa.com/notbloko-macos/notational.net">Notational Velocity</a> for a long time to take care of my notes. I like the idea of single text-entry used for both creating and searching content. I wrote my version in Swift with some features I needed for my use. You can read more about the app</p>]]></description><link>http://tagtaxa.com/notbloko-macos/</link><guid isPermaLink="false">0a62ba60-81eb-42e2-9b53-9d67198cc5b7</guid><category><![CDATA[Apps]]></category><category><![CDATA[OS X]]></category><category><![CDATA[macOS]]></category><category><![CDATA[Discontinued]]></category><dc:creator><![CDATA[Sinisa Drpa]]></dc:creator><pubDate>Sat, 24 Dec 2016 03:39:59 GMT</pubDate><media:content url="http://tagtaxa.com/content/images/2020/09/main.png" medium="image"/><content:encoded><![CDATA[<img src="http://tagtaxa.com/content/images/2020/09/main.png" alt="Notbloko (macOS)(Discontinued)"><p>I've been using <a href="http://tagtaxa.com/notbloko-macos/notational.net">Notational Velocity</a> for a long time to take care of my notes. I like the idea of single text-entry used for both creating and searching content. I wrote my version in Swift with some features I needed for my use. You can read more about the app <a href="https://tagtaxa.com/apps/notbloko/">here →</a>.</p>

<p>Mac App Store <a href="https://itunes.apple.com/us/app/notbloko/id1163842536">link →</a></p>]]></content:encoded></item><item><title><![CDATA[Two-way binding. Interstellar FRP - Cocoa]]></title><description><![CDATA[<p>A small experiment how to two-way bind a String property to a NSTextField.</p>

<p>References:</p>

<p><a href="https://github.com/JensRavens/Interstellar">Interstellar</a></p>

<p><a href="http://jensravens.com/uikonf-talk/">How to use Functional Reactive Programming without Black Magic</a> - Slide num. 40</p>

<pre><code class="language-swift">var observableKey: UInt8 = 0

extension NSTextField: NSTextFieldDelegate {

    // text is a readonly property (proxy). We create an observable string when text property is</code></pre>]]></description><link>http://tagtaxa.com/two-way-ui-binding-interstellar-swift/</link><guid isPermaLink="false">93152a6f-9667-4f44-bb4e-7c5c48d16dc3</guid><category><![CDATA[Swift]]></category><category><![CDATA[Interstellar]]></category><category><![CDATA[FRP]]></category><dc:creator><![CDATA[Sinisa Drpa]]></dc:creator><pubDate>Wed, 16 Nov 2016 17:11:54 GMT</pubDate><content:encoded><![CDATA[<p>A small experiment how to two-way bind a String property to a NSTextField.</p>

<p>References:</p>

<p><a href="https://github.com/JensRavens/Interstellar">Interstellar</a></p>

<p><a href="http://jensravens.com/uikonf-talk/">How to use Functional Reactive Programming without Black Magic</a> - Slide num. 40</p>

<pre><code class="language-swift">var observableKey: UInt8 = 0

extension NSTextField: NSTextFieldDelegate {

    // text is a readonly property (proxy). We create an observable string when text property is read for the first time and add the observable string as a custom property of the NSTextField.
    // To be able to receive the notification when text in text field changes we set self as the self delegate.
    // controlTextDidChange(:) is called when the text changes where we can update the observable string with the textField.stringValue
    public var text: Observable&lt;String&gt; {
        var observable: Observable&lt;String&gt;
        if let existing = objc_getAssociatedObject(self, &amp;observableKey) as? Observable&lt;String&gt; {
            observable = existing
        } else {
            observable = Observable&lt;String&gt;()

            self.delegate = self
            objc_setAssociatedObject(self, &amp;observableKey, observable, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        return observable
    }

    // Update text (observable string) with textField.stringValue when text in text field changes
    override open func controlTextDidChange(_ notification: Notification) {
        guard let textField = notification.object as? NSTextField else {
            return
        }
        self.text.update(textField.stringValue)
    }
}

// Two-way binding between CustomStringConvertible and NSTextField
extension Observable where T: CustomStringConvertible {

    func bind(to textField: NSTextField)  {
        self.subscribe { stringConvertible in
            textField.stringValue = String(describing: stringConvertible)
        }
        textField.text.subscribe { string in
            guard let value = string as? T else {
                return
            }
            self.update(value)
        }
    }
}

// Usage:

class ViewController: NSViewController {

    @IBOutlet weak var textField: NSTextField!

    let text = Observable&lt;String&gt;()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.text.bind(to: self.textField)
    }
}
</code></pre>

<p>Download demo project <a href="https://tagtaxa.com/download/storage/binding.zip">here</a></p>]]></content:encoded></item><item><title><![CDATA[Create Ubuntu 14.04 docker image with the latest Swift preview snapshot]]></title><description><![CDATA[<p>Short tutorial if you need a quick way to test Swift code on Linux. <br>
First, you need to download the latest available Swift preview from: <br>
<a href="https://swift.org/download/">https://swift.org/download/</a> <br>
(currently it's <a href="https://swift.org/builds/swift-3.0-preview-6/ubuntu1404/swift-3.0-PREVIEW-6/swift-3.0-PREVIEW-6-ubuntu14.04.tar.gz">https://swift.org/builds/swift-3.0-preview-6/ubuntu1404/swift-3.0-PREVIEW-6/swift-3.0-PREVIEW-6-ubuntu14.04.tar.gz</a>)</p>

<p>Download Docker for Mac from</p>]]></description><link>http://tagtaxa.com/create-ubuntu-14-04-docker-image-for-swift/</link><guid isPermaLink="false">0fe58abf-48d6-4e85-847d-bbe978e8f4c5</guid><dc:creator><![CDATA[Sinisa Drpa]]></dc:creator><pubDate>Sun, 28 Aug 2016 08:36:03 GMT</pubDate><content:encoded><![CDATA[<p>Short tutorial if you need a quick way to test Swift code on Linux. <br>
First, you need to download the latest available Swift preview from: <br>
<a href="https://swift.org/download/">https://swift.org/download/</a> <br>
(currently it's <a href="https://swift.org/builds/swift-3.0-preview-6/ubuntu1404/swift-3.0-PREVIEW-6/swift-3.0-PREVIEW-6-ubuntu14.04.tar.gz">https://swift.org/builds/swift-3.0-preview-6/ubuntu1404/swift-3.0-PREVIEW-6/swift-3.0-PREVIEW-6-ubuntu14.04.tar.gz</a>)</p>

<p>Download Docker for Mac from <a href="https://www.docker.com/products/docker#/mac">https://www.docker.com/products/docker#/mac</a> <br>
Install and run Docker.</p>

<p>Open two terminal windows. <br>
The first terminal window will be used to enter docker commands (i.e. to start/save the container), the commands are prefixed with: </p>

<pre><code>macbook:~ sdrpa$ ...
</code></pre>

<p>The second terminal will be the container running Ubuntu, the commands are prefixed with:</p>

<pre><code>root@a3f8e5c13ff8:/# ...
</code></pre>

<h3 id="herewego">Here we go:</h3>

<p>Pull ubuntu 14.04 image and run a container:</p>

<pre><code>macbook:~ sdrpa$ docker pull ubuntu:14.04
macbook:~ sdrpa$ docker run --privileged -t -i ubuntu:14.04 /bin/bash
</code></pre>

<p>Get the container's name:</p>

<pre><code>macbook:~ sdrpa$ docker ps
</code></pre>

<p>Copy Swift archive to the container:</p>

<pre><code>macbook:~ sdrpa$ docker cp /Users/sdrpa/swift-3.0-PREVIEW-6-ubuntu14.04.tar.gz &lt;CONTAINER NAME&gt;:/root/swift-3.0-PREVIEW-6-ubuntu14.04.tar.gz
</code></pre>

<p>Now inside the container extract and delete the archive:</p>

<pre><code>root@a3f8e5c13ff8:/# tar -xvf swift-3.0-PREVIEW-6-ubuntu14.04.tar.gz
root@a3f8e5c13ff8:/# rm -f swift-3.0-PREVIEW-6-ubuntu14.04.tar.gz
</code></pre>

<p>Install required libs:</p>

<pre><code>root@a3f8e5c13ff8:/# apt-get update
root@a3f8e5c13ff8:/# apt-get install clang
root@a3f8e5c13ff8:/# apt-get install binutils
root@a3f8e5c13ff8:/# apt-get install libedit2
root@a3f8e5c13ff8:/# apt-get install libicu52
root@a3f8e5c13ff8:/# apt-get install libxml2
root@a3f8e5c13ff8:/# apt-get install python2.7-dev
</code></pre>

<p>Edit PATH so Ubuntu can find Swift binaries (I prefer nano but you can use vi):</p>

<pre><code>root@a3f8e5c13ff8:/# apt-get install nano
root@a3f8e5c13ff8:/# cd ~
root@a3f8e5c13ff8:/# nano .profile and add export PATH=/root/swift-3.0-PREVIEW-6-ubuntu14.04/usr/bin:"${PATH}"
root@a3f8e5c13ff8:/# source .profile
</code></pre>

<p>The container is ready, save the changes:</p>

<pre><code>macbook:~ sdrpa$ docker ps -l
macbook:~ sdrpa$ docker commit &lt;CONTAINER ID&gt; swift
</code></pre>

<p>To start container next time:</p>

<pre><code>macbook:~ sdrpa$ docker run --privileged -t -i swift /bin/bash --login
</code></pre>

<p>Related links:</p>

<p><a href="http://www.swiftprogrammer.info/swift">http://www.swiftprogrammer.info/swift</a><em>ubuntu</em>1.html <br>
<a href="http://code.tutsplus.com/tutorials/how-to-use-swift-on-linux--cms-25934">http://code.tutsplus.com/tutorials/how-to-use-swift-on-linux--cms-25934</a></p>]]></content:encoded></item></channel></rss>