Compare commits

...

114 Commits

Author SHA1 Message Date
29c2fccbe5 bump version to 1.0.14 2025-02-19 16:14:20 +03:00
975c07fc2e ... 2025-02-19 16:09:11 +03:00
ff45beac09 ... 2025-02-19 09:46:41 +03:00
24eb709293 fixes docusaurus 2025-02-19 09:44:03 +03:00
49e2146152 Merge branch 'development_bizmodel' into development_installers 2025-02-19 07:15:28 +03:00
cdaf64b3cf git print better 2025-02-19 07:15:14 +03:00
49af31776e gitools 2025-02-19 05:53:29 +03:00
0880823576 Merge branch 'development_installers' of github.com:freeflowuniverse/herolib into development_installers 2025-02-19 05:10:45 +03:00
1fa1ecb8ec Merge branch 'development_fix' into development_installers 2025-02-19 05:09:56 +03:00
d6108c9836 Merge branch 'development' into development_installers 2025-02-19 05:08:41 +03:00
timurgordon
cc344fa60e bizmodel example report export wip 2025-02-18 23:23:26 +03:00
timurgordon
5e468359a1 start implementing docusaurus bizmodel exporting 2025-02-18 05:09:56 +03:00
timurgordon
2317dd2d4c tidy up action processing & playing 2025-02-18 05:09:06 +03:00
timurgordon
b92647c52e fix sheet processing issues 2025-02-18 05:07:56 +03:00
timurgordon
54024ee222 bizmodel example wip 2025-02-17 18:40:11 +03:00
60d6474a42 ... 2025-02-17 08:29:57 +03:00
8c52326550 ... 2025-02-17 06:41:19 +03:00
52aba347a8 ... 2025-02-17 06:40:06 +03:00
Mahmoud Emad
61a0fd2aa6 chore: Change the factories 2025-02-16 11:12:59 +00:00
Mahmoud Emad
d604d739e3 feat: Support garage_s3 installer
- Added a new config template file to be loaded when starting the server
- Run the server in zinit as a service
- Fix the install, destroy, installed, and running functions
2025-02-16 11:10:27 +00:00
Mahmoud Emad
a57f53fdb4 feat: Improved rclone installer 2025-02-16 08:56:28 +00:00
Mahmoud Emad
f276cdf697 feat: Improved tailwind installer 2025-02-16 08:15:43 +00:00
Mahmoud Emad
7fb46a4c0b feat: Improved b2 installer 2025-02-16 07:48:11 +00:00
Mahmoud Emad
fc993a95d7 feat: simplify actrunner installer
- Remove unnecessary dependencies and simplify the actrunner installation process.
2025-02-16 07:19:03 +00:00
c6ff7e7ba5 Merge branch 'development' of github.com:freeflowuniverse/herolib into development 2025-02-16 10:05:41 +03:00
3f9a3fb1cd caldav... 2025-02-16 10:05:35 +03:00
7ae4f7dbd0 mail/contacts... 2025-02-16 09:30:51 +03:00
dbb44ec30a mail 2025-02-16 08:25:25 +03:00
7f4fc42a7a mail 2025-02-16 07:49:06 +03:00
01db4540b1 imap 2025-02-16 06:44:43 +03:00
5c0c096a79 Merge pull request #64 from freeflowuniverse/development_coredns
Development coredns
2025-02-13 19:19:09 +02:00
c1719a057a Merge pull request #62 from freeflowuniverse/development_coredns
coredns
2025-02-13 19:10:13 +02:00
e969eacd06 fix(golang): add go path to env 2025-02-13 16:56:45 +00:00
8ed3439cdc fix(coredns): comment getting machine public ip 2025-02-13 16:13:15 +00:00
Mahmoud Emad
5241dfddd4 refactor: rename mycelium to mycelium_installer
- Renamed the `mycelium` module to `mycelium_installer` to improve clarity and avoid naming conflicts.
- Updated all related files and references to reflect the name change.
2025-02-13 13:29:16 +00:00
Mahmoud Emad
6e0572b48a chore: restructure the installers for organize the installers 2025-02-13 13:11:49 +00:00
Mahmoud Emad
9a4a39b19a feat: add screen installer
- Add a new screen installer to the project.
2025-02-13 13:01:48 +00:00
Mahmoud Emad
8abf113715 feat: improve LiveKit installer
- Implement key generation for LiveKit.
- Improve health check for LiveKit server.
- Add support for different startup managers.
- Simplify installation process.
- Remove unnecessary code.
- Update dependencies.
2025-02-13 12:52:03 +00:00
25c997fec5 fix(coredns): fixes in coredns installer and client 2025-02-12 17:55:36 +02:00
Mahmoud Emad
1546bf7f87 chore: Format the installers 2025-02-12 14:29:07 +00:00
Mahmoud Emad
02d4adcff0 refactor: improve gitea installer
- Simplify gitea installer logic.
- Remove unnecessary variables and functions.
- Improve code readability and maintainability.
- Update gitea version to 1.23.3.
- Add default values for GiteaServer fields.
- Remove redundant installer.v and server.v files.
2025-02-12 14:27:18 +00:00
Mahmoud Emad
147c889b53 feat: Add ZeroDB installer
- Add a new ZeroDB installer to the installers.
2025-02-12 13:44:52 +00:00
Mahmoud Emad
f6e7644284 refactor: Improve dagu, meilisearch, and postgres installers
- Remove redundant code and improve the overall structure of the installer actions.
- Add more robust error handling and logging.
- Update the postgres and dagu `destroy` function to properly remove all related services.
- Improve the `install` function to ensure all necessary components are installed.
2025-02-12 12:07:38 +00:00
Mahmoud Emad
582da6d7f0 feat: add wireguard installer
- Add a new wireguard installer to the installers.
2025-02-12 11:24:16 +00:00
Mahmoud Emad
3a337b7b0a refactor: fix meilisearch installler and rename meilisearchinstaller to meilisearch_installer
- Renamed the `meilisearchinstaller` module and related files to  `meilisearch_installer` for consistency.
- Updated import statements and references accordingly.
- Added functionality to install, start, and destroy the  Meilisearch service.
- Improved code readability and organization.
2025-02-12 11:06:08 +00:00
Mahmoud Emad
2953dd0172 fix: simplify meilisearch destroy action
- Remove unnecessary code from the `destroy` function in the `meilisearchinstaller_actions.v` file.
- NOTE: Couldn't test it due to the new hero update, don't know how even send the configs, WIP.
2025-02-12 09:31:39 +00:00
Mahmoud Emad
08f0620305 feat: add rust installer
- Add a new Rust installer.
- Fix some issues with the rust installer.
- better organize the language-specific installers.
2025-02-12 09:28:10 +00:00
Mahmoud Emad
ec22a8e0ec refactor: improve installer code
- Refactor installer code for better readability and maintainability.
- Move `dagu_server.vsh` to `examples/virt/daguserver/dagu_server.vsh`.
- Remove unnecessary `println` statements.
- Improve error handling in `zinit_installer_actions.v`.
- Update `zinit_installer_actions.v` startup type to systemd.
- Refactor several factory functions.
2025-02-12 09:02:33 +00:00
Mahmoud Emad
be4d2547e4 refactor: Improved the hero generator, removed unneeded lines 2025-02-11 11:18:04 +00:00
Mahmoud Emad
a7f8893399 feat: Improved the zinit installer, 2025-02-11 11:11:21 +00:00
Mahmoud-Emad
d0b52f40b7 feat: Improved the pacman installer, added an example 2025-02-11 10:32:15 +00:00
3117d288b1 WIP(osal.coredns): add example for coredns usage
- added openssl and iproute2 installation to install_v.sh since they're
  needed in coredns installation and usage.
- fixed bug in coredns build process.
- fixed bug in getting own public ip.
- fixed bugs in json encoding dns records before pushing to redis
2025-02-10 17:07:49 +00:00
Mahmoud-Emad
6ecd190de8 feat: Improved the docker installer, added an example 2025-02-10 13:53:53 +00:00
Mahmoud-Emad
dacd6d5afb feat: Improved the nodejs installer, added an example 2025-02-10 13:49:27 +00:00
299f6dea06 bump version to 1.0.13 2025-02-10 15:53:30 +03:00
ed025f9acb ... 2025-02-10 15:53:06 +03:00
Mahmoud-Emad
de0e66a94a feat: Improved the python installer, added an example 2025-02-10 12:08:49 +00:00
Mahmoud-Emad
e86504ecd5 feat: Improved the griddriver installer, added an example 2025-02-10 11:51:39 +00:00
Mahmoud-Emad
1b192328b2 feat: Add an example for golang usage 2025-02-10 11:39:53 +00:00
Mahmoud-Emad
77a77ff87e fix: Rename zinit files to zinit_installer 2025-02-10 11:35:21 +00:00
Mahmoud-Emad
439dff4a64 fix: Updated the golang installer 2025-02-10 11:34:45 +00:00
Mahmoud-Emad
f8cb6f25f7 fix: Rename zinit files to zinit_installer 2025-02-10 11:23:38 +00:00
c4ea066927 bump version to 1.0.12 2025-02-10 12:43:27 +03:00
5f9c6ff2bb ... 2025-02-10 12:41:14 +03:00
8965f7ae89 bump version to 1.0.10 2025-02-10 12:08:03 +03:00
Mahmoud-Emad
c157c86600 refactor: move zinit installer to infra
- Move the zinit installer from `sysadmintools` to `infra`.
- This change improves the organization of the codebase and
- makes it easier to find and manage installers.  The old
- `zinit` module was a factory only and is removed.  The
- `zinit_installer` is now a normal installer.  The code is
- significantly refactored.
2025-02-10 09:00:49 +00:00
9a931b65e2 bump version to 1.0.9 2025-02-10 09:42:52 +03:00
2c149507f6 fixes 2025-02-10 09:42:09 +03:00
timurgordon
34dea39c52 ... 2025-02-09 20:13:18 +00:00
timurgordon
f1a4547961 Merge branch 'development' of https://github.com/freeflowuniverse/herolib into development 2025-02-09 17:55:25 +00:00
timurgordon
8ae56a8df6 new 2025-02-09 17:53:16 +00:00
cb0110ed20 ... 2025-02-09 17:53:16 +01:00
2bbf814003 ... 2025-02-09 17:44:40 +01:00
86e3fdb910 WIP(osal.coredns): add example for coredns usage
- create an example to use coredns module for adding dns records
- fix module errors
2025-02-09 18:06:16 +02:00
b731c4c388 bump version to 1.0.8 2025-02-09 17:45:34 +03:00
e929ce029d Merge branch 'development_fix' of github.com:freeflowuniverse/herolib into development_fix 2025-02-09 13:51:43 +01:00
5160096a1a ... 2025-02-09 13:51:40 +01:00
f219a4041a ... 2025-02-09 15:50:56 +03:00
674eae1c11 ... 2025-02-09 13:33:21 +01:00
f62369bd01 ... 2025-02-09 13:32:44 +01:00
7a6660ebd8 ... 2025-02-09 13:32:34 +01:00
e20d1bdcc5 traeffik first version, coredns 2025-02-09 13:32:11 +01:00
3e309b6379 ... 2025-02-09 12:24:12 +01:00
ae4e92e090 ... 2025-02-09 08:55:41 +01:00
7b69719f0e ... 2025-02-09 08:55:01 +01:00
1d631fec21 ... 2025-02-09 08:52:42 +01:00
690b1b68c3 bump version to 1.0.7 2025-02-08 15:17:47 +01:00
6e619622d2 ... 2025-02-08 14:11:51 +01:00
eb38bc5e60 bump version to 1.0.6 2025-02-08 14:07:15 +01:00
b0da6d1bd2 ... 2025-02-08 09:54:29 +03:00
1377953dcf ... 2025-02-07 16:40:44 +03:00
aa85172700 Merge branch 'development_hetzner' into development_webdav 2025-02-07 13:00:16 +03:00
eff269e911 Merge branch 'development' into development_hetzner 2025-02-07 12:55:30 +03:00
65ec6ee1a3 Merge branch 'development_hetzner' of https://github.com/freeflowuniverse/herolib into development_hetzner 2025-02-07 12:55:21 +03:00
a86b23b2e9 release 2025-02-07 12:52:49 +03:00
bcccd5f247 Merge branch 'development' 2025-02-07 12:52:29 +03:00
cb8c550ed1 chore: bump version to 1.0.5 2025-02-07 12:38:49 +03:00
5fc7019dcc chore: bump version to 1.0.4 2025-02-07 12:30:56 +03:00
8c9248fd94 ... 2025-02-07 12:25:15 +03:00
d1a5f1c268 ... 2025-02-07 12:22:23 +03:00
96bc5c9e5d ... 2025-02-07 12:17:34 +03:00
20927485d9 ... 2025-02-07 12:13:39 +03:00
a034708f21 ... 2025-02-07 12:08:25 +03:00
19a2577564 ... 2025-02-07 12:07:32 +03:00
e34d804dda ... 2025-02-07 11:59:52 +03:00
cd6c899661 ... 2025-02-07 11:45:28 +03:00
4b2f83ceaf ... 2025-02-07 11:43:04 +03:00
4a2753d32c refactor(webdav): remove lock_manager from webdav app
- Remove unused `lock_manager` from the `App` struct.
- Comment out the lock and unlock handlers.
- Improve `propfind` response XML generation.
- Fix path handling in `generate_response_element`.
- Update content type handling for files.
- Improve XML generation for resource responses.

Co-authored-by: mahmmoud.hassanein <mahmmoud.hassanein@gmail.com>
2025-02-06 15:37:21 +02:00
1c0535a8b4 WIP: Implement WebDAV server
- Add a WebDAV server implementation using the `vweb` framework.
- The server supports basic authentication, request logging, and essential WebDAV methods.
- Implements file operations, authentication, and request logging.

Co-authored-by: mahmmoud.hassanein <mahmmoud.hassanein@gmail.com>
2025-02-03 18:02:16 +02:00
a0c253fa05 refactor(tfgrid3deployer): simplify Hetzner node filtering
- Remove `get_hetzner_farm_ids` function.
- Directly filter nodes using the `features` field.

Co-authored-by: mahmmoud.hassanein <mahmmoud.hassanein@gmail.com>
2025-02-03 13:57:46 +02:00
17a67870ef WIP(tfgrid3deployer): Support deploying on hetzner nodes
- Add support for deploying VMs, ZDBs, and gateways on Hetzner nodes.
- Introduce `use_hetzner_node` flag to VM, ZDB, and WebName.
- Update `filter_nodes` to filter by Hetzner farm IDs if `on_hetzner` flag is set.
- Implement `get_hetzner_farm_ids` function (currently a placeholder).

Co-authored-by: mahmmoud.hassanein <mahmmoud.hassanein@gmail.com>
2025-02-02 18:25:04 +02:00
54cfd4c353 feat: add ip-api client
- Add a new ip-api client to the project.
- This client uses the ip-api.com API to get IP information.
- An example is provided in `examples/develop/ipapi`.

Co-authored-by: mahmmoud.hassanein <mahmmoud.hassanein@gmail.com>
2025-02-02 18:04:00 +02:00
717eb1e7d8 WIP: feat: add Hetzner deployment example
- Added a new example demonstrating deployment on Hetzner using the `tfgrid3deployer`.
- The example creates a VM and adds a webname.

Co-authored-by: mahmmoud.hassanein <mahmmoud.hassanein@gmail.com>
2025-02-02 17:29:53 +02:00
03f5885980 Merge pull request #38 from freeflowuniverse/development
dev main
2025-01-28 09:49:18 +03:00
363 changed files with 13787 additions and 6479 deletions

View File

@@ -17,6 +17,7 @@ concurrency:
jobs:
deploy-documentation:
#if: startsWith(github.ref, 'refs/tags/')
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
@@ -26,22 +27,21 @@ jobs:
uses: actions/checkout@v4
- name: Setup Vlang
run: ./install_v.sh --github-actions
run: ./install_v.sh
- name: Generate documentation
run: |
./doc.vsh
# ls /home/runner/work/herolib/docs
./doc.vsh
find .
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
uses: actions/upload-pages-artifact@v3
with:
path: "/home/runner/work/herolib/herolib/docs"
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v3
uses: actions/deploy-pages@v4

View File

@@ -5,15 +5,12 @@ permissions:
on:
push:
branches: ["main","development"]
tags:
- 'v*'
workflow_dispatch:
branches: ["main","development"]
jobs:
build:
timeout-minutes: 60
if: startsWith(github.ref, 'refs/tags/')
strategy:
fail-fast: false
matrix:
@@ -31,6 +28,7 @@ jobs:
os: macos-13
short-name: macos-i64
runs-on: ${{ matrix.os }}
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
@@ -54,7 +52,6 @@ jobs:
run: |
set -e
v -w -d use_openssl -enable-globals cli/hero.v -o cli/hero-${{ matrix.target }}
- name: Upload
uses: actions/upload-artifact@v4
with:

2
.gitignore vendored
View File

@@ -7,6 +7,7 @@ vls.*
vls.log
node_modules/
docs/
vdocs/
photonwrapper.so
x
.env
@@ -25,7 +26,6 @@ dump.rdb
output/
*.db
.stellar
vdocs/
data.ms/
test_basic
cli/hero

View File

@@ -6,7 +6,7 @@
## hero install for users
```bash
curl https://raw.githubusercontent.com/freeflowuniverse/herolib/refs/heads/development_kristof10/install_hero.sh > /tmp/install_hero.sh
curl https://raw.githubusercontent.com/freeflowuniverse/herolib/refs/heads/development/install_hero.sh > /tmp/install_hero.sh
bash /tmp/install_hero.sh
```
@@ -16,7 +16,7 @@ this tool can be used to work with git, build books, play with hero AI, ...
## automated install for developers
```bash
curl 'https://raw.githubusercontent.com/freeflowuniverse/herolib/refs/heads/main/install_v.sh' > /tmp/install_v.sh
curl 'https://raw.githubusercontent.com/freeflowuniverse/herolib/refs/heads/development/install_v.sh' > /tmp/install_v.sh
bash /tmp/install_v.sh --analyzer --herolib
#DONT FORGET TO START A NEW SHELL (otherwise the paths will not be set)
```

187
aiprompts/reflection.md Normal file
View File

@@ -0,0 +1,187 @@
## Compile time reflection
$ is used as a prefix for compile time (also referred to as 'comptime') operations.
Having built-in JSON support is nice, but V also allows you to create efficient serializers for any data format. V has compile time if and for constructs:
.fields
You can iterate over struct fields using .fields, it also works with generic types (e.g. T.fields) and generic arguments (e.g. param.fields where fn gen[T](param T) {).
struct User {
name string
age int
}
fn main() {
$for field in User.fields {
$if field.typ is string {
println('${field.name} is of type string')
}
}
}
// Output:
// name is of type string
.values
You can read Enum values and their attributes.
enum Color {
red @[RED] // first attribute
blue @[BLUE] // second attribute
}
fn main() {
$for e in Color.values {
println(e.name)
println(e.attrs)
}
}
// Output:
// red
// ['RED']
// blue
// ['BLUE']
.attributes
You can read Struct attributes.
@[COLOR]
struct Foo {
a int
}
fn main() {
$for e in Foo.attributes {
println(e)
}
}
// Output:
// StructAttribute{
// name: 'COLOR'
// has_arg: false
// arg: ''
// kind: plain
// }
.variants
You can read variant types from Sum type.
type MySum = int | string
fn main() {
$for v in MySum.variants {
$if v.typ is int {
println('has int type')
} $else $if v.typ is string {
println('has string type')
}
}
}
// Output:
// has int type
// has string type
.methods
You can retrieve information about struct methods.
struct Foo {
}
fn (f Foo) test() int {
return 123
}
fn (f Foo) test2() string {
return 'foo'
}
fn main() {
foo := Foo{}
$for m in Foo.methods {
$if m.return_type is int {
print('${m.name} returns int: ')
println(foo.$method())
} $else $if m.return_type is string {
print('${m.name} returns string: ')
println(foo.$method())
}
}
}
// Output:
// test returns int: 123
// test2 returns string: foo
.params
You can retrieve information about struct method params.
struct Test {
}
fn (t Test) foo(arg1 int, arg2 string) {
}
fn main() {
$for m in Test.methods {
$for param in m.params {
println('${typeof(param.typ).name}: ${param.name}')
}
}
}
// Output:
// int: arg1
// string: arg2
## Example
```v
// An example deserializer implementation
struct User {
name string
age int
}
fn main() {
data := 'name=Alice\nage=18'
user := decode[User](data)
println(user)
}
fn decode[T](data string) T {
mut result := T{}
// compile-time `for` loop
// T.fields gives an array of a field metadata type
$for field in T.fields {
$if field.typ is string {
// $(string_expr) produces an identifier
result.$(field.name) = get_string(data, field.name)
} $else $if field.typ is int {
result.$(field.name) = get_int(data, field.name)
}
}
return result
}
fn get_string(data string, field_name string) string {
for line in data.split_into_lines() {
key_val := line.split('=')
if key_val[0] == field_name {
return key_val[1]
}
}
return ''
}
fn get_int(data string, field string) int {
return get_string(data, field).int()
}
// `decode<User>` generates:
// fn decode_User(data string) User {
// mut result := User{}
// result.name = get_string(data, 'name')
// result.age = get_int(data, 'age')
// return result
// }
```

2
cli/.gitignore vendored
View File

@@ -1 +1,3 @@
hero
compile
compile_upload

View File

@@ -19,6 +19,26 @@ fn playcmds_do(path string) ! {
}
fn do() ! {
if ! core.is_osx()! {
if os.getenv('SUDO_COMMAND') != '' || os.getenv('SUDO_USER') != '' {
println('Error: Please do not run this program with sudo!')
exit(1) // Exit with error code
}
}
if os.getuid() == 0 {
if core.is_osx()! {
eprintln("please do not run hero as root in osx.")
exit(1)
}
} else {
if ! core.is_osx()! {
eprintln("please do run hero as root, don't use sudo.")
exit(1)
}
}
if os.args.len == 2 {
mypath := os.args[1]
if mypath.to_lower().ends_with('.hero') {
@@ -31,7 +51,7 @@ fn do() ! {
mut cmd := Command{
name: 'hero'
description: 'Your HERO toolset.'
version: '2.0.6'
version: '1.0.14'
}
// herocmds.cmd_run_add_flags(mut cmd)
@@ -94,4 +114,4 @@ fn main() {
fn pre_func(cmd Command) ! {
herocmds.plbook_run(cmd)!
}
}

38
doc.vsh
View File

@@ -26,9 +26,9 @@ os.chdir(herolib_path) or {
panic('Failed to change directory to herolib: ${err}')
}
os.rmdir_all('_docs') or {}
os.rmdir_all('docs') or {}
os.rmdir_all('vdocs') or {}
os.mkdir_all('_docs') or {}
os.mkdir_all('docs') or {}
os.mkdir_all('vdocs') or {}
// Generate HTML documentation
println('Generating HTML documentation...')
@@ -42,13 +42,12 @@ os.chdir(abs_dir_of_script) or {
// Generate Markdown documentation
println('Generating Markdown documentation...')
os.rmdir_all('vdocs') or {}
// if os.system('v doc -m -no-color -f md -o ../vdocs/v/') != 0 {
// panic('Failed to generate V markdown documentation')
// }
if os.system('v doc -m -no-color -f md -o vdocs/herolib/') != 0 {
if os.system('v doc -m -no-color -f md -o vdocs/') != 0 {
panic('Failed to generate Hero markdown documentation')
}
@@ -62,4 +61,33 @@ $if !linux {
}
}
// Create Jekyll required files
println('Creating Jekyll files...')
os.mkdir_all('docs/assets/css') or {}
// Create style.scss
style_content := '---\n---\n\n@import "{{ site.theme }}";'
os.write_file('docs/assets/css/style.scss', style_content) or {
panic('Failed to create style.scss: ${err}')
}
// Create _config.yml
config_content := 'title: HeroLib Documentation
description: Documentation for the HeroLib project
theme: jekyll-theme-primer
baseurl: /herolib
exclude:
- Gemfile
- Gemfile.lock
- node_modules
- vendor/bundle/
- vendor/cache/
- vendor/gems/
- vendor/ruby/'
os.write_file('docs/_config.yml', config_content) or {
panic('Failed to create _config.yml: ${err}')
}
println('Documentation generation completed successfully!')

View File

@@ -0,0 +1,2 @@
bizmodel
dest

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env -S v -n -w -cg -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
//#!/usr/bin/env -S v -cg -enable-globals run
import freeflowuniverse.herolib.data.doctree
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.core.playcmds
import freeflowuniverse.herolib.web.mdbook
import os
const wikipath = os.dir(@FILE) + '/wiki'
const summarypath = os.dir(@FILE) + '/wiki/summary.md'
buildpath := '${os.home_dir()}/hero/var/mdbuild/bizmodel'
mut m := bizmodel.getset('example')!
m.workdir = wikipath
m.play(mut playbook.new(path: wikipath)!)!
m.export_sheets()!
bizmodel.set(m)
// // execute the actions so we have the info populated
// // playcmds.run(mut plb,false)!
// // just run the doctree & mdbook and it should
// // load the doctree, these are all collections
// mut tree := doctree.new(name: 'bizmodel')!
// tree.scan(path: wikipath)!
// tree.export(dest: buildpath, reset: true)!
// // mut bm:=bizmodel.get("test")!
// // println(bm)
// mut mdbooks := mdbook.get()!
// mdbooks.generate(
// name: 'bizmodel'
// summary_path: summarypath
// doctree_path: buildpath
// title: 'bizmodel example'
// )!
// mdbook.book_open('bizmodel')!

View File

@@ -0,0 +1,10 @@
## Loader instructions
this will make sure we load the appropriate biz model
```js
!!bizmodel.load name:'default' url:'https://github.com/freeflowuniverse/herolib/tree/development/bizmodel/example/data'
```

View File

@@ -0,0 +1 @@
name:bizmodel_example

View File

@@ -0,0 +1,10 @@
![](img/ms1bmodel.png)
# bizmodel
OurWorld has developed a tool to generate and keep business models up to date.
Our aim is to make it easy for ourworld to track changes in planning over the multiple projects and even be able to aggregated them. Because the input for such a plan is text (as you can see in this ebook) its easy to see how the modelling and parameters change over time.
This is a very flexible tool which will be extended for budgetting, cashflow management, shareholder tables, ...

View File

@@ -0,0 +1,4 @@
# Debug
Some tools and info to help debug the bizmodel simulator.

View File

@@ -0,0 +1,8 @@
# Hr Overview
!!!bizmodel.employees_wiki bizname:'test'
> note: Nr People like 0:5,20:5 means, month 0 (start) is 5, month 20 its 5 people

View File

@@ -0,0 +1,5 @@
# CTO
!!!bizmodel.employee_wiki bizname:'test' name:'despiegk'
!!wiki.include page:cto_description.md

View File

@@ -0,0 +1,3 @@
## CTO Description
this is a page to test nested includes

View File

@@ -0,0 +1 @@
ms1bmodel.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@@ -0,0 +1,52 @@
# This is our business model planner
## P&L Overview
<!-- period is in months, 3 means every quarter -->
!!bizmodel.graph_bar_row rowname:revenue_total unit:million title:'A Title' title_sub:'Sub' sheetname:'bizmodel_test'
Unit is in Million USD.
!!bizmodel.graph_bar_row rowname:revenue_total unit:million sheetname:'bizmodel_test'
!!bizmodel.graph_line_row rowname:revenue_total unit:million sheetname:'bizmodel_test'
!!bizmodel.graph_pie_row rowname:revenue_total unit:million size:'80%' sheetname:'bizmodel_test'
## FUNDING
!!bizmodel.sheet_wiki includefilter:'funding' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'REVENUE' includefilter:rev sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'Revenue Total' includefilter:'revtotal' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'REVENUE' includefilter:'revtotal2' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'COGS' includefilter:'cogs' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'Margin' includefilter:'margin' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'HR Teams' includefilter:'hrnr' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'HR Costs' includefilter:'hrcost' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'COSTS' includefilter:'ocost' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'HR Costs' includefilter:'hrcost' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'P&L Overview' includefilter:'pl' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'P&L Overview' includefilter:'pl' sheetname:'bizmodel_test'
## Some Details
> show how we can do per month
!!bizmodel.sheet_wiki includefilter:'pl' period_months:1 sheetname:'bizmodel_test'

View File

@@ -0,0 +1,31 @@
# HR Params
## Engineering
Costs can be grouped in cost centers which can then be used to futher process e.g. transcactions between companies.
```js
!!bizmodel.costcenter_define bizname:'test'
name:'tfdmcc'
descr:'TFDMCC executes on near source agreement for TFTech'
min_month:'10000USD'
max_month:'100000USD'
end_date:'1/1/2026' //when does agreement stop
!!bizmodel.costcenter_define bizname:'test'
name:'cs_tftech'
descr:'Nearsource agreement for TFTech towards Codescalers'
min_month:'10000USD'
max_month:'100000USD'
end_date:'1/1/2026'
!!bizmodel.costcenter_define bizname:'test'
name:'cs_tfcloud'
descr:'Nearsource agreement for TFCloud towards Codescalers'
min_month:'10000USD'
max_month:'100000USD'
end_date:'1/1/2026'
```

View File

@@ -0,0 +1,39 @@
# Generic Overhead Costs
possible parameters
- name
- descr: description of the cost
- cost: is 'month:amount,month:amount, ...', no extrapolation
- cost_growth: is 'month:amount,month:amount, ..., or just a nr', will extrapolate
- type: travel, admin, legal, varia, office
- cost_percent_revenue e.g. 4%, will make sure the cost will be at least 4% of revenue
- indexation, e.g. 2%
Other financial flows can be mentioned here as well.
```js
!!bizmodel.cost_define bizname:'test'
name:'rental'
descr:'Office Rental in BE.'
cost:'5000'
indexation:'2%'
type:'office'
!!bizmodel.cost_define bizname:'test'
name:'oneoff'
descr:'Event in Z.'
cost_one:'3:50000'
type:'event'
!!bizmodel.cost_define bizname:'test'
name:'cloud'
descr:'Datacenter and Cloud Costs'
cost:'2000eur'
cost_percent_revenue:'2%'
type:'cloud'
```

View File

@@ -0,0 +1,20 @@
# Department Params
```js
!!bizmodel.department_define bizname:'test'
name:'ops'
title:'Operations'
order:5
!!bizmodel.department_define bizname:'test'
name:'coordination'
title:'Coordination'
order:1
!!bizmodel.department_define bizname:'test'
name:'engineering'
title:'Engineering'
order:4
```

View File

@@ -0,0 +1,29 @@
# Funding Params
possible parameters
- name, e.g. for a specific person
- descr: description of the funding
- investment is month:amount,month:amount, ...
- type: loan or capital
Other financial flows can be mentioned here as well.
```js
!!bizmodel.funding_define bizname:'test'
name:'our_investor'
descr:'A fantastic super investor.'
investment:'3:1000000EUR'
type:'capital'
!!bizmodel.funding_define bizname:'test'
name:'a_founder'
descr:'Together Are Strong'
investment:'2000000'
type:'loan'
```

View File

@@ -0,0 +1,73 @@
# HR Params
## Engineering
possible parameters
- descr, description of the function (e.g. master architect)
- cost, any currency eg. 1000usd
- in case cost changes over time e.g. 1:10000USD,20:20000USD,60:30000USD
- indexation, e.g. 2%
- department
- name, e.g. for a specific person
- nrpeople: how many people per month, growth over time notation e.g. 1:10,60:20 means 10 in month 1 growing to 20 month 60
- cost_percent_revenue e.g. 4%, will make sure the cost will be at least 4% of revenue
```js
!!bizmodel.employee_define bizname:'test'
sid:2
descr:'Senior Engineer'
cost:'1:12000,12:14000' //cost is always per person
department:'engineering'
nrpeople:'0:5,20:5'
!!bizmodel.employee_define bizname:'test'
name:'despiegk'
title: 'CTO and crazy inventor.'
sid:3
descr:'CTO'
cost:'12000EUR' //the salary is the cost independent of the fulltime status
indexation:'10%'
department:'coordination'
page:'cto.md'
fulltime: "50%" //100% means yes
!!bizmodel.employee_define bizname:'test'
descr:'Senior Architect'
cost:'10000USD' indexation:'5%'
department:'engineering'
nrpeople:'0:5,20:10'
!!bizmodel.employee_define bizname:'test'
descr:'Junior Engineer'
cost:'4000USD' indexation:'5%'
department:'engineering'
nrpeople:'0:5,20:10'
```
## Operations
```js
!!bizmodel.employee_define bizname:'test'
descr:'Ops Manager'
cost:'1:8000,12:14000'
department:'ops'
!!bizmodel.employee_define bizname:'test'
descr:'Support Junior'
cost:'2000EUR' indexation:'5%'
department:'ops'
nrpeople:'7:5,18:10'
cost_percent_revenue:'1%'
!!bizmodel.employee_define bizname:'test'
descr:'Support Senior'
cost:'5000EUR' indexation:'5%'
department:'ops'
nrpeople:'3:5,20:10'
cost_percent_revenue:'1%'
costcenter:'tfdmcc:25,cs_tfcloud:75'
generate_page:'../employees/support_senior.md'
```

View File

@@ -0,0 +1,14 @@
# Bizmodel Params
In this section we can find all the parameters for the bizmodel.
## how to use and read
The params are defined in the different instruction files e.g. revenue_params.md
Often you will see something like `revenue_growth:'10:1000,20:1100'` this can be read as month 10 it 1000, month 20 its 1100.
The software will extrapolate.

View File

@@ -0,0 +1,64 @@
# HR Params
## Revenue Items (non recurring)
This company is a cloud company ...
```js
!!bizmodel.revenue_define bizname:'test'
descr:'OEM Deals'
revenue_time:'10:1000000EUR,15:3333,20:1200000'
cogs_perc: '1:5%,20:10%'
!!bizmodel.revenue_define bizname:'test'
descr:'License Deals'
revenue_growth:'10:1000,20:1100'
cogs_perc: '10%'
rev_delay_month: 1
!!bizmodel.revenue_define bizname:'test'
descr:'3NODE License Sales 1 Time'
//means revenue is 100 month 1, 200 month 60
revenue_item:'1:100,60:200'
revenue_nr:'10:1000,24:2000,60:40000'
cogs_perc: '10%'
rev_delay_month: 1
```
## Revenue Items Recurring
possible parameters
- name, e.g. for a specific project
- descr, description of the revenue line item
- revenue_setup, revenue for 1 item '1000usd'
- revenue_monthly, revenue per month for 1 item
- revenue_setup_delay, how many months before revenue comes in after sales
- revenue_monthly_delay, how many months before monthly revenue starts
- cogs_setup, cost of good for 1 item at setup
- cogs_setup_perc: what is percentage of the cogs (can change over time) for setup e.g. 0:50%
- cogs_monthly, cost of goods for the monthly per 1 item
- cogs_monthly_perc: what is percentage of the cogs (can change over time) for monthly e.g. 0:5%,12:10%
- nr_sold: how many do we sell per month (is in growth format e.g. 10:100,20:200)
- nr_months: how many months is recurring
if currency not specified then is always in USD
```js
!!bizmodel.revenue_recurring_define bizname:'test'
name: '3node_lic'
descr:'3NODE License Sales Recurring Basic'
revenue_setup:'1:100,60:50'
// revenue_setup:'5'
revenue_monthly_delay:3
revenue_monthly:'1:1,60:1'
// cogs_setup:'1:0'
cogs_setup_perc:'50%'
revenue_setup_delay:1
cogs_monthly_perc:'50%'
nr_sold:'10:1000,24:2000,60:40000'
60 is the default
nr_months:60
```

View File

@@ -0,0 +1,13 @@
## Revenue
Overview of achieved revenue.
Unit is in Million USD.
!!bizmodel.sheet_wiki title:'REVENUE' includefilter:rev sheetname:'bizmodel_test'
!!bizmodel.graph_bar_row rowname:revenue_total unit:million sheetname:'bizmodel_test'
!!bizmodel.graph_line_row rowname:revenue_total unit:million sheetname:'bizmodel_test'
!!bizmodel.graph_pie_row rowname:revenue_total unit:million size:'80%' sheetname:'bizmodel_test'

View File

@@ -0,0 +1,13 @@
- [bizmodel](bizmodel_example/bizmodel.md)
- [Revenue](bizmodel_example/revenue.md)
- [Result](bizmodel_example/overview.md)
- [parameters](bizmodel_example/params.md)
- [revenue_params](bizmodel_example/params/revenue_params.md)
- [funding_params](bizmodel_example/params/funding_params.md)
- [hr_params](bizmodel_example/params/hr_params.md)
- [costs_params](bizmodel_example/params/costs_params.md)
- [rows overview](bizmodel_example/rows_overview.md)
- [employees](bizmodel_example/employees.md)
- [debug](bizmodel_example/debug.md)
- [worksheet](bizmodel_example/worksheet.md)

View File

@@ -0,0 +1,4 @@
# Overview of the rows in the biz model sheet
!!bizmodel.sheet_wiki sheetname:'bizmodel_test'

View File

@@ -0,0 +1,48 @@
#!/usr/bin/env -S v -cg -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
// #!/usr/bin/env -S v -cg -enable-globals run
import freeflowuniverse.herolib.data.doctree
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.core.playcmds
import freeflowuniverse.herolib.web.mdbook
import freeflowuniverse.herolib.biz.spreadsheet
import os
const name = 'tf9_budget'
const wikipath = '${os.home_dir()}/code/git.ourworld.tf/ourworld_holding/info_ourworld/collections/${name}'
const summarypath = '${wikipath}/summary.md'
// mut sh := spreadsheet.sheet_new(name: 'test2') or { panic(err) }
// println(sh)
// sh.row_new(descr: 'this is a description', name: 'something', growth: '0:100aed,55:1000eur')!
// println(sh)
// println(sh.wiki()!)
// exit(0)
// execute the actions so we have the info populated
// mut plb:=playbook.new(path: wikipath)!
// playcmds.run(mut plb,false)!
buildpath := '${os.home_dir()}/hero/var/mdbuild/bizmodel'
// just run the doctree & mdbook and it should
// load the doctree, these are all collections
mut tree := doctree.new(name: name)!
tree.scan(path: wikipath)!
tree.export(dest: buildpath, reset: true)!
// mut bm:=bizmodel.get("test")!
// println(bm)
mut mdbooks := mdbook.get()!
mdbooks.generate(
name: 'bizmodel'
summary_path: summarypath
doctree_path: buildpath
title: 'bizmodel ${name}'
)!
mdbook.book_open('bizmodel')!

View File

@@ -0,0 +1,12 @@
need to find where the manual is
- [manual](bizmodel_example/configuration.md)
- [widgets](bizmodel_example/widgets.md)
- [graph_bar_row](bizmodel_example/graph_bar_row.md)
- [sheet_tables](bizmodel_example/sheet_tables.md)
- [widget_args](bizmodel_example/widget_args.md)
- [params](bizmodel_example/configuration.md)
- [revenue params](bizmodel_example/revenue_params.md)
- [funding params](bizmodel_example/funding_params.md)
- [hr params](bizmodel_example/hr_params.md)
- [costs params](bizmodel_example/costs_params.md)

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env -S v -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.biz.investortool
import freeflowuniverse.herolib.core.playbook
import os
mut plbook := playbook.new(
path: '${os.home_dir()}/code/git.ourworld.tf/ourworld_holding/investorstool/output'
)!
mut it := investortool.play(mut plbook)!
it.check()!

View File

@@ -1,11 +1,9 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.clients.mailclient
import freeflowuniverse.herolib.clients. mailclient
//remove the previous one, otherwise the env variables are not read
mailclient.config_delete(name:"test")!
// remove the previous one, otherwise the env variables are not read
mailclient.config_delete(name: 'test')!
// env variables which need to be set are:
// - MAIL_FROM=...
@@ -14,11 +12,14 @@ mailclient.config_delete(name:"test")!
// - MAIL_SERVER=...
// - MAIL_USERNAME=...
mut client:= mailclient.get(name:"test")!
mut client := mailclient.get(name: 'test')!
println(client)
client.send(subject:'this is a test',to:'kristof@incubaid.com',body:'
client.send(
subject: 'this is a test'
to: 'kristof@incubaid.com'
body: '
this is my email content
')!
'
)!

108
examples/clients/mycelium.vsh Executable file
View File

@@ -0,0 +1,108 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.clients.mycelium
import freeflowuniverse.herolib.installers.net.mycelium as mycelium_installer
import freeflowuniverse.herolib.osal
import time
import os
import encoding.base64
const server1_port = 9001
const server2_port = 9002
fn terminate(port int) ! {
// Step 1: Run lsof to get process details
res := os.execute('lsof -i:${port}')
if res.exit_code != 0 {
return error('no service running at port ${port} due to: ${res.output}')
}
// Step 2: Parse the output to extract the PID
lines := res.output.split('\n')
if lines.len < 2 {
return error('no process found running on port ${port}')
}
// The PID is the second column in the output
fields := lines[1].split(' ')
if fields.len < 2 {
return error('failed to parse lsof output')
}
pid := fields[1]
// Step 3: Kill the process using the PID
kill_res := os.execute('kill ${pid}')
if kill_res.exit_code != 0 {
return error('failed to kill process ${pid}: ${kill_res.output}')
}
println('Successfully terminated process ${pid} running on port ${port}')
}
// Check if not installed install it.
mut installer := mycelium_installer.get()!
installer.install()!
mycelium.delete()!
spawn fn () {
os.execute('mkdir -p /tmp/mycelium_server1 && cd /tmp/mycelium_server1 && mycelium --peers tcp://188.40.132.242:9651 quic://[2a01:4f8:212:fa6::2]:9651 tcp://185.69.166.7:9651 quic://[2a02:1802:5e:0:ec4:7aff:fe51:e36b]:9651 tcp://65.21.231.58:9651 quic://[2a01:4f9:5a:1042::2]:9651 tcp://[2604:a00:50:17b:9e6b:ff:fe1f:e054]:9651 quic://5.78.122.16:9651 tcp://[2a01:4ff:2f0:3621::1]:9651 quic://142.93.217.194:9651 --tun-name tun2 --tcp-listen-port 9652 --quic-listen-port 9653 --api-addr 127.0.0.1:${server1_port}')
}()
spawn fn () {
os.execute('mkdir -p /tmp/mycelium_server2 && cd /tmp/mycelium_server2 && mycelium --peers tcp://188.40.132.242:9651 quic://[2a01:4f8:212:fa6::2]:9651 tcp://185.69.166.7:9651 quic://[2a02:1802:5e:0:ec4:7aff:fe51:e36b]:9651 tcp://65.21.231.58:9651 quic://[2a01:4f9:5a:1042::2]:9651 tcp://[2604:a00:50:17b:9e6b:ff:fe1f:e054]:9651 quic://5.78.122.16:9651 tcp://[2a01:4ff:2f0:3621::1]:9651 quic://142.93.217.194:9651 --tun-name tun3 --tcp-listen-port 9654 --quic-listen-port 9655 --api-addr 127.0.0.1:${server2_port}')
}()
defer {
terminate(server1_port) or {}
terminate(server2_port) or {}
}
time.sleep(2 * time.second)
mut client1 := mycelium.get()!
client1.server_url = 'http://localhost:${server1_port}'
client1.name = 'client1'
println(client1)
mut client2 := mycelium.get()!
client2.server_url = 'http://localhost:${server2_port}'
client2.name = 'client2'
println(client2)
inspect1 := mycelium.inspect(key_file_path: '/tmp/mycelium_server1/priv_key.bin')!
inspect2 := mycelium.inspect(key_file_path: '/tmp/mycelium_server2/priv_key.bin')!
println('Server 1 public key: ${inspect1.public_key}')
println('Server 2 public key: ${inspect2.public_key}')
// Send a message to a node by public key
// Parameters: public_key, payload, topic, wait_for_reply
msg := client1.send_msg(
public_key: inspect2.public_key // destination public key
payload: 'Sending a message from the client 1 to the client 2' // message payload
topic: 'testing' // optional topic
)!
println('Sent message ID: ${msg.id}')
println('send succeeded')
// Receive messages
// Parameters: wait_for_message, peek_only, topic_filter
received := client2.receive_msg(wait: true, peek: false, topic: 'testing')!
println('Received message from: ${received.src_pk}')
println('Message payload: ${base64.decode_str(received.payload)}')
// Reply to a message
// client1.reply_msg(
// id: received.id
// public_key: received.src_pk
// payload: 'Got your message!'
// topic: 'greetings'
// )!
// // // Check message status
// // status := client.get_msg_status(msg.id)!
// // println('Message status: ${status.state}')
// // println('Created at: ${status.created}')
// // println('Expires at: ${status.deadline}')

View File

@@ -3,7 +3,6 @@
import freeflowuniverse.herolib.core
import freeflowuniverse.herolib.clients.postgresql_client
// Configure PostgreSQL client
heroscript := "
!!postgresql_client.configure
@@ -19,7 +18,7 @@ heroscript := "
postgresql_client.play(heroscript: heroscript)!
// Get the configured client
mut db_client := postgresql_client.get(name: "test")!
mut db_client := postgresql_client.get(name: 'test')!
// Check if test database exists, create if not
if !db_client.db_exists('test')! {
@@ -31,15 +30,14 @@ if !db_client.db_exists('test')! {
db_client.dbname = 'test'
// Create table if not exists
create_table_sql := "CREATE TABLE IF NOT EXISTS users (
create_table_sql := 'CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)"
)'
println('Creating table users if not exists...')
db_client.exec(create_table_sql)!
println('Database and table setup completed successfully!')

View File

@@ -12,8 +12,8 @@ mut:
}
mut person := Person{
name: 'Bob'
birthday: time.now()
name: 'Bob'
birthday: time.now()
}
heroscript := encoderhero.encode[Person](person)!
@@ -22,9 +22,8 @@ println(heroscript)
person2 := encoderhero.decode[Person](heroscript)!
println(person2)
//show that it doesn't matter which action & method is used
heroscript2:="!!a.b name:Bob age:20 birthday:'2025-02-06 09:57:30'"
// show that it doesn't matter which action & method is used
heroscript2 := "!!a.b name:Bob age:20 birthday:'2025-02-06 09:57:30'"
person3 := encoderhero.decode[Person](heroscript)!
println(person3)

View File

@@ -1,23 +1,22 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import json
enum JobTitle {
manager
executive
worker
manager
executive
worker
}
struct Employee {
mut:
name string
family string @[json: '-'] // this field will be skipped
age int
salary f32
title JobTitle @[json: 'ETitle'] // the key for this field will be 'ETitle', not 'title'
notes string @[omitempty] // the JSON property is not created if the string is equal to '' (an empty string).
// TODO: document @[raw]
name string
family string @[json: '-'] // this field will be skipped
age int
salary f32
title JobTitle @[json: 'ETitle'] // the key for this field will be 'ETitle', not 'title'
notes string @[omitempty] // the JSON property is not created if the string is equal to '' (an empty string).
// TODO: document @[raw]
}
x := Employee{'Peter', 'Begins', 28, 95000.5, .worker, ''}
@@ -34,4 +33,3 @@ println(y)
ss := json.encode(y)
println('JSON encoding of employee y: ${ss}')
assert ss == s

View File

@@ -18,8 +18,7 @@ heroscript := "
postgresql_client.play(heroscript: heroscript)!
// Get the configured client
mut db_client := postgresql_client.get(name: "test")!
mut db_client := postgresql_client.get(name: 'test')!
// Create a new location instance
mut loc := location.new(mut db_client, false) or { panic(err) }

View File

@@ -18,8 +18,7 @@ heroscript := "
postgresql_client.play(heroscript: heroscript)!
// Get the configured client
mut db_client := postgresql_client.get(name: "test")!
mut db_client := postgresql_client.get(name: 'test')!
// Create a new location instance
mut loc := location.new(mut db_client, false) or { panic(err) }

View File

@@ -1,18 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.develop.gittools
import freeflowuniverse.herolib.osal
import time
mut gs_default := gittools.new()!
println(gs_default)
// // Initializes the Git structure with the coderoot path.
// coderoot := '/tmp/code'
// mut gs_tmo := gittools.new(coderoot: coderoot)!
// // Retrieve the specified repository.
// mut repo := gs_default.get_repo(name: 'herolib')!
// println(repo)

View File

@@ -0,0 +1,14 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.develop.gittools
import freeflowuniverse.herolib.osal
import time
mut gs := gittools.new()!
mydocs_path := gs.get_path(
pull: true
reset: false
url: 'https://git.ourworld.tf/tfgrid/info_docs_depin/src/branch/main/docs'
)!
println(mydocs_path)

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -no-retry-compilation -d use_openssl -enable-globals run
import freeflowuniverse.herolib.clients.ipapi
import os
mut ip_api_client := ipapi.get()!
info := ip_api_client.get_ip_info('37.27.132.46')!
println('info: ${info}')

View File

@@ -1 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run

View File

@@ -1 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run

View File

@@ -1,5 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.coredns as coredns_installer
import freeflowuniverse.herolib.osal
coredns_installer.install()!
// coredns_installer.delete()!
mut installer := coredns_installer.get()!
installer.build()!

View File

@@ -1,15 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.daguserver
import freeflowuniverse.herolib.installers.infra.zinit
// make sure zinit is there and running, will restart it if needed
mut z := zinit.get()!
z.destroy()!
z.start()!
// mut ds := daguserver.get()!
// ds.destroy()!
// ds.start()!
// println(ds)

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.db.meilisearch_installer
mut meilisearch := meilisearch_installer.get()!
meilisearch.install()!
meilisearch.start()!
meilisearch.destroy()!

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.db.postgresql as postgresql_installer
mut db := postgresql_installer.get()!
db.install()!
db.start()!
db.destroy()!

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.db.zerodb as zerodb_installer
mut db := zerodb_installer.get()!
db.install()!
db.start()!
db.destroy()!

View File

@@ -1,15 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.gitea as gitea_installer
mut installer:= gitea_installer.get(name:'test')!
//if you want to configure using heroscript
gitea_installer.play(heroscript:"
!!gitea.configure name:test
passwd:'something'
domain: 'docs.info.com'
")!
installer.start()!

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.gitea as gitea_installer
mut gitea := gitea_installer.get()!
gitea.install()!
gitea.start()!
gitea.destroy()!

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.livekit as livekit_installer
mut livekit := livekit_installer.get()!
livekit.install()!
livekit.start()!
livekit.destroy()!

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.screen as screen_installer
mut screen := screen_installer.get()!
screen.install()!
screen.destroy()!

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.zinit_installer
mut installer := zinit_installer.get()!
installer.install()!
installer.start()!
// installer.destroy()!

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.lang.golang
mut golang_installer := golang.get()!
golang_installer.install()!

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.lang.nodejs
mut nodejs_installer := nodejs.get()!
// nodejs_installer.install()!
nodejs_installer.destroy()!

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.lang.python as python_module
mut python_installer := python_module.get()!
// python_installer.install()!
python_installer.destroy()!

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.lang.rust as rust_module
mut rust_installer := rust_module.get()!
// rust_installer.install()!
rust_installer.destroy()!

View File

@@ -1,5 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.net.mycelium as mycelium_installer
mycelium_installer.start()!

View File

@@ -0,0 +1,42 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.net.mycelium_installer
import freeflowuniverse.herolib.clients.mycelium
mut installer := mycelium_installer.get()!
installer.start()!
mut r := mycelium.inspect()!
println(r)
mut client := mycelium.get()!
// Send a message to a node by public key
// Parameters: public_key, payload, topic, wait_for_reply
msg := client.send_msg(
public_key: 'abc123...' // destination public key
payload: 'Hello World' // message payload
topic: 'greetings' // optional topic
wait: true // wait for reply
)!
println('Sent message ID: ${msg.id}')
// Receive messages
// Parameters: wait_for_message, peek_only, topic_filter
received := client.receive_msg(wait: true, peek: false, topic: 'greetings')!
println('Received message from: ${received.src_pk}')
println('Message payload: ${received.payload}')
// Reply to a message
client.reply_msg(
id: received.id // original message ID
public_key: received.src_pk // sender's public key
payload: 'Got your message!' // reply payload
topic: 'greetings' // topic
)!
// Check message status
status := client.get_msg_status(msg.id)!
println('Message status: ${status.state}')
println('Created at: ${status.created}')
println('Expires at: ${status.deadline}')

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.net.wireguard_installer as wireguard
mut wireguard_installer := wireguard.get()!
wireguard_installer.install()!
wireguard_installer.destroy()!

View File

@@ -1,13 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import time
import freeflowuniverse.herolib.installers.db.postgresql
mut db := postgresql.get()!
// db.destroy()!
db.start()!
// db.db_create('my_new_db')!
// db.stop()!
// db.start()!

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.actrunner
import freeflowuniverse.herolib.installers.virt.herocontainers
// import freeflowuniverse.herolib.installers.virt.herocontainers
actrunner.install()!
mut actrunner_ := actrunner.get()!
actrunner_.install()!
// herocontainers.start()!

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.garage_s3 as garage_s3_installer
mut garage_s3 := garage_s3_installer.get()!
garage_s3.install()!
garage_s3.start()!
garage_s3.destroy()!

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.rclone as rclone_installer
mut rclone := rclone_installer.get()!
rclone.install()!
rclone.destroy()!

View File

@@ -4,3 +4,4 @@ import freeflowuniverse.herolib.installers.threefold.griddriver
mut griddriver_installer := griddriver.get()!
griddriver_installer.install()!
griddriver_installer.destroy()!

12
examples/installers/traefik.vsh Executable file
View File

@@ -0,0 +1,12 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import os
import freeflowuniverse.herolib.installers.web.traefik as traefik_installer
traefik_installer.delete()!
mut installer := traefik_installer.get()!
installer.password = 'planet'
traefik_installer.set(installer)!
installer.start()!

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.daguserver
import freeflowuniverse.herolib.installers.infra.zinit_installer
mut ds := daguserver.get()!
ds.install()!
ds.start()!
ds.destroy()!

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.virt.pacman as pacman_installer
mut pacman := pacman_installer.get()!
// To install
pacman.install()!
// To remove
pacman.destroy()!

View File

@@ -0,0 +1,60 @@
#!/usr/bin/env -S v -n -w -cg -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.coredns as coredns_installer
import freeflowuniverse.herolib.osal.coredns
import freeflowuniverse.herolib.core.playbook
// coredns_installer.delete()!
mut installer := coredns_installer.get()!
// coredns_installer.fix()!
installer.start()!
mut script := "
!!dns.a_record
sub_domain: 'host1'
ip: '1.2.3.4'
ttl: 300
!!dns.aaaa_record
sub_domain: 'host1'
ip: '2001:db8::1'
ttl: 300
!!dns.mx_record
sub_domain: '*'
host: 'mail.example.com'
preference: 10
ttl: 300
!!dns.txt_record
sub_domain: '*'
text: 'v=spf1 mx ~all'
ttl: 300
!!dns.srv_record
service: 'ssh'
protocol: 'tcp'
host: 'host1'
target: 'sip.example.com'
port: 5060
priority: 10
weight: 100
ttl: 300
!!dns.ns_record
host: 'ns1.example.com'
ttl: 300
!!dns.soa_record
mbox: 'hostmaster.example.com'
ns: 'ns1.example.com'
refresh: 44
retry: 55
expire: 66
minttl: 100
ttl: 300
"
mut plbook := playbook.new(text: script)!
mut set := coredns.play_dns(mut plbook)!
set.set(key_prefix: 'dns:', domain: 'heroexample.com')!

24
examples/osal/tun.vsh Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.osal.tun
// Check if TUN is available
if available := tun.available() {
if available {
println('TUN is available on this system')
// Get a free TUN interface name
if interface_name := tun.free() {
println('Found free TUN interface: ${interface_name}')
// Example: Now you could use this interface name
// to set up your tunnel
} else {
println('Error finding free interface: ${err}')
}
} else {
println('TUN is not available on this system')
}
} else {
println('Error checking TUN availability: ${err}')
}

View File

@@ -0,0 +1,4 @@
buildah_example
buildah_run_clean
buildah_run_mdbook
buildah_run

View File

@@ -1,15 +1,14 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.virt.herocontainers
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.core.base
import freeflowuniverse.herolib.osal
import freeflowuniverse.herolib.installers.virt.pacman
import freeflowuniverse.herolib.installers.virt.podman as podman_installer
mut installer := pacman.get()!
// installer.destroy()!
// installer.install()!
mut podman_installer0 := podman_installer.get()!
// podman_installer0.destroy()!
podman_installer0.install()!
// exit(0)
@@ -17,13 +16,13 @@ mut installer := pacman.get()!
mut engine := herocontainers.new(install: true, herocompile: false)!
engine.reset_all()!
// engine.reset_all()!
mut builder_gorust := engine.builder_go_rust()!
// mut builder_gorust := engine.builder_go_rust()!
// will build nodejs, python build & herolib, hero
// mut builder_hero := engine.builder_hero(reset:true)!
// mut builder_web := engine.builder_heroweb(reset:true)!
builder_gorust.shell()!
// builder_gorust.shell()!

View File

@@ -7,14 +7,22 @@ import freeflowuniverse.herolib.core.base
import time
import os
mut pm := herocontainers.new(herocompile: true, install: false)!
// herocompile means we do it for the host system
mut pm := herocontainers.new(herocompile: false, install: false)!
mut mybuildcontainer := pm.builder_get('builder_heroweb')!
// pm.builder_base(reset:true)!
mut builder := pm.builder_get('base')!
builder.shell()!
println(builder)
// builder.install_zinit()!
// bash & python can be executed directly in build container
// any of the herocommands can be executed like this
mybuildcontainer.run(cmd: 'installers -n heroweb', runtime: .herocmd)!
// mybuildcontainer.run(cmd: 'installers -n heroweb', runtime: .herocmd)!
// //following will execute heroscript in the buildcontainer
// mybuildcontainer.run(

View File

@@ -2,7 +2,6 @@
import freeflowuniverse.herolib.virt.herocontainers
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.core.base
// import freeflowuniverse.herolib.builder
import time
import os

View File

@@ -5,16 +5,15 @@ import freeflowuniverse.herolib.web.docusaurus
// Create a new docusaurus factory
mut docs := docusaurus.new(
// build_path: '/tmp/docusaurus_build'
build_path: '/tmp/docusaurus_build'
)!
// Create a new docusaurus site
mut site := docs.dev(
url:'https://git.ourworld.tf/despiegk/docs_kristof'
url: 'https://git.ourworld.tf/despiegk/docs_kristof'
)!
//FOR FUTURE TO ADD CONTENT FROM DOCTREE
// FOR FUTURE TO ADD CONTENT FROM DOCTREE
// Create a doctree for content
// mut tree := doctree.new(name: 'content')!
@@ -34,10 +33,10 @@ mut site := docs.dev(
// )!
// Build the docusaurus site
//site.build()!
// site.build()!
// Generate the static site
//site.generate()!
// site.generate()!
// Optionally open the site in a browser
// site.open()!

View File

@@ -4,19 +4,38 @@ set -e
os_name="$(uname -s)"
arch_name="$(uname -m)"
version='1.0.14'
# Base URL for GitHub releases
base_url="https://github.com/freeflowuniverse/herolib/releases/download/v${version}"
# Select the URL based on the platform
if [[ "$os_name" == "Linux" && "$arch_name" == "x86_64" ]]; then
url="https://f003.backblazeb2.com/file/threefold/linux-i64/hero"
url="$base_url/hero-x86_64-unknown-linux-musl"
elif [[ "$os_name" == "Linux" && "$arch_name" == "aarch64" ]]; then
url="$base_url/hero-aarch64-unknown-linux-musl"
elif [[ "$os_name" == "Darwin" && "$arch_name" == "arm64" ]]; then
url="https://f003.backblazeb2.com/file/threefold/macos-arm64/hero"
# elif [[ "$os_name" == "Darwin" && "$arch_name" == "x86_64" ]]; then
# url="https://f003.backblazeb2.com/file/threefold/macos-i64/hero"
url="$base_url/hero-aarch64-apple-darwin"
elif [[ "$os_name" == "Darwin" && "$arch_name" == "x86_64" ]]; then
url="$base_url/hero-x86_64-apple-darwin"
else
echo "Unsupported platform."
echo "Unsupported platform: $os_name $arch_name"
exit 1
fi
# # Select the URL based on the platform
# if [[ "$os_name" == "Linux" && "$arch_name" == "x86_64" ]]; then
# url="https://f003.backblazeb2.com/file/threefold/linux-i64/hero"
# elif [[ "$os_name" == "Darwin" && "$arch_name" == "arm64" ]]; then
# url="https://f003.backblazeb2.com/file/threefold/macos-arm64/hero"
# # elif [[ "$os_name" == "Darwin" && "$arch_name" == "x86_64" ]]; then
# # url="https://f003.backblazeb2.com/file/threefold/macos-i64/hero"
# else
# echo "Unsupported platform."
# exit 1
# fi
# Check for existing hero installations
existing_hero=$(which hero 2>/dev/null || true)
if [ ! -z "$existing_hero" ]; then
@@ -122,4 +141,4 @@ if [ "$file_size" -ge 2 ]; then
else
echo "Downloaded file is less than 10 MB. Process aborted."
exit 1
fi
fi

View File

@@ -181,7 +181,7 @@ function os_update {
fi
#apt install apt-transport-https ca-certificates curl software-properties-common -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" --force-yes
package_install "apt-transport-https ca-certificates curl wget software-properties-common tmux"
package_install "rclone rsync mc redis-server screen net-tools git dnsutils htop ca-certificates screen lsb-release binutils pkg-config"
package_install "rclone rsync mc redis-server screen net-tools git dnsutils htop ca-certificates screen lsb-release binutils pkg-config libssl-dev iproute2"
elif [[ "${OSNAME}" == "darwin"* ]]; then
if command -v brew >/dev/null 2>&1; then

155
lib/biz/bizmodel/act.v Normal file
View File

@@ -0,0 +1,155 @@
module bizmodel
import os
import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.core.playbook { PlayBook, Action }
import freeflowuniverse.herolib.ui.console
// import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.data.paramsparser {Params}
import freeflowuniverse.herolib.biz.spreadsheet {RowGetArgs, UnitType, PeriodType}
pub fn (mut m BizModel) act(action Action) !Action {
return match texttools.snake_case(action.name) {
'funding_define' {
m.funding_define_action(action)!
}
'revenue_define' {
m.funding_define_action(action)!
}
'costcenter_define' {
m.costcenter_define_action(action)!
}
'cost_define' {
m.cost_define_action(action)!
}
'department_define' {
m.department_define_action(action)!
}
'employee_define' {
m.employee_define_action(action)!
}
'export_report' {
m.new_report_action(action)!
}
'sheet_wiki' {
m.export_sheet_action(action)!
}
'graph_bar_row' {
m.export_graph_bar_action(action)!
}
'graph_pie_row' {
m.export_graph_pie_action(action)!
}
'graph_line_row' {
m.export_graph_line_action(action)!
}
'row_overview' {
m.export_overview_action(action)!
}
else {
return error('Unknown operation: ${action.name}')
}
}
}
fn (mut m BizModel) export_sheet_action(action Action) !Action {
return m.export_action(m.sheet.wiki(row_args_from_params(action.params)!)!, action)
}
fn (mut m BizModel) export_graph_title_action(action Action) !Action {
return m.export_action(m.sheet.wiki_title_chart(row_args_from_params(action.params)!), action)
}
fn (mut m BizModel) export_graph_line_action(action Action) !Action {
return m.export_action(m.sheet.wiki_line_chart(row_args_from_params(action.params)!)!, action)
}
fn (mut m BizModel) export_graph_bar_action(action Action) !Action {
return m.export_action(m.sheet.wiki_bar_chart(row_args_from_params(action.params)!)!, action)
}
pub fn (mut m BizModel) export_graph_pie_action(action Action) !Action {
return m.export_action(m.sheet.wiki_pie_chart(row_args_from_params(action.params)!)!, action)
}
pub fn (mut m BizModel) export_overview_action(action Action) !Action {
return m.export_action(m.sheet.wiki_row_overview(row_args_from_params(action.params)!)!, action)
}
fn (mut m BizModel) new_report_action(action Action) !Action {
m.new_report(action.params.decode[Report]()!)!
return action
}
// fetches args for getting row from params
pub fn row_args_from_params(p Params) !RowGetArgs {
rowname := p.get_default('rowname', '')!
namefilter := p.get_list_default('namefilter', [])!
includefilter := p.get_list_default('includefilter', [])!
excludefilter := p.get_list_default('excludefilter', [])!
size := p.get_default('size', '')!
title_sub := p.get_default('title_sub', '')!
title := p.get_default('title', '')!
unit := p.get_default('unit', 'normal')!
unit_e := match unit {
'thousand' { UnitType.thousand }
'million' { UnitType.million }
'billion' { UnitType.billion }
else { UnitType.normal }
}
period_type := p.get_default('period_type', 'year')!
if period_type !in ['year', 'month', 'quarter'] {
return error('period type needs to be in year,month,quarter')
}
period_type_e := match period_type {
'year' { PeriodType.year }
'month' { PeriodType.month }
'quarter' { PeriodType.quarter }
else { PeriodType.error }
}
if period_type_e == .error {
return error('period type needs to be in year,month,quarter')
}
rowname_show := p.get_default_true('rowname_show')
descr_show := p.get_default_true('descr_show')
return RowGetArgs{
rowname: rowname
namefilter: namefilter
includefilter: includefilter
excludefilter: excludefilter
period_type: period_type_e
unit: unit_e
title_sub: title_sub
title: title
size: size
rowname_show: rowname_show
descr_show: descr_show
}
}
// creates the name for a file being exported given the params of the export action
fn (m BizModel) export_action(content string, action Action) !Action {
// determine name of file being exported
name := if action.params.exists('name') { action.params.get('name')! } else {
if action.params.exists('title') { action.params.get('title')! } else {
// if no name or title, name is ex: revenue_total_graph_bar_row
rowname := action.params.get_default('rowname', '')!
'${rowname}_${action.name}'
}
}
// by default exports to working dir of bizmodel
destination := action.params.get_default('destination', m.workdir)!
mut path := pathlib.get_file(
path: os.join_path(destination, name)
increment: true
empty: action.params.get_default_false('overwrite')
)!
path.write(content)!
return action
}

90
lib/biz/bizmodel/export.v Normal file
View File

@@ -0,0 +1,90 @@
module bizmodel
import os
import freeflowuniverse.herolib.web.docusaurus
import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.core.pathlib
pub struct Export {
pub:
path string
overwrite bool
format ExportFormat
}
pub enum ExportFormat {
docusaurus
mdbook
}
pub struct Report {
pub:
name string
title string
description string
path string
sections []ReportSection
}
pub enum ReportSection {
revenue_model
cost_structure
human_resources
}
pub fn (b BizModel) new_report(report Report) !Report {
name := if report.name != '' {report.name} else { texttools.snake_case(report.title) }
path := pathlib.get_dir(
path: os.join_path(os.home_dir(), '/hero/var/bizmodel/reports/${name}')
)!
return Report {
...report,
name: name
path: path.path
}
// b.export_summary()
// b.export_business_description()
// b.export_market_analysis()
// b.export_business_model()
// b.export_revenue_model(export)!
// b.export_cost_structure(export)
// b.export_operational_plan(export)!
// b.export_fundraising(export)
}
pub fn (r Report) export(export Export) ! {
match export.format {
.docusaurus {
mut factory := docusaurus.new()!
mut site := factory.get(
name: r.name
path: r.path
publish_path: export.path
config: docusaurus.Config {} //TODO: is this needed
)!
site.build()!
}
.mdbook {panic('MDBook export not fully implemented')}
}
}
pub fn (b BizModel) export_operational_plan(export Export) ! {
mut hr_page := pathlib.get_file(path: '${export.path}/human_resources.md')!
hr_page.template_write('./templates/human_resources.md', export.overwrite)!
for key, employee in b.employees {
mut employee_page := pathlib.get_file(path: '${export.path}/${texttools.snake_case(employee.name)}.md')!
employee_page.template_write('./templates/employee.md', export.overwrite)!
}
}
pub fn (b BizModel) export_revenue_model(export Export) ! {
println('begin')
mut overview_page := pathlib.get_file(path: '${export.path}/revenue_overview.md')!
overview_page.template_write('./templates/overview.md', export.overwrite)!
for key, product in b.products {
mut product_page := pathlib.get_file(path: '${export.path}/${texttools.snake_case(product.name)}.md')!
product_page.template_write('./templates/product.md', export.overwrite)!
}
}

View File

@@ -0,0 +1,14 @@
module bizmodel
import os
import freeflowuniverse.herolib.web.docusaurus
const bizmodel_name = 'test'
const export_path = os.join_path(os.dir(@FILE), 'testdata')
pub fn test_export_report() ! {
model := getset(bizmodel_name)!
model.export_report(Report{
title: 'My Business Model'
}, path: export_path)!
}

View File

@@ -11,8 +11,8 @@ pub fn get(name string) !&BizModel {
if name in bizmodels {
return bizmodels[name] or { panic('bug') }
}
return error("cann't find biz model:'${name}' in global bizmodels ${bizmodels.keys()}")
}
return error("cann't find biz model:'${name}' in global bizmodels")
}
// get bizmodel from global

View File

@@ -1,10 +1,12 @@
module bizmodel
import os
import freeflowuniverse.herolib.biz.spreadsheet
pub struct BizModel {
pub mut:
name string
workdir string = '${os.home_dir()}/hero/var/bizmodel'
sheet &spreadsheet.Sheet
employees map[string]&Employee
departments map[string]&Department

View File

@@ -1,89 +1,51 @@
module bizmodel
import freeflowuniverse.herolib.core.playbook { PlayBook }
import arrays
import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.core.playbook { PlayBook, Action }
import freeflowuniverse.herolib.ui.console
// import freeflowuniverse.herolib.core.texttools
// import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.biz.spreadsheet
pub fn play(mut plbook PlayBook) ! {
// first make sure we find a run action to know the name
mut actions4 := plbook.actions_find(actor: 'bizmodel')!
if actions4.len == 0 {
return
}
knownactions := ['revenue_define', 'employee_define', 'department_define', 'funding_define',
'costcenter_define', 'cost_define']
for action in actions4 {
// biz name needs to be specified in the the bizmodel hero actions
bizname := action.params.get('bizname') or {
return error("Can't find param: 'bizname' for ${action.actor}.${action.name} macro, is a requirement argument.")
}
mut sim := getset(bizname)!
if action.name !in knownactions {
return error("Can't find macro with name: ${action.name} for macro's for bizmodel.")
}
console.print_debug(action.name)
match action.name {
'revenue_define' {
sim.revenue_action(action)!
}
'funding_define' {
sim.funding_define_action(action)!
}
'costcenter_define' {
sim.costcenter_define_action(action)!
}
else {}
}
}
console.print_debug('TOTALS for bizmodel play')
// now we have processed the macro's, we can calculate the totals
rlock bizmodels {
for _, mut sim in bizmodels {
// sim.hr_total()!
sim.cost_total()!
sim.revenue_total()!
sim.funding_total()!
}
}
for action in actions4 {
console.print_debug(action.name)
// biz name needs to be specified in the the bizmodel hero actions
bizname := action.params.get('bizname') or {
return error("Can't find param: 'bizname' for bizmodel macro, is a requirement argument.")
}
mut sim := get(bizname)!
if action.name !in knownactions {
return error("Can't find macro with name: ${action.name} for macro's for bizmodel.")
}
match action.name {
'cost_define' {
sim.cost_define_action(action)!
}
'department_define' {
sim.department_define_action(action)!
}
'employee_define' {
sim.employee_define_action(action)!
}
else {}
}
}
// mut sim:=get("test")!
// //println(sim.sheet.rows.keys())
// //println(spreadsheet.sheets_keys())
// println(spreadsheet.sheet_get('bizmodel_test')!)
// if true{panic("sss")}
const action_priorities = {
0: ['revenue_define', 'costcenter_define', 'funding_define']
1: ['cost_define', 'department_define', 'employee_define']
2: ['sheet_wiki', 'graph_bar_row', 'graph_pie_row', 'graph_line_row', 'row_overview']
}
pub fn play(mut plbook PlayBook) ! {
// group actions by which bizmodel they belong to
actions_by_biz := arrays.group_by[string, &Action](
plbook.actions_find(actor: 'bizmodel')!,
fn (a &Action) string {
return a.params.get('bizname') or {'default'}
}
)
// play actions for each biz in playbook
for biz, actions in actions_by_biz {
mut model := getset(biz)!
model.play(mut plbook)!
}
}
pub fn (mut m BizModel) play(mut plbook PlayBook) ! {
mut actions := plbook.actions_find(actor: 'bizmodel')!
for action in actions.filter(it.name in action_priorities[0]) {
m.act(*action)!
}
m.cost_total()!
m.revenue_total()!
m.funding_total()!
for action in actions.filter(it.name in action_priorities[1]) {
m.act(*action)!
}
for action in actions.filter(it.name in action_priorities[2]) {
m.act(*action)!
}
}

View File

@@ -3,7 +3,7 @@ module bizmodel
import freeflowuniverse.herolib.core.playbook { Action }
import freeflowuniverse.herolib.core.texttools
fn (mut m BizModel) cost_define_action(action Action) ! {
fn (mut m BizModel) cost_define_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -73,6 +73,7 @@ fn (mut m BizModel) cost_define_action(action Action) ! {
)!
m.sheet.row_delete('tmp3')
}
return action
}
fn (mut sim BizModel) cost_total() ! {

View File

@@ -3,7 +3,7 @@ module bizmodel
import freeflowuniverse.herolib.core.playbook { Action }
import freeflowuniverse.herolib.core.texttools
fn (mut m BizModel) costcenter_define_action(action Action) ! {
fn (mut m BizModel) costcenter_define_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -20,4 +20,5 @@ fn (mut m BizModel) costcenter_define_action(action Action) ! {
department: department
}
m.costcenters[name] = &cc
return action
}

View File

@@ -9,7 +9,7 @@ import freeflowuniverse.herolib.core.texttools
// - descr: description of the funding .
// - investment is month:amount,month:amount, ... .
// - type: loan or capital .
fn (mut m BizModel) funding_define_action(action Action) ! {
fn (mut m BizModel) funding_define_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -29,6 +29,7 @@ fn (mut m BizModel) funding_define_action(action Action) ! {
descr: descr
extrapolate: false
)!
return action
}
fn (mut sim BizModel) funding_total() ! {

View File

@@ -15,7 +15,7 @@ import freeflowuniverse.herolib.core.texttools
// department:'engineering'
// cost_percent_revenue e.g. 4%, will make sure the cost will be at least 4% of revenue
fn (mut m BizModel) employee_define_action(action Action) ! {
fn (mut m BizModel) employee_define_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -107,10 +107,7 @@ fn (mut m BizModel) employee_define_action(action Action) ! {
fulltime_perc: action.params.get_percentage_default('fulltime', '100%')!
}
// println(employee)
// todo: use existing id gen
if name != '' {
// sid = smartid.sid_new('')!
// // TODO: this isn't necessary if sid_new works correctly
@@ -120,9 +117,10 @@ fn (mut m BizModel) employee_define_action(action Action) ! {
// }
m.employees[name] = &employee
}
return action
}
fn (mut m BizModel) department_define_action(action Action) ! {
fn (mut m BizModel) department_define_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -141,6 +139,8 @@ fn (mut m BizModel) department_define_action(action Action) ! {
if name != '' {
m.departments[name] = &department
}
return action
}
// fn (mut sim BizModel) hr_total() ! {

View File

@@ -21,7 +21,7 @@ import freeflowuniverse.herolib.core.texttools
// - nr_sold: how many do we sell per month (is in growth format e.g. 10:100,20:200)
// - nr_months_recurring: how many months is recurring, if 0 then no recurring
//
fn (mut m BizModel) revenue_action(action Action) ! {
fn (mut m BizModel) revenue_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -312,6 +312,7 @@ fn (mut m BizModel) revenue_action(action Action) ! {
// panic("sdsd")
// }
return action
}
// revenue_total calculates and aggregates the total revenue and cost of goods sold (COGS) for the business model

View File

@@ -0,0 +1,9 @@
# Human Resources
| Name | Title | Nr People |
|------|-------|-------|
@for employee in model.employees.values().filter(it.department == dept.name)
| @{employee_names[employee.name]} | @{employee.title} | @{employee.nrpeople} |
@end
@end

View File

@@ -2,53 +2,48 @@
## FUNDING
!!bizmodel.sheet_wiki includefilter:'funding'
@{bizmodel.sheet.wiki(includefilter:'funding')!}
## REVENUE vs COGS
!!bizmodel.sheet_wiki includefilter:rev
@{bizmodel.sheet.wiki(includefilter:'rev')!}
#### Revenue Lines
!!bizmodel.sheet_wiki title:'Revenue Total' includefilter:'revtotal'
@{bizmodel.sheet.wiki(title:'Revenue Total', includefilter:'revtotal')!}
#### COGS Lines
!!bizmodel.sheet_wiki title:'COGS' includefilter:'cogstotal'
@{bizmodel.sheet.wiki(title:'COGS', includefilter:'cogstotal')!}
## HR
!!bizmodel.sheet_wiki title:'HR Teams' includefilter:'hrnr'
!!bizmodel.sheet_wiki title:'HR Costs' includefilter:'hrcost'
@{bizmodel.sheet.wiki(title:'HR Teams', includefilter:'hrnr')!}
@{bizmodel.sheet.wiki(title:'HR Costs', includefilter:'hrcost')!}
## Operational Costs
!!bizmodel.sheet_wiki title:'COSTS' includefilter:'ocost'
@{bizmodel.sheet.wiki(title:'COSTS', includefilter:'ocost')!}
## P&L Overview
<!-- period is in months, 3 means every quarter -->
!!bizmodel.sheet_wiki title:'P&L Overview' includefilter:'pl'
@{bizmodel.sheet.wiki(title:'P&L Overview', includefilter:'pl')!}
!!bizmodel.graph_bar_row rowname:revenue_total unit:million title:'A Title' title_sub:'Sub'
@{bizmodel.graph_bar_row(rowname:'revenue_total', unit:'million', title:'A Title', title_sub:'Sub')!}
Unit is in Million USD.
!!bizmodel.graph_bar_row rowname:revenue_total unit:million
@{bizmodel.graph_bar_row(rowname:'revenue_total', unit:'million')!}
!!bizmodel.graph_line_row rowname:revenue_total unit:million
!!bizmodel.graph_pie_row rowname:revenue_total unit:million size:'80%'
@{bizmodel.graph_line_row(rowname:'revenue_total', unit:'million')!}
@{bizmodel.graph_pie_row(rowname:'revenue_total', unit:'million', size:'80%')!}
## Some Details
> show how we can do per month
!!bizmodel.sheet_wiki includefilter:'pl' period_months:1
@{bizmodel.sheet_wiki(includefilter:'pl', period_months:1)!}

View File

@@ -0,0 +1,68 @@
# @{product.title}
@{product.description}
#### parameters for the product
@if product.has_oneoffs
Product ${name1} has revenue events (one offs)
!!!spreadsheet.sheet_wiki
namefilter:'${name1}_revenue,${name1}_cogs,${name1}_cogs_perc,${name1}_maintenance_month_perc' sheetname:'bizmodel_tf9
- COGS = Cost of Goods Sold (is our cost to deliver the product/service)
- maintenance is fee we charge to the customer per month in relation to the revenue we charged e.g. 1% of a product which was sold for 1m EUR means we charge 1% of 1 m EUR per month.
@end //one offs
@if product.has_items
Product sold and its revenue/cost of goods
!!!spreadsheet.sheet_wiki
namefilter:'${name1}_nr_sold,${name1}_revenue_setup,${name1}_revenue_monthly,${name1}_cogs_setup,${name1}_cogs_setup_perc,${name1}_cogs_monthly,${name1}_cogs_monthly_perc'
sheetname:'bizmodel_tf9
- nr sold, is the nr sold per month of ${name1}
- revenue setup is setup per item for ${name1}, this is the money we receive. Similar there is a revenue monthly.
- cogs = Cost of Goods Sold (is our cost to deliver the product)
- can we as a setup per item, or per month per item
@if product.nr_months_recurring>1
This product ${name1} is recurring, means customer pays per month ongoing, the period customer is paying for in months is: **${product.nr_months_recurring}**
@end //recurring
@end
#### the revenue/cogs calculated
!!!spreadsheet.sheet_wiki
namefilter:'${name1}_nr_sold_recurring'
sheetname:'bizmodel_tf9
This results in following revenues and cogs:
!!!spreadsheet.sheet_wiki
namefilter:'${name1}_revenue_setup_total,${name1}_revenue_monthly_total,${name1}_cogs_setup_total,${name1}_cogs_monthly_total,${name1}_cogs_setup_from_perc,${name1}_cogs_monthly_from_perc,${name1}_maintenance_month,
${name1}_revenue_monthly_recurring,${name1}_cogs_monthly_recurring'
sheetname:'bizmodel_tf9
resulting revenues:
!!!spreadsheet.sheet_wiki
namefilter:'${name1}_revenue_total,${name1}_cogs_total'
sheetname:'bizmodel_tf9
!!!spreadsheet.graph_line_row rowname:'${name1}_cogs_total' unit:million sheetname:'bizmodel_tf9'
!!!spreadsheet.graph_line_row rowname:'${name1}_revenue_total' unit:million sheetname:'bizmodel_tf9'
@end //product has_revenue
@end //loop

Some files were not shown because too many files have changed in this diff Show More