Supporting authentication and authorization in your mobile app
Configuring your server for authentication and authorization using Keycloak
Using the Identity Management service and the @aerogear/voyager-keycloak module, it is possible to add security to a Voyager Server application.
The @aerogear/voyager-keycloak
module provides the following features out of the box:
-
Authentication - Ensure only authenticated users can access your server endpoints, including the main GraphQL endpoint.
-
Authorization - Use the
@hasRole()
directive within the GraphQL schema to implement role based access control (RBAC) on the GraphQL level. -
Integration with GraphQL context - Use the
context
object within the GraphQL resolvers to access user credentials and several helper functions.
-
There is a Keycloak service available.
-
You must add a valid
keycloak.json
config file to your project.-
Create a client for your application in the Keycloak administration console.
-
Click on the Installation tab.
-
Select Keycloak OIDC JSON for Format option, and click Download.
-
Protecting Voyager Server using Keycloak
-
Import the
@aerogear/voyager-keycloak
moduleconst { KeycloakSecurityService } = require('@aerogear/voyager-keycloak')
-
Read the Keycloak config and pass it to initialise the
KeycloakSecurityService
.const keycloakConfig = JSON.parse(fs.readFileSync(path.resolve(__dirname, './path/to/keycloak.json'))) const keycloakService = new KeycloakSecurityService(keycloakConfig)
-
Use the
keycloakService
instance to protect your app:const app = express() keycloakService.applyAuthMiddleware(app)
-
Configure the Voyager server so that the
keycloakService
is used as the security service:const voyagerConfig = { securityService: keycloakService } const server = VoyagerServer(apolloConfig, voyagerConfig)
The Keycloak Example Server Guide has an example server based off the instructions above and shows all of the steps needed to get it running.
Using the hasRole directive in a schema
The Voyager Keycloak module provides the @hasRole
directive to define role based authorisation in your schema. The @hasRole
directive is a special annotation that can be applied to
-
Fields
-
Queries
-
Mutations
-
Subscriptions
The @hasRole
usage is as follows:
-
@hasRole(role: String)
-
Example -
@hasRole(role: "admin"])
-
If the authenticated user has the role
admin
they will be authorized. -
@hasRole(role: [String])
-
Example -
@hasRole(role: ["admin", "editor"])
-
If the authenticated user has at least one of the roles in the list, they will be authorized.
The default behaviour is to check client roles. For example, @hasRole(role: "admin")
will check that user has a client role called admin
. @hasRole(role: "realm:admin")
will check if that user has a realm role called admin
The syntax for checking a realm role is @hasRole(role: "realm:<role>")
. For example, @hasRole(role: "realm:admin")
. Using a list of roles, it is possible to check for both client and realm roles at the same time.
The following example demonstrates how the @hasRole
directive can be used to define role based authorization on various parts of a GraphQL schema. This example schema represents publishing application like a news or blog website.
type Post {
id: ID!
title: String!
author: Author!
content: String!
createdAt: Int!
}
type Author {
id: ID!
name: String!
posts: [Post]!
address: String! @hasRole(role: "admin")
age: Int! @hasRole(role: "admin")
}
type Query {
allPosts:[Post]!
getAuthor(id: ID!):Author!
}
type Mutation {
editPost:[Post]! @hasRole(role: ["editor", "admin"])
deletePost(id: ID!):[Post] @hasRole(role: "admin")
}
There are two types:
-
Post
- This might be an article or a blog post -
Author
- This would represent the person that authored a Post
There are two Queries:
-
allPosts
- This might return a list of posts -
getAuthor
- This would return details about an Author
There are two Mutations:
-
editPost
- This would edit an existing post -
deletePost
- This would delete a post.
In the example schema, the @hasRole
directive has been applied to the editPost
and deletePost
mutations. The same could be done on Queries.
-
Only users with the roles
editor
and/oradmin
are allowed to perform theeditPost
mutation. -
Only users with the role
admin
are allowed to perform thedeletePost
mutation.
This example shows how the @hasRole
directive can be used on various queries and mutations.
In the example schema, the Author
type has the fields address
and age
which both have hasRole(role: "admin")
applied.
This means that users without the role admin
are not authorized to request these fields in any query or mutation.
For example, non admin users are allowed to run the getAuthor
query, but they cannot request back the address
or age
fields.
Authentication Over Websockets using Keycloak
Prerequisites:
This section describes how to implement Authentication and Authorization over websockets with Keycloak. For more generic documentation on Authentication over Websockets, read Apollo’s Authentication Over Websocket document.
The Voyager Client supports adding token information to connectionParams
that will be sent with the first WebSocket message. In the server, this token is used to authenticate the connection and to allow the subscription to proceeed. Read the section on Keycloak Authentication in Voyager Client to ensure the Keycloak token is being sent to the server.
In the server, createSubscriptionServer
accepts a SecurityService
instance in addition to the regular options that can be passed to a standard SubscriptionServer
. The KeycloakSecurityService
from @aerogear/voyager-keycloak
is used to validate the Keycloak token passed by the client in the initial WebSocket message.
const { createSubscriptionServer } = require('@aerogear/voyager-subscriptions')
const { KeycloakSecurityService } = require('@aerogear/voyager-keycloak')
const keycloakConfig = require('./keycloak.json') // typical Keycloak OIDC installation
const apolloServer = VoyagerServer({
typeDefs,
resolvers
})
securityService = new KeycloakSecurityService(keycloakConfig)
const app = express()
keycloakService.applyAuthMiddleware(app)
apolloServer.applyMiddleware({ app })
const server = app.listen({ port }, () =>
console.log(`🚀 Server ready at http://localhost:${port}${apolloServer.graphqlPath}`)
createSubscriptionServer({ schema: apolloServer.schema }, {
securityService,
server,
path: '/graphql'
})
)
The example shows how the Keycloak securityService
is created and how it is passed into createSubscriptionServer
. This enables Keycloak authentication on all subscriptions.
Keycloak Authorization in Subscriptions
The Keycloak securityService
will validate and parse the token sent by the client into a Token Object. This token is available in Subscription resolvers with context.auth
and can be used to implement finer grained role based access control.
const resolvers = {
Subscription: {
taskAdded: {
subscribe: (obj, args, context, info) => {
const role = 'admin'
if (!context.auth.hasRole(role)) {
return new Error(`Access Denied - missing role ${role}`)
}
return pubSub.asyncIterator(TASK_ADDED)
}
},
}
The above example shows role based access control inside a subscription resolver. context.auth
is a full Keycloak Token Object which means methods like hasRealmRole
and hasApplicationRole
are available.
The user details can be accessed through context.auth.content
. Here is an example.
{ "jti": "dc1d6286-c572-43c1-99c7-4f36982b0e56", "exp":<PHONE_NUMBER>, "nbf": 0, "iat":<PHONE_NUMBER>, "iss": "http://localhost:8080/auth/realms/voyager-testing", "aud": "voyager-testing-public", "sub": "57e1dcda-990f-4cc2-8542-0d1f9aae302b", "typ": "Bearer", "azp": "voyager-testing-public", "nonce": "552c3cba-a6c2-490a-9914-28784ba0e4bc", "auth_time":<PHONE_NUMBER>, "session_state": "ed35e1b4-b43c-438f-b1a3-18b1be8c6307", "acr": "0", "allowed-origins": [ "*" ], "realm_access": { "roles": [ "developer", "uma_authorization" ] }, "resource_access": { "voyager-testing-public": { "roles": [ "developer" ] }, "account": { "roles": [ "manage-account", "manage-account-links", "view-profile" ] } }, "preferred_username": "developer" }
Having access to the user details (e.g. context.auth.content.sub
is the authenticated user’s ID) means it is possible to implement Subscription Filters and to subscribe to more fine grained pubsub topics based off the user details.
Implementing authentication and authorization on your client
With Voyager Client, user information can be passed to a Data Sync server application in two ways: headers or tokens.
Headers are used to authentication HTTP requests to the server, which are used for queries and mutations.
Tokens are used to authenticate WebSocket connections, which are used for subscriptions.
Both of them can be set via the authContextProvider
configuration option. Here is an example
//get the token value from somewhere, for example the authentication service
const token = "REPLACE_WITH_REAL_TOKEN";
const config = {
...
authContextProvider: function() {
return {
header: {
"Authorization": `Bearer ${token}`
},
token: token
}
},
...
};
//create a new client
For information about how to perform authentication and authorization on the server, see the Server Authentication and Authorization Guide.


{{ current_user.id }}
Logout
Dashboard
Leaderboard
New Task
It's time to get things done.
View your tasks below.
My Tasks
Task
Due Date
Priority
Actions
{% for x in range(tasks.qsize()) %} {% set temp = tasks.get() %}
{{ temp.1.0 }}
{{ temp.1.1 }}
{{ -1 * temp.0 }}
Complete
Remove
{% endfor %}
Ready to Leave?
×
Select "Logout" below if you are ready to end your current session.


The Classroom Organizer - Students
Home
View Teachers
View Classes
View Students
View Grades
Add Student:
First Name:
Last Name:
Classes:
{% for c in rows[1] %}
{{ c[1]}}
{% endfor %}
Student Search by First Name
First Name:
Students:
First Name:
Last Name:
Classes
{% for r in rows[0] %}
{{ r[0][1] }}
{{ r[0][2] }}
{% for c in r[1] %}
{{ c[0][1]}}
{% if not c[1]%}
{% endif %} {% if c[1] %}
Grade: {{ c[1]}}
{% endif %}
{% endfor %}
{% endfor %}


Java: How to Program, 9th Edition (Deitel)
ISBN-13:<PHONE_NUMBER>669
ISBN-10:<PHONE_NUMBER>
Authors: Paul Deitel; Harvey Deitel
Edition: 9th
Binding: Paperback
Publisher: Prentice Hall
Published: March 2011
List Price: $164.60
ISBN-13:<PHONE_NUMBER>669
ISBN-10:<PHONE_NUMBER>
Authors: Paul Deitel; Harvey Deitel
Edition: 9th
Binding: Paperback
Publisher: Prentice Hall
Published: March 2011
List Price: $164.60


# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Code related to the PyTorch model registry for easily creating models.
"""
from typing import Any, Callable, Dict, List, NamedTuple, Tuple, Union
from torch.nn import Module
from merge_args import merge_args
from sparseml.pytorch.utils import load_model
from sparseml.utils import parse_optimization_str, wrapper_decorator
from sparseml.utils.frameworks import PYTORCH_FRAMEWORK
from sparsezoo import Zoo
from sparsezoo.objects import Model
__all__ = [
"ModelRegistry",
]
"""
Simple named tuple object to store model info
"""
_ModelAttributes = NamedTuple(
"_ModelAttributes",
[
("input_shape", Any),
("domain", str),
("sub_domain", str),
("architecture", str),
("sub_architecture", str),
("default_dataset", str),
("default_desc", str),
("repo_source", str),
("ignore_error_tensors", List[str]),
("args", Dict[str, Tuple[str, Any]]),
],
)
[docs]class ModelRegistry(object):
"""
Registry class for creating models
"""
_CONSTRUCTORS = {} # type: Dict[str, Callable]
_ATTRIBUTES = {} # type: Dict[str, _ModelAttributes]
[docs] @staticmethod
def available_keys() -> List[str]:
"""
:return: the keys (models) currently available in the registry
"""
return list(ModelRegistry._CONSTRUCTORS.keys())
[docs] @staticmethod
def create(
key: str,
pretrained: Union[bool, str] = False,
pretrained_path: str = None,
pretrained_dataset: str = None,
load_strict: bool = True,
ignore_error_tensors: List[str] = None,
**kwargs,
) -> Module:
"""
Create a new model for the given key
:param key: the model key (name) to create
:param pretrained: True to load pretrained weights; to load a specific version
give a string with the name of the version (pruned-moderate, base).
Default None
:param pretrained_path: A model file path to load into the created model
:param pretrained_dataset: The dataset to load for the model
:param load_strict: True to make sure all states are found in and
loaded in model, False otherwise; default True
:param ignore_error_tensors: tensors to ignore if there are errors in loading
:param kwargs: any keyword args to supply to the model constructor
:return: the instantiated model
"""
if key not in ModelRegistry._CONSTRUCTORS:
raise ValueError(
"key {} is not in the model registry; available: {}".format(
key, ModelRegistry._CONSTRUCTORS
)
)
return ModelRegistry._CONSTRUCTORS[key](
pretrained=pretrained,
pretrained_path=pretrained_path,
pretrained_dataset=pretrained_dataset,
load_strict=load_strict,
ignore_error_tensors=ignore_error_tensors,
**kwargs,
)
[docs] @staticmethod
def create_zoo_model(
key: str,
pretrained: Union[bool, str] = True,
pretrained_dataset: str = None,
) -> Model:
"""
Create a sparsezoo Model for the desired model in the zoo
:param key: the model key (name) to retrieve
:param pretrained: True to load pretrained weights; to load a specific version
give a string with the name of the version (optim, optim-perf), default True
:param pretrained_dataset: The dataset to load for the model
:return: the sparsezoo Model reference for the given model
"""
if key not in ModelRegistry._CONSTRUCTORS:
raise ValueError(
"key {} is not in the model registry; available: {}".format(
key, ModelRegistry._CONSTRUCTORS
)
)
attributes = ModelRegistry._ATTRIBUTES[key]
optim_name, optim_category, optim_target = parse_optimization_str(
pretrained if isinstance(pretrained, str) else attributes.default_desc
)
return Zoo.load_model(
attributes.domain,
attributes.sub_domain,
attributes.architecture,
attributes.sub_architecture,
PYTORCH_FRAMEWORK,
attributes.repo_source,
attributes.default_dataset
if pretrained_dataset is None
else pretrained_dataset,
None,
optim_name,
optim_category,
optim_target,
)
[docs] @staticmethod
def register(
key: Union[str, List[str]],
input_shape: Any,
domain: str,
sub_domain: str,
architecture: str,
sub_architecture: str,
default_dataset: str,
default_desc: str,
repo_source: str = "sparseml",
def_ignore_error_tensors: List[str] = None,
desc_args: Dict[str, Tuple[str, Any]] = None,
):
"""
Register a model with the registry. Should be used as a decorator
:param key: the model key (name) to create
:param input_shape: the specified input shape for the model
:param domain: the domain the model belongs to; ex: cv, nlp, etc
:param sub_domain: the sub domain the model belongs to;
ex: classification, detection, etc
:param architecture: the architecture the model belongs to;
ex: resnet, mobilenet, etc
:param sub_architecture: the sub architecture the model belongs to;
ex: 50, 101, etc
:param default_dataset: the dataset to use by default for loading
pretrained if not supplied
:param default_desc: the description to use by default for loading
pretrained if not supplied
:param repo_source: the source repo for the model, default is sparseml
:param def_ignore_error_tensors: tensors to ignore if there are
errors in loading
:param desc_args: args that should be changed based on the description
:return: the decorator
"""
if not isinstance(key, List):
key = [key]
def decorator(const_func):
wrapped_constructor = ModelRegistry._registered_wrapper(key[0], const_func)
ModelRegistry.register_wrapped_model_constructor(
wrapped_constructor,
key,
input_shape,
domain,
sub_domain,
architecture,
sub_architecture,
default_dataset,
default_desc,
repo_source,
def_ignore_error_tensors,
desc_args,
)
return wrapped_constructor
return decorator
[docs] @staticmethod
def register_wrapped_model_constructor(
wrapped_constructor: Callable,
key: Union[str, List[str]],
input_shape: Any,
domain: str,
sub_domain: str,
architecture: str,
sub_architecture: str,
default_dataset: str,
default_desc: str,
repo_source: str,
def_ignore_error_tensors: List[str] = None,
desc_args: Dict[str, Tuple[str, Any]] = None,
):
"""
Register a model with the registry from a model constructor or provider function
:param wrapped_constructor: Model constructor wrapped to be compatible
by call from ModelRegistry.create should have pretrained, pretrained_path,
pretrained_dataset, load_strict, ignore_error_tensors, and kwargs as
arguments
:param key: the model key (name) to create
:param input_shape: the specified input shape for the model
:param domain: the domain the model belongs to; ex: cv, nlp, etc
:param sub_domain: the sub domain the model belongs to;
ex: classification, detection, etc
:param architecture: the architecture the model belongs to;
ex: resnet, mobilenet, etc
:param sub_architecture: the sub architecture the model belongs to;
ex: 50, 101, etc
:param default_dataset: the dataset to use by default for loading
pretrained if not supplied
:param default_desc: the description to use by default for loading
pretrained if not supplied
:param repo_source: the source repo for the model; ex: sparseml, torchvision
:param def_ignore_error_tensors: tensors to ignore if there are
errors in loading
:param desc_args: args that should be changed based on the description
:return: The constructor wrapper registered with the registry
"""
if not isinstance(key, List):
key = [key]
for r_key in key:
if r_key in ModelRegistry._CONSTRUCTORS:
raise ValueError("key {} is already registered".format(key))
ModelRegistry._CONSTRUCTORS[r_key] = wrapped_constructor
ModelRegistry._ATTRIBUTES[r_key] = _ModelAttributes(
input_shape,
domain,
sub_domain,
architecture,
sub_architecture,
default_dataset,
default_desc,
repo_source,
def_ignore_error_tensors,
desc_args,
)
@staticmethod
def _registered_wrapper(
key: str,
const_func: Callable,
):
@merge_args(const_func)
@wrapper_decorator(const_func)
def wrapper(
pretrained_path: str = None,
pretrained: Union[bool, str] = False,
pretrained_dataset: str = None,
load_strict: bool = True,
ignore_error_tensors: List[str] = None,
*args,
**kwargs,
):
"""
:param pretrained_path: A path to the pretrained weights to load,
if provided will override the pretrained param
:param pretrained: True to load the default pretrained weights,
a string to load a specific pretrained weight
(ex: base, optim, optim-perf),
or False to not load any pretrained weights
:param pretrained_dataset: The dataset to load pretrained weights for
(ex: imagenet, mnist, etc).
If not supplied will default to the one preconfigured for the model.
:param load_strict: True to raise an error on issues with state dict
loading from pretrained_path or pretrained, False to ignore
:param ignore_error_tensors: Tensors to ignore while checking the state dict
for weights loaded from pretrained_path or pretrained
"""
attributes = ModelRegistry._ATTRIBUTES[key]
if attributes.args and pretrained in attributes.args:
kwargs[attributes.args[pretrained][0]] = attributes.args[pretrained][1]
model = const_func(*args, **kwargs)
ignore = []
if ignore_error_tensors:
ignore.extend(ignore_error_tensors)
elif attributes.ignore_error_tensors:
ignore.extend(attributes.ignore_error_tensors)
if isinstance(pretrained, str):
if pretrained.lower() == "true":
pretrained = True
elif pretrained.lower() in ["false", "none"]:
pretrained = False
if pretrained_path:
load_model(pretrained_path, model, load_strict, ignore)
elif pretrained:
zoo_model = ModelRegistry.create_zoo_model(
key, pretrained, pretrained_dataset
)
try:
paths = zoo_model.download_framework_files(extensions=[".pth"])
load_model(paths[0], model, load_strict, ignore)
except Exception:
# try one more time with overwrite on in case file was corrupted
paths = zoo_model.download_framework_files(
overwrite=True, extensions=[".pth"]
)
load_model(paths[0], model, load_strict, ignore)
return model
return wrapper


Data & Data Products: How’s My Waterway Widget
Explore your water with How’s My Waterway. Enter a location to find out about water quality anywhere in the US. How’s My Waterway answers questions about the health of waters in supporting swimming, the eating of fish, drinking water protection and delivery, the health of aquatic communities, and the restoration and protection of waterways.


Bugs in Polly
Polly uses the LLVM bug tracking system.
File a Bug
If a problem appears, please
report a bug to the LLVM bugzilla. Polly bugs are tracked under product
'Projects' and component 'Polly'.
Open Bugs
A list of the
open
bugs in Polly is also available.


Not only java or jsp files have the problem of having to load resources. Resource loading is universal and not only limited to the domain of java or its derived technologies.
Resources can be loaded also by resource files. Weblets
as universal solution to resource loading provides the hooks for CSS and javascript for authors who have to deal with the problem of having to load or reference resources in a neutral way.
The Weblets APIs follow the general patterns as described in Weblets Users Guide: Introduction to the API Patterns . for further information please follow the link.
To support resource cross referencing in a neutral manner, Weblets
adds another parsing step to generic text resources which pre-parses the resource for the occurrence of the contractual functions and then replaces them on the fly with the weblet url calls.
The browser, after the parsing step, can resolve the urls and can trigger the second weblet stage which serves the resources!
Image 0: Resource Parsing in Weblets
Now to apply this we have to have in mind that every javascript file loaded by Weblets is parsed and searched for our weblet notation. Hence we can use api functions directly without influencing the actual code.
Code 0: Javascript Usage of the weblet api
alert('weblet:url( "weblets.demo" , "/welcome.js" )'); expands to alert('/myapp/weblets/demo/welcome.js') alert("weblet:resource( 'weblets.demo' , '/welcome.js' )"); expands to alert("/weblets/demo/welcome.js")
Note: To ease the integration into various text based resource languages, the hyphenation normally found for strings was deliberately left out of the function definition!
Everything said regarding javascript also applies to CSS, following code example will showcase the features Weblets adds to CSS
Code 1: CSS Usage of the weblet api
background-image: url( weblet:resource( "weblets.demo" , "/myimage.png" ) ); will be expanded to background-image: url( /myapp/weblets/demo/myimage.png );
Basically every text resource is parsed in the parsing stage. You can use the Weblets notation in everything text based! The referencing of relative resources in Weblets as well is no problem, you still can reference resources relatively without any limitations, however you have to have in mind, that those resources are referenced relatively to the expanded weblet url. Generally spoken it is saver to simply use the weblet notation for intra weblet resource references!
Weblets resources can cross reference each other, a weblet function parser supports the direct referencing of resources via the weblet notation, out of every weblet loaded resource file.


The Gay, Lesbian, Bisexual and Transgender (GLBT) National Help Center provides vital peer-support, community connections and resource information to people with questions regarding sexual orientation and/or gender identity.
Utilizing a diverse group of GLBT volunteers, we operate two national hotlines, the
GLBT National Hotline
(888-843-4564)
and the
GLBT National Youth Talkline
(888-246-7743)
, as well as private, volunteer one-to-one online chat
(www.GLBThotline.org/chat), that helps both youth and adults with coming-out issues, safer-sex information, school bullying, family concerns, relationship problems and a lot more.
We also maintain the largest collection of resources for the GLBT community in the United States, with 15,000 local resources for cities and towns across the country.
We are the oldest and most comprehensive national organization of its type and scope in the U.S., providing this critically needed service regardless of age or geographic location.
The people who turn to us for help often live in rural and conservative parts of the country and are frequently feeling severely isolated, closeted and despairing, with literally no one else safe to talk to.
To add a resource to our database, please go to
www.GLBTnearme.org and click on
ADD TO OUR DATABASE.


bloks: engine.
r/bloks is a subreddit theme built for the new 2018 reddit redesign. It's built to be customizeable and modular, to allow you to set it up in any configuration you like.
You can use the navigation links to pinpoint exactly what you want to change, or you can use the buttons at the bottom of every page to see all of what this theme has to offer.
If you run have any questions be sure to reach out via r/bloks and I'd be happy to help.
If you run into any bugs or issues, you can reach out on r/bloks or you can open an issue on github.
Get Started!
Disables the fixed navbar.
Brings back the tabs for hot / new / top.
Next Step: Content
Disables the page margin around content/sidebar.
Margin Width
Makes NSFW Thumbnails visible.
Thumbnail Width
Thumbnail Height
Previous Step: Header
Next Step: Sidebar
Show an image at the top of the sidebar.
Sidebar Width
Subscribers Text
Online Text
Previous Step: Content
Next Step: Colors
Background
Foreground
Text
Link
Thumbnail
Upvote
Downvote
NSFW
Locked
Stickied
Preview Step: Sidebar
Next Step: Preview
bloks: preview
Previous Step: Colors
Next Step: Compile
bloks: compile
Previous Step: Preivew


Test purpose
- Create a particle world object
- Add user-defined attributes to the particle world object - check that appropriate messages print
- Create a particle Emitter entity
- Check to see that the Emitter entity can lock to the mouse cursor
- Check that particles respond to the gravity force, when applied (include gravity)
- Check the effect of changing the world object's tickMultiplier (world speed) attribute
- Change the maximum and minimum colors; check that the changes are reflected in the particle's colors (testing the Color range functionality)
- Check the effects of changing the following emitter/particle attributes: historyLength; generationRate; killAfterTime; killAfterTimeVariation; lifespan; life variation; range (x, y, z); rangeFrom (x, y, z)
- Check that the canvas backgroundColor attribute can be updated (background color)
- Navigate away from the web page (open another tab in the browser) and, a few seconds later, navigate back to the page - check that the animation resets and starts, and does not freeze the page
Touch test: should work as expected
Annotated code


:: com :: sun :: star :: sdbcx ::
|
| service Index |
- Description
- is used to specify the index for a database table. It refers to one or
more columns of a table.
Note:
All properties and columns of an index could by modified before they are appended
to a table. In that case the service is a data descriptor.
|
| Properties' Summary |
[ readonly ] string
Name |
is the name of the index.
|
[ readonly ] string
Catalog |
is the name of the index catalog, may be empty.
|
[ readonly ] boolean
IsUnique |
indicates that the index allow only unique values.
|
[ readonly ] boolean
IsPrimaryKeyIndex |
indicates that the index is used for the primary key.
|
[ readonly ] boolean
IsClustered |
indicates that the index is clustered.
|
| Properties' Details |
Name
[ readonly ] string Name;
- Description
- is the name of the index.
|
|
Catalog
[ readonly ] string Catalog;
- Description
- is the name of the index catalog, may be empty.
|
|
IsUnique
[ readonly ] boolean IsUnique;
- Description
- indicates that the index allow only unique values.
|
|
IsPrimaryKeyIndex
[ readonly ] boolean IsPrimaryKeyIndex;
- Description
- indicates that the index is used for the primary key.
|
|
IsClustered
[ readonly ] boolean IsClustered;
- Description
- indicates that the index is clustered.
|
|
Top of Page
Copyright © 2013, The Apache Software Foundation, Licensed under the Apache License, Version 2.0. Apache, the Apache feather logo, Apache OpenOffice and OpenOffice.org are trademarks of The Apache Software Foundation. Other names may be trademarks of their respective owners.


Result: (No statement)
Type any statement into the textbox above and it will be calculated and the result will be displayed above.
As of now, only addition, subtraction, multiplication, division, and exponents are supported. (It does follow the order of operations.)
It also supports prefixes:
| Prefix | Long name | Factor |
|---|---|---|
| m | milli | / 1000 |
| c | centi | / 100 |
| d | deci | / 10 |
| D | deca | * 10 |
| h | hecto | * 100 |
| k or K | kilo | * 1000 |


Parallax Demo
An experiment by Dave Gamache
Here's an example of 16 elements scaling, fading and moving at once.
Whoops! Right now this demo doesn't handle resizing or browsers less than 1000px wide. Reload this page or get on a laptop!


|
Celix
2.2.0
An implementation of the OSGi specification adapted to C and C++
|
#include <celix_bundle_context.h>
Public Attributes | |
| void *svc | OPTS_INIT |
| celix_service_factory_t *factory | OPTS_INIT |
| const char *serviceName | OPTS_INIT |
| celix_properties_t *properties | OPTS_INIT |
| const char *serviceLanguage | OPTS_INIT |
| const char *serviceVersion | OPTS_INIT |
Service Registration Options when registering services to the Celix framework.
| void* svc celix_service_registration_options::OPTS_INIT |
The service pointer. The actual pointer to the service. For C this is normally a pointer to a struct with function pointers, but theoretically this can be a pointer to anything (e.g. a pointer to a single function, or a pointer to a C++ interface implementation, or just a pointer to a data structure).
The bundle is responsible to keep the service pointer valid as long as it is registered in the Celix framework.
| celix_service_factory_t* factory celix_service_registration_options::OPTS_INIT |
The service factory pointer. Note if the factory service is set, the svc field will not be used.
The service factory will be called for every bundle requesting/de-requesting a service. This gives the provider the option to create bundle specific service instances.
When a service is requested for a bundle the getService of the factory service will be called. This function must return a valid pointer to a service conform the registered service name or NULL. When a service in no longer needed for a bundle (e.g. ending the useService(s) calls when a service tacker is stopped) the ungetService function of the service factory will be called.
The bundle is responsible to keep the service factory pointer valid as long as it is registered in the Celix framework.
| const char* serviceName celix_service_registration_options::OPTS_INIT |
The required service name. This is used to identify the service. A fully qualified name with a namespace is advisable to prevent name collision. (e.g. EXAMPLE_PRESSURE_SENSOR).
| celix_properties_t* properties celix_service_registration_options::OPTS_INIT |
The optional service properties. These contain meta information about the service in the form of string key/values. (e.g. the location of a pressure sensor: location=left-tire).
When a service is registered the Celix framework will take ownership of the provided properties. If a registration fails, the properties will be destroyed (freed) by the Celix framework.
| const char* serviceLanguage celix_service_registration_options::OPTS_INIT |
The optional service language. If this is NULL, CELIX_FRAMEWORK_SERVICE_LANGUAGE_C is used.
| const char* serviceVersion celix_service_registration_options::OPTS_INIT |
The optional service version (in the form of <MAJOR>.<MINOR>.<MICRO>.<QUALIFIER>). If present consumer of the service can specific which service version range of a specific service they are interested in. Note that it is the responsibility of the users to ensure that service in those version range are compatible (binary of source). It is advisable to use semantic versioning for this.


GridMix is a benchmark for Hadoop clusters. It submits a mix of synthetic jobs, modeling a profile mined from production loads. This version of the tool will attempt to model the resource profiles of production jobs to identify bottlenecks, guide development.
To run GridMix, you need a MapReduce job trace describing the job mix for a given cluster. Such traces are typically generated by Rumen. GridMix also requires input data from which the synthetic jobs will be reading bytes. The input data need not be in any particular format, as the synthetic jobs are currently binary readers. If you are running on a new cluster, an optional step generating input data may precede the run. In order to emulate the load of production jobs from a given cluster on the same or another cluster, follow these steps:
Locate the job history files on the production cluster. This location is specified by the mapreduce.jobhistory.done-dir or mapreduce.jobhistory.intermediate-done-dir configuration property of the cluster. (MapReduce historyserver moves job history files from mapreduce.jobhistory.done-dir to mapreduce.jobhistory.intermediate-done-dir.)
Run Rumen to build a job trace in JSON format for all or select jobs.
Use GridMix with the job trace on the benchmark cluster.
Jobs submitted by GridMix have names of the form “GRIDMIXnnnnnn”, where “nnnnnn” is a sequence number padded with leading zeroes.
Gridmix is provided as hadoop subcommand. Basic command-line usage without configuration parameters:
$ hadoop gridmix [-generate <size>] [-users <users-list>] <iopath> <trace>
Basic command-line usage with configuration parameters:
$ hadoop gridmix \ -Dgridmix.client.submit.threads=10 -Dgridmix.output.directory=foo \ [-generate <size>] [-users <users-list>] <iopath> <trace>
Configuration parameters like -Dgridmix.client.submit.threads=10 and -Dgridmix.output.directory=foo as given above should be used before other GridMix parameters.
The <iopath> parameter is the working directory for GridMix. Note that this can either be on the local file-system or on HDFS, but it is highly recommended that it be the same as that for the original job mix so that GridMix puts the same load on the local file-system and HDFS respectively.
The -generate option is used to generate input data and Distributed Cache files for the synthetic jobs. It accepts standard units of size suffixes, e.g. 100g will generate 100 * 230 bytes as input data. The minimum size of input data in compressed format (128MB by default) is defined by gridmix.min.file.size. <iopath>/input is the destination directory for generated input data and/or the directory from which input data will be read. HDFS-based Distributed Cache files are generated under the distributed cache directory <iopath>/distributedCache. If some of the needed Distributed Cache files are already existing in the distributed cache directory, then only the remaining non-existing Distributed Cache files are generated when -generate option is specified.
The -users option is used to point to a users-list file (see Emulating Users and Queues).
The <trace> parameter is a path to a job trace generated by Rumen. This trace can be compressed (it must be readable using one of the compression codecs supported by the cluster) or uncompressed. Use “-” as the value of this parameter if you want to pass an uncompressed trace via the standard input-stream of GridMix.
The supported configuration parameters are explained in the following sections.
| Parameter | Description |
|---|---|
| gridmix.output.directory | The directory into which output will be written. If specified, iopath will be relative to this parameter. The submitting user must have read/write access to this directory. The user should also be mindful of any quota issues that may arise during a run. The default is "gridmix". |
| gridmix.client.submit.threads | The number of threads submitting jobs to the cluster. This also controls how many splits will be loaded into memory at a given time, pending the submit time in the trace. Splits are pre-generated to hit submission deadlines, so particularly dense traces may want more submitting threads. However, storing splits in memory is reasonably expensive, so you should raise this cautiously. The default is 1 for the SERIAL job-submission policy (see Job Submission Policies) and one more than the number of processors on the client machine for the other policies. |
| gridmix.submit.multiplier | The multiplier to accelerate or decelerate the submission of jobs. The time separating two jobs is multiplied by this factor. The default value is 1.0. This is a crude mechanism to size a job trace to a cluster. |
| gridmix.client.pending.queue.depth | The depth of the queue of job descriptions awaiting split generation. The jobs read from the trace occupy a queue of this depth before being processed by the submission threads. It is unusual to configure this. The default is 5. |
| gridmix.gen.blocksize | The block-size of generated data. The default value is 256 MiB. |
| gridmix.gen.bytes.per.file | The maximum bytes written per file. The default value is 1 GiB. |
| gridmix.min.file.size | The minimum size of the input files. The default limit is 128 MiB. Tweak this parameter if you see an error-message like "Found no satisfactory file" while testing GridMix with a relatively-small input data-set. |
| gridmix.max.total.scan | The maximum size of the input files. The default limit is 100 TiB. |
| gridmix.task.jvm-options.enable | Enables Gridmix to configure the simulated task's max heap options using the values obtained from the original task (i.e via trace). |
GridMix takes as input a job trace, essentially a stream of JSON-encoded job descriptions. For each job description, the submission client obtains the original job submission time and for each task in that job, the byte and record counts read and written. Given this data, it constructs a synthetic job with the same byte and record patterns as recorded in the trace. It constructs jobs of two types:
| Job Type | Description |
|---|---|
| LOADJOB | A synthetic job that emulates the workload mentioned in Rumen trace. In the current version we are supporting I/O. It reproduces the I/O workload on the benchmark cluster. It does so by embedding the detailed I/O information for every map and reduce task, such as the number of bytes and records read and written, into each job's input splits. The map tasks further relay the I/O patterns of reduce tasks through the intermediate map output data. |
| SLEEPJOB | A synthetic job where each task does *nothing* but sleep for a certain duration as observed in the production trace. The scalability of the ResourceManager is often limited by how many heartbeats it can handle every second. (Heartbeats are periodic messages sent from NodeManagers to update their status and grab new tasks from the ResourceManager.) Since a benchmark cluster is typically a fraction in size of a production cluster, the heartbeat traffic generated by the slave nodes is well below the level of the production cluster. One possible solution is to run multiple NodeManagers on each slave node. This leads to the obvious problem that the I/O workload generated by the synthetic jobs would thrash the slave nodes. Hence the need for such a job. |
The following configuration parameters affect the job type:
| Parameter | Description |
|---|---|
| gridmix.job.type | The value for this key can be one of LOADJOB or SLEEPJOB. The default value is LOADJOB. |
| gridmix.key.fraction | For a LOADJOB type of job, the fraction of a record used for the data for the key. The default value is 0.1. |
| gridmix.sleep.maptask-only | For a SLEEPJOB type of job, whether to ignore the reduce tasks for the job. The default is false. |
| gridmix.sleep.fake-locations | For a SLEEPJOB type of job, the number of fake locations for map tasks for the job. The default is 0. |
| gridmix.sleep.max-map-time | For a SLEEPJOB type of job, the maximum runtime for map tasks for the job in milliseconds. The default is unlimited. |
| gridmix.sleep.max-reduce-time | For a SLEEPJOB type of job, the maximum runtime for reduce tasks for the job in milliseconds. The default is unlimited. |
GridMix controls the rate of job submission. This control can be based on the trace information or can be based on statistics it gathers from the ResourceManager. Based on the submission policies users define, GridMix uses the respective algorithm to control the job submission. There are currently three types of policies:
| Job Submission Policy | Description |
|---|---|
| STRESS | Keep submitting jobs so that the cluster remains under stress.
In this mode we control the rate of job submission by monitoring
the real-time load of the cluster so that we can maintain a stable
stress level of workload on the cluster. Based on the statistics we
gather we define if a cluster is *underloaded* or
*overloaded* . We consider a cluster *underloaded* if
and only if the following three conditions are true:
|
| REPLAY | In this mode we replay the job traces faithfully. This mode exactly follows the time-intervals given in the actual job trace. |
| SERIAL | In this mode we submit the next job only once the job submitted earlier is completed. |
The following configuration parameters affect the job submission policy:
| Parameter | Description |
|---|---|
| gridmix.job-submission.policy | The value for this key would be one of the three: STRESS, REPLAY or SERIAL. In most of the cases the value of key would be STRESS or REPLAY. The default value is STRESS. |
| gridmix.throttle.jobs-to-tracker-ratio | In STRESS mode, the minimum ratio of running jobs to NodeManagers in a cluster for the cluster to be considered *overloaded* . This is the threshold TJ referred to earlier. The default is 1.0. |
| gridmix.throttle.maps.task-to-slot-ratio | In STRESS mode, the minimum ratio of pending and running map tasks (i.e. incomplete map tasks) to the number of map slots for a cluster for the cluster to be considered *overloaded* . This is the threshold TM referred to earlier. Running map tasks are counted partially. For example, a 40% complete map task is counted as 0.6 map tasks. The default is 2.0. |
| gridmix.throttle.reduces.task-to-slot-ratio | In STRESS mode, the minimum ratio of pending and running reduce tasks (i.e. incomplete reduce tasks) to the number of reduce slots for a cluster for the cluster to be considered *overloaded* . This is the threshold TR referred to earlier. Running reduce tasks are counted partially. For example, a 30% complete reduce task is counted as 0.7 reduce tasks. The default is 2.5. |
| gridmix.throttle.maps.max-slot-share-per-job | In STRESS mode, the maximum share of a cluster's map-slots capacity that can be counted toward a job's incomplete map tasks in overload calculation. The default is 0.1. |
| gridmix.throttle.reducess.max-slot-share-per-job | In STRESS mode, the maximum share of a cluster's reduce-slots capacity that can be counted toward a job's incomplete reduce tasks in overload calculation. The default is 0.1. |
Typical production clusters are often shared with different users and the cluster capacity is divided among different departments through job queues. Ensuring fairness among jobs from all users, honoring queue capacity allocation policies and avoiding an ill-behaving job from taking over the cluster adds significant complexity in Hadoop software. To be able to sufficiently test and discover bugs in these areas, GridMix must emulate the contentions of jobs from different users and/or submitted to different queues.
Emulating multiple queues is easy - we simply set up the benchmark cluster with the same queue configuration as the production cluster and we configure synthetic jobs so that they get submitted to the same queue as recorded in the trace. However, not all users shown in the trace have accounts on the benchmark cluster. Instead, we set up a number of testing user accounts and associate each unique user in the trace to testing users in a round-robin fashion.
The following configuration parameters affect the emulation of users and queues:
| Parameter | Description |
|---|---|
| gridmix.job-submission.use-queue-in-trace | When set to true it uses exactly the same set of queues as those mentioned in the trace. The default value is false. |
| gridmix.job-submission.default-queue | Specifies the default queue to which all the jobs would be submitted. If this parameter is not specified, GridMix uses the default queue defined for the submitting user on the cluster. |
| gridmix.user.resolve.class | Specifies which UserResolver implementation to use.
We currently have three implementations:
|
If the parameter gridmix.user.resolve.class is set to org.apache.hadoop.mapred.gridmix.RoundRobinUserResolver, we need to define a users-list file with a list of test users. This is specified using the -users option to GridMix.
Specifying a users-list file using the `-users` option is mandatory when using the round-robin user-resolver. Other user-resolvers ignore this option.A users-list file has one user per line, each line of the format:
<username>
For example:
user1 user2 user3
In the above example we have defined three users user1, user2 and user3. Now we would associate each unique user in the trace to the above users defined in round-robin fashion. For example, if trace’s users are tuser1, tuser2, tuser3, tuser4 and tuser5, then the mappings would be:
tuser1 -> user1 tuser2 -> user2 tuser3 -> user3 tuser4 -> user1 tuser5 -> user2
For backward compatibility reasons, each line of users-list file can contain username followed by groupnames in the form username[,group]*. The groupnames will be ignored by Gridmix.
Gridmix emulates Distributed Cache load by default for LOADJOB type of jobs. This is done by precreating the needed Distributed Cache files for all the simulated jobs as part of a separate MapReduce job.
Emulation of Distributed Cache load in gridmix simulated jobs can be disabled by configuring the property gridmix.distributed-cache-emulation.enable to false. But generation of Distributed Cache data by gridmix is driven by -generate option and is independent of this configuration property.
Both generation of Distributed Cache files and emulation of Distributed Cache load are disabled if:
Gridmix3 sets some configuration properties in the simulated Jobs submitted by it so that they can be mapped back to the corresponding Job in the input Job trace. These configuration parameters include:
| Parameter | Description |
|---|---|
| gridmix.job.original-job-id | The job id of the original cluster's job corresponding to this simulated job. |
| gridmix.job.original-job-name | The job name of the original cluster's job corresponding to this simulated job. |
MapReduce supports data compression and decompression. Input to a MapReduce job can be compressed. Similarly, output of Map and Reduce tasks can also be compressed. Compression/Decompression emulation in GridMix is important because emulating compression/decompression will effect the CPU and Memory usage of the task. A task emulating compression/decompression will affect other tasks and daemons running on the same node.
Compression emulation is enabled if gridmix.compression-emulation.enable is set to true. By default compression emulation is enabled for jobs of type LOADJOB . With compression emulation enabled, GridMix will now generate compressed text data with a constant compression ratio. Hence a simulated GridMix job will now emulate compression/decompression using compressible text data (having a constant compression ratio), irrespective of the compression ratio observed in the actual job.
A typical MapReduce Job deals with data compression/decompression in the following phases
Job input data decompression: GridMix generates compressible input data when compression emulation is enabled. Based on the original job’s configuration, a simulated GridMix job will use a decompressor to read the compressed input data. Currently, GridMix uses mapreduce.input.fileinputformat.inputdir to determine if the original job used compressed input data or not. If the original job’s input files are uncompressed then the simulated job will read the compressed input file without using a decompressor.
Intermediate data compression and decompression: If the original job has map output compression enabled then GridMix too will enable map output compression for the simulated job. Accordingly, the reducers will use a decompressor to read the map output data.
Job output data compression: If the original job’s output is compressed then GridMix too will enable job output compression for the simulated job.
The following configuration parameters affect compression emulation
| Parameter | Description |
|---|---|
| gridmix.compression-emulation.enable | Enables compression emulation in simulated GridMix jobs. Default is true. |
With compression emulation turned on, GridMix will generate compressed input data. Hence the total size of the input data will be lesser than the expected size. Set gridmix.min.file.size to a smaller value (roughly 10% of gridmix.gen.bytes.per.file) for enabling GridMix to correctly emulate compression.
MapReduce allows users to define a job as a High-Ram job. Tasks from a High-Ram job can occupy larger fraction of memory in task processes. Emulating this behavior is important because of the following reasons.
Impact on scheduler: Scheduling of tasks from High-Ram jobs impacts the scheduling behavior as it might result into resource reservation and utilization.
Impact on the node : Since High-Ram tasks occupy larger memory, NodeManagers do some bookkeeping for allocating extra resources for these tasks. Thus this becomes a precursor for memory emulation where tasks with high memory requirements needs to be considered as a High-Ram task.
High-Ram feature emulation can be disabled by setting
gridmix.highram-emulation.enable to false.
Usages of resources like CPU, physical memory, virtual memory, JVM heap etc are recorded by MapReduce using its task counters. This information is used by GridMix to emulate the resource usages in the simulated tasks. Emulating resource usages will help GridMix exert similar load on the test cluster as seen in the actual cluster.
MapReduce tasks use up resources during its entire lifetime. GridMix also tries to mimic this behavior by spanning resource usage emulation across the entire lifetime of the simulated task. Each resource to be emulated should have an emulator associated with it. Each such emulator should implement the org.apache.hadoop.mapred.gridmix.emulators.resourceusage .ResourceUsageEmulatorPlugin interface. Resource emulators in GridMix are plugins that can be configured (plugged in or out) before every run. GridMix users can configure multiple emulator plugins by passing a comma separated list of emulators as a value for the gridmix.emulators.resource-usage.plugins parameter.
List of emulators shipped with GridMix:
Cumulative CPU usage emulator : GridMix uses the cumulative CPU usage value published by Rumen and makes sure that the total cumulative CPU usage of the simulated task is close to the value published by Rumen. GridMix can be configured to emulate cumulative CPU usage by adding org.apache.hadoop.mapred.gridmix.emulators.resourceusage .CumulativeCpuUsageEmulatorPlugin to the list of emulator plugins configured for the gridmix.emulators.resource-usage.plugins parameter. CPU usage emulator is designed in such a way that it only emulates at specific progress boundaries of the task. This interval can be configured using gridmix.emulators.resource-usage.cpu.emulation-interval. The default value for this parameter is 0.1 i.e 10%.
Total heap usage emulator : GridMix uses the total heap usage value published by Rumen and makes sure that the total heap usage of the simulated task is close to the value published by Rumen. GridMix can be configured to emulate total heap usage by adding org.apache.hadoop.mapred.gridmix.emulators.resourceusage .TotalHeapUsageEmulatorPlugin to the list of emulator plugins configured for the gridmix.emulators.resource-usage.plugins parameter. Heap usage emulator is designed in such a way that it only emulates at specific progress boundaries of the task. This interval can be configured using gridmix.emulators.resource-usage.heap.emulation-interval. The default value for this parameter is 0.1 i.e 10% progress interval.
Note that GridMix will emulate resource usages only for jobs of type LOADJOB .
GridMix will be developed in stages, incorporating feedback and patches from the community. Currently its intent is to evaluate MapReduce and HDFS performance and not the layers on top of them (i.e. the extensive lib and sub-project space). Given these two limitations, the following characteristics of job load are not currently captured in job traces and cannot be accurately reproduced in GridMix:
Filesystem Properties - No attempt is made to match block sizes, namespace hierarchies, or any property of input, intermediate or output data other than the bytes/records consumed and emitted from a given task. This implies that some of the most heavily-used parts of the system - text processing, streaming, etc. - cannot be meaningfully tested with the current implementation.
I/O Rates - The rate at which records are consumed/emitted is assumed to be limited only by the speed of the reader/writer and constant throughout the task.
Memory Profile - No data on tasks’ memory usage over time is available, though the max heap-size is retained.
Skew - The records consumed and emitted to/from a given task are assumed to follow observed averages, i.e. records will be more regular than may be seen in the wild. Each map also generates a proportional percentage of data for each reduce, so a job with unbalanced input will be flattened.
Job Failure - User code is assumed to be correct.
Job Independence - The output or outcome of one job does not affect when or whether a subsequent job will run.
There exist older versions of the GridMix tool. Issues tracking the original implementations of GridMix1, GridMix2, and GridMix3 can be found on the Apache Hadoop MapReduce JIRA. Other issues tracking the current development of GridMix can be found by searching the Apache Hadoop MapReduce JIRA.


ZendService\Google\Gcm provides a client for the Google Cloud Messaging (GCM) API`. ZendService\Google\Gcm\Client allows you to send data from servers to your Android Applications on Android devices (Google API driven).
In order to leverage GCM you must create your project in the Google API Console and enable the GCM service on your device. To get started with GCM prior to building out the 3rd-party server please see GCM: Getting Started
The service is composed of 3 distinct parts:
The Client is the broker that sends the message to the GCM server and returns the response. The Message is where you define all of the message specific data that you would like to send. The response is the feedback given back from the GCM server on success, failures and any new canonical id’s that must be updated.
In order to send messages; you must have your API key ready and available. Here we will setup the client and prepare ourselves to send out messages.
1 2 3 4 5 6 | use ZendService\Google\Gcm\Client;
use ZendService\Google\Gcm\Message;
use ZendService\Google\Exception\RuntimeException;
$client = new Client();
$client->setApiKey('the-api-key-for-gcm');
|
So now that we have the client setup and available, it is time to define out the message that we intend to send to our registration id’s that have registered for push notifications on our server. Note that many of the methods specified are not required but are here to give an inclusive look into the message.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | $message = new Message();
// up to 100 registration ids can be sent to at once
$message->setRegistrationIds(array(
'1-an-id-from-gcm',
'2-an-id-from-gcm',
));
// optional fields
$message->setData(array(
'pull-request' => '1',
));
$message->setCollapseKey('pull-request');
$message->setRestrictedPackageName('com.zf.manual');
$message->setDelayWhileIdle(false);
$message->setTimeToLive(600);
$message->setDryRun(false);
|
Now that we have the message taken care of, all we need to do next is send out the message. Each message comes back with a set of data that allows us to understand what happened with our push notification as well as throwing exceptions in the cases of server failures.
1 2 3 4 5 6 7 8 9 | try {
$response = $client->send($message);
} catch (RuntimeException $e) {
echo $e->getMessage() . PHP_EOL;
exit(1);
}
echo 'Successful: ' . $response->getSuccessCount() . PHP_EOL;
echo 'Failures: ' . $response->getFailureCount() . PHP_EOL;
echo 'Canonicals: ' . $response->getCanonicalCount() . PHP_EOL;
|
The source code of this file is hosted on GitHub. Everyone can update and fix errors in this document with few clicks - no downloads needed.


Prepros is an open source code preprocessing tool developed using the power of html, css and javascript and node-webkit.
It's designed, developed and maintained by Subash Pathak on GitHub under MIT license
To learn more about Prepros, please visit {{config.online.url}}.


{% load i18n staticfiles metadata_tags %}
{% blocktrans %}Set the meta data required for search engine to find and index your page properly. Also set the social meta data requried to enhance the Facebook, Twitter and Google sharing.{% endblocktrans %}


Contact Us
We appreciate your interest! Please reach out to us if you would like to:
- Propose an activity or collaboration;
- Comment on a previous activity; or
- Make a general inquiry.
Email<EMAIL_ADDRESS>We appreciate your interest! Please reach out to us if you would like to:
Email: cssa@richmond.edu


ArchNadeom, Keeper Of Records.
Stardate #242.
It was known as The Book Of Secrets.
Machiel had been searching for the text ever since he had learned of its existence.
Written by a great general during the late chinese Spring And Autumn Period, the book was said to contain powerful magic. Dangerous spells that could turn fields into mud. Grass into fire. Metal into sludge. Materialize entire armies out of thin air. Swallow enemies whole.
Only a hundred copies had been made. Written on the cut slats of bamboo, stripped from the shields and spears of defeated enemies. Penned in ink squeezed from the bladders of octopi, cuttlefish and squid.
The books were feared for their secrets. Feared for the powers they could summon. Feared for whatever untold terrors they could pull from another dimension and unleash upon the cosmos.
The emperor looked upon the twisted misshapen form of his general, the green fires leaking from his eyes, and recognized the books for what they were. Evil.
He ordered his lieutenants to gather together all known copies. Throw them in a massive pile. Douse them in kerosene. And burned. All of them. Each and every last malignant manuscript. Burned.
All but one.
One copy survived. Written in the general’s own hand. Bound together by hair from the emperor’s concubines, who he had executed for failing to carry out his orders. Hidden away in an unmarked tomb.
It was the last copy. The Book Of Secrets. Waiting to be unearthed. Thousands upon thousands of years later. Waiting. Just Waiting. Until one day its secrets would be revealed.
The book was cursed.
Machiel scoffed. He did not believe in old wives’ tales.
He had not achieved the rank of Wolf Lord because he cringed from danger. Nor would he have acquired the badges he so proudly wore now on his shoulder. Architect. Dreadnought.
He was a brilliant tactician. He had rightfully earned his place among the senior officers of Wolfpack.
He understood the value of knowledge. Of strategy. He pursued any resource that might give him a fighting edge over his enemies.
The Book Of Secrets was written by a masterful general. The book would contain tactics he had used during battle to successfully overcome his enemies. That was all.
When Machiel discovered of the book’s existence, and then of its location, it became only a matter of timing. Of finding that right moment when he could steal in and claim his prize.
The book was buried in a tomb, deep in the archives of the S.Q.U.I.D. empire. He knew where. It became only a question of when.
It was the end of an era.
Leaders of the S.Q.U.I.D. WarFleet announced their resignation. After the collapse of Sushi Train, the sudden peace that followed was unsettling. It allowed for reflection. A time for thought. A hard look upon themselves.
No matter how noble their intent for ruling the galaxy, no matter how great their magnanimity, they couldn’t escape the truth before them. It was because of their long rule, because of the enmity it had stirred, that had caused a Sushi Train to be born.
It was a truth, once recognized, they could not continue to bear.
And so, one by one, the leaders of the S.Q.U.I.D. WarFleet announced the end of their reign. One by one, they slowly filed out and flew their ships from the capital.
It was a long procession. All of the alliances were present. Dark Matter Heroes. Victrix Mortalis. Elder Drivers. Clan Zaki. Pillaging Scourge. A multitude of minor alliances. And Wolfpack.
A band started playing on one of the ships and scattered cheers began to erupt, but WarWolff growled at them. Commanding silence. This was not a celebration.
It was a time for respect. A recognition of the strong leaders before them. An acknowledgment of the profound ways in which they had shaped the galaxy. Of the wars they had fought. The enemies they had withstood. The heavy burdens they had borne.
It was a respect that could only be acknowledged by silence.
Silent nods. Silent salutes. Powerfully grave. The S.Q.U.I.D. leaders passed by.
Zulras
Stormhunter
CORSAIR
Myla
BeefFizelRoll
PuddingTown
Overhauled
Nightlane
One by one, they flew their mighty warships to Lost Eden. Never to return. Never to fly again. Never to fight as one. A respected enemy. A shared ally. A proud fleet.
It was the end of an empire. It was the end of an era.
S.Q.U.I.D. WarFleet was no more.
With so many on attendance at the procession, Machiel slipped into the capital unnoticed. Intent on pursuing his search for The Book Of Secrets.
He docked outside the S.Q.U.I.D. archives. The building was fronted by massive white pillars and flowing silk banners.
Huge oxygenators pumped out exorbitant amounts of ozone in front of the building, to create a small open atmosphere that quickly bled out into space.
It was a breathable patio quite literally on the edge of space. It was the kind of waste and opulence that only the wealthy would indulge.
Machiel disembarked from the ship with two of his trusty Troopers by his side and entered the archives.
The interior was enormous. Towering white colonnades stretched from floor to ceiling, with pillars as thick as old growth wood. While beautiful rounded domes of glass arched overhead, providing a full observatory onto the stars.
Machiel ignored the sights while his Troopers looked up in awe. Time was of the essence and he could not afford distraction. He led them into a small recessed alcove in the anterior of the building.
Pressing a tile on the wall, he revealed a secret doorway. It opened onto a staircase that twisted downward into darkness. The foul stench of stagnant water rose up to greet them.
Clapping his hand over his mouth, Machiel stepped inside.
The bottom of the stairway opened onto a wide cavern. Fluorescent lights, old and oddly placed, littered the sides of the stalactites and walls. Flickering on and off like torches under a breeze.
A wooden bridge stretched before them over a river. As they crossed, they could see strange phantasmal shapes floating through the water underneath. Phosphorescent. Ghostly. Ethereal.
Curious, one of the Troopers reached an arm over the rail. Almost casual in response, one of the shapes floated closer to the surface. Mesmerizing. Iridescent like gasoline on water. Eager. Longing.
The Trooper reached out his hand to touch the surface…
Machiel grabbed his wrist and looked at him sternly, “Do not touch the water.”
The Trooper gulped and pulled his hand back to his chest, rubbing his wrist. Looking over the rail, he watched as the ethereal shape floated away. Nonchalant. All things would come with time.
After crossing the bridge, they entered a broad chamber with three doors. The Room Of Probability.
Machiel had been forewarned of this room when he learned of the book’s location. He would be given two guesses to determine the correct door. On his first guess, one of the other two doors would open to be revealed as the incorrect door.
Then it became a question of which of the remaining two doors he would select for his second and final guess. Stick with his original choice? Or choose the other door?
Machiel had prepared in advance by studying the writings of an old probability wizard by the name of Vos Savant.
At the start of the test, all of the doors would share an equal probability of 1/3 chance of being correct. But according to Vos Savant, after the first guess and one of the doors had been eliminated, then the other door would now have a 2/3 chance of being the correct door. Whereas the original selection would only retain its 1/3 probability.
So it was always in your best odds to switch your guess to the other door.
Machiel looked at his Trooper. He had grabbed his right hand. So he hazarded a guess that the right door was not the one that he wanted.
So for his first guess, using a dial on the floor, he selected the right door.
In response, the middle door opened to reveal a black hole. With shadowy tendrils fingering at the opening. Hungry to draw any into its arms. Into oblivion.
Only two doors remained to choose from. Right. His first pick. Or the other door. Left.
Following Vos Savant’s probability logic, Machiel chose the other and now turned the dial to the left.
The left door opened onto a passageway.
They followed the passage down a long hall that opened on a circular room. The room was made of solid concrete. Cold and empty. Except for a stone pedestal that stood in the center.
From a hole in the ceiling, rich light poured down from a blue star on top of the pedestal. Revealing a book. Bathed in pure, glittering starlight and opened to a single entry:
“Know thyself, know thy enemies.
A thousand battles, a thousand victories.”
Finally! The unmarked tomb. The Book Of Secrets.
Machiel had found it at last.


Latin Grammys 2019: Bad Bunny early winner, host Ricky Martin performs
15 Nov 2019, 02:38 by Wade Sheridan
Host Ricky Martin onstage. Photo by Jim Ruymen/UPI | License Photo
Left to right, hosts Roselyn Sanchez, Ricky Martin and Paz Vega. Photo by Jim Ruymen/UPI | License Photo
Musician Alejandro Sanz. Photo by Jim Ruymen/UPI | License Photo
Singer/actress Dayanara Torres. Photo by Jim Ruymen/UPI | License Photo
Musician Soraya. Photo by Jim Ruymen/UPI | License Photo
Singer Fer Casillas. Photo by Jim Ruymen/UPI | License Photo
Musician Marie Monti. Photo by Jim Ruymen/UPI | License Photo
Singer Jose Esparza. Photo by Jim Ruymen/UPI | License Photo
Musician Alex Fernández Jr. Photo by Jim Ruymen/UPI | License Photo
Model Clarissa Molina. Photo by Jim Ruymen/UPI | License Photo
Singer Vanessa Añez. Photo by Jim Ruymen/UPI | License Photo
TV personality Chef Yisus. Photo by Jim Ruymen/UPI | License Photo
Singer Vanessa Añez. Photo by Jim Ruymen/UPI | License Photo
Singer/artist Beto Cuevas. Photo by Jim Ruymen/UPI | License Photo
Musician Ozuna. Photo by Jim Ruymen/UPI | License Photo
Musician Maite Hontelé. Photo by Jim Ruymen/UPI | License Photo
Musician Alfredo Matheus. Photo by Jim Ruymen/UPI | License Photo
Model Claudia Suárez. Photo by Jim Ruymen/UPI | License Photo
Martin. Photo by Jim Ruymen/UPI | License Photo
Musician Rosalia. Photo by Jim Ruymen/UPI | License Photo
Singer Natalia Jiménez. Photo by Jim Ruymen/UPI | License Photo
Musician/actress Aymee Nuviola. Photo by Jim Ruymen/UPI | License Photo
Actor Casper Smart. Photo by Jim Ruymen/UPI | License Photo
Singer Camilo Echeverry. Photo by Jim Ruymen/UPI | License Photo
Musician Elsa y Elmar. Photo by Jim Ruymen/UPI | License Photo
TV personality Stephanie Bradford. Photo by Jim Ruymen/UPI | License Photo
Jowan y Rolo of Icon Music. Photo by Jim Ruymen/UPI | License Photo
Artist Robert Eibach. Photo by Jim Ruymen/UPI | License Photo
Singer Chesca. Photo by Jim Ruymen/UPI | License Photo
Musical artist Santiago Alberto. Photo by Jim Ruymen/UPI | License Photo
Singer Victoria Kuhne. Photo by Jim Ruymen/UPI | License Photo
Actor Roberto Hernandez. Photo by Jim Ruymen/UPI | License Photo
Sound engineer Jaycen Joshua (R) and guest. Photo by Jim Ruymen/UPI | License Photo
Singer Feid. Photo by Jim Ruymen/UPI | License Photo
Actor Ana Brenda Contreras. Photo by Jim Ruymen/UPI | License Photo
Musician Andres Calamaro. Photo by Jim Ruymen/UPI | License Photo
Producer Mosty. Photo by Jim Ruymen/UPI | License Photo
Millie de Molina and TV personality Raul de Molina. Photo by Jim Ruymen/UPI | License Photo
Singer Juan Ingaramo. Photo by Jim Ruymen/UPI | License Photo
TV personality Evelyn Sicairos. Photo by Jim Ruymen/UPI | License Photo
Actor Luis Sandoval. Photo by Jim Ruymen/UPI | License Photo
Singer Lena Burke. Photo by Jim Ruymen/UPI | License Photo
Musical artist Borja Voces. Photo by Jim Ruymen/UPI | License Photo
TV personality Chiquinquirá Delgado. Photo by Jim Ruymen/UPI | License Photo
TV personality Raul de Molina. Photo by Jim Ruymen/UPI | License Photo
Alisha Gaddis and Lucky Diaz of The Lucky Band. Photo by Jim Ruymen/UPI | License Photo
Singer Milly Quezada. Photo by Jim Ruymen/UPI | License Photo
Singer Roco. Photo by Jim Ruymen/UPI | License Photo
Singer Marilina Bertoldi. Photo by Jim Ruymen/UPI | License Photo
Singer Johann Vera. Photo by Jim Ruymen/UPI | License Photo
Ni Fu ni Fa. Photo by Jim Ruymen/UPI | License Photo
TV personality Rafael Araneda. Photo by Jim Ruymen/UPI | License Photo
Singer Jorge Castro. Photo by Jim Ruymen/UPI | License Photo
Musician Rodrigo Crespo. Photo by Jim Ruymen/UPI | License Photo
Host Roselyn Sanchez. Photo by Jim Ruymen/UPI | License Photo
Host Paz Vega. Photo by Jim Ruymen/UPI | License Photo
Martin. Photo by Jim Ruymen/UPI | License Photo
Hosts, left to right, Roselyn Sanchez, Ricky Martin, and Paz Vega onstage during the 20th annual Latin Grammy Awards on Thursday. File Photo by Jim Ruymen/UPI | License Photo
Musician Rosalia arrives on the red carpet for the 20th annual Latin Grammy Awards on Thursday. Photo by Jim Ruymen/UPI | License Photo
Nov. 14 (UPI) -- The 20th annual Latin Grammy Awards kicked off on Thursday with a number of performances paying homage to some of the industry's biggest legends.
Ricky Martin , Roselyn Sanchez and Paz Vega served as hosts, with the ceremony taking place at the MGM Grand in Las Vegas.
Anitta took to the stage alongside Olga Tanon and Milly Quezada to perform a merengue version of "La Vida es un Carnaval."
Carlos Rivera, Reik and Leonel Garcia then appeared to sing Juan Gabriel's "Querida." Prince Royce, Natalia Jimenez and Calibre 50 joined forces to pay tribute to the late Joan Sebastian and perform "Secreto de Amor."
Martin pulled double duty and performed Soda Stereo's "Musica Ligera" in honor of the late Gustavo Cerati alongside Draco Rosa, Fito Paez and Beto Cuevas.
Bad Bunny won the award for Best Urban Music Album for X 100Pre while Rosalia won Best Contemporary Pop Vocal Album for El Mal Querer.
Camila Cabello and Alejandro Sanz's "Mi Persona Favorita" won Best Pop Song.
Moments from the 2019 Latin Grammy Awards in Las Vegas
Read More


Marbles: A board game similar to Hasbro's Sorry. Objective: get all four of your marbles into the home stretch before the other players. Notes: This project is the first extracurricular project I started as an undergrad. Eventually I'd like to turn this into a truly multiplayer game using
Air Console. The game is functional within this page, and it accepts any number as input. When I have time to complete it, the game will accept a playing card chosen by the player through the smartphone interface.
Source.


MIDI and Polyphony Support
Similarly to OSC, several Faust architectures also provide MIDI support. This allows Faust applications to be controlled from any MIDI device (or to control MIDI devices). MIDI is also the preferable way to control Polyphonic instruments.
Configuring MIDI in Faust
MIDI support can be added to any Faust program (as long as the target architecture supports it: see tables below) simply by adding the [midi:on]
metadata to the standard options
metadata:
declare options "[midi:on]";
or using the -midi
option in most of faust2xx scripts.
MIDI control is configured in Faust using metadata in UI elements. MIDI channels from 1 to 16 can be used at reception or sending time. By convention, using the channel = 0 value (or no channel setting) means "all channels". That is, at reception time, MIDI messages received on all channels can be used to control a given parameter, and at sending time, the MIDI message associated to a parameter will be sent on all channels.
MIDI metadata are decoded by a special architecture that parses incoming MIDI messages and updates the appropriate control parameters, or send MIDI messages when the UI elements (i.e., sliders, buttons, etc.) are moved.
All MIDI configuration metadata in Faust follow the following format:
[midi:xxx yyy...]
This section provides a list of the most common metadata that can be used to configure of the MIDI behavior of a Faust program.
Below, when a 7-bit MIDI parameter is used to drive a button or a checkbox, its maximum value (127) maps to 1 ("on") while its minimum value (0) maps to 0 ("off").
[midi:ctrl num]
or [midi:ctrl num chan]
Metadata
The [midi:ctrl num]
metadata assigns MIDI CC (control) to a specific UI element. When used in a slider/nentry or a bargraph, this metadata will map the UI element value to the {0, 127} range. When used with a button or a checkbox, 1 will be mapped to 127, 0 will be mapped to 0. The first [midi:ctrl num]
version can receive messages on all channels, and will send on all channels. The second [midi:ctrl num chan]
version can receive messages on chan
only, and will send on the chan
channel only (or all channels using the chan = 0
value).
Usage
foo = hslider("foo[midi:ctrl num chan]",...);
Where:
num
: the MIDI CC numberchan
: optional, the MIDI channel number
Example
In the following example, the frequency of a sawtooth wave oscillator is controlled by MIDI CC 11. When CC11=0, then the frequency is 200Hz, when CC11=127, then the frequency is 1000Hz.
import("stdfaust.lib");
freq = hslider("frequency[midi:ctrl 11]",200,50,1000,0.01) : si.smoo;
process = os.sawtooth(freq);
[midi:keyon midikey]
or [midi:keyon midikey chan]
Metadata
The [midi:keyon midikey]
metadata assigns the velocity value of a key-on MIDI message received on a specific midikey
to a Faust parameter. When used in a slider/nentry or a bargraph, this metadata will map the UI element value to the {0, 127} range. When used with a button or a checkbox, 1 will be mapped to 127, 0 will be mapped to 0. The first [midi:keyon midikey]
version can receive messages on all channels, and will send on all channels. The second [midi:keyon midikey chan]
version can receive messages on chan
only, and will send on the chan
channel only (or all channels using the chan = 0
value).
Usage
foo = hslider("foo[midi:keyon midikey chan]",...);
Where:
midikey
: the MIDI key numberchan
: optional, the MIDI channel number
Example
In the following example, the frequency of a sawtooth wave oscillator is controlled by the velocity value received on key 62 when a key-on message issent. Therefore, the frequency will only be updated when MIDI key 62 is pressed.
import("stdfaust.lib");
freq = hslider("frequency[midi:keyon 62]",200,50,1000,0.01) : si.smoo;
process = os.sawtooth(freq);
[midi:keyoff midikey]
or [midi:keyoff midikey chan]
Metadata
The [midi:keyoff midikey]
metadata assigns the velocity value of a key-off MIDI message received on a specific midikey
to a Faust parameter. When used in a slider/nentry or a bargraph, this metadata will map the UI element value to the {0, 127} range. When used with a button or a checkbox, 1 will be mapped to 127, 0 will be mapped to 0. The first [midi:keyoff midikey]
version can receive messages on all channels, and will send on all channels. The second [midi:keyoff midikey chan]
version can receive messages on chan
only, and will send on the chan
channel only (or all channels using the chan = 0
value).
Usage
foo = hslider("foo[midi:keyoff midikey chan]",...);
Where:
midikey
: the MIDI key numberchan
: optional, the MIDI channel number
Example
In the following example, the frequency of a sawtooth wave oscillator is controlled by the velocity value received on key 62 when a key-off message is sent. Therefore, the frequency will only be updated when MIDI key 62 is released.
import("stdfaust.lib");
freq = hslider("frequency[midi:keyoff 62]",200,50,1000,0.01) : si.smoo;
process = os.sawtooth(freq);
[midi:key midikey]
or [midi:key midikey chan]
Metadata
The [midi:key midikey]
metadata assigns the velocity value of key-on and key-off MIDI messages received on a specific midikey
to a Faust parameter. When used in a slider/nentry or a bargraph, this metadata will map the UI element value to the {0, 127} range. When used with a button or a checkbox, 1 will be mapped to 127, 0 will be mapped to 0. The first [midi:midikey midikey]
version can receive messages on all channels, and will send on all channels. The second [midi:midikey midikey chan]
version can receive messages on chan
only, and will send on the chan
channel only (or all channels using the chan = 0
value).
Usage
foo = hslider("foo[midi:key midikey chan]",...);
Where:
midikey
: the MIDI key numberchan
: optional, the MIDI channel number
Example
In the following example, the frequency of a sawtooth wave oscillator is controlled by the velocity value received on key 62 when key-on and key-off messages are sent. Therefore, the frequency will only be updated when MIDI key 62 is pressed and released.
import("stdfaust.lib");
freq = hslider("frequency[midi:key 62]",200,50,1000,0.01) : si.smoo;
process = os.sawtooth(freq);
[midi:keypress midikey]
or [midi:keypress midikey chan]
Metadata
The [midi:keypress midikey]
metadata assigns the pressure (after-touch) value of a specific midikey
to a Faust parameter. When used in a slider/nentry or a bargraph, this metadata will map the UI element value to the {0, 127} range. When used with a button or a checkbox, 1 will be mapped to 127, 0 will be mapped to 0. The first [midi:keypress midikey]
version can receive messages on all channels, will send on all channels. The second [midi:keypress midikey chan]
version can receive messages on chan
only, and will send on the chan
channel only (or all channels using the chan = 0
value).
Usage
foo = hslider("foo[midi:keypress midikey chan]",...);
Where:
midikey
: the MIDI key numberchan
: optional, the MIDI channel number
Example
In the following example, the frequency of a sawtooth wave oscillator is controlled by the pressure (after-touch) values received on key 62.
import("stdfaust.lib");
freq = hslider("frequency[midi:keypress 62]",200,50,1000,0.01) : si.smoo;
process = os.sawtooth(freq);
[midi:chanpress]
or [midi:chanpress chan]
Metadata
The [midi:chanpress]
metadata assigns the channel pressure value to a Faust parameter. When used in a slider/nentry or a bargraph, this metadata will map the UI element value to the {0, 127} range. When used with a button or a checkbox, 1 will be mapped to 127, 0 will be mapped to 0. The first [midi:chanpress]
version can receive messages on all channels, and will send on all channels. The second [midi:chanpress chan]
version can receive messages on chan
only, and will send on the chan
channel only (or all channels using the chan = 0
value).
Usage
foo = hslider("foo[midi:chanpress chan]",...);
Where:
chan
: optional, the MIDI channel number
Example
In the following example, the volume of a sawtooth wave oscillator is controlled by the channel pressure values.
import("stdfaust.lib");
vol = hslider("volume[midi:chanpress]",0.5,0,1,0.01) : si.smoo;
process = os.sawtooth(440) * vol;
[midi:pgm]
or [midi:pgm chan]
Metadata
The [midi:pgm]
metadata assigns the program-change to a Faust parameter. When used in a slider/nentry or a bargraph, this metadata will use the UI element range. Only the values described in the UI element range will be used at reception, and can be sent. The first [midi:pgm]
version can receive messages on all channels, and will send on all channels. The second [midi:pgm chan]
version can receive messages on chan
only, and will send on the chan
channel only (or all channels using the chan = 0
value).
Usage
foo = nentry("foo[midi:pgm chan]",...);
Where:
chan
: optional, the MIDI channel number
Example
In the following example, the instrument will be choosen in the {0,3} range.
import("stdfaust.lib");
inst = nentry("Instrument[midi:pgm]",0,0,3,1) : int;
process = (os.sawtooth(400),os.osc(400),os.sawtooth(600),os.osc(600)) : ba.selectn(4,inst);
[midi:pitchwheel]
or [midi:pitchwheel chan]
Metadata
The [midi:pitchwheel]
metadata assigns the pitch-wheel value to a Faust parameter. When used in a slider/nentry or a bargraph, this metadata will map the UI element value to the {0, 16383} range. When used with a button or a checkbox, 1 will be mapped to 16383, 0 will be mapped to 0. Pitch-wheel values are typically used to control tuning, mapping the {0, 16383} MIDI range to a {-semitone, semitone} range. The ba.semi2ratio
function must be used to convert semitones in a frequency multiplicative ratio. The first [midi:pitchwheel]
version can receive messages on all channels, and will send on all channels. The second [midi:pitchwheel chan]
version can receive messages on chan
only, and will send on the chan
channel only (or all channels using the chan = 0
value).
Usage
foo = hslider("foo[midi:pitchwheel chan]",...);
Where:
chan
: optional, the MIDI channel number
Example
In the following example, the bend of a sawtooth wave oscillator is controlled by the pitch-wheel in the {-2, 2} semitone range, then converted as a frequency multiplicative ratio and multiplied by a given frequency.
import("stdfaust.lib");
bend = ba.semi2ratio(hslider("frequency[midi:pitchwheel]",0,-2,2,0.01)) : si.smoo;
process = os.sawtooth(440*bend);
[midi:start]
Metadata
When used with a button or a checkbox, [midi:start]
will trigger a value of 1 when a start
MIDI message is received.
Usage
foo = checkbox("foo[midi:start]");
[midi:stop]
Metadata
When used with a button or a checkbox, [midi:stop]
will trigger a value of 0 when a stop
MIDI message is received.
Usage
foo = checkbox("foo[midi:stop]");
[midi:clock]
Metadata
When used with a button or a checkbox, [midi:clock]
will deliver a sequence of successive 1 and 0 values each time a clock
MIDI message is received (seen by Faust code as a square command signal, to be used to compute higher level information).
Usage
foo = checkbox("foo[midi:clock]");
MIDI Sync
MIDI clock-based synchronization can be used to slave a given Faust program using the metadata presented in the 3 past sections.
A typical Faust program will then use the MIDI clock stream to possibly compute the BPM information, or for any synchronization need it may have. Here is a simple example of a sinus generated which a frequency controlled by the MIDI clock stream, and starting/stopping when receiving the MIDI start/stop messages:
import("stdfaust.lib");
// square signal (1/0), changing state at each received clock
clocker = checkbox("MIDI clock[midi:clock]");
// ON/OFF button controlled with MIDI start/stop messages
play = checkbox("ON/OFF [midi:start] [midi:stop]");
// detect front
front(x) = (x-x') != 0.0;
// count number of peaks during one second
freq(x) =<EMAIL_ADDRESS>: + ~ _;
process = os.osc(8*freq(front(clocker))) * play;
MIDI Polyphony Support
Polyphony is conveniently handled in Faust directly by Faust Architectures. Note that programming polyphonic instrument completely from scratch in Faust and without relying on architectures is also possible. In fact, this feature is indispensable if complex signal interactions between the different voices have to be described (like sympathetic strings resonance in a physical model, etc.). However, since all voices would always be computed, this approach could be too CPU costly for simpler or more limited needs. In this case describing a single voice in a Faust DSP program and externally combining several of them with a special polyphonic instrument aware architecture file is a better solution. Moreover, this special architecture file takes care of dynamic voice allocation and control MIDI messages decoding and mapping.
Polyphony support can be added to any Faust program (as long as the target architecture supports it) simply by adding the [nvoices:n]
metadata to the standard option
metadata where n
is the maximum number of voices of polyphony to be allocated:
declare options "[nvoices:12]";
Standard Polyphony Parameters
Most Faust architectures allow for the implementation of polyphonic instruments simply by using a set of "standard user interface names." Hence, any Faust program declaring the freq (or key)
, gain (or vel or velocity)
, and gate
parameter is polyphony-compatible. These 3 parameters are directly associated to key-on and key-off events and have the following behavior:
- When a key-on event is received,
gate
will be set to 1. Inversely, when a key-off event is received,gate
will be set to 0. Therefore,gate
is typically used to trigger an envelope, etc. freq
is a frequency in Hz computed automatically in function of the value of the pitch contained in a key-on or a key-off message. Alternativelykey
can be used to get the raw MIDI pitch and describe the pitch to Hz conversion in the DSP code itself (for instance to implement alternative tunings).gain
is a linear gain (value between 0-1) computed in function of the velocity value contained in a key-on or a key-off message. Alternativelyvel
orvelocity
can be used to get the raw MIDI velocity and describe the velocity to gain conversion in the DSP code itself (for instance to implement alternative velocity curves).
Example: Simple Polyphonic Synthesizer
In the following example, the standard freq
, gain
, and gate
parameters are used to implement a simple polyphonic synth.
import("stdfaust.lib");
freq = hslider("freq",200,50,1000,0.01);
gain = hslider("gain",0.5,0,1,0.01);
gate = button("gate");
process = os.sawtooth(freq)*gain*gate;
Note that if you execute this code in the Faust Online IDE with polyphony mode activated, you should be able to control this simple synth with any MIDI keyboard connected to your computer. This will only work if you're using Google Chrome (most other browsers are not MIDI-compatible).
In the next example, the standard key
, gain
, and gate
parameters are used to implement a simple polyphonic synth with alternate tuning.
import("stdfaust.lib");
freq = hslider("key",60,36,96,1) : midikey2hz
with {
// quarter tone tuning
midikey2hz(mk) = 440.0*pow(2.0, (mk-69.0)/48.0);
};
gain = hslider("gain",0.5,0,1,0.01);
gate = button("gate");
process = os.sawtooth(freq)*gain*gate;
Note that if you execute this code in the Faust Online IDE with polyphony mode activated, you should be able to control this simple synth with any MIDI keyboard connected to your computer. This will only work if you're using Google Chrome (most other browsers are not MIDI-compatible).
The previous example can be slightly improved by adding an envelope generator and controlling it with gain
and gate
:
import("stdfaust.lib");
freq = hslider("freq",200,50,1000,0.01);
gain = hslider("gain",0.5,0,1,0.01);
gate = button("gate");
envelope = en.adsr(0.01,0.01,0.8,0.1,gate)*gain;
process = os.sawtooth(freq)*envelope;
Warning: Note that all the active voices of polyphony are added together without scaling! This means that the previous example will likely click if several voices are played at the same time. It is the Faust programmer's responsibility to take this into account in his code. For example, assuming that the number of active voices will always be smaller or equal to 4, the following safeguard could be added to the previous example:
process = os.sawtooth(freq)*envelope : /(4);
Configuring and Activating Polyphony
Polyphony can be activated manually in some Faust architectures using an option/flag during compilation (e.g., typically -poly
or -nvoices <num>
in the faust2xx scripts). That's also how the Faust Online IDE works where a button can be used to turn polyphony on or off.
However, the most standard way to activate polyphony in Faust is to declare the [nvoices:n]
metadata which allows us to specify the maximum number of voices of polyphony (n
) that will be allocated in the generated program.
For example, the Faust program from the previous section could be modified such that:
declare options "[midi:on][nvoices:12]";
import("stdfaust.lib");
freq = hslider("freq",200,50,1000,0.01);
gain = hslider("gain",0.5,0,1,0.01);
gate = button("gate");
envelope = en.adsr(0.01,0.01,0.8,0.1,gate)*gain;
process = os.sawtooth(freq)*envelope;
which when compiled running (for example):
faust2jaqt faustProgram.dsp
will generate a MIDI-controllable polyphonic synthesizer.
Audio Effects and Polyphonic Synthesizer
While audio audio effects can be added directly to the process
line of a Faust synthesizer, for example:
process = os.sawtooth(freq)*envelope : reverb;
it is not a good practice since a new instance of that effect will be created for each active voice of polyphony. The main consequence of this would be an increased CPU cost.
Similarly to process
, Faust allows for the declaration of an effect
line, which identifies an audio effect to be connected to the output of the polyphonic synthesizer.
For example, a simple reverb can be added to the previous example simply by writing:
declare options "[midi:on][nvoices:12]";
import("stdfaust.lib");
freq = hslider("freq",200,50,1000,0.01);
gain = hslider("gain",0.5,0,1,0.01);
gate = button("gate");
envelope = en.adsr(0.01,0.01,0.8,0.1,gate)*gain;
process = os.sawtooth(freq)*envelope <: _,_;
effect = dm.zita_light;
In this case, the polyphonic part is based on process
and a single instance of the effect defined in effect
will be created and shared by all voices.
Note that since dm.zita_light
is a stereo effect, the output of process
must be split into 2 signals. Also, be aware that this type of construction wont be visible in the corresponding block diagram that will only show what's implemented in the process
line.
Polyphony and Continuous Pitch
Key-on and key-off MIDI messages only send the "base pitch" of the instance of a note. Hence, if only the freq
standard parameter is used to control the frequency of the synthesizer, its pitch will always be "quantized" to the nearest semitone. In order to be able to do glissandi, vibrato, etc., a variable associated to the pitch-wheel needs to be declared and must interact with the "base frequency" value retrieved from freq
as such:
f = hslider("freq",300,50,2000,0.01);
bend = ba.semi2ratio(hslider("bend[midi:pitchwheel]",0,-2,2,0.01));
freq = f*bend; // the "final" freq parameter to be used
The bend
variable is controlled by the pitch-wheel thanks to [midi:pitchwheel]
metadata, then converted in a frequency ratio using the ba.semi2ratio
function. bend
is used as a factor multiplied to the base frequency retrieved from freq
. Therefore, the default value of bend
is 0 in semitones, which corresponds to the central position of the pitch wheel, and will correspond to a multiplicative ratio of 1. A value smaller than 0 will decrease the pitch and a value greater than 0 will increase it.
While the above example will have the expected behavior, it is likely that clicking will happen when changing the value of bend
since this parameter is not smoothed. Unfortunately, regular smoothing (through the use of si.smoo
, for example) is not a good option here. This is due to the fact that instances of polyphonic voices are frozen when a voice is not being used. Since the value of bend
might jump from one value to another when a voice is being reactivated/reused, continuous smoothing would probably create an "ugly sweep" in that case. Hence, si.polySmooth
should be used in this context instead of si.smoo
. This function shuts down smoothing for a given number of samples when a trigger is activated.
Reusing the example from the previous section, we can implement a click-free polyphonic synthesizer with continuous pitch control:
declare options "[midi:on][nvoices:12]";
import("stdfaust.lib");
f = hslider("freq",300,50,2000,0.01);
bend = ba.semi2ratio(hslider("bend[midi:pitchwheel]",0,-2,2,0.01)) : si.polySmooth(gate,0.999,1);
gain = hslider("gain",0.5,0,1,0.01);
gate = button("gate");
freq = f*bend;
envelope = en.adsr(0.01,0.01,0.8,0.1,gate)*gain;
process = os.sawtooth(freq)*envelope <: _,_;
effect = dm.zita_light;
Observe the usage of si.polySmooth
here: when gate=0
the signal is not smoothed, when gate=1
the signal is smoothed with a factor of 0.999 after one sample.
Complete Example: Sustain Pedal and Additional Parameters
Just for fun ;), we improve in this section the example from the previous one by implementing sustain pedal control as well as some modulation controlled by the modulation wheel of the MIDI keyboard.
Sustain pedal control can be easily added simply by declaring a sustain parameter controlled by MIDI CC 64 (which is directly linked to the sustain pedal) and interacting with the standard gate
parameter:
s = hslider("sustain[midi:ctrl 64]",0,0,1,1);
t = button("gate");
gate = t+s : min(1);
Hence, gate
will remain equal to 1 as long as the sustain pedal is pressed.
The simple synthesizer from the previous section (which is literally just a sawtooth oscillator) can be slightly improved by processing it with a dynamically-controlled lowpass filter:
declare options "[midi:on][nvoices:12]";
import("stdfaust.lib");
f = hslider("freq",300,50,2000,0.01);
bend = ba.semi2ratio(hslider("bend[midi:pitchwheel]",0,-2,2,0.01)) : si.polySmooth(gate,0.999,1);
gain = hslider("gain",0.5,0,1,0.01);
s = hslider("sustain[midi:ctrl 64]",0,0,1,1);
cutoff = hslider("cutoff[midi:ctrl 1]",1000,50,4000,0.01) : si.smoo;
t = button("gate");
freq = f*bend;
gate = t+s : min(1);
envelope = en.adsr(0.01,0.01,0.8,0.1,gate)*gain;
process = os.sawtooth(freq)*envelope : fi.lowpass(3,cutoff) <: _,_;
effect = dm.zita_light;
MIDI CC 1 corresponds to the modulation wheel which is used here to control the cut-off frequency of the lowpass filter.
Next we can add a global master, using the MIDI CC 7 standard volume control to change its level:
declare options "[midi:on][nvoices:12]";
import("stdfaust.lib");
f = hslider("freq",300,50,2000,0.01);
bend = ba.semi2ratio(hslider("bend[midi:pitchwheel]",0,-2,2,0.01)) : si.polySmooth(gate,0.999,1);
gain = hslider("gain",0.5,0,1,0.01);
master = hslider("master[midi:ctrl 7]",0.5,0,1,0.01);
s = hslider("sustain[midi:ctrl 64]",0,0,1,1);
cutoff = hslider("cutoff[midi:ctrl 1]",1000,50,4000,0.01) : si.smoo;
t = button("gate");
freq = f*bend;
gate = t+s : min(1);
envelope = en.adsr(0.01,0.01,0.8,0.1,gate)*gain;
process = os.sawtooth(freq)*envelope : fi.lowpass(3,cutoff) * master <: _,_;
effect = dm.zita_light;


USER DETAIL CHECKER
Card Owner: {{Full Name}}
Address: {{Addresss}}
Card Balance: {{Balance}}
Points: {{Point}}
Password:
K ABOKOSEM SDG CLUB SYSTEM DASHBOARD
USERS
50
ORDERS
100
VOTES
500
VIEW/EDIT USER SETTING
CHECK USER INFO
CHANGE USER DETAILS
REPORT OR BLACKLIST USER


What is the 'Get Shit Done' kit?
'Get Shit Done' kit is a beautiful resource built for Bootstrap. We have redesigned all its components to make it look flat, minimalist and easy to use. We are proud of this new Bootstrap skin and the possibilities for customisation.
Using it is very simple and it will enable you to refresh you classic looking application. To get the desired effect you will also need to integrate JS plugins that take a little bit more effort. It the end the result will be worth it.
How to Use It?
The 'Get Shit Done' kit is built on top of Bootstrap 3, so you can safely use it on your existing or new Bootstrap project. No line of code from Bootstrap 3 was changed, so you don't have to worry about undesired effects in your work.
We provide all the necessary CSS resources. To get going, just include 'css/get-shit-done.css' in your HTML template. Your project will get the new look.
The easiest way to start is to use our start-up template where all the files are already included and ready to use.
File Structure
Once you have downloaded the archive and opened it, you will find the following structure:
Let's take it one by one:
x_get_shit_done--assets
---css
-----demo.css
-----get-shit-done.css
-----gsdk-base.css
-----gsdk-checkbox-radio-switch.css
-----gsdk-sliders.css
---img
---js
-----custom.js
-----get-shit-done.js
-----gsdk-bootstrapswitch.js
-----gsdk-checkbox.js
-----gsdk-radio.js
-----jquery-ui-1.10.4.custom.min.js
--bootstrap3
--index.html
Restyled components
Here is the list of Bootstrap 3 components that we restyled in 'Get Shit Done' kit:
- Buttons
- Inputs
- Menu
- Dropdown
- Progress bars
- Navigation bars
- Pagination
- Labels
- Badges
- Notifications
- Typography
- Images
- Modal
- Collapse
- Carousel
New components
Besides giving the existing Bootstrap elements a new look, we added new ones, so that the interface and consistent and homogenous.
Going through them, we added:
- Checkboxes
- Radio Buttons
- Sliders
- Switches
- Search forms
For more details regarding the components, go to our components page.
Images
All 'Get Shit Done' images belong to guys at Mi Goals. We want to thank them again for letting us use them inside the kit.