diff --git a/.gitignore b/.gitignore index f72f0cd..daf913b 100644 --- a/.gitignore +++ b/.gitignore @@ -19,16 +19,6 @@ _cgo_export.* _testmain.go -*.prof -# Test binary, build with `go test -c` -*.test -# Binaries for programs and plugins *.exe -*.dll -*.dylib - -# JetBrains project files -.idea/ - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out \ No newline at end of file +*.test +*.prof diff --git a/CONTRIBUTING.html b/CONTRIBUTING.html new file mode 100644 index 0000000..e94dc67 --- /dev/null +++ b/CONTRIBUTING.html @@ -0,0 +1,1047 @@ + + + + + + + Contributing · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Contribution Guidelines

+

Please ensure your pull request adheres to the following guidelines:

+
    +
  • Make an individual pull request for each suggestion.
  • +
  • Choose the corresponding patterns section for your suggestion.
  • +
  • List, after your addition, should be in lexicographical order.
  • +
+

Commit Messages Guidelines

+
    +
  • The message should be in imperative form and uncapitalized.
  • +
  • If possible, please include an explanation in the commit message body
  • +
  • Use the form <pattern-section>/<pattern-name>: <message> (e.g. creational/singleton: refactor singleton constructor)
  • +
+

Pattern Template

+

Each pattern should have a single markdown file containing the important part of the implementation, the usage and the explanations for it. This is to ensure that the reader doesn't have to read bunch of boilerplate to understand what's going on and the code is as simple as possible and not simpler.

+

Please use the following template for adding new patterns:

+
# <Pattern-Name>
+<Pattern description>
+
+## Implementation
+
+## Usage
+
+// Optional
+## Rules of Thumb
+
+ + +
+ +
+
+ +
+ + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 7ae7acb..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,31 +0,0 @@ -# Contribution Guidelines - -Please ensure your pull request adheres to the following guidelines: - -- Make an individual pull request for each suggestion. -- Choose the corresponding patterns section for your suggestion. -- List, after your addition, should be in lexicographical order. - -## Commit Messages Guidelines - -- The message should be in imperative form and uncapitalized. -- If possible, please include an explanation in the commit message body -- Use the form `/: ` (e.g. `creational/singleton: refactor singleton constructor`) - -## Pattern Template - -Each pattern should have a single markdown file containing the important part of the implementation, the usage and the explanations for it. This is to ensure that the reader doesn't have to read bunch of boilerplate to understand what's going on and the code is as simple as possible and not simpler. - -Please use the following template for adding new patterns: - -```markdown -# - - -## Implementation - -## Usage - -// Optional -## Rules of Thumb -``` diff --git a/README.md b/README.md deleted file mode 100644 index 7d9f5f7..0000000 --- a/README.md +++ /dev/null @@ -1,110 +0,0 @@ -

- -

- Go Patterns -
- build-status - awesome - license -

-

- -A curated collection of idiomatic design & application patterns for Go language. - -## Creational Patterns - -| Pattern | Description | Status | -|:-------:|:----------- |:------:| -| [Abstract Factory](/creational/abstract_factory.md) | Provides an interface for creating families of releated objects | ✘ | -| [Builder](/creational/builder.md) | Builds a complex object using simple objects | ✔ | -| [Factory Method](/creational/factory.md) | Defers instantiation of an object to a specialized function for creating instances | ✔ | -| [Object Pool](/creational/object-pool.md) | Instantiates and maintains a group of objects instances of the same type | ✔ | -| [Singleton](/creational/singleton.md) | Restricts instantiation of a type to one object | ✔ | - -## Structural Patterns - -| Pattern | Description | Status | -|:-------:|:----------- |:------:| -| [Bridge](/structural/bridge.md) | Decouples an interface from its implementation so that the two can vary independently | ✘ | -| [Composite](/structural/composite.md) | Encapsulates and provides access to a number of different objects | ✘ | -| [Decorator](/structural/decorator.md) | Adds behavior to an object, statically or dynamically | ✔ | -| [Facade](/structural/facade.md) | Uses one type as an API to a number of others | ✘ | -| [Flyweight](/structural/flyweight.md) | Reuses existing instances of objects with similar/identical state to minimize resource usage | ✘ | -| [Proxy](/structural/proxy.md) | Provides a surrogate for an object to control it's actions | ✔ | - -## Behavioral Patterns - -| Pattern | Description | Status | -|:-------:|:----------- |:------:| -| [Chain of Responsibility](/behavioral/chain_of_responsibility.md) | Avoids coupling a sender to receiver by giving more than object a chance to handle the request | ✘ | -| [Command](/behavioral/command.md) | Bundles a command and arguments to call later | ✘ | -| [Mediator](/behavioral/mediator.md) | Connects objects and acts as a proxy | ✘ | -| [Memento](/behavioral/memento.md) | Generate an opaque token that can be used to go back to a previous state | ✘ | -| [Observer](/behavioral/observer.md) | Provide a callback for notification of events/changes to data | ✔ | -| [Registry](/behavioral/registry.md) | Keep track of all subclasses of a given class | ✘ | -| [State](/behavioral/state.md) | Encapsulates varying behavior for the same object based on its internal state | ✘ | -| [Strategy](/behavioral/strategy.md) | Enables an algorithm's behavior to be selected at runtime | ✔ | -| [Template](/behavioral/template.md) | Defines a skeleton class which defers some methods to subclasses | ✘ | -| [Visitor](/behavioral/visitor.md) | Separates an algorithm from an object on which it operates | ✘ | - -## Synchronization Patterns - -| Pattern | Description | Status | -|:-------:|:----------- |:------:| -| [Condition Variable](/synchronization/condition_variable.md) | Provides a mechanism for threads to temporarily give up access in order to wait for some condition | ✘ | -| [Lock/Mutex](/synchronization/mutex.md) | Enforces mutual exclusion limit on a resource to gain exclusive access | ✘ | -| [Monitor](/synchronization/monitor.md) | Combination of mutex and condition variable patterns | ✘ | -| [Read-Write Lock](/synchronization/read_write_lock.md) | Allows parallel read access, but only exclusive access on write operations to a resource | ✘ | -| [Semaphore](/synchronization/semaphore.md) | Allows controlling access to a common resource | ✔ | - -## Concurrency Patterns - -| Pattern | Description | Status | -|:-------:|:----------- |:------:| -| [N-Barrier](/concurrency/barrier.md) | Prevents a process from proceeding until all N processes reach to the barrier | ✘ | -| [Bounded Parallelism](/concurrency/bounded_parallelism.md) | Completes large number of independent tasks with resource limits | ✔ | -| [Broadcast](/concurrency/broadcast.md) | Transfers a message to all recipients simultaneously | ✘ | -| [Coroutines](/concurrency/coroutine.md) | Subroutines that allow suspending and resuming execution at certain locations | ✘ | -| [Generators](/concurrency/generator.md) | Yields a sequence of values one at a time | ✔ | -| [Reactor](/concurrency/reactor.md) | Demultiplexes service requests delivered concurrently to a service handler and dispatches them syncronously to the associated request handlers | ✘ | -| [Parallelism](/concurrency/parallelism.md) | Completes large number of independent tasks | ✔ | -| [Producer Consumer](/concurrency/producer_consumer.md) | Separates tasks from task executions | ✘ | - -## Messaging Patterns - -| Pattern | Description | Status | -|:-------:|:----------- |:------:| -| [Fan-In](/messaging/fan_in.md) | Funnels tasks to a work sink (e.g. server) | ✔ | -| [Fan-Out](/messaging/fan_out.md) | Distributes tasks among workers (e.g. producer) | ✔ | -| [Futures & Promises](/messaging/futures_promises.md) | Acts as a place-holder of a result that is initially unknown for synchronization purposes | ✘ | -| [Publish/Subscribe](/messaging/publish_subscribe.md) | Passes information to a collection of recipients who subscribed to a topic | ✔ | -| [Push & Pull](/messaging/push_pull.md) | Distributes messages to multiple workers, arranged in a pipeline | ✘ | - -## Stability Patterns - -| Pattern | Description | Status | -|:-------:|:----------- |:------:| -| [Bulkheads](/stability/bulkhead.md) | Enforces a principle of failure containment (i.e. prevents cascading failures) | ✘ | -| [Circuit-Breaker](/stability/circuit-breaker.md) | Stops the flow of the requests when requests are likely to fail | ✔ | -| [Deadline](/stability/deadline.md) | Allows clients to stop waiting for a response once the probability of response becomes low (e.g. after waiting 10 seconds for a page refresh) | ✘ | -| [Fail-Fast](/stability/fail_fast.md) | Checks the availability of required resources at the start of a request and fails if the requirements are not satisfied | ✘ | -| [Handshaking](/stability/handshaking.md) | Asks a component if it can take any more load, if it can't, the request is declined | ✘ | -| [Steady-State](/stability/steady_state.md) | For every service that accumulates a resource, some other service must recycle that resource | ✘ | - -## Profiling Patterns - -| Pattern | Description | Status | -|:-------:|:----------- |:------:| -| [Timing Functions](/profiling/timing.md) | Wraps a function and logs the execution | ✔ | - -## Idioms - -| Pattern | Description | Status | -|:-------:|:----------- |:------:| -| [Functional Options](/idiom/functional-options.md) | Allows creating clean APIs with sane defaults and idiomatic overrides | ✔ | - -## Anti-Patterns - -| Pattern | Description | Status | -|:-------:|:----------- |:------:| -| [Cascading Failures](/anti-patterns/cascading_failures.md) | A failure in a system of interconnected parts in which the failure of a part causes a domino effect | ✘ | diff --git a/SUMMARY.md b/SUMMARY.md deleted file mode 100644 index 9337c64..0000000 --- a/SUMMARY.md +++ /dev/null @@ -1,62 +0,0 @@ -# Summary - -* [Go Patterns](/README.md) - * [Creational Patterns](/README.md#creational-patterns) - * [Abstract Factory](/creational/abstract_factory.md) - * [Builder](/creational/builder.md) - * [Factory Method](/creational/factory.md) - * [Object Pool](/creational/object-pool.md) - * [Singleton](/creational/singleton.md) - * [Structural Patterns](/README.md#structural-patterns) - * [Bridge](/structural/bridge.md) - * [Composite](/structural/composite.md) - * [Decorator](/structural/decorator.md) - * [Facade](/structural/facade.md) - * [Flyweight](/structural/flyweight.md) - * [Proxy](/structural/proxy.md) - * [Behavioral Patterns](/README.md#behavioral-patterns) - * [Chain of Responsibility](/behavioral/chain_of_responsibility.md) - * [Command](/behavioral/command.md) - * [Mediator](/behavioral/mediator.md) - * [Memento](/behavioral/memento.md) - * [Observer](/behavioral/observer.md) - * [Registry](/behavioral/registry.md) - * [State](/behavioral/state.md) - * [Strategy](/behavioral/strategy.md) - * [Template](/behavioral/template.md) - * [Visitor](/behavioral/visitor.md) - * [Synchronization Patterns](/README.md#synchronization-patterns) - * [Condition Variable](/synchronization/condition_variable.md) - * [Lock/Mutex](/synchronization/mutex.md) - * [Monitor](/synchronization/monitor.md) - * [Read-Write Lock](/synchronization/read_write_lock.md) - * [Semaphore](/synchronization/semaphore.md) - * [Concurrency Patterns](/README.md#concurrency-patterns) - * [N-Barrier](/concurrency/barrier.md) - * [Bounded Parallelism](/concurrency/bounded_parallelism.md) - * [Broadcast](/concurrency/broadcast.md) - * [Coroutines](/concurrency/coroutine.md) - * [Generators](/concurrency/generator.md) - * [Reactor](/concurrency/reactor.md) - * [Parallelism](/concurrency/parallelism.md) - * [Producer Consumer](/concurrency/producer_consumer.md) - * [Messaging Patterns](/README.md#messaging-patterns) - * [Fan-In](/messaging/fan_in.md) - * [Fan-Out](/messaging/fan_out.md) - * [Futures & Promises](/messaging/futures_promises.md) - * [Publish/Subscribe](/messaging/publish_subscribe.md) - * [Push & Pull](/messaging/push_pull.md) - * [Stability Patterns](/README.md#stability-patterns) - * [Bulkheads](/stability/bulkhead.md) - * [Circuit-Breaker](/stability/circuit-breaker.md) - * [Deadline](/stability/deadline.md) - * [Fail-Fast](/stability/fail_fast.md) - * [Handshaking](/stability/handshaking.md) - * [Steady-State](/stability/steady_state.md) - * [Profiling Patterns](/README.md#profiling-patterns) - * [Timing Functions](/profiling/timing.md) - * [Idioms](/README.md#idioms) - * [Functional Options](/idiom/functional-options.md) - * [Anti-Patterns](/README.md#anti-patterns) - * [Cascading Failures](/anti-patterns/cascading_failures.md) -* [Contributing](/CONTRIBUTING.md) diff --git a/behavioral/observer.html b/behavioral/observer.html new file mode 100644 index 0000000..8b42fdb --- /dev/null +++ b/behavioral/observer.html @@ -0,0 +1,1066 @@ + + + + + + + Observer · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Observer Pattern

+

The observer pattern allows a type instance to "publish" events to other type instances ("observers") who wish to be updated when a particular event occurs.

+

Implementation

+

In long-running applications—such as webservers—instances can keep a collection of observers that will receive notification of triggered events.

+

Implementations vary, but interfaces can be used to make standard observers and notifiers:

+
type (
+    // Event defines an indication of a point-in-time occurrence.
+    Event struct {
+        // Data in this case is a simple int, but the actual
+        // implementation would depend on the application.
+        Data int64
+    }
+
+    // Observer defines a standard interface for instances that wish to list for
+    // the occurrence of a specific event.
+    Observer interface {
+        // OnNotify allows an event to be "published" to interface implementations.
+        // In the "real world", error handling would likely be implemented.
+        OnNotify(Event)
+    }
+
+    // Notifier is the instance being observed. Publisher is perhaps another decent
+    // name, but naming things is hard.
+    Notifier interface {
+        // Register allows an instance to register itself to listen/observe
+        // events.
+        Register(Observer)
+        // Deregister allows an instance to remove itself from the collection
+        // of observers/listeners.
+        Deregister(Observer)
+        // Notify publishes new events to listeners. The method is not
+        // absolutely necessary, as each implementation could define this itself
+        // without losing functionality.
+        Notify(Event)
+    }
+)
+
+

Usage

+

For usage, see observer/main.go or view in the Playground.

+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/behavioral/observer.md b/behavioral/observer.md deleted file mode 100644 index c48de84..0000000 --- a/behavioral/observer.md +++ /dev/null @@ -1,47 +0,0 @@ -# Observer Pattern - -The [observer pattern](https://en.wikipedia.org/wiki/Observer_pattern) allows a type instance to "publish" events to other type instances ("observers") who wish to be updated when a particular event occurs. - -## Implementation - -In long-running applications—such as webservers—instances can keep a collection of observers that will receive notification of triggered events. - -Implementations vary, but interfaces can be used to make standard observers and notifiers: - -```go -type ( - // Event defines an indication of a point-in-time occurrence. - Event struct { - // Data in this case is a simple int, but the actual - // implementation would depend on the application. - Data int64 - } - - // Observer defines a standard interface for instances that wish to list for - // the occurrence of a specific event. - Observer interface { - // OnNotify allows an event to be "published" to interface implementations. - // In the "real world", error handling would likely be implemented. - OnNotify(Event) - } - - // Notifier is the instance being observed. Publisher is perhaps another decent - // name, but naming things is hard. - Notifier interface { - // Register allows an instance to register itself to listen/observe - // events. - Register(Observer) - // Deregister allows an instance to remove itself from the collection - // of observers/listeners. - Deregister(Observer) - // Notify publishes new events to listeners. The method is not - // absolutely necessary, as each implementation could define this itself - // without losing functionality. - Notify(Event) - } -) -``` - -## Usage - -For usage, see [observer/main.go](observer/main.go) or [view in the Playground](https://play.golang.org/p/cr8jEmDmw0). diff --git a/behavioral/strategy.html b/behavioral/strategy.html new file mode 100644 index 0000000..f7f9404 --- /dev/null +++ b/behavioral/strategy.html @@ -0,0 +1,1071 @@ + + + + + + + Strategy · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Strategy Pattern

+

Strategy behavioral design pattern enables an algorithm's behavior to be selected at runtime.

+

It defines algorithms, encapsulates them, and uses them interchangeably.

+

Implementation

+

Implementation of an interchangeable operator object that operates on integers.

+
type Operator interface {
+    Apply(int, int) int
+}
+
+type Operation struct {
+    Operator Operator
+}
+
+func (o *Operation) Operate(leftValue, rightValue int) int {
+    return o.Operator.Apply(leftValue, rightValue)
+}
+
+

Usage

+

Addition Operator

+
type Addition struct{}
+
+func (Addition) Apply(lval, rval int) int {
+    return lval + rval
+}
+
+
add := Operation{Addition{}}
+add.Operate(3, 5) // 8
+
+

Multiplication Operator

+
type Multiplication struct{}
+
+func (Multiplication) Apply(lval, rval int) int {
+    return lval * rval
+}
+
+
mult := Operation{Multiplication{}}
+
+mult.Operate(3, 5) // 15
+
+

Rules of Thumb

+
    +
  • Strategy pattern is similar to Template pattern except in its granularity.
  • +
  • Strategy pattern lets you change the guts of an object. Decorator pattern lets you change the skin.
  • +
+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/behavioral/strategy.md b/behavioral/strategy.md deleted file mode 100644 index 3290227..0000000 --- a/behavioral/strategy.md +++ /dev/null @@ -1,55 +0,0 @@ -# Strategy Pattern -Strategy behavioral design pattern enables an algorithm's behavior to be selected at runtime. - -It defines algorithms, encapsulates them, and uses them interchangeably. - -## Implementation -Implementation of an interchangeable operator object that operates on integers. - -```go -type Operator interface { - Apply(int, int) int -} - -type Operation struct { - Operator Operator -} - -func (o *Operation) Operate(leftValue, rightValue int) int { - return o.Operator.Apply(leftValue, rightValue) -} -``` - -## Usage -### Addition Operator -```go -type Addition struct{} - -func (Addition) Apply(lval, rval int) int { - return lval + rval -} -``` - -```go -add := Operation{Addition{}} -add.Operate(3, 5) // 8 -``` - -### Multiplication Operator -```go -type Multiplication struct{} - -func (Multiplication) Apply(lval, rval int) int { - return lval * rval -} -``` - -```go -mult := Operation{Multiplication{}} - -mult.Operate(3, 5) // 15 -``` - -## Rules of Thumb -- Strategy pattern is similar to Template pattern except in its granularity. -- Strategy pattern lets you change the guts of an object. Decorator pattern lets you change the skin. diff --git a/book.json b/book.json deleted file mode 100644 index fa55aa1..0000000 --- a/book.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "plugins": [ - "-search", - "-lunr", - "github", - "edit-link" - ], - "pluginsConfig": { - "github": { - "url": "https://github.com/tmrts/go-patterns" - }, - "edit-link": { - "base": "https://github.com/tmrts/go-patterns/edit/master/", - "label": "" - } - } -} diff --git a/concurrency/bounded_parallelism.html b/concurrency/bounded_parallelism.html new file mode 100644 index 0000000..a7b61e0 --- /dev/null +++ b/concurrency/bounded_parallelism.html @@ -0,0 +1,1031 @@ + + + + + + + Bounded Parallelism · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Bounded Parallelism Pattern

+

Bounded parallelism is similar to parallelism, but allows limits to be placed on allocation.

+

Implementation and Example

+

An example showing implementation and usage can be found in bounded_parallelism.go.

+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/concurrency/bounded_parallelism.md b/concurrency/bounded_parallelism.md deleted file mode 100644 index 8f1429c..0000000 --- a/concurrency/bounded_parallelism.md +++ /dev/null @@ -1,7 +0,0 @@ -# Bounded Parallelism Pattern - -[Bounded parallelism](https://blog.golang.org/pipelines#TOC_9.) is similar to [parallelism](parallelism.md), but allows limits to be placed on allocation. - -# Implementation and Example - -An example showing implementation and usage can be found in [bounded_parallelism.go](bounded_parallelism.go). \ No newline at end of file diff --git a/concurrency/generator.html b/concurrency/generator.html new file mode 100644 index 0000000..a261a15 --- /dev/null +++ b/concurrency/generator.html @@ -0,0 +1,1058 @@ + + + + + + + Generators · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Generator Pattern

+

Generators) yields a sequence of values one at a time.

+

Implementation

+
func Count(start int, end int) chan int {
+    ch := make(chan int)
+
+    go func(ch chan int) {
+        for i := start; i <= end ; i++ {
+            // Blocks on the operation
+            ch <- i
+        }
+
+        close(ch)
+    }(ch)
+
+    return ch
+}
+
+

Usage

+
fmt.Println("No bottles of beer on the wall")
+
+for i := range Count(1, 99) {
+    fmt.Println("Pass it around, put one up,", i, "bottles of beer on the wall")
+    // Pass it around, put one up, 1 bottles of beer on the wall
+    // Pass it around, put one up, 2 bottles of beer on the wall
+    // ...
+    // Pass it around, put one up, 99 bottles of beer on the wall
+}
+
+fmt.Println(100, "bottles of beer on the wall")
+
+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/concurrency/generator.md b/concurrency/generator.md deleted file mode 100644 index e9821b6..0000000 --- a/concurrency/generator.md +++ /dev/null @@ -1,38 +0,0 @@ -# Generator Pattern - -[Generators](https://en.wikipedia.org/wiki/Generator_(computer_programming)) yields a sequence of values one at a time. - -## Implementation - -```go -func Count(start int, end int) chan int { - ch := make(chan int) - - go func(ch chan int) { - for i := start; i <= end ; i++ { - // Blocks on the operation - ch <- i - } - - close(ch) - }(ch) - - return ch -} -``` - -## Usage - -```go -fmt.Println("No bottles of beer on the wall") - -for i := range Count(1, 99) { - fmt.Println("Pass it around, put one up,", i, "bottles of beer on the wall") - // Pass it around, put one up, 1 bottles of beer on the wall - // Pass it around, put one up, 2 bottles of beer on the wall - // ... - // Pass it around, put one up, 99 bottles of beer on the wall -} - -fmt.Println(100, "bottles of beer on the wall") -``` diff --git a/concurrency/parallelism.html b/concurrency/parallelism.html new file mode 100644 index 0000000..ce9cdcb --- /dev/null +++ b/concurrency/parallelism.html @@ -0,0 +1,1031 @@ + + + + + + + Parallelism · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Parallelism Pattern

+

Parallelism allows multiple "jobs" or tasks to be run concurrently and asynchronously.

+

Implementation and Example

+

An example showing implementation and usage can be found in parallelism.go.

+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/concurrency/parallelism.md b/concurrency/parallelism.md deleted file mode 100644 index c9aeab8..0000000 --- a/concurrency/parallelism.md +++ /dev/null @@ -1,7 +0,0 @@ -# Parallelism Pattern - -[Parallelism](https://blog.golang.org/pipelines#TOC_8.) allows multiple "jobs" or tasks to be run concurrently and asynchronously. - -# Implementation and Example - -An example showing implementation and usage can be found in [parallelism.go](parallelism.go). \ No newline at end of file diff --git a/creational/builder.html b/creational/builder.html new file mode 100644 index 0000000..225154b --- /dev/null +++ b/creational/builder.html @@ -0,0 +1,1080 @@ + + + + + + + Builder · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Builder Pattern

+

Builder pattern separates the construction of a complex object from its +representation so that the same construction process can create different +representations.

+

In Go, normally a configuration struct is used to achieve the same behavior, +however passing a struct to the builder method fills the code with boilerplate +if cfg.Field != nil {...} checks.

+

Implementation

+
package car
+
+type Speed float64
+
+const (
+    MPH Speed = 1
+    KPH       = 1.60934
+)
+
+type Color string
+
+const (
+    BlueColor  Color = "blue"
+    GreenColor       = "green"
+    RedColor         = "red"
+)
+
+type Wheels string
+
+const (
+    SportsWheels Wheels = "sports"
+    SteelWheels         = "steel"
+)
+
+type Builder interface {
+    Color(Color) Builder
+    Wheels(Wheels) Builder
+    TopSpeed(Speed) Builder
+    Build() Interface
+}
+
+type Interface interface {
+    Drive() error
+    Stop() error
+}
+
+

Usage

+
assembly := car.NewBuilder().Paint(car.RedColor)
+
+familyCar := assembly.Wheels(car.SportsWheels).TopSpeed(50 * car.MPH).Build()
+familyCar.Drive()
+
+sportsCar := assembly.Wheels(car.SteelWheels).TopSpeed(150 * car.MPH).Build()
+sportsCar.Drive()
+
+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/creational/builder.md b/creational/builder.md deleted file mode 100644 index e19179e..0000000 --- a/creational/builder.md +++ /dev/null @@ -1,61 +0,0 @@ -# Builder Pattern - -Builder pattern separates the construction of a complex object from its -representation so that the same construction process can create different -representations. - -In Go, normally a configuration struct is used to achieve the same behavior, -however passing a struct to the builder method fills the code with boilerplate -`if cfg.Field != nil {...}` checks. - -## Implementation - -```go -package car - -type Speed float64 - -const ( - MPH Speed = 1 - KPH = 1.60934 -) - -type Color string - -const ( - BlueColor Color = "blue" - GreenColor = "green" - RedColor = "red" -) - -type Wheels string - -const ( - SportsWheels Wheels = "sports" - SteelWheels = "steel" -) - -type Builder interface { - Color(Color) Builder - Wheels(Wheels) Builder - TopSpeed(Speed) Builder - Build() Interface -} - -type Interface interface { - Drive() error - Stop() error -} -``` - -## Usage - -```go -assembly := car.NewBuilder().Paint(car.RedColor) - -familyCar := assembly.Wheels(car.SportsWheels).TopSpeed(50 * car.MPH).Build() -familyCar.Drive() - -sportsCar := assembly.Wheels(car.SteelWheels).TopSpeed(150 * car.MPH).Build() -sportsCar.Drive() -``` diff --git a/creational/factory.html b/creational/factory.html new file mode 100644 index 0000000..04ac2ec --- /dev/null +++ b/creational/factory.html @@ -0,0 +1,1072 @@ + + + + + + + Factory Method · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Factory Method Pattern

+

Factory method creational design pattern allows creating objects without having +to specify the exact type of the object that will be created.

+

Implementation

+

The example implementation shows how to provide a data store with different +backends such as in-memory, disk storage.

+

Types

+
package data
+
+import "io"
+
+type Store interface {
+    Open(string) (io.ReadWriteCloser, error)
+}
+
+

Different Implementations

+
package data
+
+type StorageType int
+
+const (
+    DiskStorage StorageType = 1 << iota
+    TempStorage
+    MemoryStorage
+)
+
+func NewStore(t StorageType) Store {
+    switch t {
+    case MemoryStorage:
+        return newMemoryStorage( /*...*/ )
+    case DiskStorage:
+        return newDiskStorage( /*...*/ )
+    default:
+        return newTempStorage( /*...*/ )
+    }
+}
+
+

Usage

+

With the factory method, the user can specify the type of storage they want.

+
s, _ := data.NewStore(data.MemoryStorage)
+f, _ := s.Open("file")
+
+n, _ := f.Write([]byte("data"))
+defer f.Close()
+
+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/creational/factory.md b/creational/factory.md deleted file mode 100644 index 8d80a1f..0000000 --- a/creational/factory.md +++ /dev/null @@ -1,58 +0,0 @@ -# Factory Method Pattern - -Factory method creational design pattern allows creating objects without having -to specify the exact type of the object that will be created. - -## Implementation - -The example implementation shows how to provide a data store with different -backends such as in-memory, disk storage. - -### Types - -```go -package data - -import "io" - -type Store interface { - Open(string) (io.ReadWriteCloser, error) -} -``` - -### Different Implementations - -```go -package data - -type StorageType int - -const ( - DiskStorage StorageType = 1 << iota - TempStorage - MemoryStorage -) - -func NewStore(t StorageType) Store { - switch t { - case MemoryStorage: - return newMemoryStorage( /*...*/ ) - case DiskStorage: - return newDiskStorage( /*...*/ ) - default: - return newTempStorage( /*...*/ ) - } -} -``` - -## Usage - -With the factory method, the user can specify the type of storage they want. - -```go -s, _ := data.NewStore(data.MemoryStorage) -f, _ := s.Open("file") - -n, _ := f.Write([]byte("data")) -defer f.Close() -``` diff --git a/creational/object-pool.html b/creational/object-pool.html new file mode 100644 index 0000000..143d46f --- /dev/null +++ b/creational/object-pool.html @@ -0,0 +1,1067 @@ + + + + + + + Object Pool · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Object Pool Pattern

+

The object pool creational design pattern is used to prepare and keep multiple +instances according to the demand expectation.

+

Implementation

+
package pool
+
+type Pool chan *Object
+
+func New(total int) *Pool {
+    p := make(Pool, total)
+
+    for i := 0; i < total; i++ {
+        p <- new(Object)
+    }
+
+    return &p
+}
+
+

Usage

+

Given below is a simple lifecycle example on an object pool.

+
p := pool.New(2)
+
+select {
+case obj := <-p:
+    obj.Do( /*...*/ )
+
+    p <- obj
+default:
+    // No more objects left — retry later or fail
+    return
+}
+
+

Rules of Thumb

+
    +
  • Object pool pattern is useful in cases where object initialization is more +expensive than the object maintenance.
  • +
  • If there are spikes in demand as opposed to a steady demand, the maintenance +overhead might overweigh the benefits of an object pool.
  • +
  • It has positive effects on performance due to objects being initialized beforehand.
  • +
+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/creational/object-pool.md b/creational/object-pool.md deleted file mode 100644 index c50667d..0000000 --- a/creational/object-pool.md +++ /dev/null @@ -1,48 +0,0 @@ -# Object Pool Pattern - -The object pool creational design pattern is used to prepare and keep multiple -instances according to the demand expectation. - -## Implementation - -```go -package pool - -type Pool chan *Object - -func New(total int) *Pool { - p := make(Pool, total) - - for i := 0; i < total; i++ { - p <- new(Object) - } - - return &p -} -``` - -## Usage - -Given below is a simple lifecycle example on an object pool. - -```go -p := pool.New(2) - -select { -case obj := <-p: - obj.Do( /*...*/ ) - - p <- obj -default: - // No more objects left — retry later or fail - return -} -``` - -## Rules of Thumb - -- Object pool pattern is useful in cases where object initialization is more - expensive than the object maintenance. -- If there are spikes in demand as opposed to a steady demand, the maintenance - overhead might overweigh the benefits of an object pool. -- It has positive effects on performance due to objects being initialized beforehand. diff --git a/creational/singleton.html b/creational/singleton.html new file mode 100644 index 0000000..7fcb9f5 --- /dev/null +++ b/creational/singleton.html @@ -0,0 +1,1062 @@ + + + + + + + Singleton · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Singleton Pattern

+

Singleton creational design pattern restricts the instantiation of a type to a single object.

+

Implementation

+
package singleton
+
+type singleton map[string]string
+
+var (
+    once sync.Once
+
+    instance singleton
+)
+
+func New() singleton {
+    once.Do(func() {
+        instance = make(singleton)
+    })
+
+    return instance
+}
+
+

Usage

+
s := singleton.New()
+
+s["this"] = "that"
+
+s2 := singleton.New()
+
+fmt.Println("This is ", s2["this"])
+// This is that
+
+

Rules of Thumb

+
    +
  • Singleton pattern represents a global state and most of the time reduces testability.
  • +
+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/creational/singleton.md b/creational/singleton.md deleted file mode 100644 index 632cdf8..0000000 --- a/creational/singleton.md +++ /dev/null @@ -1,42 +0,0 @@ -# Singleton Pattern - -Singleton creational design pattern restricts the instantiation of a type to a single object. - -## Implementation - -```go -package singleton - -type singleton map[string]string - -var ( - once sync.Once - - instance singleton -) - -func New() singleton { - once.Do(func() { - instance = make(singleton) - }) - - return instance -} -``` - -## Usage - -```go -s := singleton.New() - -s["this"] = "that" - -s2 := singleton.New() - -fmt.Println("This is ", s2["this"]) -// This is that -``` - -## Rules of Thumb - -- Singleton pattern represents a global state and most of the time reduces testability. diff --git a/gitbook/fonts/fontawesome/FontAwesome.otf b/gitbook/fonts/fontawesome/FontAwesome.otf new file mode 100644 index 0000000..d4de13e Binary files /dev/null and b/gitbook/fonts/fontawesome/FontAwesome.otf differ diff --git a/gitbook/fonts/fontawesome/fontawesome-webfont.eot b/gitbook/fonts/fontawesome/fontawesome-webfont.eot new file mode 100644 index 0000000..c7b00d2 Binary files /dev/null and b/gitbook/fonts/fontawesome/fontawesome-webfont.eot differ diff --git a/gitbook/fonts/fontawesome/fontawesome-webfont.svg b/gitbook/fonts/fontawesome/fontawesome-webfont.svg new file mode 100644 index 0000000..8b66187 --- /dev/null +++ b/gitbook/fonts/fontawesome/fontawesome-webfont.svg @@ -0,0 +1,685 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gitbook/fonts/fontawesome/fontawesome-webfont.ttf b/gitbook/fonts/fontawesome/fontawesome-webfont.ttf new file mode 100644 index 0000000..f221e50 Binary files /dev/null and b/gitbook/fonts/fontawesome/fontawesome-webfont.ttf differ diff --git a/gitbook/fonts/fontawesome/fontawesome-webfont.woff b/gitbook/fonts/fontawesome/fontawesome-webfont.woff new file mode 100644 index 0000000..6e7483c Binary files /dev/null and b/gitbook/fonts/fontawesome/fontawesome-webfont.woff differ diff --git a/gitbook/fonts/fontawesome/fontawesome-webfont.woff2 b/gitbook/fonts/fontawesome/fontawesome-webfont.woff2 new file mode 100644 index 0000000..7eb74fd Binary files /dev/null and b/gitbook/fonts/fontawesome/fontawesome-webfont.woff2 differ diff --git a/gitbook/gitbook-plugin-edit-link/plugin.js b/gitbook/gitbook-plugin-edit-link/plugin.js new file mode 100644 index 0000000..32f3494 --- /dev/null +++ b/gitbook/gitbook-plugin-edit-link/plugin.js @@ -0,0 +1,30 @@ +require(["gitbook", "jQuery"], function(gitbook, $) { + gitbook.events.bind('start', function (e, config) { + var conf = config['edit-link']; + var label = conf.label; + var base = conf.base; + var lang = gitbook.state.innerLanguage; + if (lang) { + // label can be a unique string for multi-languages site + if (typeof label === 'object') label = label[lang]; + + lang = lang + '/'; + } + + // Add slash at the end if not present + if (base.slice(-1) != "/") { + base = base + "/"; + } + + gitbook.toolbar.createButton({ + icon: 'fa fa-edit', + text: label, + onClick: function() { + var filepath = gitbook.state.filepath; + + window.open(base + lang + filepath); + } + }); + }); + +}); \ No newline at end of file diff --git a/gitbook/gitbook-plugin-fontsettings/fontsettings.js b/gitbook/gitbook-plugin-fontsettings/fontsettings.js new file mode 100644 index 0000000..ff7be71 --- /dev/null +++ b/gitbook/gitbook-plugin-fontsettings/fontsettings.js @@ -0,0 +1,240 @@ +require(['gitbook', 'jquery'], function(gitbook, $) { + // Configuration + var MAX_SIZE = 4, + MIN_SIZE = 0, + BUTTON_ID; + + // Current fontsettings state + var fontState; + + // Default themes + var THEMES = [ + { + config: 'white', + text: 'White', + id: 0 + }, + { + config: 'sepia', + text: 'Sepia', + id: 1 + }, + { + config: 'night', + text: 'Night', + id: 2 + } + ]; + + // Default font families + var FAMILIES = [ + { + config: 'serif', + text: 'Serif', + id: 0 + }, + { + config: 'sans', + text: 'Sans', + id: 1 + } + ]; + + // Return configured themes + function getThemes() { + return THEMES; + } + + // Modify configured themes + function setThemes(themes) { + THEMES = themes; + updateButtons(); + } + + // Return configured font families + function getFamilies() { + return FAMILIES; + } + + // Modify configured font families + function setFamilies(families) { + FAMILIES = families; + updateButtons(); + } + + // Save current font settings + function saveFontSettings() { + gitbook.storage.set('fontState', fontState); + update(); + } + + // Increase font size + function enlargeFontSize(e) { + e.preventDefault(); + if (fontState.size >= MAX_SIZE) return; + + fontState.size++; + saveFontSettings(); + } + + // Decrease font size + function reduceFontSize(e) { + e.preventDefault(); + if (fontState.size <= MIN_SIZE) return; + + fontState.size--; + saveFontSettings(); + } + + // Change font family + function changeFontFamily(configName, e) { + if (e && e instanceof Event) { + e.preventDefault(); + } + + var familyId = getFontFamilyId(configName); + fontState.family = familyId; + saveFontSettings(); + } + + // Change type of color theme + function changeColorTheme(configName, e) { + if (e && e instanceof Event) { + e.preventDefault(); + } + + var $book = gitbook.state.$book; + + // Remove currently applied color theme + if (fontState.theme !== 0) + $book.removeClass('color-theme-'+fontState.theme); + + // Set new color theme + var themeId = getThemeId(configName); + fontState.theme = themeId; + if (fontState.theme !== 0) + $book.addClass('color-theme-'+fontState.theme); + + saveFontSettings(); + } + + // Return the correct id for a font-family config key + // Default to first font-family + function getFontFamilyId(configName) { + // Search for plugin configured font family + var configFamily = $.grep(FAMILIES, function(family) { + return family.config == configName; + })[0]; + // Fallback to default font family + return (!!configFamily)? configFamily.id : 0; + } + + // Return the correct id for a theme config key + // Default to first theme + function getThemeId(configName) { + // Search for plugin configured theme + var configTheme = $.grep(THEMES, function(theme) { + return theme.config == configName; + })[0]; + // Fallback to default theme + return (!!configTheme)? configTheme.id : 0; + } + + function update() { + var $book = gitbook.state.$book; + + $('.font-settings .font-family-list li').removeClass('active'); + $('.font-settings .font-family-list li:nth-child('+(fontState.family+1)+')').addClass('active'); + + $book[0].className = $book[0].className.replace(/\bfont-\S+/g, ''); + $book.addClass('font-size-'+fontState.size); + $book.addClass('font-family-'+fontState.family); + + if(fontState.theme !== 0) { + $book[0].className = $book[0].className.replace(/\bcolor-theme-\S+/g, ''); + $book.addClass('color-theme-'+fontState.theme); + } + } + + function init(config) { + // Search for plugin configured font family + var configFamily = getFontFamilyId(config.family), + configTheme = getThemeId(config.theme); + + // Instantiate font state object + fontState = gitbook.storage.get('fontState', { + size: config.size || 2, + family: configFamily, + theme: configTheme + }); + + update(); + } + + function updateButtons() { + // Remove existing fontsettings buttons + if (!!BUTTON_ID) { + gitbook.toolbar.removeButton(BUTTON_ID); + } + + // Create buttons in toolbar + BUTTON_ID = gitbook.toolbar.createButton({ + icon: 'fa fa-font', + label: 'Font Settings', + className: 'font-settings', + dropdown: [ + [ + { + text: 'A', + className: 'font-reduce', + onClick: reduceFontSize + }, + { + text: 'A', + className: 'font-enlarge', + onClick: enlargeFontSize + } + ], + $.map(FAMILIES, function(family) { + family.onClick = function(e) { + return changeFontFamily(family.config, e); + }; + + return family; + }), + $.map(THEMES, function(theme) { + theme.onClick = function(e) { + return changeColorTheme(theme.config, e); + }; + + return theme; + }) + ] + }); + } + + // Init configuration at start + gitbook.events.bind('start', function(e, config) { + var opts = config.fontsettings; + + // Generate buttons at start + updateButtons(); + + // Init current settings + init(opts); + }); + + // Expose API + gitbook.fontsettings = { + enlargeFontSize: enlargeFontSize, + reduceFontSize: reduceFontSize, + setTheme: changeColorTheme, + setFamily: changeFontFamily, + getThemes: getThemes, + setThemes: setThemes, + getFamilies: getFamilies, + setFamilies: setFamilies + }; +}); + + diff --git a/gitbook/gitbook-plugin-fontsettings/website.css b/gitbook/gitbook-plugin-fontsettings/website.css new file mode 100644 index 0000000..26591fe --- /dev/null +++ b/gitbook/gitbook-plugin-fontsettings/website.css @@ -0,0 +1,291 @@ +/* + * Theme 1 + */ +.color-theme-1 .dropdown-menu { + background-color: #111111; + border-color: #7e888b; +} +.color-theme-1 .dropdown-menu .dropdown-caret .caret-inner { + border-bottom: 9px solid #111111; +} +.color-theme-1 .dropdown-menu .buttons { + border-color: #7e888b; +} +.color-theme-1 .dropdown-menu .button { + color: #afa790; +} +.color-theme-1 .dropdown-menu .button:hover { + color: #73553c; +} +/* + * Theme 2 + */ +.color-theme-2 .dropdown-menu { + background-color: #2d3143; + border-color: #272a3a; +} +.color-theme-2 .dropdown-menu .dropdown-caret .caret-inner { + border-bottom: 9px solid #2d3143; +} +.color-theme-2 .dropdown-menu .buttons { + border-color: #272a3a; +} +.color-theme-2 .dropdown-menu .button { + color: #62677f; +} +.color-theme-2 .dropdown-menu .button:hover { + color: #f4f4f5; +} +.book .book-header .font-settings .font-enlarge { + line-height: 30px; + font-size: 1.4em; +} +.book .book-header .font-settings .font-reduce { + line-height: 30px; + font-size: 1em; +} +.book.color-theme-1 .book-body { + color: #704214; + background: #f3eacb; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section { + background: #f3eacb; +} +.book.color-theme-2 .book-body { + color: #bdcadb; + background: #1c1f2b; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section { + background: #1c1f2b; +} +.book.font-size-0 .book-body .page-inner section { + font-size: 1.2rem; +} +.book.font-size-1 .book-body .page-inner section { + font-size: 1.4rem; +} +.book.font-size-2 .book-body .page-inner section { + font-size: 1.6rem; +} +.book.font-size-3 .book-body .page-inner section { + font-size: 2.2rem; +} +.book.font-size-4 .book-body .page-inner section { + font-size: 4rem; +} +.book.font-family-0 { + font-family: Georgia, serif; +} +.book.font-family-1 { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal { + color: #704214; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal a { + color: inherit; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h1, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h2, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h3, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h4, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h5, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h6 { + color: inherit; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h1, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h2 { + border-color: inherit; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h6 { + color: inherit; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal hr { + background-color: inherit; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal blockquote { + border-color: inherit; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code { + background: #fdf6e3; + color: #657b83; + border-color: #f8df9c; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal .highlight { + background-color: inherit; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table th, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table td { + border-color: #f5d06c; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table tr { + color: inherit; + background-color: #fdf6e3; + border-color: #444444; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table tr:nth-child(2n) { + background-color: #fbeecb; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal { + color: #bdcadb; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal a { + color: #3eb1d0; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h1, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h2, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h3, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h4, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h5, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h6 { + color: #fffffa; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h1, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h2 { + border-color: #373b4e; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h6 { + color: #373b4e; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal hr { + background-color: #373b4e; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal blockquote { + border-color: #373b4e; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code { + color: #9dbed8; + background: #2d3143; + border-color: #2d3143; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal .highlight { + background-color: #282a39; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table th, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table td { + border-color: #3b3f54; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table tr { + color: #b6c2d2; + background-color: #2d3143; + border-color: #3b3f54; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table tr:nth-child(2n) { + background-color: #35394b; +} +.book.color-theme-1 .book-header { + color: #afa790; + background: transparent; +} +.book.color-theme-1 .book-header .btn { + color: #afa790; +} +.book.color-theme-1 .book-header .btn:hover { + color: #73553c; + background: none; +} +.book.color-theme-1 .book-header h1 { + color: #704214; +} +.book.color-theme-2 .book-header { + color: #7e888b; + background: transparent; +} +.book.color-theme-2 .book-header .btn { + color: #3b3f54; +} +.book.color-theme-2 .book-header .btn:hover { + color: #fffff5; + background: none; +} +.book.color-theme-2 .book-header h1 { + color: #bdcadb; +} +.book.color-theme-1 .book-body .navigation { + color: #afa790; +} +.book.color-theme-1 .book-body .navigation:hover { + color: #73553c; +} +.book.color-theme-2 .book-body .navigation { + color: #383f52; +} +.book.color-theme-2 .book-body .navigation:hover { + color: #fffff5; +} +/* + * Theme 1 + */ +.book.color-theme-1 .book-summary { + color: #afa790; + background: #111111; + border-right: 1px solid rgba(0, 0, 0, 0.07); +} +.book.color-theme-1 .book-summary .book-search { + background: transparent; +} +.book.color-theme-1 .book-summary .book-search input, +.book.color-theme-1 .book-summary .book-search input:focus { + border: 1px solid transparent; +} +.book.color-theme-1 .book-summary ul.summary li.divider { + background: #7e888b; + box-shadow: none; +} +.book.color-theme-1 .book-summary ul.summary li i.fa-check { + color: #33cc33; +} +.book.color-theme-1 .book-summary ul.summary li.done > a { + color: #877f6a; +} +.book.color-theme-1 .book-summary ul.summary li a, +.book.color-theme-1 .book-summary ul.summary li span { + color: #877f6a; + background: transparent; + font-weight: normal; +} +.book.color-theme-1 .book-summary ul.summary li.active > a, +.book.color-theme-1 .book-summary ul.summary li a:hover { + color: #704214; + background: transparent; + font-weight: normal; +} +/* + * Theme 2 + */ +.book.color-theme-2 .book-summary { + color: #bcc1d2; + background: #2d3143; + border-right: none; +} +.book.color-theme-2 .book-summary .book-search { + background: transparent; +} +.book.color-theme-2 .book-summary .book-search input, +.book.color-theme-2 .book-summary .book-search input:focus { + border: 1px solid transparent; +} +.book.color-theme-2 .book-summary ul.summary li.divider { + background: #272a3a; + box-shadow: none; +} +.book.color-theme-2 .book-summary ul.summary li i.fa-check { + color: #33cc33; +} +.book.color-theme-2 .book-summary ul.summary li.done > a { + color: #62687f; +} +.book.color-theme-2 .book-summary ul.summary li a, +.book.color-theme-2 .book-summary ul.summary li span { + color: #c1c6d7; + background: transparent; + font-weight: 600; +} +.book.color-theme-2 .book-summary ul.summary li.active > a, +.book.color-theme-2 .book-summary ul.summary li a:hover { + color: #f4f4f5; + background: #252737; + font-weight: 600; +} diff --git a/gitbook/gitbook-plugin-github/plugin.js b/gitbook/gitbook-plugin-github/plugin.js new file mode 100644 index 0000000..14810ce --- /dev/null +++ b/gitbook/gitbook-plugin-github/plugin.js @@ -0,0 +1,14 @@ +require([ 'gitbook' ], function (gitbook) { + gitbook.events.bind('start', function (e, config) { + var githubURL = config.github.url; + + gitbook.toolbar.createButton({ + icon: 'fa fa-github', + label: 'GitHub', + position: 'right', + onClick: function() { + window.open(githubURL) + } + }); + }); +}); diff --git a/gitbook/gitbook-plugin-highlight/ebook.css b/gitbook/gitbook-plugin-highlight/ebook.css new file mode 100644 index 0000000..cecaaab --- /dev/null +++ b/gitbook/gitbook-plugin-highlight/ebook.css @@ -0,0 +1,135 @@ +pre, +code { + /* http://jmblog.github.io/color-themes-for-highlightjs */ + /* Tomorrow Comment */ + /* Tomorrow Red */ + /* Tomorrow Orange */ + /* Tomorrow Yellow */ + /* Tomorrow Green */ + /* Tomorrow Aqua */ + /* Tomorrow Blue */ + /* Tomorrow Purple */ +} +pre .hljs-comment, +code .hljs-comment, +pre .hljs-title, +code .hljs-title { + color: #8e908c; +} +pre .hljs-variable, +code .hljs-variable, +pre .hljs-attribute, +code .hljs-attribute, +pre .hljs-tag, +code .hljs-tag, +pre .hljs-regexp, +code .hljs-regexp, +pre .hljs-deletion, +code .hljs-deletion, +pre .ruby .hljs-constant, +code .ruby .hljs-constant, +pre .xml .hljs-tag .hljs-title, +code .xml .hljs-tag .hljs-title, +pre .xml .hljs-pi, +code .xml .hljs-pi, +pre .xml .hljs-doctype, +code .xml .hljs-doctype, +pre .html .hljs-doctype, +code .html .hljs-doctype, +pre .css .hljs-id, +code .css .hljs-id, +pre .css .hljs-class, +code .css .hljs-class, +pre .css .hljs-pseudo, +code .css .hljs-pseudo { + color: #c82829; +} +pre .hljs-number, +code .hljs-number, +pre .hljs-preprocessor, +code .hljs-preprocessor, +pre .hljs-pragma, +code .hljs-pragma, +pre .hljs-built_in, +code .hljs-built_in, +pre .hljs-literal, +code .hljs-literal, +pre .hljs-params, +code .hljs-params, +pre .hljs-constant, +code .hljs-constant { + color: #f5871f; +} +pre .ruby .hljs-class .hljs-title, +code .ruby .hljs-class .hljs-title, +pre .css .hljs-rules .hljs-attribute, +code .css .hljs-rules .hljs-attribute { + color: #eab700; +} +pre .hljs-string, +code .hljs-string, +pre .hljs-value, +code .hljs-value, +pre .hljs-inheritance, +code .hljs-inheritance, +pre .hljs-header, +code .hljs-header, +pre .hljs-addition, +code .hljs-addition, +pre .ruby .hljs-symbol, +code .ruby .hljs-symbol, +pre .xml .hljs-cdata, +code .xml .hljs-cdata { + color: #718c00; +} +pre .css .hljs-hexcolor, +code .css .hljs-hexcolor { + color: #3e999f; +} +pre .hljs-function, +code .hljs-function, +pre .python .hljs-decorator, +code .python .hljs-decorator, +pre .python .hljs-title, +code .python .hljs-title, +pre .ruby .hljs-function .hljs-title, +code .ruby .hljs-function .hljs-title, +pre .ruby .hljs-title .hljs-keyword, +code .ruby .hljs-title .hljs-keyword, +pre .perl .hljs-sub, +code .perl .hljs-sub, +pre .javascript .hljs-title, +code .javascript .hljs-title, +pre .coffeescript .hljs-title, +code .coffeescript .hljs-title { + color: #4271ae; +} +pre .hljs-keyword, +code .hljs-keyword, +pre .javascript .hljs-function, +code .javascript .hljs-function { + color: #8959a8; +} +pre .hljs, +code .hljs { + display: block; + background: white; + color: #4d4d4c; + padding: 0.5em; +} +pre .coffeescript .javascript, +code .coffeescript .javascript, +pre .javascript .xml, +code .javascript .xml, +pre .tex .hljs-formula, +code .tex .hljs-formula, +pre .xml .javascript, +code .xml .javascript, +pre .xml .vbscript, +code .xml .vbscript, +pre .xml .css, +code .xml .css, +pre .xml .hljs-cdata, +code .xml .hljs-cdata { + opacity: 0.5; +} diff --git a/gitbook/gitbook-plugin-highlight/website.css b/gitbook/gitbook-plugin-highlight/website.css new file mode 100644 index 0000000..6674448 --- /dev/null +++ b/gitbook/gitbook-plugin-highlight/website.css @@ -0,0 +1,434 @@ +.book .book-body .page-wrapper .page-inner section.normal pre, +.book .book-body .page-wrapper .page-inner section.normal code { + /* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ + /* Tomorrow Comment */ + /* Tomorrow Red */ + /* Tomorrow Orange */ + /* Tomorrow Yellow */ + /* Tomorrow Green */ + /* Tomorrow Aqua */ + /* Tomorrow Blue */ + /* Tomorrow Purple */ +} +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-comment, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-comment, +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-title, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-title { + color: #8e908c; +} +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-variable, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-variable, +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-attribute, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-attribute, +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-tag, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-tag, +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-regexp, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-regexp, +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-deletion, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-deletion, +.book .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-constant, +.book .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-constant, +.book .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-tag .hljs-title, +.book .book-body .page-wrapper .page-inner section.normal code .xml .hljs-tag .hljs-title, +.book .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-pi, +.book .book-body .page-wrapper .page-inner section.normal code .xml .hljs-pi, +.book .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-doctype, +.book .book-body .page-wrapper .page-inner section.normal code .xml .hljs-doctype, +.book .book-body .page-wrapper .page-inner section.normal pre .html .hljs-doctype, +.book .book-body .page-wrapper .page-inner section.normal code .html .hljs-doctype, +.book .book-body .page-wrapper .page-inner section.normal pre .css .hljs-id, +.book .book-body .page-wrapper .page-inner section.normal code .css .hljs-id, +.book .book-body .page-wrapper .page-inner section.normal pre .css .hljs-class, +.book .book-body .page-wrapper .page-inner section.normal code .css .hljs-class, +.book .book-body .page-wrapper .page-inner section.normal pre .css .hljs-pseudo, +.book .book-body .page-wrapper .page-inner section.normal code .css .hljs-pseudo { + color: #c82829; +} +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-number, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-number, +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-preprocessor, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-preprocessor, +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-pragma, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-pragma, +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-built_in, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-built_in, +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-literal, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-literal, +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-params, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-params, +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-constant, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-constant { + color: #f5871f; +} +.book .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-class .hljs-title, +.book .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-class .hljs-title, +.book .book-body .page-wrapper .page-inner section.normal pre .css .hljs-rules .hljs-attribute, +.book .book-body .page-wrapper .page-inner section.normal code .css .hljs-rules .hljs-attribute { + color: #eab700; +} +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-string, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-string, +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-value, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-value, +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-inheritance, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-inheritance, +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-header, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-header, +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-addition, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-addition, +.book .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-symbol, +.book .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-symbol, +.book .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-cdata, +.book .book-body .page-wrapper .page-inner section.normal code .xml .hljs-cdata { + color: #718c00; +} +.book .book-body .page-wrapper .page-inner section.normal pre .css .hljs-hexcolor, +.book .book-body .page-wrapper .page-inner section.normal code .css .hljs-hexcolor { + color: #3e999f; +} +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-function, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-function, +.book .book-body .page-wrapper .page-inner section.normal pre .python .hljs-decorator, +.book .book-body .page-wrapper .page-inner section.normal code .python .hljs-decorator, +.book .book-body .page-wrapper .page-inner section.normal pre .python .hljs-title, +.book .book-body .page-wrapper .page-inner section.normal code .python .hljs-title, +.book .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-function .hljs-title, +.book .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-function .hljs-title, +.book .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-title .hljs-keyword, +.book .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-title .hljs-keyword, +.book .book-body .page-wrapper .page-inner section.normal pre .perl .hljs-sub, +.book .book-body .page-wrapper .page-inner section.normal code .perl .hljs-sub, +.book .book-body .page-wrapper .page-inner section.normal pre .javascript .hljs-title, +.book .book-body .page-wrapper .page-inner section.normal code .javascript .hljs-title, +.book .book-body .page-wrapper .page-inner section.normal pre .coffeescript .hljs-title, +.book .book-body .page-wrapper .page-inner section.normal code .coffeescript .hljs-title { + color: #4271ae; +} +.book .book-body .page-wrapper .page-inner section.normal pre .hljs-keyword, +.book .book-body .page-wrapper .page-inner section.normal code .hljs-keyword, +.book .book-body .page-wrapper .page-inner section.normal pre .javascript .hljs-function, +.book .book-body .page-wrapper .page-inner section.normal code .javascript .hljs-function { + color: #8959a8; +} +.book .book-body .page-wrapper .page-inner section.normal pre .hljs, +.book .book-body .page-wrapper .page-inner section.normal code .hljs { + display: block; + background: white; + color: #4d4d4c; + padding: 0.5em; +} +.book .book-body .page-wrapper .page-inner section.normal pre .coffeescript .javascript, +.book .book-body .page-wrapper .page-inner section.normal code .coffeescript .javascript, +.book .book-body .page-wrapper .page-inner section.normal pre .javascript .xml, +.book .book-body .page-wrapper .page-inner section.normal code .javascript .xml, +.book .book-body .page-wrapper .page-inner section.normal pre .tex .hljs-formula, +.book .book-body .page-wrapper .page-inner section.normal code .tex .hljs-formula, +.book .book-body .page-wrapper .page-inner section.normal pre .xml .javascript, +.book .book-body .page-wrapper .page-inner section.normal code .xml .javascript, +.book .book-body .page-wrapper .page-inner section.normal pre .xml .vbscript, +.book .book-body .page-wrapper .page-inner section.normal code .xml .vbscript, +.book .book-body .page-wrapper .page-inner section.normal pre .xml .css, +.book .book-body .page-wrapper .page-inner section.normal code .xml .css, +.book .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-cdata, +.book .book-body .page-wrapper .page-inner section.normal code .xml .hljs-cdata { + opacity: 0.5; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code { + /* + +Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull + +*/ + /* Solarized Green */ + /* Solarized Cyan */ + /* Solarized Blue */ + /* Solarized Yellow */ + /* Solarized Orange */ + /* Solarized Red */ + /* Solarized Violet */ +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs { + display: block; + padding: 0.5em; + background: #fdf6e3; + color: #657b83; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-comment, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-comment, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-template_comment, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-template_comment, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .diff .hljs-header, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .diff .hljs-header, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-doctype, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-doctype, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-pi, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-pi, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .lisp .hljs-string, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .lisp .hljs-string, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-javadoc, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-javadoc { + color: #93a1a1; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-keyword, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-keyword, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-winutils, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-winutils, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .method, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .method, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-addition, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-addition, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-tag, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .css .hljs-tag, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-request, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-request, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-status, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-status, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .nginx .hljs-title, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .nginx .hljs-title { + color: #859900; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-number, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-number, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-command, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-command, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-string, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-string, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-tag .hljs-value, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-tag .hljs-value, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-rules .hljs-value, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-rules .hljs-value, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-phpdoc, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-phpdoc, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .tex .hljs-formula, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .tex .hljs-formula, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-regexp, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-regexp, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-hexcolor, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-hexcolor, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-link_url, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-link_url { + color: #2aa198; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-title, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-title, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-localvars, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-localvars, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-chunk, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-chunk, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-decorator, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-decorator, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-built_in, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-built_in, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-identifier, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-identifier, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .vhdl .hljs-literal, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .vhdl .hljs-literal, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-id, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-id, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-function, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .css .hljs-function { + color: #268bd2; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-attribute, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-attribute, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-variable, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-variable, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .lisp .hljs-body, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .lisp .hljs-body, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .smalltalk .hljs-number, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .smalltalk .hljs-number, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-constant, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-constant, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-class .hljs-title, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-class .hljs-title, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-parent, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-parent, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .haskell .hljs-type, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .haskell .hljs-type, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-link_reference, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-link_reference { + color: #b58900; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-preprocessor, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-preprocessor, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-preprocessor .hljs-keyword, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-preprocessor .hljs-keyword, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-pragma, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-pragma, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-shebang, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-shebang, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-symbol, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-symbol, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-symbol .hljs-string, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-symbol .hljs-string, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .diff .hljs-change, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .diff .hljs-change, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-special, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-special, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-attr_selector, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-attr_selector, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-subst, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-subst, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-cdata, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-cdata, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .clojure .hljs-title, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .clojure .hljs-title, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-pseudo, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .css .hljs-pseudo, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-header, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-header { + color: #cb4b16; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-deletion, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-deletion, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-important, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-important { + color: #dc322f; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-link_label, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-link_label { + color: #6c71c4; +} +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .tex .hljs-formula, +.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .tex .hljs-formula { + background: #eee8d5; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code { + /* Tomorrow Night Bright Theme */ + /* Original theme - https://github.com/chriskempson/tomorrow-theme */ + /* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ + /* Tomorrow Comment */ + /* Tomorrow Red */ + /* Tomorrow Orange */ + /* Tomorrow Yellow */ + /* Tomorrow Green */ + /* Tomorrow Aqua */ + /* Tomorrow Blue */ + /* Tomorrow Purple */ +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-comment, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-comment, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-title, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-title { + color: #969896; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-variable, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-variable, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-attribute, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-attribute, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-tag, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-tag, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-regexp, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-regexp, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-deletion, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-deletion, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-constant, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-constant, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-tag .hljs-title, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .hljs-tag .hljs-title, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-pi, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .hljs-pi, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-doctype, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .hljs-doctype, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .html .hljs-doctype, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .html .hljs-doctype, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-id, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .css .hljs-id, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-class, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .css .hljs-class, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-pseudo, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .css .hljs-pseudo { + color: #d54e53; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-number, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-number, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-preprocessor, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-preprocessor, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-pragma, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-pragma, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-built_in, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-built_in, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-literal, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-literal, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-params, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-params, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-constant, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-constant { + color: #e78c45; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-class .hljs-title, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-class .hljs-title, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-rules .hljs-attribute, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .css .hljs-rules .hljs-attribute { + color: #e7c547; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-string, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-string, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-value, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-value, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-inheritance, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-inheritance, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-header, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-header, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-addition, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-addition, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-symbol, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-symbol, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-cdata, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .hljs-cdata { + color: #b9ca4a; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-hexcolor, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .css .hljs-hexcolor { + color: #70c0b1; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-function, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-function, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .python .hljs-decorator, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .python .hljs-decorator, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .python .hljs-title, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .python .hljs-title, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-function .hljs-title, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-function .hljs-title, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-title .hljs-keyword, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-title .hljs-keyword, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .perl .hljs-sub, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .perl .hljs-sub, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .javascript .hljs-title, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .javascript .hljs-title, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .coffeescript .hljs-title, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .coffeescript .hljs-title { + color: #7aa6da; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-keyword, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-keyword, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .javascript .hljs-function, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .javascript .hljs-function { + color: #c397d8; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs { + display: block; + background: black; + color: #eaeaea; + padding: 0.5em; +} +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .coffeescript .javascript, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .coffeescript .javascript, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .javascript .xml, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .javascript .xml, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .tex .hljs-formula, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .tex .hljs-formula, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .javascript, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .javascript, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .vbscript, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .vbscript, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .css, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .css, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-cdata, +.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .hljs-cdata { + opacity: 0.5; +} diff --git a/gitbook/gitbook-plugin-sharing/buttons.js b/gitbook/gitbook-plugin-sharing/buttons.js new file mode 100644 index 0000000..709a4e4 --- /dev/null +++ b/gitbook/gitbook-plugin-sharing/buttons.js @@ -0,0 +1,90 @@ +require(['gitbook', 'jquery'], function(gitbook, $) { + var SITES = { + 'facebook': { + 'label': 'Facebook', + 'icon': 'fa fa-facebook', + 'onClick': function(e) { + e.preventDefault(); + window.open('http://www.facebook.com/sharer/sharer.php?s=100&p[url]='+encodeURIComponent(location.href)); + } + }, + 'twitter': { + 'label': 'Twitter', + 'icon': 'fa fa-twitter', + 'onClick': function(e) { + e.preventDefault(); + window.open('http://twitter.com/home?status='+encodeURIComponent(document.title+' '+location.href)); + } + }, + 'google': { + 'label': 'Google+', + 'icon': 'fa fa-google-plus', + 'onClick': function(e) { + e.preventDefault(); + window.open('https://plus.google.com/share?url='+encodeURIComponent(location.href)); + } + }, + 'weibo': { + 'label': 'Weibo', + 'icon': 'fa fa-weibo', + 'onClick': function(e) { + e.preventDefault(); + window.open('http://service.weibo.com/share/share.php?content=utf-8&url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title)); + } + }, + 'instapaper': { + 'label': 'Instapaper', + 'icon': 'fa fa-instapaper', + 'onClick': function(e) { + e.preventDefault(); + window.open('http://www.instapaper.com/text?u='+encodeURIComponent(location.href)); + } + }, + 'vk': { + 'label': 'VK', + 'icon': 'fa fa-vk', + 'onClick': function(e) { + e.preventDefault(); + window.open('http://vkontakte.ru/share.php?url='+encodeURIComponent(location.href)); + } + } + }; + + + + gitbook.events.bind('start', function(e, config) { + var opts = config.sharing; + + // Create dropdown menu + var menu = $.map(opts.all, function(id) { + var site = SITES[id]; + + return { + text: site.label, + onClick: site.onClick + }; + }); + + // Create main button with dropdown + if (menu.length > 0) { + gitbook.toolbar.createButton({ + icon: 'fa fa-share-alt', + label: 'Share', + position: 'right', + dropdown: [menu] + }); + } + + // Direct actions to share + $.each(SITES, function(sideId, site) { + if (!opts[sideId]) return; + + gitbook.toolbar.createButton({ + icon: site.icon, + label: site.text, + position: 'right', + onClick: site.onClick + }); + }); + }); +}); diff --git a/gitbook/gitbook.js b/gitbook/gitbook.js new file mode 100644 index 0000000..10000c7 --- /dev/null +++ b/gitbook/gitbook.js @@ -0,0 +1,4 @@ +!function e(t,n,r){function o(s,a){if(!n[s]){if(!t[s]){var u="function"==typeof require&&require;if(!a&&u)return u(s,!0);if(i)return i(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[s]={exports:{}};t[s][0].call(l.exports,function(e){var n=t[s][1][e];return o(n?n:e)},l,l.exports,e,t,n,r)}return n[s].exports}for(var i="function"==typeof require&&require,s=0;s0&&t-1 in e)}function o(e,t,n){return de.isFunction(t)?de.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?de.grep(e,function(e){return e===t!==n}):"string"!=typeof t?de.grep(e,function(e){return se.call(t,e)>-1!==n}):je.test(t)?de.filter(t,e,n):(t=de.filter(t,e),de.grep(e,function(e){return se.call(t,e)>-1!==n&&1===e.nodeType}))}function i(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}function s(e){var t={};return de.each(e.match(qe)||[],function(e,n){t[n]=!0}),t}function a(e){return e}function u(e){throw e}function c(e,t,n){var r;try{e&&de.isFunction(r=e.promise)?r.call(e).done(t).fail(n):e&&de.isFunction(r=e.then)?r.call(e,t,n):t.call(void 0,e)}catch(e){n.call(void 0,e)}}function l(){te.removeEventListener("DOMContentLoaded",l),e.removeEventListener("load",l),de.ready()}function f(){this.expando=de.expando+f.uid++}function p(e){return"true"===e||"false"!==e&&("null"===e?null:e===+e+""?+e:Ie.test(e)?JSON.parse(e):e)}function h(e,t,n){var r;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(Pe,"-$&").toLowerCase(),n=e.getAttribute(r),"string"==typeof n){try{n=p(n)}catch(e){}Re.set(e,t,n)}else n=void 0;return n}function d(e,t,n,r){var o,i=1,s=20,a=r?function(){return r.cur()}:function(){return de.css(e,t,"")},u=a(),c=n&&n[3]||(de.cssNumber[t]?"":"px"),l=(de.cssNumber[t]||"px"!==c&&+u)&&$e.exec(de.css(e,t));if(l&&l[3]!==c){c=c||l[3],n=n||[],l=+u||1;do i=i||".5",l/=i,de.style(e,t,l+c);while(i!==(i=a()/u)&&1!==i&&--s)}return n&&(l=+l||+u||0,o=n[1]?l+(n[1]+1)*n[2]:+n[2],r&&(r.unit=c,r.start=l,r.end=o)),o}function g(e){var t,n=e.ownerDocument,r=e.nodeName,o=Ue[r];return o?o:(t=n.body.appendChild(n.createElement(r)),o=de.css(t,"display"),t.parentNode.removeChild(t),"none"===o&&(o="block"),Ue[r]=o,o)}function m(e,t){for(var n,r,o=[],i=0,s=e.length;i-1)o&&o.push(i);else if(c=de.contains(i.ownerDocument,i),s=v(f.appendChild(i),"script"),c&&y(s),n)for(l=0;i=s[l++];)Ve.test(i.type||"")&&n.push(i);return f}function b(){return!0}function w(){return!1}function T(){try{return te.activeElement}catch(e){}}function C(e,t,n,r,o,i){var s,a;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(a in t)C(e,a,n,r,t[a],i);return e}if(null==r&&null==o?(o=n,r=n=void 0):null==o&&("string"==typeof n?(o=r,r=void 0):(o=r,r=n,n=void 0)),o===!1)o=w;else if(!o)return e;return 1===i&&(s=o,o=function(e){return de().off(e),s.apply(this,arguments)},o.guid=s.guid||(s.guid=de.guid++)),e.each(function(){de.event.add(this,t,o,r,n)})}function j(e,t){return de.nodeName(e,"table")&&de.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e:e}function k(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function E(e){var t=rt.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function S(e,t){var n,r,o,i,s,a,u,c;if(1===t.nodeType){if(Fe.hasData(e)&&(i=Fe.access(e),s=Fe.set(t,i),c=i.events)){delete s.handle,s.events={};for(o in c)for(n=0,r=c[o].length;n1&&"string"==typeof d&&!pe.checkClone&&nt.test(d))return e.each(function(n){var i=e.eq(n);g&&(t[0]=d.call(this,n,i.html())),A(i,t,r,o)});if(p&&(i=x(t,e[0].ownerDocument,!1,e,o),s=i.firstChild,1===i.childNodes.length&&(i=s),s||o)){for(a=de.map(v(i,"script"),k),u=a.length;f=0&&nC.cacheLength&&delete e[t.shift()],e[n+" "]=r}var t=[];return e}function r(e){return e[$]=!0,e}function o(e){var t=L.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function i(e,t){for(var n=e.split("|"),r=n.length;r--;)C.attrHandle[n[r]]=t}function s(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function a(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function u(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function c(e){return function(t){return"form"in t?t.parentNode&&t.disabled===!1?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&je(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function l(e){return r(function(t){return t=+t,r(function(n,r){for(var o,i=e([],n.length,t),s=i.length;s--;)n[o=i[s]]&&(n[o]=!(r[o]=n[o]))})})}function f(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function p(){}function h(e){for(var t=0,n=e.length,r="";t1?function(t,n,r){for(var o=e.length;o--;)if(!e[o](t,n,r))return!1;return!0}:e[0]}function m(e,n,r){for(var o=0,i=n.length;o-1&&(r[c]=!(s[c]=f))}}else x=v(x===s?x.splice(d,x.length):x),i?i(null,s,x,u):K.apply(s,x)})}function x(e){for(var t,n,r,o=e.length,i=C.relative[e[0].type],s=i||C.relative[" "],a=i?1:0,u=d(function(e){return e===t},s,!0),c=d(function(e){return ee(t,e)>-1},s,!0),l=[function(e,n,r){var o=!i&&(r||n!==A)||((t=n).nodeType?u(e,n,r):c(e,n,r));return t=null,o}];a1&&g(l),a>1&&h(e.slice(0,a-1).concat({value:" "===e[a-2].type?"*":""})).replace(ae,"$1"),n,a0,i=e.length>0,s=function(r,s,a,u,c){var l,f,p,h=0,d="0",g=r&&[],m=[],y=A,x=r||i&&C.find.TAG("*",c),b=B+=null==y?1:Math.random()||.1,w=x.length;for(c&&(A=s===L||s||c);d!==w&&null!=(l=x[d]);d++){if(i&&l){for(f=0,s||l.ownerDocument===L||(O(l),a=!F);p=e[f++];)if(p(l,s||L,a)){u.push(l);break}c&&(B=b)}o&&((l=!p&&l)&&h--,r&&g.push(l))}if(h+=d,o&&d!==h){for(f=0;p=n[f++];)p(g,m,s,a);if(r){if(h>0)for(;d--;)g[d]||m[d]||(m[d]=Q.call(u));m=v(m)}K.apply(u,m),c&&!r&&m.length>0&&h+n.length>1&&t.uniqueSort(u)}return c&&(B=b,A=y),g};return o?r(s):s}var w,T,C,j,k,E,S,N,A,q,D,O,L,H,F,R,I,P,M,$="sizzle"+1*new Date,W=e.document,B=0,_=0,U=n(),z=n(),X=n(),V=function(e,t){return e===t&&(D=!0),0},G={}.hasOwnProperty,Y=[],Q=Y.pop,J=Y.push,K=Y.push,Z=Y.slice,ee=function(e,t){for(var n=0,r=e.length;n+~]|"+ne+")"+ne+"*"),le=new RegExp("="+ne+"*([^\\]'\"]*?)"+ne+"*\\]","g"),fe=new RegExp(ie),pe=new RegExp("^"+re+"$"),he={ID:new RegExp("^#("+re+")"),CLASS:new RegExp("^\\.("+re+")"),TAG:new RegExp("^("+re+"|[*])"),ATTR:new RegExp("^"+oe),PSEUDO:new RegExp("^"+ie),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ne+"*(even|odd|(([+-]|)(\\d*)n|)"+ne+"*(?:([+-]|)"+ne+"*(\\d+)|))"+ne+"*\\)|)","i"),bool:new RegExp("^(?:"+te+")$","i"),needsContext:new RegExp("^"+ne+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ne+"*((?:-\\d)?\\d*)"+ne+"*\\)|)(?=[^-]|$)","i")},de=/^(?:input|select|textarea|button)$/i,ge=/^h\d$/i,me=/^[^{]+\{\s*\[native \w/,ve=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ye=/[+~]/,xe=new RegExp("\\\\([\\da-f]{1,6}"+ne+"?|("+ne+")|.)","ig"),be=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},we=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,Te=function(e,t){return t?"\0"===e?"�":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},Ce=function(){O()},je=d(function(e){return e.disabled===!0&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{K.apply(Y=Z.call(W.childNodes),W.childNodes),Y[W.childNodes.length].nodeType}catch(e){K={apply:Y.length?function(e,t){J.apply(e,Z.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}T=t.support={},k=t.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},O=t.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:W;return r!==L&&9===r.nodeType&&r.documentElement?(L=r,H=L.documentElement,F=!k(L),W!==L&&(n=L.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",Ce,!1):n.attachEvent&&n.attachEvent("onunload",Ce)),T.attributes=o(function(e){return e.className="i",!e.getAttribute("className")}),T.getElementsByTagName=o(function(e){return e.appendChild(L.createComment("")),!e.getElementsByTagName("*").length}),T.getElementsByClassName=me.test(L.getElementsByClassName),T.getById=o(function(e){return H.appendChild(e).id=$,!L.getElementsByName||!L.getElementsByName($).length}),T.getById?(C.filter.ID=function(e){var t=e.replace(xe,be);return function(e){return e.getAttribute("id")===t}},C.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&F){var n=t.getElementById(e);return n?[n]:[]}}):(C.filter.ID=function(e){var t=e.replace(xe,be);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},C.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&F){var n,r,o,i=t.getElementById(e);if(i){if(n=i.getAttributeNode("id"),n&&n.value===e)return[i];for(o=t.getElementsByName(e),r=0;i=o[r++];)if(n=i.getAttributeNode("id"),n&&n.value===e)return[i]}return[]}}),C.find.TAG=T.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):T.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],o=0,i=t.getElementsByTagName(e);if("*"===e){for(;n=i[o++];)1===n.nodeType&&r.push(n);return r}return i},C.find.CLASS=T.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&F)return t.getElementsByClassName(e)},I=[],R=[],(T.qsa=me.test(L.querySelectorAll))&&(o(function(e){H.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&R.push("[*^$]="+ne+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||R.push("\\["+ne+"*(?:value|"+te+")"),e.querySelectorAll("[id~="+$+"-]").length||R.push("~="),e.querySelectorAll(":checked").length||R.push(":checked"),e.querySelectorAll("a#"+$+"+*").length||R.push(".#.+[+~]")}),o(function(e){e.innerHTML="";var t=L.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&R.push("name"+ne+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&R.push(":enabled",":disabled"),H.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&R.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),R.push(",.*:")})),(T.matchesSelector=me.test(P=H.matches||H.webkitMatchesSelector||H.mozMatchesSelector||H.oMatchesSelector||H.msMatchesSelector))&&o(function(e){T.disconnectedMatch=P.call(e,"*"),P.call(e,"[s!='']:x"),I.push("!=",ie)}),R=R.length&&new RegExp(R.join("|")),I=I.length&&new RegExp(I.join("|")),t=me.test(H.compareDocumentPosition),M=t||me.test(H.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},V=t?function(e,t){if(e===t)return D=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n?n:(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1,1&n||!T.sortDetached&&t.compareDocumentPosition(e)===n?e===L||e.ownerDocument===W&&M(W,e)?-1:t===L||t.ownerDocument===W&&M(W,t)?1:q?ee(q,e)-ee(q,t):0:4&n?-1:1)}:function(e,t){if(e===t)return D=!0,0;var n,r=0,o=e.parentNode,i=t.parentNode,a=[e],u=[t];if(!o||!i)return e===L?-1:t===L?1:o?-1:i?1:q?ee(q,e)-ee(q,t):0;if(o===i)return s(e,t);for(n=e;n=n.parentNode;)a.unshift(n);for(n=t;n=n.parentNode;)u.unshift(n);for(;a[r]===u[r];)r++;return r?s(a[r],u[r]):a[r]===W?-1:u[r]===W?1:0},L):L},t.matches=function(e,n){return t(e,null,null,n)},t.matchesSelector=function(e,n){if((e.ownerDocument||e)!==L&&O(e),n=n.replace(le,"='$1']"),T.matchesSelector&&F&&!X[n+" "]&&(!I||!I.test(n))&&(!R||!R.test(n)))try{var r=P.call(e,n);if(r||T.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return t(n,L,null,[e]).length>0},t.contains=function(e,t){return(e.ownerDocument||e)!==L&&O(e),M(e,t)},t.attr=function(e,t){(e.ownerDocument||e)!==L&&O(e);var n=C.attrHandle[t.toLowerCase()],r=n&&G.call(C.attrHandle,t.toLowerCase())?n(e,t,!F):void 0;return void 0!==r?r:T.attributes||!F?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},t.escape=function(e){return(e+"").replace(we,Te)},t.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},t.uniqueSort=function(e){var t,n=[],r=0,o=0;if(D=!T.detectDuplicates,q=!T.sortStable&&e.slice(0),e.sort(V),D){for(;t=e[o++];)t===e[o]&&(r=n.push(o));for(;r--;)e.splice(n[r],1)}return q=null,e},j=t.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=j(e)}else if(3===o||4===o)return e.nodeValue}else for(;t=e[r++];)n+=j(t);return n},C=t.selectors={cacheLength:50,createPseudo:r,match:he,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(xe,be),e[3]=(e[3]||e[4]||e[5]||"").replace(xe,be),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||t.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&t.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return he.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&fe.test(n)&&(t=E(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(xe,be).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=U[e+" "];return t||(t=new RegExp("(^|"+ne+")"+e+"("+ne+"|$)"))&&U(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,n,r){return function(o){var i=t.attr(o,e);return null==i?"!="===n:!n||(i+="","="===n?i===r:"!="===n?i!==r:"^="===n?r&&0===i.indexOf(r):"*="===n?r&&i.indexOf(r)>-1:"$="===n?r&&i.slice(-r.length)===r:"~="===n?(" "+i.replace(se," ")+" ").indexOf(r)>-1:"|="===n&&(i===r||i.slice(0,r.length+1)===r+"-"))}},CHILD:function(e,t,n,r,o){var i="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===o?function(e){return!!e.parentNode}:function(t,n,u){var c,l,f,p,h,d,g=i!==s?"nextSibling":"previousSibling",m=t.parentNode,v=a&&t.nodeName.toLowerCase(),y=!u&&!a,x=!1;if(m){if(i){for(;g;){for(p=t;p=p[g];)if(a?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;d=g="only"===e&&!d&&"nextSibling"}return!0}if(d=[s?m.firstChild:m.lastChild],s&&y){for(p=m,f=p[$]||(p[$]={}),l=f[p.uniqueID]||(f[p.uniqueID]={}),c=l[e]||[],h=c[0]===B&&c[1],x=h&&c[2],p=h&&m.childNodes[h];p=++h&&p&&p[g]||(x=h=0)||d.pop();)if(1===p.nodeType&&++x&&p===t){l[e]=[B,h,x];break}}else if(y&&(p=t,f=p[$]||(p[$]={}),l=f[p.uniqueID]||(f[p.uniqueID]={}),c=l[e]||[],h=c[0]===B&&c[1],x=h),x===!1)for(;(p=++h&&p&&p[g]||(x=h=0)||d.pop())&&((a?p.nodeName.toLowerCase()!==v:1!==p.nodeType)||!++x||(y&&(f=p[$]||(p[$]={}),l=f[p.uniqueID]||(f[p.uniqueID]={}),l[e]=[B,x]),p!==t)););return x-=o,x===r||x%r===0&&x/r>=0}}},PSEUDO:function(e,n){var o,i=C.pseudos[e]||C.setFilters[e.toLowerCase()]||t.error("unsupported pseudo: "+e);return i[$]?i(n):i.length>1?(o=[e,e,"",n],C.setFilters.hasOwnProperty(e.toLowerCase())?r(function(e,t){for(var r,o=i(e,n),s=o.length;s--;)r=ee(e,o[s]),e[r]=!(t[r]=o[s])}):function(e){return i(e,0,o)}):i}},pseudos:{not:r(function(e){var t=[],n=[],o=S(e.replace(ae,"$1"));return o[$]?r(function(e,t,n,r){for(var i,s=o(e,null,r,[]),a=e.length;a--;)(i=s[a])&&(e[a]=!(t[a]=i))}):function(e,r,i){return t[0]=e,o(t,null,i,n),t[0]=null,!n.pop()}}),has:r(function(e){return function(n){ +return t(e,n).length>0}}),contains:r(function(e){return e=e.replace(xe,be),function(t){return(t.textContent||t.innerText||j(t)).indexOf(e)>-1}}),lang:r(function(e){return pe.test(e||"")||t.error("unsupported lang: "+e),e=e.replace(xe,be).toLowerCase(),function(t){var n;do if(n=F?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===H},focus:function(e){return e===L.activeElement&&(!L.hasFocus||L.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:c(!1),disabled:c(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!C.pseudos.empty(e)},header:function(e){return ge.test(e.nodeName)},input:function(e){return de.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:l(function(){return[0]}),last:l(function(e,t){return[t-1]}),eq:l(function(e,t,n){return[n<0?n+t:n]}),even:l(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:l(function(e,t,n){for(var r=n<0?n+t:n;++r2&&"ID"===(s=i[0]).type&&9===t.nodeType&&F&&C.relative[i[1].type]){if(t=(C.find.ID(s.matches[0].replace(xe,be),t)||[])[0],!t)return n;c&&(t=t.parentNode),e=e.slice(i.shift().value.length)}for(o=he.needsContext.test(e)?0:i.length;o--&&(s=i[o],!C.relative[a=s.type]);)if((u=C.find[a])&&(r=u(s.matches[0].replace(xe,be),ye.test(i[0].type)&&f(t.parentNode)||t))){if(i.splice(o,1),e=r.length&&h(i),!e)return K.apply(n,r),n;break}}return(c||S(e,l))(r,t,!F,n,!t||ye.test(e)&&f(t.parentNode)||t),n},T.sortStable=$.split("").sort(V).join("")===$,T.detectDuplicates=!!D,O(),T.sortDetached=o(function(e){return 1&e.compareDocumentPosition(L.createElement("fieldset"))}),o(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||i("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),T.attributes&&o(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||i("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),o(function(e){return null==e.getAttribute("disabled")})||i(te,function(e,t,n){var r;if(!n)return e[t]===!0?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),t}(e);de.find=xe,de.expr=xe.selectors,de.expr[":"]=de.expr.pseudos,de.uniqueSort=de.unique=xe.uniqueSort,de.text=xe.getText,de.isXMLDoc=xe.isXML,de.contains=xe.contains,de.escapeSelector=xe.escape;var be=function(e,t,n){for(var r=[],o=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(o&&de(e).is(n))break;r.push(e)}return r},we=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},Te=de.expr.match.needsContext,Ce=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,je=/^.[^:#\[\.,]*$/;de.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?de.find.matchesSelector(r,e)?[r]:[]:de.find.matches(e,de.grep(t,function(e){return 1===e.nodeType}))},de.fn.extend({find:function(e){var t,n,r=this.length,o=this;if("string"!=typeof e)return this.pushStack(de(e).filter(function(){for(t=0;t1?de.uniqueSort(n):n},filter:function(e){return this.pushStack(o(this,e||[],!1))},not:function(e){return this.pushStack(o(this,e||[],!0))},is:function(e){return!!o(this,"string"==typeof e&&Te.test(e)?de(e):e||[],!1).length}});var ke,Ee=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,Se=de.fn.init=function(e,t,n){var r,o;if(!e)return this;if(n=n||ke,"string"==typeof e){if(r="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:Ee.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof de?t[0]:t,de.merge(this,de.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:te,!0)),Ce.test(r[1])&&de.isPlainObject(t))for(r in t)de.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return o=te.getElementById(r[2]),o&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):de.isFunction(e)?void 0!==n.ready?n.ready(e):e(de):de.makeArray(e,this)};Se.prototype=de.fn,ke=de(te);var Ne=/^(?:parents|prev(?:Until|All))/,Ae={children:!0,contents:!0,next:!0,prev:!0};de.fn.extend({has:function(e){var t=de(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&de.find.matchesSelector(n,e))){i.push(n);break}return this.pushStack(i.length>1?de.uniqueSort(i):i)},index:function(e){return e?"string"==typeof e?se.call(de(e),this[0]):se.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(de.uniqueSort(de.merge(this.get(),de(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),de.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return be(e,"parentNode")},parentsUntil:function(e,t,n){return be(e,"parentNode",n)},next:function(e){return i(e,"nextSibling")},prev:function(e){return i(e,"previousSibling")},nextAll:function(e){return be(e,"nextSibling")},prevAll:function(e){return be(e,"previousSibling")},nextUntil:function(e,t,n){return be(e,"nextSibling",n)},prevUntil:function(e,t,n){return be(e,"previousSibling",n)},siblings:function(e){return we((e.parentNode||{}).firstChild,e)},children:function(e){return we(e.firstChild)},contents:function(e){return e.contentDocument||de.merge([],e.childNodes)}},function(e,t){de.fn[e]=function(n,r){var o=de.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(o=de.filter(r,o)),this.length>1&&(Ae[e]||de.uniqueSort(o),Ne.test(e)&&o.reverse()),this.pushStack(o)}});var qe=/[^\x20\t\r\n\f]+/g;de.Callbacks=function(e){e="string"==typeof e?s(e):de.extend({},e);var t,n,r,o,i=[],a=[],u=-1,c=function(){for(o=e.once,r=t=!0;a.length;u=-1)for(n=a.shift();++u-1;)i.splice(n,1),n<=u&&u--}),this},has:function(e){return e?de.inArray(e,i)>-1:i.length>0},empty:function(){return i&&(i=[]),this},disable:function(){return o=a=[],i=n="",this},disabled:function(){return!i},lock:function(){return o=a=[],n||t||(i=n=""),this},locked:function(){return!!o},fireWith:function(e,n){return o||(n=n||[],n=[e,n.slice?n.slice():n],a.push(n),t||c()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l},de.extend({Deferred:function(t){var n=[["notify","progress",de.Callbacks("memory"),de.Callbacks("memory"),2],["resolve","done",de.Callbacks("once memory"),de.Callbacks("once memory"),0,"resolved"],["reject","fail",de.Callbacks("once memory"),de.Callbacks("once memory"),1,"rejected"]],r="pending",o={state:function(){return r},always:function(){return i.done(arguments).fail(arguments),this},catch:function(e){return o.then(null,e)},pipe:function(){var e=arguments;return de.Deferred(function(t){de.each(n,function(n,r){var o=de.isFunction(e[r[4]])&&e[r[4]];i[r[1]](function(){var e=o&&o.apply(this,arguments);e&&de.isFunction(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,o?[e]:arguments)})}),e=null}).promise()},then:function(t,r,o){function i(t,n,r,o){return function(){var c=this,l=arguments,f=function(){var e,f;if(!(t=s&&(r!==u&&(c=void 0,l=[e]),n.rejectWith(c,l))}};t?p():(de.Deferred.getStackHook&&(p.stackTrace=de.Deferred.getStackHook()),e.setTimeout(p))}}var s=0;return de.Deferred(function(e){n[0][3].add(i(0,e,de.isFunction(o)?o:a,e.notifyWith)),n[1][3].add(i(0,e,de.isFunction(t)?t:a)),n[2][3].add(i(0,e,de.isFunction(r)?r:u))}).promise()},promise:function(e){return null!=e?de.extend(e,o):o}},i={};return de.each(n,function(e,t){var s=t[2],a=t[5];o[t[1]]=s.add,a&&s.add(function(){r=a},n[3-e][2].disable,n[0][2].lock),s.add(t[3].fire),i[t[0]]=function(){return i[t[0]+"With"](this===i?void 0:this,arguments),this},i[t[0]+"With"]=s.fireWith}),o.promise(i),t&&t.call(i,i),i},when:function(e){var t=arguments.length,n=t,r=Array(n),o=re.call(arguments),i=de.Deferred(),s=function(e){return function(n){r[e]=this,o[e]=arguments.length>1?re.call(arguments):n,--t||i.resolveWith(r,o)}};if(t<=1&&(c(e,i.done(s(n)).resolve,i.reject),"pending"===i.state()||de.isFunction(o[n]&&o[n].then)))return i.then();for(;n--;)c(o[n],s(n),i.reject);return i.promise()}});var De=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;de.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&De.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},de.readyException=function(t){e.setTimeout(function(){throw t})};var Oe=de.Deferred();de.fn.ready=function(e){return Oe.then(e).catch(function(e){de.readyException(e)}),this},de.extend({isReady:!1,readyWait:1,holdReady:function(e){e?de.readyWait++:de.ready(!0)},ready:function(e){(e===!0?--de.readyWait:de.isReady)||(de.isReady=!0,e!==!0&&--de.readyWait>0||Oe.resolveWith(te,[de]))}}),de.ready.then=Oe.then,"complete"===te.readyState||"loading"!==te.readyState&&!te.documentElement.doScroll?e.setTimeout(de.ready):(te.addEventListener("DOMContentLoaded",l),e.addEventListener("load",l));var Le=function(e,t,n,r,o,i,s){var a=0,u=e.length,c=null==n;if("object"===de.type(n)){o=!0;for(a in n)Le(e,t,a,n[a],!0,i,s)}else if(void 0!==r&&(o=!0,de.isFunction(r)||(s=!0),c&&(s?(t.call(e,r),t=null):(c=t,t=function(e,t,n){return c.call(de(e),n)})),t))for(;a1,null,!0)},removeData:function(e){return this.each(function(){Re.remove(this,e)})}}),de.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Fe.get(e,t),n&&(!r||de.isArray(n)?r=Fe.access(e,t,de.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=de.queue(e,t),r=n.length,o=n.shift(),i=de._queueHooks(e,t),s=function(){de.dequeue(e,t)};"inprogress"===o&&(o=n.shift(),r--),o&&("fx"===t&&n.unshift("inprogress"),delete i.stop,o.call(e,s,i)),!r&&i&&i.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Fe.get(e,n)||Fe.access(e,n,{empty:de.Callbacks("once memory").add(function(){Fe.remove(e,[t+"queue",n])})})}}),de.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,Ve=/^$|\/(?:java|ecma)script/i,Ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};Ge.optgroup=Ge.option,Ge.tbody=Ge.tfoot=Ge.colgroup=Ge.caption=Ge.thead,Ge.th=Ge.td;var Ye=/<|&#?\w+;/;!function(){var e=te.createDocumentFragment(),t=e.appendChild(te.createElement("div")),n=te.createElement("input");n.setAttribute("type","radio"),n.setAttribute("checked","checked"),n.setAttribute("name","t"),t.appendChild(n),pe.checkClone=t.cloneNode(!0).cloneNode(!0).lastChild.checked,t.innerHTML="",pe.noCloneChecked=!!t.cloneNode(!0).lastChild.defaultValue}();var Qe=te.documentElement,Je=/^key/,Ke=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ze=/^([^.]*)(?:\.(.+)|)/;de.event={global:{},add:function(e,t,n,r,o){var i,s,a,u,c,l,f,p,h,d,g,m=Fe.get(e);if(m)for(n.handler&&(i=n,n=i.handler,o=i.selector),o&&de.find.matchesSelector(Qe,o),n.guid||(n.guid=de.guid++),(u=m.events)||(u=m.events={}),(s=m.handle)||(s=m.handle=function(t){return"undefined"!=typeof de&&de.event.triggered!==t.type?de.event.dispatch.apply(e,arguments):void 0}),t=(t||"").match(qe)||[""],c=t.length;c--;)a=Ze.exec(t[c])||[],h=g=a[1],d=(a[2]||"").split(".").sort(),h&&(f=de.event.special[h]||{},h=(o?f.delegateType:f.bindType)||h,f=de.event.special[h]||{},l=de.extend({type:h,origType:g,data:r,handler:n,guid:n.guid,selector:o,needsContext:o&&de.expr.match.needsContext.test(o),namespace:d.join(".")},i),(p=u[h])||(p=u[h]=[],p.delegateCount=0,f.setup&&f.setup.call(e,r,d,s)!==!1||e.addEventListener&&e.addEventListener(h,s)),f.add&&(f.add.call(e,l),l.handler.guid||(l.handler.guid=n.guid)),o?p.splice(p.delegateCount++,0,l):p.push(l),de.event.global[h]=!0)},remove:function(e,t,n,r,o){var i,s,a,u,c,l,f,p,h,d,g,m=Fe.hasData(e)&&Fe.get(e);if(m&&(u=m.events)){for(t=(t||"").match(qe)||[""],c=t.length;c--;)if(a=Ze.exec(t[c])||[],h=g=a[1],d=(a[2]||"").split(".").sort(),h){for(f=de.event.special[h]||{},h=(r?f.delegateType:f.bindType)||h,p=u[h]||[],a=a[2]&&new RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=i=p.length;i--;)l=p[i],!o&&g!==l.origType||n&&n.guid!==l.guid||a&&!a.test(l.namespace)||r&&r!==l.selector&&("**"!==r||!l.selector)||(p.splice(i,1),l.selector&&p.delegateCount--,f.remove&&f.remove.call(e,l));s&&!p.length&&(f.teardown&&f.teardown.call(e,d,m.handle)!==!1||de.removeEvent(e,h,m.handle),delete u[h])}else for(h in u)de.event.remove(e,h+t[c],n,r,!0);de.isEmptyObject(u)&&Fe.remove(e,"handle events")}},dispatch:function(e){var t,n,r,o,i,s,a=de.event.fix(e),u=new Array(arguments.length),c=(Fe.get(this,"events")||{})[a.type]||[],l=de.event.special[a.type]||{};for(u[0]=a,t=1;t=1))for(;c!==this;c=c.parentNode||this)if(1===c.nodeType&&("click"!==e.type||c.disabled!==!0)){for(i=[],s={},n=0;n-1:de.find(o,this,null,[c]).length),s[o]&&i.push(r);i.length&&a.push({elem:c,handlers:i})}return c=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,tt=/\s*$/g;de.extend({htmlPrefilter:function(e){return e.replace(et,"<$1>")},clone:function(e,t,n){var r,o,i,s,a=e.cloneNode(!0),u=de.contains(e.ownerDocument,e);if(!(pe.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||de.isXMLDoc(e)))for(s=v(a),i=v(e),r=0,o=i.length;r0&&y(s,!u&&v(e,"script")),a},cleanData:function(e){for(var t,n,r,o=de.event.special,i=0;void 0!==(n=e[i]);i++)if(He(n)){if(t=n[Fe.expando]){if(t.events)for(r in t.events)o[r]?de.event.remove(n,r):de.removeEvent(n,r,t.handle);n[Fe.expando]=void 0}n[Re.expando]&&(n[Re.expando]=void 0)}}}),de.fn.extend({detach:function(e){return q(this,e,!0)},remove:function(e){return q(this,e)},text:function(e){return Le(this,function(e){return void 0===e?de.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return A(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=j(this,e);t.appendChild(e)}})},prepend:function(){return A(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=j(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return A(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return A(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(de.cleanData(v(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return de.clone(this,e,t)})},html:function(e){return Le(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!tt.test(e)&&!Ge[(Xe.exec(e)||["",""])[1].toLowerCase()]){e=de.htmlPrefilter(e);try{for(;n1)}}),de.Tween=I,I.prototype={constructor:I,init:function(e,t,n,r,o,i){this.elem=e,this.prop=n,this.easing=o||de.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=i||(de.cssNumber[n]?"":"px")},cur:function(){var e=I.propHooks[this.prop];return e&&e.get?e.get(this):I.propHooks._default.get(this)},run:function(e){var t,n=I.propHooks[this.prop];return this.options.duration?this.pos=t=de.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):I.propHooks._default.set(this),this}},I.prototype.init.prototype=I.prototype,I.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=de.css(e.elem,e.prop,""),t&&"auto"!==t?t:0)},set:function(e){de.fx.step[e.prop]?de.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[de.cssProps[e.prop]]&&!de.cssHooks[e.prop]?e.elem[e.prop]=e.now:de.style(e.elem,e.prop,e.now+e.unit)}}},I.propHooks.scrollTop=I.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},de.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},de.fx=I.prototype.init,de.fx.step={};var ht,dt,gt=/^(?:toggle|show|hide)$/,mt=/queueHooks$/;de.Animation=de.extend(U,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return d(n.elem,e,$e.exec(t),n),n}]},tweener:function(e,t){de.isFunction(e)?(t=e,e=["*"]):e=e.match(qe);for(var n,r=0,o=e.length;r1)},removeAttr:function(e){return this.each(function(){de.removeAttr(this,e)})}}),de.extend({attr:function(e,t,n){var r,o,i=e.nodeType;if(3!==i&&8!==i&&2!==i)return"undefined"==typeof e.getAttribute?de.prop(e,t,n):(1===i&&de.isXMLDoc(e)||(o=de.attrHooks[t.toLowerCase()]||(de.expr.match.bool.test(t)?vt:void 0)),void 0!==n?null===n?void de.removeAttr(e,t):o&&"set"in o&&void 0!==(r=o.set(e,n,t))?r:(e.setAttribute(t,n+""),n):o&&"get"in o&&null!==(r=o.get(e,t))?r:(r=de.find.attr(e,t),null==r?void 0:r))},attrHooks:{type:{set:function(e,t){if(!pe.radioValue&&"radio"===t&&de.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,o=t&&t.match(qe);if(o&&1===e.nodeType)for(;n=o[r++];)e.removeAttribute(n)}}),vt={set:function(e,t,n){return t===!1?de.removeAttr(e,n):e.setAttribute(n,n),n}},de.each(de.expr.match.bool.source.match(/\w+/g),function(e,t){var n=yt[t]||de.find.attr;yt[t]=function(e,t,r){var o,i,s=t.toLowerCase();return r||(i=yt[s],yt[s]=o,o=null!=n(e,t,r)?s:null,yt[s]=i),o}});var xt=/^(?:input|select|textarea|button)$/i,bt=/^(?:a|area)$/i;de.fn.extend({prop:function(e,t){return Le(this,de.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[de.propFix[e]||e]})}}),de.extend({prop:function(e,t,n){var r,o,i=e.nodeType;if(3!==i&&8!==i&&2!==i)return 1===i&&de.isXMLDoc(e)||(t=de.propFix[t]||t,o=de.propHooks[t]),void 0!==n?o&&"set"in o&&void 0!==(r=o.set(e,n,t))?r:e[t]=n:o&&"get"in o&&null!==(r=o.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=de.find.attr(e,"tabindex");return t?parseInt(t,10):xt.test(e.nodeName)||bt.test(e.nodeName)&&e.href?0:-1}}},propFix:{for:"htmlFor",class:"className"}}),pe.optSelected||(de.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),de.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){de.propFix[this.toLowerCase()]=this}),de.fn.extend({addClass:function(e){var t,n,r,o,i,s,a,u=0;if(de.isFunction(e))return this.each(function(t){de(this).addClass(e.call(this,t,X(this)))});if("string"==typeof e&&e)for(t=e.match(qe)||[];n=this[u++];)if(o=X(n),r=1===n.nodeType&&" "+z(o)+" "){for(s=0;i=t[s++];)r.indexOf(" "+i+" ")<0&&(r+=i+" ");a=z(r),o!==a&&n.setAttribute("class",a)}return this},removeClass:function(e){var t,n,r,o,i,s,a,u=0;if(de.isFunction(e))return this.each(function(t){de(this).removeClass(e.call(this,t,X(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof e&&e)for(t=e.match(qe)||[];n=this[u++];)if(o=X(n),r=1===n.nodeType&&" "+z(o)+" "){for(s=0;i=t[s++];)for(;r.indexOf(" "+i+" ")>-1;)r=r.replace(" "+i+" "," ");a=z(r),o!==a&&n.setAttribute("class",a)}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):de.isFunction(e)?this.each(function(n){de(this).toggleClass(e.call(this,n,X(this),t),t)}):this.each(function(){var t,r,o,i;if("string"===n)for(r=0,o=de(this),i=e.match(qe)||[];t=i[r++];)o.hasClass(t)?o.removeClass(t):o.addClass(t);else void 0!==e&&"boolean"!==n||(t=X(this),t&&Fe.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||e===!1?"":Fe.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;for(t=" "+e+" ";n=this[r++];)if(1===n.nodeType&&(" "+z(X(n))+" ").indexOf(t)>-1)return!0;return!1}});var wt=/\r/g;de.fn.extend({val:function(e){var t,n,r,o=this[0];{if(arguments.length)return r=de.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=r?e.call(this,n,de(this).val()):e,null==o?o="":"number"==typeof o?o+="":de.isArray(o)&&(o=de.map(o,function(e){return null==e?"":e+""})),t=de.valHooks[this.type]||de.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&void 0!==t.set(this,o,"value")||(this.value=o))});if(o)return t=de.valHooks[o.type]||de.valHooks[o.nodeName.toLowerCase()],t&&"get"in t&&void 0!==(n=t.get(o,"value"))?n:(n=o.value,"string"==typeof n?n.replace(wt,""):null==n?"":n)}}}),de.extend({valHooks:{option:{get:function(e){var t=de.find.attr(e,"value");return null!=t?t:z(de.text(e))}},select:{get:function(e){var t,n,r,o=e.options,i=e.selectedIndex,s="select-one"===e.type,a=s?null:[],u=s?i+1:o.length;for(r=i<0?u:s?i:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),i}}}}),de.each(["radio","checkbox"],function(){de.valHooks[this]={set:function(e,t){if(de.isArray(t))return e.checked=de.inArray(de(e).val(),t)>-1}},pe.checkOn||(de.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Tt=/^(?:focusinfocus|focusoutblur)$/;de.extend(de.event,{trigger:function(t,n,r,o){var i,s,a,u,c,l,f,p=[r||te],h=ce.call(t,"type")?t.type:t,d=ce.call(t,"namespace")?t.namespace.split("."):[];if(s=a=r=r||te,3!==r.nodeType&&8!==r.nodeType&&!Tt.test(h+de.event.triggered)&&(h.indexOf(".")>-1&&(d=h.split("."),h=d.shift(),d.sort()),c=h.indexOf(":")<0&&"on"+h,t=t[de.expando]?t:new de.Event(h,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=d.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=r),n=null==n?[t]:de.makeArray(n,[t]),f=de.event.special[h]||{},o||!f.trigger||f.trigger.apply(r,n)!==!1)){if(!o&&!f.noBubble&&!de.isWindow(r)){for(u=f.delegateType||h,Tt.test(u+h)||(s=s.parentNode);s;s=s.parentNode)p.push(s),a=s;a===(r.ownerDocument||te)&&p.push(a.defaultView||a.parentWindow||e)}for(i=0;(s=p[i++])&&!t.isPropagationStopped();)t.type=i>1?u:f.bindType||h,l=(Fe.get(s,"events")||{})[t.type]&&Fe.get(s,"handle"),l&&l.apply(s,n),l=c&&s[c],l&&l.apply&&He(s)&&(t.result=l.apply(s,n),t.result===!1&&t.preventDefault());return t.type=h,o||t.isDefaultPrevented()||f._default&&f._default.apply(p.pop(),n)!==!1||!He(r)||c&&de.isFunction(r[h])&&!de.isWindow(r)&&(a=r[c],a&&(r[c]=null),de.event.triggered=h,r[h](),de.event.triggered=void 0,a&&(r[c]=a)),t.result}},simulate:function(e,t,n){var r=de.extend(new de.Event,n,{type:e,isSimulated:!0});de.event.trigger(r,null,t)}}),de.fn.extend({trigger:function(e,t){return this.each(function(){de.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return de.event.trigger(e,t,n,!0)}}),de.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,t){de.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),de.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),pe.focusin="onfocusin"in e,pe.focusin||de.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){de.event.simulate(t,e.target,de.event.fix(e))};de.event.special[t]={setup:function(){var r=this.ownerDocument||this,o=Fe.access(r,t);o||r.addEventListener(e,n,!0),Fe.access(r,t,(o||0)+1)},teardown:function(){var r=this.ownerDocument||this,o=Fe.access(r,t)-1;o?Fe.access(r,t,o):(r.removeEventListener(e,n,!0),Fe.remove(r,t))}}});var Ct=e.location,jt=de.now(),kt=/\?/;de.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||de.error("Invalid XML: "+t),n};var Et=/\[\]$/,St=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;de.param=function(e,t){var n,r=[],o=function(e,t){var n=de.isFunction(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(de.isArray(e)||e.jquery&&!de.isPlainObject(e))de.each(e,function(){o(this.name,this.value)});else for(n in e)V(n,e[n],t,o);return r.join("&")},de.fn.extend({serialize:function(){return de.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=de.prop(this,"elements");return e?de.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!de(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!ze.test(e))}).map(function(e,t){var n=de(this).val();return null==n?null:de.isArray(n)?de.map(n,function(e){return{name:t.name,value:e.replace(St,"\r\n")}}):{name:t.name,value:n.replace(St,"\r\n")}}).get()}});var qt=/%20/g,Dt=/#.*$/,Ot=/([?&])_=[^&]*/,Lt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Ht=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Ft=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Pt={},Mt="*/".concat("*"),$t=te.createElement("a");$t.href=Ct.href,de.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Ht.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Mt,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":de.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Q(Q(e,de.ajaxSettings),t):Q(de.ajaxSettings,e)},ajaxPrefilter:G(It),ajaxTransport:G(Pt),ajax:function(t,n){function r(t,n,r,a){var c,p,h,b,w,T=n;l||(l=!0,u&&e.clearTimeout(u),o=void 0,s=a||"",C.readyState=t>0?4:0,c=t>=200&&t<300||304===t,r&&(b=J(d,C,r)),b=K(d,b,C,c),c?(d.ifModified&&(w=C.getResponseHeader("Last-Modified"),w&&(de.lastModified[i]=w),w=C.getResponseHeader("etag"),w&&(de.etag[i]=w)),204===t||"HEAD"===d.type?T="nocontent":304===t?T="notmodified":(T=b.state,p=b.data,h=b.error,c=!h)):(h=T,!t&&T||(T="error",t<0&&(t=0))),C.status=t,C.statusText=(n||T)+"",c?v.resolveWith(g,[p,T,C]):v.rejectWith(g,[C,T,h]),C.statusCode(x),x=void 0,f&&m.trigger(c?"ajaxSuccess":"ajaxError",[C,d,c?p:h]),y.fireWith(g,[C,T]),f&&(m.trigger("ajaxComplete",[C,d]),--de.active||de.event.trigger("ajaxStop")))}"object"==typeof t&&(n=t,t=void 0),n=n||{};var o,i,s,a,u,c,l,f,p,h,d=de.ajaxSetup({},n),g=d.context||d,m=d.context&&(g.nodeType||g.jquery)?de(g):de.event,v=de.Deferred(),y=de.Callbacks("once memory"),x=d.statusCode||{},b={},w={},T="canceled",C={readyState:0,getResponseHeader:function(e){var t;if(l){if(!a)for(a={};t=Lt.exec(s);)a[t[1].toLowerCase()]=t[2];t=a[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return l?s:null},setRequestHeader:function(e,t){return null==l&&(e=w[e.toLowerCase()]=w[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==l&&(d.mimeType=e),this},statusCode:function(e){var t;if(e)if(l)C.always(e[C.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||T;return o&&o.abort(t),r(0,t),this}};if(v.promise(C),d.url=((t||d.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),d.type=n.method||n.type||d.method||d.type,d.dataTypes=(d.dataType||"*").toLowerCase().match(qe)||[""],null==d.crossDomain){c=te.createElement("a");try{c.href=d.url,c.href=c.href,d.crossDomain=$t.protocol+"//"+$t.host!=c.protocol+"//"+c.host}catch(e){d.crossDomain=!0}}if(d.data&&d.processData&&"string"!=typeof d.data&&(d.data=de.param(d.data,d.traditional)),Y(It,d,n,C),l)return C;f=de.event&&d.global,f&&0===de.active++&&de.event.trigger("ajaxStart"),d.type=d.type.toUpperCase(),d.hasContent=!Ft.test(d.type),i=d.url.replace(Dt,""),d.hasContent?d.data&&d.processData&&0===(d.contentType||"").indexOf("application/x-www-form-urlencoded")&&(d.data=d.data.replace(qt,"+")):(h=d.url.slice(i.length),d.data&&(i+=(kt.test(i)?"&":"?")+d.data,delete d.data),d.cache===!1&&(i=i.replace(Ot,"$1"),h=(kt.test(i)?"&":"?")+"_="+jt++ +h),d.url=i+h),d.ifModified&&(de.lastModified[i]&&C.setRequestHeader("If-Modified-Since",de.lastModified[i]),de.etag[i]&&C.setRequestHeader("If-None-Match",de.etag[i])),(d.data&&d.hasContent&&d.contentType!==!1||n.contentType)&&C.setRequestHeader("Content-Type",d.contentType),C.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+("*"!==d.dataTypes[0]?", "+Mt+"; q=0.01":""):d.accepts["*"]);for(p in d.headers)C.setRequestHeader(p,d.headers[p]);if(d.beforeSend&&(d.beforeSend.call(g,C,d)===!1||l))return C.abort();if(T="abort",y.add(d.complete),C.done(d.success),C.fail(d.error),o=Y(Pt,d,n,C)){if(C.readyState=1,f&&m.trigger("ajaxSend",[C,d]),l)return C;d.async&&d.timeout>0&&(u=e.setTimeout(function(){C.abort("timeout")},d.timeout));try{l=!1,o.send(b,r)}catch(e){if(l)throw e;r(-1,e)}}else r(-1,"No Transport");return C},getJSON:function(e,t,n){return de.get(e,t,n,"json")},getScript:function(e,t){return de.get(e,void 0,t,"script")}}),de.each(["get","post"],function(e,t){de[t]=function(e,n,r,o){return de.isFunction(n)&&(o=o||r,r=n,n=void 0),de.ajax(de.extend({url:e,type:t,dataType:o,data:n,success:r},de.isPlainObject(e)&&e))}}),de._evalUrl=function(e){return de.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,throws:!0})},de.fn.extend({wrapAll:function(e){var t;return this[0]&&(de.isFunction(e)&&(e=e.call(this[0])),t=de(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return de.isFunction(e)?this.each(function(t){de(this).wrapInner(e.call(this,t))}):this.each(function(){var t=de(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=de.isFunction(e);return this.each(function(n){de(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){de(this).replaceWith(this.childNodes)}),this}}),de.expr.pseudos.hidden=function(e){return!de.expr.pseudos.visible(e)},de.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},de.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Wt={0:200,1223:204},Bt=de.ajaxSettings.xhr();pe.cors=!!Bt&&"withCredentials"in Bt,pe.ajax=Bt=!!Bt,de.ajaxTransport(function(t){var n,r;if(pe.cors||Bt&&!t.crossDomain)return{send:function(o,i){var s,a=t.xhr();if(a.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(s in t.xhrFields)a[s]=t.xhrFields[s];t.mimeType&&a.overrideMimeType&&a.overrideMimeType(t.mimeType),t.crossDomain||o["X-Requested-With"]||(o["X-Requested-With"]="XMLHttpRequest");for(s in o)a.setRequestHeader(s,o[s]);n=function(e){return function(){n&&(n=r=a.onload=a.onerror=a.onabort=a.onreadystatechange=null,"abort"===e?a.abort():"error"===e?"number"!=typeof a.status?i(0,"error"):i(a.status,a.statusText):i(Wt[a.status]||a.status,a.statusText,"text"!==(a.responseType||"text")||"string"!=typeof a.responseText?{binary:a.response}:{text:a.responseText},a.getAllResponseHeaders()))}},a.onload=n(),r=a.onerror=n("error"),void 0!==a.onabort?a.onabort=r:a.onreadystatechange=function(){4===a.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{a.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),de.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),de.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return de.globalEval(e),e}}}),de.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),de.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(r,o){t=de(" + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/idiom/functional-options.md b/idiom/functional-options.md deleted file mode 100644 index 1e95086..0000000 --- a/idiom/functional-options.md +++ /dev/null @@ -1,94 +0,0 @@ -# Functional Options - -Functional options are a method of implementing clean/eloquent APIs in Go. -Options implemented as a function set the state of that option. - -## Implementation - -### Options - -```go -package file - -type Options struct { - UID int - GID int - Flags int - Contents string - Permissions os.FileMode -} - -type Option func(*Options) - -func UID(userID int) Option { - return func(args *Options) { - args.UID = userID - } -} - -func GID(groupID int) Option { - return func(args *Options) { - args.GID = groupID - } -} - -func Contents(c string) Option { - return func(args *Options) { - args.Contents = c - } -} - -func Permissions(perms os.FileMode) Option { - return func(args *Options) { - args.Permissions = perms - } -} -``` - -### Constructor - -```go -package file - -func New(filepath string, setters ...Option) error { - // Default Options - args := &Options{ - UID: os.Getuid(), - GID: os.Getgid(), - Contents: "", - Permissions: 0666, - Flags: os.O_CREATE | os.O_EXCL | os.O_WRONLY, - } - - for _, setter := range setters { - setter(args) - } - - f, err := os.OpenFile(filepath, args.Flags, args.Permissions) - if err != nil { - return err - } else { - defer f.Close() - } - - if _, err := f.WriteString(args.Contents); err != nil { - return err - } - - return f.Chown(args.UID, args.GID) -} -``` - -## Usage - -```go -emptyFile, err := file.New("/tmp/empty.txt") -if err != nil { - panic(err) -} - -fillerFile, err := file.New("/tmp/file.txt", file.UID(1000), file.Contents("Lorem Ipsum Dolor Amet")) -if err != nil { - panic(err) -} -``` diff --git a/index.html b/index.html new file mode 100644 index 0000000..f398d18 --- /dev/null +++ b/index.html @@ -0,0 +1,1399 @@ + + + + + + + Go Patterns · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

+ +

+ Go Patterns +
+ build-status + awesome + license +

+

+ +

A curated collection of idiomatic design & application patterns for Go language.

+

Creational Patterns

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PatternDescriptionStatus
Abstract FactoryProvides an interface for creating families of releated objects✘
BuilderBuilds a complex object using simple objects✔
Factory MethodDefers instantiation of an object to a specialized function for creating instances✔
Object PoolInstantiates and maintains a group of objects instances of the same type✔
SingletonRestricts instantiation of a type to one object✔
+

Structural Patterns

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PatternDescriptionStatus
BridgeDecouples an interface from its implementation so that the two can vary independently✘
CompositeEncapsulates and provides access to a number of different objects✘
DecoratorAdds behavior to an object, statically or dynamically✔
FacadeUses one type as an API to a number of others✘
FlyweightReuses existing instances of objects with similar/identical state to minimize resource usage✘
ProxyProvides a surrogate for an object to control it's actions✘
+

Behavioral Patterns

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PatternDescriptionStatus
Chain of ResponsibilityAvoids coupling a sender to receiver by giving more than object a chance to handle the request✘
CommandBundles a command and arguments to call later✘
MediatorConnects objects and acts as a proxy✘
MementoGenerate an opaque token that can be used to go back to a previous state✘
ObserverProvide a callback for notification of events/changes to data✔
RegistryKeep track of all subclasses of a given class✘
StateEncapsulates varying behavior for the same object based on its internal state✘
StrategyEnables an algorithm's behavior to be selected at runtime✔
TemplateDefines a skeleton class which defers some methods to subclasses✘
VisitorSeparates an algorithm from an object on which it operates✘
+

Synchronization Patterns

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PatternDescriptionStatus
Condition VariableProvides a mechanism for threads to temporarily give up access in order to wait for some condition✘
Lock/MutexEnforces mutual exclusion limit on a resource to gain exclusive access✘
MonitorCombination of mutex and condition variable patterns✘
Read-Write LockAllows parallel read access, but only exclusive access on write operations to a resource✘
SemaphoreAllows controlling access to a common resource✔
+

Concurrency Patterns

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PatternDescriptionStatus
N-BarrierPrevents a process from proceeding until all N processes reach to the barrier✘
Bounded ParallelismCompletes large number of independent tasks with resource limits✔
BroadcastTransfers a message to all recipients simultaneously✘
CoroutinesSubroutines that allow suspending and resuming execution at certain locations✘
GeneratorsYields a sequence of values one at a time✔
ReactorDemultiplexes service requests delivered concurrently to a service handler and dispatches them syncronously to the associated request handlers✘
ParallelismCompletes large number of independent tasks✔
Producer ConsumerSeparates tasks from task executions✘
+

Messaging Patterns

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PatternDescriptionStatus
Fan-InFunnels tasks to a work sink (e.g. server)✔
Fan-OutDistributes tasks among workers (e.g. producer)✔
Futures & PromisesActs as a place-holder of a result that is initially unknown for synchronization purposes✘
Publish/SubscribePasses information to a collection of recipients who subscribed to a topic✔
Push & PullDistributes messages to multiple workers, arranged in a pipeline✘
+

Stability Patterns

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PatternDescriptionStatus
BulkheadsEnforces a principle of failure containment (i.e. prevents cascading failures)✘
Circuit-BreakerStops the flow of the requests when requests are likely to fail✔
DeadlineAllows clients to stop waiting for a response once the probability of response becomes low (e.g. after waiting 10 seconds for a page refresh)✘
Fail-FastChecks the availability of required resources at the start of a request and fails if the requirements are not satisfied✘
HandshakingAsks a component if it can take any more load, if it can't, the request is declined✘
Steady-StateFor every service that accumulates a resource, some other service must recycle that resource✘
+

Profiling Patterns

+ + + + + + + + + + + + + + + +
PatternDescriptionStatus
Timing FunctionsWraps a function and logs the execution✔
+

Idioms

+ + + + + + + + + + + + + + + +
PatternDescriptionStatus
Functional OptionsAllows creating clean APIs with sane defaults and idiomatic overrides✔
+

Anti-Patterns

+ + + + + + + + + + + + + + + +
PatternDescriptionStatus
Cascading FailuresA failure in a system of interconnected parts in which the failure of a part causes a domino effect✘
+ + +
+ +
+
+ +
+ + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/messaging/fan_in.html b/messaging/fan_in.html new file mode 100644 index 0000000..0ccaff2 --- /dev/null +++ b/messaging/fan_in.html @@ -0,0 +1,1061 @@ + + + + + + + Fan-In · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Fan-In Messaging Patterns

+

Fan-In is a messaging pattern used to create a funnel for work amongst workers (clients: source, server: destination).

+

We can model fan-in using the Go channels.

+
// Merge different channels in one channel
+func Merge(cs ...<-chan int) <-chan int {
+    var wg sync.WaitGroup
+
+    out := make(chan int)
+
+    // Start an send goroutine for each input channel in cs. send
+    // copies values from c to out until c is closed, then calls wg.Done.
+    send := func(c <-chan int) {
+        for n := range c {
+            out <- n
+        }
+        wg.Done()
+    }
+
+    wg.Add(len(cs))
+    for _, c := range cs {
+        go send(c)
+    }
+
+    // Start a goroutine to close out once all the send goroutines are
+    // done.  This must start after the wg.Add call.
+    go func() {
+        wg.Wait()
+        close(out)
+    }()
+    return out
+}
+
+

The Merge function converts a list of channels to a single channel by starting a goroutine for each inbound channel that copies the values to the sole outbound channel.

+

Once all the output goroutines have been started, Merge a goroutine is started to close the main channel.

+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/messaging/fan_in.md b/messaging/fan_in.md deleted file mode 100644 index d4b3991..0000000 --- a/messaging/fan_in.md +++ /dev/null @@ -1,40 +0,0 @@ -Fan-In Messaging Patterns -=================================== -Fan-In is a messaging pattern used to create a funnel for work amongst workers (clients: source, server: destination). - -We can model fan-in using the Go channels. - -```go -// Merge different channels in one channel -func Merge(cs ...<-chan int) <-chan int { - var wg sync.WaitGroup - - out := make(chan int) - - // Start an send goroutine for each input channel in cs. send - // copies values from c to out until c is closed, then calls wg.Done. - send := func(c <-chan int) { - for n := range c { - out <- n - } - wg.Done() - } - - wg.Add(len(cs)) - for _, c := range cs { - go send(c) - } - - // Start a goroutine to close out once all the send goroutines are - // done. This must start after the wg.Add call. - go func() { - wg.Wait() - close(out) - }() - return out -} -``` - -The `Merge` function converts a list of channels to a single channel by starting a goroutine for each inbound channel that copies the values to the sole outbound channel. - -Once all the output goroutines have been started, `Merge` a goroutine is started to close the main channel. diff --git a/messaging/fan_out.html b/messaging/fan_out.html new file mode 100644 index 0000000..6c69e48 --- /dev/null +++ b/messaging/fan_out.html @@ -0,0 +1,1069 @@ + + + + + + + Fan-Out · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Fan-Out Messaging Pattern

+

Fan-Out is a messaging pattern used for distributing work amongst workers (producer: source, consumers: destination).

+

We can model fan-out using the Go channels.

+
// Split a channel into n channels that receive messages in a round-robin fashion.
+func Split(ch <-chan int, n int) []<-chan int {
+    cs := make([]chan int)
+    for i := 0; i < n; i++ {
+        cs = append(cs, make(chan int))
+    }
+
+    // Distributes the work in a round robin fashion among the stated number
+    // of channels until the main channel has been closed. In that case, close
+    // all channels and return.
+    distributeToChannels := func(ch <-chan int, cs []chan<- int) {
+        // Close every channel when the execution ends.
+        defer func(cs []chan<- int) {
+            for _, c := range cs {
+                close(c)
+            }
+        }(cs)
+
+        for {
+            for _, c := range cs {
+                select {
+                case val, ok := <-ch:
+                    if !ok {
+                        return
+                    }
+
+                    c <- val
+                }
+            }
+        }
+    }
+
+    go distributeToChannels(ch, cs)
+
+    return cs
+}
+
+

The Split function converts a single channel into a list of channels by using +a goroutine to copy received values to channels in the list in a round-robin fashion.

+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/messaging/fan_out.md b/messaging/fan_out.md deleted file mode 100644 index 3052319..0000000 --- a/messaging/fan_out.md +++ /dev/null @@ -1,47 +0,0 @@ -Fan-Out Messaging Pattern -========================= -Fan-Out is a messaging pattern used for distributing work amongst workers (producer: source, consumers: destination). - -We can model fan-out using the Go channels. - -```go -// Split a channel into n channels that receive messages in a round-robin fashion. -func Split(ch <-chan int, n int) []<-chan int { - cs := make([]chan int) - for i := 0; i < n; i++ { - cs = append(cs, make(chan int)) - } - - // Distributes the work in a round robin fashion among the stated number - // of channels until the main channel has been closed. In that case, close - // all channels and return. - distributeToChannels := func(ch <-chan int, cs []chan<- int) { - // Close every channel when the execution ends. - defer func(cs []chan<- int) { - for _, c := range cs { - close(c) - } - }(cs) - - for { - for _, c := range cs { - select { - case val, ok := <-ch: - if !ok { - return - } - - c <- val - } - } - } - } - - go distributeToChannels(ch, cs) - - return cs -} -``` - -The `Split` function converts a single channel into a list of channels by using -a goroutine to copy received values to channels in the list in a round-robin fashion. diff --git a/messaging/publish_subscribe.html b/messaging/publish_subscribe.html new file mode 100644 index 0000000..1aae40f --- /dev/null +++ b/messaging/publish_subscribe.html @@ -0,0 +1,1093 @@ + + + + + + + Publish/Subscribe · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Publish & Subscribe Messaging Pattern

+

Publish-Subscribe is a messaging pattern used to communicate messages between +different components without these components knowing anything about each other's identity.

+

It is similar to the Observer behavioral design pattern. +The fundamental design principals of both Observer and Publish-Subscribe is the decoupling of +those interested in being informed about Event Messages from the informer (Observers or Publishers). +Meaning that you don't have to program the messages to be sent directly to specific receivers.

+

To accomplish this, an intermediary, called a "message broker" or "event bus", +receives published messages, and then routes them on to subscribers.

+

There are three components messages, topics, users.

+
type Message struct {
+    // Contents
+}
+
+
+type Subscription struct {
+    ch chan<- Message
+
+    Inbox chan Message
+}
+
+func (s *Subscription) Publish(msg Message) error {
+    if _, ok := <-s.ch; !ok {
+        return errors.New("Topic has been closed")
+    }
+
+    s.ch <- msg
+
+    return nil
+}
+
+
type Topic struct {
+    Subscribers    []Session
+    MessageHistory []Message
+}
+
+func (t *Topic) Subscribe(uid uint64) (Subscription, error) {
+    // Get session and create one if it's the first
+
+    // Add session to the Topic & MessageHistory
+
+    // Create a subscription
+}
+
+func (t *Topic) Unsubscribe(Subscription) error {
+    // Implementation
+}
+
+func (t *Topic) Delete() error {
+    // Implementation
+}
+
+
type User struct {
+    ID uint64
+    Name string
+}
+
+type Session struct {
+    User User
+    Timestamp time.Time
+}
+
+

Improvements

+

Events can be published in a parallel fashion by utilizing stackless goroutines.

+

Performance can be improved by dealing with straggler subscribers +by using a buffered inbox and you stop sending events once the inbox is full.

+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/messaging/publish_subscribe.md b/messaging/publish_subscribe.md deleted file mode 100644 index 638363e..0000000 --- a/messaging/publish_subscribe.md +++ /dev/null @@ -1,80 +0,0 @@ -Publish & Subscribe Messaging Pattern -============ -Publish-Subscribe is a messaging pattern used to communicate messages between -different components without these components knowing anything about each other's identity. - -It is similar to the Observer behavioral design pattern. -The fundamental design principals of both Observer and Publish-Subscribe is the decoupling of -those interested in being informed about `Event Messages` from the informer (Observers or Publishers). -Meaning that you don't have to program the messages to be sent directly to specific receivers. - -To accomplish this, an intermediary, called a "message broker" or "event bus", -receives published messages, and then routes them on to subscribers. - - -There are three components **messages**, **topics**, **users**. - -```go -type Message struct { - // Contents -} - - -type Subscription struct { - ch chan<- Message - - Inbox chan Message -} - -func (s *Subscription) Publish(msg Message) error { - if _, ok := <-s.ch; !ok { - return errors.New("Topic has been closed") - } - - s.ch <- msg - - return nil -} -``` - -```go -type Topic struct { - Subscribers []Session - MessageHistory []Message -} - -func (t *Topic) Subscribe(uid uint64) (Subscription, error) { - // Get session and create one if it's the first - - // Add session to the Topic & MessageHistory - - // Create a subscription -} - -func (t *Topic) Unsubscribe(Subscription) error { - // Implementation -} - -func (t *Topic) Delete() error { - // Implementation -} -``` - -```go -type User struct { - ID uint64 - Name string -} - -type Session struct { - User User - Timestamp time.Time -} -``` - -Improvements -============ -Events can be published in a parallel fashion by utilizing stackless goroutines. - -Performance can be improved by dealing with straggler subscribers -by using a buffered inbox and you stop sending events once the inbox is full. diff --git a/profiling/timing.html b/profiling/timing.html new file mode 100644 index 0000000..0fbc39b --- /dev/null +++ b/profiling/timing.html @@ -0,0 +1,1059 @@ + + + + + + + Timing Functions · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Timing Functions

+

When optimizing code, sometimes a quick and dirty time measurement is required +as opposed to utilizing profiler tools/frameworks to validate assumptions.

+

Time measurements can be performed by utilizing time package and defer statements.

+

Implementation

+
package profile
+
+import (
+    "time"
+    "log"
+)
+
+func Duration(invocation time.Time, name string) {
+    elapsed := time.Since(invocation)
+
+    log.Printf("%s lasted %s", name, elapsed)
+}
+
+

Usage

+
func BigIntFactorial(x big.Int) *big.Int {
+    // Arguments to a defer statement is immediately evaluated and stored.
+    // The deferred function receives the pre-evaluated values when its invoked.
+    defer profile.Duration(time.Now(), "IntFactorial")
+
+    y := big.NewInt(1)
+    for one := big.NewInt(1); x.Sign() > 0; x.Sub(x, one) {
+        y.Mul(y, x)
+    }
+
+    return x.Set(y)
+}
+
+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/profiling/timing.md b/profiling/timing.md deleted file mode 100644 index 575356a..0000000 --- a/profiling/timing.md +++ /dev/null @@ -1,40 +0,0 @@ -# Timing Functions - -When optimizing code, sometimes a quick and dirty time measurement is required -as opposed to utilizing profiler tools/frameworks to validate assumptions. - -Time measurements can be performed by utilizing `time` package and `defer` statements. - -## Implementation - -```go -package profile - -import ( - "time" - "log" -) - -func Duration(invocation time.Time, name string) { - elapsed := time.Since(invocation) - - log.Printf("%s lasted %s", name, elapsed) -} -``` - -## Usage - -```go -func BigIntFactorial(x big.Int) *big.Int { - // Arguments to a defer statement is immediately evaluated and stored. - // The deferred function receives the pre-evaluated values when its invoked. - defer profile.Duration(time.Now(), "IntFactorial") - - y := big.NewInt(1) - for one := big.NewInt(1); x.Sign() > 0; x.Sub(x, one) { - y.Mul(y, x) - } - - return x.Set(y) -} -``` diff --git a/stability/circuit-breaker.html b/stability/circuit-breaker.html new file mode 100644 index 0000000..c9bfe75 --- /dev/null +++ b/stability/circuit-breaker.html @@ -0,0 +1,1116 @@ + + + + + + + Circuit-Breaker · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Circuit Breaker Pattern

+

Similar to electrical fuses that prevent fires when a circuit that is connected +to the electrical grid starts drawing a high amount of power which causes the +wires to heat up and combust, the circuit breaker design pattern is a fail-first +mechanism that shuts down the circuit, request/response relationship or a +service in the case of software development, to prevent bigger failures.

+

Note: The words "circuit" and "service" are used synonymously throught this +document.

+

Implementation

+

Below is the implementation of a very simple circuit breaker to illustrate the purpose +of the circuit breaker design pattern.

+

Operation Counter

+

circuit.Counter is a simple counter that records success and failure states of +a circuit along with a timestamp and calculates the consecutive number of +failures.

+
package circuit
+
+import (
+    "time"
+)
+
+type State int
+
+const (
+    UnknownState State = iota
+    FailureState
+    SuccessState
+)
+
+type Counter interface {
+    Count(State)
+    ConsecutiveFailures() uint32
+    LastActivity() time.Time
+    Reset()
+}
+
+

Circuit Breaker

+

Circuit is wrapped using the circuit.Breaker closure that keeps an internal operation counter. +It returns a fast error if the circuit has failed consecutively more than the specified threshold. +After a while it retries the request and records it.

+

Note: Context type is used here to carry deadlines, cancelation signals, and +other request-scoped values across API boundaries and between processes.

+
package circuit
+
+import (
+    "context"
+    "time"
+)
+
+type Circuit func(context.Context) error
+
+func Breaker(c Circuit, failureThreshold uint32) Circuit {
+    cnt := NewCounter()
+
+    return func(ctx context) error {
+        if cnt.ConsecutiveFailures() >= failureThreshold {
+            canRetry := func(cnt Counter) {
+                backoffLevel := Cnt.ConsecutiveFailures() - failureThreshold
+
+                // Calculates when should the circuit breaker resume propagating requests
+                // to the service
+                shouldRetryAt := cnt.LastActivity().Add(time.Seconds * 2 << backoffLevel)
+
+                return time.Now().After(shouldRetryAt)
+            }
+
+            if !canRetry(cnt) {
+                // Fails fast instead of propagating requests to the circuit since
+                // not enough time has passed since the last failure to retry
+                return ErrServiceUnavailable
+            }
+        }
+
+        // Unless the failure threshold is exceeded the wrapped service mimics the
+        // old behavior and the difference in behavior is seen after consecutive failures
+        if err := c(ctx); err != nil {
+            cnt.Count(FailureState)
+            return err
+        }
+
+        cnt.Count(SuccessState)
+        return nil
+    }
+}
+
+ +
    +
  • sony/gobreaker is a well-tested and intuitive circuit breaker implementation for real-world use cases.
  • +
+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/stability/circuit-breaker.md b/stability/circuit-breaker.md deleted file mode 100644 index 66b0487..0000000 --- a/stability/circuit-breaker.md +++ /dev/null @@ -1,102 +0,0 @@ -# Circuit Breaker Pattern - -Similar to electrical fuses that prevent fires when a circuit that is connected -to the electrical grid starts drawing a high amount of power which causes the -wires to heat up and combust, the circuit breaker design pattern is a fail-first -mechanism that shuts down the circuit, request/response relationship or a -service in the case of software development, to prevent bigger failures. - -**Note:** The words "circuit" and "service" are used synonymously throught this -document. - -## Implementation - -Below is the implementation of a very simple circuit breaker to illustrate the purpose -of the circuit breaker design pattern. - -### Operation Counter - -`circuit.Counter` is a simple counter that records success and failure states of -a circuit along with a timestamp and calculates the consecutive number of -failures. - -```go -package circuit - -import ( - "time" -) - -type State int - -const ( - UnknownState State = iota - FailureState - SuccessState -) - -type Counter interface { - Count(State) - ConsecutiveFailures() uint32 - LastActivity() time.Time - Reset() -} -``` - -### Circuit Breaker - -Circuit is wrapped using the `circuit.Breaker` closure that keeps an internal operation counter. -It returns a fast error if the circuit has failed consecutively more than the specified threshold. -After a while it retries the request and records it. - -**Note:** Context type is used here to carry deadlines, cancelation signals, and -other request-scoped values across API boundaries and between processes. - -```go -package circuit - -import ( - "context" - "time" -) - -type Circuit func(context.Context) error - -func Breaker(c Circuit, failureThreshold uint32) Circuit { - cnt := NewCounter() - - return func(ctx context) error { - if cnt.ConsecutiveFailures() >= failureThreshold { - canRetry := func(cnt Counter) { - backoffLevel := Cnt.ConsecutiveFailures() - failureThreshold - - // Calculates when should the circuit breaker resume propagating requests - // to the service - shouldRetryAt := cnt.LastActivity().Add(time.Seconds * 2 << backoffLevel) - - return time.Now().After(shouldRetryAt) - } - - if !canRetry(cnt) { - // Fails fast instead of propagating requests to the circuit since - // not enough time has passed since the last failure to retry - return ErrServiceUnavailable - } - } - - // Unless the failure threshold is exceeded the wrapped service mimics the - // old behavior and the difference in behavior is seen after consecutive failures - if err := c(ctx); err != nil { - cnt.Count(FailureState) - return err - } - - cnt.Count(SuccessState) - return nil - } -} -``` - -## Related Works - -- [sony/gobreaker](https://github.com/sony/gobreaker) is a well-tested and intuitive circuit breaker implementation for real-world use cases. diff --git a/structural/decorator.html b/structural/decorator.html new file mode 100644 index 0000000..1656a50 --- /dev/null +++ b/structural/decorator.html @@ -0,0 +1,1063 @@ + + + + + + + Decorator · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Decorator Pattern

+

Decorator structural pattern allows extending the function of an existing object dynamically without altering its internals.

+

Decorators provide a flexible method to extend functionality of objects.

+

Implementation

+

LogDecorate decorates a function with the signature func(int) int that +manipulates integers and adds input/output logging capabilities.

+
type Object func(int) int
+
+func LogDecorate(fn Object) Object {
+    return func(n int) int {
+        log.Println("Starting the execution with the integer", n)
+
+        result := fn(n)
+
+        log.Println("Execution is completed with the result", result)
+
+        return result
+    }
+}
+
+

Usage

+
func Double(n int) int {
+    return n * 2
+}
+
+f := LogDecorate(Double)
+
+f(5)
+// Starting execution with the integer 5
+// Execution is completed with the result 10
+
+

Rules of Thumb

+
    +
  • Unlike Adapter pattern, the object to be decorated is obtained by injection.
  • +
  • Decorators should not alter the interface of an object.
  • +
+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/structural/decorator.md b/structural/decorator.md deleted file mode 100644 index cfb769f..0000000 --- a/structural/decorator.md +++ /dev/null @@ -1,41 +0,0 @@ -# Decorator Pattern -Decorator structural pattern allows extending the function of an existing object dynamically without altering its internals. - -Decorators provide a flexible method to extend functionality of objects. - -## Implementation -`LogDecorate` decorates a function with the signature `func(int) int` that -manipulates integers and adds input/output logging capabilities. - -```go -type Object func(int) int - -func LogDecorate(fn Object) Object { - return func(n int) int { - log.Println("Starting the execution with the integer", n) - - result := fn(n) - - log.Println("Execution is completed with the result", result) - - return result - } -} -``` - -## Usage -```go -func Double(n int) int { - return n * 2 -} - -f := LogDecorate(Double) - -f(5) -// Starting execution with the integer 5 -// Execution is completed with the result 10 -``` - -## Rules of Thumb -- Unlike Adapter pattern, the object to be decorated is obtained by **injection**. -- Decorators should not alter the interface of an object. diff --git a/structural/proxy.md b/structural/proxy.md deleted file mode 100644 index 8a33b9b..0000000 --- a/structural/proxy.md +++ /dev/null @@ -1,45 +0,0 @@ -# Proxy Pattern - -The [proxy pattern](https://en.wikipedia.org/wiki/Proxy_pattern) provides an object that controls access to another object, intercepting all calls. - -## Implementation - -The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate. - -Short idea of implementation: -```go - // To use proxy and to object they must implement same methods - type IObject interface { - ObjDo(action string) - } - - // Object represents real objects which proxy will delegate data - type Object struct { - action string - } - - // ObjDo implements IObject interface and handel's all logic - func (obj *Object) ObjDo(action string) { - // Action behavior - fmt.Printf("I can, %s", action) - } - - // ProxyObject represents proxy object with intercepts actions - type ProxyObject struct { - object *Object - } - - // ObjDo are implemented IObject and intercept action before send in real Object - func (p *ProxyObject) ObjDo(action string) { - if p.object == nil { - p.object = new(Object) - } - if action == "Run" { - p.object.ObjDo(action) // Prints: I can, Run - } - } -``` - -## Usage -More complex usage of proxy as example: User creates "Terminal" authorizes and PROXY send execution command to real Terminal object -See [proxy/main.go](proxy/main.go) or [view in the Playground](https://play.golang.org/p/mnjKCMaOVE). diff --git a/structural/proxy/main.go b/structural/proxy/main.go deleted file mode 100644 index e8a50f8..0000000 --- a/structural/proxy/main.go +++ /dev/null @@ -1,127 +0,0 @@ -package main - -import ( - "fmt" -) - -// For example: -// we must a execute some command -// so before that we must to create new terminal session -// and provide our user name and command -func main() { - // Create new instance of Proxy terminal - t, err := NewTerminal("gopher") - if err != nil { - // panic: User cant be empty - // Or - // panic: You (badUser) are not allowed to use terminal and execute commands - panic(err.Error()) - } - - // Execute user command - excResp, excErr := t.Execute("say_hi") // Proxy prints to STDOUT -> PROXY: Intercepted execution of user (gopher), asked command (say_hi) - if excErr != nil { - fmt.Printf("ERROR: %s\n", excErr.Error()) // Prints: ERROR: I know only how to execute commands: say_hi, man - } - - // Show execution response - fmt.Println(excResp) // Prints: gopher@go_term$: Hi gopher -} - -/* - From that it's can be different terminals realizations with different methods, propertys, yda yda... -*/ - -// ITerminal is interface, it's a public method whose implemented in Terminal(Proxy) and Gopher Terminal -type ITerminal interface { - Execute(cmd string) (resp string, err error) -} - -// GopherTerminal for example: -// Its a "huge" structure with different public methods -type GopherTerminal struct { - // user is a current authorized user - User string -} - -// Execute just runs known commands for current authorized user -func (gt *GopherTerminal) Execute(cmd string) (resp string, err error) { - // Set "terminal" prefix for output - prefix := fmt.Sprintf("%s@go_term$:", gt.User) - - // Execute some asked commands if we know them - switch cmd { - case "say_hi": - resp = fmt.Sprintf("%s Hi %s", prefix, gt.User) - case "man": - resp = fmt.Sprintf("%s Visit 'https://golang.org/doc/' for Golang documentation", prefix) - default: - err = fmt.Errorf("%s Unknown command", prefix) - } - - return -} - -/* - And now we will create owr proxy to deliver user and commands to specific objects -*/ - -// Terminal is a implementation of Proxy, it's validates and sends data to GopherTerminal -// As example before send commands, user must be authorized -type Terminal struct { - currentUser string - gopherTerminal *GopherTerminal -} - -// NewTerminal creates new instance of terminal -func NewTerminal(user string) (t *Terminal, err error) { - // Check user if given correctly - if user == "" { - err = fmt.Errorf("User cant be empty") - return - } - - // Before we execute user commands, we validate current user, if he have rights to do it - if authErr := authorizeUser(user); authErr != nil { - err = fmt.Errorf("You (%s) are not allowed to use terminal and execute commands", user) - return - } - - // Create new instance of terminal and set valid user - t = &Terminal{currentUser: user} - - return -} - -// Execute intercepts execution of command, implements authorizing user, validates it and -// poxing command to real terminal (gopherTerminal) method -func (t *Terminal) Execute(command string) (resp string, err error) { - // If user allowed to execute send commands then, for example we can decide which terminal can be used, remote or local etc.. - // but for example we just creating new instance of terminal, - // set current user and send user command to execution in terminal - t.gopherTerminal = &GopherTerminal{User: t.currentUser} - - // For example our proxy can log or output intercepted execution... etc - fmt.Printf("PROXY: Intercepted execution of user (%s), asked command (%s)\n", t.currentUser, command) - - // Transfer data to original object and execute command - if resp, err = t.gopherTerminal.Execute(command); err != nil { - err = fmt.Errorf("I know only how to execute commands: say_hi, man") - return - } - - return -} - -// authorize validates user right to execute commands -func authorizeUser(user string) (err error) { - // As we use terminal like proxy, then - // we will intercept user name to validate if it's allowed to execute commands - if user != "gopher" { - // Do some logs, notifications etc... - err = fmt.Errorf("User %s in black list", user) - return - } - - return -} diff --git a/synchronization/semaphore.html b/synchronization/semaphore.html new file mode 100644 index 0000000..df779d7 --- /dev/null +++ b/synchronization/semaphore.html @@ -0,0 +1,1103 @@ + + + + + + + Semaphore · GitBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ +
+ +

Semaphore Pattern

+

A semaphore is a synchronization pattern/primitive that imposes mutual exclusion on a limited number of resources.

+

Implementation

+
package semaphore
+
+var (
+    ErrNoTickets      = errors.New("semaphore: could not aquire semaphore")
+    ErrIllegalRelease = errors.New("semaphore: can't release the semaphore without acquiring it first")
+)
+
+// Interface contains the behavior of a semaphore that can be acquired and/or released.
+type Interface interface {
+    Acquire() error
+    Release() error
+}
+
+type implementation struct {
+    sem     chan struct{}
+    timeout time.Duration
+}
+
+func (s *implementation) Acquire() error {
+    select {
+    case s.sem <- struct{}{}:
+        return nil
+    case <-time.After(s.timeout):
+        return ErrNoTickets
+    }
+}
+
+func (s *implementation) Release() error {
+    select {
+    case _ = <-s.sem:
+        return nil
+    case <-time.After(s.timeout):
+        return ErrIllegalRelease
+    }
+
+    return nil
+}
+
+func New(tickets int, timeout time.Duration) Interface {
+    return &implementation{
+        sem:     make(chan struct{}, tickets),
+        timeout: timeout,
+    }
+}
+
+

Usage

+

Semaphore with Timeouts

+
tickets, timeout := 1, 3*time.Second
+s := semaphore.New(tickets, timeout)
+
+if err := s.Acquire(); err != nil {
+    panic(err)
+}
+
+// Do important work
+
+if err := s.Release(); err != nil {
+    panic(err)
+}
+
+

Semaphore without Timeouts (Non-Blocking)

+
tickets, timeout := 0, 0
+s := semaphore.New(tickets, timeout)
+
+if err := s.Acquire(); err != nil {
+    if err != semaphore.ErrNoTickets {
+        panic(err)
+    }
+
+    // No tickets left, can't work :(
+    os.Exit(1)
+}
+
+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/synchronization/semaphore.md b/synchronization/semaphore.md deleted file mode 100644 index 85c7109..0000000 --- a/synchronization/semaphore.md +++ /dev/null @@ -1,84 +0,0 @@ -# Semaphore Pattern -A semaphore is a synchronization pattern/primitive that imposes mutual exclusion on a limited number of resources. - -## Implementation - -```go -package semaphore - -var ( - ErrNoTickets = errors.New("semaphore: could not aquire semaphore") - ErrIllegalRelease = errors.New("semaphore: can't release the semaphore without acquiring it first") -) - -// Interface contains the behavior of a semaphore that can be acquired and/or released. -type Interface interface { - Acquire() error - Release() error -} - -type implementation struct { - sem chan struct{} - timeout time.Duration -} - -func (s *implementation) Acquire() error { - select { - case s.sem <- struct{}{}: - return nil - case <-time.After(s.timeout): - return ErrNoTickets - } -} - -func (s *implementation) Release() error { - select { - case _ = <-s.sem: - return nil - case <-time.After(s.timeout): - return ErrIllegalRelease - } - - return nil -} - -func New(tickets int, timeout time.Duration) Interface { - return &implementation{ - sem: make(chan struct{}, tickets), - timeout: timeout, - } -} -``` - -## Usage -### Semaphore with Timeouts - -```go -tickets, timeout := 1, 3*time.Second -s := semaphore.New(tickets, timeout) - -if err := s.Acquire(); err != nil { - panic(err) -} - -// Do important work - -if err := s.Release(); err != nil { - panic(err) -} -``` -### Semaphore without Timeouts (Non-Blocking) - -```go -tickets, timeout := 0, 0 -s := semaphore.New(tickets, timeout) - -if err := s.Acquire(); err != nil { - if err != semaphore.ErrNoTickets { - panic(err) - } - - // No tickets left, can't work :( - os.Exit(1) -} -```