Track & compare performance of ICOs. Displays detailed stats like ROI since ICO, ROI vs ETH since ICO, and charts for comparing the historical performance of ICOs.
actionslacks13-Sep-18 09:48 AM
NXT was pretty epic
thanks jl
vpn coin too, but that was before ico's were a thing
I think a well plotted out timeline of returns for projects that jl777 was associated with would serve to elucidate the masses on what is being created here. I'm fine with us being in shadows though. I'll just keep buying while it's cheap.
And I suspect that the coins that supernet holds are payments for the expertise contributed by our anonymous leader and wizard lvl blockchain engineer. If you are new to crypto, and you are here.. you have found a diamond in the rough
3
3
actionslacks13-Sep-18 10:19 AM
The thing I that I find most compelling is that it is the intellectual returns on the work itself that are the driving influence. It is the work in and of itself that feeds this machine. Needless to say. I am backing this project for the rest of my life.(edited)
house13-Sep-18 10:21 AM
props up pillow while chugging a beer
To be frank, after the hundreds of white papers, interviews, conversations with developers since 2013, I will admit that James and Komodo team are far ahead in terms of realising the vision that we as libertarians (small L) are addressing
On top of amazing tech that is incomparable
liberté de mort !
1
jl777c13-Sep-18 10:35 AM
The CC tech has been quite surprising even to me!
10
1
1
1
1
1
1
3
I was able to make a gatewaysCC (improved MGW) in 3 days, still finalizing some issues, but to get an automated crypto tokenizer in days, instead of many months (or years), it is due to the CC architecture
TonyL13-Sep-18 10:37 AM
It's really mind-blowing that so cool and relatively secure things creating so fast
actionslacks13-Sep-18 10:50 AM
I think the most instructional thing as that we, the common plebs of society can build and develop the infrastructure to usurp those that use their system to control us
lucifer13-Sep-18 10:50 AM
Omg this pumping how many people from nxt are in here
actionslacks13-Sep-18 10:51 AM
right here
$tefano.13-Sep-18 10:52 AM
I have bought many kmd this morning (edited)
actionslacks13-Sep-18 10:54 AM
yesterday the sky was falling, today the unicorns are prancing. <My life for a couple years now
lucifer13-Sep-18 10:56 AM
What is the correct channel to propose a project
actionslacks13-Sep-18 10:57 AM
propose away new friend
LocoMB13-Sep-18 10:57 AM
Nice! Sounds like new life for MGW
jl777c13-Sep-18 10:58 AM
yes, it it MGW++
actionslacks13-Sep-18 10:58 AM
was looking at my 401k prospectus and just had to laugh. fixed income fund at 1.8% per year. too bad you can't get an employer match on kmd.
lucifer13-Sep-18 10:59 AM
James How's it going it's a while since the Greek project
jl777c13-Sep-18 11:00 AM
making steady progress
lucifer13-Sep-18 11:01 AM
Yes I can see that its booming in here plenty of activity
How to write utxo based CryptoConditions contracts for KMD chains - by jl777 - KomodoPlatform/Mastering_CryptoConditions
sφldat13-Sep-18 11:24 AM
#cc-general@root
root13-Sep-18 11:24 AM
than you
SHossain13-Sep-18 11:30 AM
Pinned a message.
lucifer13-Sep-18 11:42 AM
Guys, we are running several projects and KMD we have listed as method of payment to buy into our project, The project has several connections to government and academia
www.drachmae.money
Invite Code DTMA160818
555,555 @ 2 EURO Closing 15th of September 2018
555,556 @ 3 EURO Closing 30th of September 2018
1,111,111 @ 4 EURO Closing 15th of October 2018
2,222,222 @ 5 EURO Closing 22nd of October 2018
4,444,444 @ 6 EURO Closing 30th of October 2018
8,888,888 @ 7 EURO Closing 30th of November 2018
The project needs to raise 2.5 million Euro it includes 53 hectares Airport space, and 42 hectares of Free Economic ZOne http://civilixation.md/e-gagauzia/
the asset is the land we build on such as business center, new terminal, hotel/apartments and Extreme sports park
Yep nobody know where moldova is its the poorest country in Europe and most corrupt yet the regional government started to use our blockhcain surveys platform last week https://www.drachmae.money/en/survey/3
e-Gagauzia Business Plan DRAFT GZ-Drachma Version 1.3 2018 CONTENT 1.0.0 Executive Summary 1.1.0 Introduction 1.1.1 Territory 1.1.2 Population 1.1.3 Languages 1.1.4 History of the Gagauz People 1.1.5 Regional Area 1.2.0 The Organisation 1.3.0 Servi...
actionslacks13-Sep-18 12:38 PM
you can get a bootstrap template for a couple dozen euros. just saying...


Oxford Street to get stunning £2.9billion transformation: 'Customers will be so spoilt'
Expect brand temples, new pedestrian spaces and more as Oxford Street plans an incredible £2.9billion regeneration to cement its place as one of the world's premier shopping destinations
by James Andrews, http://www.facebook.com/jameswritesmoney/The biggest transformation in more than 50 years is about to be unleashed on Oxford Street.
In the next 1,000 days some £2.9billion is set to be spent to "catalyse the birth of a new West End", the New West End Company has said.
The organisation - which represents Oxford, Bond and Regent Street businesses - said the money will go to ensure Oxford Street and the shops around it retain their place as a global shopping and leisure destination.
New West End Company chief executive Jace Tyrrell said: "The new deal will see the West End secure ‘International Centre’ status which will lead to a generational shift in how Oxford Street is used.
"Customers will be so spoilt: the rise of brand temples will offer more than just products but experience and reasons to visit; new green pedestrian spaces will emerge; a super speed Crossrail will connect Heathrow Airport to the West End in less than 30 minutes; a vibrant Oxford Street will allow visitors to experience the very best retail, leisure and hospitality."
The move to “International Centre” classification is set to be ratified in 2020 - allowing big changes in how businesses can use the street.
That could mean the arrival of showrooms, cultural spaces, food and leisure activities as well as the traditional shop fronts - and allow community events and evening attractions too.
A quarter of a billion pounds is set to be spent on two new public piazzas at Oxford Circus and Marble Arch as well as "vastly wider and more comfortable" footpaths.
Another £1 billion is being spent in new developments and refurbishments on Oxford Street shops.
Then there's Derwent London’s Soho Place - the first new theatre in the West End for 50 years - alongside Selfridges’ planned permanent cinema in Oxford Street West offering experiences beyond shopping.
There's also the arrival of Crossrail and the Elizabeth Line in 2021 - meaning Oxford Street is just two hours from Paris and Amsterdam.
"The next five years will see extraordinary change in the district, more than in the last 50 years," Tyrrell said.
"We are truly witnessing a transformative moment for the most renowned shopping destination in the world.”


Based in Nairobi Kenya,ICEET prides itself in provision of professional corporate trainings, annual awards, research, Publications in the clean energy industry.
When you work with us, you are part of a team of committed collaborators. all aspects of our software development process are intergrated,interactive and agile
Our approach unifies design, development and product management to create exceptional products.
We start each project by understanding your business goals, the user's needs and the product requirements
Then we help translate them into effective and elegant solutions.
Before we sign a contract or write a line of code our team will spend the neccessary time needed to understand your product vision
The outcome of this scoping session is a proposal or high-level statement of work.
based on your requirements, we can provide acomplete offering or just the ieces you need.
our design practice offers a full range of services including brand strategy, interaction and visual designs and user experience testing. Throughout your project, our designers create and implement visual design and workflows, solicit user feedback and work with you to make sure what gets built is what is needed.
All engineers are fluent in the latest enterprise, mobile and web development technologies. They collaborate with your team to write and improve code on a daily basis, using proven practices such as test-driven development and pair programming.
Planning and development is iteractive. Because we are constantly coding and testing, the products we build are always ready to go live. This iterative process allows for changes as business requirements evolve.
ICEET
Security
Transformations
Landing page
Interactivity
Indulge
Seal
Signature


Lens of Situation
The overall situation for Shin Megami Tensei can be confusing at first the game seems simple, the main character has a dream one night about demons and people he will meet later in the game and as his whole world starts to flip upside down as you go from average boy to killing zombie cops that are helping a bad guy sacrifice a girl, but then the game kills everyone with a nuke and it seems like that should be the end. However, the player wakes up 30 years into the future somehow alive and the world has become a war between literal God and Satan, the player must choose to pick a side or either side, this will change some storyline and the ending of the game.
In the end the situation for the main character is one of hardship and constant struggle against two ideologies expressed by the war between God and Satan, although the storyline is confusing it is a very long game so going through it the player goes at a slow pace with lots more detail and time to explain the deeper workings for the storyline making it not as confusing. This game is very story heavy and not like many other games of its time or nowadays truly making it a very unique game that many players fell in love with as there had not been a game like this before in America. Most RPGs tend to live in a fantasy world or another time period But SMT was set in current time making characters and their problems relatable to the player.


1. The android device can’t use the WiFi and Date at same time. To share the photos or videos, please download the videos or photos to your phone at APP “DashCam” first, then open the App “Gallery” to find videos or photos and
disconnect the Dash Cam’s WiFi to share it via phone network.
2. For you safety, DO NOT operate the phone while you are driving.


If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden...
If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden...
If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden...


Ballykissangel actor Niall Tóibín dead at 89 after 'long illness'
Irish actor Niall Tóibín was best known for playing Father MacAnally in the hit BBC series
by Louise Randell, https://www.mirror.co.uk/authors/louise-randell/Ballykissangel actor Niall Tóibín has died aged 89.
The Irish actor and comedian is said to have passed away after a long illness, according to RTE News.
He's believed to have died in Dublin on Wednesday, and is survived by his children Sean, Muireann, Aisling, Sighle and Fiana.
His wife Judy died in 2002.
Tóibín is best known for playing Father MacAnally in the hit BBC series which ran from 1996 until 2001, starring opposite Stephen Tompkinson and Dervla Kirwan.
Another high profile role was starring opposite Nicole Kidman and Tom Cruise in 1992 movie Far and Away.
Tóibín started his career in the 1950s by appearing in a series of radio dramas before graduating to film and TV as well as the stage.
In 1970, he appeared in the film Ryan's Daughter with Robert Mitcheum, and went on to land a role in Irish TV drama Bracken with Gabriel Byrne in 1978.
He appeared in the TV adaptation of Brideshead Revisited with Jeremy Irons in 1981, and with Kidman and Cruise in 1992 Ron Howard drama Far and Away.
In 2003, he scored another Hollywood role by playing Judge Ballaugh in Cate Blanchett's thriller Veronica Guerin.
He continued working up until last year, with his final project being a short film called Remains.
Tóibín was handed a number of honours for his acting work over the years, picking up a lifetime achievement award from the Irish Film and Television Academy 2011 and being awarded the freedom of Cork in 2015.


About us
Frans Scherpenisse founded Alconet in 1997, the creation took place in the Rotterdam Botlek. Alconet offers different services; a variety of services that are facilitated on the own depot, such as maintenance and renovation and the purchase and sales of a large number of container types every year. By using high quality materials and certified staff, we offer the highest possible service towards our customers.
In the past 15 years Alconet has grown into a business with a solid negotiating position in the market. In addition several modification programs are being used, we have fully equipped mobile workshops and we obtained many storage contracts successfully.
The primary advantage of Alconet is that we offer customer-oriented solutions; every customer has different wishes and needs and therefor requires a different approach. By keeping this in mind, we are able to offer every customer a suitable solution, provided that this is technically feasible, related to each container type. Alconet guarantees a high-quality product, in addition we act fast and we are flexible and reliable. You can trust us with your containers!


2017 Campership Application:
Dear Parent/Scout Leader:
Greater New York Councils offers camperships to registered youth from New York City to assist with camp fees. Campership amounts are based on amount requested and family need. In some cases, depending on speciﬁc circumstances, no campership may be awarded.
This form must be completely ﬁlled out.
Total yearly income must reflect all household family members. Please include all types of household income: salary, unemployment insurance, pensions, alimony, disability, public assistance, SNAP, earned income tax credit, etc.
A $25 per camper, per session/week deposit must be paid for this application to be considered.
To accurately credit the unit with the camper’s awarded amount, the council, district, and pack/troop information must be completed.
Cub Scouts who are crossing over to Boy Scouts must indicate their new troop and the troop they will be attending camp with. Submit camper’s transfer information to the GNYC ofﬁce on time to avoid confusion in locating camper with the appropriate unit.
Camperships awarded will be based on the Early Bird cost. No consideration will be given for the higher fee charged after May 31st.
If a Scout receives multiple camperships, the total cannot exceed the cost of camp, less the $25 deposit. If a Scout’s total camperships exceed this amount, the GNYC campership will be reduced accordingly.
Any awarded campership amount is included and deducted from the total camp cost of fees due by May 31st. All campers who have not received camperships by May 31st will be responsible for full payment. Reimbursement, if any will be provided in a pack/troop check, typically while unit is at camp (if no discrepancies are found). We do not make checks out to individuals (except for youth attending an individual specialty camp). Please keep track of payments by individual parents for their reimbursement from the pack/troop check.


Politics
The Trump administration has to follow a series of statutory deadlines in order to get NAFTA 2.0 passed through Congress. How far along are they?
By Megan Cassella | 04/10/18 08:13 PM EDT


public class Resources
extends totalcross.lang.Object
| Modifier and Type | Field and Description |
|---|---|
static Image |
back |
static Image |
button |
static TristateImage |
checkBkg |
static TristateImage |
checkSel |
static String |
chimeMP3 |
static Image |
comboArrow |
static Image |
comboArrow2 |
static Image |
combobox |
static Image |
edit |
static Image |
exit |
static Image |
grid |
static Image |
listbox |
static Image |
menu |
static Image |
multibutton |
static Image |
multiedit |
static Image |
progressbarv |
static Image |
progressHandle |
static TristateImage |
radioBkg |
static TristateImage |
radioSel |
static Image |
scrollposh |
static Image |
scrollposv |
static Image |
switchBack |
static Image |
switchBrd |
static Image |
switchBrdAnd |
static Image |
switchBrdIos |
static Image |
switchBtn |
static Image |
switchBtnAnd |
static Image |
switchBtnIos |
static Image |
tab |
static Image |
tab2 |
static Image |
warning |
| Constructor and Description |
|---|
Resources() |
| Modifier and Type | Method and Description |
|---|---|
static void |
flush()
Flush all resources held in the hashtables of the classes used by the Android user interface style.
|
static void |
uiStyleChanged() |
public static Image button
public static Image edit
public static Image combobox
public static Image multibutton
public static Image listbox
public static Image multiedit
public static Image progressbarv
public static Image scrollposh
public static Image scrollposv
public static Image tab
public static Image tab2
public static Image grid
public static TristateImage checkSel
public static TristateImage checkBkg
public static TristateImage radioSel
public static TristateImage radioBkg
public static Image warning
public static Image progressHandle
public static Image exit
public static Image back
public static Image menu
public static Image comboArrow
public static Image comboArrow2
public static Image switchBrdAnd
public static Image switchBack
public static Image switchBtnAnd
public static Image switchBtnIos
public static Image switchBrdIos
public static Image switchBtn
public static Image switchBrd
public static String chimeMP3


Persistence - Schema Evolution
When working on long running projects using Persistence, or any kind of Event Sourcing architectures, schema evolution becomes one of the more important technical aspects of developing your application. The requirements as well as our own understanding of the business domain may (and will) change in time.
In fact, if a project matures to the point where you need to evolve its schema to adapt to changing business requirements you can view this as first signs of its success – if you wouldn't need to adapt anything over an apps lifecycle that could mean that no-one is really using it actively.
In this chapter we will investigate various schema evolution strategies and techniques from which you can pick and choose the ones that match your domain and challenge at hand.
Note
This page proposes a number of possible solutions to the schema evolution problem and explains how some of the utilities Akka provides can be used to achieve this, it is by no means a complete (closed) set of solutions.
Sometimes, based on the capabilities of your serialization formats, you may be able to evolve your schema in different ways than outlined in the sections below. If you discover useful patterns or techniques for schema evolution feel free to submit Pull Requests to this page to extend it.
Schema evolution in event-sourced systems
In recent years we have observed a tremendous move towards immutable append-only datastores, with event-sourcing being the prime technique successfully being used in these settings. For an excellent overview why and how immutable data makes scalability and systems design much simpler you may want to read Pat Helland's excellent Immutability Changes Everything whitepaper.
Since with Event Sourcing the events are immutable and usually never deleted – the way schema evolution is handled differs from how one would go about it in a mutable database setting (e.g. in typical CRUD database applications).
The system needs to be able to continue to work in the presence of "old" events which were stored under the "old" schema. We also want to limit complexity in the business logic layer, exposing a consistent view over all of the events of a given type to PersistentActor s and persistence queries. This allows the business logic layer to focus on solving business problems instead of having to explicitly deal with different schemas.
- In summary, schema evolution in event sourced systems exposes the following characteristics:
- Allow the system to continue operating without large scale migrations to be applied,
- Allow the system to read "old" events from the underlying storage, however present them in a "new" view to the application logic,
- Transparently promote events to the latest versions during recovery (or queries) such that the business logic need not consider multiple versions of events
Types of schema evolution
Before we explain the various techniques that can be used to safely evolve the schema of your persistent events over time, we first need to define what the actual problem is, and what the typical styles of changes are.
Since events are never deleted, we need to have a way to be able to replay (read) old events, in such way that does not force the PersistentActor to be aware of all possible versions of an event that it may have persisted in the past. Instead, we want the Actors to work on some form of "latest" version of the event and provide some means of either converting old "versions" of stored events into this "latest" event type, or constantly evolve the event definition - in a backwards compatible way - such that the new deserialization code can still read old events.
The most common schema changes you will likely are:
- adding a field to an event type,
- remove or rename field in event type,
- remove event type,
- split event into multiple smaller events.
The following sections will explain some patterns which can be used to safely evolve your schema when facing those changes.
Picking the right serialization format
Picking the serialization format is a very important decision you will have to make while building your application. It affects which kind of evolutions are simple (or hard) to do, how much work is required to add a new datatype, and, last but not least, serialization performance.
If you find yourself realising you have picked "the wrong" serialization format, it is always possible to change the format used for storing new events, however you would have to keep the old deserialization code in order to be able to replay events that were persisted using the old serialization scheme. It is possible to "rebuild" an event-log from one serialization format to another one, however it may be a more involved process if you need to perform this on a live system.
Binary serialization formats that we have seen work well for long-lived applications include the very flexible IDL based: Google Protobuf, Apache Thrift or Apache Avro. Avro schema evolution is more "entire schema" based, instead of single fields focused like in protobuf or thrift, and usually requires using some kind of schema registry.
Users who want their data to be human-readable directly in the write-side datastore may opt to use plain-old JSON as the storage format, though that comes at a cost of lacking support for schema evolution and relatively large marshalling latency.
There are plenty excellent blog posts explaining the various trade-offs between popular serialization formats, one post we would like to highlight is the very well illustrated Schema evolution in Avro, Protocol Buffers and Thrift by Martin Kleppmann.
Provided default serializers
Akka Persistence provides Google Protocol Buffers based serializers (using Akka Serialization) for it's own message types such as PersistentRepr, AtomicWrite and snapshots. Journal plugin implementations may choose to use those provided serializers, or pick a serializer which suits the underlying database better.
Note
Serialization is NOT handled automatically by Akka Persistence itself. Instead, it only provides the above described serializers, and in case a AsyncWriteJournal plugin implementation chooses to use them directly, the above serialization scheme will be used.
Please refer to your write journal's documentation to learn more about how it handles serialization!
For example, some journals may choose to not use Akka Serialization at all and instead store the data in a format that is more "native" for the underlying datastore, e.g. using JSON or some other kind of format that the target datastore understands directly.
The below figure explains how the default serialization scheme works, and how it fits together with serializing the user provided message itself, which we will from here on refer to as the payload (highlighted in yellow):
The blue colored regions of the PersistentMessage indicate what is serialized using the generated protocol buffers serializers, and the yellow payload indicates the user provided event (by calling persist(payload)(...)). As you can see, the PersistentMessage acts as an envelope around the payload, adding various fields related to the origin of the event (persistenceId, sequenceNr and more).
More advanced techniques (e.g. Remove event class and ignore events) will dive into using the manifests for increasing the flexibility of the persisted vs. exposed types even more. However for now we will focus on the simpler evolution techniques, concerning simply configuring the payload serializers.
By default the payload will be serialized using Java Serialization. This is fine for testing and initial phases of your development (while you're still figuring out things and the data will not need to stay persisted forever). However, once you move to production you should really pick a different serializer for your payloads.
Warning
Do not rely on Java serialization (which will be picked by Akka by default if you don't specify any serializers) for serious application development! It does not lean itself well to evolving schemas over long periods of time, and its performance is also not very high (it never was designed for high-throughput scenarios).
Configuring payload serializers
This section aims to highlight the complete basics on how to define custom serializers using Akka Serialization. Many journal plugin implementations use Akka Serialization, thus it is tremendously important to understand how to configure it to work with your event classes.
Note
Read the Akka Serialization docs to learn more about defining custom serializers, to improve performance and maintainability of your system. Do not depend on Java serialization for production deployments.
The below snippet explains in the minimal amount of lines how a custom serializer can be registered. For more in-depth explanations on how serialization picks the serializer to use etc, please refer to its documentation.
First we start by defining our domain model class, here representing a person:
final case class Person(name: String, surname: String)
Next we implement a serializer (or extend an existing one to be able to handle the new Person class):
/**
* Simplest possible serializer, uses a string representation of the Person class.
*
* Usually a serializer like this would use a library like:
* protobuf, kryo, avro, cap'n proto, flatbuffers, SBE or some other dedicated serializer backend
* to perform the actual to/from bytes marshalling.
*/
class SimplestPossiblePersonSerializer extends SerializerWithStringManifest {
val Utf8 = Charset.forName("UTF-8")
val PersonManifest = classOf[Person].getName
// unique identifier of the serializer
def identifier = 1234567
// extract manifest to be stored together with serialized object
override def manifest(o: AnyRef): String = o.getClass.getName
// serialize the object
override def toBinary(obj: AnyRef): Array[Byte] = obj match {
case p: Person => s"""${p.name}|${p.surname}""".getBytes(Utf8)
case _ => throw new IllegalArgumentException(
s"Unable to serialize to bytes, clazz was: ${obj.getClass}!")
}
// deserialize the object, using the manifest to indicate which logic to apply
override def fromBinary(bytes: Array[Byte], manifest: String): AnyRef =
manifest match {
case PersonManifest =>
val nameAndSurname = new String(bytes, Utf8)
val Array(name, surname) = nameAndSurname.split("[|]")
Person(name, surname)
case _ => throw new IllegalArgumentException(
s"Unable to deserialize from bytes, manifest was: $manifest! Bytes length: " +
bytes.length)
}
}
And finally we register the serializer and bind it to handle the docs.persistence.Person class:
# application.conf
akka {
actor {
serializers {
person = "docs.persistence.SimplestPossiblePersonSerializer"
}
serialization-bindings {
"docs.persistence.Person" = person
}
}
}
Deserialization will be performed by the same serializer which serialized the message initially because of the identifier being stored together with the message.
Please refer to the Akka Serialization documentation for more advanced use of serializers, especially the Serializer with String Manifest section since it is very useful for Persistence based applications dealing with schema evolutions, as we will see in some of the examples below.
Schema evolution in action
In this section we will discuss various schema evolution techniques using concrete examples and explaining some of the various options one might go about handling the described situation. The list below is by no means a complete guide, so feel free to adapt these techniques depending on your serializer's capabilities and/or other domain specific limitations.
Add fields
Situation: You need to add a field to an existing message type. For example, a SeatReservation(letter:String, row:Int) now needs to have an associated code which indicates if it is a window or aisle seat.
Solution: Adding fields is the most common change you'll need to apply to your messages so make sure the serialization format you picked for your payloads can handle it apropriately, i.e. such changes should be binary compatible. This is easily achieved using the right serializer toolkit – we recommend something like Google Protocol Buffers or Apache Thrift however other tools may fit your needs just as well – picking a serializer backend is something you should research before picking one to run with. In the following examples we will be using protobuf, mostly because we are familiar with it, it does its job well and Akka is using it internally as well.
While being able to read messages with missing fields is half of the solution, you also need to deal with the missing values somehow. This is usually modeled as some kind of default value, or by representing the field as an Option[T] See below for an example how reading an optional field from a serialized protocol buffers message might look like.
sealed abstract class SeatType { def code: String }
object SeatType {
def fromString(s: String) = s match {
case Window.code => Window
case Aisle.code => Aisle
case Other.code => Other
case _ => Unknown
}
case object Window extends SeatType { override val code = "W" }
case object Aisle extends SeatType { override val code = "A" }
case object Other extends SeatType { override val code = "O" }
case object Unknown extends SeatType { override val code = "" }
}
case class SeatReserved(letter: String, row: Int, seatType: SeatType)
Next we prepare an protocol definition using the protobuf Interface Description Language, which we'll use to generate the serializer code to be used on the Akka Serialization layer (notice that the schema aproach allows us to easily rename fields, as long as the numeric identifiers of the fields do not change):
// FlightAppModels.proto
option java_package = "docs.persistence.proto";
option optimize_for = SPEED;
message SeatReserved {
required string letter = 1;
required uint32 row = 2;
optional string seatType = 3; // the new field
}
The serializer implementation uses the protobuf generated classes to marshall the payloads. Optional fields can be handled explicitly or missing values by calling the has... methods on the protobuf object, which we do for seatType in order to use a Unknown type in case the event was stored before we had introduced the field to this event type:
/**
* Example serializer impl which uses protocol buffers generated classes (proto.*)
* to perform the to/from binary marshalling.
*/
class AddedFieldsSerializerWithProtobuf extends SerializerWithStringManifest {
override def identifier = 67876
final val SeatReservedManifest = classOf[SeatReserved].getName
override def manifest(o: AnyRef): String = o.getClass.getName
override def fromBinary(bytes: Array[Byte], manifest: String): AnyRef =
manifest match {
case SeatReservedManifest =>
// use generated protobuf serializer
seatReserved(FlightAppModels.SeatReserved.parseFrom(bytes))
case _ =>
throw new IllegalArgumentException("Unable to handle manifest: " + manifest)
}
override def toBinary(o: AnyRef): Array[Byte] = o match {
case s: SeatReserved =>
FlightAppModels.SeatReserved.newBuilder
.setRow(s.row)
.setLetter(s.letter)
.setSeatType(s.seatType.code)
.build().toByteArray
}
// -- fromBinary helpers --
private def seatReserved(p: FlightAppModels.SeatReserved): SeatReserved =
SeatReserved(p.getLetter, p.getRow, seatType(p))
// handle missing field by assigning "Unknown" value
private def seatType(p: FlightAppModels.SeatReserved): SeatType =
if (p.hasSeatType) SeatType.fromString(p.getSeatType) else SeatType.Unknown
}
Rename fields
Situation: When first designing the system the SeatReverved event featured an code field. After some time you discover that what was originally called code actually means seatNr, thus the model should be changed to reflect this concept more accurately.
Solution 1 - using IDL based serializers: First, we will discuss the most efficient way of dealing with such kinds of schema changes – IDL based serializers.
IDL stands for Interface Description Language, and means that the schema of the messages that will be stored is based on this description. Most IDL based serializers also generate the serializer / deserializer code so that using them is not too hard. Examples of such serializers are protobuf or thrift.
Using these libraries rename operations are "free", because the field name is never actually stored in the binary representation of the message. This is one of the advantages of schema based serializers, even though that they add the overhead of having to maintain the schema. When using serializers like this, no additional code change (except renaming the field and method used during serialization) is needed to perform such evolution:
This is how such a rename would look in protobuf:
// protobuf message definition, BEFORE:
message SeatReserved {
required string code = 1;
}
// protobuf message definition, AFTER:
message SeatReserved {
required string seatNr = 1; // field renamed, id remains the same
}
It is important to learn about the strengths and limitations of your serializers, in order to be able to move swiftly and refactor your models fearlessly as you go on with the project.
Note
Learn in-depth about the serialization engine you're using as it will impact how you can aproach schema evolution.
Some operations are "free" in certain serialization formats (more often than not: removing/adding optional fields, sometimes renaming fields etc.), while some other operations are strictly not possible.
Solution 2 - by manually handling the event versions: Another solution, in case your serialization format does not support renames as easily as the above mentioned formats, is versioning your schema. For example, you could have made your events carry an additional field called _version which was set to 1 (because it was the initial schema), and once you change the schema you bump this number to 2, and write an adapter which can perform the rename.
This approach is popular when your serialization format is something like JSON, where renames can not be performed automatically by the serializer. You can do these kinds of "promotions" either manually (as shown in the example below) or using a library like Stamina which helps to create those V1->V2->V3->...->Vn promotion chains without much boilerplate.
The following snippet showcases how one could apply renames if working with plain JSON (using spray.json.JsObject):
class JsonRenamedFieldAdapter extends EventAdapter {
val marshaller = new ExampleJsonMarshaller
val V1 = "v1"
val V2 = "v2"
// this could be done independently for each event type
override def manifest(event: Any): String = V2
override def toJournal(event: Any): JsObject =
marshaller.toJson(event)
override def fromJournal(event: Any, manifest: String): EventSeq = event match {
case json: JsObject => EventSeq(marshaller.fromJson(manifest match {
case V1 => rename(json, "code", "seatNr")
case V2 => json // pass-through
case unknown => throw new IllegalArgumentException(s"Unknown manifest: $unknown")
}))
case _ =>
val c = event.getClass
throw new IllegalArgumentException("Can only work with JSON, was: %s".format(c))
}
def rename(json: JsObject, from: String, to: String): JsObject = {
val value = json.fields(from)
val withoutOld = json.fields - from
JsObject(withoutOld + (to -> value))
}
}
As you can see, manually handling renames induces some boilerplate onto the EventAdapter, however much of it you will find is common infrastructure code that can be either provided by an external library (for promotion management) or put together in a simple helper trait.
Note
The technique of versioning events and then promoting them to the latest version using JSON transformations can of course be applied to more than just field renames – it also applies to adding fields and all kinds of changes in the message format.
Remove event class and ignore events
Situation: While investigating app performance you notice that insane amounts of CustomerBlinked events are being stored for every customer each time he/she blinks. Upon investigation you decide that the event does not add any value and should be deleted. You still have to be able to replay from a journal which contains those old CustomerBlinked events though.
Naive solution - drop events in EventAdapter:
The problem of removing an event type from the domain model is not as much its removal, as the implications for the recovery mechanisms that this entails. For example, a naive way of filtering out certain kinds of events from being delivered to a recovering PersistentActor is pretty simple, as one can simply filter them out in an EventAdapter:
This however does not address the underlying cost of having to deserialize all the events during recovery, even those which will be filtered out by the adapter. In the next section we will improve the above explained mechanism to avoid deserializing events which would be filtered out by the adapter anyway, thus allowing to save precious time during a recovery containing lots of such events (without actually having to delete them).
Improved solution - deserialize into tombstone:
In the just described technique we have saved the PersistentActor from receiving un-wanted events by filtering them out in the EventAdapter, however the event itself still was deserialized and loaded into memory. This has two notable downsides:
- first, that the deserialization was actually performed, so we spent some of out time budget on the deserialization, even though the event does not contribute anything to the persistent actors state.
- second, that we are unable to remove the event class from the system – since the serializer still needs to create the actuall instance of it, as it does not know it will not be used.
The solution to these problems is to use a serializer that is aware of that event being no longer needed, and can notice this before starting to deserialize the object.
This aproach allows us to remove the original class from our classpath, which makes for less "old" classes lying around in the project. This can for example be implemented by using an SerializerWithStringManifest (documented in depth in Serializer with String Manifest). By looking at the string manifest, the serializer can notice that the type is no longer needed, and skip the deserialization all-together:
The serializer detects that the string manifest points to a removed event type and skips attempting to deserialize it:
case object EventDeserializationSkipped
class RemovedEventsAwareSerializer extends SerializerWithStringManifest {
val utf8 = Charset.forName("UTF-8")
override def identifier: Int = 8337
val SkipEventManifestsEvents = Set(
"docs.persistence.CustomerBlinked" // ...
)
override def manifest(o: AnyRef): String = o.getClass.getName
override def toBinary(o: AnyRef): Array[Byte] = o match {
case _ => o.toString.getBytes(utf8) // example serialization
}
override def fromBinary(bytes: Array[Byte], manifest: String): AnyRef =
manifest match {
case m if SkipEventManifestsEvents.contains(m) =>
EventDeserializationSkipped
case other => new String(bytes, utf8)
}
}
The EventAdapter we implemented is aware of EventDeserializationSkipped events (our "Tombstones"), and emits and empty EventSeq whenever such object is encoutered:
class SkippedEventsAwareAdapter extends EventAdapter {
override def manifest(event: Any) = ""
override def toJournal(event: Any) = event
override def fromJournal(event: Any, manifest: String) = event match {
case EventDeserializationSkipped => EventSeq.empty
case _ => EventSeq(event)
}
}
Detach domain model from data model
Situation: You want to separate the application model (often called the "domain model") completely from the models used to persist the corresponding events (the "data model"). For example because the data representation may change independently of the domain model.
Another situation where this technique may be useful is when your serialization tool of choice requires generated classes to be used for serialization and deserialization of objects, like for example Google Protocol Buffers do, yet you do not want to leak this implementation detail into the domain model itself, which you'd like to model as plain Scala case classes.
Solution: In order to detach the domain model, which is often represented using pure scala (case) classes, from the data model classes which very often may be less user-friendly yet highly optimised for throughput and schema evolution (like the classes generated by protobuf for example), it is possible to use a simple EventAdapter which maps between these types in a 1:1 style as illustrated below:
We will use the following domain and data models to showcase how the separation can be implemented by the adapter:
/** Domain model - highly optimised for domain language and maybe "fluent" usage */
object DomainModel {
final case class Customer(name: String)
final case class Seat(code: String) {
def bookFor(customer: Customer): SeatBooked = SeatBooked(code, customer)
}
final case class SeatBooked(code: String, customer: Customer)
}
/** Data model - highly optimised for schema evolution and persistence */
object DataModel {
final case class SeatBooked(code: String, customerName: String)
}
The EventAdapter takes care of converting from one model to the other one (in both directions), alowing the models to be completely detached from each other, such that they can be optimised independently as long as the mapping logic is able to convert between them:
class DetachedModelsAdapter extends EventAdapter {
override def manifest(event: Any): String = ""
override def toJournal(event: Any): Any = event match {
case DomainModel.SeatBooked(code, customer) =>
DataModel.SeatBooked(code, customer.name)
}
override def fromJournal(event: Any, manifest: String): EventSeq = event match {
case DataModel.SeatBooked(code, customerName) =>
EventSeq(DomainModel.SeatBooked(code, DomainModel.Customer(customerName)))
}
}
The same technique could also be used directly in the Serializer if the end result of marshalling is bytes. Then the serializer can simply convert the bytes do the domain object by using the generated protobuf builders.
Store events as human-readable data model
Situation: You want to keep your persisted events in a human-readable format, for example JSON.
Solution: This is a special case of the Detach domain model from data model pattern, and thus requires some co-operation from the Journal implementation to achieve this.
An example of a Journal which may implement this pattern is MongoDB, however other databases such as PostgreSQL and Cassandra could also do it because of their built-in JSON capabilities.
In this aproach, the EventAdapter is used as the marshalling layer: it serializes the events to/from JSON. The journal plugin notices that the incoming event type is JSON (for example by performing a match on the incoming event) and stores the incoming object directly.
class JsonDataModelAdapter extends EventAdapter {
override def manifest(event: Any): String = ""
val marshaller = new ExampleJsonMarshaller
override def toJournal(event: Any): JsObject =
marshaller.toJson(event)
override def fromJournal(event: Any, manifest: String): EventSeq = event match {
case json: JsObject =>
EventSeq(marshaller.fromJson(json))
case _ =>
throw new IllegalArgumentException(
"Unable to fromJournal a non-JSON object! Was: " + event.getClass)
}
}
Note
This technique only applies if the Akka Persistence plugin you are using provides this capability. Check the documentation of your favourite plugin to see if it supports this style of persistence.
If it doesn't, you may want to skim the list of existing journal plugins, just in case some other plugin for your favourite datastore does provide this capability.
Alternative solution:
In fact, an AsyncWriteJournal implementation could natively decide to not use binary serialization at all, and always serialize the incoming messages as JSON - in which case the toJournal implementation of the EventAdapter would be an identity function, and the fromJournal would need to de-serialize messages from JSON.
Note
If in need of human-readable events on the write-side of your application reconsider whether preparing materialized views using Persistence Query would not be an efficient way to go about this, without compromising the write-side's throughput characteristics.
If indeed you want to use a human-readable representation on the write-side, pick a Persistence plugin that provides that functionality, or – implement one yourself.
Split large event into fine-grained events
Situation: While refactoring your domain events, you find that one of the events has become too large (coarse-grained) and needs to be split up into multiple fine-grained events.
Solution: Let us consider a situation where an event represents "user details changed". After some time we discover that this event is too coarse, and needs to be split into "user name changed" and "user address changed", because somehow users keep changing their usernames a lot and we'd like to keep this as a separate event.
The write side change is very simple, we simply persist UserNameChanged or UserAddressChanged depending on what the user actually intended to change (instead of the composite UserDetailsChanged that we had in version 1 of our model).
During recovery however, we now need to convert the old V1 model into the V2 representation of the change. Depending if the old event contains a name change, we either emit the UserNameChanged or we don't, and the address change is handled similarily:
trait V1
trait V2
// V1 event:
final case class UserDetailsChanged(name: String, address: String) extends V1
// corresponding V2 events:
final case class UserNameChanged(name: String) extends V2
final case class UserAddressChanged(address: String) extends V2
// event splitting adapter:
class UserEventsAdapter extends EventAdapter {
override def manifest(event: Any): String = ""
override def fromJournal(event: Any, manifest: String): EventSeq = event match {
case UserDetailsChanged(null, address) => EventSeq(UserAddressChanged(address))
case UserDetailsChanged(name, null) => EventSeq(UserNameChanged(name))
case UserDetailsChanged(name, address) =>
EventSeq(
UserNameChanged(name),
UserAddressChanged(address))
case event: V2 => EventSeq(event)
}
override def toJournal(event: Any): Any = event
}
By returning an EventSeq from the event adapter, the recovered event can be converted to multiple events before being delivered to the persistent actor.
Contents


class Sequence
Operations for higher-level sequences
does PositionalBindFailover
A Sequence
implements a series of methods for converting hight-level Seq
s into different types of objects, from positional to other.
Methods
TBD
Operations for higher-level sequences
does PositionalBindFailover
A Sequence
implements a series of methods for converting hight-level Seq
s into different types of objects, from positional to other.
TBD


Well, it doesn't work, what's the
buzz.
Here, but hardly we'll
answer.
It means that you can find this post
as a note
here and nobody will see it.

Because you can't have friends, huh!
In fact, we want it to be available in the future.
You can choose or find someone here.
Say thanks that you can delete them.
You can change your name, picture,
password and etc. here.
{% endblock %}


Calendar.CalendarWeekRowComponent Class
Item Index
Properties
Properties
classNames
Array
private
Default: `[ 'week-row' ]`
days
Array
private
An array of Day
objects to display for this week (row) of the calendar.
var Day = Ember.Object.extend({
date: {Integer}, // 1-31
month: {Integer},// 0-11
year: {Integer},
inMonth: true
});
There should be 7 days. 1 for each day of the week (starting on monday).
events
Data_type
private
layout
String
private
model
Array
An array of event models.


VPPINFRA (Infrastructure)¶
The files associated with the VPP Infrastructure layer are located in the ./src/vppinfra folder.
 It also provides high-performance dynamic arrays, hashes, bitmaps, high-precision real-time clock support, fine-grained event-logging, and data structure serialization.
One fair comment / fair warning about vppinfra: you can’t always tell a macro from an inline function from an ordinary function simply by name. Macros are used to avoid function calls in the typical case, and to cause (intentional) side-effects.
Vppinfra has been around for almost 20 years and tends not to change frequently. The VPP Infrastructure layer contains the following functions:
Vectors¶
Vppinfra vectors are ubiquitous dynamically resized arrays with by user defined “headers”. Many vpppinfra data structures (e.g. hash, heap, pool) are vectors with various different headers.
The memory layout looks like this:
User header (optional, uword aligned)
Alignment padding (if needed)
Vector length in elements
User's pointer -> Vector element 0
Vector element 1
...
Vector element N-1
As shown above, the vector APIs deal with pointers to the 0th element of a vector. Null pointers are valid vectors of length zero.
To avoid thrashing the memory allocator, one often resets the length of a vector to zero while retaining the memory allocation. Set the vector length field to zero via the vec_reset_length(v) macro. [Use the macro! It’s smart about NULL pointers.]
Typically, the user header is not present. User headers allow for other data structures to be built atop vppinfra vectors. Users may specify the alignment for first data element of a vector via the [vec]()*_aligned macros.
Vector elements can be any C type e.g. (int, double, struct bar). This is also true for data types built atop vectors (e.g. heap, pool, etc.). Many macros have _a variants supporting alignment of vector elements and _h variants supporting non-zero-length vector headers. The _ha variants support both. Additionally cacheline alignment within a vector element structure can be specified using the [CLIB_CACHE_LINE_ALIGN_MARK]() macro.
Inconsistent usage of header and/or alignment related macro variants will cause delayed, confusing failures.
Standard programming error: memorize a pointer to the ith element of a vector, and then expand the vector. Vectors expand by 3/2, so such code may appear to work for a period of time. Correct code almost always memorizes vector indices which are invariant across reallocations.
In typical application images, one supplies a set of global functions designed to be called from gdb. Here are a few examples:
vl(v) - prints vec_len(v)
pe(p) - prints pool_elts(p)
pifi(p, index) - prints pool_is_free_index(p, index)
debug_hex_bytes (p, nbytes) - hex memory dump nbytes starting at p
Use the “show gdb” debug CLI command to print the current set.
Bitmaps¶
Vppinfra bitmaps are dynamic, built using the vppinfra vector APIs. Quite handy for a variety jobs.
Pools¶
Vppinfra pools combine vectors and bitmaps to rapidly allocate and free fixed-size data structures with independent lifetimes. Pools are perfect for allocating per-session structures.
Hashes¶
Vppinfra provides several hash flavors. Data plane problems involving packet classification / session lookup often use ./src/vppinfra/bihash_template.[ch] bounded-index extensible hashes. These templates are instantiated multiple times, to efficiently service different fixed-key sizes.
Bihashes are thread-safe. Read-locking is not required. A simple spin-lock ensures that only one thread writes an entry at a time.
The original vppinfra hash implementation in ./src/vppinfra/hash.[ch] are simple to use, and are often used in control-plane code which needs exact-string-matching.
In either case, one almost always looks up a key in a hash table to obtain an index in a related vector or pool. The APIs are simple enough, but one must take care when using the unmanaged arbitrary-sized key variant. Hash_set_mem (hash_table, key_pointer, value) memorizes key_pointer. It is usually a bad mistake to pass the address of a vector element as the second argument to hash_set_mem. It is perfectly fine to memorize constant string addresses in the text segment.
Timekeeping¶
Vppinfra includes high-precision, low-cost timing services. The datatype clib_time_t and associated functions reside in ./src/vppinfra/time.[ch]. Call clib_time_init (clib_time_t *cp) to initialize the clib_time_t object.
Clib_time_init(…) can use a variety of different ways to establish the hardware clock frequency. At the end of the day, vppinfra timekeeping takes the attitude that the operating system’s clock is the closest thing to a gold standard it has handy.
When properly configured, NTP maintains kernel clock synchronization with a highly accurate off-premises reference clock. Notwithstanding network propagation delays, a synchronized NTP client will keep the kernel clock accurate to within 50ms or so.
Why should one care? Simply put, oscillators used to generate CPU ticks aren’t super accurate. They work pretty well, but a 0.1% error wouldn’t be out of the question. That’s a minute and a half’s worth of error in 1 day. The error changes constantly, due to temperature variation, and a host of other physical factors.
It’s far too expensive to use system calls for timing, so we’re left with the problem of continously adjusting our view of the CPU tick register’s clocks_per_second parameter.
The clock rate adjustment algorithm measures the number of cpu ticks and the “gold standard” reference time across an interval of approximately 16 seconds. We calculate clocks_per_second for the interval: use rdtsc (on x86_64) and a system call to get the latest cpu tick count and the kernel’s latest nanosecond timestamp. We subtract the previous interval end values, and use exponential smoothing to merge the new clock rate sample into the clocks_per_second parameter.
As of this writing, we maintain the clock rate by way of the following first-order differential equation:
clocks_per_second(t) = clocks_per_second(t-1) * K + sample_cps(t)*(1-K)
where K = e**(-1.0/3.75);
This yields a per observation “half-life” of 1 minute. Empirically, the clock rate converges within 5 minutes, and appears to maintain near-perfect agreement with the kernel clock in the face of ongoing NTP time adjustments.
See ./src/vppinfra/time.c:clib_time_verify_frequency(…) to look at the rate adjustment algorithm. The code rejects frequency samples corresponding to the sort of adjustment which might occur if someone changes the gold standard kernel clock by several seconds.
Monotonic timebase support¶
Particularly during system initialization, the “gold standard” system reference clock can change by a large amount, in an instant. It’s not a best practice to yank the reference clock - in either direction - by hours or days. In fact, some poorly-constructed use-cases do so.
To deal with this reality, clib_time_now(…) returns the number of seconds since vpp started, guaranteed to be monotonically increasing, no matter what happens to the system reference clock.
This is first-order important, to avoid breaking every active timer in the system. The vpp host stack alone may account for tens of millions of active timers. It’s utterly impractical to track down and fix timers, so we must deal with the issue at the timebase level.
Here’s how it works. Prior to adjusting the clock rate, we collect the kernel reference clock and the cpu clock:
/* Ask the kernel and the CPU what time it is... */
now_reference = unix_time_now ();
now_clock = clib_cpu_time_now ();
Compute changes for both clocks since the last rate adjustment, roughly 15 seconds ago:
/* Compute change in the reference clock */
delta_reference = now_reference - c->last_verify_reference_time;
/* And change in the CPU clock */
delta_clock_in_seconds = (f64) (now_clock - c->last_verify_cpu_time) *
c->seconds_per_clock;
Delta_reference is key. Almost 100% of the time, delta_reference and delta_clock_in_seconds are identical modulo one system-call time. However, NTP or a privileged user can yank the system reference time - in either direction - by an hour, a day, or a decade.
As described above, clib_time_now(…) must return monotonically increasing answers to the question “how long has it been since vpp started, in seconds.” To do that, the clock rate adjustment algorithm begins by recomputing the initial reference time:
c->init_reference_time += (delta_reference - delta_clock_in_seconds);
It’s easy to convince yourself that if the reference clock changes by 15.000000 seconds and the cpu clock tick time changes by 15.000000 seconds, the initial reference time won’t change.
If, on the other hand, delta_reference is -86400.0 and delta clock is 15.0 - reference time jumped backwards by exactly one day in a 15-second rate update interval - we add -86415.0 to the initial reference time.
Given the corrected initial reference time, we recompute the total number of cpu ticks which have occurred since the corrected initial reference time, at the current clock tick rate:
c->total_cpu_time = (now_reference - c->init_reference_time)
* c->clocks_per_second;
Timebase precision¶
Cognoscenti may notice that vlib/clib_time_now(…) return a 64-bit floating-point value; the number of seconds since vpp started.
Please see this Wikipedia article for more information. C double-precision floating point numbers (called f64 in the vpp code base) have a 53-bit effective mantissa, and can accurately represent 15 decimal digits’ worth of precision.
There are 315,360,000.000001 seconds in ten years plus one microsecond. That string has exactly 15 decimal digits. The vpp time base retains 1us precision for roughly 30 years.
vlib/clib_time_now do not provide precision in excess of 1e-6 seconds. If necessary, please use clib_cpu_time_now(…) for direct access to the CPU clock-cycle counter. Note that the number of CPU clock cycles per second varies significantly across CPU architectures.
Timer Wheels¶
Vppinfra includes configurable timer wheel support. See the source
code in …/src/vppinfra/tw_timer_template.[ch], as well as a
considerable number of template instances defined in
…/src/vppinfra/tw_timer_
Instantiation of tw_timer_template.h generates named structures to implement specific timer wheel geometries. Choices include: number of timer wheels (currently, 1 or 2), number of slots per ring (a power of two), and the number of timers per “object handle”.
Internally, user object/timer handles are 32-bit integers, so if one selects 16 timers/object (4 bits), the resulting timer wheel handle is limited to 2**28 objects.
Here are the specific settings required to generate a single 2048 slot wheel which supports 2 timers per object:
#define TW_TIMER_WHEELS 1
#define TW_SLOTS_PER_RING 2048
#define TW_RING_SHIFT 11
#define TW_RING_MASK (TW_SLOTS_PER_RING -1)
#define TW_TIMERS_PER_OBJECT 2
#define LOG2_TW_TIMERS_PER_OBJECT 1
#define TW_SUFFIX _2t_1w_2048sl
#define TW_FAST_WHEEL_BITMAP 0
#define TW_TIMER_ALLOW_DUPLICATE_STOP 0
See tw_timer_2t_1w_2048sl.h for a complete example.
tw_timer_template.h is not intended to be #included directly. Client codes can include multiple timer geometry header files, although extreme caution would required to use the TW and TWT macros in such a case.
API usage examples¶
The unit test code in …/src/vppinfra/test_tw_timer.c provides a concrete API usage example. It uses a synthetic clock to rapidly exercise the underlying tw_timer_expire_timers(…) template.
There are not many API routines to call.
Initialize a two-timer, single 2048-slot wheel w/ a 1-second timer granularity¶
tw_timer_wheel_init_2t_1w_2048sl (&tm->single_wheel,
expired_timer_single_callback,
1.0 / * timer interval * / );
Start a timer¶
handle = tw_timer_start_2t_1w_2048sl (&tm->single_wheel, elt_index,
[0 | 1] / * timer id * / ,
expiration_time_in_u32_ticks);
Stop a timer¶
tw_timer_stop_2t_1w_2048sl (&tm->single_wheel, handle);
An expired timer callback¶
static void
expired_timer_single_callback (u32 * expired_timers)
{
int i;
u32 pool_index, timer_id;
tw_timer_test_elt_t *e;
tw_timer_test_main_t *tm = &tw_timer_test_main;
for (i = 0; i < vec_len (expired_timers);
{
pool_index = expired_timers[i] & 0x7FFFFFFF;
timer_id = expired_timers[i] >> 31;
ASSERT (timer_id == 1);
e = pool_elt_at_index (tm->test_elts, pool_index);
if (e->expected_to_expire != tm->single_wheel.current_tick)
{
fformat (stdout, "[%d] expired at %d not %d\n",
e - tm->test_elts, tm->single_wheel.current_tick,
e->expected_to_expire);
}
pool_put (tm->test_elts, e);
}
}
We use wheel timers extensively in the vpp host stack. Each TCP session needs 5 timers, so supporting 10 million flows requires up to 50 million concurrent timers.
Timers rarely expire, so it’s of utmost important that stopping and restarting a timer costs as few clock cycles as possible.
Stopping a timer costs a doubly-linked list dequeue. Starting a timer involves modular arithmetic to determine the correct timer wheel and slot, and a list head enqueue.
Expired timer processing generally involves bulk link-list retirement with user callback presentation. Some additional complexity at wheel wrap time, to relocate timers from slower-turning timer wheels into faster-turning wheels.
Format¶
Vppinfra format is roughly equivalent to printf.
Format has a few properties worth mentioning. Format’s first argument is a (u8 *) vector to which it appends the result of the current format operation. Chaining calls is very easy:
u8 * result;
result = format (0, "junk = %d, ", junk);
result = format (result, "more junk = %d\n", more_junk);
As previously noted, NULL pointers are perfectly proper 0-length vectors. Format returns a (u8 *) vector, not a C-string. If you wish to print a (u8 *) vector, use the “%v” format string. If you need a (u8 *) vector which is also a proper C-string, either of these schemes may be used:
vec_add1 (result, 0)
or
result = format (result, "<whatever>%c", 0);
Remember to vec_free() the result if appropriate. Be careful not to pass format an uninitialized (u8 *).
Format implements a particularly handy user-format scheme via the “%U” format specification. For example:
u8 * format_junk (u8 * s, va_list *va)
{
junk = va_arg (va, u32);
s = format (s, "%s", junk);
return s;
}
result = format (0, "junk = %U, format_junk, "This is some junk");
format_junk() can invoke other user-format functions if desired. The programmer shoulders responsibility for argument type-checking. It is typical for user format functions to blow up spectacularly if the va_arg(va, type) macros don’t match the caller’s idea of reality.
Unformat¶
Vppinfra unformat is vaguely related to scanf, but considerably more general.
A typical use case involves initializing an unformat_input_t from either a C-string or a (u8 *) vector, then parsing via unformat() as follows:
unformat_input_t input;
unformat_init_string (&input, "<some-C-string>");
/* or */
unformat_init_vector (&input, <u8-vector>);
Then loop parsing individual elements:
while (unformat_check_input (&input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (&input, "value1 %d", &value1))
;/* unformat sets value1 */
else if (unformat (&input, "value2 %d", &value2)
;/* unformat sets value2 */
else
return clib_error_return (0, "unknown input '%U'",
format_unformat_error, input);
}
As with format, unformat implements a user-unformat function capability via a “%U” user unformat function scheme. Generally, one can trivially transform “format (s, “foo %d”, foo) -> “unformat (input, “foo %d”, &foo)”.
Unformat implements a couple of handy non-scanf-like format specifiers:
unformat (input, "enable %=", &enable, 1 /* defaults to 1 */);
unformat (input, "bitzero %|", &mask, (1<<0));
unformat (input, "bitone %|", &mask, (1<<1));
<etc>
The phrase “enable %=” means “set the supplied variable to the default value” if unformat parses the “enable” keyword all by itself. If unformat parses “enable 123” set the supplied variable to 123.
We could clean up a number of hand-rolled “verbose” + “verbose %d” argument parsing codes using “%=”.
The phrase “bitzero %|” means “set the specified bit in the supplied bitmask” if unformat parses “bitzero”. Although it looks like it could be fairly handy, it’s very lightly used in the code base.
%_
toggles whether or not to skip input white space.
For transition from skip to no-skip in middle of format string, skip input white space. For example, the following:
fmt = "%_%d.%d%_->%_%d.%d%_"
unformat (input, fmt, &one, &two, &three, &four);
matches input “1.2 -> 3.4”. Without this, the space after -> does not get skipped.
### How to parse a single input line
Debug CLI command functions MUST NOT accidentally consume input
belonging to other debug CLI commands. Otherwise, it's impossible to
script a set of debug CLI commands which "work fine" when issued one
at a time.
This bit of code is NOT correct:
```c
/* Eats script input NOT beloging to it, and chokes! */
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (input, ...))
;
else if (unformat (input, ...))
;
else
return clib_error_return (0, "parse error: '%U'",
format_unformat_error, input);
}
}
When executed as part of a script, such a function will return “parse
error: ‘
Instead, use “unformat_line_input” to consume the rest of a line’s worth of input - everything past the path specified in the VLIB_CLI_COMMAND declaration.
For example, unformat_line_input with “my_command” set up as shown below and user input “my path is clear” will produce an unformat_input_t that contains “is clear”.
VLIB_CLI_COMMAND (...) = {
.path = "my path",
};
Here’s a bit of code which shows the required mechanics, in full:
static clib_error_t *
my_command_fn (vlib_main_t * vm,
unformat_input_t * input,
vlib_cli_command_t * cmd)
{
unformat_input_t _line_input, *line_input = &_line_input;
u32 this, that;
clib_error_t *error = 0;
if (!unformat_user (input, unformat_line_input, line_input))
return 0;
/*
* Here, UNFORMAT_END_OF_INPUT is at the end of the line we consumed,
* not at the end of the script...
*/
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (line_input, "this %u", &this))
;
else if (unformat (line_input, "that %u", &that))
;
else
{
error = clib_error_return (0, "parse error: '%U'",
format_unformat_error, line_input);
goto done;
}
}
<do something based on "this" and "that", etc>
done:
unformat_free (line_input);
return error;
}
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (my_command, static) = {
.path = "my path",
.function = my_command_fn",
};
/* *INDENT-ON* */
Vppinfra errors and warnings¶
Many functions within the vpp dataplane have return-values of type clib_error_t *. Clib_error_t’s are arbitrary strings with a bit of metadata [fatal, warning] and are easy to announce. Returning a NULL clib_error_t * indicates “A-OK, no error.”
Clib_warning(format-args) is a handy way to add debugging output; clib warnings prepend function:line info to unambiguously locate the message source. Clib_unix_warning() adds perror()-style Linux system-call information. In production images, clib_warnings result in syslog entries.
Serialization¶
Vppinfra serialization support allows the programmer to easily serialize and unserialize complex data structures.
The underlying primitive serialize/unserialize functions use network byte-order, so there are no structural issues serializing on a little-endian host and unserializing on a big-endian host.


Buttons communicate the action that will occur when the user touches them. Material buttons trigger an ink reaction on press. They may display text, imagery, or both. Flat buttons and raised buttons are the most commonly used types.
Additional button types include:
Flat buttons are text-only buttons. They may be used in dialogs, toolbars, or inline. They do not lift, but fill with color on press and hover.
Raised buttons are rectangular-shaped buttons. They may be used inline. They lift and display ink reactions on press.
Flat buttons: 0dp
Raised buttons: 2dp
There are three standard types of buttons:
Floating Action Button
Raised Button
Flat Button
Example of a Floating Action Button
Example of a Raised Button
Example of a Flat Button
Function: Is it important and ubiquitous enough to be a floating action button?
Dimension: Choose raised or flat depending on the container it will be in and how many z-space layers you have on screen. There should not be many layers of objects on the screen.
Layout: Use primarily one type of button per container. Only mix button types when you have a good reason to, such as emphasizing an important function.
Raised Button
The type of button used should be suited to the context in which it appears.
|
Context |
Button type |
|
Dialogs |
Use flat buttons in dialogs. |
|
Inline |
Raised buttons or flat buttons can be used for inline buttons. |
|
Always available |
If your app requires actions to be persistent and readily available, you can use the floating action button or persistent footer buttons. |
Button alignment on screen: right
Place the affirmative button on the left, the dismissive button on the right.
Button alignment on screen: Left
Place the affirmative button on the right, the dismissive button on the left.
Buttons are best placed on the right side of a card to increase their visibility. However, as cards have flexible layouts, buttons may be placed in a location suited to the content and context, while maintaining consistency within the product.
Button placement in non-standard dialogs and modal windows depends on the complexity of the content they contain.
For dialogs with relatively simple content, it is recommended to place buttons on the right side of a dialog, with the affirmative button to the left of the dismissive button.
For lengthy or complex forms, it is recommended to place buttons on the left of the form, with the affirmative button to the right of the dismissive button.
Button text should be capitalized in languages that have capitalization. For other languages, colored text on flat buttons distinguishes them from normal text.
To ensure usability for people with disabilities, give buttons a height of 36dp and give touchable targets a minimum height of 48dp.
Button height: 36dp
Touchable target height: 48dp
Buttons should have a 2dp corner radius.
Button height: 36dp
Touchable target height: 48dp
When mouse and keyboard are the primary input methods, button measurements can be slightly reduced to accommodate dense UIs.
Default Button
Button text: 14pt Roboto medium
Button height: 36dp
Button text left and right padding: 16dp
Corner
radius: 2dp
Dense Button
Button text: 13pt Roboto medium
Button height: 32dp
Button text left and right padding: 16dp
Corner
radius: 2dp
When mouse and keyboard are the primary input methods, button measurements can be slightly reduced to accommodate dense UIs.
Examples of flat buttons in dialogs
Height: 36dp
Minimum width: 88dp
Touch target height: 48dp
Corner radius: 2dp
Horizontal
margin: 8dp
Horizontal padding: 8dp
Flat buttons are printed on material. They do not lift, but fill with color on press.
Use flat buttons in the following locations:
Flat buttons are appropriate in dialogs.
Flat buttons minimize distraction from content.
Use flat buttons in the following locations:
Flat Light/Light theme
Minimum width: 88dp
Height: 36dp
Corner radius: 2dp
Pressed: 40% #999999
Disabled text: 26% #000000
Flat Dark/Dark theme
Minimum width: 88dp
Height: 36dp
Corner radius: 2dp
Pressed: 25% #CCCCCC
Disabled text: 30% #FFFFFF
Dialog text padding: 24dp
Dialog button container height: 52dp
Dialog buttons: 8dp padding from container edges, aligned to the right of container (for LTR scripts)
Flat buttons in dialogs
Dialog Buttons
Button height: 36dp
Button top margin: 24dp
Button padding: 8dp
Button alignment: Right edge for LTR scripts
Button width: Varies based on button text length
Raised buttons add dimension to mostly flat layouts. They emphasize functions on busy or wide spaces.
Use raised buttons to give more prominence to actions in layouts with a lot of varying content.
Do.
Raised buttons stand out more than flat buttons.
Raised buttons can help delineate sections of content on a page.
Don't
Don’t use flat buttons in UIs where they would be difficult to see.
Raised buttons behave like a piece of material resting on another sheet – they lift and fill with color on press.
Raised Light/Light theme
Minimum width: 88dp
Height: 36dp
Corner radius: 2dp
Disabled text: 26% #000000
Disabled button: 12% #000000
Focused:12% #000000 shade over the color
Raised Dark/Dark theme
Minimum width: 88dp
Height: 36dp
Corner radius: 2dp
Normal color: 500
Pressed color: 700
Disabled text: 30% #FFFFFF
Disabled button: 12% #FFFFFF
Focused:12% #000000 shade over the color
Raised buttons have a default elevation of 2dp. On desktop, raised buttons can gain this elevation on hover.
Dark/Light theme
Minimum width: 88dp
Elevation: 0dp
Disabled text: 30% #FFFFFF
Disabled button: 12% #FFFFFF
If your app requires actions to be persistent and readily available to the user, consider using the floating action button or persistent footer buttons.
Persistent footer buttons are 48dp tall.
Example of persistent footer buttons
Do not use raised buttons within persistent button areas.
Don't.
A persistent footer button may be used for scrollable dialogs when a divider is added.
Persistent footer button in dialog
Persistent footer button in scrollable dialog
A dropdown button selects between multiple selections. The button displays the current state and a down arrow. Available states may be shown as a list of strings, a palette, or icons, for example.
When a user interacts with the button, a menu covers the button and displays the possible states. Pressing a state dismisses the menu and updates the button to display this new state.
Scrolling within the dropdown behaves the same way a menu scrolls.
Closed dropdown button, open dropdown menu, and selected dropdown menu
The generic overflow dropdown button displays an arrow or menu button by default. When the button is pressed, the menu appears. Pressing an option on the menu navigates to further settings for that option.
A segmented dropdown has two sections: the current state and the dropdown arrow icon. Pressing the current state will cause that state’s action to fire within the screen. Pressing the dropdown arrow will display all the state options. Selecting one will change the displayed state.
This button has a segmented dropdown, where the displayed state is text editable, such as a font size picker. Pressing the current state causes both that state’s action to fire and makes the displayed state editable. Pressing the arrow displays all the state options.
Generic, segmented, and editable overflow dropdown buttons in normal, hover, focus, pressed, and selecting states
Desktop app bar specs
Top and bottom padding: 16dp
Left padding: 24dp
Right margin: 16dp
Horizontal space between font styles: 24dp


GRA
GRA
accenture
Toggle navigation
4
You have 4 messages
Support Team
5 mins
Why not buy a new awesome theme?
See All Messages
10
You have 10 notifications
5 new members joined today
View all
9
You have 9 tasks
Design some buttons
20%
20% Complete
View all tasks
Alexander Pierce
Alexander Pierce - Web Developer
Member since Nov. 2012
Followers
Sales
Friends
Profile
Sign out
Create a Role
Project skills
Role ID
Role Name
Date Creation
Start Date
Location
Level Range
Technology
Tool
Proficiency lvl
1
Fundamentals
Managment
Continous Intagration
Deployment
Cloud / IaaS / PaaS
BI / Monitoring
Database Management
Repo Managment
Config / Provisioning
Release Managment
Logging
Build
Testing
Containerization
Collaboration
Security
Environment
Jenkins
Bamboo
Travis CI
Codeship
Visual Studio
Circle CI
TeamCity
Shippable
CruiseControl
Continuum
Continua CI
Solano CI
Add Row
Delete Row
Search Candidate


Xmake is a lightweight cross-platform build utility based on Lua.
It is very lightweight and has no dependencies because it has a built-in Lua runtime.
It uses xmake.lua to maintain project builds and its configuration syntax is very simple and readable.
We can use it to build project directly like Make/Ninja, or generate project files like CMake/Meson, and it also has a built-in package management system to help users solve the integrated use of C/C++ dependent libraries.
Xmake = Build backend + Project Generator + Package Manager + [Remote|Distributed] Build + Cache
Although not very precise, we can still understand Xmake in the following way:
Xmake ~= Make/Ninja + CMake/Meson + Vcpkg/Conan + distcc + ccache/sccache
Introduction of new features
Package component support
Introduction
This new feature is intended to enable the integration of specific sub-libraries from a C/C++ package, and is generally used for library component integration in larger packages.
This is because such packages provide a number of sub-libraries, not all of which are required by the user, and linking them all may be problematic.
Although, previous versions were able to support the feature of sublibrary selection, e.g.
add_requires("sfml~foo", {configs = {graphics = true, window = true}})
add_requires("sfml~bar", {configs = {network = true}})
target("foo")
set_kind("binary")
add_packages("sfml~foo")
target("bar")
set_kind("binary")
add_packages("sfml~bar")
This is done by custom configuration of each package, but there are some problems with this approach.
sfml~foo
andsfml~bar
will be installed repeatedly as two separate packages, taking up double the disk space- some common code will be compiled repeatedly, which will affect the efficiency of the installation
- if a target depends on both
sfml~foo
andsfml~bar
, there will be link conflicts
The impact of double-compilation and disk usage can be very high for very large package integrations such as boost, and can even lead to more than N times the disk usage if there are a large number of sub-library combinations.
To solve this problem, Xmake has added a package component mode, which offers some of the following benefits.
- fast integration of any number of components in just one compile, greatly improving installation efficiency and reducing disk footprint
- component abstraction, across compilers and platforms, so users don’t need to worry about configuring link order dependencies between each sub library
- easier to use
For more background details see: #2636
Use package components
For the user, using package components is very convenient because the user is not required to maintain the package, as long as the package is used, it is configured with the relevant set of components and we can quickly integrate and use it, e.g.
add_requires("sfml")
target("foo")
set_kind("binary")
add_packages("sfml", {components = "graphics"})
target("bar")
set_kind("binary")
add_packages("sfml", {components = "network"})
View package components
So how do we know what components are provided by a given package? We can check by executing the following command.
$ xrepo info sfml
The package info of project:
require(sfml):
-> description: Simple and Fast Multimedia Library
-> version: 2.5.1
...
-> components:
-> system:
-> graphics: system, window
-> window: system
-> audio: system
-> network: system
Package component configuration
If you are a package maintainer and want to add component support to a package, then you need to configure the package components via the following two interfaces.
- add_components: adds a list of package components
- on_component: Configures each package component
Link configuration for package components
In most cases, a package component only needs to be configured with some of its own sub-link information, e.g.
package("sfml")
add_components("graphics")
add_components("audio", "network", "window")
add_components("system")
on_component("graphics", function (package, component)
local e = package:config("shared") and "" or "-s"
component:add("links", "sfml-graphics" ... e)
if package:is_plat("windows", "mingw") and not package:config("shared") then
component:add("links", "freetype")
component:add("syslinks", "opengl32", "gdi32", "user32", "advapi32")
end
end)
on_component("window", function (package, component)
local e = package:config("shared") and "" or "-s"
component:add("links", "sfml-window" ... e)
if package:is_plat("windows", "mingw") and not package:config("shared") then
component:add("syslinks", "opengl32", "gdi32", "user32", "advapi32")
end
end)
...
The above is an incomplete package configuration, I have only extracted a part of the configuration related to the package components.
A full example of the configuration and use of package components can be found at: components example
Configure compilation information for components
We can configure not only the linking information for each component, but also the compilation information for includedirs, defines etc. We can also configure each component individually.
package("sfml")
on_component("graphics", function (package, component)
package:add("defines", "TEST")
end)
Configure component dependencies
package("sfml")
add_components("graphics")
add_components("audio", "network", "window")
add_components("system")
on_component("graphics", function (package, component)
component:add("deps", "window", "system")
end)
The above configuration tells the package that our graphics component will have additional dependencies on the window
and system
components.
So, on the user side, our use of the graphics component can be done from the
add_packages("sfml", {components = {"graphics", "window", "system"})
Simplified to.
add_packages("sfml", {components = "graphics")
Because, as soon as we turn on the graphics component, it will also automatically enable the dependent window and system components and automatically ensure that the links are in the right order.
Alternatively, we can configure component dependencies with add_components("graphics", {deps = {"window", "system"}})
.
Find components from the system library
We know that configuring add_extsources
in the package configuration can improve package discovery on the system, for example by finding libraries from system package managers such as apt/pacman.
Of course, we can also make it possible for each component to prioritise finding them from the system repositories via the extsources
configuration as well.
For example, the sfml package, which is actually also componentized in homebrew, can be made to find each component from the system repository without having to install them in source each time.
$ ls -l /usr/local/opt/sfml/lib/pkgconfig
-r--r--r-- 1 ruki admin 317 10 19 17:52 sfml-all.pc
-r--r--r-- 1 ruki admin 534 10 19 17:52 sfml-audio.pc
-r--r--r-- 1 ruki admin 609 10 19 17:52 sfml-graphics.pc
-r--r--r-- 1 ruki admin 327 10 19 17:52 sfml-network.pc
-r--r--r-- 1 ruki admin 302 10 19 17:52 sfml-system.pc
-r--r--r-- 1 ruki admin 562 10 19 17:52 sfml-window.pc
We just need, for each component, to configure its extsources: the
if is_plat("macosx") then
add_extsources("brew::sfml/sfml-all")
end
on_component("graphics", function (package, component)
-- ...
component:add("extsources", "brew::sfml/sfml-graphics")
end)
Default Global Component Configuration
In addition to configuring specific components by specifying component names, if we do not specify a component name, the default is to globally configure all components.
package("sfml")
on_component(function (package, component)
-- configure all components
end)
Of course, we could also specify the configuration of the graphics component and the rest of the components would be configured via the default global configuration interface in the following way.
package("sfml")
add_components("graphics")
add_components("audio", "network", "window")
add_components("system")
on_component("graphics", function (package, component)
-- configure graphics
end)
on_component(function (package, component)
-- component audio, network, window, system
end)
C++ module build improvements
Incremental build support
I thought that Xmake already had good support for C++ modules, but then I realised that its incremental builds don’t work properly yet.
So this version of Xmake also does a good job of supporting incremental builds of C++ modules, although the support process still took a lot of effort.
My analysis shows that the format of the include dependency information (*.d
) generated with modules varies considerably between the compilers.
The gcc format is the most complex, but I got it to support it anyway.
build/.objs/dependence/linux/x86_64/release/src/foo.mpp.o: src/foo.mpp\
build/.objs/dependence/linux/x86_64/release/src/foo.mpp.o gcm.cache/foo.gcm: bar.c++m cat.c++m\
foo.c++m: gcm.cache/foo.gcm\
.PHONY: foo.c++m\
gcm.cache/foo.gcm:| build/.objs/dependence/linux/x86_64/release/src/foo.mpp.o\
CXX_IMPORTS += bar.c++m cat.c++m\
clang has the best format compatibility and supports it without any special changes.
build//hello.pcm: /usr/lib/llvm-15/lib/clang/15.0.2/include/module.modulemap src/hello.mpp\
The msvc format is more extensible and easier to parse and support: the
{
"Version": "1.2",
"Data": {
"Source": "c:\users\ruki\desktop\user_headerunit\src\main.cpp",
"ProvidedModule": "",
"Includes": [],
"ImportedModules": [
{
"Name": "hello",
"BMI": "c:\users\ruki\desktop\user_headerunit\src\hello.ifc"
}
],
"ImportedHeaderUnits": [
{
"Header": "c:\users\ruki\desktop\user_headerunit\src\header.hpp",
"BMI": "c:\users\ruki\desktop\user_headerunit\src\header.hpp.ifc"
}
]
}
}
Circular Dependency Detection Support
As there are dependencies between modules, it is not possible to compile if there are circular dependencies between several modules.
However, in previous versions Xmake was unable to detect this, and when a circular dependency was encountered, the compilation would get stuck without any message, which was very unfriendly to the user.
In this new version, we have improved this situation by adding the detection of cyclic dependencies for modules, and the following error message will appear when compiling to make it easier for the user to locate the problem.
$ xmake
[ 0%]: generating.cxx.module.deps Foo.mpp
[ 0%]: generating.cxx.module.deps Foo2.mpp
[ 0%]: generating.cxx.module.deps Foo3.mpp
[ 0%]: generating.cxx.module.deps main.cpp
error: circular modules dependency(Foo2, Foo, Foo3, Foo2) detected!
-> module(Foo2) in Foo2.mpp
-> module(Foo) in Foo.mpp
-> module(Foo3) in Foo3.mpp
-> module(Foo2) in Foo2.mpp
A more LSP friendly syntax format
Our default convention of domain configuration syntax, although very clean, is not very friendly to auto-formatted indentation and IDEs, and if you format your configuration, the indentation is completely misplaced.
target("foo")
set_kind("binary")
add_files("src/*.cpp")
Also, if some global configuration is configured between two targets, it does not automatically end the current target scope and the user needs to explicitly call ``target_end()`.
target("foo")
set_kind("binary")
add_files("src/*.cpp")
target_end()
add_defines("ROOT")
target("bar")
set_kind("binary")
add_files("src/*.cpp")
Although, as we mentioned above, you can use the do end
mode to solve the auto-indentation problem, the problem of needing target_end()
still exists.
target("foo") do
set_kind("binary")
add_files("src/*.cpp")
end
target_end()
add_defines("ROOT")
target("bar") do
set_kind("binary")
add_files("src/*.cpp")
end
Therefore, in this new version, we provide a better optional domain configuration syntax to solve the auto-indentation, target domain isolation problem, e.g.
target("foo", function ()
set_kind("binary")
add_files("src/*.cpp")
end)
add_defines("ROOT")
target("bar", function ()
set_kind("binary")
add_files("src/*.cpp")
end)
The foo and bar fields are completely isolated, so we can configure other settings between them without affecting them, plus it’s very LSP friendly and won’t cause indentation confusion, even with one-click formatting.
Note: This is only an optional extension syntax, the existing configuration syntax is still fully supported and the user can choose the right one according to their needs preferences.
Add flags to specific compilers
Values configured using interfaces such as add_cflags
, add_cxxflags
, etc. are usually compiler specific, although Xmake does provide automatic detection and mapping mechanisms.
Even if a flags is set that is not supported by the current compiler, Xmake can automatically ignore it, but there will still be a warning.
In this new version, we have improved the interface for adding all flags to avoid additional warnings by specifying flags only for specific compilers, e.g.
add_cxxflags("clang::-stdlib=libc++")
add_cxxflags("gcc::-stdlib=libc++")
Or
add_cxxflags("-stdlib=libc++", {tools = "clang"})
add_cxxflags("-stdlib=libc++", {tools = "gcc"})
Note: Not just compile flags, but also for link flags such as add_ldflags, which also work.
renderdoc debugger support
Thanks to @SirLynix for contributing this great feature which allows Xmake to load renderdoc directly to debug some graphics renderers.
It’s very simple to use, we first make sure renderdoc is installed, then configure the debugger to renderdoc and load the debug run as follows
$ xmake f --debugger=renderdoc
$ xmake run -d
The concrete usage effect is as follows.
New C++ exception interface configuration
Xmake has added a new set_exceptions
abstraction configuration interface, which allows us to configure C++/Objc exceptions to be enabled and disabled.
Normally, if we configure them via the add_cxxflags interface, it would be cumbersome for the compiler to handle them separately, depending on the platform.
For example
on_config(function (target)
if (target:has_tool("cxx", "cl")) then
target:add("cxflags", "/EHsc", {force = true})
target:add("defines", "_HAS_EXCEPTIONS=1", {force = true})
elseif(target:has_tool("cxx", "clang") or target:has_tool("cxx", "clang-cl")) then
target:add("cxflags", "-fexceptions", {force = true})
target:add("cxflags", "-fcxx-exceptions", {force = true})
end
end)
And with this interface, we can abstract to configure them in a compiler-independent way.
Enabling C++ exceptions:
set_exceptions("cxx")
Disable C++ exceptions:
set_exceptions("no-cxx")
We can also configure to turn on objc exceptions at the same time.
set_exceptions("cxx", "objc")
or disable them.
set_exceptions("no-cxx", "no-objc")
Xmake automatically adapts the flags internally to the different compilers.
Support for ispc compilation rules
Xmake has added support for built-in rules for the ipsc compiler, thanks to @star-hengxing, which is used in the following way.
target("test")
set_kind("binary")
add_rules("utils.ispc", {header_extension = "_ispc.h"})
set_values("ispc.flags", "--target=host")
add_files("src/*.ispc")
add_files("src/*.cpp")
Support for msvc’s armasm compiler
Previous versions of Xmake added initial support for Windows ARM, but did not yet have good support for asm compilation, so in this version we have continued to improve Windows ARM support.
Support for msvc’s armasm.exe
and armasm64.exe
is now available.
In addition, we have also improved package cross-compilation support for the Windows ARM platform.
New gnu-rm build rules
Xmake has also added a new rule and example project for building embedded projects using the gnu-rm toolchain, thanks to @JacobPeng for this.
add_rules("mode.debug", "mode.release")
add_requires("gnu-rm")
set_toolchains("@gnu-rm")
set_plat("cross")
set_arch("armv7")
target("foo")
add_rules("gnu-rm.static")
add_files("src/foo/*.c")
target("hello")
add_deps("foo")
add_rules("gnu-rm.binary")
add_files("src/*.c", "src/*.S")
add_files("src/*.ld")
add_includedirs("src/lib/cmsis")
For the full project see: Embed GNU-RM Example
Add OpenBSD system support
In previous versions, Xmake only supported FreeBSD, and OpenBSD had a number of differences that prevented Xmake from compiling and installing on it.
The new version now fully supports running Xmake on OpenBSD.
Changelog
New features
- A new optional configuration syntax. It is LSP friendly, automatically calls target_end() to achieve scope isolation.
- #2944: Add
gnu-rm.binary
andgnu-rm.static
rules and tests for embed project - #2636: Support package components
- Support armasm/armasm64 for msvc
- #3023: Add support for debugging with renderdoc
- #3022: Add flags for specific compilers and linkers
- #3025: C++ exception enabled/disabled switch method
- #3017: Support ispc compiler
Changes
- #2925: Improve doxygen plugin
- #2948: Support OpenBSD
- Add
xmake g --insecure-ssl=y
option to disable ssl certificate when downloading packages - #2971: Stabilize vs and vsxmake project generation
- #3000: Incremental compilation support for modules
- #3016: Improve clang/msvc to better support std modules


When using Sass, you can change the color scheme of your site extremely quickly. Below is a very small
sample of what you can change through sass in _variables.scss
.
$primary-color: color("materialize-red", "lighten-2") !default;
$primary-color-light: false !default;
$primary-color-dark: false !default;
@if not $primary-color-light {
$primary-color-light: lighten($primary-color, 15%);
}
@if not $primary-color-dark {
$primary-color-dark: darken($primary-color, 15%);
}
$secondary-color: color("teal", "lighten-1") !default;
$success-color: color("green", "base") !default;
$error-color: color("red", "base") !default;
$link-color: color("light-blue", "darken-1") !default;
/*** More variables not shown here.. ***/
Small screens are defined as having a max-width of 600px
Medium screens are defined as having a max-width of 992px
Large screen are defined as having a min-width of 992px
/* These classes can be added to HTML Elements
* to affect visibility on certain displays.
*/
.hide-on-small-only
.hide-on-small-and-down
.hide-on-med-and-down
.hide-on-med-and-up
.hide-on-med-only
.hide-on-large-only
.show-on-large
.show-on-medium
.show-on-small
.show-on-medium-and-up
.show-on-medium-and-down
@media #{$small-and-down} {
// styles for small screens and down
}
@media #{$medium-and-up} {
// styles for medium screens and larger
}
@media #{$medium-and-down} {
// styles for medium screens and down
}
@media #{$large-and-up} {
// styles for large screens and up
}
@media #{$extra-large-and-up} {
// styles for extra large screens and up
}