<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alexandr K</title>
    <description>The latest articles on DEV Community by Alexandr K (@oivoodoo).</description>
    <link>https://dev.to/oivoodoo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F49798%2Fa9d81436-891a-4ce6-8e76-b15d9c0ef128.jpg</url>
      <title>DEV Community: Alexandr K</title>
      <link>https://dev.to/oivoodoo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oivoodoo"/>
    <language>en</language>
    <item>
      <title>Build unsigned iOS ipa to install via Sideloadly!</title>
      <dc:creator>Alexandr K</dc:creator>
      <pubDate>Wed, 05 Nov 2025 11:08:07 +0000</pubDate>
      <link>https://dev.to/oivoodoo/build-unsigned-ios-ipa-to-install-via-sideloadly-236f</link>
      <guid>https://dev.to/oivoodoo/build-unsigned-ios-ipa-to-install-via-sideloadly-236f</guid>
      <description>&lt;p&gt;Recently during the development it would require to test Apple Enclave with public/private key generation, since we are using Expo / React Native. I wanted to have the close enough build to the real app and don’t deliver the app to TestFlight by reducing the amount of time for the development.&lt;/p&gt;

&lt;p&gt;Yes, used claude code to make the script but anyway it worked well for me and decided to share it.&lt;/p&gt;

&lt;p&gt;Justfile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# iOS Build Configuration&lt;/span&gt;
app_name :&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PushUP"&lt;/span&gt;
workspace :&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ios/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;app_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.xcworkspace"&lt;/span&gt;
scheme :&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;app_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
configuration :&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Release"&lt;/span&gt;
archive_path :&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"build/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;app_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.xcarchive"&lt;/span&gt;
export_path :&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"build/ipa"&lt;/span&gt;
bundle_id :&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"co.bitscorp.pushup"&lt;/span&gt;

&lt;span class="c"&gt;# Default recipe - shows available commands&lt;/span&gt;
default:
    @just &lt;span class="nt"&gt;--list&lt;/span&gt;

&lt;span class="c"&gt;# Deep clean (closes Xcode and cleans everything)&lt;/span&gt;
clean:
    &lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
    &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"🧹 Deep cleaning (closing Xcode)..."&lt;/span&gt;
    &lt;span class="c"&gt;# Close Xcode if running&lt;/span&gt;
    killall Xcode 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
    sleep &lt;/span&gt;2
    &lt;span class="c"&gt;# Clean everything&lt;/span&gt;
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; build/
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ios/build/
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ios/Pods
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ios/Podfile.lock
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Developer/Xcode/DerivedData/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;app_name&lt;/span&gt;&lt;span class="k"&gt;}*&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Deep clean complete"&lt;/span&gt;

&lt;span class="c"&gt;# Build without archiving (for testing)&lt;/span&gt;
build:
    &lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
    &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"🔨 Building project..."&lt;/span&gt;
    &lt;span class="c"&gt;# Source Xcode environment for Node binary&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; ios/.xcode.env.local &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;source &lt;/span&gt;ios/.xcode.env.local
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; ios/.xcode.env &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;source &lt;/span&gt;ios/.xcode.env
    &lt;span class="k"&gt;fi
    &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;NODE_BINARY
    xcodebuild build &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-workspace&lt;/span&gt; &lt;span class="o"&gt;{{&lt;/span&gt;workspace&lt;span class="o"&gt;}}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-scheme&lt;/span&gt; &lt;span class="o"&gt;{{&lt;/span&gt;scheme&lt;span class="o"&gt;}}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-configuration&lt;/span&gt; &lt;span class="o"&gt;{{&lt;/span&gt;configuration&lt;span class="o"&gt;}}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-sdk&lt;/span&gt; iphoneos &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-destination&lt;/span&gt; &lt;span class="s1"&gt;'generic/platform=iOS'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-allowProvisioningUpdates&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nv"&gt;CODE_SIGN_STYLE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Automatic &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nv"&gt;ONLY_ACTIVE_ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NO

&lt;span class="c"&gt;# Archive the iOS app&lt;/span&gt;
archive:
    &lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
    &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"📦 Creating archive..."&lt;/span&gt;
    &lt;span class="c"&gt;# Source Xcode environment for Node binary&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; ios/.xcode.env.local &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;source &lt;/span&gt;ios/.xcode.env.local
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; ios/.xcode.env &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;source &lt;/span&gt;ios/.xcode.env
    &lt;span class="k"&gt;fi
    &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;NODE_BINARY
    xcodebuild archive &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-workspace&lt;/span&gt; &lt;span class="o"&gt;{{&lt;/span&gt;workspace&lt;span class="o"&gt;}}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-scheme&lt;/span&gt; &lt;span class="o"&gt;{{&lt;/span&gt;scheme&lt;span class="o"&gt;}}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-configuration&lt;/span&gt; &lt;span class="o"&gt;{{&lt;/span&gt;configuration&lt;span class="o"&gt;}}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-sdk&lt;/span&gt; iphoneos &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-destination&lt;/span&gt; &lt;span class="s1"&gt;'generic/platform=iOS'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-archivePath&lt;/span&gt; &lt;span class="o"&gt;{{&lt;/span&gt;archive_path&lt;span class="o"&gt;}}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-allowProvisioningUpdates&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nv"&gt;CODE_SIGN_STYLE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Automatic &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nv"&gt;ONLY_ACTIVE_ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NO


&lt;span class="c"&gt;# Extract IPA from archive without code signing (for Sideloadly)&lt;/span&gt;
export-unsigned:
    &lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
    &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"📱 Creating unsigned IPA from archive for Sideloadly..."&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="o"&gt;{{&lt;/span&gt;archive_path&lt;span class="o"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"❌ Archive not found at {{archive_path}}"&lt;/span&gt;
        &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="k"&gt;fi&lt;/span&gt;

    &lt;span class="c"&gt;# Find the .app in the archive&lt;/span&gt;
    &lt;span class="nv"&gt;APP_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;find &lt;span class="o"&gt;{{&lt;/span&gt;archive_path&lt;span class="o"&gt;}}&lt;/span&gt;/Products/Applications &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.app"&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 1 | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 1&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$APP_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"❌ No .app found in archive"&lt;/span&gt;
        &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="k"&gt;fi

    &lt;/span&gt;&lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$APP_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;IPA_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="p"&gt;%.app&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.ipa"&lt;/span&gt;

    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Found app: &lt;/span&gt;&lt;span class="nv"&gt;$APP_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="c"&gt;# Create Payload directory&lt;/span&gt;
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="o"&gt;{{&lt;/span&gt;export_path&lt;span class="o"&gt;}}&lt;/span&gt;/Payload
    &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="o"&gt;{{&lt;/span&gt;export_path&lt;span class="o"&gt;}}&lt;/span&gt;/Payload

    &lt;span class="c"&gt;# Copy .app to Payload&lt;/span&gt;
    &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$APP_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;{{&lt;/span&gt;export_path&lt;span class="o"&gt;}}&lt;/span&gt;/Payload/

    &lt;span class="c"&gt;# Create IPA (which is just a zip file)&lt;/span&gt;
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="o"&gt;{{&lt;/span&gt;export_path&lt;span class="o"&gt;}}&lt;/span&gt;
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IPA_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    zip &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IPA_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; Payload
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; Payload

    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Unsigned IPA created at {{export_path}}/&lt;/span&gt;&lt;span class="nv"&gt;$IPA_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;


&lt;span class="c"&gt;# Full build: clean, archive, and export for Development&lt;/span&gt;
ios: build archive export-unsigned
    @echo &lt;span class="s2"&gt;"✅ Done at {{export_path}}"&lt;/span&gt;J
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;just ios&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And then download Sideloadly! app for mac and install it to your iPhone by signing with your developer account.&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

</description>
      <category>mobiledevelopment</category>
      <category>reactnative</category>
      <category>expo</category>
      <category>consulting</category>
    </item>
    <item>
      <title>Full Stack Developer from bitscorp.co looking for new opportunities</title>
      <dc:creator>Alexandr K</dc:creator>
      <pubDate>Tue, 04 Nov 2025 09:33:32 +0000</pubDate>
      <link>https://dev.to/oivoodoo/full-stack-developer-from-bitscorpco-looking-for-new-opportunities-19nj</link>
      <guid>https://dev.to/oivoodoo/full-stack-developer-from-bitscorpco-looking-for-new-opportunities-19nj</guid>
      <description>&lt;p&gt;Hey everyone!&lt;/p&gt;

&lt;p&gt;One of the developers from our team at bitscorp.co is looking for new opportunities. He's been working with us for a while and I can say he's a solid engineer who can handle both backend and frontend pretty well.&lt;/p&gt;

&lt;p&gt;The stack he's comfortable with: Node, Go, Ruby on the backend side and React, React Native for the frontend. Pretty much full stack developer who can jump into any part of the project and deliver.&lt;/p&gt;

&lt;p&gt;He's been working on different projects with us, from building APIs to mobile apps. Good experience with production systems, knows how to debug issues and ship features without breaking things.&lt;/p&gt;

&lt;p&gt;If you're looking for someone who can work independently and doesn't need hand-holding for every task, he would be a good fit..&lt;/p&gt;

&lt;p&gt;If you have something interesting or know someone who's hiring, feel free to reach out. You can contact through bitscorp.co or leave a comment here.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;p&gt;Our portfolio:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://balconygames.com" rel="noopener noreferrer"&gt;https://balconygames.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bitscorp.co" rel="noopener noreferrer"&gt;https://bitscorp.co&lt;/a&gt;&lt;/p&gt;

</description>
      <category>fullstack</category>
      <category>javascript</category>
      <category>career</category>
      <category>react</category>
    </item>
    <item>
      <title>Catalan Verbs - mobile app</title>
      <dc:creator>Alexandr K</dc:creator>
      <pubDate>Sat, 28 Dec 2024 15:55:10 +0000</pubDate>
      <link>https://dev.to/oivoodoo/catalan-verbs-mobile-app-5abm</link>
      <guid>https://dev.to/oivoodoo/catalan-verbs-mobile-app-5abm</guid>
      <description>&lt;p&gt;Hello.&lt;/p&gt;

&lt;p&gt;Couple days ago for my birthday I published the new application, developed it for fun and learning catalan because living close enough to Barcelona and it's really nice &lt;br&gt;
language.&lt;/p&gt;

&lt;p&gt;Tech stack: ReactNative, Scrapy, Python (to automate translations), Cursor (probably I should include it now because it's really increasing speed of the development)&lt;/p&gt;

&lt;p&gt;Ready to master Catalan verbs? Download now:&lt;br&gt;
📱 iOS: &lt;a href="https://apps.apple.com/es/app/catalan-verbs/id6738144158" rel="noopener noreferrer"&gt;https://apps.apple.com/es/app/catalan-verbs/id6738144158&lt;/a&gt;&lt;br&gt;
🤖 Android: &lt;a href="https://play.google.com/store/apps/details?id=co.bitscorp.cat" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=co.bitscorp.cat&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  CatalanLanguage #LanguageLearning #Education #ReactNative #TechInEducation
&lt;/h1&gt;

</description>
      <category>mobileapp</category>
      <category>reactnative</category>
      <category>indiedev</category>
    </item>
    <item>
      <title>Learn Spanish Chrome extension</title>
      <dc:creator>Alexandr K</dc:creator>
      <pubDate>Sun, 08 Sep 2024 17:14:56 +0000</pubDate>
      <link>https://dev.to/oivoodoo/learn-spanish-chrome-extension-b12</link>
      <guid>https://dev.to/oivoodoo/learn-spanish-chrome-extension-b12</guid>
      <description>&lt;p&gt;Hello.&lt;/p&gt;

&lt;p&gt;I've just published the new extension for google chrome. I developed so fast but it's really useful for me because of learning the last months Spanish in free time. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://chromewebstore.google.com/detail/learn-spanish/onnolcnjhjbmcgfppkmamfkadklopbkj?ref=producthunt" rel="noopener noreferrer"&gt;Learn Spanish&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;10 words for free daily to learn&lt;/p&gt;

&lt;p&gt;and then I added whop integration to make one time lifetime payment to make the app unlimited words daily on each tab open.&lt;/p&gt;

&lt;p&gt;Don't think it would be possible to monetize it anyway but I tried to make such in chrome extension payment for learning purpose anyway.&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

</description>
      <category>chrome</category>
      <category>extension</category>
    </item>
    <item>
      <title>React Native and OpenAI</title>
      <dc:creator>Alexandr K</dc:creator>
      <pubDate>Mon, 10 Jun 2024 18:38:44 +0000</pubDate>
      <link>https://dev.to/oivoodoo/react-native-and-openai-4e9a</link>
      <guid>https://dev.to/oivoodoo/react-native-and-openai-4e9a</guid>
      <description>&lt;p&gt;Hello.&lt;/p&gt;

&lt;p&gt;I've just developed the simple application using OpenAI / ChatGPT and  had a lot of fun and how easy it was.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=4NjaXtJHTwM" rel="noopener noreferrer"&gt;App preview&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I know the app is really joke but anyway I liked the ability to pass the image and ask the specific questions about it.&lt;/p&gt;

&lt;p&gt;For me it's really the first experience and probably it's really too obvious for a lot of developers who are involved now in using AI models for their applications.&lt;/p&gt;

&lt;p&gt;Lets see the communication function and it would be really clean enough what the app does.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;image_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppLanguage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// This is the default and can be omitted&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;completion&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4-turbo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
You are palm reader, explain by reading palm the user background, life, future, fate. Please write at least 10 setences about each topic:
- user line of life
- user line of heart
- user line of mind
- user line of fate
- user extra information that we need to mention

Only provide a RFC8259 compliant JSON response:
[
  {
    "line_life": "user line of life",
    "line_heart": "user line of heart",
    "line_mind": "user line of mind",
    "line_fate": "user line of fate",
    "line_extra": "user extra information"
  }
]`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
- user line of life, 10+ sentences
- user line of heart, 10+ sentences
- user line of mind, 10+ sentences
- user line of fate, 10+ sentences
- user extra information that we need to mention, 10+ sentences
                `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Use language &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; for answers.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Describe my palm but in format { "line_heart": "text...", "line_life": "text...", "line_mind": "text...", "line_fate": "text...", "line_extra": "text..." }&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image_url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;image_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`data:image/jpeg;base64,&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;image_url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withResponse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;replies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;Sentry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Native&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;captureException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;cur&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;replies&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Sentry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Native&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;captureException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see I used the specific prompts to output the responses in json and pass the image to analyze it. Also I localized the app by using en, es, de, fr, ru languages and saying to ChatGPT to respond me in specific language and it works out of the box. it's really math magic. :)&lt;/p&gt;

&lt;p&gt;Of course I will publish the app but the huge problem for now that it's really expensive to ask &lt;code&gt;gpt-4-turbo&lt;/code&gt; and probably the app will stay for awhile and then I would need to disable it.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>openai</category>
      <category>mobileapp</category>
      <category>react</category>
    </item>
    <item>
      <title>Would it be interesting for anyone to have the text-based guide on how we develop pushup.bitscorp.co mobile app for 2 weeks?</title>
      <dc:creator>Alexandr K</dc:creator>
      <pubDate>Sun, 01 Oct 2023 13:53:56 +0000</pubDate>
      <link>https://dev.to/oivoodoo/would-it-be-interesting-for-anyone-to-have-the-text-based-guide-on-how-we-develop-pushupbitscorpco-mobile-app-for-2-weeks-2bae</link>
      <guid>https://dev.to/oivoodoo/would-it-be-interesting-for-anyone-to-have-the-text-based-guide-on-how-we-develop-pushupbitscorpco-mobile-app-for-2-weeks-2bae</guid>
      <description>&lt;p&gt;Thinking about building a text-based course about how we developed a mobile app using ReactNative / Supabase / ChatGPT and then published it to the App Store and Google Play?&lt;/p&gt;

&lt;p&gt;The app for a month got about 60+ users with no adverts (only organic traffic) and having daily 20–40 daily tracked sports activities for the current users daily.&lt;/p&gt;

&lt;p&gt;I would say in iOS the sports apps have more organic traffic in my experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apps.apple.com/us/app/pushup-challenges/id6450053262" rel="noopener noreferrer"&gt;App Store&lt;/a&gt;&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=co.bitscorp.pushup" rel="noopener noreferrer"&gt;Google Play&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pushup.bitscorp.co" rel="noopener noreferrer"&gt;Web&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>supabase</category>
      <category>mobileapp</category>
    </item>
    <item>
      <title>Push up | Mobile App</title>
      <dc:creator>Alexandr K</dc:creator>
      <pubDate>Mon, 11 Sep 2023 13:35:11 +0000</pubDate>
      <link>https://dev.to/bitscorp/push-up-mobile-app-4lll</link>
      <guid>https://dev.to/bitscorp/push-up-mobile-app-4lll</guid>
      <description>&lt;p&gt;Hello.&lt;/p&gt;

&lt;p&gt;We published our pet project to improve health by daily habbits.&lt;/p&gt;

&lt;p&gt;Actually it's only about push ups and squats. Invite your friend and start to do exercises together.&lt;/p&gt;

&lt;p&gt;Simple enough idea migrated from google spreadsheets into the app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pushup.bitscorp.co/" rel="noopener noreferrer"&gt;Push Up&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope it would help someone to improve their life style during the working day.&lt;/p&gt;

</description>
      <category>appstore</category>
      <category>googleplay</category>
      <category>mobileapp</category>
    </item>
    <item>
      <title>Optimizing Elixir Phoenix action with huge json response by responding by cached, gzipped values.</title>
      <dc:creator>Alexandr K</dc:creator>
      <pubDate>Wed, 19 Jul 2023 08:43:59 +0000</pubDate>
      <link>https://dev.to/bitscorp/optimizing-elixir-phoenix-action-with-huge-json-response-by-responding-by-cached-gzipped-values-1d64</link>
      <guid>https://dev.to/bitscorp/optimizing-elixir-phoenix-action-with-huge-json-response-by-responding-by-cached-gzipped-values-1d64</guid>
      <description>&lt;p&gt;Hello,&lt;/p&gt;

&lt;p&gt;It's great to be back, and I'm excited to share the recent code changes I've implemented for my clients. We've been working on a mobile react native application that includes a wiki-like section, providing users with valuable step-by-step information to improve their health.&lt;/p&gt;

&lt;p&gt;One of the challenges we faced was dealing with a massive JSON response, roughly 20MB in size, retrieved from a single endpoint during the app's loading process. While we could split API requests and load content on-demand, we also wanted to ensure that users could access the app offline, making a one-time load during the initial launch beneficial.&lt;/p&gt;

&lt;p&gt;The loading process was taking around 6 seconds, depending on the internet speed, and I decided to implement a quick fix, particularly for the wiki endpoints.&lt;/p&gt;

&lt;p&gt;In our Elixir environment, we found the perfect solution in the &lt;a href="https://github.com/whitfin/cachex" rel="noopener noreferrer"&gt;cachex&lt;/a&gt; library. This impressive library features a &lt;code&gt;warmer&lt;/code&gt; module, which automatically refreshes cached data either on boot or after a specified &lt;code&gt;ttl&lt;/code&gt; (time-to-live).&lt;/p&gt;

&lt;p&gt;By integrating &lt;a href="https://github.com/whitfin/cachex" rel="noopener noreferrer"&gt;cachex&lt;/a&gt; into our system, we're now able to optimize the loading process, providing users with a smoother experience while still benefiting from offline accessibility. Stay tuned as I delve deeper into the caching practices that helped us enhance the performance of our Phoenix Controller actions with JSON responses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;BlogApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;PostsWarmer&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Cachex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Warmer&lt;/span&gt;

  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;BlogApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Posts&lt;/span&gt;

  &lt;span class="kn"&gt;require&lt;/span&gt; &lt;span class="no"&gt;Logger&lt;/span&gt;
  &lt;span class="kn"&gt;require&lt;/span&gt; &lt;span class="no"&gt;Jsonrs&lt;/span&gt;

  &lt;span class="nv"&gt;@cache_table&lt;/span&gt; &lt;span class="ss"&gt;:blog_app_cache&lt;/span&gt;
  &lt;span class="nv"&gt;@posts_cache_key&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:posts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:list_posts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;:timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="n"&gt;get_posts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;ttl:&lt;/span&gt; &lt;span class="ss"&gt;:timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)]}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get_cached_posts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;get_or_put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@posts_cache_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;get_posts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Posts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list_published_posts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="no"&gt;BlogAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;V1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;PostsView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"index.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;
        &lt;span class="ss"&gt;posts:&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Jsonrs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode!&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:zlib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gzip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;@posts_cache_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;get_or_put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;Cachex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@cache_table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
          &lt;span class="nv"&gt;@posts_cache_key&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_posts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="no"&gt;Cachex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@cache_table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="no"&gt;Cachex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@cache_table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

          &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="no"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"[your_app] cache key not found: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="no"&gt;nil&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;cache.ex&lt;/code&gt; in the lib folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;BlogApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Cache&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@moduledoc&lt;/span&gt; &lt;span class="sd"&gt;"""
  Cache
  """&lt;/span&gt;
  &lt;span class="nv"&gt;@cache_table&lt;/span&gt; &lt;span class="ss"&gt;:blog_app_cache&lt;/span&gt;

  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Cachex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Spec&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;child_spec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_init_arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;%{&lt;/span&gt;
      &lt;span class="ss"&gt;id:&lt;/span&gt; &lt;span class="nv"&gt;@cache_table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;type:&lt;/span&gt; &lt;span class="ss"&gt;:supervisor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;start:&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;Cachex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:start_link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="p"&gt;[&lt;/span&gt;
           &lt;span class="nv"&gt;@cache_table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="p"&gt;[&lt;/span&gt;
             &lt;span class="ss"&gt;warmers:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
               &lt;span class="n"&gt;warmer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;module:&lt;/span&gt; &lt;span class="no"&gt;BlogApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;PostsWarmer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;state:&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="p"&gt;]&lt;/span&gt;
           &lt;span class="p"&gt;]&lt;/span&gt;
         &lt;span class="p"&gt;]}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this warmer module to &lt;code&gt;application.ex&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;BlogApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@moduledoc&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;

  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="o"&gt;...&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;BlogApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="no"&gt;Supervisor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;strategy:&lt;/span&gt; &lt;span class="ss"&gt;:one_for_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="no"&gt;BlogApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Supervisor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now you are ready to integrate this cached, gzipped data in the Phoenix controller.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;PostsWarmer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_cached_posts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="n"&gt;conn&lt;/span&gt;
  &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;put_resp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Content-Encoding"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"gzip"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;put_resp_content_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;send_resp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s a short but powerful speed-up. Also, I’ve just started to use it for the huge JSON files &lt;a href="https://github.com/benhaney/Jsonrs" rel="noopener noreferrer"&gt;jsonrs&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

&lt;p&gt;Available for consulting Elixir, Go, JS, and Big Data. Our website: &lt;a href="https://bitscorp.co" rel="noopener noreferrer"&gt;bitscorp.co&lt;/a&gt; and my Github: &lt;a href="https://github.com/oivoodoo" rel="noopener noreferrer"&gt;github.com/oivoodoo&lt;/a&gt;, &lt;a href="https://github.com/bitscorp" rel="noopener noreferrer"&gt;github.com/bitscorp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My other blog: &lt;a href="https://dev.to/oivoodoo"&gt;https://dev.to/oivoodoo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>phoenix</category>
      <category>phoenixframework</category>
    </item>
    <item>
      <title>Road to ecommerce via Gumroad :)</title>
      <dc:creator>Alexandr K</dc:creator>
      <pubDate>Mon, 27 Dec 2021 22:11:34 +0000</pubDate>
      <link>https://dev.to/balconygames/road-to-ecommerce-via-gumroad--20nh</link>
      <guid>https://dev.to/balconygames/road-to-ecommerce-via-gumroad--20nh</guid>
      <description>&lt;p&gt;Hi everyone!&lt;/p&gt;

&lt;p&gt;I've just started to sell of my game arts and complete games based on Unity engine that it could be useful for someone. I decided to focus on building the new games and one more coming the next month for testing the audience in TD style.&lt;/p&gt;

&lt;p&gt;But for now I need to capture some budget for the marketing the new game. Hope it will be possible to do it with wonderful platform Gumroad. I've just discovered how easy to create the products pages and start selling it.&lt;/p&gt;

&lt;p&gt;Products:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://balconygames.gumroad.com/l/game-dont-fall/happycoding?_gl=1*2dery6*_ga*MTg3ODY3OTMxNS4xNjM3MTgzMjQw*_ga_6LJN6D94N6*MTY0MDY0Mjc2MC4xMy4xLjE2NDA2NDI5MjUuMA.." rel="noopener noreferrer"&gt;Complete Game - Don't Fall&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.balconygames.dontfall" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.balconygames.dontfall&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apps.apple.com/es/app/dont-fall-by-balcony-games/id1460842492" rel="noopener noreferrer"&gt;https://apps.apple.com/es/app/dont-fall-by-balcony-games/id1460842492&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://balconygames.gumroad.com/l/dont-fall-art/bsfr4ww?_gl=1*1k5lihx*_ga*MTg3ODY3OTMxNS4xNjM3MTgzMjQw*_ga_6LJN6D94N6*MTY0MDY0Mjc2MC4xMy4xLjE2NDA2NDI5OTQuMA.." rel="noopener noreferrer"&gt;Game Art - Don't Fall, older version&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://balconygames.gumroad.com/l/snake-game-art/bsfr4ww?_gl=1*1jr3fd8*_ga*MTg3ODY3OTMxNS4xNjM3MTgzMjQw*_ga_6LJN6D94N6*MTY0MDY0Mjc2MC4xMy4xLjE2NDA2NDMwMTIuMA.." rel="noopener noreferrer"&gt;Game Art - Snake&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.balconygames.snake" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.balconygames.snake&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://balconygames.gumroad.com/l/paiint-swipe-game/bsfr4ww?_gl=1*o9b1hp*_ga*MTg3ODY3OTMxNS4xNjM3MTgzMjQw*_ga_6LJN6D94N6*MTY0MDY0Mjc2MC4xMy4xLjE2NDA2NDMwMzIuMA.." rel="noopener noreferrer"&gt;Game Art - Paint Swipe&lt;/a&gt; - this game I didn't finish it but I will polish and share the source code later as well. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;p&gt;Thank you!&lt;/p&gt;

&lt;p&gt;Alex.&lt;/p&gt;

</description>
      <category>gameart</category>
      <category>gamedev</category>
      <category>ecommerce</category>
      <category>gumroad</category>
    </item>
    <item>
      <title>Phoenix umbrella proxy application.</title>
      <dc:creator>Alexandr K</dc:creator>
      <pubDate>Tue, 15 Jun 2021 09:40:08 +0000</pubDate>
      <link>https://dev.to/oivoodoo/phoenix-umbrella-proxy-application-7kc</link>
      <guid>https://dev.to/oivoodoo/phoenix-umbrella-proxy-application-7kc</guid>
      <description>&lt;p&gt;Hey everyone!&lt;/p&gt;

&lt;p&gt;It's really long time to take me to start writing again. I was really busy trying to make the games as part of my free time company &lt;a href="https://balcony.games" rel="noopener noreferrer"&gt;balconygames&lt;/a&gt; :) Good progress but it's not so good enough for the market because of the user acquisition is so expensive.&lt;/p&gt;

&lt;p&gt;Today I've decided to share the example of the proxy application for umbrella Phoenix, probably it would be useful for someone who has the same issues like code reloading, websocket support. It has 4 apps inside of &lt;code&gt;apps/&lt;/code&gt;, &lt;code&gt;proxy&lt;/code&gt;, &lt;code&gt;web(phoenix)&lt;/code&gt;, &lt;code&gt;admin(phoenix)&lt;/code&gt;, &lt;code&gt;db(shared ecto project)&lt;/code&gt;. No more words, going to share::&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;YourApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@moduledoc&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;

  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;LiveReloader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;as:&lt;/span&gt; &lt;span class="no"&gt;LiveReloadSocket&lt;/span&gt;

  &lt;span class="kn"&gt;require&lt;/span&gt; &lt;span class="no"&gt;Logger&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Supervisor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Spec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;warn:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;

    &lt;span class="n"&gt;require_code_reloading?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:your_app_web&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;strategy:&lt;/span&gt; &lt;span class="ss"&gt;:one_for_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="no"&gt;YourApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Supervisor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="no"&gt;Supervisor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:test&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;proxy_children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="no"&gt;Plug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Cowboy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;scheme:&lt;/span&gt; &lt;span class="ss"&gt;:http&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;plug:&lt;/span&gt; &lt;span class="no"&gt;YourApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;port:&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="ss"&gt;dispatch:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="p"&gt;[&lt;/span&gt;
             &lt;span class="c1"&gt;# your_app_web&lt;/span&gt;
             &lt;span class="n"&gt;web_phoenix_live_reload&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
             &lt;span class="n"&gt;web_phoenix_live_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
             &lt;span class="n"&gt;web_websocket&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
             &lt;span class="c1"&gt;# your_app_admin&lt;/span&gt;
             &lt;span class="n"&gt;admin_phoenix_live_reload&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
             &lt;span class="n"&gt;admin_phoenix_live_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
             &lt;span class="n"&gt;admin_websocket&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
             &lt;span class="c1"&gt;# proxy&lt;/span&gt;
             &lt;span class="n"&gt;master_proxy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
           &lt;span class="p"&gt;]}&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# - proxy endpoints&lt;/span&gt;
    &lt;span class="c1"&gt;#    - /api endpoints&lt;/span&gt;
    &lt;span class="c1"&gt;#    - /dev/admin pages&lt;/span&gt;
    &lt;span class="c1"&gt;# - web watchers for webpacker and code reloading&lt;/span&gt;
    &lt;span class="c1"&gt;# - admin watchers for webpacker and code reloading&lt;/span&gt;
    &lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="n"&gt;proxy_children&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;
        &lt;span class="n"&gt;watcher_children&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="ss"&gt;:your_app_web&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="no"&gt;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;
        &lt;span class="n"&gt;watcher_children&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="ss"&gt;:your_app_admin_web&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="no"&gt;YourAppAdminWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;children&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;watcher_children&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;otp_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;conf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;otp_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:watchers&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Watcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;watcher_args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;watcher_args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split_while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd_args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;is_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"PORT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"4000"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_integer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;web_phoenix_live_reload&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;websocket_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;"/phoenix/live_reload/socket/websocket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="no"&gt;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;LiveReloadSocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:websocket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;web_phoenix_live_view&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;websocket_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;"/live"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="no"&gt;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;LiveView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:websocket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;web_websocket&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;websocket_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;"/cable/websocket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="no"&gt;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;UserSocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;websocket:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;admin_phoenix_live_reload&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;websocket_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;"/dev/admin/phoenix/live_reload/socket/websocket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="no"&gt;YourAppAdminWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;LiveReloadSocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:websocket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;admin_phoenix_live_view&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;websocket_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;"/dev/admin/live"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="no"&gt;YourAppAdminWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;LiveView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:websocket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;admin_websocket&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;websocket_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;"/dev/admin/websocket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="no"&gt;YourAppAdminWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;YourAppAdminWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;UserSocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;websocket:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;master_proxy&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Plug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Cowboy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;YourApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Plug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]}}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;websocket_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Cowboy2Handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;require_code_reloading?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;otp_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;conf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;otp_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:code_reloader&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;CodeReloader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_symlinks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>phoenixframework</category>
      <category>phoenix</category>
      <category>development</category>
    </item>
    <item>
      <title>New version of Crystal Blast 2.0</title>
      <dc:creator>Alexandr K</dc:creator>
      <pubDate>Mon, 20 Jul 2020 06:19:50 +0000</pubDate>
      <link>https://dev.to/balconygames/new-version-of-crystal-blast-3922</link>
      <guid>https://dev.to/balconygames/new-version-of-crystal-blast-3922</guid>
      <description>&lt;p&gt;Hi everyone!&lt;/p&gt;

&lt;p&gt;Finally, we have just published the new version of &lt;a href="https://play.google.com/store/apps/details?id=com.balconygames.CrystalBlast" rel="noopener noreferrer"&gt;Crystal Blast - Google Play&lt;/a&gt; and waiting for review success in &lt;a href="https://apps.apple.com/us/app/crystal-blast/id1451868968" rel="noopener noreferrer"&gt;Crystal Blast - App Store&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We added the wonderful sound effects, more ways to earn coins (it's only about the monetization, we added for the players to fast grow their weapons, ships), leaderboard.&lt;/p&gt;

&lt;p&gt;As part of this build, I started to use my own game server for collecting analytics, storing player game settings, leaderboard. &lt;/p&gt;

&lt;p&gt;Working on cleaning up the server-side code and share with the community as a good entry point for indie game developers.&lt;/p&gt;

&lt;p&gt;Stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go&lt;/li&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;ClickHouse&lt;/li&gt;
&lt;li&gt;NSQ&lt;/li&gt;
&lt;li&gt;ansible + docker-compose as the fastest way to just deploy the app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

&lt;p&gt;Best regards,&lt;br&gt;
Alexandr.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>indiegame</category>
      <category>indiegamedev</category>
    </item>
    <item>
      <title>Started to build game server for indie developers</title>
      <dc:creator>Alexandr K</dc:creator>
      <pubDate>Wed, 17 Jun 2020 13:50:44 +0000</pubDate>
      <link>https://dev.to/balconygames/started-to-build-game-server-for-indie-developers-1j9m</link>
      <guid>https://dev.to/balconygames/started-to-build-game-server-for-indie-developers-1j9m</guid>
      <description>&lt;p&gt;For the last months I didn't write anything, isolation in the house, work and work. Searching for the new contracts to work in free time, it was a bit exhausting :) and I decided to build something new for me.&lt;/p&gt;

&lt;p&gt;I've just started to work on generic purporse game server for indie developers. I have already implemented key, value storage, leaderboards, guest auth by device id and working on the social networking.&lt;/p&gt;

&lt;p&gt;I know that nakame exists, but it's challenge to make my own server and apply it for the current games in the market. Crystal Blast starting from 2.1 release version would use own analytics platform and storage instead of Firebase.&lt;/p&gt;

&lt;p&gt;Plan to go away for external tools like firebase, game services and have everything in house and in the same time as cheap as possible.&lt;/p&gt;

&lt;p&gt;Planning to open source it in 2-3 months if the games in prod will work fine.&lt;/p&gt;

&lt;p&gt;Update: &lt;a href="https://crystalblast.page.link/install" rel="noopener noreferrer"&gt;Crystal Blast&lt;/a&gt; is going to have sounds, leaderboards, settings syncing between platforms by using social sign in.&lt;/p&gt;

</description>
      <category>go</category>
      <category>status</category>
      <category>gamedev</category>
    </item>
  </channel>
</rss>
