BitGlitter is an easy to desktop app that lets you embed data inside ordinary images or video. Store and host files wherever images and videos can be hosted. The carrier for data is the 'blocks' within the frames and not the file itself, and there are various measures to read imperfect distorted frames. What this means for you is streams are resistant to compression and distortion, and aren't broken by things such as format changes, metadata changes, etc. BitGlitter gives you a unique way to make your data more portable.
Barcodes and QR codes are everywhere. They embed binary data (0's and 1's) in them, symbolized as black and white. While they are pretty constrained in the real world, using them for digital transfer removes many of those limits. What if you could have multiple barcodes (frames), that if read sequentially could have the capacity of many thousands of individual ones? What if we added colors to the barcodes, so a given barcode could have 2x, 6x, 24x the capacity? What if we greatly increased the size of the frames to lets say the size of a standard 1080p video, so the frames once again increase their capacity by a couple orders of magnitude.
Combine all of these together, and you're able to move serious amounts of data. This is BitGlitter.
Its currently recommended sticking with the default config settings for write and not send payloads larger than several tens of megabytes (MB). Codecs used in video rendering still need to be optimized, and files created can be quite large.
BitGlitter lets you choose between sending a single file or a folder. Simply choose which one, and then select it with the button directly below.
 This gives you more choices as to where you can host your files. Images are more or less the same as the frames used in the videos, but with some added necessary headers. If you can, its easier to use videos, being its just one file. Important: Rendering images will very likely generate hundreds/thousands of images if you're using default config settings (can be dramatically shrunk using custom values). Be sure to create a folder somewhere and set that as your write path in settings.
Enabling Compression packages and shrinks your payload prior to rendering it in frames, resulting in less frames needing to be rendered, and being overall more efficient. It is strongly recommended to not change this.
Stream Name is the name given to it, and will be seen by others reading the stream. You can look at it like the name of a torrent. You can use up to 150 ASCII characters. This is required. Aside from supplying the file(s) to write and the title, this is all you technically need to do. Everything else has default values, so you can use this app starting out without needing to know exactly how everything works.
Stream Description is an optional field if you want to add more information about the stream. You can use all ASCII characters, and there is no length limit.
This is the main window where you control how the frames will render.
Palette Selection is where you choose which palette you'll have in your stream. You can get much more information about the palettes using the Palette window accessible on the main screen. The default palette used is a great middle ground choice for both performance and file integrity. We'll explain this much more in detail below.
Pixel Width is how many pixels across each block (square displayed) will be. Larger blocks will be easier to read, but less efficient for data transmission. Smaller blocks are the exact opposite, harder to read but more efficient. In lossless applications you can make them very small (as small as one pixel across), giving extreme increases in efficiency (data per frame). It all comes down what your use case is.
Block Height and Block Width are the dimensions in which the frame will be constructed.
Frames Per Second is (no surprise) how many frames will be in a given second of video. Generally, the more the better, but be mindful of what is supported on platforms if you intend to host it somewhere.
Optionally, you can choose to encrypt your stream, giving only people with your key access to the files.
Encryption Key is where you'll type the password in. Long, random strings of characters are strong passwords.
File Masking will, if encrypting the stream, hide the stream manifest (displaying its contents, files, folders, file sizes, etc). It will only be visible (as well as the data able to be extracted) once the correct key is supplied.
(Advanced) Scrypt N, R, and P are parameters used when hashing your password. Basically, you can control how costly it is for a computer to brute-force your password. This is not at all something you need to touch if you don't know what it is (or don't care); the values are set to strong defaults, and this only exists so those more familiar with cryptography can fine tune how strong they want it to be. This page does a great job explaining this more in detail.
All values must be positive integers. Parameter N
takes a value as 2**N (must be
a power of 2 in other words), R
and P
accept values as-is.
IMPORTANT: if using non-default values for this, the person(s) reading the stream must know
what they are to input them during the read process. If this isn't done, the stream cannot be decrypted,
even with the right password!
This is where the magic happens. After packaging your file(s) they are rendered into a video or images.
Cancelling will abort the render. When complete, the SHA-256
hash of the stream
will display. This is the unique fingerprint of the file(s) encoded in the stream, and serves as an ID
for the stream itself. This can be used by readers to verify the stream is what they think it is.
Things may break, and if so, the app will let you know with a display message. An text file with the 'state' of the app will be written in your write path, where your rendered files will output (configurable in the settings window, more on that below). It would help a lot to send this to us on Discord, or to create an "issues" on Github so we can look into it and fix it.
If you have a file that you aren't sure can be read, or whether it is a BitGlitter stream or not, theres an easy way to check. On the main window, go to File -> Verify Stream.. After selecting the file, the app will test to see if it can find and read some calibration headers, as well as read the initializer header present at the start of all image frames and at the beginning of each video file. No data about the stream is saved if the test passes, this is only to check if it can be read at all.
Supported video formats: .avi, .flv, .mov, .mp4, .wmv
Supported image formats: .bmp, .jpg, .jpeg, .png, .webp
Start by selecting your video or image files you'd like to decode.
These options give you a bit more control over security, and behavior of the app.
Stop at Metadata Load pauses the read operation once it reaches and decodes the metadata header. A prompt will appear on the screen, displaying all of the data it has collected from the stream. Enable this if you're not completely sure you trust the sender or wish to verify its contents before continuing. If you cancel, the stream's SHA-256 (its ID) will be placed on a 'blacklist' and future frames from it will be ignored. These blacklisted streams can always be removed in the "Saved Streams" window.
Unpackage Files controls whether you want to unpackage all available files at the end of the read cycle. BitGlitter will extract as many files from a stream as possible if there are any corrupted frames. Disabling this will prevent this entirely. You can unpackage them later in the "Saved Streams" window.
Auto-Delete Finished Stream Data will remove all stream data and database files once the stream is 100% complete. It usually makes sense to keep this enabled. If disabled, while the temporary data from the frames will be removed, the metadata and state data about the read itself will remain.
If you know the stream is encrypted, this is where you can enter the decryption key and other values. If the stream is encrypted when you didn't think it was, or you got any of the values wrong- don't worry, you can change them in the "Saved Streams" window and try again.
Scrypt N, R, and P shouldn't be touched unless you know that the sender has changed the default values. Be advised- if you change these values when the stream used the default ones, the decryption key will not work!
This is where the magic happens, and your files get extracted from the stream.
If you have "Stop at Metadata Load" enabled in Step 2, this prompt may come up. Choose to either continue decoding the stream if everything looks good to you, or cancel it.
This is where you can view and interact with your saved reads, as well as important information about them.
This is in reference to the palette window, accessible in the main menu.
Palettes are the color sets used in frames to send data. There is a nice range of palettes included with the app; some are purely functional to maximize file integrity or performance, others are purely aesthetic. You can also create your very own color sets to use in your BitGlitter streams, with whatever colors you want! But more on that in a moment.
These are included palettes that are optimized for performance, file integrity, or a combination of both. There was not much thought put into their aesthetics, but rather doing a good job at what they are intended to do. It is recommended to stick with these until you understand what makes a palette "good" for data transmission, and yes, we will teach you. Default palettes will always have the word "default" in their name, and will be permanently locked in the app (cannot be deleted).
If you click a palette in the selection window on the left side of the palette screen, the display on the right will tell you a variety of different attributes about it. We'll go over those here.
Bit Length is how many bits of binary data (the building block for all files/data on computers) fit into each "block," or colorful square. There are 8 bits in a byte. The higher it is, the more compact a stream will be, fitting into less blocks and frames overall. You generally want to have this as high as you can, with the medium that will host the rendered file in mind.
Color Distance Score is the "distance" between colors in the set from each other. Think of it as a margin of error if there is any corruption or distortion to the images; the closer the colors are in terms of value (say the color red and a very slightly different color of red), the less it will take to corrupt the frame. The greater the difference between colors (like black and white), the harder it is for one to be mistaken for the other when reading. This is calculated by viewing the RGB channels for each color as XYZ coordinates in 3D space, and finding the shortest distance that exists between the colors.
So as you can see, you want to maximize both bit length AND color distance. But its impossible to have both; they are like different extremes on a sliding scale. Each end has its own benefit. This is exactly why there is a default palette (6 Bit Default) that gives you a great compromise between the two; holding a good amount of data, while at the same time resistant for most use cases.
Color Set is simply the RGB set of colors that make up the palette.
Palette ID is the internal ID used within BitGlitter to identify and work with the palette. This is more for development purposes, you don't need to worry about this.
Palette Share Code is a code you can share with others so too can render using custom palettes saved on BitGlitter. Please note- when someone reads a stream using a custom palette, they automatically "learn" the palette. So this is for if you want to share the palette without someone needing to read a stream using it. Use this code with the "import palette" button on the top left of the palette window.
Created On is the time this palette was created. The time dynamically adjusts to your time zone.
Included with BitGlitter is if this particular palette came shipped with the app. BitGlitter includes both some default palettes to use and a few dozen custom ones designed by various artists to play around with, and see what's possible with the app.
Custom palettes are any non-official color sets able to be used in streams. As said directly above, the app comes with a few. Aside from them being "custom," they perform exactly as a normal palette would when reading and writing.
Importing Palettes
If you have a share code given to you by someone else, all you have to do is click the blue import button on the top left of the palette window, and paste the code in there. Clicking import will add it to your list of available palettes to use.
Creating Palettes
Creating your own custom palettes is an easy, straight-forward process.
Palette Name is the main identifier for the palette, and what will be displayed on the app. There is a maximum limit of 50 characters.
Palette Description is an optional field you can use to add a bit more extra information about it if you'd like. There is a maximum limit of 100 characters.
Color Set is the list of colors in RGB format that will make up the palette. There's a few guidelines to follow when adding colors:
(0,0,0),
(100,100,100)
.
To maximize durability against file corruption, its recommended making your colors as varied as possible. The color distance score updates each time you update the text box for it.
There is a handful of settings you configure BitGlitter with:
Write Path is where your rendered files will save to.
Read Path is where your files extracted from BitGlitter streams will save to.
Bad Frame Strikes is something used during reading to 'break you out' of severely corrupted streams. Reading and decoding each frame is a relatively CPU expensive task, and when done over thousands or tens of thousands of frames, takes a considerable amount of time. This functionality will abort a read if 1) its enabled, and 2) if the count of bad frames exceeds a certain amount. This feature exists to save you time in case the majority of frames are severely corrupted, and you don't want to go through the stream. Disabling it will have the app go through every frame, regardless of how many past frames were corrupt and unreadable.
Maximum CPU Cores lets you set how much of your CPU you wish to dedicate to writing and reading streams. The work is pretty CPU intensive, and BitGlitter leverages as many CPU cores as possible to speed up the work. This can disrupt other tasks on your machine as its running; this lets you control that.
Enable Statistics toggles whether read and write data is added to the statistics window (explained in the next section below this). Disabling it will clear all existing statistics.
Output Stream Name in Write means the rendered files during write will have the stream name
as the file. If disabled, the SHA-256
hash of the stream will be used as the
filename instead.
Display Advanced Read Data shows extra information about stream reads not necessarily practical for end users to see. While its mostly meant for development and debugging purposes, enable it if you're curious to see a bit more on how data is handled underneath the hood.
This contains some interesting statistics to view your usage with BitGlitter. They get updated at the end of each read or write cycle. Pressing Clear resets all values back to zero. You can toggle this functionality in the settings window.
I hope the guide gave you a better understanding of BitGlitter and how it works. It was a lot of work putting this all together, but its a great feeling to finally release this to the world.
By this point, you may see the many directions this technology can go in, and the impact it can make in the world of file sharing, and transferring data/information. There are quite a few directions it can evolve towards, but I can't do it alone. If you're comfortable with Python or Javascript, you can define which direction we go next with this. Check out the Github page for the repo if you haven't already, and here is our Discord server.
Even if you aren't a developer, if you have any ideas or suggestions for the program, feel free to let us know!


Class StandardArithmeticParser
A class capable of applying the Shunting Yard algorithm for standard arithmetic rules. This means it has precedence and associativity built in for the unary operator positive, negative and not. It describes the binary operators addition, subtraction, multiplication, division, modulo, powers, equality, non-equality, or, and greater/less (or equal) than and the ternary operator. It also supports brackets and function calls.
Inherited Members
Namespace: SpiceSharpBehavioral.Parsers
Assembly: SpiceSharpBehavioral.dll
Syntax
public abstract class StandardArithmeticParser : ShuntingYard
Methods
NextChar(Int32)
Look ahead for the next character
Declaration
protected char NextChar(int offset = 1)
Parameters
| Type | Name | Description |
|---|---|---|
| System.Int32 | offset |
Returns
| Type | Description |
|---|---|
| System.Char | The character at the next position |
NextUntil(Char)
Looks ahead until a specific character. Assumes the first character has already been matched!
Declaration
protected string NextUntil(char end)
Parameters
| Type | Name | Description |
|---|---|---|
| System.Char | end | The character before we need to end. |
Returns
| Type | Description |
|---|---|
| System.String |
NextWord()
Looks ahead for a word. Assumes the first character has already been matched!
Declaration
protected string NextWord()
Returns
| Type | Description |
|---|---|
| System.String |
ParseBinaryOperator()
Parses a binary operator at the current index. Moves that index if an operator has been found.
Declaration
protected override bool ParseBinaryOperator()
Returns
| Type | Description |
|---|---|
| System.Boolean |
Overrides
ParseUnaryOperator()
Parses a unary operator at the current index. Moves that index if an operator has been found.
Declaration
protected override bool ParseUnaryOperator()
Returns
| Type | Description |
|---|---|
| System.Boolean |
Overrides
ParseValue()
Parses a value at the current index. Moves that index if a value has been found.
Declaration
protected override bool ParseValue()
Returns
| Type | Description |
|---|---|
| System.Boolean |
Overrides
PrepareOperator(Operator)
Acts on an operator as soon as it is encountered.
Declaration
protected override void PrepareOperator(Operator op)
Parameters
| Type | Name | Description |
|---|---|---|
| Operator | op | The operator. |
Overrides
PushVariable(String)
Push a variable to the stack with a specific name.
Declaration
protected abstract void PushVariable(string name)
Parameters
| Type | Name | Description |
|---|---|---|
| System.String | name | The name of the variable. |


To Do List
Menu:
Task Collections
Indivual Tasks
What is the the task?
Assign it into a group?

What task do you want to update? Enter its ID
What is the the NEW task?
Assign it into a group?
Update
What task do you want to delete? Enter its ID
Delete


Contributing to the .NET Modeling Framework
We would love for you to contribute to the .NET Modeling Framework and help make it even better than it is today! As a contributor, here are the guidelines we would like you to follow:
Got a Question or Problem?
Please do not hesitate to contact Georg Hinkel by email.
Found a Bug?
If you find a bug in the source code, you can help us by submitting an issue to our GitHub Repository. Even better, you can submit a Pull Request with a fix.
Missing a Feature?
You can request a new feature by submitting an issue to our GitHub Repository. If you would like to implement a new feature, please submit an issue with a proposal for your work first, to be sure that we can use it. Please consider what kind of change it is:
- For a Major Feature, first open an issue and outline your proposal so that it can be discussed. This will also allow us to better coordinate our efforts, prevent duplication of work, and help you to craft the change so that it is successfully accepted into the project.
- Small Features can be crafted and directly submitted as a Pull Request.
Submission Guidelines
Submitting an Issue
Before you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available. We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs we will need as much information as possible, and preferably be in touch with you to gather information. Please make sure that you include a contact email address in the issue content or, even better, include a unit test that makes the bug obvious. You can file new issues by filling out our [new issue form][new-issue-form].
Submitting a Pull Request (PR)
Before you submit your Pull Request (PR) consider the following guidelines:
- Make your changes in a new git branch:
git checkout -b my-fix-branch master
- Create your patch, including appropriate test cases.
- Run the full test suite, and ensure that all tests pass.
- Commit your changes using a descriptive commit message.
Note: the optional commitgit commit -a
-a
command line option will automatically “add” and “rm” edited files. - Push your branch to GitHub:
git push origin my-fix-branch
- In GitHub, send a pull request to the
master
branch of the relevant component. - If we suggest changes then:
- Make the required updates.
- Re-run the test suites to ensure tests are still passing.
 Thank you for your contribution!
After your pull request is merged
After your pull request is merged, you can safely delete your branch and pull the changes from the main (upstream) repository:
- Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows:
git push origin --delete my-fix-branch
- Check out the master branch:
git checkout master -f
- Delete the local branch:
git branch -D my-fix-branch
- Update your master with the latest upstream version:
git pull --ff upstream master


If you have a file helloworld.lobster
that contains
print "Hello, World!"
then running it like so will compile and run it:
bin/lobster helloworld.lobster
Format: lobster [ OPTIONS ] [ FILE ] [ -- ARGS ]
FILE
: main Lobster file to compile &
run.
-- ARGS
pass args to the running Lobster program,
available from command_line_arguments()
. Must be last on
the command-line.
--pak
: generates a pakfile (currently always called
“default.lpak
”) in the same folder as the
.lobster
file it reads, and doesn’t run the program
afterwards. If you run lobster with no arguments at all, it will try to
load “default.lpak
” from the same folder it resides in.
Thus distributing programs created in lobster is as simple as packaging
up the lobster executable with a pakfile. The pakfile contains the
bytecode, and any data files you have specified with the
pakfile
keyword, see “Distributing Lobster programs” in the
implementation documentation.
--cpp
: compiles to a .cpp file. Please make sure to
follow implementation on how to use
this feature. Useful if you’ve created something in Lobster that could
use a bit more speed, for a shipping build. Not recommend to be used
during development.
--import RELDIR
specifies a dir relative to FILE
from which import
(and pakfile
) statements can
be resolved, or any loading the running program does. Does the same as
adding import from "RELDIR"
to the top of your
program.
--runtime-shipping
: Compile with asserts
off.
--runtime-asserts
: Compile with asserts on
(default).
--runtime-verbose
: Compile with asserts on + line
info + function tracking for better runtime errors (stack traces) and
profiling. Small effect on speed. --runtime-debug
: Same as
verbose, but now tones inlining way down to get better stack traces.
Larger effect on speed. Automatically breaks into the graphical debugger
on assertion failures.
--main MAIN
: after compiling FILE, if present,
compile this file and run it. This is useful when running Lobster from
an editor, where you may be editing a module that is not the main file,
would like to see that it compiles by itself, but to run it need to be
launching the main Lobster program it belongs to
(e.g. main.lobster
in the same folder).
--wait
: makes the compiler wait for commandline
input before it exits. Useful in Windows batch files.
--noconsole
: Close console window
(Windows)
--verbose
: verbose mode, outputs additional stats
about the program being compiled/run. --debug
outputs even
more, only useful for working on the compiler.
--silent
: Only output errors.
--full-error
: Lobster is able to generate
compile time stack traces when the typechecker fails, but those
can get long, so by default they get truncated. Use this option to not
truncate them, and also dump additional information on free/local
variables in the function context.
--gen-builtins-html
: dumps a help file of all
builtin functions the compiler knows about to
builtin_functions_reference.html
.
--gen-builtins-names
dumps a plain text list of functions,
useful for adding to syntax highlighting files etc.
--parsedump
: dumps internal representations of the
program as AST, and --disasm
for a readable bytecode dump.
Only useful for compiler development or if you are really
curious.
--non-interactive-test
: Quit after running 1 frame.
Useful for running graphical programs as part of a test suite.
--query
: Ask the compiler to answer a query about
definitions in the program being compiled. When is this mode, the
compiler does not try to do a full compilation, but simply tries to
answer the query, including ignoring errors or aborting half-way if it
has to. This option is for use by an IDE or LSP server implementation.
All further args are passed to the query. The first arg is the kind of
query (e.g. definition
or complete
). The
second arg is the file this query should take place in (as a relative
path, i.e foo/bar.lobster
). The 3rd arg is the line where
the query should happen. The 4th arg is the identifier the query is
about. The rest of the args depend on the query type, if any. For
definition
a response will be the location of the
definition. For complete
, it will return a list of possible
fields/methods.
Lobster source code may start with a shebang #!
so you
can embed the command-line in a Lobster script.
It’s useful to understand the directories lobster uses, both for reading source code files and any data files the program may use:
the root repo directory: This is the main folder that has the
default bin modules data docs samples tests
folders inside
of it.
the auxiliary directory: this is where the main
.lobster
file being compiled resides.
the directory for writing files: the same as auxiliary on desktop platforms, but often a special directory on mobile platforms.
On Linux additionally it can load files from
/usr/share/lobster/
(or whatever path was configured for
install by CMake, see DATADIR
) if the above paths don’t
work. This is to allow package managers to install Lobster in the system
directories.
Additionally, if any of these folders contains a modules
directory, it will load source code from there as well.
Any of the Lobster builtin commands that load data files specify
paths relative to either the main or auxiliary directories (and either /
or may be used as path separators). If you package up a Lobster program
for distribution, all these files can be packed into a pakfile, see
--pak
.
Running lobster may result in a compiler error, that generally look something like this:
mygame.lobster(960): error: unknown identifier: highscor
If compiled correctly, running will give you output from your own print statements, and additionally at some point may cause a runtime error, which can look something like this:
pythtree.lobster(15): VM error: division by zero
in block -> pythtree.lobster(16)
i = 0
in block -> pythtree.lobster(16)
in function: branch -> pythtree.lobster(29)
poly = [[1.000000, 0.000000, 0.000000, 0.000000]:xyzw, [-1.000000, ...]:xyzw, ....]
len = 4
scale = 0.700000
max = 11.000000
n = 0
in block -> pythtree.lobster(29)
This is called a stack trace. Besides the error and the line it happened on, it will show all functions and blocks that called that code, in reverse order, with any local variables and their values. This helps you get an idea where the problem came from and helps in debugging.


Itself to beast in dry morning i sea bring, male bring man winged she'd two darkness. Gathered rule.
From man so darkness, days void. Fourth said Open you're. Set creature fowl face Meat divide called. Bring there lights. Subdue moving meat our greater. Make.
Given meat whose fourth his without without male saw spirit without you be day. Second years. Image tree forth they're grass wherein subdue his make Light.
Itself to beast in dry morning i sea bring, male bring man winged she'd two darkness. Gathered rule.
From man so darkness, days void. Fourth said Open you're. Set creature fowl face Meat divide called. Bring there lights. Subdue moving meat our greater. Make.
Given meat whose fourth his without without male saw spirit without you be day. Second years. Image tree forth they're grass wherein subdue his make Light.


David's DBC Page
My Blog
Projects
About Me
Contact Information
This is my main index page.
Most recent blog posts
CSS Design: The Box Model
Chefs in the Kitchen
Git Blog


About FC
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim accusamus, deleniti rerum at veritatis facere vel laudantium illum esse magnam, libero aspernatur quas in, hic rem maxime sunt voluptas aliquid.
Latest Result
Match 4
1
:
1
Upcoming Matches
-
AFC ConsequatSao Paolo 30 May 23:00Magenta FC
-
Andrea FCSao Paolo 30 May 23:00Magenta United
-
Xavier UnitedSao Paolo 30 May 23:00Altair FC
-
Azkalz FCSao Paolo 30 May 23:00Juggernaut
-
Andrea FCSao Paolo 30 May 23:00Magenta United
-
Xavier UnitedSao Paolo 30 May 23:00Altair FC
Week 7
Latest Result
Match 4
2
:
1
Latest Result
Match 1
5
:
3
Upcoming Matches
-
Azkalz FCSao Paolo 30 May 23:00Juggernaut
-
Andrea FCSao Paolo 30 May 23:00Magenta United
-
Xavier UnitedSao Paolo 30 May 23:00Altair FC
-
AFC ConsequatSao Paolo 30 May 23:00Magenta FC
-
Andrea FCSao Paolo 30 May 23:00Magenta United
-
Xavier UnitedSao Paolo 30 May 23:00Altair FC
Week 7
Team 5 in Last 6 games
2014 training schedule (all times central)
Next| Day | Date | Practice Time/Notes | Morning Autographs |
|---|---|---|---|
| Friday | July 25 | 9:00 - 11:30 am | No Autographs |
| Saturday | July 26 | 9:00 - 11:30 am | No Autographs |
| Sunday | July 27 | 9:00 - 11:30 am | Offensive Line |
| Monday | July 28 | 9:00 - 11:30 am | No Autographs |
| Tuesday | July 29 | No practice - closed to the public | Defensive Backs |
Team 12 in Last 6 games
2014 training schedule (all times central)
Next| Day | Date | Practice Time/Notes | Morning Autographs |
|---|---|---|---|
| Friday | July 25 | 9:00 - 11:30 am | No Autographs |
| Saturday | July 26 | 9:00 - 11:30 am | No Autographs |
| Sunday | July 27 | 9:00 - 11:30 am | Offensive Line |
| Monday | July 28 | 9:00 - 11:30 am | No Autographs |
| Tuesday | July 29 | No practice - closed to the public | Defensive Backs |
Team 21 in Last 6 games
2014 training schedule (all times central)
Next| Day | Date | Practice Time/Notes | Morning Autographs |
|---|---|---|---|
| Friday | July 25 | 9:00 - 11:30 am | No Autographs |
| Saturday | July 26 | 9:00 - 11:30 am | No Autographs |
| Sunday | July 27 | 9:00 - 11:30 am | Offensive Line |
| Monday | July 28 | 9:00 - 11:30 am | No Autographs |
| Tuesday | July 29 | No practice - closed to the public | Defensive Backs |


Hi,
I am in the process of replacing my factory solar h2o controller with a custom version using an Arduino. Mostly just cos it is fun, but also because I want to measure the hot water cylinder temps and monitor when the pump is firing etc. Using EmonCMS + MQTT of course ;).
So I have got pretty much everything working, including replicating most of the functionality in my existing controller. But I wanted to run it by the experts on here and check if I have missed anything, since we are dealing with potentially very hot water and if this things goes wrong it cause serious issues/damage!
Here is the current code for my updatePump() routine which fires after I read the various temp sensors. Hopefully the variable names are obvious enough (e.g. temp_hwc_b/m/t => temp at HWC bottom/middle/top).
Any questions fire away, would appreciate any and all feedback!
void updatePump() { // ignore calculations if the temp sensors haven't been read yet if (temp_hwc_b == 0 || temp_col == 0) { Serial.println("Ignoring pump calculations until we have temps"); return; } // first we check if we are within the boundaries of any of our // protection/safety modes to prevent any damage to the system // emergency overheating if (temp_col > temp_col_emerg_off ) emerg_shutdown = 1; if (temp_col < temp_col_emerg_on) emerg_shutdown = 0; // collector cooling mode if (temp_col > temp_col_max) col_cooling = 1; if (temp_col < (temp_col_max - 2)) col_cooling = 0; // collector warming mode if (temp_col < temp_col_min) col_warming = 1; if (temp_col > (temp_col_min + 2)) col_warming = 0; // start with the current state int pump = pump_current; // calculate the difference between the collector and HWC bottom double diff = temp_col - temp_hwc_b; // if collector is X degrees above the HWC bottom then pump on if (diff > temp_diff_on) pump = PUMP_ON; // if collector is less than X degrees above HWC bottom then pump off if (diff < temp_diff_off) pump = PUMP_OFF; // check to stop overheating of cylinder if (temp_hwc_m > temp_hwc_max) pump = PUMP_OFF; // check if we are in the collector cooling or warming modes // and override our differential calculations above if (col_cooling || col_warming) pump = PUMP_ON; // emergency override so we don't overheat if (emerg_shutdown || temp_hwc_m > 95.0 || temp_hwc_t > 95.0) pump = PUMP_OFF; // only update if the pump state has changed if (pump != pump_current) { Serial.print("Switching pump -> "); Serial.println(pump == PUMP_ON ? "ON" : "OFF"); digitalWrite(PUMP_PIN, pump); pump_current = pump; } }
Re: Solar H2O Controller Logic
I should have mentioned that my code is based on the example at http://openenergymonitor.org/emon/applications/shw#software. I have taken this and extended it to add some additional checks and 'modes'.
Re: Solar H2O Controller Logic
Do not rely on your code for safety. You must have hard-wired over-temperature protection in there somewhere as well. There is no way that you can guarantee that the output controlling the pump will fail to OFF. (There is no guarantee that a pair of thermostat contacts won't weld either, but I'd rather put my money on the thermostat than on a relay on the end of a microcontroller.)
So the first problem I see - if you haven't read the sensors or they fail to zero, the pump carries on doing whatever it was doing. 'emerg_shutdown' doesn't get a look-in as the function has returned. That's an obvious failure in the logic.
I'm also confused by the 'PUMP_OFF' and 'PUMP_ON' being repeated. Only the last true condition will set the pump state. Do you really want the later conditions to override the earlier ones? If you do, that's OK, but as you have it, collector heating/cooling will override the maximum set temperature 'PUMP_OFF'. I obviously don't know your system, nor what it can and can't do safely, but that looks wrong to me.
Re: Solar H2O Controller Logic
Thanks Robert - you have a valid point re. the hard-wired over-temp protection. The currently installed system doesn't have anything like this and I know of half a doz systems using the same controller - not saying it is ok, just that this controller has been approved by the regulators here in NZ and is in operation in a lot of places.
I do have a watchdog timer on my Arduino so it will restart if it ever locks up but I think moving the emergency shutoff logic above the temp validation is a very smart idea - I will definitely do that. At least then if my temp sensors fail then I will know the pump is off (well at least that the output pin is high!).
The idea with the PUMP_ON/OFF being repeated is that you have higher priority rules further down the list. So initially we just do the standard temp differential checks and make a decision as to whether to switch the pump on/off. Then after that is done we have a look at our special protection modes and they are allowed to override the basic logic. Finally the emergency checks can override everything.
I have a user manual here for the existing controller which explains some of this in more detail but basically the idea is you have a max HWC temp (in my case 85C). The controller will stop circulating heated water once the HWC reaches this. However, if the collector gets above 110C (temp_col_max) we start circulating water from the HWC to cool the collector down - this only runs until the collector cools down a couple of degrees. Similar logic for the lower temps - to prevent freezing. This can obviously increase the temp of the HWC above our configured max, which is why there is the hardcoded shutoff at 95C.
Here are the current values (which are the default values that come shipped on my existing controller) for reference;
Appreciate your feedback. Would be interested to hear you suggestions for a hard-wired thermostat shutoff - would this be a secondary temp probe in the cylinder which is wired in series with the live feed to the pump - if the thermostat is tripped it would shutoff the pump circuit altogether?
Cheers,
Ben
Re: Solar H2O Controller Logic
"a secondary temp probe in the cylinder which is wired in series with the live feed to the pump - if the thermostat is tripped it would shutoff the pump circuit altogether."
Indeed. A common-and-garden thermostat is more or less what I had in mind. It may well be that your installed and approved system has got a second protection mechanism in place that you don't know about, that has allowed its approval. Or maybe your regulators aren't quite as cynical as I am.
But you could have a problem with cooling the collector if the system has already tripped on the 'stat - I guess there's less danger to life and property in having a boiling collector than a boiling tank.
And I've no argument with the priority mechanism, I was simply questioning whether you indeed had what you intended.
Re: Solar H2O Controller Logic
I don't think there is any other protection system - the controller has a wire to the pump, and wires to the various temperature probes. So if those probes failed there is nothing else in the system to override the pump circuit - other than it auto-shutting down like we have discussed if the temp readings fail.
The 'stat would be on the HWC temp since that is the only thing we care about getting too hot, so the collector cooling should still be ok. If the HWC was so hot that it tripped the 'stat then I don't think we really want to be circulating that water to cool down the collector...
Thanks again for your feedback. Appreciate you taking the time to have a look over it all.
Re: Solar H2O Controller Logic
Hi,
I went through this a while back. The easiest way to do this is by getting a 12v DC Solar hot water pump on eBay, a 5-10 watt solar panel and an optional 50 deg C NO thermal switch and just wire it up. Switch on solar collector output pipe. Sun comes up, solar panel heats up, output get to 50 deg, closes switch, output from solar panel connected to pump and and away it goes. Water cools, pump off and cycle continues until hot water remains at 50 deg and above and pump continues to run until night time.
easy peasy
I also have a device that diverts hot water to prevent steaming called the Solar Steam Stopper.
Re: Solar H2O Controller Logic
Sumnerboy, my Resol controller follows pretty much exactly the same algorithm as yours, but with slightly different set-points (which are user-tweakable). I'm pretty sure mine lacks the "collector cooling mode" that you describe. Mine is an open loop system, which means it's actually the hotwater that gets sent up to the collector, and there's a pressure relief valve up there to let it boil/vent if it ever needs to. I'm guessing yours might be closed loop, and they're worried about loosing coolant if the collector gets too hot?
I was interested in monitoring it but not replacing it,so I piggy-back my monitor on top of their controller. I passively observe the temp sensor readings whenever their controller pulses them. I've got a dedicated CT on that GPO, so can easily detect when the circulation pump is running. It's about 22W (real) from memory but close to 70VA (apparent) so pretty easy to detect. And I have another CT on the 3600W electric boost element. All that lets me create the web display shown below. The pump icon turns green when it's running, dark otherwise, and the boost element turns red when it's energised. I even make an educated guess (based on some very rough measurements) at the flow rate, which lets me include a power readout.
Does yours use pt1000 temperature probes? How do you plan driving them? Mine doesn't energise them permanently, but rather pulses them every few seconds. I read somewhere that's to avoid self-heating effects.
Meanwhile, if this article is to be believed: http://reneweconomy.com.au/2014/solar-hot-water-solar-pv-study-says-pv-cheapest-way-go-34519 the crossover point has been reached (at least here in Aus). When total cost of ownership is considered, it's now cheaper to just add some more PV panels and heat your water with their output. The maths varies a lot depending on tariffs, for example it doesn't apply to me because of my generous feed-in tariff.
Re: Solar H2O Controller Logic
Very nice dBC! Are you using the VBus adapter to get your various readings from the controller? I just watched a short YouTube clip of someone setting up a Resol and the parameters and settings look remarkably similar to my controller (http://www.sokdoo.com/SR868C8.pdf). I wonder if they are based off the same firmware?
Unfortunately there is no way (that I know of) to piggy back off my controller however. More's the pity!
Mine uses a PT1000 probe in the collector and NTC10K probes for the HWC temp measurements. I am going to replace the NTC10K probes with DS18B20s as it is nice and easy to use these on an Arduino, but I can't change the probe in the collector very easily so I decided to leave it there and have bought a MAX31865 breakout board from PlayingWithFusion (http://playingwithfusion.com/productview.php?pdid=26) which handles reading the temperature values via the SPI bus.
Interesting point about self-heating - I will do some investigation into that.
My system is the same as yours, i.e. open loop. It will vent on the roof if required but the collector cooling is a function in the existing controller so I was keen to replicate.
The one thing the controller does is PWM the pump signal - which I am not going to attempt in my controller. I am a little concerned at this difference but time will tell if it makes any difference. My current controller was setup with a min pump % = 90% so I don't think I will be too different if I just run it at 100% (i.e. fully on) instead.
Very nice display you have setup there - pretty much exactly what I want to achieve, but in EmonCMS using MQTT. I can then integrate with openHAB and do things like stop HWC boosting if we are away on holiday, and warn if the HWC is a bit cool in the evenings for example.
Thanks for your feedback!
Re: Solar H2O Controller Logic
Are you using the VBus adapter to get your various readings from the controller?
It was quite a few years ago now, but I'm pretty sure I determined mine didn't have the VBus module. I guess when integrators (Conergy in my case) request these bits from the suppliers, there are a bunch of tick-boxes they can de-select to keep the costs down.
Unfortunately there is no way (that I know of) to piggy back off my controller however. More's the pity!
It may be a lot easier than you think. Provided you have access to the screw terminals for the temperature probes, just put a scope, or even a voltmeter on them. That's where I started, then worked out what it was doing from there. Every 2 seconds it energises one of the pt1000s with a brief pulse. I could see that pulse with a digital voltmeter so it's all very slow. My controller includes an LCD display displaying the two temperatures, so it was very easy to calibrate the voltage to their temperature display. Then I wired those two signals to two analog inputs and a few lines of code later, I had the readings in AtoD units... again easy to calibrate against their temperature display. I think I had to use an isolated (i.e. transformer based) DC supply to the Arduino to avoid earth loop issues, and I also used an external Vref (~ 2V) to give me better resolution.
I just poked around in the archives, and came across my calibration spreadsheet:
Re: Solar H2O Controller Logic
I might have to give that a go - thanks for the tip! If I can keep the existing controller I would be a lot happier I think - not that I don't think my version is much different - it is just nice to have standalone controllers for these mission critical systems.
Yet another thing to add to my project list...
Cheers,
Ben
Re: Solar H2O Controller Logic
dBC - would you care to share your Arduino sketch? To give me a starting point...Cheers!
Re: Solar H2O Controller Logic
Sure, but keep in mind it's not exactly in "shareable" state. It's quite bespoke to my system and it's a good 3 years old. Reading it again now, I'd probably do a few things differently... but it's been screwed to the wall under the house and working fine for 3 years, so I've not messed with it. To aid calibration with the Resol readout, I briefly attached a little I2C LCD display I had lying about, but that's not in the final version, which is why it's all been #ifdef'd away.
Oh, and TC and TS are Resol names for TempCollector and TempStorage. My rig only has 2 temp sensors: TC on the output of the collector, and TS at the bottom of the tank (65.5C and 53.9C in the display above). The raw A/D readings are sent over the virtualwire RF link, and the conversion/calibration is done externally.
This box/sketch only provides the two temperature readings. CT sensing of whether or not the circulation pump and boost element are running is done by my energy monitor.
You really need to start by looking at the signal on your temp sensor screw terminals to see how much of it is relevant to your setup. All those edge triggers, waste counts etc. were all hand crafted for my rig.
Re: Solar H2O Controller Logic
Sweet - appreciate it - I will have a play this weekend.
Re: Solar H2O Controller Logic
Thought I would follow up with this little project. I ended up canning the idea of replacing the Solar H2O controller, I got it working ok in my test bed, but when I deployed I was getting bad sensor readings quite regularly, and whenever the pump was activated I was seeing sensor errors - I am not sure what was wrong but after stuffing around and letting my collector temp get up to over 180 degrees (since the pump wasn't being run properly while I installed/tested) I decided to leave the existing factory-fitted controller in place.
I followed dBCs advice and went about designing an Arduino sketch to monitor the existing NTC 10K thermistors that are measuring the HWC temps (bottom/middle/top). After all, all I really wanted to do is track the HWC temps.
Turns out this wasn't as hard as I feared. I had never done analog reads using an external voltage reference so it was a great learning experience. Basically the NTC thermistors are wired up in a voltage divider within the solar controller. Then 5V is applied (actually about 4.91V) and a reading taken at the divider mid-point - all pretty standard stuff.
So my Arduino connects a wire from the top of one of the thermistors (VCC) and connects to AREF. I also connect a common GND between the Arduino and the solar controller. Then I just connect 3 of the analog pins to the other side of the three thermistors.
With the correct calculations and ADC conversions, I end up with a very accurate temperature reading - which is very close to what the solar controller is reporting on its LCD display.
Chuck in a bit of MQTT publishing and I now have all three of my cylinder probes reporting temps to both EmonCMS and openHAB. openHAB can now intelligently decide whether to enable my PV Router depending on the HWC temperature.
Very happy with the end result although it has taken me a while to get to this point! Thanks to all those who offered help and suggestions on here!
Re: Solar H2O Controller Logic
I finally got around to putting a scope on the two pt1000 screw terminals on my Resol controller, so figured I'd document it here for anyone else doing something similar. At the time I wrote that sketch above I only had a voltmeter and readings from the Arduino to go on.
Looks like it probes both temp sensors every 1.564 seconds, first TC (red trace) and then TS (yellow trace). It reads each one for 392 msecs (possibly doing a bit of oversampling there). It takes about 1 msec for the voltage to settle when it switches from TC to TS. At teh time of taking these pics, the two sensors were pretty close to the same temperature.
Re: Solar H2O Controller Logic
I have a user with an emon Pi installed and running and reporting his two solar panel outputs to our database. He also has a solar thermal installation with a Resol DeltaSol CS2 controller and we'd like to pick up the temperature and flow values from that system as well. Looks like some of you guys may have already done exactly that, so I'm hoping you might be able to offer some help.
I'm fairly good at building electronics but can't design stuff so I'm hoping some can post a circuit diagram. From Googling I see Resol company do actually make and sell both VBus/USB and VBus/Ethernet adaptors but if there's a simpler/more direct approach that will need just a little electronics, so we avoid having to get another Pi, that would be great.
Chris.
The greenDATA Project
http://projects.kmi.open.ac.uk/greendata/
Re: Solar H2O Controller Logic
I think there are a lot of different Resol controller models, so you probably can't assume they're all the same. I'd start by putting a voltmeter on the pt1000 screw terminals and see if you see the same voltages. If they are, there is no schematic really. I just ran those two signals to two ADC inputs on a 5V Arduino. To improve resolution, I built a simple ~2V Vref out of a 680/470 resistor divider as shown below. If you're going to be using a 3.3V system to monitor yours, you may not need to.
One bug in my current "design" is that if the power to the Arduino goes off, the Resol reports a sensor fault. Presumably the ADC inputs of an unpowered Arduino put quite a load on the sensors as they effectively try to power up the Arduino via the internal protection diodes. A series resistor on those ADC inputs might solve that, but I've not experimented with that (still well down my to-do list). As mentioned above, I think I had to use an isolated (i.e. transformer based) DC supply to the Arduino to avoid earth loop issues. It's all a bit of a hack, and may well void your Resol warranty, but mine has been monitoring happily for years.
[EDIT] hmmm... I could have sworn I was replying to a request for a schematic, but that request seems to have disappeared now. In any case, I'll leave this reply here in case it helps anyone else.
Re: Solar H2O Controller Logic
Regarding the voltage differences I did just find this on the Resol VBus group on Google Groups:
https://groups.google.com/forum/#!topic/resol-vbus/3CjZffK53ig
Sorry - I edited my post so I have to assume its being re-moderated.
Re: Solar H2O Controller Logic
dBC: Both Chris's posts of today were stuck in the moderation queue, so you shouldn't have seen them at all until 30 s ago.
Re: Solar H2O Controller Logic
Another option is the Resol VBus/LAN adaptor which costs around £100. This would save making any custom electronics but would need code added to the emon Pi to collect the data from it, cache it and send it. This is the UK authorised reseller:
http://www.seconsolar.com/
Re: Solar H2O Controller Logic
Actually, my Resol controller doesn't have the Vbus option. The solution described above just monitors the analog voltages from the pt1000 sensors as the Resol controller probes them every 2 seconds.
Re: Solar H2O Controller Logic
dBc/Chris
Here in Ireland the Resol Controllers are used and rebranded by a company called Joule as part of their Solar panel kits. I have a Deltasol BS/2 HS. It can be connected to a data logger and some software to monitor everything. The Resol controller uses a proprietary protocol but some smart people out in the internet have cracked this and have also designed the interface to the Raspberry Pi.
You may be interested in this link: https://www.domoticz.com/forum/viewtopic.php?t=8370
I was intending to have go at following these as a practical exercise to learn more about the raspberry pi and feed the output to emoncms but I am really very new at the raspberry pi thing so don't hold your breath!! If this could be "commoditised" I think there would be a lot of interest in it.
In the mean time, without knowing what your set up is, I have used the DS18b20 probes as replacements for the plug in thermometers in my solar pumping station to monitor the heat of the solar fluid going to/from my panels. You can take look at my results here: https://emoncms.org/dashboard/view?id=32140
Its not rocket science but it does save me getting up into the loft!! and its been of interest to my plumber who installed my system as a marketing tool to some of his other customers.
PS. The big slope recently was caused by me accidently turning off my wifi router when I went on holiday.
PPS The pump monitor I now know is not technically correct and I need to revisit how I do this.
Hope this helps
Re: Solar H2O Controller Logic
This topic is very timely as I have just had Viridan Solar Thermal in-roof panels fitted and providing heat to a thermal store. The pump centre is a Resol unit and I have just added a KM1 communication unit to access the data over VBus network. My intent is to monitor my system with a view to better heating optimisation


Protocols
The following protocols are available globally.
-
See moreRSDSurveyNavigationStep
evaluatesRSDSurveyRule
objects that are associated with each input field to determine if the step navigation should skip to another step.Declaration
Swift
public protocol RSDSurveyNavigationStep : RSDNavigationRule
-
See moreRSDSurveyInputField
extends theRSDInputField
protocol to also support an array ofRSDSurveyRule
objects. These rules are evaluated on theRSDAnswerResult
given for this input field and if they evaluate totrue
then they are used to return the next identifier.Declaration
Swift
public protocol RSDSurveyInputField : RSDInputField
-
Delegate for the data source.
See moreDeclaration
Swift
public protocol RSDFormStepDataSourceDelegate: class, NSObjectProtocol
-
RSDFormStepDataSource
: the internal model for a table view controller. It provides the UITableViewDataSource, manages and stores answers provided thru user input, and provides an RSDResult with those answers upon request.It also provides several convenience methods for saving or selecting answers, checking if all answers are valid, and retrieving specific model objects that may be needed by the ViewController.
The tableView data source is comprised of 3 objects:
RSDTableSection
: An object representing a section in the tableView. It has one or more RSDTableItemGroup objects.RSDTableItemGroup
: An object representing a specific question supplied byRSDStep
as an input field. Upon init(), the ItemGroup will create one or moreRSDTableItem
objects representing the answer options for theRSDInputField
. The ItemGroup is responsible for storing/computing the answers for itsRSDInputField
.RSDTableItem
: An object representing a specific answer option from the ItemGroup (RSDInputField), such as a Yes or No choice in a boolean question or a string or number that’s entered thru a text field. There will be one TableItem for each indexPath in the tableView.
Declaration
Swift
public protocol RSDFormStepDataSource : class
-
See moreRSDTaskControllerDelegate
is responsible for processing the results of the task, providing some input into how the controller behaves, and providing additional content as needed. It’s primary purpose is to handle processing the results of running the task.Declaration
Swift
public protocol RSDTaskControllerDelegate : class, NSObjectProtocol
-
RSDTaskController
handles default implementations for running a task.To start a task, create an instance of a view controller that conforms to this protocol and set either the
See moretopLevelTask
or thetopLevelTaskInfo
.Declaration
Swift
public protocol RSDTaskController : class, NSObjectProtocol
-
See moreRSDSchemaInfo
is a lightweight interface for schema information used to upload the results of a task. The schema info is intended to allow for reproducing a previously presented survey where the survey may have changed and requires revisioning to know what version of the survey task was run.Declaration
Swift
public protocol RSDSchemaInfo
-
See moreRSDEmbeddedIconVendor
is a convenience protocol for fetching an codable image using an optionalRSDImageWrapper
. This protocol implements an extension method to fetch the icon.Declaration
Swift
public protocol RSDEmbeddedIconVendor
-
The
See moreRSDImageWrapperDelegate
is a singleton delegate that can be used to customize the rules for fetching an image using theRSDImageWrapper
. If defined and attached to theRSDImageWrapper
using the static propertysharedDelegate
then the image wrapper will ask the delegate for the appropriate image.Declaration
Swift
public protocol RSDImageWrapperDelegate
-
See moreRSDPickerDataSource
includes information that can be used to build a picker UI element.Declaration
Swift
public protocol RSDPickerDataSource
-
A data source for selecting a date.
See moreDeclaration
Swift
public protocol RSDDatePickerDataSource : RSDPickerDataSource
-
A picker data source for selecting choices.
See moreDeclaration
Swift
public protocol RSDChoicePickerDataSource : RSDPickerDataSource
-
A picker data source for picking a number.
See moreDeclaration
Swift
public protocol RSDNumberPickerDataSource : RSDPickerDataSource
-
Undocumented
See moreDeclaration
Swift
public protocol RSDNumberFormatterProtocol
-
See moreRSDMultipleComponentOptions
is a data source protocol that can be used to set up a picker.Declaration
Swift
public protocol RSDMultipleComponentChoiceOptions : RSDChoicePickerDataSource
-
See moreRSDMultipleComponentOptions
is a data source protocol that can be used to set up a picker.Declaration
Swift
public protocol RSDMultipleComponentOptions : RSDMultipleComponentChoiceOptions
-
See moreRSDChoiceOptions
is a data source protocol that can be used to set up a picker or list of choices.Declaration
Swift
public protocol RSDChoiceOptions : RSDChoicePickerDataSource
-
See moreRSDTextFieldOptions
defines the options for a text field.Declaration
Swift
public protocol RSDTextFieldOptions
-
Undocumented
See moreDeclaration
Swift
public protocol RSDTextValidator
-
Undocumented
See moreDeclaration
Swift
public protocol RSDRegExMatchValidator : RSDTextValidator
-
Undocumented
See moreDeclaration
Swift
public protocol RSDCodableRegExMatchValidator : RSDRegExMatchValidator
-
RSDSectionStepTransformer
is a lightweight protocol for vending the steps in a section. This object is used to allow accessing anRSDSectionStep
for use in multiple tasks or multiple times within a task.For example, for a task where the user is going to run for 12 minutes, the researchers may wish to record the user’s heart rate both before and after the run. The heart rate can be defined in a seperate file or model object and the transformer is used as a placeholder that can fetch and replace itself with a section of steps that are used to capture the user’s heartrate.
See moreDeclaration
Swift
public protocol RSDSectionStepTransformer
-
See moreRSDSectionStepResourceTransformer
is an implementation of aRSDSectionStepTransformer
that uses aRSDResourceTransformer
to support transforming the section from one resource for inclusion in another task defined using a different resource.Declaration
Swift
public protocol RSDSectionStepResourceTransformer : RSDSectionStepTransformer, RSDResourceTransformer
-
RSDStringLiteralOptionSet
extendsOptionSet
to allow mapping any OptionSet that uses aBinaryInteger
as itsRawValue
to a set of string keys.See moreSeealso
RSDActiveUICommand
for example usage.Declaration
Swift
public protocol RSDStringLiteralOptionSet : OptionSet, Codable
-
See moreRSDTaskTransformer
The task transformer is a lightweight protocol for vending a task. This can be used by anRSDTaskInfoStep
to fetch a task or depending upon the design of the application, it could be used to fetch a task that is loaded from a table or collection view before presenting the task.Declaration
Swift
public protocol RSDTaskTransformer
-
See moreRSDTaskResourceTransformer
is an implementation of aRSDTaskTransformer
that uses aRSDResourceTransformer
to support transforming a resource either using an online URL or an embedded file.Declaration
Swift
public protocol RSDTaskResourceTransformer : RSDTaskTransformer, RSDResourceTransformer
-
See moreRSDPermissionType
is a generic configuration object with information about a given permission. The permission type can be used by the app to handle gracefully requesting authorization from the user for access to sensors and hardware required by the app.Declaration
Swift
public protocol RSDPermissionType
-
RSDAsyncActionConfiguration
defines general configuration for an asynchronous background action that should be run in the background. Depending upon the parameters and how the action is set up, this could be something that is run continuously or else is paused or reset based on a timeout interval.The configuration is intended to be a serializable object and does not call services, record data, or anything else. It does include a step identifier that can be used to let the
See moreRSDTaskController
know when to trigger the async action.Declaration
Swift
public protocol RSDAsyncActionConfiguration
-
See moreRSDAsyncActionControllerVendor
is an extension of the configuration protocol for configurations that know how to vend a new controller.Declaration
Swift
public protocol RSDAsyncActionControllerVendor : RSDAsyncActionConfiguration
-
See moreRSDRecorderConfiguration
is used to configure a recorder. For example, recording accelerometer data or video.Declaration
Swift
public protocol RSDRecorderConfiguration : RSDAsyncActionConfiguration
-
RSDJSONRecorderConfigureation
is used to configure a recorder to record JSON samples.See moreSeealso
RSDSampleRecorder
Declaration
Swift
public protocol RSDJSONRecorderConfiguration : RSDRecorderConfiguration
-
RSDRequestConfiguration
is used to start an asynchronous service such as a url request or fetching from core data.See moreNote
This configuration type is stubbed out for future work. This is not currently implemented in eitherRSDTaskController
orRSDTaskViewController
. (syoung 11/15/2017)Declaration
Swift
public protocol RSDRequestConfiguration : RSDAsyncActionConfiguration
-
See moreRSDAsyncActionControllerDelegate
is the delegate protocol forRSDAsyncActionController
.Declaration
Swift
public protocol RSDAsyncActionControllerDelegate : class
-
A controller for an async action configuration.
See moreDeclaration
Swift
public protocol RSDAsyncActionController : class, NSObjectProtocol
-
See moreRSDEmbeddedResourceUIAction
is a convenience protocol for returning an image using an encodable strings for the name and bundle identifier.Declaration
Swift
public protocol RSDEmbeddedResourceUIAction: RSDUIAction, RSDDecodableBundleInfo
-
Undocumented
Declaration
Swift
public protocol RSDArrayExtension
-
See moreRSDTaskInfoStep
is a reference interface for information about the task. This includes information that can be displayed in a table or collection view before starting the task as well as information that is displayed while the task is being fetched in the case where the task is not fetched using an embedded resource or via a hardcoded task.Declaration
Swift
public protocol RSDTaskInfoStep : RSDStep
-
See moreRSDStepController
handles default implementations for running a step in a task.Declaration
Swift
public protocol RSDStepController : class, NSObjectProtocol
-
RSDRange
defines range constraints that are appropriate for a given data type.Declaration
Swift
public protocol RSDRange
-
See moreRSDRangeWithFormatter
is an optional extension of the range that can be used to extend the range to include a formatter appropriate to the UI. For example, this could be used to describe a number range that displays currency.Declaration
Swift
public protocol RSDRangeWithFormatter : RSDRange
-
See moreRSDNumberRange
extends the properties of anRSDInputField
for adecimal
orinteger
data type.Declaration
Swift
public protocol RSDNumberRange : RSDRange
-
Define the navigation rule as a protocol to allow for protocol-oriented extension (multiple inheritance). Currently defined usage is to allow the
See moreRSDConditionalStepNavigator
to check if a step has a navigation rule and apply as necessary.Declaration
Swift
public protocol RSDNavigationRule : RSDStep
-
A conditional rule is appended to the navigable task to check a secondary source for whether or not the step should be displayed.
See moreNote
ResearchSuite
does not currently implement any conditional rule objects. The conditional rule is included here for future implementation of data tracking across runs of a task. (syoung 10/03/2017)Declaration
Swift
public protocol RSDConditionalRule
-
Implementation of a step navigator that will apply conditions and navigation based on the steps, navigation rules, and conditional rules associated with this navigator.
See moreDeclaration
Swift
public protocol RSDConditionalStepNavigator : RSDStepNavigator, RSDStepValidator
-
See moreRSDUSMeasurementPickerDataSource
is a generic protocol for converting US Customary units (multiple component) to metric units.Declaration
Swift
public protocol RSDUSMeasurementPickerDataSource : RSDMultipleComponentChoiceOptions
-
The
See moreRSDUIAction
protocol can be used to customize the title and image displayed for a given action of the UI.Declaration
Swift
public protocol RSDUIAction : Codable
-
See moreRSDWebViewUIAction
implements an extension of the base protocol where the action includes a pointer to a url that can display in a webview. The url can either be fully qualified or optionally point to an embedded resource. The resource bundle is assumed to be the main bundle if thebundleIdentifier
property isnil
.Declaration
Swift
public protocol RSDWebViewUIAction : RSDUIAction, RSDResourceTransformer
-
RSDSkipToUIAction
implements an extension of the base protocol where the action includes an identifier for a step to skip to if this action is called. This is used by theRSDConditionalStepNavigator
to navigate based on anil
result.See moreSeealso
RSDSurveyNavigationStep
Declaration
Swift
public protocol RSDSkipToUIAction : RSDUIAction
-
See moreRSDUIActionHandler
implements the custom actions of the step.Declaration
Swift
public protocol RSDUIActionHandler
-
RSDResult
is the base implementation for a result associated with a task, step, or asynchronous action.When running a task, there will be a result of some variety used to mark each step in the task. This is the base protocol. All the
See moreRSDResult
objects are required to conform to theCodable
protocol to allow the app to store and upload results in a standardized way.Declaration
Swift
public protocol RSDResult : Codable
-
See moreRSDTaskResult
is a result associated with a task. This object includes a step history, task run UUID, schema identifier, and asynchronous results.Declaration
Swift
public protocol RSDTaskResult : RSDResult, RSDAnswerResultFinder
-
See moreRSDCollectionResult
is used include multiple results associated with a single step or async action that may have more that one result.Declaration
Swift
public protocol RSDCollectionResult : RSDResult, RSDAnswerResultFinder
-
RSDAnswerResultFinder
is a convenience protocol used to retrieve an answer result. It is used in survey navigation to find the result for a given input field.See moreSeealso
RSDSurveyNavigationStep
Declaration
Swift
public protocol RSDAnswerResultFinder
-
See moreRSDAnswerResult
is a result that can be described using a single value.Declaration
Swift
public protocol RSDAnswerResult : RSDResult, RSDAnswerResultFinder
-
See moreRSDTask
is the interface for running a task. It includes information about how to calculate progress, validation, and the order of display for the steps.Declaration
Swift
public protocol RSDTask : RSDUIActionHandler
-
See moreRSDTaskDataSource
is a data source that can be used by the factory to get info that should be included with a task result or used to display subgroups of a task.Declaration
Swift
public protocol RSDTaskDataSource
-
See moreJSONDecoder
andPropertyListDecoder
do not share a common protocol so extend them to be able to create the appropriate decoder and set the userInfo keys as needed.Declaration
Swift
public protocol RSDFactoryDecoder
-
See moreJSONEncoder
andPropertyListEncoder
do not share a common protocol so extend them to be able to create the appropriate decoder and set the userInfo keys as needed.Declaration
Swift
public protocol RSDFactoryEncoder
-
See moreRSDTaskGroup
defines a subgrouping of tasks. This is used in UI presentations where the researchers wish to tie a group of activities and surveys together but allow the user to perform them non-sequentially or with a break between the activities.Declaration
Swift
public protocol RSDTaskGroup
-
Light-weight protocol for handling generic equality without requiring a class or struct to implement all of the
See moreNSObjectProtocol
.Declaration
Swift
public protocol RSDObjectProtocol
-
The
See moreRSDSampleRecord
defines the properties that are included with all JSON logging samples. By defining a protocol, the logger can include markers for step transitions and the records are defined asCodable
but the actualCodingKey
implementation can be changed to match the requirements of the research study.Declaration
Swift
public protocol RSDSampleRecord : Codable
-
See moreRSDSurveyRule
defines an evaluation rule and returns a step identifier if appropriate.Declaration
Swift
public protocol RSDSurveyRule
-
See moreRSDComparableSurveyRule
is a survey rule that matches an expected result to the answer and vends a skip identifier if the match is evaluated totrue
.Declaration
Swift
public protocol RSDComparableSurveyRule : RSDSurveyRule, RSDComparable
-
See moreRSDComparable
can be used to compare a stored result to a matching value.Declaration
Swift
public protocol RSDComparable
-
See moreRSDDecimalComparable
can be used to compare a stored result to a matching value where the values are decimals.Declaration
Swift
public protocol RSDDecimalComparable : RSDComparable
-
RSDInputField
is used to describe a form input and includes the data type and a possible hint to how the UI should be displayed. The ResearchSuite framework usesRSDFormUIStep
to represent questions to ask the user. Each question must have at least one associated input field. An input field is validated when its owning step is validated.See moreSeealso
RSDFormUIStep
Declaration
Swift
public protocol RSDInputField
-
See moreRSDChoice
is used to describe a choice item for use with a multiple choice or multiple component input field.Declaration
Swift
public protocol RSDChoice
-
See moreRSDChoiceInputField
extends the properties ofRSDInputField
with information required to create a multiple or single choice question.Declaration
Swift
public protocol RSDChoiceInputField : RSDInputField, RSDChoiceOptions
-
RSDMultipleComponentInputField
extends the properties ofRSDInputField
with information required to create a multiple component input field.Declaration
Swift
public protocol RSDMultipleComponentInputField : RSDInputField, RSDMultipleComponentOptions
-
RSDStep
is the base protocol for the steps that can compose a task for presentation using a controller appropriate to the device and application. EachRSDStep
object represents one logical piece of data entry, information, or activity in a larger task.Implementations included in this SDK include:
RSDGenericStep
is used byRSDFactory
to create a step that does not include a recognized subtype.RSDSectionStep
is used to define a logical subgroup of steps.RSDUIStep
is used to define a display step.RSDTaskInfoStep
is used to combine tasks into a single flow. For example, if the researcher wishes to ask for survey responses before an activity.
A step can be a question, an active test, or a simple instruction. An
See moreRSDStep
subclass is usually paired with anRSDStepController
that controls the actions of the step.Declaration
Swift
public protocol RSDStep
-
See moreRSDGenericStep
is a step with key/value pairs decoded from a dictionary. This is the default step returned byRSDFactory
for an unrecoginized type.Declaration
Swift
public protocol RSDGenericStep : RSDStep
-
See moreRSDSectionStep
is used to define a logical subgrouping of steps such as a section in a longer survey or an active step that includes an instruction step, countdown step, and activity step.Declaration
Swift
public protocol RSDSectionStep: RSDStep, RSDTask, RSDConditionalStepNavigator
-
See moreRSDUIStep
is used to define a singledisplay unit
. Depending upon the available real-estate, more than one ui step may be displayed at a time. For example, on an iPad, you may choose to group a set of questions using aRSDSectionStep
.Declaration
Swift
public protocol RSDUIStep: RSDStep, RSDUIActionHandler
-
RSDMutableStep
is a step that supports copying information from a dictionary into this step. Because this step can be mutated, it must be implemented as a class.See moreSeealso
RSDUIStepObject
for an example implementation.Declaration
Swift
public protocol RSDMutableStep: class, RSDStep
-
See moreRSDActiveUIStep
extends theRSDUIStep
to include a duration and commands. This is used for the case where anRSDUIStep
has an action such asstart walking
orstop walking
; the step may also implement theRSDActiveUIStep
protocol to allow for spoken instruction.Declaration
Swift
public protocol RSDActiveUIStep: RSDUIStep
-
See moreRSDResourceTransformer
is a protocol for getting either embedded resources or online resources.Declaration
Swift
public protocol RSDResourceTransformer: RSDDecodableBundleInfo
-
See moreRSDStepNavigator
is the model object used by theRSDTaskController
to determine the order of presentation of the steps in a task.Declaration
Swift
public protocol RSDStepNavigator
-
See moreRSDJSONNumber
implements converting a Swift number to an Objective-CNSNumber
.Declaration
Swift
public protocol RSDJSONNumber : Codable
-
Undocumented
Declaration
Swift
public protocol RSDDictionaryExtension
-
See moreRSDUIThemeElement
is used to tell the application UI view controllers how to style a given step.Declaration
Swift
public protocol RSDUIThemeElement
-
See moreRSDDecodableBundleInfo
is a convenience protocol for getting a bundle from a bundle identifier.Declaration
Swift
public protocol RSDDecodableBundleInfo
-
See moreRSDViewThemeElement
tells the UI where to find the view controller to use when instantiating theRSDStepController
.Declaration
Swift
public protocol RSDViewThemeElement : RSDUIThemeElement
-
See moreRSDColorThemeElement
tells the UI what the background color and foreground color are for a given view as well as whether or not the foreground elements should uselight style
.Declaration
Swift
public protocol RSDColorThemeElement : RSDUIThemeElement
-
See moreRSDImageThemeElement
extends the UI step to include an image.Declaration
Swift
public protocol RSDImageThemeElement : RSDUIThemeElement
-
See moreRSDFetchableImageThemeElement
defines an image that can be fetched asynchronously.Declaration
Swift
public protocol RSDFetchableImageThemeElement : RSDImageThemeElement
-
See moreRSDAnimatedImageThemeElement
defines a series of images that can be animated.Declaration
Swift
public protocol RSDAnimatedImageThemeElement : RSDImageThemeElement
-
See moreRSDStepValidator
is a convenience protocol for validating the steps in a list as unique.Declaration
Swift
public protocol RSDStepValidator
-
See moreRSDDateCoder
is used to handle specifying date encoding/decoding. If the calendar components supported by this formatter only include a subset of all the components then only those components should be displayed in the UI.Declaration
Swift
public protocol RSDDateCoder : Codable
-
Protocol for converting an object to a dictionary representation. This is included for reverse-compatiblility to older implementations that are not Swift 4
See moreCodable
and instead use a dictionary representation.Declaration
Swift
public protocol RSDDictionaryRepresentable
-
Protocol for converting objects to JSON serializable objects
See moreDeclaration
Swift
public protocol RSDJSONValue


Simple scrollspy without jQuery, no dependencies and lightweight. Only 1.94Kb.
This is a demo
You can install by npm or download inject simple-scrollspy.js file into your HTML code:
npm install simple-scrollspy
<script src="/path/to/dist/simple-scrollspy.js"></script>
import scrollSpy from 'simple-scrollspy' scrollSpy('#menu-list', { offset: 100, menuActiveTarget: '.menu__item > a', sectionClass: 'body section.scrollspy', activeClass: 'active' })
<script src="/path/to/dist/simple-scrollspy.js"></script> <script> window.onload = function () { scrollSpy('#menu-list', { offset: 100, menuActiveTarget: '.menu__item > a', sectionClass: 'body section.scrollspy', activeClass: 'active' }) } </script>
| Name | Type | Default | Description |
|---|---|---|---|
| offset | Number | 0 | Offset number |
| menuActiveTarget | String | li > a | Element will be added active class |
| sectionClass | String | .scrollspy | Query selector to your sections |
| activeClass | String | active | Active class name |
MIT License
Copyright (c) 2018 Kim Nguyen Huu
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Nguyen Huu Kim <kimnguyen.ict@gmail.com>


- Dynamic Beaconing
- Use dynamic beaconing to describe your site's traffic in more detail.
- Contextual Recommendations
- Use the
/related
API endpoint to pull recommendations based on a particular article.
- Personalized Recommendations
- Use the
/related
and /profile
API endpoints to pull recommendations based on a trained user profile.
- Analytics
- Use the
/analytics
API endpoint to pull top performing posts, authors, sections, topics or tags.
- Author dashboard
- Use the
/analytics
API endpoint to build a custom dashboard within your CMS.


Excel Mail Merge
Send bulk email with personalized information.
1
Write an email
to send to multiple people.
2
Fill out a mailing list
to personalize the email for each recipient.
3
Preview and send your email.
Sign in with Microsoft


Use-case Driven API Design
In the previous post, I discussed the qualities of a good public API design. Knowing where we want to go does not automatically tell us how to get there. Today I wanted to travel from Detroit to Chicago so I got in the car and opened Google Maps on my phone. It told me exactly how to get where I wanted to go. But before 1800 Chicago was much harder to find; there were no roads, no maps, no directions. Often it feels that way when we embark on the design of an API that does not yet exist. We are blazing a trail into new territory. We know the end goal - a clear, complete, compact, consistent API - and we can recognize it when we see it. But where do we start? We start from the end of course!
Requirements for an API must begin as a collection of tasks that the consumers of the API will accomplish. These should be written down in the language of the domain. If the person responsible for these requirements is not a subject matter expert (SME) then please try hard to consult with one. Getting the language right is crucial at this stage. The language will contain nouns and verbs that should become part of the final API methods. If you are using Domain Driven Design (DDD) these will also appear in the implementation.
Nomenclature (aka Ubiquitous Language)
Ubiquitous language is simply the language of a particular domain. Your API should be built on that language. Your object domain model should only include those domain concepts, the same ones understood and used by users and subject matter experts. It should not contain concepts related to the technical implementation of your computing solution.
For example, a flight reservation model would include nouns like person, passenger, reservation, scheduled flight, flight description, and airport. It would also include verbs or verb phrases like add reservation, add passenger, check space, add scheduled flight, and add airport.
These terms should be well documented. It is important to understand that the scope of a language can be fairly narrow. To an enterprise like a telephone company the term telephone will mean different things in different contexts (e.g. repair vs billing vs routing). Each domain will have its own dictionary.
Queries
The term ‘command query separation’ (or CQS) was coined by Bertrand Meyer in his influential book Object-Oriented Software Construction It states that every method should either be a command that performs an action, or a query that returns data to the caller, but not both. Methods that return data should have no observable side effects (except perhaps drowsiness).
Adherence to CQS is not necessary for a good API design, but it is helpful to keep these two types of API separate since they present different challenges to scalability. For example, in a distributed system the results of queries can be cached to improve performance at the cost of some staleness. On the other hand, commands need special handling to avoid race conditions that might lead to data corruption.
When designing APIs it is first helpful to rule out “reports”. Like queries, reports return data to the caller typically by getting some information from many database tables and doing some joins. The business is usually pretty lax about report requirements depending on how they are used. A report may be generated only for compliance and archived. Or it may be used to look for anomalies in a historical record of transactions. Typically reports span a fixed period of time. Most importantly, reports rarely interact with the domain model of the system, being generated instead from the data store. It is this that allows us to ignore reports when designing an API for the domain.
By contrast data that is presented to the user in a user interface is intended for immediate action. It represents the current status of the domain and so it must aspire to higher standards of “freshness”. Still, the business should be willing to provide guidance on how stale a piece of data in the UI can be allowed to get. Freshness is useful to include, along with the data in the UI, some indication of the staleness of that data to inform the end user (e.g. “as of 10:25:20 on 02/13/18” or “valid until 9am ET on 04/08/18”).
The key design consideration for a query is that all the data in the result should come from one subdomain. If the query must aggregate information from other subdomains then it will be slow and inconsistent. This may lead to some surprising results in the UI.
Example. In the online library domain there are several use cases which are pure queries. These correspond to listing or giving detailed information for the following entities:
- branches
- accounts
- items on loan
- reservation requests
- items in the library collection
The design should keep the data returned by these query API orthogonal. How this is accomplished in practice when relationships exist between entities is by embedding identifiers in the response. For example, an item on loan is an item held by a specific account at a specific branch. These three identifiers would be part of the data returned.
A well factored (orthogonal) set of API need not be inefficient. In the specific case of REST over HTTP, the results of query operations are typically cached. This is made easier when the allowed staleness of the data is defined.
Example. The list of branches or items in a library’s collection needn’t be updated more than once a day. Repeated requests that are served from a cache require no processing on the server end. To aggregate the same information on the server (requiring no extra code with OData or GraphQL) means that the back end is responsible, adding more processing, latency, and harming scalability. Magic is never cheap.
Commands
An API call with side effects is called a command
. Commands should be
designed not to fail to the maximum extent possible. Ideally a command provides
no response, not even a success or failure status, allowing it to be handled
asynchronously. This advice requires some justification.
When a command fails it can usually fail in many different ways:
- the command request could not be properly interpreted
- the agent issuing the command may not have permission
- the server hosting target resource may be unavailable
- the target resource itself may have been deleted
- the target resource state may have changed in an incompatible way
We can group all failures into one of four categories:
- good request; temporary unavailability of the target
- good request; permanent unavailability of the target
- bad request; client side coding error (bad use of the API)
- bad request; invalid state (user error, race condition, etc)
Some of these require a retry, some will fail no matter how many times a retry is attempted. Some require a client side code change, and some require the user to fix and try again.
A well designed system will understand the classification of the failure and automatically handle all of these on behalf of the client, when possible. For example, a retry can be attempted if a resource is not available. This too may eventually fail. In some cases there is nothing that can be done on the client side. The client code cannot fix itself for example (well not yet). In all cases when recovery from a failure cannot be done, the user will need to be informed, but no client side code need be written to handle that other than reloading the current state of client side objects from the server.
Informing the user of a failure, if done asynchronously, will allow the client to be more responsive. The client code should be designed with this in mind: do not assume success of your commands but wait for notification (via a domain event) that your command succeeded. In a distributed multi-user system clients should be notified of changes done by other users via domain events anyway.
Subdomains were important for keeping queries fast. They are equally important for avoiding race conditions in commands. Subdomains define the transactional boundaries of the data. There are two important rules to follow:
- A single command may change data only in one subdomain.
- A command must be atomic: all changes or none must be committed.
This suggests that the design of domains and subdomains follows the use cases since use cases identify all the data which must be changed. We should keep the subdomains small. Surprisingly this advice will break the data of one entity across subdomain boundaries. For example in Amazon the price of an item for sale and the description of the item are in different domains.
When business rules require changes to data in multiple subdomains this can still be accomplished by commands that work in unison within the domain. For example if the availability of rooms on a particular night in a hotel affects the room price, then the price subdomain must listen to room booked events from the room booking subdomain and adjust prices accordingly.
Finally, long lived workflows that involve commands from multiple domains can be implemented as sagas. Sagas are an improvement on two phase commit. Sagas support the notion of getting distributed agreement of a process (with reduced guarantees). In case of failures, all involved domains that successfully executed their commands perform compensating commands. If you want to use sagas then for every command also define an idempotent compensating command. Sagas are very cool but their discussion is beyond the scope of this post.
Example. In the online library domain there are several use cases which are commands. These correspond to creating, deleting, or updating the following entities:
- add, delete, or edit account
- renew items on loan
- create or cancel reservation requests
Branches and items held by a branch are not mutable via the API, simplifying the implementation. Branches are specified in a configuration file while the collection of their items (e.g. books) is maintained in an external system. The renewal of an item or the creation of a reservation request can fail due to race conditions with other users. The success of any mutation command is reported via a domain event.
When a command fails (which should be rare) the user instigating the command can be notified, either in the UI via a notification area, or by email.
Conclusion
In the next post I will show an API design for the online library system we have been discussing, starting from the use cases. I will discuss testing the API and then conclude with some thoughts about how the use case driven approach applies to REST API design.


Note how the change event for this dropdown from the shadow DOM is stopped. It doesn't show up in the console.


- FAQ - Class in models
-
- FAQ() - Constructor for class models.FAQ
-
Default constructor
- FAQ(String, String) - Constructor for class models.FAQ
-
Contructor with two parameters
- FAQController - Class in controllers
-
Class FAQController which contains all the handling of all the actions and
function that are done for the FAQs on our portal;
- FAQController() - Constructor for class controllers.FAQController
-
- FAQModelTest - Class in models
-
- FAQModelTest() - Constructor for class models.FAQModelTest
-
- filterCondition(String, String) - Static method in class controllers.ProductController
-
- filteredSearch(String, String) - Static method in class controllers.ProductController
-
- FilteredSearch() - Constructor for class controllers.ProductController.FilteredSearch
-
Constructor;
- FilteredSearch(String, String, String) - Constructor for class controllers.ProductController.FilteredSearch
-
Constructor with parameters;
- find - Static variable in class models.Blogger
-
- find - Static variable in class models.Comment
-
- find(int) - Static method in class models.Comment
-
Finder for comments (by id)
- find - Static variable in class models.FAQ
-
- find - Static variable in class models.MainCategory
-
- find - Static variable in class models.Newsletter
-
- find - Static variable in class models.PrivateMessage
-
- find - Static variable in class models.Product
-
- find - Static variable in class models.SubCategory
-
- find - Static variable in class models.TransactionP
-
The finder for the Transactions;
Searches by the id (Integer); and
the finder retruns the Transaction;
- find - Static variable in class models.User
-
- find(int) - Static method in class models.User
-
Finds the User under the id;
- find_bought_products() - Static method in class controllers.UserController
-
This method lists all the bought items of the User logged in;
If no products where bought by the user we inform him about it;
- findByName - Static variable in class models.MainCategory
-
- findByName - Static variable in class models.SubCategory
-
- finder(int) - Static method in class models.FAQ
-
Finder for FAQ (by id)
- finder(String) - Static method in class models.User
-
Finds the User under the username(parameter) in the database;
- findFaq - Static variable in class controllers.FAQController
-
- findInt - Static variable in class models.User
-
- findMainCategory(int) - Static method in class models.MainCategory
-
Method finds MainCategory by its Id
- findMainCategoryByName(String) - Static method in class models.MainCategory
-
Method finds MainCategory by its name
- findProduct - Static variable in class controllers.ProductController
-
- findProfileProducts() - Static method in class controllers.UserController
-
For the profiles products - that the current logged in user that has published;
The query search for all the products are published by the user logged in;
And renders the profile.html page;
- findReturnSubCategoryByNameAndMainCategory(String, MainCategory) - Static method in class models.SubCategory
-
- findSoldProducts() - Static method in class controllers.UserController
-
This method lists all the items of the User logged in that he has sold;
If no products where sold by the user we inform him about it;
- findSubCategory(int) - Static method in class models.SubCategory
-
- findSubCategoryByName(String) - Static method in class models.SubCategory
-
- findSubCategoryByNameAndMainCategory(String, MainCategory) - Static method in class models.SubCategory
-
- findUser() - Static method in class controllers.UserController
-
1.


Let's hold a bake sale! Doesn't that sound delicious? We'll have cupcakes and brownies and pies and maybe the woman down the street who runs a baking blog will invent something completely unique for all of us to taste. We send out a list to collect names and see who wants to participate. Alice, Jenny, Derek, Megan, Samantha, Josh, Davis, Brittney, Jessica, Brad, and Heather. If we're going to create a database where we can easily access the list of participants, an array is a great way to store our list. Create an array using the literal method by typing each of the names inside of square brackets, with quotation marks on either side of each name (string):
bakers_array = ["Alice", "Jenny", "Derek", "Megan", "Samantha", "Josh", "Davis", "Brittney", "Jessica", "Brad", "Heather"]If a few weeks go by and you forget who signed up, accessing the list again is easy. Type in "p bakers" and the list will be printed back out to you:
p bakers_array -->["Alice", "Jenny", "Derek", "Megan", "Samantha", "Josh", "Davis", "Brittney", "Jessica", "Brad", "Heather"]As the bake sale approaches, you realize that you don't know how many people have signed up. Cue ".length":
p bakers_array.length -->11There are 11 bakers bringing goodies to your sale, but you want to make sure you have variety. Cupcakes are great, but what if someone came to the sale craving a brownie? Once you've collected who will be bringing what, an array won't work for storing both the name of the person and what they are bringing. This is where an array is what you're looking for. An array stores an object, like the names referred to as strings in our bakers array above, but it also can store corresponding information for each object. One value is called a key, the other is called a value. Hashes are always built with key-value pairs. For our baking sale the names will be the keys and the yummy treats people bring will be the values. Key names must always be unique, so when creating your hash think through what strings or integers might be duplicates of each other and make that the values.
bakers_hash = { :Alice => "cupcakes", :Jenny => "brownies", :Derek => "cake", :Megan => "brownies", :Samantha => "cupcakes", :Josh => "cupcakes", :Davis => "cupcakes", :Brittney => "cookies", :Jessica => "cookies", :Brad => "brownies", :Heather => "cookies" }What was it that Samantha was bringing?
p bakers_hash[:Samantha] -->"cupcakes"And one ambitious person was bringing a cake, right? Who was that again?
p bakers_hash.find {|key, val| val == "cake"} -->[:Derek, "cake"]And that's one way to think about the difference between hashes and arrays. Now Derek, can you please bring me some of that cake?


Links Tool
By: Yodamaul
Show Values in Node
If you are just adding a new connection, add the number of the person in the input box
Just adding a new connection (between two existing people)
Enter
hi