Language Overview


Concurnas is an open source JVM programming language designed for building reliable, scalable, high performance concurrent, distributed and parallel systems.

The challenges faced by the modern enterprise require software solutions that are both highly performant, scalable and quick to market. Traditionally, statically typed languages (such as Java) have dominated the high performance computing market, whereas dynamically typed languages (such as Python) have been favored by domain experts working in areas such as scientific computing, research and development, prototyping and rapid application development. Statically typed languages are harder than dynamic languages for non technical users to work with but generally have superior performance. And so it has been that we've had to make a choice between between runtime performance and developer performance, statically typed and dynamically typed languages. With Concurnas this is different, with Concurnas we are able to obtain both the advantages of statically typed languages,and those of dynamically typed languages. In this way we no longer need to sacrifice developer performance and time to market for performance, we win on both counts: we get Python like syntax with Java like speed!

Concurnas makes use of type inference in order to present an easy to learn dynamically typed like syntax. At its core it is a statically typed language that is type safe and which runs upon the Java Virtual Machine (JVM). It is through this implementation upon the JVM that Concurnas is afforded:

  • The incredible performance of the JVM.
  • Automatic memory management via garbage collection. Managing memory is one of the most complex and challenging aspects of modern programming, by automating this process via language support we free up time for focusing on the more domain specific parts of the engineering project at hand. Not only do we obtain a grantee that our memory will be properly managed, but automatic garbage collection is usually better or equal to any algorithm that which we would otherwise need to implement!
  • Just in time compilation and optimization - allowing us to write code once and run anywhere, and for that code to be optimized automatically contingent upon runtime usage (not possible with ahead of time compilation).
  • Separate compilation and runtime phases - allowing us to catch the majority of programming errors ahead of runtime and increasing the confidence we can have in our code before it goes into production.
  • Access to the Java Development Kit (JDK), providing us with efficient data structure implementations, networking, i/o tools etc.
  • Compatibility with existing and new enterprise code written in JVM languages such as Java, Scala, Kotlin and more!

Furthermore, since Concurnas has the performance of a statically typed language, with the ease of use of a dynamically typed one, and is designed to scale, teams are able to use both the same programming language: Concurnas and code written in Concurnas as their core programming language through all stages of software development: from research, prototyping, development, production and scaling. There is no need to switch between different languages in teams made up of heterogeneous domain experts and software engineers, one language can be used - reducing cost and time to market.

From a design perspective Concurnas has been designed as a language which:

  • Is easy to learn and productive. We want Concurnas to feel familiar and easy to learn. For this reason much of the syntax is inspired by the likes of Python, widely recognized as one of the easiest programming languages to learn and program in.
  • Has an optionally lightweight and concise syntax. A criticism of traditionally statically typed languages such as Java is that they are verbose and that this verbosity creates extra work in the form of so called 'boiler plate code'. This is bad for two reasons, firstly the more code we have to write, the greater the chance of errors and secondly this verbosity has the effect of introducing a mental gap between the problem solution expressed in code and the problem domain. To address this Concurnas provides an optionally concise syntax. The optionality of this syntax means that where we need to be more verbose so as to aid in the understanding of the person reading (and maintaining!) the code, we can do this easily. For example, if we feel that explicitly expressing the return type of a function would improve readability, we are allowed to do this (without having to resort to extra comments, or annotations etc).
  • Is high performance. We want Concurnas to be used for building real systems which the world depends upon, hence Concurnas has been designed to be highly performant. This is achieved by providing an explicit compilation stage where most type and structural checks take place on the code and making use of the JVM for runtime execution. Both of these approaches have been proven to be successful methods for achieving high performance computation.
  • Follows the principle of least surprise. If we assign a value for a variable, we expect a value to be assigned, if we write code which looks like it invokes a function, we expect a function to be invoked. The key idea here is to present syntax that is sufficiently balanced so as to be expressive but non too divergent from other traditional programming languages.
  • Has a simplified concurrent programming model. We now live in a multi-core world. With Concurnas we present a thread free, lock free model of concurrency oriented around communicating changes of state via messages. We also offer managed shared state via Actors. Through these means we are able to preserve the power of existing thread and lock based models of concurrency control whilst keeping the interface simple and intuitive for non computer science experts.
  • Is scalable with minimal effort. From prototype to production. We want Concurnas code to take full advantage of the available hardware presented to it without requiring re-engineering. Ideally whether a solution is being run on a single core, a multi-core server, a local multi-machine cluster or as a distributed system, the same code should be usable.
  • Has first class citizen support for GPU computing. Most computers now come standard with GPU's - these can be thought of as co-processors which are perfect for solving data parallel problems with incredible speed and reduced power consumption. Often 100x speedups are achievable when using a GPU compared to a CPU (even when the GPU and CPU compared are of comparable class).
  • Enables direct working with data off heap (big data). Working with large data sets is a reality for many data scientists and software engineers. We wish to make this task easier.
  • Is null safe. The null pointer exception is the bane of many a programmers existence and one of the most common errors to occur (often in production!), Concurnas incorporates a nullability constraint as part its type system as well as a number of tools for managing nullable state.
  • Is extensible. Sometimes we just need to use a snippet of another programming language to get the job done. From SQL to APL, Concurnas provides language extensions which can be used to embed code written in other languages directly into Concurnas code!
  • Is suitable for building Domain Specific Languages (DSL). Complex systems often require additional alignment to their problem domain, it is at this point that writing a DSL makes sense and Concurnas offers the support for this.
  • Aims to be in use and maintained for at least the next 30 years. Successful programming languages have long lifetimes, Concurnas has been designed with this in mind.

Concurnas is able to boost productivity by virtue of the fact that its concise syntax and first class citizen support for common enterprise computing problems enable us to be productive by writing fewer lines of code. This reduces the changes of bugs, increases productivity and helps us get to market with solutions quicker.

Multi-paradigm

Concurnas is a multi-paradigm programming language which aims to unify the best features of the Imperative, Functional, Object Oriented and emerging Reactive programming paradigms.

Imperative

Almost all programmers are familiar with imperative programming constructs such as variable assignment, control flow statements (if-elif-else), for loops, assertions, exceptions etc. Concurnas deliberately offers no surprises here, what we learned about programming in school works as expected. Concurnas does however offer a number of useful features in the imperative space which makes it very concise and easy to use:

  • Implicit return values from blocks and control structures such as if-elif-else statements and for loops. The last referenced expression in a block is returned.
  • Implicit return values from function definitions. The last referenced expression in a function is returned.
  • One line syntax for function definitions. This optional syntax allows us to define simple short functions in a very concise manner.
  • List comprehension. This enables us to easily perform iterations over data structures.
  • Object copiers. Concurnas enables us to perform a deep copy of an object graph using a concise sublanguage, and usually just one character.
  • Type inference. Concurnas is able to infer the type of most expressions, grealy reducing the amount of code we need to write.
  • Support for Unicode. This enables us to write mathematical expressions such as the following easily and without having to switch to a different programming language to do so.

Functional

The Functional programming paradigm represents an often untapped resource of really good ways of making programs easier to write, read and reason about. Concurnas makes use of a number of these features:

  • Lambdas. These allow us to derive some really concise and expressive solutions to problems particularly when working with data.
  • Method references. These allow us to treat ordinary existing methods and functions as lambda's.
  • Partial functions. This allows us to partially qualify the arguments of a lambda which itself produces a new lambda.
  • Pattern matching. Pattern matching expands upon the traditional imperative programming approach to branching logic in allowing us to us to easily implement complex solutions which otherwise would require an elaborate and difficult to maintain web of if-elif-else statements.
  • Lazy evaluation of variables. In imperative programming, and Concurnas in general, variable assignments are evaluated on an eager basis. With lazy variables, this evaluation can be delayed until the variable in question is used.

Object oriented

The object oriented programming paradigm has become synonymous with enterprise software development, for many debatably good and bad reasons. What's for sure though is that traditional programming languages often place the burden of implementation of object orientation upon the developer. In practice this results in a tremendous amount of boiler plate code. With Concurnas this is different. Concurnas takes the hard work and repetition out of writing object oriented software whilst embracing modern software engineering best practices. We have support for the ordinary established features of object orientation including: classes (concrete, abstract, inheritance), encapsulation, method overloading, dynamic binding, generics (in out, wild cards, bounded), enumerations and annotations. Concurnas also has support for a number of emerging features/best practices including:

  • Tuples. These are a convenient way to move groups of data around a program and offer an alternative to defining classes specifically for fulfilling this purpose - for example, returning multiple values from a function invocation.
  • Typedefs. Typedefs act like macros in that they offer a convenient way of writing class names, when used as types or as constructors, in shorthand form. This is particularly helpful when one is working with fully or partially qualified generic types.
  • Object Providers. Object providers give us first class citizen support for dependency injection - a technique which has become accepted as best practice for designing object oriented systems.
  • Automatic getter/setter generation. Encapsulation of state and controlled access to that state via getters and setters is a cornerstone of modern object oriented programming, unfortunately this often requires a tremendous amount of boiler plate code to be written in support of it. Concurnas automates the production of this code.
  • Automatic getter/setter redirection. Concurnas will treat a field access or assignment as a call to a getter or setter method respectfully. This greatly reduces the amount of code one needs to write.
  • Default constructors. These enable us to succinctly define classes with a constructor that can be used to initialize their state within their instance objects.
  • Traits. Traits allow us to define elements of reusable functionality (both methods and state) which can be mixed-in to classes. Traits are useful as they encourage and facilitate software creation via composition as opposed to inheritance, which generally understood as best practice in modern object oriented programming. Traits themselves may be stacked together.
  • Automatic generation of hash codes and equalities. By default all objects of classes in Concurnas implement equality by value, this is achieved by Concurnas automatically generating a suitable pair of hash code (for numerical summarizing a class and its state, used within HashMaps etc) and equals (for testing to see if two objects are equal to one another) methods for all classes unless otherwise user defined.

Reactive

The isolate and ref oriented model of Concurrency in Concurnas (explored later) naturally lends itself to supporting the emerging reactive programming paradigm. In reactive programming we can create implicit dependency pipelines of data throughout our code such that changes in data are automatically propagated throughout our system with our code written in such a way that it reacts to those changes, maybe itself further propagating change.

The reactive style of programming tends to be very intuitive for solving many types of algorithmic problem, particularly those involving asynchronous flows of concurrent data. Unlike traditional imperative programming where one is pulling data into a location for further processing, with the reactive model data is effectively pushed into a location for processing.

Expressing reactivity in Concurnas is usually doable in only a few lines of code.

Concurrency with Concurnas

One of the most challenging aspects of modern enterprise programming, along with the likes of Artificial intelligence/Machine learning, computer graphics and security, is concurrent programming. We want Concurrent programming to be accessible to everyone, not just software engineers. Concurnas was originally designed from its core as a concurrent programming language. The Concurnas concurrency model is thread, critical section and lock free, which of course naturally precludes deadlocks. The model of concurrency computation offered by Concurnas generally results in us writing software which looks single threaded by virtue of the fact that the hard work of managing concurrent state is abstracted away.

For better or worse we exist in an age of multi-core computation, thus for our programs to be as performant as possible they need to be able to take advantage of the multiple cores available to them. Code written to be concurrent in Concurnas is designed to behave in the same way whether it is run on a single core or multi-core machine, automatically scaling to take advantage of the available hardware.

Instead of sharing memory, messages are used to communicate changes in state, this greatly simplifies the programming model of concurrency, whilst preventing non deterministic changes in state which can otherwise occur in traditional shared memory languages when that shared memory is not properly managed. This is achieved through the use of what we term: isolates and ref's. Isolates are the underlying unit of concurrent computing in Concurnas, ref's are a means of communicating changes in state in a controlled manner.

All code in Concurnas is executed within isolates. Isolates are mapped onto the underlying hardware threads of the machine upon which one is running one's code. Isolates operate within their own dedicated memory space. All state used in an isolate is copied with the exception of references, actors and some specially marked shareable classes. This isolation of state makes reasoning and designing concurrent algorithms easier since it reduces the need to code for synchronization and race conditions.

Refs allow us to share state between isolates in a controlled manner. They are not copied between isolates, rather they are shared but provide controlled, atomic access to their changeable state. If a value is not yet set on a ref when it is requested, execution is paused and other isolates are allowed to execute until a value has been set, after which execution continues. Ref's take an optimistic approach to concurrency control which shields the end user from managing locks and critical sections.

As has already been mentioned, the isolate and ref model of concurrency in Concurnas naturally lends itself to supporting the emerging paradigm of reactive programming. Elements of reactivity (onchange and every blocks) are triggered for execution upon changes to their input ref's and remain paused otherwise. This approach of suspending and resuming execution is achieved by virtue of the fact that isolates are continuations - an executing isolate may save its state and yield its underling multiplexed thread to another pending isolate thus enabling cooperative multitasking.

We are able to perform transactional computing with refs. Concurnas supports software transactional memory via the trans block keyword. This allows us to make changes to one or more refs and have those changes visible outside of our transaction on an atomic basis.

Actors

Concurnas offers first class citizen support for Actors. The Actor model of computation has become popular in recent years as multi-core chips have become ubiquitous. Actors in Concurnas enable us to build micro-services. Each actor operates within its own dedicated isolate. Actors look and behave just like regular objects from the perspective of the calling code.

Actors allow us to write service code in a single threaded style and be able to run them safety in a concurrent manner without having to concern ourselves with synchronization or race conditions as each call to an actor runs sequentially and has exclusive access to the sate of the actor until it completes. Naturally, because actors implement their own concurrency control they are safe to be shared between multiple isolates without requiring copying.

Concurnas offers a succinct syntax for defining and working with actors.

Temporal programming

A common pattern in concurrent systems engineering is to want to have some for of time based trigger, "wait 10 seconds then do x" or "do y every 3 seconds" etc or "perform this action at this certain time". At Concurnas we refer to this as temporal computing.

Temporal computing is supported via the built in Pulsar library found at: com.concurnas.lang.pulsar. This library allows us to schedule activities to take place in the future after a certain amount of time has elapsed. It also allows us to schedule tasks for repetition.

Concurnas offers both a realtime implementation of pulsars and a 'Frozen'-time implementation (designed primarily for testing temporal applications), which permits time to be treated as a variable to be injected.

Parfor

Concurnas has first class citizen support for parallel for loops. These are a convenient and intuitive mechanism for performing task based operations in the context of a loop, in parallel. They have the same syntax as conventional loops in Concurnas.

Distributed Computing

Concurnas provides an easy to use, intuitive and non invasive solution for distributed computing which acts as an extension of the isolate model of concurrent computation. In this way we are able to use the concurrent computing model which we are used to/have already built our software using and can easily extend this to working on a remote basis. In this way as our computational requirements grow we can easily scale our solutions to accommodate.

Concurnas abstracts away much of the hard work Concerning managing distributed computing, allowing us to focus on the more interesting problems which we are trying to solve. For instance, with Concurnas remote servers will cache results and wait for clients to reconnect in the event of network failure.

With Concurnas, remote servers are able to be configured such that they can run any code submit to them deemed safe for execution.

The internal Concurnas distributed computing API includes a provision for dependency resolution which itself is quite sophisticated and in the interests of performance is able to perform static code dependency analysis in order to determine and preemptively provide upfront the code that is required in order to execute a request.

In this way clients are able to submit any defined code and have this run on a remote machine with dependent code automatically distributed to the remote machine. This greatly simplifies the usually arduous process of remote code dependency distribution.

Dependant object state is also distributed for use with remote execution, rendering the execution semantic between local and remote computation identical. This makes it very easy for us to start building a solution locally, and to then later scale that solution up on a distributed platform.

Off Heap Memory

In languages such as Java there exist a number of commercial products for performing this form of off heap memory management, often costing thousands of dollars per user per year. With Concurnas you get this for free as an integral part of the language!

Off Heap Stores

Concurnas has support for off heap memory in the form of stores and maps. These allow us to work with datasets which are far greater than that which can be held within the managed garbage collected portion of memory used by Concurnas termed the heap. Additionally by using off heap memory we gain a tremendous amount of control over how we manage memory and can reserve portions of memory separate from garbage collection which is incredibly useful for high performance computing.

Objects are stored off heap in binary format. With Concurnas all objects are quickly serializable and deserializable to and from this format by default.

Concurnas presents two variants of off heap storage, for RAM and disk - for use contingent on the amount of data one is working with. The off heap disk variant is backed by memory mapped files which greatly enhances performance as spatially localized data is cached in memory.

Off Heap Maps

The Key-Value pair map has become an industry standard too for persisting data. With Concurnas support is provided in the form of off heap maps. Both a RAM and disk backed variant of these maps is provided.

The off heap map disk variant is backed by memory mapped files which greatly enhances performance as spatially localized data is cached in memory. Additionally, the disk based variant is capable of long term persistence of data.

Schema evolution

One of the strongest points of the Concurnas off heap map implementation is its support for schema evolution. We term schema evolution as changes to a classes fields after it has been persisted.

Schema evolution turns out to be a surprisingly normal operation performed in enterprise computing. Traditionally this would cause a problem for us upon deserialization since the persisted version of the class code would not match that of the current 'live' version, but Concurnas is largely able to account for these sorts of evolutionary changes including:

  • Removal of a data field
  • Adding a new data field
  • Changing the data type of a field

Concurnas is able to account for the above changes to object schemas when serializing and deserializing data from persistent storage. This saves us the headache of explicit migration.

GPU Computing

Concurnas has built in first class citizen support for programming GPUs and associated parallel computing constructs. GPU's are massively data parallel computation devices which are perfect for solving SIMD (single instruction, multiple data) and normally CPU bound problems. Compared to a single CPU core algorithm implementation, in solving a computation bound problem, it is common to be able to obtain up to a 100x speed improvement (two orders of magnitude) when using a GPU! And this is with a far reduced energy and hardware cost per gigaflop relative to CPU based computation. All modern graphics cards have a built in GPU and there exist dedicated GPU computation devices. In fact some of the world's leading supercomputers achieve their parallelization through the use of dedicated GPU hardware. With Concurnas this power is your as well.

Support is provided via interfacing to OpenCL - an excellent multiplatform API for GPU computing. OpenCL is supported by the big three GPU manufacturers - NVidia, AMD and Intel. However, even with conventional, raw OpenCL (or any GPU computing platform for that matter) one must write a lot of boilerplate code and perform a lot of non work related management in order to get computation done on the GPU. A such, authoring large applications can be an intimidating prospect. With Concurnas you will see that this boilerplate code is minimized, allowing the developer to focus on solving real business problems. Additionally there is no need to learn (and have to paradigm shift into) C or C++ which is the native language used by OpenCL for expressing parallel functions on the GPU as functions marked as parallel in Concurnas are automatically translated into a form understandable by the GPU/OpenCL. GPU computing is for everyone.

Data structures

Modern enterprise computing involves working with data organized into data structures. Some of the most common data structures used are arrays, matrices, lists, sets, maps and numerical ranges.

Concurnas has advanced first class citizen support for not just defining arrays, matrices and n-dimensional arrays but working with them to. Concatenation operators are provided to aid in joining of n dimensional arrays and matrices as well as various means to extract values.

In addition to n-dimensional arrays, Concurnas supports lists, sets, maps and ranges. Concurnas has built in first class citizen support for these essential data structures. With Concurnas you can define lists, maps and ranges in place with convenient, dedicated Python like compact syntax. Concurnas supports the most commonly used operations on these data structures directly, such as adding, removing and checking for the presence of elements.

Concurnas leverages the Java JDK implementation of these data structures. They make use of generics in order to support convenient multi typing of structures. Furthermore, Concurnas employs usage based type inference in order to infer what these generic types should be qualified as at compilation time based on the usage of the data structure.

Null Safe

Concurnas, like other modern programming languages such as Kotlin and Swift has null safety built into its type system. Concurnas requires that a variable's type be explicitly declared as being nullable in order for it to be assigned null, or potentially null value. When working with nullable types, Concurnas enforces a number of restrictions so as to avoid the risk of throwing a NullPointerException. In this way Concurnas enables us to write safe code which is guaranteed to be largely free of NullPointerException's (an unexpected NullPointerException being widely recognized as being one of the most common bugs in modern software engineering).

Concurnas includes sophisticated logic for working with nullable types to cater for situations in which they have already been established as being not null. This makes working with nullable types easy.

Concurnas includes three useful built in operators that can be used when working with nullable types:

  • The safe call operator. This will execute normally as if it were applied to a non nullable type, except for when it's applied to null - in which case it shall return null.
  • The Elvis operator. This will execute normally as if it were applied to a non nullable type, except for when it's applied to null - in which case it shall execute and return the expression on the right hand side of the operator. Often used in conjunction with the safe call operator.
  • The not null assertion operator. This is our final and most dangerous tool for working with nullable types. This operator will deliberately throw a NullPointerException if it is applied to a nullable type of value null, otherwise shall execute normally.

Object Providers

Concurnas offers first class citizen support for dependency injection through Object Providers. Dependency Injection (DI) is a modern software engineering technique for building object oriented systems. The core principle of DI is to separate behavior from dependency resolution (the "plumbing"). In doing so one is obliged to compartmentalize one's software into core functionality, making dependent behavior injectable and thus separating that injectable code from the "plumbing". This has benefits of aiding:

  • Reasoning - By compartmentalizing one's software, it makes reasoning about code easier.
  • Testing - DI facilitates the use of mock implementations when we are testing software which allows that testing to take place in isolation, side effect free and with controlled inputs and outputs which we can validate against.
  • Re-usability - By reducing our software into core functionality we are generally more able to re use that functionality within and outside of the original systems we set out to build.

For the above reasons and more it's clear why DI has become such a useful tool for modern software development. Concurnas object providers build upon the successes of the likes of Spring and Google Guice

Concurnas object providers offer a non invasive and concise, mechanism by which code may be both marked for dependency injection (via the inject keyword), configured (via object provider's) and provided for further execution with all dependencies (including transitive) resolved. Best of all, this all happens in idiomatic Concurnas code and is validated at compile time!

Extensible

Concurnas has first class citizen support for language extensions.

Language extensions are an incredibly powerful feature of Concurnas which enable guest code to be written in languages other than Concurnas. Language extensions reduce the amount of code one would otherwise be required to write and reduce the distance between the problem domain one is operating in, and Concurnas, by allowing us to use the most appropriate language for the task.

Concurnas language extensions operate entirely at compilation time and so have no negative impact upon performance, furthermore, as with Concurnas in general, compile time checking of code is employed, which greatly reduces the likelihood of an error at runtime. Concurnas Language extensions seamlessly integrate with idiomatic Concurnas code and may be used at any point in a Concurnas program. Language extensions may use and produce any component of Concurnas syntax, such as variables, methods, classes etc

Concurnas Language extensions are easy to create and greatly reduce the amount of work a language implementor must perform in order to bring a language into production. They are required to output valid Concurnas code in the form of a String. This Concurnas code is then processed as par normal Concurnas code in subsequent compilation phases. One need focus only upon the 'front-end' aspects of language development, i.e. tokenization, parsing and semantic analysis (which tend to be where the most value add resides), leaving the hard work on code generation etc to the core Concurnas compiler.

Concurnas Language extensions provide an elegant and concise API for language integration (to access variables in scope, types etc), which supports streamline interrogation of the core Concurnas compiler and a convenient mechanism for reporting errors back to the code author as par normal Concurnas compilation.

Domain Specific Language support

Concurnas is a great language for building Domain Specific Languages (DSL's). DSL's enable us to define our own programming languages on top of the functionality offered by the host language in order to achieve the following objectives:

  • Narrow the semantic gap between our host language and the domain in which the problems we're trying to solve persist.
  • Make it easier for domain experts to express solutions to problems without requiring full knowledge of the host programming language.
  • Reduce time to market of solutions.
  • Reduce the amount of code we need to write and maintain.

The aspects of Concurnas which make achieving the above objectives possible are as follows:

  • Operator Overloading. Concurnas provides operator overloading which allows you to apply most of the operators provided by Concurnas to user defined types. Operator overloading reduces the amount of code one would otherwise be required to write and reduces the distance between the problem domain one is operating in, and the underlying language one is programming in.
  • Extension functions. These allow for functionality to be added to classes without needing to interact with the class hierarchy (e.g.extending the class etc). They are a convenient alternative to having to use utility functions/methods/classes which take an instance of a class and often permit a more natural way of interacting with objects. Extension functions may be defined on any type including primitive types
  • Expression lists. This is a neat feature which enables a more natural way of writing expression related code that would otherwise have to be written as a set of chained together calls using the dot operator and/or function invocation brackets. Expression lists may be combined with operator overloading and extension functions to achieve some very impressive results. Using this feature one can create very succinct and readable DSLs

Open Source

Concurnas is free and open source, licensed under the popular and permissive MIT license.

Commercial Backing

Concurnas Ltd. was established in 2018 as a commercial entity in order to support the ongoing development of the Concurnas programming language as open source and to provide commercial support for Concurnas in addition to consulting. For more information on our support packages please see our Support Plans and and Consulting Services here.