text:
[![Code Climate](https://codeclimate.com/github/apneadiving/waterfall/badges/gpa.svg)](https://codeclimate.com/github/apneadiving/waterfall)
[![Test Coverage](https://codeclimate.com/github/apneadiving/waterfall/badges/coverage.svg)](https://codeclimate.com/github/apneadiving/waterfall/coverage)
[![Build Status](https://travis-ci.org/apneadiving/waterfall.svg?branch=master)](https://travis-ci.org/apneadiving/waterfall)
[![Gem Version](https://badge.fury.io/rb/waterfall.svg)](https://badge.fury.io/rb/waterfall)
#### Goal

Chain ruby commands, and treat them like a flow, which provides a new approach to application control flow.

When logic is complicated, waterfalls show their true power and let you write intention revealing code. Above all they excel at chaining services.

#### Material

Upcoming book about failure management patterns, leveraging the gem: [The Unhappy path](https://leanpub.com/the-unhappy-path)

General presentation blog post there: [Chain services objects like a boss](https://medium.com/p/chain-service-objects-like-a-boss-35d0b83606ab).

Reach me [@apneadiving](https://twitter.com/apneadiving)

#### Overview

A waterfall object has its own flow of commands, you can chain your commands and if something wrong happens, you dam the flow which bypasses the rest of the commands.

Here is a basic representation:
- green, the flow goes on, `chain` by `chain`
- red its bypassed and only `on_dam` blocks are executed.

![Waterfall Principle](https://apneadiving.github.io/images/waterfall_principle.png)

#### Example

```ruby
class FetchUser
  include Waterfall

  def initialize(user_id)
    @user_id = user_id
  end

  def call
    chain { @response = HTTParty.get("https://jsonplaceholder.typicode.com/users/#{@user_id}") }
    when_falsy { @response.success? }
      .dam { "Error status #{@response.code}" }
    chain(:user) { @response.body }
  end
end
```

and call / chain:

```ruby
Flow.new
    .chain(user1: :user) { FetchUser.new(1) }
    .chain(user2: :user) { FetchUser.new(2) }
    .chain  {|outflow| puts(outflow.user1, outflow.user2)  } # report success
    .on_dam {|error, context| puts(error, context) }         # report error
```

Which works like:

![Waterfall Logo](http://apneadiving.github.io/images/waterfall_full_example.png)

## Installation

For installation, in your gemfile:

    gem 'waterfall'

then `bundle` as usual.

## Waterfall mixin

### Outputs

Each waterfall has its own `outflow` and `error_pool`.

`outflow` is an Openstruct so you can get/set its property like a hash or like a standard object.

### Wiki
Wiki contains many details, please check appropriate pages:

- [Predicates](https://github.com/apneadiving/waterfall/wiki/Predicates)
- [Wf Object](https://github.com/apneadiving/waterfall/wiki/Wf-object)
- [Testing](https://github.com/apneadiving/waterfall/wiki/Testing)

### Koans (!)
You can try and exercise your understanding of Waterfall using the [Koans here](https://github.com/apneadiving/waterfall_koans)

## Illustration of chaining
Doing
```ruby
Flow.new
    .chain(foo: :bar) { Flow.new.chain(:bar){ 1 } }
```

is the same as doing:

```ruby
Flow.new
    .chain do |outflow, parent_waterfall|
      unless parent_waterfall.dammed?
        child = Wf.new.chain(:bar){ 1 }
        if child.dammed?
          parent_waterfall.dam(child.error_pool)
        else
          parent_waterfall.ouflow.foo = child.outflow.bar
        end
      end
    end
```

Hopefully you better get the chaining power this way.

## Syntactic sugar
Given:
```ruby
class MyWaterfall
  include Waterfall
  def call
    self.chain { 1 }
  end
end
```
You may have noticed that I usually write:

```ruby
Flow.new
    .chain { MyWaterfall.new }
```
instead of
```ruby
Flow.new
    .chain { MyWaterfall.new.call }
```

Both are not really the same:
- the only source of information for the gem is the return value of the block
- if it returns a `Waterfall`, it will apply chaining logic. If ever the waterfall was not executed yet, it will trigger `call`, hence the convention.
- if you call your waterfall object inside the block, the return value would be whatever your `call` method returns. So the gem doesnt know there was a waterfall involved and cannot apply chaining logic... unless you ensure `self` is always returned, which is cumbersome, so it's better to avoid this

Syntax advice
=========
```ruby
# this is valid
self
  .chain { Service1.new }
  .chain { Service2.new }

# this is equivalent
self.chain { Service1.new }
self.chain { Service2.new }

# this is equivalent too
chain { Service1.new }
chain { Service2.new }

# this is invalid Ruby due to the extra line
self
  .chain { Service1.new }

  .chain { Service2.new }
```

Tips
=========
### Error pool
For the error_pool, its up to you. But using Rails, I usually include ActiveModel::Validations in my services.

Thus you:

- have a standard way to deal with errors
- can deal with multiple errors
- support I18n out of the box
- can use your model errors out of the box

### Conditional Flow
In a service, there is one and single flow, so if you need conditionals to branch off, you can do:
```ruby
self.chain { Service1.new }

if foo?
  self.chain { Service2.new }
else
  self.chain { Service3.new }
end
```
### Halting chain
Sometimes you have a flow and you need a return value. You can use `halt_chain`, which is executed whether or not the flow is dammed. It returns what the block returns. As a consequence, it cannot be chained anymore, so it must be the last command:

```ruby
self.halt_chain do |outflow, error_pool|
  if error_pool
    # what you want to return on error
  else
    # what you want to return from the outflow
  end
end
```

### Rails and transactions
I'm used to wrap every single object involving database interactions within transactions, so it can be rolled back on error.
Here is my usual setup:
```ruby
module Waterfall
  extend ActiveSupport::Concern

  class Rollback < StandardError; end

  def with_transaction(&block)
    ActiveRecord::Base.transaction(requires_new: true) do
      yield
      on_dam do
        raise Waterfall::Rollback
      end
    end
  rescue Waterfall::Rollback
    self
  end
end
```

And to use it:
```ruby
class AuthenticateUser
  include Waterfall
  include ActiveModel::Validations

  validates :user, presence: true
  attr_reader :user

  def initialize(email, password)
    @email, @password = email, password
  end

  def call
    with_transaction do
      chain { @user = User.authenticate(@email, @password) }
      when_falsy { valid? }
        .dam { errors }
      chain(:user) { user }
    end
  end
end
```
The huge benefit is that if you call services from services, everything will be rolled back.

### Undo

If you get to dam a flow, this would trigger the `reverse_flow` method in all Services previously executed.

`reverse_flow` is not executed on the service which just failed, consider the `on_dam` hook in this case.

Take this as a hook to undo whatever you need to undo if things go wrong. Yet, you probably do not need to bother about databases inserts: this is the purpose of `with_transaction`.

### FYI

`Flow` is just an alias for the `Wf` class, so just use the one you prefer :)

Examples / Presentations
========================
- Check the [wiki for other examples](https://github.com/apneadiving/waterfall/wiki/Refactoring-examples).
- [Structure and chain your POROs](http://slides.com/apneadiving/structure-and-chain-your-poros).
- [Service objects implementations](https://slides.com/apneadiving/service-objects-waterfall-rails).
- [Handling error in Rails](https://slides.com/apneadiving/handling-error-in-ruby-rails).

Thanks
=========
Huge thanks to [robhorrigan](https://github.com/robhorrigan) for the help during infinite naming brainstorming.


text:
class Enemy : public GameCharacter
{
protected:
	bool _inAir;
	// Changes here
	bool _destroyed;
	bool _hit;
	bool _attackCalled;
	Health _health;
	int _damage;

	enum State {
		Idle,
		Walking,
		Running,
		Rising,
		Falling,
		Landing,
		Hurt,
		Dead,
		Attack
	};

	State _state;
	State _previousState;

	bool playerFound;
	int playerOnRight;

	std::map<State, Texture> _textureBank;
	std::map<State, Animation> _animationBank;
	Animation *_currentAnimation;
	AnimatedSprite _animatedSprite;

public:
	Enemy();
	void Damage(int);
	virtual void Draw(sf::RenderWindow& window, sf::Time dt);
	void DamageByPlayer(Player::State playerState, int frame);
	bool IsDestroyed() const;
};

redpajama_set_name: RedPajamaGithub


text:
Guava-Probably: Probabilistic Filters
=====================================
The Guava-Probably project provides two probabilistic filters for Guava.

[![Build Status](https://travis-ci.org/bdupras/guava-probably.svg?branch=master)](https://travis-ci.org/bdupras/guava-probably)
[![GitHub license](https://img.shields.io/github/license/bdupras/guava-probably.svg)](./LICENSE)
[![Maven Central](https://img.shields.io/maven-central/v/com.duprasville.guava/guava-probably.svg)](https://maven-badges.herokuapp.com/maven-central/com.duprasville.guava/guava-probably)

# What is it?
A probabilistic filter is a space-efficient data structure for representing a set in order to support membership queries. [ref][BroderMitzenmacher]

# How does it work?
Check out this sweet, interactive demo: [Probabilistic Filters By Example](https://bdupras.github.io/filter-tutorial/)

# What's it good for?
Probabilistic filters are great for reducing unnecessary disk, database or network queries. Applications where the universe of possible members in a set is much larger than actual members may benefit from probabilistic filters, especially when most membership queries are expected to return false.

# No really, what's it good for?
- Google Chrome uses p-filters to make a preliminary decision whether a particular web site is malicious or safe. [ref][Yakunin]
- Exim mail transfer agent uses p-filters in its rate-limiting logic. [ref][Finch]
- Use a p-filter to reject malicious authentication attempts, protecting your cache and database from botnet queries.

# Cool, how do I get it?
Requires JDK 8 or higher and Google Guava 19.0 or higher (as of 1.0).
- `1.0`: [API Docs][guava-probably-snapshot-api-docs], 05 July 2019.

To add a dependency on Guava-Probably using Maven, use the following:
```xml
<dependency>
  <groupId>com.duprasville.guava</groupId>
  <artifactId>guava-probably</artifactId>
  <version>1.0</version>
</dependency>
```

To add a dependency using Gradle:
```
dependencies {
  compile 'com.duprasville.guava:guava-probably:1.0'
}
```

# How do I learn more?
- [Probabilistic Filters By Example](https://bdupras.github.io/filter-tutorial/)
- [Cuckoo Filter: Practically Better Than Bloom](https://www.cs.cmu.edu/~dga/papers/cuckoo-conext2014.pdf)
- [Bloom Filters by Example](http://billmill.org/bloomfilter-tutorial/)
- [Google Guava BloomFilter](https://github.com/google/guava/wiki/HashingExplained#bloomfilter)
- [Network Applications of Bloom Filters: A Survey](http://projecteuclid.org/DPubS?service=UI&version=1.0&verb=Display&handle=euclid.im/1109191032)
- [Nice Bloom filter application](http://blog.alexyakunin.com/2010/03/nice-bloom-filter-application.html)
- [What use are Bloom filters, anyway?](http://fanf.livejournal.com/82764.html)

# Links
- [GitHub project](https://github.com/bdupras/guava-probably)
- [Issue tracker: report a defect or feature request](https://github.com/bdupras/guava-probably/issues/new)

[BroderMitzenmacher]: http://projecteuclid.org/DPubS?service=UI&version=1.0&verb=Display&handle=euclid.im/1109191032  "Network Applications of Bloom Filters: A Survey; Andrei Broder and Michael Mitzenmacher"
[Yakunin]: http://blog.alexyakunin.com/2010/03/nice-bloom-filter-application.html "Nice Bloom filter application"
[Finch]: http://fanf.livejournal.com/82764.html "What use are Bloom filters, anyway?"
[guava-probably-release-api-docs]: http://bdupras.github.io/guava-probably/releases/1.0/api/docs/
[guava-probably-snapshot-api-docs]: http://bdupras.github.io/guava-probably/releases/snapshot/api/docs/


text:
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ChangeListManager">
    <list default="true" id="a6685d66-de90-42d4-be33-515098ce1ba8" name="Default" comment="">
      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/add.php" />
      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/create.php" />
      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/edit.php" />
      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/list.php" />
      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/update.php" />
    </list>
    <ignored path="ftflBook.iws" />
    <ignored path=".idea/workspace.xml" />
    <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
    <option name="TRACKING_ENABLED" value="true" />
    <option name="SHOW_DIALOG" value="false" />
    <option name="HIGHLIGHT_CONFLICTS" value="true" />
    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
    <option name="LAST_RESOLUTION" value="IGNORE" />
  </component>
  <component name="ChangesViewManager" flattened_view="true" show_ignored="false" />
  <component name="CreatePatchCommitExecutor">
    <option name="PATCH_PATH" value="" />
  </component>
  <component name="DaemonCodeAnalyzer">
    <disable_hints />
  </component>
  <component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
  <component name="FavoritesManager">
    <favorites_list name="ftflBook" />
  </component>
  <component name="FileEditorManager">
    <leaf>
      <file leaf-file-name="create.php" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/create.php">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="-30.0" vertical-offset="930" max-vertical-offset="1755">
              <caret line="110" column="0" selection-start-line="110" selection-start-column="0" selection-end-line="110" selection-end-column="0" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="edit.php" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/edit.php">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="-33.125" vertical-offset="600" max-vertical-offset="1485">
              <caret line="93" column="7" selection-start-line="93" selection-start-column="7" selection-end-line="93" selection-end-column="7" />
              <folding>
                <marker date="1419850292119" expanded="true" signature="151:182" placeholder="select * fro..users..." />
              </folding>
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="update.php" pinned="false" current-in-tab="true">
        <entry file="file://$PROJECT_DIR$/update.php">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="1.119403" vertical-offset="0" max-vertical-offset="690">
              <caret line="40" column="33" selection-start-line="40" selection-start-column="33" selection-end-line="40" selection-end-column="33" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="add.php" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/add.php">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="-29.375" vertical-offset="0" max-vertical-offset="795">
              <caret line="47" column="2" selection-start-line="47" selection-start-column="2" selection-end-line="47" selection-end-column="2" />
              <folding>
                <marker date="1419850188643" expanded="true" signature="505:810" placeholder="INSERT INTO ..." />
              </folding>
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="list.php" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/list.php">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="-33.125" vertical-offset="285" max-vertical-offset="1170">
              <caret line="72" column="0" selection-start-line="72" selection-start-column="0" selection-end-line="72" selection-end-column="0" />
              <folding>
                <marker date="1419850260055" expanded="true" signature="99:118" placeholder="select * fro..users..." />
              </folding>
            </state>
          </provider>
        </entry>
      </file>
    </leaf>
  </component>
  <component name="FindManager">
    <FindUsagesManager>
      <setting name="OPEN_NEW_TAB" value="true" />
    </FindUsagesManager>
  </component>
  <component name="Git.Settings">
    <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
  </component>
  <component name="IdeDocumentHistory">
    <option name="changedFiles">
      <list>
        <option value="$PROJECT_DIR$/add.php" />
        <option value="$PROJECT_DIR$/list.php" />
        <option value="$PROJECT_DIR$/create.php" />
        <option value="$PROJECT_DIR$/edit.php" />
        <option value="$PROJECT_DIR$/update.php" />
      </list>
    </option>
  </component>
  <component name="PhpWorkspaceProjectConfiguration" backward_compatibility_performed="true" />
  <component name="ProjectFrameBounds">
    <option name="x" value="42" />
    <option name="y" value="34" />
    <option name="width" value="1205" />
    <option name="height" value="972" />
  </component>
  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
    <OptionsSetting value="true" id="Add" />
    <OptionsSetting value="true" id="Remove" />
    <OptionsSetting value="true" id="Checkout" />
    <OptionsSetting value="true" id="Update" />
    <OptionsSetting value="true" id="Status" />
    <OptionsSetting value="true" id="Edit" />
    <ConfirmationsSetting value="2" id="Add" />
    <ConfirmationsSetting value="0" id="Remove" />
  </component>
  <component name="ProjectReloadState">
    <option name="STATE" value="0" />
  </component>
  <component name="ProjectView">
    <navigator currentView="ProjectPane" proportions="" version="1">
      <flattenPackages />
      <showMembers />
      <showModules />
      <showLibraryContents />
      <hideEmptyPackages />
      <abbreviatePackageNames />
      <autoscrollToSource />
      <autoscrollFromSource />
      <sortByType />
    </navigator>
    <panes>
      <pane id="Scope" />
      <pane id="ProjectPane">
        <subPane>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="ftflBook" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="ftflBook" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="ftflBook" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
        </subPane>
      </pane>
    </panes>
  </component>
  <component name="PropertiesComponent">
    <property name="WebServerToolWindowFactoryState" value="false" />
  </component>
  <component name="RunManager">
    <configuration default="true" type="JavascriptDebugType" factoryName="JavaScript Debug">
      <method />
    </configuration>
    <configuration default="true" type="PhpUnitRemoteRunConfigurationType" factoryName="PHPUnit on Server">
      <method />
    </configuration>
    <configuration default="true" type="PHPUnitRunConfigurationType" factoryName="PHPUnit">
      <TestRunner />
      <method />
    </configuration>
    <configuration default="true" type="PhpLocalRunConfigurationType" factoryName="PHP Console">
      <method />
    </configuration>
    <configuration default="true" type="PhpBehatConfigurationType" factoryName="Behat">
      <BehatRunner />
      <method />
    </configuration>
    <configuration default="true" type="js.build_tools.gulp" factoryName="Gulp.js">
      <method />
    </configuration>
    <list size="0" />
  </component>
  <component name="ShelveChangesManager" show_recycled="false" />
  <component name="SvnConfiguration">
    <configuration />
  </component>
  <component name="TaskManager">
    <task active="true" id="Default" summary="Default task">
      <changelist id="a6685d66-de90-42d4-be33-515098ce1ba8" name="Default" comment="" />
      <created>1419850081499</created>
      <option name="number" value="Default" />
      <updated>1419850081499</updated>
    </task>
    <servers />
  </component>
  <component name="ToolWindowManager">
    <frame x="42" y="34" width="1205" height="972" extended-state="0" />
    <editor active="false" />
    <layout>
      <window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
      <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.2514523" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
      <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
      <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
      <window_info id="Application Servers" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
      <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
      <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
      <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
      <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.32990867" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
      <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
      <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
      <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
      <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
      <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="SLIDING" type="SLIDING" visible="false" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
      <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
      <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
      <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
      <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
    </layout>
  </component>
  <component name="Vcs.Log.UiProperties">
    <option name="RECENTLY_FILTERED_USER_GROUPS">
      <collection />
    </option>
    <option name="RECENTLY_FILTERED_BRANCH_GROUPS">
      <collection />
    </option>
  </component>
  <component name="VcsContentAnnotationSettings">
    <option name="myLimit" value="2678400000" />
  </component>
  <component name="VcsManagerConfiguration">
    <option name="myTodoPanelSettings">
      <TodoPanelSettings />
    </option>
  </component>
  <component name="XDebuggerManager">
    <breakpoint-manager>
      <breakpoints>
        <line-breakpoint enabled="true" type="php">
          <url>file://$PROJECT_DIR$/add.php</url>
        </line-breakpoint>
      </breakpoints>
      <option name="time" value="1" />
    </breakpoint-manager>
    <watches-manager />
  </component>
  <component name="editorHistoryManager">
    <entry file="file://$PROJECT_DIR$/add.php">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="-29.375" vertical-offset="0" max-vertical-offset="795">
          <caret line="47" column="2" selection-start-line="47" selection-start-column="2" selection-end-line="47" selection-end-column="2" />
          <folding>
            <marker date="1419850188643" expanded="true" signature="505:810" placeholder="INSERT INTO ..." />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/list.php">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="-33.125" vertical-offset="285" max-vertical-offset="1170">
          <caret line="72" column="0" selection-start-line="72" selection-start-column="0" selection-end-line="72" selection-end-column="0" />
          <folding>
            <marker date="1419850260055" expanded="true" signature="99:118" placeholder="select * fro..users..." />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/create.php">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="-30.0" vertical-offset="930" max-vertical-offset="1755">
          <caret line="110" column="0" selection-start-line="110" selection-start-column="0" selection-end-line="110" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/edit.php">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="-33.125" vertical-offset="600" max-vertical-offset="1485">
          <caret line="93" column="7" selection-start-line="93" selection-start-column="7" selection-end-line="93" selection-end-column="7" />
          <folding>
            <marker date="1419850292119" expanded="true" signature="151:182" placeholder="select * fro..users..." />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/update.php">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="1.119403" vertical-offset="0" max-vertical-offset="690">
          <caret line="40" column="33" selection-start-line="40" selection-start-column="33" selection-end-line="40" selection-end-column="33" />
          <folding />
        </state>
      </provider>
    </entry>
  </component>
</project>


text:
    <igz-splash-screen data-is-splash-showed="$ctrl.isSplashShowed"></igz-splash-screen>

    <igz-info-page-filters data-is-filters-showed="$ctrl.isFiltersShowed.value"
                           data-apply-filters="$ctrl.onApplyFilters(false)"
                           data-reset-filters="$ctrl.onResetFilters(false)"
                           data-change-state-callback="$ctrl.isFiltersShowed.changeValue(newVal)"
                           data-toggle-method="$ctrl.toggleFilters()">

        <igz-search-input class="info-page-filters-item igz-component"
                          data-data-set="$ctrl.projects"
                          data-search-keys="$ctrl.searchKeys"
                          data-search-callback="$ctrl.onUpdateFiltersCounter(searchQuery)"
                          data-placeholder="{{ 'functions:PLACEHOLDER.SEARCH_PROJECTS' | i18next }}"
                          data-live-search="false"
                          data-search-states="$ctrl.searchStates">
        </igz-search-input>
    </igz-info-page-filters>

    <igz-info-page-actions-bar class="igz-component">

            <igz-action-panel data-actions="$ctrl.projectActions">
            </igz-action-panel>

            <button class="project-import-input"
                    ngf-select="$ctrl.importProject($file)"
                    accept=".yml, .yaml">
            </button>

                <igz-default-dropdown data-select-property-only="id"
                                      data-placeholder="{{ 'functions:PLACEHOLDER.ACTIONS' | i18next }}"
                                      data-values-array="$ctrl.dropdownActions"
                                      data-item-select-callback="$ctrl.onSelectDropdownAction(item)"
                                      data-skip-selection="true">
                </igz-default-dropdown>
                <button class="ncl-new-entity-button igz-button-primary"
                        data-ng-click="$ctrl.openNewProjectDialog()">
                    {{ 'functions:NEW_PROJECT' | i18next }}
                </button>
                <button class="ncl-new-entity-button igz-button-primary"
                        data-ng-click="$ctrl.openNewFunctionScreen()">
                    {{ 'functions:NEW_FUNCTION' | i18next }}
                </button>

                        <igz-action-item-refresh
                                data-refresh="$ctrl.refreshProjects()">
                        </igz-action-item-refresh>
                        <igz-sort-dropdown class="igz-component pull-left"
                                           data-sort-options="$ctrl.sortOptions"
                                           data-selected-option="$ctrl.sortedColumnName"
                                           data-reverse-sorting="$ctrl.isReverseSorting"
                                           data-on-sort-change="$ctrl.onSortOptionsChange(option)">
                        </igz-sort-dropdown>

            <igz-actions-panes data-filters-toggle-method="$ctrl.toggleFilters()"
                               data-filters-counter="$ctrl.filtersCounter"
                               data-show-filter-icon="true"
                               data-is-filters-opened="$ctrl.isFiltersShowed.value">
            </igz-actions-panes>

    </igz-info-page-actions-bar>

    <igz-info-page-content class="igz-component">

                    <igz-action-checkbox-all class="check-all-rows"
                                             data-items-count="$ctrl.projects.length"
                                             data-items-type="{{$ctrl.projectsService.checkedItem}}">
                    </igz-action-checkbox-all>

                        {{ 'common:NAME' | i18next }}

                        {{ 'common:DESCRIPTION' | i18next }}

                {{ 'functions:PROJECTS_NOT_FOUND' | i18next }}

                                <ncl-project-table-row
                                        data-is-splash-showed="$ctrl.isSplashShowed"
                                        data-project="project"
                                        data-project-action-handler-callback="$ctrl.handleProjectAction(actionType, checkedItems)"
                                        data-projects-list="$ctrl.projects">
                                </ncl-project-table-row>

    </igz-info-page-content>


text:
using LANSearch.Data;
using LANSearch.Models.Admin;
using LANSearch.Modules.BaseClasses;
using Nancy;
using Nancy.Security;

namespace LANSearch.Modules.Admin
{
    public class FeedbackModule : AdminModule
    {
        public FeedbackModule()
        {
            Get["/Feedback"] = x =>
            {
                var model = GetFeedbackModel(Request);
                return View["Admin/Feedback.cshtml", model];
            };
            Post["/Feedback"] = x =>
            {
                try
                {
                    this.ValidateCsrfToken();
                }
                catch (CsrfValidationException)
                {
                    return Response.AsText("CSRF Token is invalid.").WithStatusCode(403);
                }
                int id;
                if (int.TryParse(Request.Form.delete, out id))
                {
                        Ctx.FeedbackManager.SetDeleted(id);
                }
                else if (int.TryParse(Request.Form.read, out id))
                {
                    Ctx.FeedbackManager.SetRead(id, true);
                }
                return Response.AsRedirect("/Admin/Feedback");
            };
        }

        public FeedbackModel GetFeedbackModel(Request request)
        {
            var feedback = new FeedbackModel(new UrlBuilder(Request.Url));
            bool showDeleted = false, showOnlyNew = false;
            foreach (var qs in request.Query)
            {
                var qsKey = qs as string;
                if (qsKey == null) continue;
                switch (qsKey)
                {
                    case "p":
                        int page;
                        if (int.TryParse(request.Query["p"], out page))
                            feedback.Page = page;
                        break;

                    case "ps":
                        int pagesize;
                        if (int.TryParse(request.Query["ps"], out pagesize))
                        {
                            feedback.PageSize = pagesize;
                        }
                        break;

                    case "sn":
                        showOnlyNew = true;
                        break;

                    case "sd":
                        showDeleted = true;
                        break;
                }
            }

            if (feedback.Page < 0)
                feedback.Page = 0;
            if (feedback.PageSize < 20)
                feedback.PageSize = 20;

            int count = 0;
            feedback.Feedbacks = Ctx.FeedbackManager.GetPaged(feedback.Page, feedback.PageSize, out count, showOnlyNew, showDeleted);
            feedback.Count = count;

            return feedback;
        }
    }
}


text:
package co.cask.tephra;

import co.cask.tephra.persist.TransactionSnapshot;
import co.cask.tephra.persist.TransactionStateStorage;
import com.google.common.collect.ImmutableSet;
import org.junit.Assert;
import org.junit.Test;

import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.TimeUnit;

/**
 *
 */
public abstract class TransactionSystemTest {

  public static final byte[] C1 = new byte[] { 'c', '1' };
  public static final byte[] C2 = new byte[] { 'c', '2' };
  public static final byte[] C3 = new byte[] { 'c', '3' };
  public static final byte[] C4 = new byte[] { 'c', '4' };

  protected abstract TransactionSystemClient getClient() throws Exception;

  protected abstract TransactionStateStorage getStateStorage() throws Exception;

  @Test
  public void testCommitRaceHandling() throws Exception {
    TransactionSystemClient client1 = getClient();
    TransactionSystemClient client2 = getClient();

    Transaction tx1 = client1.startShort();
    Transaction tx2 = client2.startShort();

    Assert.assertTrue(client1.canCommit(tx1, asList(C1, C2)));
    // second one also can commit even thought there are conflicts with first since first one hasn't committed yet
    Assert.assertTrue(client2.canCommit(tx2, asList(C2, C3)));

    Assert.assertTrue(client1.commit(tx1));

    // now second one should not commit, since there are conflicts with tx1 that has been committed
    Assert.assertFalse(client2.commit(tx2));
  }

  @Test
  public void testMultipleCommitsAtSameTime() throws Exception {
    // We want to check that if two txs finish at same time (wrt tx manager) they do not overwrite changesets of each
    // other in tx manager used for conflicts detection (we had this bug)
    // NOTE: you don't have to use multiple clients for that
    TransactionSystemClient client1 = getClient();
    TransactionSystemClient client2 = getClient();
    TransactionSystemClient client3 = getClient();
    TransactionSystemClient client4 = getClient();
    TransactionSystemClient client5 = getClient();

    Transaction tx1 = client1.startShort();
    Transaction tx2 = client2.startShort();
    Transaction tx3 = client3.startShort();
    Transaction tx4 = client4.startShort();
    Transaction tx5 = client5.startShort();

    Assert.assertTrue(client1.canCommit(tx1, asList(C1)));
    Assert.assertTrue(client1.commit(tx1));

    Assert.assertTrue(client2.canCommit(tx2, asList(C2)));
    Assert.assertTrue(client2.commit(tx2));

    // verifying conflicts detection
    Assert.assertFalse(client3.canCommit(tx3, asList(C1)));
    Assert.assertFalse(client4.canCommit(tx4, asList(C2)));
    Assert.assertTrue(client5.canCommit(tx5, asList(C3)));
  }

  @Test
  public void testCommitTwice() throws Exception {
    TransactionSystemClient client = getClient();
    Transaction tx = client.startShort();

    Assert.assertTrue(client.canCommit(tx, asList(C1, C2)));
    Assert.assertTrue(client.commit(tx));
    // cannot commit twice same tx
    try {
      Assert.assertFalse(client.commit(tx));
      Assert.fail();
    } catch (TransactionNotInProgressException e) {
      // expected
    }
  }

  @Test
  public void testAbortTwice() throws Exception {
    TransactionSystemClient client = getClient();
    Transaction tx = client.startShort();

    Assert.assertTrue(client.canCommit(tx, asList(C1, C2)));
    client.abort(tx);
    // abort of not active tx has no affect
    client.abort(tx);
  }

  @Test
  public void testReuseTx() throws Exception {
    TransactionSystemClient client = getClient();
    Transaction tx = client.startShort();

    Assert.assertTrue(client.canCommit(tx, asList(C1, C2)));
    Assert.assertTrue(client.commit(tx));
    // can't re-use same tx again
    try {
      client.canCommit(tx, asList(C3, C4));
      Assert.fail();
    } catch (TransactionNotInProgressException e) {
      // expected
    }
    try {
      Assert.assertFalse(client.commit(tx));
      Assert.fail();
    } catch (TransactionNotInProgressException e) {
      // expected
    }

    // abort of not active tx has no affect
    client.abort(tx);
  }

  @Test
  public void testUseNotStarted() throws Exception {
    TransactionSystemClient client = getClient();
    Transaction tx1 = client.startShort();
    Assert.assertTrue(client.commit(tx1));

    // we know this is one is older than current writePointer and was not used
    Transaction txOld = new Transaction(tx1.getReadPointer(), tx1.getTransactionId() - 1,
                                        new long[] {}, new long[] {}, Transaction.NO_TX_IN_PROGRESS,
                                        TransactionType.SHORT);
    try {
      Assert.assertFalse(client.canCommit(txOld, asList(C3, C4)));
      Assert.fail();
    } catch (TransactionNotInProgressException e) {
      // expected
    }
    try {
      Assert.assertFalse(client.commit(txOld));
      Assert.fail();
    } catch (TransactionNotInProgressException e) {
      // expected
    }
    // abort of not active tx has no affect
    client.abort(txOld);

    // we know this is one is newer than current readPointer and was not used
    Transaction txNew = new Transaction(tx1.getReadPointer(), tx1.getTransactionId() + 1,
                                        new long[] {}, new long[] {}, Transaction.NO_TX_IN_PROGRESS,
                                        TransactionType.SHORT);
    try {
      Assert.assertFalse(client.canCommit(txNew, asList(C3, C4)));
      Assert.fail();
    } catch (TransactionNotInProgressException e) {
      // expected
    }
    try {
      Assert.assertFalse(client.commit(txNew));
      Assert.fail();
    } catch (TransactionNotInProgressException e) {
      // expected
    }
    // abort of not active tx has no affect
    client.abort(txNew);
  }

  @Test
  public void testAbortAfterCommit() throws Exception {
    TransactionSystemClient client = getClient();
    Transaction tx = client.startShort();

    Assert.assertTrue(client.canCommit(tx, asList(C1, C2)));
    Assert.assertTrue(client.commit(tx));
    // abort of not active tx has no affect
    client.abort(tx);
  }

  // todo add test invalidate method
  @Test
  public void testInvalidateTx() throws Exception {
    TransactionSystemClient client = getClient();
    // Invalidate an in-progress tx
    Transaction tx1 = client.startShort();
    client.canCommit(tx1, asList(C1, C2));
    Assert.assertTrue(client.invalidate(tx1.getTransactionId()));
    // Cannot invalidate a committed tx
    Transaction tx2 = client.startShort();
    client.canCommit(tx2, asList(C3, C4));
    client.commit(tx2);
    Assert.assertFalse(client.invalidate(tx2.getTransactionId()));
  }

  @Test
  public void testResetState() throws Exception {
    // have tx in progress, committing and committed then reset,
    // get the last snapshot and see that it is empty
    TransactionSystemClient client = getClient();
    TransactionStateStorage stateStorage = getStateStorage();

    Transaction tx1 = client.startShort();
    Transaction tx2 = client.startShort();
    client.canCommit(tx1, asList(C1, C2));
    client.commit(tx1);
    client.canCommit(tx2, asList(C3, C4));

    Transaction txPreReset = client.startShort();
    long currentTs = System.currentTimeMillis();
    client.resetState();

    TransactionSnapshot snapshot = stateStorage.getLatestSnapshot();
    Assert.assertTrue(snapshot.getTimestamp() >= currentTs);
    Assert.assertEquals(0, snapshot.getInvalid().size());
    Assert.assertEquals(0, snapshot.getInProgress().size());
    Assert.assertEquals(0, snapshot.getCommittingChangeSets().size());
    Assert.assertEquals(0, snapshot.getCommittedChangeSets().size());

    // confirm that transaction IDs are not reset
    Transaction txPostReset = client.startShort();
    Assert.assertTrue("New tx ID should be greater than last ID before reset",
                      txPostReset.getTransactionId() > txPreReset.getTransactionId());
  }

  @Test
  public void testTruncateInvalidTx() throws Exception {
    // Start few transactions and invalidate all of them
    TransactionSystemClient client = getClient();
    Transaction tx1 = client.startLong();
    Transaction tx2 = client.startShort();
    Transaction tx3 = client.startLong();

    client.invalidate(tx1.getTransactionId());
    client.invalidate(tx2.getTransactionId());
    client.invalidate(tx3.getTransactionId());

    // Remove tx2 and tx3 from invalid list
    Assert.assertTrue(client.truncateInvalidTx(ImmutableSet.of(tx2.getTransactionId(), tx3.getTransactionId())));

    Transaction tx = client.startShort();
    // Only tx1 should be in invalid list now
    Assert.assertArrayEquals(new long[] {tx1.getTransactionId()}, tx.getInvalids());
    client.abort(tx);
  }

  @Test
  public void testTruncateInvalidTxBefore() throws Exception {
    // Start few transactions
    TransactionSystemClient client = getClient();
    Transaction tx1 = client.startLong();
    Transaction tx2 = client.startShort();
    // Sleep so that transaction ids get generated a millisecond apart for assertion
    // TEPHRA-63 should eliminate the need to sleep
    TimeUnit.MILLISECONDS.sleep(1);
    long beforeTx3 = System.currentTimeMillis();
    Transaction tx3 = client.startLong();

    try {
      // throws exception since tx1 and tx2 are still in-progress
      client.truncateInvalidTxBefore(beforeTx3);
      Assert.fail("Expected InvalidTruncateTimeException exception");
    } catch (InvalidTruncateTimeException e) {
      // Expected exception
    }

    // Invalidate all of them
    client.invalidate(tx1.getTransactionId());
    client.invalidate(tx2.getTransactionId());
    client.invalidate(tx3.getTransactionId());

    // Remove transactions before time beforeTx3
    Assert.assertTrue(client.truncateInvalidTxBefore(beforeTx3));

    Transaction tx = client.startShort();
    // Only tx3 should be in invalid list now
    Assert.assertArrayEquals(new long[] {tx3.getTransactionId()}, tx.getInvalids());
    client.abort(tx);
  }

  @Test
  public void testGetInvalidSize() throws Exception {
    // Start few transactions and invalidate all of them
    TransactionSystemClient client = getClient();
    Transaction tx1 = client.startLong();
    Transaction tx2 = client.startShort();
    Transaction tx3 = client.startLong();

    Assert.assertEquals(0, client.getInvalidSize());

    client.invalidate(tx1.getTransactionId());
    client.invalidate(tx2.getTransactionId());
    client.invalidate(tx3.getTransactionId());

    Assert.assertEquals(3, client.getInvalidSize());
  }

  private Collection<byte[]> asList(byte[]... val) {
    return Arrays.asList(val);
  }
}


text:
/*
  Our Transform type is always respresented relative to
  `transform-origin: 0px 0px`. This is different from the browser's
  own `transform` property, which will vary based on the present value
  of `transform-origin`, and which defaults to `50% 50%`. I am
  standardizing on zero because it disentangles our coordinate system
  from the size of the element, which can vary over time.

  Conceptually, each of our Transforms is a 2d affine transformation
  representd as a 3x3 matrix:

      a c tx
      b d ty
      0 0  1
*/

export default class Transform {
  constructor(
    readonly a: number,
    readonly b: number,
    readonly c: number,
    readonly d: number,
    readonly tx: number,
    readonly ty: number,
  ) {}

  serialize(): string {
    return `matrix(${this.a}, ${this.b}, ${this.c}, ${this.d}, ${this.tx}, ${this.ty})`;
  }

  // See the comment below on `const identity`.
  isIdentity(): boolean {
    return (
      this === identity ||
      (this.a === 1 &&
        this.b === 0 &&
        this.c === 0 &&
        this.d === 1 &&
        this.tx === 0 &&
        this.ty === 0)
    );
  }

  mult(other: Transform): Transform {
    // This is deliberately not isIdentity(). I'm optimizing for the
    // case where there was no preexisting transform at all.
    if (this === identity) {
      return other;
    }
    if (other === identity) {
      return this;
    }
    return new Transform(
      this.a * other.a + this.c * other.b,
      this.b * other.a + this.d * other.b,
      this.a * other.c + this.c * other.d,
      this.b * other.c + this.d * other.d,
      this.a * other.tx + this.c * other.ty + this.tx,
      this.b * other.tx + this.d * other.ty + this.ty,
    );
  }
}

// WARNING: this constant matrix exists as an optimization. But not
// every no-op transform triple-equals this value. If you apply two
// transforms that cancel each other out, you will get an identity
// matrix but it will not triple-equal this one. And that is OK: we
// use the triple-equality as an optimization only, not for
// correctness.
//
// The optimization should be worthwhile because the majority of
// things start out with no preexisting Transform, which we can
// represent as `identity`, which will make identity.mult(something) a
// no-op, etc.
export const identity = new Transform(1, 0, 0, 1, 0, 0);

const matrixPattern = /matrix\((.*)\)/;

function parseTransform(matrixString: string): Transform {
  let match = matrixPattern.exec(matrixString);
  if (!match) {
    return identity;
  }
  let [a, b, c, d, tx, ty] = match[1].split(',').map(parseFloat);
  return new Transform(a, b, c, d, tx, ty);
}

function parseOrigin(originString: string): [number, number] {
  return originString.split(' ').map(parseFloat) as [number, number];
}

/**
  Returns a Transform instance representing the cumulative CSS
  transform of this element and all its ancestors.

  @function cumulativeTransform
  @hide
  @param {HTMLElement} elt
  @return {Transform}
*/
export function cumulativeTransform(elt: HTMLElement) {
  let accumulator = null;
  let current: HTMLElement | null = elt;
  while (current && current.nodeType === 1) {
    let transform = ownTransform(current);
    if (transform !== identity && !transform.isIdentity()) {
      if (accumulator) {
        accumulator = transform.mult(accumulator);
      } else {
        accumulator = transform;
      }
    }
    current = current.parentElement;
  }
  return accumulator || identity;
}

/**
  Returns a Transform instance representing the CSS transform of this
  element.

 * @function ownTransform
 * @param {HTMLElement} elt
 * @return {Transform} instance representing this element's css transform property.
 */
export function ownTransform(elt: HTMLElement): Transform {
  let eltStyles = window.getComputedStyle(elt);
  let t =
    eltStyles.transform !== '' ? eltStyles.transform! : elt.style.transform!;
  if (t === 'none') {
    // This constant value is an optimization, and we rely on that in
    // cumulativeTransform
    return identity;
  }
  let matrix = parseTransform(t);
  if (matrix.a !== 1 || matrix.b !== 0 || matrix.c !== 0 || matrix.d !== 1) {
    // If there is any rotation, scaling, or skew we need to do it within the context of transform-origin.
    let origin =
      eltStyles.getPropertyValue('transform-origin') !== ''
        ? eltStyles.getPropertyValue('transform-origin')!
        : elt.style.getPropertyValue('transform-origin')!;
    let [originX, originY] = parseOrigin(origin);
    if (originX === 0 && originY === 0) {
      // transform origin is at 0,0 so it will have no effect, so we're done.
      return matrix;
    }

    return new Transform(1, 0, 0, 1, originX, originY)
      .mult(matrix)
      .mult(new Transform(1, 0, 0, 1, -originX, -originY));
  } else {
    // This case is an optimization for when there is only translation.
    return matrix;
  }
}


text:
```shell
$ npm install
$ npm start
```

# Example Requests
```shell
$ curl -ivX GET 'http://localhost:3001/hello'
$ curl -ivX GET 'http://localhost:3001/user'
```