TomTom |
HTD |
Mobica |
Rndity |
SEQR |
|
8:00 |
Registration | ||||
9:00 |
Hello world! (EN, Beginner) |
||||
9:10 |
No Coffee Break | ||||
9:15 |
How to combine Swift/Kotlin with C/C++ (EN, Beginner) Michał Kowalczyk |
Machine learning for a healthy society (EN, Intermediate) Zachary Markin |
Augmented Reality in the iOS World. What's in there for us? (EN, Beginner) Kamil Czopek |
Drink Espresso during Android Testing (EN, Intermediate) Aliaksandr Zhukovich |
DevOps in mobile? (EN, Intermediate) Tomasz Pająk |
10:00 |
Coffee Break | ||||
10:15 |
MVC vs MVP vs MVVM vs MVI (EN, Intermediate) Marcin Moskała |
Unmaintainable code - iOS developer perspective (EN, Intermediate) Tomasz Gebarowski |
Android Things 101 (EN, Beginner) Raul Portales |
Realm database in real life (EN, Intermediate) Marcin Zbijowski |
Awesome native apps with NativeScript and Angular! (EN, Beginner) Rowdy Rabouw |
11:00 |
Coffee Break | ||||
11:15 |
Functional approach to Android architecture using Kotlin (EN, Advanced) Jorge Castillo |
GraphQL vs REST (EN, Intermediate) Adam Żaczek |
Speech Analysis techniques (EN, Beginner) Martin Mitrevski |
Ogres and tests are like onions (EN, Intermediate) Aleksander Grzyb, Ewa Ludwiczak |
Breaking Bug (EN, Intermediate) Saúl Díaz |
12:00 |
Lunch Break | ||||
13:00 |
Android Architecture Components Considered Harmful (EN, Intermediate) Vasiliy Zukanov |
Database handling with Room (EN, Intermediate) Sergi Martinez |
Let's framework everything! (EN, Intermediate) Jakub Mazur |
Introduction to React Native (EN, Beginner) Eliasz Sawicki |
Making Scriptable iOS Apps (EN, Intermediate) Daniel Tull |
13:45 |
Coffee Break | ||||
14:00 |
kotlin.tools() of the trade (EN, Intermediate) Lorenzo Quiroli |
Advanced Retrofit (EN, Intermediate) Maciej Puchalski |
Zero to hero in UI testing (EN, Intermediate) Veselin Iliev |
Using Android Things to detect & exterminate Reptilians (EN, Beginner) Gautier Mechling |
Offline-first (EN, Intermediate) Miguel Quinones |
14:45 |
Coffee Break | ||||
15:00 |
RxSwift: Deep Cuts (EN, Advanced) Krzysztof Siejkowski |
Optimizing Android App performance with AT&T Video Optimizer (EN, Intermediate) Bartosz Kraszewski |
Optimizing Android apps for desktop experience (EN, Intermediate) Aleksei Kliuev, Victor Okunev |
Building CI pipeline based on TeamCity & Docker in Android Team (EN, Intermediate) Paweł Gajda |
I didn’t know the browser could do that! (EN, Beginner) Sam Bellen |
15:45 |
Coffee Break | ||||
16:00 |
Building iOS Apps at Scale (EN, Intermediate) Yusei Nishiyama |
Predict impending doom with IoT and ReactNative (EN, Beginner) Gabor Wnuk |
Tensorflow for Mobile Developers (EN, Intermediate) Enrique Lopez Manas |
Make your app instant (EN, Intermediate) Yuliya Kaleda |
Don’t fear SQL: A better way to store and handle data with SQLBrite && SQLDelight (EN, Intermediate) Leandro Favarin |
16:45 |
Coffee Break | ||||
17:00 |
The Kodein KOtlin DEpendency INjection library (EN, Intermediate) Salomon Brys |
Database driven UI with MVVM & Realm (EN, Intermediate) Nikola Irinchev |
Lenses and Prisms in Swift (EN, Advanced) Elviro Rocca |
Bluetooth Low Energy on Android: Top Tips for the Tricky Bits (EN, Intermediate) Stuart Kent |
Don't loose your users because of endless quality issues (EN, Intermediate) Olivier Destrebecq |
17:45 |
No Coffee Break | ||||
17:50 |
Finally meeting (EN, Advanced) |
||||
18:30 |
AfterParty in All Star Klubokawiarnia |


James Blunt reveals secret behind sounding like ‘a very talented girl’
James Blunt has revealed the secret behind his famed falsetto voice.
The chart-topping singer has recently released his new album, Once Upon A Mind.
Blunt said the key to his distinctive top notes on the record is Marmite.
Speaking to Chris Evans on the Virgin Radio breakfast show, he said: “I take a teaspoonful of Marmite … direct to the throat.
“Vitamin B12. Applied direct to the throat. Right now I can sing like an angel.
“Actually, if I’m honest, like a girl, but a very talented girl.”
The singer also said he has performed the same vocal warm-ups every day for the past 15 years.


Please see the file changes.html for details of all changes in this release.
Installation of Saxon simply involves unzipping the supplied download file into a suitable directory. The procedure is the same for the Standard product and the Schema-Aware product. The two products can co-exist in the same directory or in different directories.
One of the files that will be created in this directory is the principal JAR file. This is saxon8.jar in the case of Saxon-B, saxon8sa.jar in the case of Saxon-SA. There are additional JAR files to support optional features including the JDOM interface and the SQL interface. When running Saxon, the principal JAR file should be on the class path. The class path is normally represented by an environment variable named CLASSPATH: see your Java documentation for details. Note that the JAR file itself (not the directory that contains it) should be named on the class path.
The open-source Saxon-B distribution also includes source code. The modules included in the source code are also used, without modification, in the schema-aware product. Source code for the additional components of the schema-aware Saxon-SA product is not provided.
Saxon no longer includes a built-in XML parser: by default it uses the XML parser supplied with
the Java VM. But you can use it with a different XML
parser if you wish. To do this from the command line, specify the required parser using the
-x or -y options; from the Java API, set the name of the parser class as an attribute of
the TransformerFactory
or Configuration
object.
User documentation, covering both the XSLT and Java interfaces, is included in the download in the form
of extensive javadoc
specifications. Be sure to read the package summaries, which give an overview
in the form of a user guide.


This page must be accessed using HTTPS or via localhost.
If no notification is sent, unsubscribe then re-subscribe - when the Heroku server falls asleep it "forgets" your subscription information
333252921215
AIzaSyC_i2HqF5w5_-ArGKSsrJRIDPUCT10bDIQ


Web Developer Examples and Resources by Haidar Aliwi
Accessibility
Web AccessibilityWeb accessibility Web accessibility means making your website usable for people who might have barriers to accessing it. Typically it's associated with making your website usable by people with blindness or other visual disabilities, but in a general sense, it means making a website that can be used by people accessing it with a device other than the typical visual screens most people use. Often these devices are screen readers, which parse the underlying code of a website and read it aloud to a user. Making a website accessible usually requires fixing issues in the underlying code that don't show up as issues to users on visual screens. For example, some web pages rely on images to convey meaning, whether it's by using icons to indicate how to navigate the site, or by having an article that relies heavily on embedded pictures. For users on screens, these don't present a problem, but screen readers can't interpret icons or pictures. In these cases, there are ways to provide text alternatives to the graphical elements so that the screen reader can make sense of the page. The Web is an increasingly important resource in many aspects of life: education, employment, government, commerce, health care, recreation, and more. It is essential that the Web be accessible in order to provide equal access and equal opportunity to people with disabilities. An accessible Web can also help people with disabilities more actively participate in society. The Web offers the possibility of unprecedented access to information and interaction for many people with disabilities. That is, the accessibility barriers to print, audio, and visual media can be much more easily overcome through Web technologies. The document "Social Factors in Developing a Web Accessibility Business Case for Your Organization" discusses how the Web impacts the lives of people with disabilities, the overlap with digital divide issues, and Web accessibility as an aspect of corporate social responsibility. Another important consideration for organizations is that Web accessibility is required by laws and policies in some cases. WAI Web Accessibility Policy Resources links to resources for addressing legal and policy factors within organizations, including a list of relevant laws and policies around the world. Works cited 1. Introduction to web accessibility by Shawn Lawton Henry. 5 June 2019 https://www.w3.org/WAI/fundamentals/accessibility-intro/ 2. What Web Accessibility Is, and Why It's Important. March,3,2018 https://cleancatalog.com/blog/web-accessibility/ 3.The Business Case for Digital Accessibility. Sharron Rush. Contributors: Shawn Lawton Henry, Eric Eggert, Brent Bakken, Vicki Menezes Miller, Laura Keen. Acknowledgements lists additional contributors. Published 9 Nov 2018. https://www.w3.org/WAI/business-case/


Random Walk 3D by zb3
Hey! This is not a game (it has no objective), but a visualization of how a random walk (almost) from the inside or outside (free mode). If you want, you can actually control the construction, but you don't have to - it will just go in the random direction.
To open settings, click/tap on "Open controls". Here are some more controls:
arrows/WSAD - schedule a move (space to go straight), or move the camera in free mode
f / double click/tap - enter/exit free mode
left drag - look around
right drag - move camera
mouse wheel - rotate camera in Z axis
long press/tap - reset camera
OK


|
| | ADC () |
| |
| int | analogRead (uint8_t pin, int8_t adc_num=-1) |
| | Returns the analog value of the pin. More...
|
| |
| int | analogRead (ADC_INTERNAL_SOURCE pin, int8_t adc_num=-1) |
| | Returns the analog value of the special internal source, such as the temperature sensor. More...
|
| |
| int | analogReadDifferential (uint8_t pinP, uint8_t pinN, int8_t adc_num=-1) |
| | Reads the differential analog value of two pins (pinP - pinN). More...
|
| |
| bool | startSingleRead (uint8_t pin, int8_t adc_num=-1) |
| | Starts an analog measurement on the pin and enables interrupts. More...
|
| |
| bool | startSingleDifferential (uint8_t pinP, uint8_t pinN, int8_t adc_num=-1) |
| | Start a differential conversion between two pins (pinP - pinN) and enables interrupts. More...
|
| |
| int | readSingle (int8_t adc_num=-1) |
| | Reads the analog value of a single conversion. More...
|
| |
| bool | startContinuous (uint8_t pin, int8_t adc_num=-1) |
| | Starts continuous conversion on the pin. More...
|
| |
| bool | startContinuousDifferential (uint8_t pinP, uint8_t pinN, int8_t adc_num=-1) |
| | Starts continuous conversion between the pins (pinP-pinN). More...
|
| |
| int | analogReadContinuous (int8_t adc_num=-1) |
| | Reads the analog value of a continuous conversion. More...
|
| |
| void | stopContinuous (int8_t adc_num=-1) |
| | Stops continuous conversion. More...
|
| |
| Sync_result | analogSynchronizedRead (uint8_t pin0, uint8_t pin1) |
| | Returns the analog values of both pins, measured at the same time by the two ADC modules. More...
|
| |
| Sync_result | analogSyncRead (uint8_t pin0, uint8_t pin1) |
| | Same as analogSynchronizedRead. More...
|
| |
| Sync_result | analogSynchronizedReadDifferential (uint8_t pin0P, uint8_t pin0N, uint8_t pin1P, uint8_t pin1N) |
| | Returns the differential analog values of both sets of pins, measured at the same time by the two ADC modules. More...
|
| |
| Sync_result | analogSyncReadDifferential (uint8_t pin0P, uint8_t pin0N, uint8_t pin1P, uint8_t pin1N) |
| | Same as analogSynchronizedReadDifferential. More...
|
| |
| bool | startSynchronizedSingleRead (uint8_t pin0, uint8_t pin1) |
| | Starts an analog measurement at the same time on the two ADC modules. More...
|
| |
| bool | startSynchronizedSingleDifferential (uint8_t pin0P, uint8_t pin0N, uint8_t pin1P, uint8_t pin1N) |
| | Start a differential conversion between two pins (pin0P - pin0N) and (pin1P - pin1N) More...
|
| |
| Sync_result | readSynchronizedSingle () |
| | Reads the analog value of a single conversion. More...
|
| |
| bool | startSynchronizedContinuous (uint8_t pin0, uint8_t pin1) |
| | Starts a continuous conversion in both ADCs simultaneously. More...
|
| |
| bool | startSynchronizedContinuousDifferential (uint8_t pin0P, uint8_t pin0N, uint8_t pin1P, uint8_t pin1N) |
| | Starts a continuous differential conversion in both ADCs simultaneously. More...
|
| |
| Sync_result | readSynchronizedContinuous () |
| | Returns the values of both ADCs. More...
|
| |
|
void | stopSynchronizedContinuous () |
| | Stops synchronous continuous conversion.
|
| |
| void | resetError () |
| |
|
|
static const uint8_t | channel2sc1aADC0 [ADC_MAX_PIN+1] |
| | Translate pin number to SC1A nomenclature.
|
| |
|
static const uint8_t | channel2sc1aADC1 [ADC_MAX_PIN+1] |
| | Translate pin number to SC1A nomenclature.
|
| |
|
static const uint8_t | sc1a2channelADC0 [ADC_MAX_PIN+1] |
| | Translate pin number to SC1A nomenclature for differential pins.
|
| |
|
static const uint8_t | sc1a2channelADC1 [ADC_MAX_PIN+1] |
| | Translate pin number to SC1A nomenclature for differential pins.
|
| |
|
static const ADC_Module::ADC_NLIST | diff_table_ADC0 [ADC_DIFF_PAIRS] |
| | Translate differential pin number to SC1A nomenclature.
|
| |
|
static const ADC_Module::ADC_NLIST | diff_table_ADC1 [ADC_DIFF_PAIRS] |
| | Translate differential pin number to SC1A nomenclature.
|
| |
Class ADC: Controls the Teensy 3.x, 4 ADC
Returns the analog value of the special internal source, such as the temperature sensor.
It calls analogRead(uint8_t pin) internally, with the correct value for the pin for all boards. Possible values: TEMP_SENSOR, Temperature sensor. VREF_OUT, 1.2 V reference (switch on first using VREF.h). BANDGAP, BANDGAP (switch on first using VREF.h). VREFH, High VREF. VREFL, Low VREF.
- Parameters
-
| pin | ADC_INTERNAL_SOURCE to read. |
| adc_num | ADC_X ADC module |
- Returns
- the value of the pin.
| int ADC::analogRead |
( |
uint8_t |
pin, |
|
|
int8_t |
adc_num = -1 |
|
) |
| |
Returns the analog value of the pin.
It waits until the value is read and then returns the result. If a comparison has been set up and fails, it will return ADC_ERROR_VALUE. This function is interrupt safe, so it will restore the adc to the state it was before being called If more than one ADC exists, it will select the module with less workload, you can force a selection using adc_num. If you select ADC1 in Teensy 3.0 it will return ADC_ERROR_VALUE.
- Parameters
-
| pin | can be any of the analog pins |
| adc_num | ADC_X ADC module |
- Returns
- the value of the pin.
| Sync_result ADC::analogSynchronizedReadDifferential |
( |
uint8_t |
pin0P, |
|
|
uint8_t |
pin0N, |
|
|
uint8_t |
pin1P, |
|
|
uint8_t |
pin1N |
|
) |
| |
Returns the differential analog values of both sets of pins, measured at the same time by the two ADC modules.
It waits until the values are read and then returns the result as a struct Sync_result, use Sync_result.result_adc0 and Sync_result.result_adc1. If a comparison has been set up and fails, it will return ADC_ERROR_VALUE in both fields of the struct. This function is interrupt safe, so it will restore the adc to the state it was before being called
- Parameters
-
| pin0P | positive pin in ADC0 |
| pin0N | negative pin in ADC0 |
| pin1P | positive pin in ADC1 |
| pin1N | negative pin in ADC1 |
- Returns
- a Sync_result struct with the result of each differential ADC value.


Hello! In this task, you will be playing a cooking game. You will play one of two chefs in a restaurant that serves various soups.
This is what one level of the game looks like:
There are a number of objects in the game, labeled here:
You can move up, down, left, and right using the arrow keys, and interact with objects using the spacebar.
You can interact with objects by facing them and pressing spacebar. Here are some examples:
Note that as you and your partner are moving around the kitchen you cannot occupy the same location.
Once an ingredient is in the pot, you can begin cooking a soup by pressing spacebar as noted above. You can place up to 3 ingredients in a pot before cooking.
When a soup begins cooking, you'll notice a red number appear over the pot to denote the cook time. This number counts upward until the soup is done. Soup cook time is determined its ingredients; every onion add {{ layout_conf.onion_time }} and every tomato adds {{ layout_conf.tomato_time }} to the cook time.
Additionally, the base reward for any recipe is determined by its ingredients; each onion adds {{ layout_conf.onion_value }} points and each tomato adds {{ layout_conf.tomato_value }} points.
Once the soup is in a bowl, you can serve it by bringing it to a grey serving counter.
There are 9 possible soup recipes that can be created from combinations of tomatoes and onions, each with its own icon. The recipe icons and the corresponding ingredients are listed below
| Ingredients | Icon | Base Reward | Cook Time |
|---|---|---|---|
| {{ num_onions ~ " Onion" if num_onions }} {{ num_tomatoes ~ " Tomato" if num_tomatoes }} | {{ layout_conf.onion_value * num_onions + layout_conf.tomato_value * num_tomatoes }} | {{ layout_conf.onion_time * num_onions + layout_conf.tomato_time * num_tomatoes }} |
While you are free to cook any 3-ingredient soup you like, only some are worth points. The All Orders list shows which recipes will recieve points. This is important, as any soup served not in this list will not count towards your score. The All Orders list does not change throughout the duration of a level.
To reiterate: ANY SOUP COOKED THAT IS NOT IN ALL ORDERS WILL NOT BE WORTH POINTS
In addition to the list of available orders, there is also a list of bonus orders. Any soup from this list served will be worth its base reward times {{ layout_conf.order_bonus }}
When a soup is served at the serving counter, points could potentially be added to your score. The base reward for any recipe is determined by its ingredients; each onion adds {{ layout_conf.onion_value }} points and each tomato adds {{ layout_conf.tomato_value }} points. Note that serving a soup in the Bonus Orders multiplies the base soup score by {{ layout_conf.order_bonus }}. Additionally, serving a soup not in the All Orders list results in zero points not matter what!
Your goal in this task is to serve as many of the orders as you can before each level ends. The current all orders, bonus orders, time, and score are all displayed in an info panel below the layout.


Add AWS Account |
What is Endpoint? Inject PACKET_LOSS_PERCENTAGE=5% on vRealize Automation Appliance Node #1, Run workflow for network latency, Remediate fault and run workflow again. |
| Organization Name | Endpoint Name | Access Key | Secret Key | AWS Region | Delete Endpoint |
|---|---|---|---|---|---|
| {{awsendpoint.organization}} | {{ awsendpoint.name }} | {{ awsendpoint.accessKey }} | xxxxxxxxxx | {{awsendpoint.region}} |
Add VMware vSphere Account |
What is Endpoint? Inject PACKET_LOSS_PERCENTAGE=5% on vRealize Automation Appliance Node #1, Run workflow for network latency, Remediate fault and run workflow again. |
| Organization Name | Endpoint Name | vSphere SDK URL | vSphere User | vSphere Password | vSphere Computes | Delete Endpoint |
|---|---|---|---|---|---|---|
| {{vsphereendpoint.organization}} | {{ vsphereendpoint.name }} | {{ vsphereendpoint.sdkUrl }} | {{ vsphereendpoint.user }} | xxxxxxxxxx | {{vsphereendpoint.computes}} |


Orders are processed the same day as they are received or the following day if the order is placed outside normal hours of business. You will normally receive your goods in 2 – 4 working days.
In the unlikely event goods are out of stock, we will advise you by telephone or e-mail of the expected delay in dispatching them to you and you will have the option to cancel the order.
We currently deliver to mainland UK only.
Delivery charges
The current UK vat rate is {{admin.rates.taxRate * 100}}%
If you are not fully satisfied with your order you may return the goods with undamaged packaging to us within 28 days to receive a full refund. Refunds are not however possible on perishable or non-reusable items.
Goods must be returned in good condition, complete with all contents and packaging.
Please return goods to:
Returns Department, Damp Expert Ltd, WBC House, High Holborn Rd, Codnor Gate Industrial Estate, Ripley, Derbyshire, DE5 3NWEnclose your name and address details and reason for return inside the parcel.
Customers are responsible for the cost of returning goods unless the goods are faulty. We recommend goods are returned recorded delivery.
Your statutory rights are not affected by our shipping and returns policy.


|
system
0.1.0
|
#include <uart_logger.hpp>
Public Member Functions | |
| uart_backend (uart &in_uart) | |
| void | write (const std::string &in_str) override |
| Public Member Functions inherited from logging::backend | |
| virtual | ~backend () noexcept=default |
|
inline |
|
overridevirtual |
Implements logging::backend.


2017-07-15
Preamble: about a month ago, I was completely void of any android experience.
This is to say: using both QML (which is easy to learn) and Common Lisp (which I assume you already know) to develop android apps is not a difficult task at all, as you'll see.
So, if you are like me just a month ago, there are no excuses not to write your own, first android app using this new "EQL5-Android" project!
We will build a small game (Sokoban), which uses Lisp for the program logic, and QML for the UI, and build an APK for the android platform.
Being the author of that very first attempt of integrating Lisp and Qt4 (see lisp-cffi-qt4), what I would like to accomplish is providing you with a ca. 3 MB download, which can be tried out instantly.
10 years ago, the lisp-cffi-qt4.zip
(a runnable win32 binary version), was a 3 MB download, including both ECL and Qt4 (UPX compressed, but still).
10 years later, this time on android, what download size is to be expected?
We will see...
Since all the documentation needed for preparing the development environment is already covered in the "EQL5-Android" project itself, I will give only the link here:
So, I'm assuming that you already have everything installed and set up (Qt 5.7.1, Android NDK 10e, Android SDK, Java JDK, and obviously the EQL5-Android sources from gitlab), in order to build android packages (APK files).
(EQL5 itself, the desktop version, is not strictly needed to follow this example; but for developing your own apps, you will obviously need it; even here it's very helpful for testing and debugging, if something doesn't work as expected.)
If you already know the process of building EQL5 apps for the desktop, you will find that building (cross-compiling) to android is very similar, with only a few more steps involved.
Since we use an example of EQL5-Android itself, everything has already been set up. But I want to remember the steps that are not obvious, if you are not familiar with Qt and EQL:
.qrc
); this will integrate them (compressed) directly into the executable
make.lisp
(in a future version of EQL5, I will try to integrate this step with ASDF)
And that's it, basically (except the app name, which needs to be adapted to the *.qrc
file name, to your *.pro
file name and contents (see TARGET
and RESOURCES
), and to the contents of the third script 3-build-apk.sh
(see *.json
file name).
Everything else will stay the same for every project.
Now I want to call your attention on the huge advantage of using Qt for your android apps: you can first build a desktop exe
, with the exact same sources, and try/debug it. If the desktop version works, the android app will generally work too (the only things that may need adaption are e.g. font sizes and similar).
So, let's get practical! In the EQL5-Android sources, switch to 'examples/sokoban/'
.
Building a desktop exe would be this 3 liner:
$ eql5 make-desktop.lisp
$ qmake sokoban_desktop.pro
$ make
(To test if all resources have really been included in the sokoban_desktop
executable, you need to move it to a different directory, and launch it from there.)
Here's a screenshot of our app running on the desktop:
But now let's do the cross-compile dance!
First let's copy the needed shared libraries to the 'android-build/'
directory.
Just run script number 1:
$ ./1-copy-libs.sh
This step needs only be done once for every new project. It will copy the cross-compiled ECL and EQL5 libs into our android build directory.
The next steps are very similar to a desktop build:
$ ecl-android -shell make.lisp
$ qmake-android sokoban.pro
$ make
Since cross-compiling requires a special "host ECL", which needs to match the target platform (that is, 32 bit, no double floats), we would be in trouble with cross-compiling EQL5 code: we certainly don't want a seperate EQL5 32 bit version, only for cross-compiling...
But there is a solution to this (see 'utils/EQL5-symbols.lisp'
in sources): for cross-compiling -- which is the job of our "host ECL" -- we pretend to be the eql5
executable, by defining all packages and symbols, defining all EQL5 macros (otherwise we can't compile), and simply defining dummy-functions for all EQL5 functions, so the compiler will not complain.
So, loading 'utils/EQL5-symbols.lisp'
in our host ECL will be sufficient for cross-compiling EQL5 code.
If you are interested in how the cross-compile environment is set up, please see:
(thanks to Sylvain Ageneau, who wrote the original version; this is a simplified version not depending on ASDF; the latter will be integrated in a future version)
So, the above 3 liner will build the shared library of our app, ready to be included in the android build. To copy it where the android build expects it, use script number 2:
$ ./2-install-lib.sh
The last step, which will build our APK file, is a verbose one (for eventual debugging), and a little time consuming: it will create the whole package structure, and compile the whole thing into an APK file, ready to be installed on an android device.
There is this great tool (courtesy Qt) called androiddeployqt
, which automates the whole and complex process of creating an APK file, with all the needed options already set in our 3rd script:
$ ./3-build-apk.sh
Here the contents of the above script, where you can see all the selected options:
$ ~/Qt5.7.1/5.7/android_armv7/bin/androiddeployqt \
--input android-libsokoban.so-deployment-settings.json \
--output android-build \
--deployment ministro \
--gradle \
--verbose
If it will tell you BUILD SUCCESSFUL
, then you'll find the APK file (ready for deployment) in 'android-build/build/outputs/apk/'
.
The last step is copying over the APK file to your android device, and install / run it. Normally you're not allowed to do this, because it requires special developer settings (please search the web for instructions how to enable them, as they are different for every android version).
After connecting via USB and copying the APK file over to your device, just tap it from there. This will ask for installing, and then for opening the app.
Here's a screenshot of the sokoban app running on a tablet:
Above you see the splash screen, because startup will take a few seconds.
Below the game:
After seeing the result, I'd like to consider a few QML and Lisp snippets.
QML is easy to learn. You just need to declare what you want (and it will do the how behind the scenes).
Let's see this snippet for defining and placing our arrow buttons:
// container for arrow buttons
Item {
id: arrows
width: up.width * 3
height: up.height * 3
anchors.margins: 10
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
Ext.Button {
id: up
objectName: "up"
source: "img/up.png"
anchors.horizontalCenter: parent.horizontalCenter
}
Ext.Button {
objectName: "left"
source: "img/left.png"
anchors.verticalCenter: parent.verticalCenter
}
Ext.Button {
objectName: "right"
source: "img/right.png"
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
}
Ext.Button {
objectName: "down"
source: "img/down.png"
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
}
}
So, we define an Item
as container for the buttons, giving it the width (up.width * 3
) and height (up.height * 3
), according to the button sizes: this may be any calculation or function call, and may refer to any item of the file, referred to by its id
.
For placing the container itself, and the single arrow buttons, we just need to define anchors
, which can be relative to other items (here: the parent
item).
The Ext.Button
is a user defined item class, which can be found in 'qml/ext/Button.qml'
. That is, the whole directory 'ext/'
is imported as Ext
:
import "ext/" as Ext
This means that every file in 'ext/'
is now a new QML class, which can be referred to via Ext
(like a namespace).
The definition of our image button class (see 'qml/ext/Button.qml')
is:
import QtQuick 2.0
Image {
signal pressed()
MouseArea {
anchors.fill: parent
onPressed: parent.pressed()
}
}
So, we don't need a real button, but only a clickable image: adding a mouse area will allow us to capture mouse events; this event is then passed to the parent (that is, the Image
class), where a Qt signal will be emitted: this will allow us to connect to it from Lisp:
(defun connect ()
(macrolet ((pressed (item function)
`(qconnect (find-quick-item ,item) "pressed()"
(lambda () ,function))))
(pressed "up" (sokoban:move :north *maze*))
(pressed "down" (sokoban:move :south *maze*))
(pressed "left" (sokoban:move :west *maze*))
(pressed "right" (sokoban:move :east *maze*))
(pressed "previous" (change-level :previous))
(pressed "next" (change-level :next))
(pressed "undo" (undo))
(pressed "restart" (reset-maze))
(pressed "solve" (solve))))
If you already played the game finishing a level, you will have noticed that there are 2 animations (rotation of the player, wiggling of all boxes) which run queued.
This is a little tricky to do, but with the help of a Lisp macro, we only need these lines in Lisp (being queued
a macro):
(defun final-animation ()
(queued (qml-set "rotate_player" "running" t)
(qml-set-all "wiggle_box" "running" t)))
Please see the sources for all the details. And this would not be possible without a Lisp function called from QML for notifying us whenever an animation state changes, see 'qml/ext/RotationAnimation.qml'
:
import QtQuick 2.0
import EQL5 1.0
RotationAnimation {
onRunningChanged: Lisp.call("qsoko:animation-change", running)
}
What I left out to explain is the dynamic (at run time) creation of QML items (see 'qml/items/*'
and 'lisp/sokoban.lisp'
); let's just say that this is left as an exercise to the reader, as all sources will patiently stay there to be read...
Well. But I still didn't answer the initial question: how big of a download is to be expected, 10 years later?
Since our APK file uses the ministro service for automatically installing the needed Qt libraries at the first launch of the app, it will only need to include both the ECL and EQL5 libraries (you can therefore use different ECL and EQL5 versions for every app you deploy).
So, to finally answer the question: our download will be ca. 3.5 MB (instead of 3 MB, 10 years ago, although we obviously compare apples and oranges here).
Seems acceptable.
And since I promised you to test it instantly (if you own a device with ARM processor), here you are:
Enjoy!
P.S. This was written a while ago, and is already outdated, sorry for that. The above APK now includes a REPL etc., and is therefore bigger. Please note that a full APK, including everything (not using the ministro service) is about 15 MB big, including the prebuilt ECL libs and Quicklisp support, plus a patched Slime version (see current download page).


The name and version of the API to create (should be unique).
The resource this API will expose (will be used for default CRUD API operations).


last revised: 2021-04-14
In the Content Fabric, ingesting video for streaming involves two kinds of objects, Production Masters and ABR Mezzanines:
Production Masters
default
ABR Mezzanines
The ingest process consists of the following steps:
NOTE: Although currently caption/subtitle files are added to ABR Mezzanines separately after creation, in the future this may be changed so that they are part of the original Production Master instead.
If you do not have them already, install git and node.js / npm
Navigate to the directory where you would like to install elv-client-js
git clone https://github.com/eluv-io/elv-client-js
cd elv-client-js
npm install
npm audit fix
At this point, you may still see some warnings about package vulnerabilities. As we are only running local command line scripts (rather than using node.js to run a web app that accepts input from the outside world) these are safe to disregard.
Edit the file elv-client-js/TestConfiguration.json
To connect to our demo network, this file should be set to contain the following:
{
"config-url": "https://demov3.net955210.contentfabric.io/config"
}
To connect to our production network, the file should be set to contain the following:
{
"config-url": "https://main.net955305.contentfabric.io/config"
}
Configure the private key environment variable:
export PRIVATE_KEY=0x...
(your Content Fabric private key)If your media files are hosted on AWS S3, also set the following environment variables:
export AWS_REGION=
(your AWS region)export AWS_BUCKET=
(your AWS bucket name)export AWS_KEY=AK...
(your AWS S3 key)export AWS_SECRET=...
(your AWS S3 secret)If you need to update to the latest version of elv-client-js, you can do so with:
cd elv-client-js
git pull
npm install
This documentation uses scripts in directory /elv-client-js/testScripts
.
These will eventually be replaced by new scripts in directory /elv-client-js/utilities
. To minimize disruption to existing customer workflows, the existing testScripts
directory and its contents will remain for the time being, but deprecation warning messages will be added to the old scripts as corresponding replacements become available.
Differences between old and new scripts are detailed in the following Google doc:
The Production Master object contains links to your original source material. It is not directly playable, but is used to generate a playable Mezzanine object.
To create a Production Master, you will need the following:
Each tenant of the Content Fabric has a number Content Types created for them. These provide a way of customizing the structure of your fabric objects.
If you click on Content Types on the left side you will see a list of these types, among which should be one named "TENANT_NAME - Title Master".
If you click on this item, you will see a detail screen where you can select and copy the Name and Object ID for this Content Type. When you run commands to create Production Masters, you will need to supply either the name or the ID of this content type, e.g.:
--type "TENANT_NAME - Title Master"
or
--type iq__...
(your 'Title Master' content type ID - content type IDs start with "iq__")
NOTE: In the instructions below there are a number of operations done via browser. These can be done programmatically as well and we can provide code samples as needed.
Click on Content in the left sidebar to get to your list of libraries.
Each tenant also has a number of libraries created for them, including one to hold Production Masters - it should be labeled "TENANT_NAME - Title Masters". Click on this item to see a list of objects currently in the library (initially it may be empty).
On the next screen, click on the Library Info tab to find the Library ID. When you run commands to create Production Masters, you will need to supply this ID, e.g.:
--library ilib...
(your 'Title Masters' library ID - library IDs start with "ilib")
Here is a sample command line to generate a Production Master using a file on AWS S3. Once you have the required information, substitute it into the sample below (if you do not need to attach an asset ID, you can omit the --ip-title-id
line):
cd elv-client-js
node testScripts/CreateProductionMaster.js \
--library ilib3xDQU7yDgZZQsmMwUrHTwzAEbbdu \
--title "Big Buck Bunny (master)" \
--s3-reference \
--type "TENANT_NAME - Title Master" \
--ip-title-id "YOUR_INTERNAL_ASSET_ID" \
--files bbb_sunflower_1080p_60fps_stereo_abl.mp4
NOTE: Our convention in this case is to omit the "s3://" prefix and bucket name from the start of file path, i.e. use bbb_sunflower_1080p_60fps_stereo_abl.mp4
instead of s3://BUCKET_NAME/bbb_sunflower_1080p_60fps_stereo_abl.mp4
. If the file is in a subdirectory, start with the name of the subdirectory, without any leading slash character (/)
Here is a sample command line to generate a Production Master using a local file. Once you have the required information, substitute it into the sample below (if you do not need to attach an asset ID, you can omit the --ip-title-id
line):
cd elv-client-js
node testScripts/CreateProductionMaster.js \
--library ilib3xDQU7yDgZZQsmMwUrHTwzAEbbdu \
--title "Big Buck Bunny (master)" \
--type "TENANT_NAME - Title Master" \
--ip-title-id "YOUR_INTERNAL_ASSET_ID" \
--files PATH_TO_YOUR_DIRECTORY/bbb_sunflower_1080p_60fps_stereo_abl.mp4
When you run the CreateProductionMaster.js
script, the server examines the file(s) for audio and video streams, then makes a simple guess about what should be included in the mezzanine.
You should see output like the following:
Creating Production Master
Production Master
{ done: true, uploadedFiles: 1, totalFiles: 1 }
Production master object created:
Object ID: iq__2QEH2nqrLkwZpkNoguw1RGW7hFK4
Version Hash: hq__9v2JY21ESnsvNdwWwgJrjiw7jHWv5nXik6quVn6FUgDxbgTgJT8toxBVb1ShZZH4mcFSFcJUJJ
If you included any non-media files in the --files list, you will also see warnings at the end of the output complaining Failed to create media.Source from file
. These can be ignored as long as you included at least one media file.
If the server did not find a presupplied stereo (2-channel) audio stream among the files, you will see the following warning:
WARNING: no audio stream found
If the server did not find a video stream among the files, you will see the following warning:
WARNING: no video stream found
A Production Master contains one or more Variants. A Variant is one version of the original title (this allows you to create different content versions for particular countries or distribution channels). The CreateProductionMaster.js
script creates a single Variant named default
.
Clicking on the Show Metadata button and drilling down into production_master → variants → default → streams will reveal what files and stream indexes the server has chosen to include in this "default" Variant.
In order to make the Mezzanine viewable for your site, you must set overall permission level for object to Viewable.
From the object details page, click the Content Info tab, then change the Permissions: line to Viewable.
If you cannot change the Permissions: line, make sure you are logged in to the Fabric Browser with the private key used to create the mezzanine.
In order to make the Mezzanine viewable using the command line, you will need to know the following:
The command to add permissions is then:
node testScript/ObjectSetPermissions.js \
--objectId YOUR_OBJECT_ID \
--value Viewable
In order to let other Content Admins work with your Production Master object, you must grant group permissions to an Access Group.
From the object details page, click the blue Groups button at top - you should see a screen with the Access Group field already chosen for you, set to "TENANT_NAME Content Admins".
Check the Manage box, then click Submit.
In order to grant group permissions via the command line, you will need to know the following:
You can find the Address of your group by clicking on the blue Groups button at top when you are browsing the details of any object. You can choose a group from the Access Group dropdown, then double-click the Address field to select it and copy to your clipboard.
The command to add permissions is then:
node testScripts/AddGroupPermissions.js \
--objectId YOUR_OBJECT_ID \
--groupAddress YOUR_GROUP_ADDRESS \
--permissions manage
If you need to make any changes to the Variant's stream selections (e.g. because the server did not choose the desired streams, or if you wish to add more audio streams) you can use scripts to add/edit/remove Variant streams. In order to use these scripts, you will need to look at the Production Master's existing stream information.
You can inspect stream information for files and Variants in the fabric browser by clicking on the Show Metadata button and drilling down by clicking on productionmaster → sources → (filename) → streams and productionmaster → variants → (variant name) → streams. (Clicking on a downward pointing triangle ▼ will expand all details for a line item, clicking on an expanded line item will collapse it)
Alternately, you can use the ProductionMasterInfo.js
script, which will output a subset of this information:
node testScripts/ProductionMasterInfo.js \
--libraryId YOUR_LIBRARY_ID \
--objectId YOUR_MASTER_OBJECT_ID
In order add a stream to a Variant, you will need to supply the following information:
"Director's commentary"
.--isDefault
. If omitted, the stream is assumed to be an alternate stream and will not be chosen by default unless it is the only stream of its type (audio or subtitle) or if the user has a matching browser/player language preference configured. The command to add the stream is then would resemble the following:
(note that --mapping
, SECOND_STREAM_INDEX
, and --isDefault
would not always be included)
node testScripts/VariantAddStream.js \
--libraryId YOUR_LIBRARY_ID \
--objectId YOUR_MASTER_OBJECT_ID \
--variantKey THE_VARIANT_NAME \
--streamKey YOUR_CHOSEN_STREAM_KEY \
--file THE_FILENAME \
--label YOUR_EXTERNALLY_VISIBLE_STREAM_LABEL \
--language THE_LANGUAGE_CODE \
--streamIndex FIRST_STREAM_INDEX SECOND_STREAM_INDEX \
--mapping THE_MAPPING \
--isDefault
Here is a sample command with example values filled in, for the case where the master source file contains a stereo audio stream:
node testScripts/VariantAddStream.js \
--libraryId ilib3t4Cf8pdxftVcc4Si35yZxPgN33 \
--objectId iq__3RVmL1WdnVj7mYrKZcDUPpzstFNU \
--variantKey default \
--streamKey audio-alternate \
--file MyAlternateAudio.mp4 \
--label "Director's commentary" \
--language en \
--streamIndex 0
Once you run the command, it will output the new version hash for the Production Master. You will need this value in order to create a mezzanine, unless you have more streams to add to the Variant, in which case you will need the version hash that is output by your final VariantAddStream.js
command.
The command to edit a stream is similar to the one for adding a stream. In order edit a stream in a Variant, you will need to supply the following information:
"Director's commentary"
.--isDefault
. If omitted, the stream is assumed to be an alternate stream and will not be chosen by default unless it is the only stream of its type (audio or subtitle) or if the user has a matching browser/player language preference configured. The command to edit the stream is then would resemble the following:
(note that --mapping
, SECOND_STREAM_INDEX
, and --isDefault
would not always be included)
node testScripts/VariantEditStream.js \
--libraryId YOUR_LIBRARY_ID \
--objectId YOUR_MASTER_OBJECT_ID \
--variantKey THE_VARIANT_NAME \
--streamKey THE_EXISTING_STREAM_KEY \
--file THE_FILENAME \
--label YOUR_EXTERNALLY_VISIBLE_STREAM_LABEL \
--language THE_LANGUAGE_CODE \
--streamIndex FIRST_STREAM_INDEX SECOND_STREAM_INDEX \
--mapping THE_MAPPING \
--isDefault
Here is a sample command with example values filled in, to change the streamIndex from the previous example to 1 instead of zero:
node testScripts/VariantAddStream.js \
--libraryId ilib3t4Cf8pdxftVcc4Si35yZxPgN33 \
--objectId iq__3RVmL1WdnVj7mYrKZcDUPpzstFNU \
--variantKey default \
--streamKey audio-alternate \
--file MyAlternateAudio.mp4 \
--label "Director's commentary" \
--language en \
--streamIndex 1
Once you run the command, it will output the new version hash for the Production Master. You will need this value in order to create a mezzanine, unless you have more streams to edit, in which case you will need the version hash that is output by your final VariantEditStream.js
command.
In order remove a stream from a Variant, you will need to supply the following information:
The command to edit the stream is then would be the following:
node testScripts/VariantRemoveStream.js \
--libraryId YOUR_LIBRARY_ID \
--objectId YOUR_MASTER_OBJECT_ID \
--variantKey THE_VARIANT_NAME \
--streamKey THE_EXISTING_STREAM_KEY
Once you run the command, it will output the new version hash for the Production Master. You will need this value in order to create a mezzanine, unless you have more streams to remove, in which case you will need the version hash that is output by your final VariantRemoveStream.js
command.
A Mezzanine object contains transcoded media optimized for adaptive bitrate (ABR) streaming. Depending on the ABR profile you choose, it is playable via HLS and/or DASH with DRM (you also have the option to offer playout in the clear).
To create a Mezzanine, you will need the following:
NOTE: In the instructions below there are a number of operations done via browser. These can be done programmatically as well and we can provide code samples as needed.
Any script that creates and/or modifies a Production Master will output the new version hash for the object, e.g.:
Adding stream 'audio' to variant 'default'...
Writing metadata back to object...
Finalizing object...
New version hash: hq__N8VZbpdEtRyTsuPtnczwKNi2hgFNu3F7CJEHmroPqbwEaJNwoL9tiGGLEvi7zm4ZpGmQrntWT
Done.
Version hashes always start with the characters hq__
and this value can be copied and pasted in your command terminal window.
Alternately, you can also look up the version hash in the Fabric Browser and copy from there:
In your browser, if you click on Content in the left sidebar, then click on your Title Masters library, you should be able to find your new Production Master object.
(If you are already on the page that lists objects in the library you may need to click the refresh icon to see the new object)
Clicking on the object will show you details about the object. For the next step (generating a mezzanine) you will need the Latest Version Hash for the object. This value (hq__9v2JY2… for this example) can be copied by clicking on the clipboard icon as shown below. It is also listed in the output from the CreateProductionMaster.js
script.
Click on Content Types on the left side and click on the one named "TENANT_NAME - Title".
You will see a detail screen where you can select and copy the Name and Object ID for this Content Type. When you run commands to create Mezzanines, you will need to supply either the name or the ID of this content type, e.g.:
--type "TENANT_NAME - Title"
or
--type iq__...
(your 'Title' content type ID - content type IDs start with "iq__")
Click on Content in the left sidebar to get to your list of libraries.
Click on the one labeled "TENANT_NAME - Titles", then click on the Library Info tab to find the Library ID. When you run commands to create Mezzanines, you will need to supply this ID, e.g.:
--library ilib...
(your 'Titles' library ID - library IDs start with "ilib")
An ABR Profile contains information on what formats, resolutions and bitrates to offer for streaming playout, as well as any DRM and/or watermarking information.
There are JSON files containing commonly used profiles in elv-client-js/testScripts/
abr_profile_4k_clear_store_encrypted.json
abr_profile_4k_clear_store_unencrypted.json
abr_profile_4k_drm.json
abr_profile_clear_store_encrypted.json
abr_profile_clear_store_unencrypted.json
abr_profile_drm.json
The 4k files are specifically for offering 16:9 material at 3840x2160 resolution.
For most content we recommend using the abr_profile_drm.json
file, which contains resolution ladders for a variety of aspect ratios. (For material with 16:9 aspect ratio, this file's top ladder rung is 1920x1080 @ 9.5 mbps)
The *_clear_*
files are for publishing without DRM. For items that are intended to be publicly accessible, use the profiles that end in _store_unencrypted.json
. If there is a chance that you might want to change the mezzanine later to have DRM, use the profiles that end in _store_encrypted.json
(however, these offerings will not be playable to users without a Fabric private key that has been granted access to it).
Once you have the required information, substitute it into the sample command below (if you do not need to attach an asset ID, you can omit the --ip-title-id
line):
node testScripts/CreateABRMezzanine.js --library ilib4JFY7hontNKJJmM4XnZaweTbH9tq \
--masterHash hq__9v2JY21ESnsvNdwWwgJrjiw7jHWv5nXik6quVn6FUgDxbgTgJT8toxBVb1ShZZH4mcFSFcJUJJ \
--title "Big Buck Bunny" \
--type "TENANT_NAME - Title" \
--ip-title-id "YOUR_INTERNAL_ASSET_ID" \
--abr-profile testScripts/abr_profile_drm.json
Note in particular that the --library
and --type
parameters will be different from your commands to create Production Masters.
Once the object is created, transcoding will begin on the server.
Your output from the previous command should look something like this:
Creating ABR Mezzanine...
Starting Mezzanine Job(s)
Library ID ilib4JFY7hontNKJJmM4XnZaweTbH9tq
Object ID iq__4N1gG59cE1YzAL3NfRs39rFVTq8q
Offering: default
Write Token: tqw_4SiNg6kktmRGmAjLXjeFzt8s8C2Lbo5Bo
Write Node: https://host-38-142-50-110.contentfabric.io/
The Object ID identifies your new Mezzanine, you will need this value for subsequent commands.
In your browser, if you click on Content in the left sidebar, then click on your Titles library, you should see your new Mezzanine object. (If you are already on the page that lists objects in the library you may need to click the refresh icon to see the new object)
If you go into the "TENANT_NAME - Title Mezzanines" library in your browser you should see the new mezzanine object.
(If you are already on the object list page you may need to click the refresh icon to see the new object)
Drilling down into it, you should see some information about transcoding progress (you will not be able to play it until transcoding has finished and you have finalized the object):
In most cases, the percentage value shown is an average of 2 values (audio percent done and video percent done). The audio generally processes much more quickly, so you will see the value climb quickly to just above 50%, then progress more slowly.
You can get detailed progress info with the following command:
node testScripts/MezzanineStatus.js --objectId YOUR_NEW_MEZ_OBJECT_ID
Your output should look something like this, listing 2 jobs (1 for audio, 1 for video):
{
"63fe3cbf-4660-44b2-8d93-415d97e4bd88": {
"duration":<PHONE_NUMBER>11,
"duration_ms": 485986,
"progress": {
"percentage": 68.9119170984456
},
"run_state": "running",
"start": "2020-03-26T18:49:28Z"
},
"f39c9de1-4c29-49cf-bcf9-f173bc114e73": {
"duration":<PHONE_NUMBER>27,
"duration_ms": 482414,
"progress": {
"percentage": 3.6269430051813467
},
"run_state": "running",
"start": "2020-03-26T18:49:28Z"
}
}
The "start" field is in UTC time.
Divide the "duration_ms" field by 1000 to get seconds elapsed.
Depending on the format, bitrate and complexity of the original source material, and the speed of transfer between your S3 bucket and the Content Fabric node, it can take anywhere from 1x to 8x the actual duration of the program to complete transcoding.
Once both jobs show a "run_state" of "finished", you are ready for the next step, finalization.
Finalizing the Mezzanine makes the transcoded media available for viewing and distributes it to other nodes in the Content Fabric.
The command to finalize is the same as for checking progress, but with an additional --finalize parameter:
node testScripts/MezzanineStatus.js --objectId YOUR_NEW_MEZ_OBJECT_ID --finalize
While the command itself should complete quickly, it can take 2-3 minutes for the finalized content to become visible in the browser. (Behind the scenes, the nodes in the fabric are distributing parts among themselves)
In the browser, click the refresh icon to update your view, then click on the Display tab to see the finalized content.
(Identical process as for the Production Master object)
From the object details page, click the blue Groups button at top - you should see a screen with the Access Group field already chosen for you, set to "TENANT_NAME Content Admins".
Check the Manage box, then click Submit.
(Identical process as for the Production Master object)
In order to grant group permissions via the command line, you will need to know the following:
You can find the Address of your group by clicking on the blue Groups button at top when you are browsing the details of any object. You can choose a group from the Access Group dropdown, then double-click the Address field to select it and copy to your clipboard.
The command to add permissions is then:
node testScripts/AddGroupPermissions.js \
--objectId YOUR_OBJECT_ID \
--groupAddress YOUR_GROUP_ADDRESS \
--permissions manage
Caption streams are added using .vtt files.
In order to add a caption stream, you will need to know the following:
en
) then the offering must also contain an audio stream with lang code en
.yue
or cmn
) rather than the text language code (zh-hans
or zh-hant
). If your offering contains both Mandarin (cmn
) and Cantonese (yue
) audio streams then you will need to add your Chinese forced caption file twice, once using cmn
and once using yue
.zh-hans
or zh-hant
).Sample command with minimal options:
cd elv-client-js
node testScripts/OfferingAddCaptionStream.js \
--libraryId YOUR_MEZ_LIB_ID \
--objectId YOUR_MEZ_OBJECT_ID \
--lang "YOUR_LANGUAGE_CODE" \
--label "YOUR_LABEL_FOR_PLAYER_UI" \
--file PATH_TO_YOUR_VTT_FILE
Add the following optional parameters above the --file
line if desired:
--offeringKey THE_OFFERING_KEY \
--isDefault \
--forced \
--encrypt \
--timeShift NUMBER_OF_SECONDS \
--timeShift -NUMBER_OF_SECONDS \
--streamKey DESIRED_STREAM_KEY \
(Identical process as for the Production Master object)
From the object details page, click the blue Groups button at top - you should see a screen with the Access Group field already chosen for you, set to "TENANT_NAME Content Admins".
Check the Manage box, then click Submit.
(Identical process as for the Production Master object)
In order to grant group permissions via the command line, you will need to know the following:
You can find the Address of your group by clicking on the blue Groups button at top when you are browsing the details of any object. You can choose a group from the Access Group dropdown, then double-click the Address field to select it and copy to your clipboard.
The command to add permissions is then:
node testScripts/AddGroupPermissions.js \
--objectId YOUR_OBJECT_ID \
--groupAddress YOUR_GROUP_ADDRESS \
--permissions manage
A Mezzanine object contains one or more Offerings. Each Offering specifies the following information:
When the CreateABRMezzanine.js
script is run, it creates a single Offering named default
.
The OfferingCopy.js
script allows you to duplicate an existing Offering, after which you can modify the copy to change the playout options (see "Adding / removing playout options from an Offering" section below):
node testScripts/OfferingCopy.js \
--libraryId YOUR_TITLE_LIBRARY_ID \
--objectId YOUR_MEZ_OBJECT_ID \
--offeringKey default \
--targetOfferingKey YOUR_NEW_OFFERING_NAME
(if you want to copy an Offering other than the one named default
then change the end of the --offeringKey
line)
In the Fabric Browser, when you are on the Display tab for your Mezzanine, click on the Advanced Controls button to access additional options. The Offering pulldown menu will allow you to choose other Offerings besides "default".
You can make changes to an Offering (either the default
, or one you have created via the OfferingCopy.js
script) to modify playout options.
The OfferingAddClear.js
script will add a DRM-free playout option to one Offering within your Mezzanine:
node testScripts/OfferingAddClear.js \
--libraryId YOUR_TITLE_LIBRARY_ID \
--objectId YOUR_MEZ_OBJECT_ID \
--offeringKey THE_OFFERING_NAME
The OfferingRemoveClear.js
script will remove DRM-free playout options from one Offering within your Mezzanine:
node testScripts/OfferingRemoveClear.js \
--libraryId YOUR_TITLE_LIBRARY_ID \
--objectId YOUR_MEZ_OBJECT_ID \
--offeringKey THE_OFFERING_NAME
The OfferingRemoveDRM.js
script will remove DRM-protected playout options from one Offering within your Mezzanine:
node testScripts/OfferingRemoveDRM.js \
--libraryId YOUR_TITLE_LIBRARY_ID \
--objectId YOUR_MEZ_OBJECT_ID \
--offeringKey THE_OFFERING_NAME
The OfferingListRungs.js
script will display the resolution ladder for an existing Offering:
node testScripts/OfferingListRungs.js \
--libraryId YOUR_TITLE_LIBRARY_ID \
--objectId YOUR_MEZ_OBJECT_ID \
--offeringKey THE_OFFERING_NAME
If --offeringKey
is omitted then default
will be assumed.
Sample output:
Listing resolution ladder rungs for all streams in offering 'default'
{
"audio": {
"representations": {
"audio@128000": {
"bit_rate": 128000,
"media_struct_stream_key": "audio",
"type": "RepAudio"
}
}
},
"video": {
"representations": {
"video_1452x1080@4900000": {
"bit_rate": 4900000,
"crf": 0,
"height": 1080,
"media_struct_stream_key": "video",
"type": "RepVideo",
"width": 1452
}
"video_726x540@1500000": {
"bit_rate": 1500000,
"crf": 0,
"height": 540,
"media_struct_stream_key": "video",
"type": "RepVideo",
"width": 726
},
"video_968x720@3375000": {
"bit_rate": 3375000,
"crf": 0,
"height": 720,
"media_struct_stream_key": "video",
"type": "RepVideo",
"width": 968
}
}
}
}
The OfferingAddVideoRung.js
script will allow you to add a new rung to an Offering's video resolution ladder:
node testScripts/OfferingAddVideoRung.js \
--libraryId YOUR_TITLE_LIBRARY_ID \
--objectId YOUR_MEZ_OBJECT_ID \
--offeringKey THE_OFFERING_NAME \
--width THE_NEW_WIDTH \
--height THE_NEW_HEIGHT \
--bitrate THE_NEW_BITRATE
If you omit --offeringKey
then default
will be assumed.
Optionally, the --width
and/or --bitrate
options can be omitted, and the script will scale the existing top rung based on --height
.
Note that if you supply both --width
and --height
but the resulting aspect ratio would differ more than 5% from the existing top rung's aspect ratio the script will halt with an error. If you would like to add anyway, add --ignoreAspectRatio
to the command.
Note also that only lower quality rungs can be added to an existing Offering. The new rung's bitrate must be lower than the existing top rung, and height and width must be less than or equal to the existing top rung.
For example, if your top rung is 1920x1080 @ 9,500,000 bps:
OK:
1920x1080 @ 7,000,000 bps
1280x720 @ 7,000,000 bps
Not OK:
1920x1080 @ 12,000,000 bps (bitrate must be less than top rung)
3840x2160 @ 7,000,000 bps (height and width must be equal to or smaller than top rung)
1280x720 @ 9,500,000 bps (bitrate must be less than top rung)
Note that in special cases, your Offering's video stream may not be named video
- if this is the case, use --streamKey STREAM_NAME
to specify the actual name of the stream. (You can use the OfferingListRungs.js
script to see the names of your Offering's streams)
The OfferingRemoveVideoRung.js
script will allow you to remove an existing rung from an Offering's video resolution ladder:
node testScripts/OfferingRemoveVideoRung.js \
--libraryId YOUR_TITLE_LIBRARY_ID \
--objectId YOUR_MEZ_OBJECT_ID \
--offeringKey THE_OFFERING_NAME \
--rungKey THE_RUNG_NAME
If you omit --offeringKey
then default
will be assumed.
To look up the value of --rungKey
, use the OfferingListRungs.js
script (see above). Video rungs are generally named "video_WIDTHxHEIGHT@BITRATE", e.g.: video_1280x720@4500000
, but this is not guaranteed - use the OfferingListRungs.js
script to show all the rung names.
You are not allowed to remove the top rung from the ladder, if you try the script will halt with an error.
Note that in special cases, your Offering's video stream may not be named video
- if this is the case, use --streamKey STREAM_NAME
to specify the actual name of the stream. (You can use the OfferingListRungs.js
script to see the names of your Offering's streams)
In the case where the source has left and right audio stored individually as mono streams, adding a stereo stream requires using the VariantAddStream.js
script and specifying the stream indexes to use, as well as the mapping type 2MONO_1STEREO.
For example, The following assumes that your source audio streams are in file 'MyMovie.mp4', at stream indexes 1 and 2, is English, and should be the default audio choice.
node testScripts/VariantAddStream.js \
--libraryId ilib3t4Cf8pdxftVcc4Si35yZxPgN33 \
--objectId iq__3RVmL1WdnVj7mYrKZcDUPpzstFNU \
--variantKey default \
--streamKey audio \
--file MyMovie.mp4 \
--label English \
--language en \
--streamIndex 1 2 \
--mapping 2MONO_1STEREO \
--isDefault
For more detailed info on the individual options, please see Add stream to Production Master Variant
In the case where the source only has a single mono stream, adding a stereo stream is similar to the case where you have 2 mono channels (above), except that you would specify the same source stream index twice.
For example, The following assumes that your source audio stream is in file 'MyMovie.mp4', has stream index 1, is English, and should be the default audio choice.
node testScripts/VariantAddStream.js \
--libraryId ilib3t4Cf8pdxftVcc4Si35yZxPgN33 \
--objectId iq__3RVmL1WdnVj7mYrKZcDUPpzstFNU \
--variantKey default \
--streamKey audio \
--file MyMovie.mp4 \
--label English \
--language en \
--streamIndex 1 1 \
--mapping 2MONO_1STEREO \
--isDefault
For more detailed info on the individual options, please see Add stream to Production Master Variant
The following assumes that you created your Mezzanine using the abr_profile_drm.json
profile, which will result in a default
Offering that only offers DRM playback:
node testScripts/OfferingCopy.js \
--libraryId YOUR_TITLE_LIBRARY_ID \
--objectId YOUR_MEZ_OBJECT_ID \
--offeringKey default \
--targetOfferingKey clear-playout
node testScripts/OfferingAddClear.js \
--libraryId YOUR_TITLE_LIBRARY_ID \
--objectId YOUR_MEZ_OBJECT_ID \
--offeringKey clear-playout
node testScripts/OfferingRemoveDRM.js \
--libraryId YOUR_TITLE_LIBRARY_ID \
--objectId YOUR_MEZ_OBJECT_ID \
--offeringKey clear-playout
After running the above commands, you will have an additional clear-playout
Offering that has only DRM-free playout options.
Below is a table of codes and labels for some of the most commonly encountered languages. To look up a language not on this list, visit the IANA Language Subtag Registry
Note that some references may capitalize letters appearing after a dash, e.g. "pt-BR" instead of "pt-br".
| language | code | label | note |
|---|---|---|---|
| Arabic | ar | اَلْعَرَبِيَّةُ | |
| Bangla / Bengali | bn | বাংলা | |
| Chinese (Cantonese) | yue | 廣東話 | (spoken) for audio streams only |
| Chinese (Mandarin) | cmn | 普通话 | (spoken) for audio streams only |
| Chinese (Simplified) | zh-hans | 简体中文 | (written) for text streams only |
| Chinese (Traditional) | zh-hant | 繁體中文 | (written) for text streams only |
| Danish | da | Dansk | |
| Dutch | nl | Nederlands | |
| Dutch (Netherlands) | nl-nl | Nederlands | specifically as spoken/written in the Netherlands |
| English | en | English | |
| English | en-gb | English (United Kingdom) | specifically as spoken/written in the United Kingdom |
| English | en | English | |
| Finnish | fi | Suomi | |
| French | fr | Français | |
| French (Parisian) | fr-fr | Français | specifically as spoken/written in France |
| German | de | Deutsch | |
| German (Germany) | de-de | Deutsch (Deutschland) | specifically as spoken/written in Germany |
| Hebrew | he | עִבְרִית | |
| Hindi | hi | हिन्दी | |
| Indonesian | id | Bahasa Indonesia | |
| Italian | it | Italiano | |
| Japanese | ja | 日本語 | |
| Korean | ko | 한국어 | |
| Marathi | mr | मराठी | |
| Norwegian | no | Norsk | |
| Polish | pl | Polski | |
| Portuguese | pt | Português | |
| Portuguese (Brazil) | pt-br | Português (Brasil) | specifically as spoken/written in Brazil |
| Russian | ru | Русский | |
| Spanish (Castilian) | es | Español | specifically as spoken/written in Spain |
| Spanish (Latin America) | es-419 | Español (Latinoamericano) | specifically as spoken/written in Latin America |
| Swedish | sv | Svenska | |
| Telugu | te | తెలుగు | |
| Thai | th | ภาษาไทย | |
| Turkish | tr | Türkçe |


Match
Guess It
Recognise Color
Counting
Identify Animal
Spell Number
Functionality Match
Color Matching Activity
Number Matching Activity


--- layout: page title: Knockblock date: 2016-08-31 07:52:54.000000000 +02:00 type: page parent_id: '0' published: true password: '' status: publish categories: [] tags: [] meta: _edit_last: '45769764' _rest_api_published: '1' _rest_api_client_id: "-1" _publicize_job_id: '26330566625' _wpcom_is_markdown: '1' _thumbnail_id: '438' author: login: pboes email<EMAIL_ADDRESS>display_name: pboes first_name: '' last_name: '' permalink: "/portfolio/knockblock/" ---
Knockblock is an installation that asks for the kind for cultural narrative that is necessary for a magic of digital spaces. The knock block is a plexiglass box of dimensions 13x11x21cm in the middle of which sits a block of wood and a solenoid hammer connected to an Arduino. It tracks tweets and knocks on wood whenever a tweet contains a phrase that usually evokes a "knock-on-wood"-gesture. The corresponding, anonymized tweets are displayed on a wall next to the knockblock.
[gallery ids="437,436,425,439" type="rectangular"]
The installation thematises the ontological status of digital objects, its vantage point being the common intuition that writing "knock knock" or something similar in a tweet is not sufficient to achieve the apotropaic effect of deflecting harm. The underlying thesis to knockblock is that, since magic always invocates powers beyond human, in order to figure in societal rituals as credible material representations with magical powers, objects require transcendent qualities, an ontological independence. Physical objects gain this independence by not subsuming to the mere will of humans - rocks scratch, wood splinters, water drowns. It is the absence of this kind of recalcitrance to digital objects that disqualifies them from the viewpoint of superstition.
How can digital objects develop this kind of credible otherness in order to allow for a magic of digital spaces? Or will we all end up renting our private knockblock, like our cloud space today, effectively outsourcing the physical aspect of our digital existence?
I wrote a longer post on these questions here and am glad to have been asked to publish the text also on the Vibrant Ecologies blog. The knock block itself I built using my sound carpet.
https://www.youtube.com/watch?v=Bv33IueR1ZQ


On me ...
Following Jay, On me, 14 March 2014, I have the following things on me.
Pockets
Front right: Brown wallet (ANZ cards, one not activated, ASP card, driver’s license, university card, $40 cash, a Myki, two hand-made business cards, one receipt written in Arabic, two “You are not alllowed to pass until you decide about your future” pieces of paper, Burstin and Partners business card, Biarri business card, ANZ business card, Spudbar card with free potato waiting, receipt for bike repairs, I.R.L. shooter business card, Electron Workshop business card, driver’s license renewal document, colour run sticker, tiny tiny notebook for phone numbers with one number in it (a hairdresser), Castro’s coffee card, and about 5 “You are not allowed to pass…” notes in a hidden compartment).
Because I am sitting at my desk, I don’t have my keys or phone in my pocket, so I exclude those from consideration.
Front left: Handkerchief.
Back pockets: Empty.
Backpack
Front pocket: Handerchieft, and a small rock.
Second front pocket: Assortment of Allen keys, portable box of personal grooming things (nail clippers, etc), several paper “clamps”? $13.30 in coins from Australia.
Main pocket: Several pieces of scrap paper, more paper clamps, a bottle cap, “Approximation Algorithms”, a single bandaid, panadol, and a purple pencil.


The review wizard's proof navigation page shows the list of statements in the semi-formal proof argument. This navigation page is used to raise details about each statement in the opposing pane.
Select a statement in the navigation pane to raise its details in the opposing pane. There are two kinds of detail pages available: one for the proof statement (the first or Theorem line) and one for the supporting statements. Each statement line will show its validation status (valid, invalid, or unknown) as the icon associated with the statement. Typically a review wizard session will focus on eliminating invalid and unknown status flags. Use the validation buttons on the details pages to change these flags.
The review panes normally are opposed left-to-right, but using the layout buttons in the top right-hand corner of the wizard dialog one can choose a top-to-bottom orientation.


|
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object com.opentok.android.Publisher
public abstract class Publisher
A publisher captures an audio-video stream from the device's microphone and camera. Create a Publisher instance
by calling the Publisher.newInstance()
static method.
When the view of a Publisher leaves the active window, the Publisher object is destroyed. This is the case for
an activity that is stopped or paused. Also, you should disconnect a session when its activity is stopped or paused
due to the app becoming inactive (going into the background). You can then reconnect when the activity resumes.
(See the Session.connect()
and Session.disconnect()
methods.) When the activity resumes and the window is active, you can create a new Publisher object and publish to
the session.
| Nested Class Summary | |
|---|---|
static interface |
Publisher.Listener
Monitors state changes in a Publisher object. |
| Method Summary | |
|---|---|
abstract void |
destroy()
Releases this object, including all hardware and UI resources bound to it. |
abstract int |
getCameraId()
Returns the currently active camera ID. |
Publisher.Listener |
getListener()
Returns the listener that was bound to this publisher by setListener(Listener) . |
java.lang.String |
getName()
The stream name. |
abstract boolean |
getPublishAudio()
Returns true if the Publisher is publishing audio; false if it is not. |
abstract boolean |
getPublishVideo()
Returns true if the Publisher is publishing video; false if it is not. |
Session |
getSession()
Returns the Session associated this instance. |
abstract View |
getView()
Returns the View object that contains the Publisher video. |
static Publisher |
newInstance(Context context)
Creates a new Publisher instance. |
abstract boolean |
setCameraId(int cameraId)
Set the desired camera. |
void |
setListener(Publisher.Listener listener)
Binds a Publisher.Listener to this Publisher instance to monitor state changes. |
abstract void |
setName(java.lang.String name)
Set the name for this stream. |
abstract void |
setPublishAudio(boolean publishAudio)
Whether to publish audio or not. |
abstract void |
setPublishVideo(boolean publishVideo)
Whether to publish video or not. |
abstract void |
swapCamera()
Cycles between cameras, if there are multiple cameras on the device. |
| Methods inherited from class java.lang.Object |
|---|
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
| Method Detail |
|---|
public static Publisher newInstance(Context context)
Session.publish()
method
to start streaming from this Publisher into a session.
The getView()
method returns the android.view.View object containing the published video.
Publishers cannot be reused
When the view of a Publisher leaves the active window, the Publisher object is destroyed. This is the case for
an activity that is stopped or paused. Also, you should disconnect a session when its activity is stopped or paused
due to the app becoming inactive (going into the background). You can then reconnect when the activity resumes.
(See the Session.connect()
and Session.disconnect()
methods.) When the activity resumes and the window is active, you can create a new Publisher object and publish to
the session.
context
- The android.content.Context
for the Publisher.
null
if an error occurs.public abstract void destroy()
public abstract void swapCamera()
Publisher.Listener.onPublisherChangedCamera(int)
method is called.
public abstract boolean setCameraId(int cameraId)
cameraId
can be a value between 0 and
Camera#getNumberOfCameras()
- 1.
When the camera used by the Publisher changes, the Publisher.Listener.onPublisherChangedCamera(int)
method is called.
cameraId
- the id of the camera you want to use on this publisher
true
if the change is accepted.public abstract int getCameraId()
setCameraId(int)
is never called,
the return value is 1 (for the front-facing camera).
public void setListener(Publisher.Listener listener)
Publisher.Listener
to this Publisher instance to monitor state changes.
listener
- The Publisher.Listener
that will monitor this instance, or null to disconnect a listener.public Publisher.Listener getListener()
setListener(Listener)
.
listener
bound to this publisher.public Session getSession()
Session
associated this instance.
Session
associated this instance.public abstract boolean getPublishVideo()
public abstract boolean getPublishAudio()
public abstract void setPublishVideo(boolean publishVideo)
publishVideo
- Whether to publish video (true) or not (false)public abstract void setPublishAudio(boolean publishAudio)
publishAudio
- Whether to publish audio (true) or not (false)public java.lang.String getName()
public abstract void setName(java.lang.String name)
Publisher.Listener.onPublisherStreamingStarted()
method is called. Setting the property after the Publisher.Listener.onPublisherStreamingStarted()
method is called has no effect on the name displayed for the stream.
The default name is "" (an empty string).
public abstract View getView()
View
object that contains the Publisher video.
|
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |


Second panel content goes here...
| Button | class="" | Description |
|---|---|---|
button primary |
Provides extra visual weight and identifies the primary action in a set of buttons | |
button primary-dark |
Provides extra visual weight and identifies the primary action in a set of buttons | |
button secondary |
Standard gray button with gradient | |
button highlight |
To highlight some extraordinary action | |
button highlight-dark |
To highlight some extraordinary action | |
button info |
Used as an alternative to the default styles | |
button info-dark |
Used as an alternative to the default styles | |
button success |
Indicates a successful or positive action | |
button success-dark |
Indicates a successful or positive action | |
button success-darker |
Indicates a successful or positive action | |
button success-darkest |
Indicates a successful or positive action | |
button warning |
Indicates caution should be taken with this action | |
button warning-dark |
Indicates caution should be taken with this action | |
button alert |
Indicates a dangerous or potentially negative action | |
button alert-dark |
Indicates a dangerous or potentially negative action | |
button inverse |
Alternate dark gray button, not tied to a semantic action or use | |
button inverse-dark |
Alternate dark gray button, not tied to a semantic action or use |
| Button | class="" | Description |
|---|---|---|
button tiny |
Tiny Button | |
button small |
Small Button | |
button |
Regular Button | |
button large |
Large Button |
| Button | class="" | Description |
|---|---|---|
button radius |
Radius Button | |
button round |
Round Button | |
button disabled |
Disabled Button |
This is a paragraph. Paragraphs are preset with a font size, line height and spacing to match the overall vertical rhythm. To show what a paragraph looks like this needs a little more content so, did you know that there are storms occurring on Jupiter that are larger than the Earth? Pretty cool. Wrap
around type to make it bold!. You can also use
to italicize your words.
Links are very standard, and the color is preset to the Foundation primary color.
Lists are helpful for, well, lists of things.
Sometimes other people say smart things, and you may want to mention that through a blockquote callout. We've got you covered.
I do not fear computers. I fear the lack of them. Maecenas faucibus mollis interdum. Aenean lacinia bibendum nulla sed consectetur.Isaac Asimov
Here's a handy microformat-friendly list to address all your needs.
Regular Label
Radius Secondary Label
Round Alert Label
Success Label
It has an easy to override visual style, and is appropriately subdued.
It's a little ostentatious, but useful for important content.
| Table Header | Table Header | Table Header | Table Header |
|---|---|---|---|
| Content Goes Here | This is longer content Donec id elit non mi porta gravida at eget metus. | Content Goes Here | Content Goes Here |
| Content Goes Here | This is longer Content Goes Here Donec id elit non mi porta gravida at eget metus. | Content Goes Here | Content Goes Here |
| Content Goes Here | This is longer Content Goes Here Donec id elit non mi porta gravida at eget metus. | Content Goes Here | Content Goes Here |
"Tip-top" (hehe), "tip-left", or "tip-right"


Sorry, your browser needs to support canvas for this game.
Правила на играта.
Choose category
Movies
Towns
Soccer Teams
Animals
I'm Ready !
Incorrect guesses:


Banners
Managing Banners
Managing banners is done by accessing the Settings > Banners > Search Banners function in the control panel menu.
From this interface you can add new banners and search, edit, or delete the existing banners. For an overview of searching,
adding, editing, and deleting items, please see the Control Panel Basics section of this software manual.
Database Fields
Banners have the following fields associated with them:
Uploading Content
-
Banner ID - The ID number assigned to the banner. ID numbers are generated in sequential order automatically by the software.
Sponsor - The sponsor associated with this banner
Zone - The zone in which this banner can be displayed. Zones can be any text string that you like, and will be used with the zone attribute of the {banner} template function. For example, if you wanted to restrict the banners that are displayed directly under the search bar you might use a zone named "Under Search Bar". All banners that you want to be able to appear in that location should be assigned the same Zone.
Then in your site templates you can use a {banner} function like so:
Tags - The tags that have been assigned to the banner. The tags attribute of the {banner} template function can be used to select only banners with specific tags
Times Displayed - The number of times this banner has been selected for display
Banner HTML - The complete HTML code to use for this banner. Within this HTML code there are some template variables that you can utilize:
{$upload_file}
See the Uploading Content section below for a complete description.
{$sponsor_url}
If you have selected a sponsor for this banner, this value will be replaced by the URL associated with that sponsor.
When adding or editing a banner you have the option to upload some content which will be associated with the banner. This is useful if you want to upload an image file,
a swf flash file, or anything else. When uploading content it is necessary to use the special template variable {$upload_file} in the Banner HTML value
to specify where you want the URL of the uploaded content to be placed.
For example, assume you are uploading a JPEG image named banner.jpg. You would select that file to be the upload content and for the Banner HTML you would use something like this:
The software will process the file that you upload and replace the {$upload_file} template variable with the correct path to the uploaded file.
For example, assume you are uploading a JPEG image named banner.jpg. You would select that file to be the upload content and for the Banner HTML you would use something like this:


Welcome to kdepeakprops’s documentation!¶
Brief description¶
A module to get some basic properties of a KDE peak: peak location, FWHM and its upper and lower bounds. The KDE is estimated with sklearn.neighbors.KernelDensity.
kdepeakprops.kde_props
takes a 1D array of values and returns an array
with the KDE peak properties (value, FWHM, upp, low) and another (2D
array) with the KDE samples.
Contents¶
Install¶
cd /path/to/install/dir
git clone https://github.com/iskren-y-g/kdepeakprops.git
Add path or
import sys
sys.path.insert(0,'/path/to/install/dir')</code>
API main¶
-
kdepeakprops.kdepeakprops.
kde_props
(x, nbins='doane', n_samples=1000, show=False)[source]¶ Estimation of KDE peak properties: FWHM and its upper and lower bounds. It uses the scikit-learn KDE estimator.
- Parameters
x (array_like) – The 1D data array.
nbins (int or str, default: 'doane') –
Number of bins to generate histogram and scale the KDE cernel. If a str, it must be one of the numpy.histogram_bin_edges bin calculation algorithms: auto, fd, doane, scott, stone, rice, sturges, sqrt.
Details in numpy.histogram_bin_edges: https://numpy.org/doc/stable/reference/generated/numpy.histogram_bin_edges.html.
n_samples (int, default: 1000) – Number of samples for the KDE
show (bool, default: False) – Plot the result
- Returns
kde_peak_prop (1D array) – The properties of the KDE peak value, FWHM, upper and lower bounds.
kde_xy (2D array) – The KDE samples for manual plotting.


multiray.js
- JavaScript ray-tracing
Randomized Scene
Your browser does not support the HTML5 canvas1 tag.


A and D to move left/right, click character to jump. Keys give points, sawblades make you lose HP.
SCORE: 0
HP: 10


- Temperature
-
See the sensor data page for display of the
current temperature value reported by the temperature sensor.
- Sensor Configuration
-
See the sensor configuration page to define
the characteristics and operating parameters for the sensor hardware.
- Wifi Configuration
-
See the wifi network configuration page
to define the values for establishing a wifi connection.
- Upload File
-
See the file upload page to upload
a file to the web server.
|


I recently updated my dependency on the excellent XCGLogger and noticed that in the jump from major version 4 to 6, a new log level appeared: SEVERE
. Now, I already had a hard time when deciding between certain log levels for certain situations. The first rule in SOLID, separation of concerns, lends a helping hand by contextualizing our logs instead of overloading the spectrum of priority.
XCGLogger, and CocoaLumberjack before it, had 5 levels: verbose, debug, info, warn and error. Here are some loose rules I have for how to choose which level to use:
VERBOSE
: outputting the values of variables and large data structures.DEBUG
: function invocations to trace execution, additional context in hairy routines, maybe outputting values.INFO
: general events describing usage, e.g. “navigated to such and such screen” or “pressed such and such button”.WARN
: execution has left the happy path, but code exists to recover gracefully so that the app can proceed in a previous good state with minimal UX detour (e.g. showing the user a dialog).ERROR
: a problem that will cause data loss, UX breakage, or otherwise require user intervention up to a forced relaunch of the application. I like to know about these early and aggregate them, so I use Fabric’s nonfatal error reporting as part of logging at this level.That being said, I have found exceptions to every rule, and often have trouble deciding which level to use. Usually though, the best indicator is how fast you’re able to sift through your own logs–or more painfully, what you’re missing.
I don’t think I’m alone in my confusion. All sorts of blog posts have been written on the subject, outlining the author’s preferences and rules just as I have above. Of course, there’s plenty of discussion on Stack Overflow too.
As if it were bad enough trying to choose a log level, not all logging frameworks have the same amount of levels, or call equivalent levels by the same name:
ALL
instead of VERBOSE
and an extra level in between that and DEBUG
called TRACE
. ALL
seems redundant in a system where log levels are ranked and you could just choose the most permissive level, so I like VERBOSE
more here. I do like the idea of TRACE
, but having to stick it in a rank between DEBUG
and VERBOSE
doesn’t seem like an easy fit.OFF
and ALL
), including FINE
, FINER
and FINEST
, and developers can add custom levels. I would YAGNI a few of these into oblivion if I had my way, and instead of custom levels I prefer having individual contexts that can each have its own log level or on/off switch.Individual contexts help relieve the need for more and more log levels. Adding levels seems like an attempt to cut through high amounts of noise to get to what’s really important. We want to minimize log size on disk while capturing essential information. Moving away from a monolithic log helps more here than adding log levels: it affords much more flexibility without adding more cognitive overhead at each call site.
In Trgnmtry, I had a need to log the CGPoint of a touch as it was dragging around the screen. This output a large amount of information to the log. At first I debated myself whether to log these at debug or verbose levels, but then it occurred to me that I could log them independently, using a different instance of my logging class. Now if I need to see those logs again I can flip them on and off independently without worrying about other information I might suppress or unleash.
For now, I’m not spending time working in a new log level. Hopefully it’s helping folks out there instead of making things less clear. At least for now they won’t have to muck with creating customizations, which would require way more magical Swift code to write with type safety.
🙏🏻 Enjoy the post? Please help support more like it by buying me a cup of coffee!.
💡 Suggestions, questions, comments? Please submit a PR!.