--- layout: toplevelcontent title: Evaluating WebAssembly for front-end web development. Emscripten vs Rust vs Blazor. description: Evaluating WebAssembly for front-end web development. A comparison of Emscripten, Rust and Blazor. keyword: emscripten, blazor, webassembly, rust, rustwasm, mono-wasm ---
In 1997, Eric Steven Raymond wrote the famous essay The Cathedral and the Bazaar where it distinguishes between two styles of software development. In the Cathedral, an isolated and secretive team of developers works on their software quietly out of public view and a team of testers helping the developers find and fix bugs. In the Bazaar, the work or project is placed in open source, sometimes in a "haphazard" manner, for everyone interested to see and "mess around". The development work is carried out in the open, sometimes in a chaotic but ultimately coherent manner by the crowd. Everyone and anyone can be a developer or a tester for the project.
During the time of the essay, there are likely more Cathedrals than Bazaars. As of today, if you look closely, the Bazaar has grown significantly. Everywhere, from individuals, small passionate teams or even large organizations, are setting up stores in the Bazaar. Some of the stores are managed and evangelized by professionals paid by the Cathedrals while putting their products into open source. The idea of the Cathedral sponsoring a Bazaar store is to ensure early embracement of the public community and to gather feedback and interests for the project. The Bazaar, together with the sponsorship from Cathedrals, has led to better products and even better lives of many customers, users, and developers, including that of mine.
Today, if you walk into a Bazaar, for example GitHub, many of the stores are peddling products build with one popular and "secret" ingredient, JavaScript. JavaScript is found in everything from server products, engines, frameworks, libraries, SAAS, Cloud to databases and more. This is especially so for front-end web development where JavaScript and its derived framework and transpiled languages has total monopoly. The JavaScript language is also the most popular programming language in the Bazaar (GitHub), according to reports such as Developer Skills Report by HackerRank.
At the same time, in a little dark corner of every BIG Cathedral sponsored Bazaar store, an unfinished product, where programmers like us, like to call Beta, is built using a different "secret" ingredient. Though sometimes in a non prominent way, this new kid on the block ingredient is being actively explored and researched upon by the big guys for their new products and projects. The new ingredient is called WebAssembly. So what is WebAssembly really?
WebAssembly is a web standard, developed by the World Wide Web Consortium (W3C), that defines an assembly-like binary code format for execution in web pages. The executing code runs nearly as fast as native machine code and is meant to speed up performance of web applications significantly.
As WebAssembly is a low-level binary bytecode, it supports compilation from different programming languages. This enables many existing and commonly used libraries or applications to be compiled into WebAssembly easily. WebAssembly has been natively supported by all major browsers including Firefox, Chrome, Safari and Edge since 2007. It has started to become an alternative programming language to JavaScript, especially for front-end web development.
I was lucky to be involved in an evaluation of WebAssembly for an in-house web frontend project. The project basically involves an Admin Dashboard where a user logs in to monitor what is going on, looks at some sales charts and orders activities. In the evaluation, our goal is to determine whether it is feasible to use WebAssembly for front end web development, and if possible, build a prototype to prove the feasibility.
As of recent times, WebAssembly based frameworks are released and announced at a rapid pace. Many of them are still early in the development stages. We think the following are mature enough for your considerations.
1. If you have C/C++ codes or are going to develop a game, Emscripten is likely what you should be looking at first.
2. If you have an existing app or website written in JavaScript and would like to improve the performance of certain parts through WebAssembly, you should look at Rust WebAssembly. The following are from their website for your consideration.
According to https://rustwasm.github.io
Mozilla has also put in a lot of effort on extremely fast performance between JavaScript and WebAssembly in their Firefox browser. If you are targeting Mozilla Firefox browser, this is a no-brainer.
https://hacks.mozilla.org/2018/10/calls-between-javascript-and-webassembly-are-finally-fast
3. If you want to develop a totally new web application front-end and you are using .NET in the backend or you would like to use C#, you should choose Blazor. It is a complete framework with capabilities of modern front-end framework such as Routing, Components, Dependency Injection and Events. You can easily leverage existing .NET libraries and the strong C# community support.
One of the aspects we looked at is the experience of using different tools, or more specifically, the experience of the development process.
{% include aa1.html %}My first experience with WebAssembly was with Emscripten. As my background was from C/C++, I may be biased. I love Emscripten. The basic concept of using Emscripten is to develop a module in WebAssembly and use JavaScript to load and execute the module.
I have extracted some of the codes from my previous article on how to Develop W3C WebComponents with WebAssembly for you to get a feel of using Emscripten.
class Code39 {
public:
.
.
.
std::string encode() {
std::string filteredData=filterInput(inputData);
int filteredlength = filteredData.length();
std::string result;
if (checkDigit==1)
result="*"+filteredData+generateCheckDigit(filteredData)+"*";
else
result="*"+filteredData+"*";
std::string mappedResult;
for (int x=0;x<result.length();x++)
{
mappedResult=mappedResult+""+
std::to_string((unsigned char)result[x])+";";
}
result=mappedResult;
human_readable_text=result;
return result;
}
private:
std::string inputData;
.
.
.
};
// Binding code
EMSCRIPTEN_BINDINGS(connectcode_code39) {
class_<Code39>("Code39")
.constructor<>()
.constructor<std::string, int>()
.function("encode", &Code39::encode)
.property("inputData",
&Code39::getInputData,
&Code39::setInputData)
.
.
.
;
}
The part you should focus on is "EMSCRIPTEN_BINDINGS", which defines how JavaScript and C/C++ class interacts. It may change when we have access to the DOM in future with the following WebAssembly proposal:
https://github.com/WebAssembly/proposals/issues/16
Without access to the DOM, we must pass our results back to JavaScript for display. In our code above, the "EMSCRIPTEN_BINDINGS" defines a C++ class, an encode function and an inputData property. The rest are standard C++ programming codes. After we compile the class into WebAssembly, we can include the generated "wasm" (WebAssembly module) into JavaScript and access it as shown below:
var instance = new Module.Code39();
instance.inputData = list.barcodeInputData;
instance.checkDigit = 1;
elements.innerHTML=instance.encode();
elementsHR.innerHTML=instance.humanReadableText;
For Rust, the story is like Emscripten. We must import JavaScript "things" into Rust and export Rust "things" to JavaScript. Below is an example.
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
// Import the `window.alert` function from the Web.
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
}
// Export a `greet` function from Rust to JavaScript, that alerts a
// hello message.
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
The main part is the use of "wasm_bindgen" to pass values and structures across the boundary. I have extracted some snippets of code from the well-known Rust WebAssembly Game of Life sample:
https://rustwasm.github.io/book/game-of-life/implementing.html
to further demonstrate how wasm_bindgen is used.
/// Public methods, exported to JavaScript.
#[wasm_bindgen]
impl Universe {
// ...
pub fn width(&self) -> u32 {
self.width
}
pub fn height(&self) -> u32 {
self.height
}
pub fn cells(&self) -> *const Cell {
self.cells.as_ptr()
}
}
Accessing the Rust WebAssembly methods in JavaScript:
const universe = Universe.new();
const width = universe.width();
const height = universe.height();
Below are some Rust programming codes to let you get a feel of using Rust.
impl Universe {
// ...
fn live_neighbor_count(&self, row: u32, column: u32) -> u8 {
let mut count = 0;
for delta_row in [self.height - 1, 0, 1].iter().cloned() {
for delta_col in [self.width - 1, 0, 1].iter().cloned() {
if delta_row == 0 && delta_col == 0 {
continue;
}
let neighbor_row = (row + delta_row) % self.height;
let neighbor_col = (column + delta_col) % self.width;
let idx = self.get_index(neighbor_row, neighbor_col);
count += self.cells[idx] as u8;
}
}
count
}
}
Rust is a programming language well-loved by its community. According to Mozilla:
Rust is the most loved language for developers with 73% of users saying they want to keep working with it. The same month this survey came out, Developer Analyst firm Redmonk charted Rust's move on the Github rankings from 46 to 18.
https://medium.com/mozilla-tech/why-rust-is-the-most-loved-language-by-developers-666add782563
Blazor takes a different approach from Emscripten and Rust. It leverages on .NET and WebAssembly. You can think of it as having a .NET platform compiled to WebAssembly and then using it to run your .NET applications or DLLs. The Blazor framework comes with many capabilities found in modern JavaScript frameworks such as Angular and React. I will describe some of these capabilities in more details below.
The following is how a sample Blazor page (index.cshtml) looks like. As Blazor is a complete framework for a Single-Page Application, you can imagine when you first access a web URL, you are routed to this Blazor page.
@page "/"
@if (fruits == null)
{
}
else
{

@dataBinding

@foreach (var fruit in fruits)
{

@fruit

}

}
@functions {
string[] fruits = { "Apple", "Orange", "Mango" };
string dataBinding = "My Farm";
}
The @page "/" is used for page routing, @ symbol is used for transitioning from HTML to C#, @functions contains C# programming codes, @if and @foreach are Blazor C# specific markups. The most important thing is you can easily invoke C# classes or libraries from @functions.
The example also illustrates one other concept, Data Binding, that Blazor supports. For those of you who not familiar with it, Data binding is a bridge or connection between your application View and Data. When the data changes, the View automatically reflects the updated data values. With data binding, direct access to the DOM and dependency on JavaScript is minimized.
In our example,

@dataBinding
is binded to the variable
string dataBindingData Binding is very useful. For example, it can be used to tie the CSS classes in a HTML div element to a C# string variable.

By changing the string, you can then add or remove CSS classes. The use of JavaScript to add or remove CSS classes is thus not required. It feels kind of weird but it works.
The above codes in index.cshtml produce the following HTML output.
My Farm
Apple
Orange
Mango
In our example above, it contains a mixture of HTML and C# for generating the output. You can also generate everything from C# codes. The following shows how to generate dynamic content in a Blazor component with the BuildRenderTree function.
namespace BlazorExample.Pages
{
[Route("/")]
[Layout(typeof(MainLayout))]
public class ClassOnlyComponent :BlazorComponent
{
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
var seq = 0;
builder.OpenElement(seq, "h3");
builder.AddContent(++seq, "Hello, world!");
builder.CloseElement();
}
}
}
When the above component is included in a web page, it gives you the following ouput:

Hello, world!

We have compared very briefly the ways of developing a WebAssembly based front-end using Emscripten, Rust and Blazor. As of now, before the implementation of Host Bindings https://github.com/WebAssembly/host-bindings, Blazor appears to be the easiest to develop on. There is no need to write codes for JavaScript to interact with WebAssembly (wasm), except to load it. However, having the .NET framework to support your development has an impact on the size of the application. Just as Spiderman said, "With Great Power Comes Great Responsibility". Please see the next section for a more detailed discussion on this.
For our in-house project, we have decided to develop a prototype using Blazor. The source of our Admin Dashboard prototype and in-house Charts are available under the MIT License in GitHub, if you are interested.
As a programmer, I value the feel-good factor and ease of writing codes. But I acknowledge the user experience of the application is more important. The download size of the application plays an important part in the user experience, especially for a web application. No one likes to spend time waiting for an application to load.
Below are some of my findings. They are not the results of a scientific approach of comparing the tools or codes in an apple to apple manner. It is more of letting you know the download size of the WebAssembly modules generated by different tools.
For Emscripten, we concluded that an average of 110 lines of C++ code gives us roughly a 40KB wasm module. This is based on an average of over 20 C++ classes that we have written. The C++ classes are quite simple, involving string manipulation and minimal dependencies on other libraries.
For Rust WebAssembly, we use the Game of Life sample as the basis. I looked through the size, it is similar to what the website has claimed.
https://rustwasm.github.io/book/game-of-life/implementing.html
With the default release build configuration (without debug symbols), our WebAssembly binary is 29,410 bytes:
After enabling LTO, setting opt-level = "z", and running wasm-opt -Oz, the resulting .wasm binary shrinks to only 17,317 bytes:
And if we compress it with gzip (which nearly every HTTP server does) we get down to a measly 9,045 bytes!
Blazor
For Blazor, our Admin Dashboard with Charts when published, gives us a folder of 9.57MB! Let me give you a breakdown.
Top items belonging to Blazor
To summarize the figures for Blazor, we have 9.57MB in total, around 5MB are our project images and CSS. The rest (4.5MB) belongs to our app and Blazor. Our app alone uses around 150KB. The size required for Blazor and our app together is quite large considering that it is just a prototype without much UI logic. Our GitHub project mentioned above provides a live demo of how the project looks like.
We can probably apply Progressive Web App (PWA) capabilities, a separate concept, to Blazor so that we can download the core part and subsequently load other pages "lazily". Of course, deep in my heart, I really hope that some of these mechanisms are already part of Blazor.
The following is what I found from http://blazor.net FAQ that could be useful to you.
Wouldn't the app download size be huge if it also includes a .NET runtime?
Not necessarily. .NET runtimes come in all shapes in sizes. Early Blazor prototypes used a compact .NET runtime (including assembly execution, garbage collection, threading) that compiled to a mere 60KB of WebAssembly. Blazor now runs on Mono which is currently significantly larger. However, opportunities for size optimization abound, including merging and trimming the runtime and application binaries. Other potential download size mitigations include caching and using a CDN.
It is interesting to see DLLs as part of the published binaries in Blazor. Remember, Blazor IS currently NOT compiling your app into WebAssembly. It is the .NET Framework (mono specifically) that is compiled to WebAssembly and sent to your browser to run your .NET DLLs in the browser. One question that pops up is whether the Blazor framework will be bundled as part of Microsoft Edge browser or perhaps even Windows? Only time will tell.
One thing I know for sure will change in the future is the support for full Static Ahead of Time (AOT) compilation for Blazor (or more specifically mono-wasm).
https://www.mono-project.com/news/2018/01/16/mono-static-webassembly-compilation/
From some of the videos by Microsoft, I understand that the AOT compilation will improve the performance of Blazor apps and may also reduce the download size. Or I could be wrong, as I was distracted by my delicious ramen while watching them. We plan to test this further when AOT compilation for Blazor is available. But that's for another day.
Unfortunately, the debugging story for WebAssembly is still immature. Both Emscripten and Rust depend on logs, logging/console APIs. Blazor has a better story at the moment with some very early support for "Step and Resume" in C# codes on Chrome through Remote Debugging.
1. WebAssembly is Fast. Many benchmarks show the proof of this. Don't just take my word for it. Go and check out the many articles out there.
2. WebAssembly is Inclusive.
As of today, you can compile C, C++, Go, C#, Rust, AssemblyScript, Kotlin, Python, Perl, Ruby and many more to WebAssembly. Almost every day (ok maybe not every day), some projects in GitHub will announce support for an existing programming language to compile to WebAssembly, thanks to the great work on the LLVM WebAssembly backend. With WebAssembly supporting many programming languages, the different communities can use the language that they love and target the largest platform in the world - the web.
3. The big guys are getting involved.
Microsoft, Google, Mozilla to name a few. Yes, the guys who develop platforms.
4. WebAssembly is still improving
More languages are going to support compilation to WebAssembly. This is especially with proposals of access to the DOM and Garbage collection https://github.com/WebAssembly/proposals/issues/16, and support for Host Bindings https://github.com/WebAssembly/host-bindings. With Garbage collection, we can expect languages such as Java, to have a significant role in this field.


--- title: "Inspiration" menutitle: "Inspiration" mainfont: Arial fontsize: 12pt urlcolor: blue weight: 25 ---
Basic Abstract Spiral
## Data
ab.seq <- as.data.frame(seq(from = 1,
to = 100,
by = 1))
ab.seq$V1 <- rep(0, times = 100)
colnames(ab.seq) <- c("ab", "V1")
## Plot
ggplot() +
geom_polygon(data = (ab.seq + 250), mapping = aes(x = 1:100, y = V1),
alpha = 0.5) +
geom_point(data = (ab.seq - 150), mapping = aes(x = 1:100, y = ab)) +
geom_point(data = (ab.seq - 100), mapping = aes(x = 1:100, y = ab)) +
geom_point(data = (ab.seq - 50), mapping = aes(x = 1:100, y = ab)) +
geom_point(data = (ab.seq), mapping = aes(x = 1:100, y = ab)) +
geom_point(data = (ab.seq + 50), mapping = aes(x = 1:100, y = ab)) +
geom_point(data = (ab.seq + 100), mapping = aes(x = 1:100, y = ab)) +
geom_point(data = (ab.seq + 150), mapping = aes(x = 1:100, y = ab)) +
ylim(-100, 250) +
theme_void() +
coord_polar()
Colourful Spiral V1
## Data
ab.seq.2 <- as.data.frame(seq(from = 0,
to = 99.99,
by = 0.01))
ab.seq.2$ab2 <- seq(from = 99.99,
to = 0,
by = -0.01)
ab.seq.2$col <- rep(seq(from = 1,
to = 5,
by = 1))
ab.seq.2$V1 <- rep(0, time = 10000)
colnames(ab.seq.2) <- c("ab", "ab2", "col", "V1")
ggplot() +
geom_polygon(data = (ab.seq.2 + 200),
mapping = aes(x = 1:10000, y = (V1)), fill = "grey") +
geom_point(data = (ab.seq.2 - 100),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 - 50),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 50),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 100),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 150),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 200),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 - 75),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 - 25),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 25),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 75),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 125),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 175),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
ylim(0, 200) + xlim(0, 10000) +
theme_void() +
theme(legend.position = "none") +
coord_polar()
Colourful Spiral V2
## Data
ab.seq.2 <- as.data.frame(seq(from = 0,
to = 99.99,
by = 0.01))
ab.seq.2$ab2 <- seq(from = 99.99,
to = 0,
by = -0.01)
ab.seq.2$col <- (rep(seq(from = 1,
to = 5,
by = 1)))
ab.seq.2$V1 <- rep(0, time = 10000)
colnames(ab.seq.2) <- c("ab", "ab2", "col", "V1")
ggplot() +
geom_polygon(data = (ab.seq.2 + 200),
mapping = aes(x = 1:10000, y = (V1)), fill = "lightblue") +
geom_point(data = (ab.seq.2 - 100),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 - 50),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 50),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 100),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 150),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 200),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 - 75),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 - 25),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 25),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 75),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 125),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
geom_point(data = (ab.seq.2 + 175),
mapping = aes(x = 1:10000, y = ab, colour = ab)) +
scale_colour_gradient(
low = "purple", high = "lightblue") +
ylim(0, 200) + xlim(0, 10000) +
theme_void() +
theme(legend.position = "none") +
coord_polar()
Sin Celtic Circlular Weave
fs.seq <- as.data.frame(seq(from = 1,
to = 51.3,
by = 0.25))
fs.seq$alpha <- rep(0, times = 202)
colnames(fs.seq) <- c("fs", "alpha")
ggplot() +
geom_polygon(data = fs.seq,
mapping = aes(x = 1:202, y = (alpha - 2))) +
geom_polygon(data = fs.seq,
mapping = aes(x = 1:202, y = (alpha + 2)), alpha = 0.2) +
geom_polygon(data = fs.seq,
mapping = aes(x = 1:202, y = (alpha + 4)), alpha = 0.2) +
geom_point(data = fs.seq,
mapping = aes(x = 1:202, y = (sin(fs) - 3))) +
geom_point(data = fs.seq,
mapping = aes(x = 1:202, y = (-sin(fs) - 3))) +
geom_point(data = fs.seq,
mapping = aes(x = 1:202, y = sin(fs))) +
geom_point(data = fs.seq,
mapping = aes(x = 1:202, y = -sin(fs))) +
geom_point(data = fs.seq,
mapping = aes(x = 1:202, y = (sin(fs) + 3))) +
geom_point(data = fs.seq,
mapping = aes(x = 1:202, y = (-sin(fs) + 3))) +
ylim(-10, 10) +
theme_void() +
coord_polar()
Colourful cos Celtic Circlular Weave
fs.seq <- as.data.frame(seq(from = 1,
to = 51.3,
by = 0.25))
fs.seq$alpha <- rep(0, times = 202)
colnames(fs.seq) <- c("fs", "alpha")
ggplot() +
geom_polygon(data = fs.seq,
mapping = aes(x = 1:202, y = (alpha - 2)),
alpha = 0.2, fill = "purple") +
geom_polygon(data = fs.seq,
mapping = aes(x = 1:202, y = (alpha + 2)),
alpha = 0.2, fill = "purple") +
geom_polygon(data = fs.seq,
mapping = aes(x = 1:202, y = (alpha + 4)),
alpha = 0.2, fill = "purple") +
geom_point(data = fs.seq,
mapping = aes(x = 1:202, y = ((cos(fs)-7))),
alpha = 0.8, colour = "blue") +
geom_point(data = fs.seq,
mapping = aes(x = 1:202, y = ((-cos(fs)-7))),
alpha = 0.8, colour = "red") +
geom_point(data = fs.seq,
mapping = aes(x = 1:202, y = (cos(fs) - 3)),
alpha = 0.8, colour = "blue") +
geom_point(data = fs.seq,
mapping = aes(x = 1:202, y = (-cos(fs) - 3)),
alpha = 0.8, colour = "red") +
geom_point(data = fs.seq,
mapping = aes(x = 1:202, y = cos(fs)),
alpha = 0.5, colour = "blue") +
geom_point(data = fs.seq,
mapping = aes(x = 1:202, y = -cos(fs)),
alpha = 0.5, colour = "red") +
geom_point(data = fs.seq,
mapping = aes(x = 1:202, y = (cos(fs) + 3)),
alpha = 0.2, colour = "blue") +
geom_point(data = fs.seq,
mapping = aes(x = 1:202, y = (-cos(fs) + 3)),
alpha = 0.2, colour = "red") +
ylim(-10, 10) +
theme_void() +
coord_polar()
Square Weaves
kw.seq <- (seq(from = -10,
to = 10,
by = 0.05)) %>%
expand.grid(x = ., y = .)
## Celtic Square Weave
ggplot() +
geom_point(data = kw.seq,
mapping = aes(x = (x + sin(y)), y = (y + cos(x))),
alpha = 0.01, colour = "white") +
coord_fixed() +
theme_void() +
theme(panel.background = element_rect(fill = "orange"))
## Wave Weave
ggplot() +
geom_point(data = kw.seq,
mapping = aes(x = ((x*x) + sin(y)), y = ((y*y) + cos(x))),
alpha = 0.01, colour = "white") +
coord_fixed() +
theme_void() +
theme(panel.background = element_rect(fill = "blue"))
## Multiple Square Panel Weave
ggplot() +
geom_point(data = kw.seq,
mapping = aes(x = (sin(x) + cos(x)), y = (sin(y) + cos(y))),
alpha = 0.02, colour = "white") +
geom_point(data = kw.seq,
mapping = aes(x = (sin(x) + cos(x) - 2), y = (sin(y) + cos(y) - 2)),
alpha = 0.02, colour = "blue") +
coord_fixed() +
theme_void() +
theme(panel.background = element_rect(fill = "green"))
## Square tan Weave
ggplot() +
geom_point(data = kw.seq,
mapping = aes(x = (2*x + tan(y)), y = (2*y + tan(x))),
alpha = 0.02, colour = "white") +
ylim(-50, 50) + xlim(-50, 50) +
coord_fixed() +
theme_void() +
theme(panel.background = element_rect(fill = "green"))
## Jellyfish
ggplot() +
geom_point(data = kw.seq,
mapping = aes(x = (sqrt(x) + (sin(y))), y = (sqrt(y) + (sin(x)))),
alpha = 0.1, colour = "blue") +
coord_fixed() +
theme_void() +
theme(panel.background = element_rect(fill = "orange"))
## Random Square
ggplot() +
geom_point(data = (kw.seq + 25),
mapping = aes(x = (sqrt(x) + (sin(y))), y = (sqrt(y) + (sin(x)))),
alpha = 0.02, colour = "blue") +
coord_fixed() +
theme_void() +
theme(panel.background = element_rect(fill = "lightpink"))
##
ggplot() +
geom_point(data = (kw.seq),
mapping = aes(x = (cos(x^2)^2 + sin(y)), y = (cos(y^2)^2 + sin(x)),
colour = x, alpha = y)) +
geom_point(data = (kw.seq),
mapping = aes(x = (cos(x^2)^2 + sin(y)), y = (cos(y^2)^2 + sin(x)),
colour = -x, alpha = -y)) +
coord_fixed() +
theme_void() +
theme(panel.background = element_rect(fill = "blue"),
legend.position = "none")
Complex Designs
Based on Fronkonstin’s blog
Summoning Cthulhu
sc.seq <- seq(from = -3,
to = 3,
by = 0.01) %>%
expand.grid(x = ., y = .)
ggplot(data = sc.seq,
mapping = aes(x=(x^3-sin(y^2)), y=(y^3-cos(x^2)))) +
geom_point(alpha=.1, shape=20, size=0, color="white") +
theme_void() +
theme(panel.background = element_rect(fill="black")) +
coord_polar()
Marine Creature
mc.seq <- seq(from = -10,
to = 10,
by = 0.05) %>%
expand.grid(x = ., y = .)
ggplot(data = mc.seq,
mapping = aes(x=(x^2+pi*cos(y)^2), y=(y+pi*sin(x)))) +
geom_point(alpha=.1, shape=20, size=1, color="black")+
theme_void()+coord_fixed()


{% include head.html %}
{% include nav.html %} {% include header.html %} {% include download-app.html %} {% include services.html %} {% include services_detail.html %} {% include features_respio.html %} {% include tech.html %} {% include spec_setup_unbox.html %} {% include iot_customization.html %} {% include clinic_application.html %} {% include application_businessmodel.html %} {% include covid_predict.html %} {% include contact.html %} {% include scripts.html %}


For Greater Glory: The True Story of Cristiada
For Greater Glory: The True Story of Cristiada is a movie starring Andy Garcia, Oscar Isaac, and Catalina Sandino Moreno. A chronicle of the Cristeros War (1926-1929); a war by the people of Mexico against the atheistic Mexican...


Classes
The following classes are available globally.
-
Undocumented
See moreDeclaration
Objective-C
@interface KDIBadgeView : UIView <KDIDynamicTypeObject> #else @interface KDIBadgeView : NSView #endif /** Set and get the highlighted state of the view. If `highlighted` is NO, `badgeForegroundColor` and `badgeBackgroundColor` are used to display the `badge` value. Otherwise, if `highlighted` is YES, `badgeHighlightedForegroundColor` and `badgeHighlightedBackgroundColor` are used to display the `badge` value. @warning *NOTE:* This property will get set automatically if the receiver is used within a `UITableViewCell` */ @property (assign,nonatomic,getter=isHighlighted) BOOL highlighted; /** Set and get the badge value of the receiver. This value is displayed using `badgeForegroundColor` or `badgeHighlightedForegroundColor`, depending on the value of `highlighted`. */ @property (copy,nonatomic,nullable) NSString *badge; /** Set and get the text color used to display `badge` value when `highlighted` is NO. The default is `[UIColor whiteColor]` or `[NSColor whiteColor]`. */ #if (TARGET_OS_IPHONE) @property (strong,nonatomic,null_resettable) UIColor *badgeForegroundColor UI_APPEARANCE_SELECTOR; #else @property (strong,nonatomic,null_resettable) NSColor *badgeForegroundColor; #endif /** Set and get the background color used to display `badge` value when `highlighted` is NO. The default is `[UIColor blackColor]` or `[NSColor blackColor]`. */ #if (TARGET_OS_IPHONE) @property (strong,nonatomic,null_resettable) UIColor *badgeBackgroundColor UI_APPEARANCE_SELECTOR; #else @property (strong,nonatomic,null_resettable) NSColor *badgeBackgroundColor; #endif /** Set and get the text color used to display `badge` value when `highlighted` is YES. The default is `[UIColor lightGrayColor]` or `[NSColor lightGrayColor]`. */ #if (TARGET_OS_IPHONE) @property (strong,nonatomic,null_resettable) UIColor *badgeHighlightedForegroundColor UI_APPEARANCE_SELECTOR; #else @property (strong,nonatomic,null_resettable) NSColor *badgeHighlightedForegroundColor; #endif /** Set and get the background color used to display `badge` value when `highlighted` is YES. The default is `[UIColor whiteColor]` or `[NSColor whiteColor]`. */ #if (TARGET_OS_IPHONE) @property (strong,nonatomic,null_resettable) UIColor *badgeHighlightedBackgroundColor UI_APPEARANCE_SELECTOR; #else @property (strong,nonatomic,null_resettable) NSColor *badgeHighlightedBackgroundColor; #endif /** Set and get the font used to display `badge` value. The default is `[UIFont boldSystemFontOfSize:17.0]` or `[NSFont boldSystemFontOfSize:17.0]`. */ #if (TARGET_OS_IPHONE) @property (strong,nonatomic,null_resettable) UIFont *badgeFont UI_APPEARANCE_SELECTOR; #else @property (strong,nonatomic,null_resettable) NSFont *badgeFont; #endif /** Set and get the badge corner radius used to draw the rounded corners of the receiver. The default is 8.0. */ #if (TARGET_OS_IPHONE) @property (assign,nonatomic) CGFloat badgeCornerRadius UI_APPEARANCE_SELECTOR; #else @property (assign,nonatomic) CGFloat badgeCornerRadius; #endif /** Set and get the edge insets used to layout the `badge` value text. The default is `UIEdgeInsetsMake(4.0, 8.0, 4.0, 8.0)` or `NSEdgeInsetsMake(4.0, 8.0, 4.0, 8.0)`. */ #if (TARGET_OS_IPHONE) @property (assign,nonatomic) UIEdgeInsets badgeEdgeInsets UI_APPEARANCE_SELECTOR; #else @property (assign,nonatomic) NSEdgeInsets badgeEdgeInsets; #endif #if (!TARGET_OS_IPHONE) /** Equivalent to `-[UIView sizeThatFits:]` for cross platform reasons. @param size The preferred size of the receiver @return A new size that fits the receiver's subviews */ - (NSSize)sizeThatFits:(NSSize)size; #endif @end
-
Undocumented
See moreDeclaration
Objective-C
@interface KDIGradientView : UIView #else @interface KDIGradientView : NSView #endif /** Set and get the colors of the underlying CAGradientLayer. The array should contain either UIColor or NSColor instances. */ @property (copy,nonatomic,nullable) NSArray<KDIColor *> *colors; /** Set and get the locations of the underlying CAGradientLayer. The gradient stops are specified as values between 0 and 1. The values must be monotonically increasing. If nil, the stops are spread uniformly across the range. Defaults to nil. */ @property (copy,nonatomic,nullable) NSArray<NSNumber *> *locations; /** The start point of the underlying CAGradientLayer. The point is defined in unit coordinate space. */ @property (assign,nonatomic) KDIPoint startPoint; /** The end point of the underlying CAGradientLayer. The point is defined in the unit coordinate space. */ @property (assign,nonatomic) KDIPoint endPoint; @end
-
KDIView is a UIView/NSView subclass that provides state change methods on macOS. It also conforms to KDIBorderedView, allowing it to display borders.
See moreDeclaration
Objective-C
@interface KDIView : UIView <KDIBorderedView>


I brought Snapchat’s new $380 smart glasses on a trip to London, and their biggest selling point was a major letdown
by Paige Leskin, Business Insider US- Snapchat has released the newest iteration of its smart sunglasses, called Spectacles 3, designed to let you record pictures and videos from a first-person point of view.
- The new model is equipped with two high-res cameras to better capture depth and dimension, which allow for the introduction of 3D filters and effects.
- However, these 3D effects – Snapchat’s major selling point – are subpar, don’t enhance the Spectacles experience, and can only be added later in the Snapchat app after you’re done recording.
- Snapchat says the Spectacles 3 are essentially just a next step toward AR hardware in the future, a bet that ensures not many users will want to shell out a sky-high $380 for this model.
- Visit Business Insider’s homepage for more stories.
Snapchat is betting big on a future when augmented reality hardware reigns supreme, but that wager comes at the cost of its newest pair of smart sunglasses, Spectacles 3.
Spectacles 3 were made available to the public on November 12. These new Spectacles come with two cameras and a trendier design, while also costing $380 – $220 more than the previous model released in 2018.
Spectacles design lead Lauryn Morris told Business Insider that the new glasses are designed to be more “premium and sophisticated,” meant for the “mid-20s consumer who cares about that style and wants to explore technology.” It’s a risky move for a company whose first pair of Spectacles amassed a lot of early hype, but failed to deliver and resulted in $40 million worth of unsold inventory.
With a vacation to London scheduled right after Spectacles 3 launched, I decided to take the sunglasses across the pond to try them out in a city know for its cloudy skies and rainy days.
At first glance, the Spectacles 3 have an overhauled design that does make them stylish.
I received a pair of the glasses in “monochromatic black” (though they also come in a carbon color and a lighter “mineral” tone). The black matte finish and circular lenses put them in line with the vintage style that is popular today.
Compared with the oversized look of the first two models of Spectacles, the design of the new pair is a big step up.
“Form is just as important as function,” Spectacles design lead Lauryn Morris told Business Insider. “You choose the clothes you wear because they reflect your style and values.”
The biggest change with Spectacles 3 is the addition of a second camera to the glasses. This is intended to “capture the world the way your eyes do,” Morris says — that is, the new glasses are designed to capture design and dimension.
While the symmetrical appearance of previous Spectacles models may have made it seem as if there was two cameras, Spectacles 3 are the first Snapchat glasses to have dual-camera recording capabilities.
By adding two high-res cameras, Snapchat is opening the doors to a world of capturing 3D. That enables some filters and lenses, which are already popular in the Snapchat app itself, to be applied to Spectacles videos.
To be clear, the filters available in Snapchat are not catered for Spectacles – there are Spectacles-specific lenses and filters that Snapchat’s community of creators have been working on, the company said.
One Spectacles feature I’m happy has lasted through the three different models is the wireless charging case.
The charging case is essentially a blown-up version of headphones cases for Apple AirPods and other wireless earbuds. They work in the same way: place the Spectacles in the case and they’ll charge up to four times before you’ll need to recharge the case via USB-C. Snapchat says the Spectacles can charge 50% in 15 minutes.
Additionally, the charging case nicely folds flat, allowing you to tuck it into a jacket pocket or bag when you’re wearing your Spectacles.
One of the first bothersome things about using the Spectacles was the location of the buttons, one on each sunglasses arm, which are used for recording pictures and videos.
The locations of the buttons, right on the top of each arm, are where I would normally grasp onto when putting on and removing my Spectacles. The result: A ton of videos I accidentally recorded, with no ability to halt the recording.
Since the second version of Spectacles, users have had the ability to capture both videos and still images. With Spectacles 3, it takes a long press to take a picture, and a short tap to record a video. You can record up to six 60-second-long Spectacles videos.
As with previous models, an LED light blinks when your Spectacles are recording, and I found it easy to see the light while wearing my glasses. With Spectacles 3, you can also configure that LED light to blink when you receive Snapchats from specific users.
However, I did find it a bit odd that the LED light signaling that you’re recording only flashes on one side of the glasses, although both cameras are recording. If both LED lights went off, it would make it a whole lot easier to ensure you don’t remove your glasses prematurely before your recording is finished.
Ahead of putting my Spectacles to the test, Snapchat told me they had already given some of their Official Lens Creators (artists who work with Snapchat to create filters and effects) pairs of the new sunglasses to try out. You can see some of their Spectacles captures here:
However, I was crushed to discover, almost immediately, that the videos I captured with my Spectacles 3 weren’t as nice as these masterpieces. Sure, the resolution is high-quality — but you have to ensure your ability to record video is too.
I quickly learned in using my Spectacles that you have to be extremely, extremely measured in your movements. It takes a while to figure out how to move your head super slowly while scanning a landscape, and you have to hold your head steady while walking to ensure the video doesn’t violently bounce with each step.
For the average user, this steep learning curve would be incredibly taxing, and I might have given up on Spectacles in favor of my iPhone pretty quickly.
And at night, Spectacles 3 have a lot of trouble. It depended on the color of the lights, but here — at a Christmas market in central London — many of the lights showed up over-saturated.
Previous Spectacles models have not performed well in low-light scenarios. Although the video quality on Spectacles 3 is 1216 x 1216 pixels, the high resolution hasn’t drastically improved the glasses’ performance at night.
Now, onto the new types of content you can create with Spectacles 3. The pictures you can take be converted into 3D images and GIFs (like the one below). It’s cool I guess, but I honestly don’t see the use or point.
Snapchat says that the point of these 3D images is to make your photos “more dynamic and lifelike” than a picture taken with a normal camera.
Then there are the 3D lenses and filters, effects that use augmented reality to make them reactive to the scene captured on your Spectacles. With only 10 filters at Spectacles 3’s launch — Snapchat says there are more coming — the effects are pretty disappointing.
Some effects, like these “gradient blobs” in the above video, don’t do anything more than add several dark blue masses that float around your screen. To me, this effect did nothing to enhance the video I took with my Spectacles.
While I was less than impressed by the 3D filters currently available, they’re even less exciting when you consider you can only overlay them onto your video after importing them into the Snapchat app. You won’t see these effects in action until you’re done using your Spectacles.
The AR effects and lenses become less exciting when you learn they only get applied to videos in-app, after you’re finished recording. Combined with my disappointment in the existing filters available on Spectacles, the new model’s AR capabilities don’t appeal to me.
Something that hasn’t changed with Spectacles 3 is a long-standing complaint: the cumbersome process of getting your videos and photos ready to share. All of this is done through the Snapchat app.
Since the first Spectacles model, content captured with your Snapchat wearables are viewed, edited, and shared all through the Snapchat app. Importing content has gotten easier and faster, thanks to Spectacles’ built-in WiFi network that allows photos and videos to get transferred at any time.
However, Spectacles videos are still buried within your Memories, a section of the Snapchat app I do not use frequently. You can use the Snapchat app to export your videos in a variety of formats.
I was also frustrated to learn that if you record video for longer than 10 seconds, the video is broken down into 10-second segments anyways in the app.
Before Spectacles 3 even launched, Snapchat was already emphasizing that these glasses are meant to be just a small step toward a future where augmented reality hardware is widely adopted. It’s a risky move to put out $380 smart glasses when CEO Evan Spiegel still envisions that era 10 years away.
When I first found out that Snapchat’s newest Spectacles would cost $380 – $220 more than the previous model – I was surprised. Initial hype around the first Spectacles model in 2016 led the company to order 800,000 units, resulting in $40 million worth of unsold inventory. By any measure, Spectacles were a flop.
This time around, Snapchat only planned to make around 24,000 units of Spectacles 3, according to Cheddar. Morris, Spectacles’ design lead, told Business Insider that Spectacles 3 are an “iterative approach” toward a future with widely adopted AR wearables.
That future, according to Snap CEO Evan Spiegel, is still 10 years away.
While the sunglasses are indeed trendy and similar to a style I’d buy myself, there’s no situation in which I could justify spending $380 on a pair of wearables with cool filters. Since Snapchat is betting on the future, I recommend betting — and waiting — on it too.
Essentially, Snapchat is expecting you the shell out an extra $220 for its new AR lenses and filters on Spectacles. But it’s apparent that Snapchat still has a long way to go: The filters don’t provide a clear benefit, and the learning curve for using the glasses means I couldn’t see myself using these regularly after the allure of a new gadget wears off.
Everyone at Snapchat, from Spectacles’ design lead to Snapchat’s CEO, are telling people that we’re still years away from widely adopted AR hardware. There’s no reason then to rush to get a pair of Spectacles 3, and you may as well wait to see what Snapchat’s next – and hopefully less pricey – next step is.


{% for vehicle in vehicles %}
{{ vehicle }}
{{ vehicle.color }}
{{ vehicle.vehicle_number }}
{% empty %}
No objects yet.
{% endfor %}


Page maintained by Ke-Sen
Huang. If you have additions or changes, send an
e-mail.
Note that when possible I link to the page containing the link
to the actual PDF or PS of the preprint. I prefer this as it
gives some context to the paper and avoids possible copyright
problems with direct linking. Thus you may need to
search on the page to find the actual document.
Changelog
Invited Talk
- Volume Rendering for Curvilinear and Unstructured Grids (PDF link provided by authors)
-
Nelson Max,
Peter Williams,
Claudio Silva,
Richard Cook
CG Hardware
- Hardware Assisted Multichannel Volume Rendering
-
Abhijeet Ghosh,
Poojan Prabhu,
Arie Kaufman,
Klaus Mueller
- Interactive Transfer Function Modification For Volume Rendering Using Compressed Sample Runs
-
Vivek Srivastava,
Uday Chebrolu,
Klaus Mueller
- Design and Implementation of Panoramic Movie System by Using Commodity 3D Graphics Hardware
-
Tsuyoshi Yamamoto,
Munehiro Doi
CG Modeling
- Interpolatory Subdivision Curves via Diffusion of Normals
-
Yutaka Ohtake,
Alexander Belyaev,
Hans-Peter Seidel
- Mesh Denoising via Iterative Alpha-Trimming and Nonlinear Diffusion of Normals with Automatic Thresholding
-
Hirokazu Yagou,
Yutaka Ohtake,
Alexander Belyaev
- An Efficient Mesh Simplification Method with Feature Detection for Unstructured Meshes and Web Graphics
-
Bing-Yu Chen,
Tomoyuki Nishita
Natural Scene Modeling
- 1/f\beta Noise-Based Real-Time Animation of Trees Swaying in Wind Fields
-
Shin Ota,
Tadahiro Fujimoto,
Machiko Tamura,
Kazunobu Muraoka,
Kunihiko Fujita,
Norishige Chiba
- Modeling of Lobed Leaves
-
Lars Muendermann,
Peter Macmurchy,
Juraj Pivovarov,
Przemyslaw Prusinkiewicz
Rendering
- Data Compression for a Massive Image Data Set in IBMR
-
Chi-Sing Leung,
Ping-Man Lam,
Tien-Tsin Wong
- Fast Volumetric Display of Natural Gaseous Phemomena
-
Stefan Roettger,
Thomas Ertl
- Ray Tracing Height Fields
-
Huamin Qu,
Nan Zhang,
Feng Qir,
Arie Kaufman,
Ming Wan
Virtual Reality
- Flexible Materials in Avango Virtual Environment Framework
-
Lialia Nikitina,
Igor Nikitin,
Stanislav Klimenko
- Immersive Vehicle Simulators for Prototyping, Training and Ergonomics
-
Marcelo Kallmann,
Patrick Lemoine,
Daniel Thalmann,
Frederic Cordier,
Nadia Magnenat-Thalmann,
Cecilia Ruspa,
Silvia Quattrocolo
- VHD++Development Framework: Towards Extendible, Component Based VR/AR Simultation Engine Featuring Advanced Virtual Character Technologies
-
Michal Ponder,
George Papagiannakis,
Tom Molet,
Nadia Magnenat-Thalmann,
Daniel Thalmann
- Real Time Detection Interface For Walking on CAVE
-
Salvador Barrera,
Piperakis Romanos,
Suguru Saito,
Hiroki Takahashi
Texture
- Textile and Tile Pattern Design Automatic Cataloguing Using Detection of the Plane Symmerty Group
-
Margarita Valor,
Francisco Albert,
Jose Maria Gomis,
Manuel Contero
- Restoration using Multiresolution Texture Synthesis and Image Inpainting
-
Hitoshi Yamauchi,
Joerg Haber,
Hans-Peter Seidel
- Compressing Texture Coordinates with Selective Linear Predictions
-
Martin Isenburg,
Jack Snoeyink
Non-photo
- Rendering Artistic and Believable Trees for Cartoon Animation
-
Fabian Di Fiore,
William Van Haevre,
Frank Van Reeth
- "Nijimi" Rendering Algorithm for Creating Quality Black Ink Paintings
-
Qinglian Guo,
Tosiyasu L.. Kunii
Application CG
- Visualization of Distributed Processes Using Data Jewelry Box Algorithm
-
Yumi Yamaguchi,
Takayuki Itoh
- Automatic Tracking of Face Sequences from MPEG Video
-
Yunlong Zhao,
Tat-Seng Chua
- A Framework for Transfer Colors Based on the Basic Color Categories
-
Youngha Chang,
Suguru Saito,
Masayuki Nakajima
Real Time Rendering
- Real-Time Visualization of Japanese Artcraft
-
Roman Durikovic,
Ryou Kimura,
Konstantin Kolchin
- A Real-Time Refraction Renderer for Volume Objects Using a Polygon-Rendering Scheme
-
Eisaku Obuchi
- Fast Depth of Field Rendering with Surface Splatting
-
Jaroslav Krivanek,
Jiri Zara,
Kadi Bouatouch
Animation
- Extraction of Motion Individuality in Sports and its Application to Motion of Characters with Different Figures
-
Raita Kawasaki,
Yoshifumi Kitamura,
Fumio Kishino
- Creating Various Styles of Animations Using Example-Based Filtering
-
Ryota Hashimoto,
Henry Johan,
Tomoyuki Nishita
- Diorama Engine-A 3D Directing Tool for 3D Computer Animation Production
-
Koji Mikami,
Toru Tokuhara
- Reaching Volumes Generated by Means of Octal Trees and Cartesian Constraints
-
I.Rodriguez,
M.Peinado,
R.Boulic,
D.Meziat
kesen.huang@gmail.com


IN THE HIGH COURT OF JUDICATURE AT PATNA Criminal Miscellaneous No.18821 of 2012 ====================================================== Uday Kumar .... .... Petitioner/s Versus The State Of Bihar .... .... Opposite Party/s ====================================================== CORAM: HONOURABLE MR. JUSTICE DINESH KUMAR SINGH ORAL ORDER
3 20-06-2012 Learned counsel for the petitioner is permitted to make necessary correction in the prayer portion of the petition.
Heard learned counsels for the petitioner and the State. The petitioner is apprehending arrest in a case registered for the offences punishable under Section 379 of the Indian Penal Code, Section 4, 40 and 26 of the B.M.M.C. Act, 21A of the Air Act and 31 of the Water Act.
The accusation is of running the brick kiln without valid authorization and thereby causing loss to the government to the tune of Rs. 52,000/-.
It is submitted by learned counsel for the petitioner that without verification of the fact that the brick kiln was running, the loss has been calculated.
Without entering into merit of the case, the petitioner is ready to deposit Rs. 25,000/- before the learned court below which will be invested in some fixed deposit scheme which will be Patna High Court Cr.Misc. No.18821 of 2012 (3) dt.20-06-2012 2/2 subject to the result of the case.
On deposit of the aforesaid amount, let the above named petitioner be released on anticipatory bail, in the event of arrest or surrender before the learned Court below within a period of 12 weeks from today, on furnishing bail bond of Rs. 10,000/- (ten thousand) with two sureties of the like amount each to the satisfaction of the learned Chief Judicial Magistrate, Jehanabad in connection with Makhdumpur P.S. Case No. 352 of 2010, subject to the conditions as laid down under Section 438(2) Cr.P.C.
(Dinesh Kumar Singh, J) Amrendra/-


elephant.go |
|
|---|---|
package main
import (
"errors"
"fmt"
"time"
log "github.com/sirupsen/logrus"
"github.com/jinzhu/gorm" |
|
|
We need this for gorm to connect to postgres |
_ "github.com/jinzhu/gorm/dialects/postgres"
) |
|
elephant is a struct to define DB interaction |
type elephant struct{}
var ( |
|
Elephant is the exposed model into DB |
Elephant = &elephant{}
) |
|
connectDB connects to the database |
func (*elephant) connectDB(database string) (*gorm.DB, error) {
const timeout = 1 * time.Minute
deadline := time.Now().Add(timeout)
tries := 0
for tries = 0; time.Now().Before(deadline); tries++ {
db, err := gorm.Open(dbType, database)
if err == nil {
return db, nil
}
log.Printf("Couldn't connect to the database (%s). Retrying...", err.Error())
time.Sleep(time.Second << uint(tries))
} |
|
Sleep for 2 seconds |
time.Sleep(2 * time.Second)
return nil, fmt.Errorf("failed connect to the database after %d attempts", tries)
} |
|
createCompany adds company to the database |
func (*elephant) createCompany(name string) (*Company, error) {
res := &Company{Name: name}
return res, db.Create(res).Error
} |
|
createSentiment adds a raw sentiment datapoint to the database |
func (e *elephant) createSentiment(tweetID string, unix int, sentiment float64, company string) (*Sentiment, error) {
ans := &Sentiment{
TweetID: tweetID,
Unix: unix,
Sentiment: sentiment,
CompanyID: e.ctod(company, true),
}
return ans, db.Create(ans).Error
} |
|
createWindowAverage adds a list of averaged sentiment datapoints to the database |
func (e *elephant) createWindowAverage(unix []int, averages []float64, company string) ([]*Average, error) {
end := make([]*Average, len(unix))
var err error
if len(averages) != len(unix) {
return nil, errors.New("Length of unix timestamps and averages don't match!")
}
for ind, time := range unix {
ave := &Average{
Unix: time,
Average: averages[ind],
CompanyID: e.ctod(company, true),
}
end = append(end, ave)
err = db.Create(ave).Error
if err != nil {
break
}
}
return end, err
} |
|
getSentiments gets raw sentiments from “sentiments” table for all values that are connected to company and bound by after < t < before |
func (e *elephant) getSentiments(company string, before, after int) ([]Sentiment, error) {
result := make([]Sentiment, 0, 128)
return result, db.Model(e.fcompany(company)).
Where("unix > ?", after).
Where("unix < ?", before).
Order("unix desc").
Related(&result).
Error
} |
|
getCompanies returns a string list of all companies in “companies” table |
func (e *elephant) getCompanies() ([]string, error) {
result := make([]string, 0, 16)
return result, db.Model(&Company{}).
Pluck("name", &result).
Error
} |
|
getLatestAverageSentiment gets latest unix timestamp for company. Used by josh for anchoring and starting processing only from that point onward |
func (e *elephant) getLatestAverageSentiment(company string) (int, error) {
result := &Average{}
err := db.Model(e.fcompany(company)).
Order("unix desc").
Limit(1).
Related(result).
Error
if err != nil {
if err.Error() == "record not found" {
return 0, nil
}
return 0, err
}
return result.Unix, err
} |
|
getAverages is the same as getSentiments but only returns already processed values |
func (e *elephant) getAverages(company string, before, after int) ([]Average, error) {
result := make([]Average, 0, 128)
return result, db.Model(e.fcompany(company)).
Where("unix > ?", after).
Where("unix < ?", before).
Order("unix asc").
Related(&result).
Error
} |
|
deleteOldRaws deletes all raw sentiments that are older than before |
func (e *elephant) deleteOldRaws(before int64) error {
return db.Unscoped().Model(&Sentiment{}).
Where("unix < ?", before).
Delete(&Sentiment{}).
Error
} |
|
close closes the connection to the database |
func (*elephant) close() error {
return db.Close()
} |
|
autoMigrate automatically sets up all the tables that are used |
func (*elephant) autoMigrate() error {
return db.AutoMigrate(&Company{}, &Sentiment{}, &Average{}).Error
}
func (e *elephant) fcompany(company string) *Company {
res := &Company{}
res.ID = e.ctod(company, false)
if res.ID == 0 {
fmt.Println("failed to resolve company: ", company)
}
return res
} |
|
ctod takes a company and returns the company’s id (and possibly makes the company a new entry if it wasn’t there already) |
func (e *elephant) ctod(company string, autocreate bool) uint {
companyID := uint(0)
var ok bool
if companyID, ok = cachedNames[company]; !ok {
res := &Company{}
err := db.Where(&Company{Name: company}).First(res).Error |
|
Not found, automatically make one |
if res.ID == 0 || err != nil {
if !autocreate {
return 0
}
c, err := e.createCompany(company)
if err != nil {
return 0
}
res.ID = c.ID
}
cachedNames[company] = res.ID
companyID = res.ID
}
return companyID
}
|


Warmind
Username:
Controls:
Arrow keys to move Q to repair E to activate Quantum Power up 1-9 to buy an upgrade


Papers et al.
Founder @papersetal Dundee, United KingdomA startup providing new clever ways of managing and consuming research literature.
A startup providing new clever ways of managing and consuming research literature.
Organization and development/design of the event's website and ticket sale.
Organization and development/design of the event's website.
Participated with a team project "IntelliGene: Empower your future" in the Biotechnology Young Entrepreneurs Scheme Competition.