惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Securelist
C
CERT Recently Published Vulnerability Notes
Forbes - Security
Forbes - Security
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
L
LINUX DO - 最新话题
The Hacker News
The Hacker News
Google Online Security Blog
Google Online Security Blog
SecWiki News
SecWiki News
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
The Last Watchdog
The Last Watchdog
S
Schneier on Security
T
Troy Hunt's Blog
N
News | PayPal Newsroom
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Schneier on Security
Schneier on Security
P
Privacy & Cybersecurity Law Blog
T
Tor Project blog
T
Threatpost
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
A
Arctic Wolf
S
Secure Thoughts
P
Proofpoint News Feed
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Security Latest
Security Latest
Scott Helme
Scott Helme
Security Archives - TechRepublic
Security Archives - TechRepublic
Latest news
Latest news
PCI Perspectives
PCI Perspectives
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Hacker News - Newest:
Hacker News - Newest: "LLM"
L
LINUX DO - 热门话题
P
Palo Alto Networks Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
G
GRAHAM CLULEY
V2EX - 技术
V2EX - 技术
Google DeepMind News
Google DeepMind News
Project Zero
Project Zero
V
Vulnerabilities – Threatpost
T
Threat Research - Cisco Blogs
Webroot Blog
Webroot Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
N
News and Events Feed by Topic
TaoSecurity Blog
TaoSecurity Blog
大猫的无限游戏
大猫的无限游戏
T
Tenable Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
Visual Studio Blog
H
Hacker News: Front Page
Simon Willison's Weblog
Simon Willison's Weblog
AWS News Blog
AWS News Blog

Minko Gechev's blog

skillgrade Unit Tests for AI Agent Skills You Should Care About AI Generative Development LLM-first Web Framework Reactive framework in ~200 lines of JavaScript Managing Angular Are LLMs going to replace us? Prefetching Heuristics Design Patterns in Open Source Projects - Part II Design Patterns in Open Source Projects - Part I What I learned doing 125 public talks - Part I Dynamic imports solve all the problems, right? 5 Angular CLI Features You Didn't Know About Angular quicklink Preloading Strategy Introducing Bazel Schematics for Angular CLI Building TypeScript Projects with Bazel Joining Google Playing Mortal Kombat with TensorFlow.js. Transfer learning and data augmentation Fast, extensible, configurable, and beautiful linter for Go Introducing Guess.js - a toolkit for enabling data-driven user-experiences on the Web Machine Learning-Driven Bundling. The Future of JavaScript Tooling. JavaScript Decorators for Declarative and Readable Code 3 Tricks For Using Redux and Immutable.js with TypeScript Follow Your Dream Career with Open Source. Personal Story. Redux Anti-Patterns - Part 1. State Management. Faster Angular Applications - Understanding Differs. Developing a Custom IterableDiffer Faster Angular Applications - Part 2. Pure Pipes, Pure Functions and Memoization Faster Angular Applications - Part 1. On Push Change Detection and Immutability Understanding Dynamic Scoping and TemplateRef Implementing a Simple Compiler on 25 Lines of JavaScript Developing Statically Typed Programming Language 7 Angular Tools That You Should Consider Announcing ngrev - Reverse Engineering Tool for Angular Implementing Angular's Dependency Injection in React. Understanding Element Injectors. Distributing an Angular Library - The Brief Guide Angular in Production Ahead-of-Time Compilation in Angular 2.5X Smaller Angular 2 Applications with Google Closure Compiler Using Stripe with Angular (Deprecated) Building an Angular Application for Production Implementing the Missing "resolve" Feature of the Angular 2 Router Scalable Single-Page Application Architecture Managing ambient type definitions and dealing with the "Duplicate identifier" TypeScript error Static Code Analysis of Angular 2 and TypeScript Projects Enforcing Best Practices with Static Code Analysis of Angular 2 Projects ViewChildren and ContentChildren in Angular Dynamically Configuring the Angular's Router Angular 2 Hot Loader Lazy Loading of Route Components in Angular 2 Aspect-Oriented Programming in JavaScript Flux in Depth. Store and Network Communication. Using JSX with TypeScript Flux in Depth. Overview and Components. Even Faster AngularJS Data Structures Boost the Performance of an AngularJS Application Using Immutable Data - Part 2 Angular2 - First Impressions Build Your own Simplified AngularJS in 200 Lines of JavaScript Persistent State of ReactJS Component Boost the Performance of an AngularJS Application Using Immutable Data Processing Binary Protocols with Client-Side JavaScript Stream your Desktop to HTML5 Video Element Multi-User Video Conference with WebRTC Asynchronous calls with ES6 generators Binary Tree iterator with ES6 generators WebRTC chat with React.js AngularJS in Patterns (Part 3) AngularJS in Patterns (Part 2). Services. Using GitHub Pages with Jekyll! AngularJS in Patterns (Part 1). Overview of AngularJS Singleton in JavaScript Express over HTTPS What I get from the JavaScript MV* frameworks Remote Desktop Client with AngularJS and Yeoman The magic of $resource (or simply a client-side Active Record) AngularJS Inheritance Patterns AngularAOP v0.1.0 Advanced JavaScript at Sofia University AngularJS style guide Lazy prefetching of AngularJS partials VNC client on 200 lines of JavaScript Aspect-Oriented Programming with AngularJS CSS3 flipping effect Practical programming with JavaScript Why I should use publish/subscribe in JavaScript JavaScript, the weird parts Functional programming with JavaScript plainvm Looking for performance? Probably you should NOT use [].sort (V8) JavaScript image scaling ELang Caching CSS with localStorage Self-invoking functions in JavaScript (or Immediately Invoked Function Expressions) Asus N56VZ + Ubuntu 12.04 (en) Asus N56VZ + Ubuntu 12.04 Debian Squeeze + LXDE on Google Nexus S (or having some fun while suffering) HTML5 image editor Курсови проекти – ФМИ Carousel Gallery SofiaJS...
WebVR for a Gamified IDE
2017-06-25 · via Minko Gechev's blog

Edit · Jun 25, 2017 · 11 minutes read · Follow @mgechev Source code visualization VR WebVR IDE

In the first part of this blog post I discuss the idea of using virtual reality for gamification of manual tasks in the software development process. I introduce a demo project which allows source code visualization and manipulation in a generated Minecraft-like virtual reality. My initial presentation of the demo project was on ngconf 2017, and the project’s extension I presented on AngularUP 2017 during my talks “Mad Science with the Angular Compiler”.

Since I heard a lot of people being interested in the actual implementation of the demo, in the second part of the post we’ll go through its source code, which is hosted here, on GitHub. You can find demo of the project in the last part of the blog post.

VR as a gamified IDE

This section leaves more questions than answers. In the next a couple of subsections I discuss the idea of abstracting manual software engineering tasks as games, and releasing them on the global market. If you’re interested in the actual implementation of ngworld tool, skip to the “Sample Implementation” section.

Background

The purpose of my “Mad Science with the Angular Compiler” talk is to demonstrate what doors the Angular compiler opens by providing us an access to the ASTs produced by the frontend of the TypeScript compiler, Angular template, expression and CSS parsers. In the talk I explain how the compiler can be used for:

  • Proving that our code aligns to style-related recommendations listed in the Angular style guide (see codelyzer)
  • Simplification of the migration process, by providing pluggable AST transformation rules, depending on the deprecations and the breaking changes introduced by the framework.
  • Tool for reverse engineering of Angular applications through source code visualization.

ngrev is already quite useful, however, I wanted to go one step further and provide a more fun demo. That’s why for ngconf, I developed an “unconventional compiler” which from an Angular application produces a Minecraft-like WebVR. The VR is produced by the following rules:

  • The virtual world corresponds to the entire application, composed by the Angular modules.
  • Each module is represented by a “garden”.
  • The trees in the gardens are the components of the application.
  • Each tree has a crown which consists of blocks. Each block is a template element.
  • The blocks have different colors depending on whether they represent an Angular component or a plain HTML element.

Open questions

While I was building this demo, I was thinking about the following three questions:

  • Can we make the visualization more interactive and propagate mutations happening in the virtual world to the application’s source code?
  • Can we use VR for meaningful source code visualization? Obviously, although fun, the demo application doesn’t provide a lot of value.
  • Can we solve real-life problems this way?

I experimented with the first point. Since tree-shaking is a big thing in the JavaScript world, and I already had the trees, for AngularUP I introduced the shaking part. In order to make it more memorable, I created a lightweight server which accepts commands from the virtual reality and modifies the source code. For the purpose of the demo, we can tree-shake a tree and drop its leaves, one by one.

After one of the Angular SF meetups, I had a chat with Shawn Stedman who told me that after watching my talk on ngconf, he thought about extending the demo and building a Minecraft-based IDE where one can plant trees (i.e. create components), create gardens (add modules), etc. Abstractly thinking, this can be considered as a gamified IDE in the virtual reality.

It turns out that gamifying the software development process is a broadly researched topic.

Gamifying the software development process looks like an interesting opportunity, however, it still requires the full engagement of very expensive asset - software engineers. In our daily work environment, as engineers we don’t always have to solve exciting, challenging problems which use our full potential. Such tasks can be outsourced to people with lower expertise, even without engineering background.

This is where it gets interesting. Imagine if we’re able to isolate the manual, boring tasks that we need to perform every single day and present them into the form of a game released on the global market. This way hundreds of thousands of people, can solve the manual problems while consuming these games.

Looking at this from slightly different perspective, it turns out that scientists already use similar technic for using gamers as computational units for solving NP-complete protein folding problems [1] [2] [3].

Meanwhile, I found that there is a research for visualization of object-oriented source code in the three dimensional space [4] and in AltspaceVR experimented introducing a more traditional IDE to VR [5].

Conclusions

Virtual Reality opens an entire new world of visualization which we will most likely take advantage of as part of our development process in the next a couple of years. The questions that this blog post opens are:

  • Can we move our integrated development environment to VR and…
  • Can we isolate some of the manual tasks we need to perform as engineers, abstract them into the form of a game and outsource them as a game.

Although the demo project demonstrated in this blog post doesn’t have the potential to be turned into a full-fledged IDE, based on the third-party research in this direction seems that there’s an opportunity in this space.

Sample Implementation

Since looking in the code is always fun, in this section I’ll briefly describe the implementation of the demo project. Its source code is hosted on GitHub. Working demo can be found in the end of the post or here

Parsing

The initial part of the implementation of every compiler is its frontend. We get the phases of lexical analysis and syntax analysis for free from ngast, which delegates some of the work to ngc and the tsc.

Parsing the entire project with ngast is as simple as this:

export const parse = (projectPath: string) => {
  const project = new ProjectSymbols(createProgramFromTsConfig(projectPath), {
    getSync: (path: string) => readFileSync(path).toString(),
    get: (path: string) =>
      new Promise((resolve, reject) =>
        readFile(path, (error, content) => error ? reject(error) : resolve(content.toString())))
  }, (error: string, path: string) => console.error(error, path));
  return formatContext(project);
};

All we need to do is to create a new instance of the ProjectSymbols class by providing a TypeScript program, a host (ResourceResolver) and a logger to its constructor.

In the end of the parse method we transform the project with the function formatContext.

Transforms

After we have the symbols of the project, we need to extract the ASTs of the templates of the components and transform it to a form convenient for code generation.

Here are the signatures of the methods used for the phase of AST transformation, and the interfaces of their output:

export interface Module {
  name: string;
  components: Component[];
}

export interface Component {
  name: string;
  template: Node[];
  templateUrl: string;
}

export enum NodeType {
  Plain,
  Custom
}

export interface Node {
  name: string;
  type: NodeType,
  children: Node[];
  startOffset: number;
  endOffset: number;
}

export const formatContext = (context: ProjectSymbols) => {...};

const formatModules = (modules: ModuleSymbol[]) => {...};

const transformTemplateAst = (template: TemplateAst) => {...};

const formatComponents = (directives: DirectiveSymbol[]) => {...};
  • formatModules is responsible for transforming the internal ngast module representation to a structure which can be used for generation of a “garden”.
  • formatComponents will transform the internal DirectiveSymbols to object suitable for generation of “trees”.
  • transformTemplateAst is used for transformation of the directive’s TemplateAsts.

The implementations of these methods are straightforward, so we don’t have to go into any details, however, if you’re interested them, you can see the transformers here.

Layout

For our compiler, we need to implement one more AST transformation phase, which put into the context of ngworld is just computation of the layout of the virtual world. For simplicity in our VR everything will be known ahead of time and nothing will be generated lazily.

Here are the methods declarations and the interfaces of their outputs:

...

export interface Size {
  width: number;
  height: number;
  depth: number;
}

export interface Position {
  x: number;
  y: number;
  z: number;
}

export enum LeafType {
  Plain,
  Special
}

export interface Leaf {
  label: string;
  type: LeafType;
  startOffset: number;
  endOffset: number;
}

export type LeaveSet = Leaf[];

export interface TreeLayout {
  name: string;
  position: Position;
  leaves: LeaveSet[];
  templateUrl: string;
}

export interface GardenLayout {
  name: string;
  size: Size;
  position: Position;
  trees: TreeLayout[];
}

export interface WorldLayout {
  size: Size;
  position: Position;
  gardens: GardenLayout[];
}

const getLeaves = (template: Node[]) => {...};

// We have less trees compared to previous layer
const getTreesLayout = (components: Component[], prevSize: Size, prevPosition: Position): TreeLayout[] => {...};

const getGardenLayout = (module: Module, prevGarden: GardenLayout | undefined) => {...};

const getGardensLayout = (modules: Module[]): GardenLayout[] => {...};

export const createWorldLayout = (modules: Module[]): WorldLayout => {...};

In the snippet above we calculate the layout for the first tree of the first module, after that the second one, etc, until we calculate the layout for all the trees for the garden (module). Since at this point we already know the location of all the trees in given garden, we can just surround them with a fence which is the garden’s layout.

When we’ve calculated the layout of each individual garden, we can calculate the layout of the entire world.

Code Generation

The last step is the code generation. Given that we’ll use aframe, this is going to be a straightforward process. We can represent the leaves, trees and gardens as a mustache templates. Later, based on our calculations in the layout phase, we can render the templates and fill the placeholders corresponding to colors, positioning, labeling, etc.

Let’s take a look at the tree template, to get a better idea:

const TreeTemplate = `
<a-entity id="{{id}}" geometry="primitive: box; depth: 0.1; height: {{height}}; width: 0.2" position="{{x}} {{y}} {{z}}" rotation="0 30 0" material="shader: standard; metalness: 0.6; src: url(images/dirt.jpg); repeat: 1 4" data-template-url="{{{templateUrl}}}">
  <a-entity static-body="" geometry="primitive: box; depth: 0.1; height: {{height}}; width: 0.2" position="-0.1 0 0" rotation="2 60 0" material="shader: standard; metalness: 0.6; src: url(images/dirt.jpg); repeat: 1 4"></a-entity>
  <a-entity static-body="" geometry="primitive: box; depth: 0.1; height: {{height}}; width: 0.2" position="0 0 0.1" rotation="2 -90 0" material="shader: standard; metalness: 0.6; src: url(images/dirt.jpg); repeat: 1 4"></a-entity>
  <a-entity position="0 0 0.4" rotation="-35 -30 0" text="side: double; width: 5; color: white; align: center; value: {{label}};">
  </a-entity>
  {{{leaves}}}
  <a-animation attribute="rotation"¬
               dur="150"¬
               to="5 30 0"¬
               begin="shake-front-{{id}}"
               repeat="0">¬
  </a-animation>¬
  <a-animation attribute="rotation"¬
               dur="150"¬
               to="-3 30 0"¬
               begin="shake-back-{{id}}"
               repeat="0">¬
  </a-animation>¬
  <a-animation attribute="rotation"¬
               dur="150"¬
               to="0 30 0"¬
               begin="shake-ready-{{id}}"
               repeat="0">¬
  </a-animation>¬
</a-entity>
`;

This is a standard aframe template where we have an entity with identifier. Inside of it we have declaration of three animations and also placeholder for the leaves. The animations are related to the tree-shaking simulation. The properties of the object that this template accepts, can be represented by the following interface:

interface TreeProperties {
  x: number;
  y: number;
  z: number;
  height: number;
  label: string;
  id: string;
  leaves: string;
  templateUrl: string;
}

Notice that inside of the TreeProperties interface we have declaration of templateUrl. Now lets take a look at the leaf template and properties interface:

interface LeafProperties {
  color: string;
  x: number;
  y: number;
  z: number;
  label: string;
  width: number;
  height: number;
  depth: number;
  halfLeaf: number;
  id: string;
  treeId: string;
  endOffset: number;
  startOffset: number;
}

const LeafTemplate = `
<a-entity
  id="{{id}}"
  data-start-offset="{{startOffset}}"
  data-end-offset="{{endOffset}}"
  data-tree-id="{{treeId}}"
  geometry="primitive: box; depth: {{depth}}; height: {{height}}; width: {{width}}"
  position="{{x}} {{y}} {{z}}"
  material="shader: standard; metalness: 0.6; color: {{color}}; repeat: 1 1">
  ...
  <a-animation attribute="position"¬
               dur="1000"¬
               begin="shake-{{id}}"
               fill="forwards"¬
               to="{{x}} 0 {{z}}"¬
               repeat="0">¬
  </a-animation>¬
</a-entity>
`;

There are three interesting properties that we need to consider:

  • treeId - identifier of the tree this leaf is attached to.
  • startOffset - the start offset of the template element represented by this leaf. This is the start position of the opening tag of the element in the string representing the component’s template.
  • endOffset - the end offset of the template element represented by this leaf. This is the end position of the closing tag of the element in the string representing the component’s template.

This is all the metadata required for removal of template elements by “shaking the tree”.

Tree-Shaking

When we shake the tree, we activate the following invocation:

fetch('http://localhost:8081', {
  method: 'post',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    file: tree.getAttribute('data-template-url'),
    start: leaf.getAttribute('data-start-offset'),
    end: leaf.getAttribute('data-end-offset')
  })
});

All it does is to send a post request to an HTTP application server listening on port 8081. All the server needs to do, is to remove the element corresponding to the given offset.

However, notice that if we remove an element, the offsets of all the elements following it in the template, will require an update. This will involve more complex communication protocol between the VR UI and the application server. Because of that, the demo simply replaces all the different characters from the element with whitespace.

Server

Here’s the server implementation, with the mentioned hack:

app.post('/', (request, response) => {
  const p = request.body;
  console.log(p.file);
  if (p.file) {
    const content = readFileSync(p.file).toString();
    const result = content.substring(0, p.start) +
      content.substring(p.start, p.end).replace(/\S/g, ' ') +
      content.substring(p.end, content.length);
    writeFileSync(p.file, result);
  }
  response.end();
});

Further improvements

Of course, we can start planting trees and creating gardens in order to turn this demo into a more complete “IDE”. Another place for improvement is to drop all child leaves once a parent leaf has been shaken.

There’s place for a lot of improvement, however, I’m not sure if such a demo project will provide enough value to worth this investment.

External resources

  1. Gamers succeed where scientists fail
  2. Games companies turn to outsourcers for low-cost workers
  3. Online Games as Social-Computational Systems for Solving NP-complete Problems
  4. Visualizing Software in an Immersive Virtual Reality Environment
  5. http://cognitivevr.co/blog/programming-in-virtual-reality/

Demo