Aoto Ant Financial · Data Experience Technology team
Q: Why did you write this article? What does the passage mean?
A: We are considering to use TS as the development language in SPA application. We need an article that systematically introduces TS itself and its surroundings to demonstrate that it is scientific and reasonable to use TS as the development language in the project, and it is in line with the trend.
guidance
- What is the TS
- Why use TS
- What can TS do
- Cost of using TS
- Community development
- The surrounding ecological
- An in-depth look at TS
- Accept the TS
- Weigh the
What is the TS
TypeScript = Type + Script (standard JS). TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. TypeScript is a type-defined JS superset compiled into pure JS.
Why use TS
Goal: Complex SPA applications with long life cycles (often several years) to improve code maintainability and online runtime quality while maintaining development efficiency.
- From the perspective of development efficiency, although we need to write more type definition code, TS can provide intelligent hints and intellisom bugs under VSCode, WebStorm and other IDES. At the same time, some third-party class library frameworks commonly used in our project have TS type declarations. We can also write declaration files for those stable modules that do not have TS type declarations. For example, our front-end KOP framework (currently an ant internal framework, similar to DVA) can improve the overall development efficiency in team collaboration projects.
- Look from the maintainability, iterative maintenance over a long period of time there will be a lot of development and maintenance of project members, team members level difference, the software has the characteristics of entropy, long-term iterative maintenance project of maintainability, gradually reduce the problems always, have a strong type constraints and static checking, and intelligent IDE, with the help of can reduce the speed of the software corruption, improve maintainability, Strong typing and static type checking can be a big help when refactoring, and even having type definitions can inadvertently increase the frequency of refactoring (safer and safer).
- Look from the online running quality, our SPA project many bugs are now due to some of the caller and the called party (such as the collaboration of the component module, interface or function calls) data format does not match, due to the static checking TS have a compile time, let’s bug, as far as possible in the compiler, plus the IDE intelligent error correction, Bugs can be sensed in advance when coding, and the quality of our online runtimes will be more stable and controllable.
The general research and development process of a complex software is roughly divided into defining problems, requirements analysis, planning and construction, software architecture, detailed design, coding and debugging, unit testing, integration testing, integration, system testing and maintenance. Build activities (mainly coding debugging) account for more than 50% of the workload on medium to large projects. At the same time, in a medium to large project, the proportion of bugs caused by the construction phase accounts for 50% to 75%. For a successful project, construction activities are necessary and more controllable for engineers. 【 code 】
TS scales for large-scale JavaScript applications, as its official tagline JavaScript that Scales says. TS has obvious benefits in terms of teamwork, maintainability, readability, stability (bugs exposed early at compile time), and so on:
- The addition of a type system is friendly to both code readers and compilers. For the reader, the type definition, along with the IDE’s smart hints, enhances the legibility of the code; For the compiler, type definitions allow the compiler to catch hidden bugs.
- Type system + static analysis check + intellisence/hints make large-scale applications with higher code quality, less bugs at runtime and easier to maintain.
- With supporting IDE support such as VSCode, it is convenient to view type inference and reference relationships, which can be more convenient and safe for reconstruction, no longer need to search globally, one by one modification.
- Define types for application configuration, application state, front-end and back-end interfaces, and various modules. The entire application is typed one by one, making collaboration more convenient, efficient, and secure.
What can TS do
Static checking
This type of problem is not detected by tools such as ESLint.
Low-level mistakes
const peoples = [{
name: 'tim',
age: 20
}, {
name: 'alex',
age: 22
}];
const sortedPeoples = peoples.sort((a, b) = > a.name.localCompare(b.name));
Copy the code
Error detected when executing TSC:
error TS2339: Property 'localCompare' does not exist on type 'string'.
Copy the code
If you are in an IDE that supports TS (VS Code, WebStorm, etc.), the error message in the localCompare position is very obvious in the IDE without waiting for compilation.
Typing errors like localCompare (or accidentally deleting or adding characters by hand) happen all the time, and if the compiler doesn’t statically check it, it could be a character bloodbath: a hidden runtime bug buried. If this problem takes a long path to discover in a SPA application, it can explode as soon as the user triggers the mine: the application crashes directly (especially in a SPA where there is no page refresh).
Judge not empty
let data = {
list: null,
success: true
};
const value = data.list.length;
Copy the code
Perform TSC compilation:
error TS2532: Object is possibly 'null'.
Copy the code
The data.list.length line directly references the attribute of data.list, but the data format of data.list may not be an array. This scenario often occurs when the front end processes the data returned by the back end interface. That would mean planting a bomb that could detonate at any given moment.
Type inference
const arr = [];
arr.toUpperCase();
class Cat {
miao() {}
}
class Dog {
wang() {}
}
const cat = new Cat();
cat.wang();
Copy the code
Perform TSC compilation:
error TS2339: Property 'toUpperCase' does not exist on type 'any[]'.
error TS2339: Property 'wang' does not exist on type 'Cat'.
Copy the code
TS has type inference, and calls to the wrong method for different types of execution objects will be detected.
Object-oriented programming enhancements
Access control
class Person {
protected name: string;
public age: number;
constructor(name: string) { this.name = name; }}class Employee extends Person {
static someAttr = 1;
private department: string;
constructor(name: string, department: string) {
super(name);
this.department = department; }}let howard = new Employee("Howard"."Sales");
console.log(howard.name);
Copy the code
Perform TSC compilation:
error TS2445: Property 'name' is protected and only accessible within class 'Person' and its subclasses.
Copy the code
The name attribute in Person is protected and can only be used in its own class or subclasses. Access control is very useful in object oriented programming, it can help us to do information hiding, a big problem with JS object oriented programming is that there is no native support for information hiding (a lot of times it is done by convention encoding). Information hiding helps to better manage system complexity, which is particularly important in software engineering.
interface
interface Machine {
move(): void
}
interface Human {
run(): void
}
class Base {
}
class Robot extends Base implements Machine, Human {
run() {
console.log('run');
}
move() {
console.log('move'); }}Copy the code
The Robot class can inherit the Base class and implement Machine and Human interfaces. This combination of inherited classes and implemented interfaces makes object-oriented programming more flexible and extensible.
The generic
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) = > T;
}
let myGenericNumber = new GenericNumber<number> (); myGenericNumber.zeroValue =0;
myGenericNumber.add = function(x, y) { return x + y; };
Copy the code
GenericNumber defines a template type T that can be passed in built-in or custom types when instantiating the GenericNumber class. Generics (templates) are a common concept in traditional object-oriented programming languages and can be useful in scenarios where code logic is generic and arguments can be dynamically typed.
The type system
interface SystemConfig {
attr1: number;
attr2: string;
func1(): string;
}
interfaceModuleType { data: { attr1? :string, attr2? :number
},
visible: boolean
}
const config: SystemConfig = {
attr1: 1,
attr2: 'str',
func1: (a)= > ' '
};
const mod: ModuleType = {
data: {
attr1: '1'
},
visible: true
};
Copy the code
We define a system configuration type, SystemConfig, and a ModuleType, ModuleType, so we can’t modify config and mod data when using these types. Each called party is responsible for its own external type representation, and the caller only needs to care about the type of the called party, not the internal details. This is the benefit of type constraints, which can be very helpful for team projects with multiple people working together.
Module system enhancement
namespace N {
export namespace NN {
export function a() {
console.log('N.a');
}
}
}
N.NN.a();
Copy the code
TS supports namespaces in addition to ES6’s modular system. This is useful when managing the internals of complex modules.
Cost of using TS
Learning costs
In theory, learning and using a new language can be expensive, but the good news is that TS itself is a superset of JS, which means it can support existing JS code, at least in theory. Learn about type systems and basic object-oriented knowledge, should be able to hold TS, the cost is not very high. Official documents are the best learning material.
Application of the cost
The old project
For older projects, since TS is compatible with the ES specification, it is relatively easy to upgrade existing JS (ES6 and above) code, gradually add type annotations, and gradually improve code robustness. Migration process:
-
NPM installs the typescript package globally and runs TSC –init in the project root to automatically generate the tsconfig.json file. The default configuration items are as follows: More configuration items
"target":"es5"
: ES version of compiled code, es3, ES2105, etc."module":"commonjs"
Modular organization of compiled code, amd, UMD, ES2015, etc."strict":true
: strict check, including no meaningless any, null check options.
-
The tsconfig.json initialization does not need to be modified, adding the “allowJs”: true option.
-
Configure webpack configuration to add TS loaders such as awesome-typescript-loader. (If the project is built based on The Atool-build, it has ts compilation built in, which is omitted.)
loaders: [ // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'. { test: /\.tsx?$/, loader: "awesome-typescript-loader" } ] Copy the code
-
Now you can write code named ts and TSX (React). It can coexist with existing ES6 code. VSCode automatically validates this part of the code, and webpack is no problem.
-
As time goes by, we’re looking to refactor old ES6 code into TS code, simply change the file suffix to TS (x), and enjoy the benefits of TS and IDE intellisawareness/error correction.
More migration tutorials: Official Migration Tutorial, Official React Project Migration Tutorial, Community Tutorial 1, Community Tutorial 2.
The new project
- For new projects, Microsoft has some great Starter projects that detail how to use TS with other frameworks and libraries. For React projects, see the Starter: typescript-react-starter
The cost comparison
Star means dominant
The cost of some | ES | TS | instructions |
---|---|---|---|
Learning and stomping costs | Does does does does does | Does does does | Although it is JS superset, but still to learn TS itself and object-oriented basic knowledge, the development environment, the use of problems and pits also need their own trip, fortunately, TS community is more mature, online precipitation of a lot of information |
Total code weight | Does does does does does | Does does does does | TS code with more complete type definitions is 5% to 10% more than native ES code |
Native JS (standard ES, browser side, server side) | Does does does | Does does does does does | IDE built-in detailed type declaration, can intelligently prompt method and parameter description, improve efficiency |
Rely on external libraries (React, Lodash, Antd) | Does does does | Does does does does does | TS type declaration library, IDE intelligent tips and analysis, efficiency improvement |
Internal common libraries, modules | Does does does | Does does does does | The type definition file is written by the team itself, which has a certain amount of work, but the development efficiency can be improved. After the type definition is gradually improved, the efficiency will be further improved |
Teamwork efficiency | Does does | Does does does does does | After defining system configuration, external interface, and internal module types, instance object attributes cannot be changed at will. Each called party is responsible for its own external type representation (which can be understood as shapes). The caller only needs to care about the type of the called party, not the internal details |
Code maintainability | Does does | Does does does does | Due to team member level differences, and softwareentropyWith the help of strong type constraints and static checking, as well as intelligent IDE, it can reduce the rate of software corruption, improve maintainability, and improve the maintainabilityrefactoringStrong typing and static type checking can help a lot, and even having type definitions can inadvertently increase the frequency of refactoring |
Runtime stability | Does does | Does does does does | Since TS has static type checking, many bugs will be eliminated before launch |
summary
Can see from the above comparison, using familiar ES as development language only in learning and advantage on cost of pit and the overall amount of code, if only short-term projects that use ES understandable, but our project life cycle lasts several years, iterative upgrade continuously, the TS is comparatively mature community, many learning materials, Moreover, TS brings improved efficiency, maintainability and stability of internal collaborative development, so it is a price worth paying in the long run. Moreover, the existence of various type declaration definition files can improve the development efficiency; In addition, static type checking can reduce the number of bugs and the difficulty of troubleshooting bugs, which also improves efficiency, and makes the whole project relatively more stable and controllable.
Community development
As you can see from Stackoverflow’s 2017 Developer Survey, Google Trends, and NPM download trends, the TypeScript community has grown rapidly, especially in recent years. Especially with the advent of VS Code (written by TS and very TS friendly), the VS Code + TypeScript combination has brought a clean flow of productivity and standardization to the front end. As you can see from Google’s support for TS (Angular versions higher than 2 are written in TS), so are the big international manufacturers.
From the inside of Ant Group, products such as Ant Design and Basement are also based on TS (or at least are in extensive use). Although there are some objections, the overall outlook is positive. With the right soil, it will develop rapidly, such as Ant Design.
The surrounding ecological
Type declaration package
React and various other popular frameworks and libraries have TS declarations. You can install them in your project by using NPM install@types/React. You can search this website for library declarations that you want to install. Once installed, writing code related to those frameworks and libraries will be a great experience, and the function definitions and comments will be automatically prompted, which will improve development efficiency.
IDE
Popular IDES such as VS Code and WebStorm have very friendly support for TS. VS Code is even written by TS itself.
An in-depth look at TS
TS language design objectives
The target
You can do static checking at compile time, provide a structured device for large-scale code, compile custom readable JS code, align it with the ECMAScript standard, use a consistent, removable, structured type system, protect the runtime behavior of compiled JS code, and so on.
The target
Mimic an existing language, optimize the performance of compiled code, apply the “right” type system, add runtime type information, and so on.
TS design objective text
TS a brief history of
In recent years, with the V8 platform, the major modern browsers up, JS running platform continues to improve, but, JS for large application development is very difficult, JS language is not designed for large applications, it is a scripting language, it does not have static type verification, but more importantly, He didn’t provide classes, modules/namespaces, interfaces, etc., which are required for large scale applications. He also has GWT and other projects that allow you to develop large JS applications in other languages, such as Java and other object-oriented languages. You can use nice ides like Eclipse, but these projects don’t write code in JS, so if you want to use something in JS, you might have to struggle to implement it in another language. So we thought about how to enhance the JS language. **TS is a language for developing large JS applications. More specifically, TS is a superset of JS compiled into typed pure JS. ** So in general, JS code is also TS code. The TS compiler itself is also written by TS and runs the Node.js environment. [Anders Hejlsberg: Introducing TypeScript 2012]
Here’s a graph from TS’s recent Build conference:
As shown in the figure, the JS of Web and Node platform always has a distance from the latest JS specification, and the distance of Web platform is farther. TS can fill this gap, so that users can use the latest features on both Web and Node platform, use elegant JS, and improve productivity. Anders Hejlsberg: What’s New in TypeScript? 2017
Contrast with Flow and Babel
vs Flow
As you can see from this article, the basic type-checking capabilities are not that different now, but TS beats Flow in terms of surrounding ecology, document integrity, and community resources.
vs Babel
Babel is also a very good ES6 to 5 compilation tool, with good plug-in mechanism and good community development. However, in the JS code compiled by the same code, we can see that the TS compiled code is more consistent with the habit, concise and easy to read (both using Playground tool of the official website). I have maintained TS compiled JS code (TS source lost), feel OK.
Babel:
TS compiled:
TS basic knowledge and core concepts
The base type
let isDone: boolean = false;
let decimal: number = 6;
let color: string = "blue";
// Array, there are two ways to write it
let list: number[] = [1.2.3];
let list: Array<number> = [1.2.3];
/ / yuan group (a Tuple)
let x: [string.number] = ["hello".10];
/ / the enumeration
enum Color {Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green;
// If you are not sure, you can declare any first
let notSure: any = 4;
// Declare no return value
function warnUser() :void {
alert("This is my warning message");
}
let u: undefined = undefined;
let n: null = null;
// The type never returns
function error(message: string) :never {
throw new Error(message);
}
// Type assertion, which means you know more than the compiler and actively tell the compiler more information, can be written in two ways
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
let strLength: number = (someValue as string).length;
Copy the code
More information can be found in the official documentation.
interface
One of the core tenets of TS is that type checking focuses on the shape of values, sometimes called “duck typing” or “structural subtyping.” In TS interfaces take on such a role, defining shapes and constraints for use internally or in collaboration with external systems. An example:
interface SystemConfig {
attr1: string;
attr2: number;
func1(): string;
func2(): void;
}
Copy the code
This interface defines the shape of the system configuration, attr1 and attr2, and func1 and func2, so that const systemConfig is defined: SystemConfig = {}, SystemConfig cannot be modified at will, it has a shape.
In Java, we advocate interface programming, which is superior to Effective Java classes. In TS class systems, interfaces can play a similar role. You can implement interfaces with implements, which allow for more flexible inheritance, such as:
class A extends BaseClass implements BaseInterface1, BaseInterface2 {}
Copy the code
Class A inherits BaseClass and BaseInterface1 and BaseInterface2 interfaces.
module/namespace
External modules are written in the same way as ES6 modules. Internal modules are recommended to use namespace, for example:
namespace Module1 {
export interface SubModule1 {}
export interface SubModule2 {}
}
const module: Module1.SubModule = {}
Copy the code
Namespaces can also be implemented in JS as object literals, and many JS libraries in the early years have done this, but it is clear that with this explicit namespace declaration, the code is much more readable and cannot be changed at will, unlike it is easily overridden with native JS objects.
Access control
TS has public, protected, and private access privileges similar to those of traditional object-oriented languages, which are useful in large applications and are not expanded here.
other
Classes, decorators, async/await, etc. are written similarly to ES6 and ES7, except that generics are relatively difficult to master.
The Type and the Type System
TypeScript = Type + Script. How do we define Type in programming languages?
In computer science and computer programming, a data type or simply type is a classification of data which tells the compiler or interpreter how the programmer Adapt to use the data.
In computer science, data types, or simply types, are categories of data that tell the compiler/interpreter what the programmer wants to do with the data. Basic data types such as integers, booleans, and characters, combined data types such as groups, objects, and abstract data types such as queues, stacks, collections, dictionaries, and so on. Data types are used in the type system, which provides the way in which types are defined, implemented, and used. Each programming language has its own type system implementation (if any).
Let’s look at the definition of Type System:
In programming languages, a type system is a set of rules that assigns a property called type to the various constructs of a computer program, such as variables, expressions, functions or modules.[1] These types formalize and enforce the (otherwise implicit) categories the programmer uses for data structures and components (ex: “string”, “array of float”, “function returning boolean”). The main purpose of a type system is to reduce possibilities for bugs in computer programs[2] by defining interfaces between different parts of a computer program, And then checking that the parts have been connected in a consistent way.
In a programming language, a type system is a collection of rules that assign attributes called types to variables, expressions, functions, modules, and other program building elements in a program. These types specify and force, perhaps implicitly, programmers on how to use data structures. The main purpose of the ** type system is to reduce the number of bugs a program can produce by defining an interface for collaboration between different parts of the program and checking that the different parts collaborate in a consistent way. ** This check may be static (compile-time) or dynamic (runtime), or both.
Benefits of the type system
Detect errors
The most obvious benefit of static typechecking is that it allows early detection of some programming errors. Errors that are detected early can be fixed immediately, Rather than lurking in the code to be discovered much later,when the programmer is in the middle of something else — or even after the program has been deployed. Moreover, errors can often be pinpointed more accurately during typechecking than at run time, Types and Programming when their effects may not become visible until some time after things begin to go wrong Languages.
As your app grows, you can catch a lot of bugs with typechecking.
The most obvious benefit of static type checking is that errors can be detected early in the program. Bugs are detected early so they can be fixed quickly, rather than lurking in the code until mid-deployment or even live. Furthermore, errors can be more accurately located at compile time, whereas at run time, the effects of errors may not be easily detected until a problem occurs in the program.
Applications can have a variety of data structures, and if a data type is changed, the front end will often handle this refactoring through a global lookup. Static type checking, on the other hand, allows you to detect all possible errors once you compile again, and the IDE’s intelligent error prompts make refactoring easier and easier.
abstract
Another important way in which type systems support the programming process is by enforcing disciplined programming. In particular, in the context of large-scale software composition, type systems form the backbone of the module languages used to package and tie together the components of large systems. Types show up in the interfaces of modules (and related structures such as classes); indeed, An interface itself can be viewed as “the type of a module,” providing a summary of the facilities provided by the Module — a kind of partial contract between implementors and users.
Structuring large systems in terms of modules with clear interfaces leads to a more abstract style of design, where interfaces are designed and discussed independently from their eventual implementations. More abstract thinking about interfaces generally leads to better design.【Types and Programming Languages】
Another important way that type systems support the programming phase is by enforcing discipline. In large-scale software systems, type systems form the backbone of component collaboration systems. A type is represented in the interface of a module (or related structure such as a class). An interface can be thought of as a “module type,” which represents the functionality that a module can provide and is a contract between an implementer and a user.
Clear interfaces in large-scale structured software systems with a large number of modules working together can make design more abstract, and the design and discussion of interfaces are independent of their implementation. In general, more abstract thinking about interfaces leads to better designs.
Types enable programmers to think at a higher level than the bit or byte, not bothering with low-level implementation. For example, programmers can begin to think of a string as a set of character values instead of as a mere array of bytes. Higher still, types enable programmers to think about and express interfaces between two of any-sized subsystems. This enables more levels of localization so that the definitions required for interoperability of the subsystems remain consistent when Those two subsystems communicate.
Types make programmers think in a higher dimension, rather than getting bogged down in the details of the underlying computer implementation. For example, we can think of strings as character sets, not just arrays of bits. At a higher level, type systems allow us to think and express collaboration between any subsystem/subroutine in terms of interfaces, and interface definitions allow consistent communication between subsystems/subroutines.
document
Types are also useful when reading programs. The type declarations in procedure headers and module interfaces constitute a form of documentation,giving useful hints about behavior. Moreover, unlike descriptions embedded in comments, this form of documentation cannot become outdated, since it is checked during every run of the compiler. This role of types is particularly important in module Signatures.【Types and Programming Languages】
Types are also useful for reading programs. Type declarations and module interfaces in the program header form the shape of the document that provides hints for the behavior of the program. Also, unlike what is described in comments, this form of documentation is not out of date because it is validated each time you compile, which is particularly important in module signatures.
In more expressive type systems, types can serve as a form of documentation clarifying the intent of the programmer. For example, if a programmer declares a function as returning a timestamp type, this documents the function when the timestamp type can be explicitly declared deeper in the code to be an integer 【 Wikipedia 】
In type systems that reuse expressiveness, types can be seen as a way of describing programmer intentions. For example, we declare that a function returns a timestamp, which makes it clear that the function returns an integer type in further code calls.
Language security
The term “safe language” is, unfortunately, Even more misgivings than “type system.” Although people generally feel they know one when they see it, their notions of exactly what constitutes language safety are strongly influenced by the language community to which they belong. Informally, though, Safe languages can be defined as ones that make it impossible to shoot yourself in the foot while programming Programming Languages.
The term “safe language” is controversial. Heavily influenced by the language community. Unofficially, a secure language can be defined as programming without the possibility of killing itself from the ground up.
A type system enables the compiler to detect meaningless or probably invalid code. For example, we can identify an expression 3 / “Hello, World” as invalid, when the rules do not specify how to divide an integer by a string. Strong typing offers more safety, But cannot guarantee complete type safety.
The type system allows the compiler to check for nonsensical or possibly illegal code. For example, we know that 3/’ Hello world’ is illegal, and that strong typing provides more security, but not complete type safety.
The efficiency of
Static type-checking may provide useful compile-time information. For example, if a type requires that a value must align in memory at a multiple of four bytes, The compiler may be able to use more efficient machine instructions.
Static type checking provides useful compile-time information. For example, if a type requires four bytes in memory, the compiler might use more efficient machine instructions.
Static type, dynamic type, weak type, strong type
- Static typing: The type of each variable is known at compile time. Type error compile failure is a syntax problem. Such as Java, C++.
- Dynamic typing: the type is not known at compile time, but at run time. Type errors throw exceptions that occur at run time. Such as JS, Python.
- Weak typing: Tolerates implicit type conversions. Such as JS,
1 + '1' = '11'
The numeric type is converted to the character type. - Strong typing: Implicit type conversions are not tolerated. Such as Python,
1 + '1'
Will be thrownTypeError
.
Accept the TS
I was a little resistant to TS when it first came out, or I felt similar to it when it was compiled into JS languages such as CoffeeScript and Dart. I felt that IT was the product of other languages’ penetration into JS. In the past year or two, THE voice of TS has become stronger and stronger in the community, and I also started to do large-scale JavaScript applications, and gradually rerecognized TS. I gradually realized the importance of TS type system, TSC static checking, VS Code and other IDE support for developing maintainable and stable large JavaScript applications.
Weigh the
How to make better use of JS dynamic and TS static characteristics, we need to combine the actual situation of the project to make a comprehensive judgment. Some suggestions:
- If it’s a small to medium size project with a short life cycle, use JS instead of getting stuck with TS.
- For large applications with a long life cycle, you are advised to try TS. Open source projects such as VS Code and GitHub desktop, while non-open ones such as Slack Desktop, Asana and Palantir.
- If it is a public module such as a framework or library, then TS is recommended. Examples include Ant Design, Angular, Ionic.
Whether to use TS depends on the actual project size, project life cycle, team size, team members and other actual conditions.
Original address: github.com/ProtoTeam/b…