text:
.class final Lcom/android/server/hdmi/SendKeyAction;
.super Lcom/android/server/hdmi/HdmiCecFeatureAction;
.source "SendKeyAction.java"

# static fields
.field private static final AWAIT_LONGPRESS_MS:I = 0x190

.field private static final AWAIT_RELEASE_KEY_MS:I = 0x3e8

.field private static final STATE_CHECKING_LONGPRESS:I = 0x1

.field private static final STATE_PROCESSING_KEYCODE:I = 0x2

.field private static final TAG:Ljava/lang/String; = "SendKeyAction"

# instance fields
.field private mLastKeycode:I

.field private mLastSendKeyTime:J

.field private final mTargetAddress:I

# direct methods
.method constructor <init>(Lcom/android/server/hdmi/HdmiCecLocalDevice;II)V
    .locals 0
    .param p1, "source"    # Lcom/android/server/hdmi/HdmiCecLocalDevice;
    .param p2, "targetAddress"    # I
    .param p3, "keycode"    # I

    .prologue
    .line 76
    invoke-direct {p0, p1}, Lcom/android/server/hdmi/HdmiCecFeatureAction;-><init>(Lcom/android/server/hdmi/HdmiCecLocalDevice;)V

    .line 77
    iput p2, p0, Lcom/android/server/hdmi/SendKeyAction;->mTargetAddress:I

    .line 78
    iput p3, p0, Lcom/android/server/hdmi/SendKeyAction;->mLastKeycode:I

    .line 79
    return-void
.end method

.method private getCurrentTime()J
    .locals 2

    .prologue
    .line 97
    invoke-static {}, Ljava/lang/System;->currentTimeMillis()J

    move-result-wide v0

    return-wide v0
.end method

.method private sendKeyDown(I)V
    .locals 3
    .param p1, "keycode"    # I

    .prologue
    .line 145
    invoke-static {p1}, Lcom/android/server/hdmi/HdmiCecKeycode;->androidKeyToCecKey(I)[B

    move-result-object v0

    .line 146
    .local v0, "cecKeycodeAndParams":[B
    if-nez v0, :cond_0

    .line 151
    :goto_0
    return-void

    .line 149
    :cond_0
    invoke-virtual {p0}, Lcom/android/server/hdmi/SendKeyAction;->getSourceAddress()I

    move-result v1

    iget v2, p0, Lcom/android/server/hdmi/SendKeyAction;->mTargetAddress:I

    invoke-static {v1, v2, v0}, Lcom/android/server/hdmi/HdmiCecMessageBuilder;->buildUserControlPressed(II[B)Lcom/android/server/hdmi/HdmiCecMessage;

    move-result-object v1

    invoke-virtual {p0, v1}, Lcom/android/server/hdmi/SendKeyAction;->sendCommand(Lcom/android/server/hdmi/HdmiCecMessage;)V

    goto :goto_0
.end method

.method private sendKeyUp()V
    .locals 2

    .prologue
    .line 154
    invoke-virtual {p0}, Lcom/android/server/hdmi/SendKeyAction;->getSourceAddress()I

    move-result v0

    iget v1, p0, Lcom/android/server/hdmi/SendKeyAction;->mTargetAddress:I

    invoke-static {v0, v1}, Lcom/android/server/hdmi/HdmiCecMessageBuilder;->buildUserControlReleased(II)Lcom/android/server/hdmi/HdmiCecMessage;

    move-result-object v0

    invoke-virtual {p0, v0}, Lcom/android/server/hdmi/SendKeyAction;->sendCommand(Lcom/android/server/hdmi/HdmiCecMessage;)V

    .line 156
    return-void
.end method

# virtual methods
.method public handleTimerEvent(I)V
    .locals 2
    .param p1, "state"    # I

    .prologue
    .line 166
    iget v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mState:I

    packed-switch v0, :pswitch_data_0

    .line 181
    const-string v0, "SendKeyAction"

    const-string v1, "Not in a valid state"

    invoke-static {v0, v1}, Landroid/util/Slog;->w(Ljava/lang/String;Ljava/lang/String;)I

    .line 184
    :goto_0
    return-void

    .line 169
    :pswitch_0
    iget-object v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mActionTimer:Lcom/android/server/hdmi/HdmiCecFeatureAction$ActionTimer;

    invoke-interface {v0}, Lcom/android/server/hdmi/HdmiCecFeatureAction$ActionTimer;->clearTimerMessage()V

    .line 170
    const/4 v0, 0x2

    iput v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mState:I

    .line 171
    iget v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mLastKeycode:I

    invoke-direct {p0, v0}, Lcom/android/server/hdmi/SendKeyAction;->sendKeyDown(I)V

    .line 172
    invoke-direct {p0}, Lcom/android/server/hdmi/SendKeyAction;->getCurrentTime()J

    move-result-wide v0

    iput-wide v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mLastSendKeyTime:J

    .line 173
    iget v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mState:I

    const/16 v1, 0x3e8

    invoke-virtual {p0, v0, v1}, Lcom/android/server/hdmi/SendKeyAction;->addTimer(II)V

    goto :goto_0

    .line 177
    :pswitch_1
    invoke-direct {p0}, Lcom/android/server/hdmi/SendKeyAction;->sendKeyUp()V

    .line 178
    invoke-virtual {p0}, Lcom/android/server/hdmi/SendKeyAction;->finish()V

    goto :goto_0

    .line 166
    nop

    :pswitch_data_0
    .packed-switch 0x1
        :pswitch_0
        :pswitch_1
    .end packed-switch
.end method

.method public processCommand(Lcom/android/server/hdmi/HdmiCecMessage;)Z
    .locals 1
    .param p1, "cmd"    # Lcom/android/server/hdmi/HdmiCecMessage;

    .prologue
    .line 161
    const/4 v0, 0x0

    return v0
.end method

.method processKeyEvent(IZ)V
    .locals 4
    .param p1, "keycode"    # I
    .param p2, "isPressed"    # Z

    .prologue
    .line 107
    iget v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mState:I

    const/4 v1, 0x1

    if-eq v0, v1, :cond_1

    iget v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mState:I

    const/4 v1, 0x2

    if-eq v0, v1, :cond_1

    .line 108
    const-string v0, "SendKeyAction"

    const-string v1, "Not in a valid state"

    invoke-static {v0, v1}, Landroid/util/Slog;->w(Ljava/lang/String;Ljava/lang/String;)I

    .line 142
    :cond_0
    :goto_0
    return-void

    .line 111
    :cond_1
    if-eqz p2, :cond_4

    .line 114
    iget v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mLastKeycode:I

    if-eq p1, v0, :cond_2

    .line 115
    invoke-direct {p0, p1}, Lcom/android/server/hdmi/SendKeyAction;->sendKeyDown(I)V

    .line 116
    invoke-direct {p0}, Lcom/android/server/hdmi/SendKeyAction;->getCurrentTime()J

    move-result-wide v0

    iput-wide v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mLastSendKeyTime:J

    .line 117
    invoke-static {p1}, Lcom/android/server/hdmi/HdmiCecKeycode;->isRepeatableKey(I)Z

    move-result v0

    if-nez v0, :cond_3

    .line 118
    invoke-direct {p0}, Lcom/android/server/hdmi/SendKeyAction;->sendKeyUp()V

    .line 119
    invoke-virtual {p0}, Lcom/android/server/hdmi/SendKeyAction;->finish()V

    goto :goto_0

    .line 126
    :cond_2
    invoke-direct {p0}, Lcom/android/server/hdmi/SendKeyAction;->getCurrentTime()J

    move-result-wide v0

    iget-wide v2, p0, Lcom/android/server/hdmi/SendKeyAction;->mLastSendKeyTime:J

    sub-long/2addr v0, v2

    const-wide/16 v2, 0x12c

    cmp-long v0, v0, v2

    if-ltz v0, :cond_3

    .line 127
    invoke-direct {p0, p1}, Lcom/android/server/hdmi/SendKeyAction;->sendKeyDown(I)V

    .line 128
    invoke-direct {p0}, Lcom/android/server/hdmi/SendKeyAction;->getCurrentTime()J

    move-result-wide v0

    iput-wide v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mLastSendKeyTime:J

    .line 131
    :cond_3
    iget-object v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mActionTimer:Lcom/android/server/hdmi/HdmiCecFeatureAction$ActionTimer;

    invoke-interface {v0}, Lcom/android/server/hdmi/HdmiCecFeatureAction$ActionTimer;->clearTimerMessage()V

    .line 132
    iget v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mState:I

    const/16 v1, 0x3e8

    invoke-virtual {p0, v0, v1}, Lcom/android/server/hdmi/SendKeyAction;->addTimer(II)V

    .line 133
    iput p1, p0, Lcom/android/server/hdmi/SendKeyAction;->mLastKeycode:I

    goto :goto_0

    .line 137
    :cond_4
    iget v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mLastKeycode:I

    if-ne p1, v0, :cond_0

    .line 138
    invoke-direct {p0}, Lcom/android/server/hdmi/SendKeyAction;->sendKeyUp()V

    .line 139
    invoke-virtual {p0}, Lcom/android/server/hdmi/SendKeyAction;->finish()V

    goto :goto_0
.end method

.method public start()Z
    .locals 3

    .prologue
    const/4 v2, 0x1

    .line 83
    iget v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mLastKeycode:I

    invoke-direct {p0, v0}, Lcom/android/server/hdmi/SendKeyAction;->sendKeyDown(I)V

    .line 84
    invoke-direct {p0}, Lcom/android/server/hdmi/SendKeyAction;->getCurrentTime()J

    move-result-wide v0

    iput-wide v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mLastSendKeyTime:J

    .line 86
    iget v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mLastKeycode:I

    invoke-static {v0}, Lcom/android/server/hdmi/HdmiCecKeycode;->isRepeatableKey(I)Z

    move-result v0

    if-nez v0, :cond_0

    .line 87
    invoke-direct {p0}, Lcom/android/server/hdmi/SendKeyAction;->sendKeyUp()V

    .line 88
    invoke-virtual {p0}, Lcom/android/server/hdmi/SendKeyAction;->finish()V

    .line 93
    :goto_0
    return v2

    .line 91
    :cond_0
    iput v2, p0, Lcom/android/server/hdmi/SendKeyAction;->mState:I

    .line 92
    iget v0, p0, Lcom/android/server/hdmi/SendKeyAction;->mState:I

    const/16 v1, 0x190

    invoke-virtual {p0, v0, v1}, Lcom/android/server/hdmi/SendKeyAction;->addTimer(II)V

    goto :goto_0
.end method


text:
package org.apache.camel.component.dataset;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;

import org.apache.camel.ContextTestSupport;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.spi.Registry;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

public class FileDataSetProducerWithSplitTest extends ContextTestSupport {

    @Rule
    public TemporaryFolder tempFolder = new TemporaryFolder();

    protected FileDataSet dataSet;

    final int testDataFileRecordCount = 10;

    final String sourceUri = "direct://source";
    final String dataSetName = "foo";
    final String dataSetUri = "dataset://" + dataSetName;

    @Override
    protected Registry createRegistry() throws Exception {
        Registry answer = super.createRegistry();
        answer.bind("foo", dataSet);
        return answer;
    }

    @Test
    public void testDefaultListDataSet() throws Exception {
        for (int i = 0; i < testDataFileRecordCount; ++i) {
            template.sendBodyAndHeader(sourceUri, "Line " + (1 + i), Exchange.DATASET_INDEX, i);
        }

        assertMockEndpointsSatisfied();
    }

    @Test
    public void testDefaultListDataSetWithSizeGreaterThanListSize() throws Exception {
        int messageCount = 20;
        dataSet.setSize(messageCount);

        getMockEndpoint(dataSetUri).expectedMessageCount(messageCount);

        for (int i = 0; i < messageCount; ++i) {
            template.sendBodyAndHeader(sourceUri, "Line " + (1 + (i % testDataFileRecordCount)), Exchange.DATASET_INDEX, i);
        }

        assertMockEndpointsSatisfied();
    }

    @Override
    @Before
    public void setUp() throws Exception {
        File fileDataset = createFileDatasetWithSystemEndOfLine();
        dataSet = new FileDataSet(fileDataset, LS);
        Assert.assertEquals("Unexpected DataSet size", testDataFileRecordCount, dataSet.getSize());
        super.setUp();
    }

    private File createFileDatasetWithSystemEndOfLine() throws IOException {
        tempFolder.create();
        File fileDataset = tempFolder.newFile("file-dataset-test.txt");
        ByteArrayInputStream content = new ByteArrayInputStream(String.format("Line 1%nLine 2%nLine 3%nLine 4%nLine 5%nLine 6%nLine 7%nLine 8%nLine 9%nLine 10%n").getBytes());
        Files.copy(content, fileDataset.toPath(), StandardCopyOption.REPLACE_EXISTING);
        return fileDataset;
    }

    @Override
    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            public void configure() throws Exception {
                from(sourceUri).to(dataSetUri);
            }
        };
    }
}

redpajama_set_name: RedPajamaGithub


text:
import { Meteor } from 'meteor/meteor';

Meteor.methods({
	'personalAccessTokens:removeToken'({ tokenName }) {
		if (!Meteor.userId()) {
			throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'personalAccessTokens:removeToken' });
		}
		if (!RocketChat.settings.get('API_Enable_Personal_Access_Tokens')) {
			throw new Meteor.Error('error-personal-access-tokens-are-current-disabled', 'Personal Access Tokens are currently disabled', { method: 'personalAccessTokens:removeToken' });
		}
		const tokenExist = RocketChat.models.Users.findPersonalAccessTokenByTokenNameAndUserId({
			userId: Meteor.userId(),
			tokenName,
		});
		if (!tokenExist) {
			throw new Meteor.Error('error-token-does-not-exists', 'Token does not exist', { method: 'personalAccessTokens:removeToken' });
		}
		RocketChat.models.Users.removePersonalAccessTokenOfUser({
			userId: Meteor.userId(),
			loginTokenObject: {
				type: 'personalAccessToken',
				name: tokenName,
			},
		});
	},
});


text:
#ifndef __domGl_samplerRECT_h__
#define __domGl_samplerRECT_h__

#include <dom/domTypes.h>
#include <dom/domElements.h>

#include <dom/domFx_samplerRECT_common.h>

/**
 * A two-dimensional texture sampler for the GLSL profile.
 */
class domGl_samplerRECT_complexType : public domFx_samplerRECT_common_complexType
{

protected:
	/**
	 * Constructor
	 */
	domGl_samplerRECT_complexType() {}
	/**
	 * Destructor
	 */
	virtual ~domGl_samplerRECT_complexType() {}
	/**
	 * Copy Constructor
	 */
	domGl_samplerRECT_complexType( const domGl_samplerRECT_complexType &cpy ) : domFx_samplerRECT_common_complexType() { (void)cpy; }
	/**
	 * Overloaded assignment operator
	 */
	virtual domGl_samplerRECT_complexType &operator=( const domGl_samplerRECT_complexType &cpy ) { (void)cpy; return *this; }
};

/**
 * An element of type domGl_samplerRECT_complexType.
 */
class domGl_samplerRECT : public daeElement, public domGl_samplerRECT_complexType
{
public:
	COLLADA_TYPE::TypeEnum getElementType() const { return COLLADA_TYPE::GL_SAMPLERRECT; }
protected:
	/**
	 * Constructor
	 */
	domGl_samplerRECT() {}
	/**
	 * Destructor
	 */
	virtual ~domGl_samplerRECT() {}
	/**
	 * Copy Constructor
	 */
	domGl_samplerRECT( const domGl_samplerRECT &cpy ) : daeElement(), domGl_samplerRECT_complexType() { (void)cpy; }
	/**
	 * Overloaded assignment operator
	 */
	virtual domGl_samplerRECT &operator=( const domGl_samplerRECT &cpy ) { (void)cpy; return *this; }

public: // STATIC METHODS
	/**
	 * Creates an instance of this class and returns a daeElementRef referencing it.
	 * @param bytes The size allocated for this instance.
	 * @return a daeElementRef referencing an instance of this object.
	 */
	static DLLSPEC daeElementRef create(daeInt bytes);
	/**
	 * Creates a daeMetaElement object that describes this element in the meta object reflection framework.
	 * If a daeMetaElement already exists it will return that instead of creating a new one.
	 * @return A daeMetaElement describing this COLLADA element.
	 */
	static DLLSPEC daeMetaElement* registerElement();

public: // STATIC MEMBERS
	/**
	 * The daeMetaElement that describes this element in the meta object reflection framework.
	 */
	static DLLSPEC daeMetaElement* _Meta;
};

#endif


text:
<?php
	session_start();
	$username = "root";
	$password = "";
	$hostname = "localhost";

	//connection to the database
	$dbhandle = mysqli_connect($hostname, $username, $password) or die("Unable to connect to MySQL");
	//select a database to work with
	$selected = mysqli_select_db($dbhandle, "shopbanhang") or die("Could not select shopbanhang");
	//mysql_query("SET NAMES utf8");
	// $dbhandle->set_charset("utf-8");
	mysqli_query($GLOBALS['dbhandle'],'set names utf8');

	$id = $_SESSION['productID'];

	$result1 = mysqli_query($GLOBALS['dbhandle'],"SELECT * FROM product WHERE ID=$id");
	$result2 = mysqli_query($GLOBALS['dbhandle'],"SELECT comment.ID,comment.Content,comment.Time,user.Username FROM comment,user WHERE comment.ProductID = $id AND user.ID = comment.UserID ORDER BY Time DESC");

	$data = array();
	while ($row = mysqli_fetch_array($GLOBALS['result1'])){
	    $data["product"][] = $row;
	}
	while ($row = mysqli_fetch_array($GLOBALS['result2'])){
	    $data["comment"][] = $row;
	}
	echo json_encode($data);
?>


text:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>Statistics of INTJ in UD_Urdu</title>
    <link rel="root" href=""/>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
    <link rel="stylesheet" type="text/css" href="../../css/jquery-ui-redmond.css"/>
    <link rel="stylesheet" type="text/css" href="../../css/style.css"/>
    <link rel="stylesheet" type="text/css" href="../../css/style-vis.css"/>
    <link rel="stylesheet" type="text/css" href="../../css/hint.css"/>

          home

          edit page
          issue tracker

          <gcse:search></gcse:search>

        This page pertains to UD version 2.

            It appears that you have Javascript disabled.
            Please consider enabling Javascript for this page to see the visualizations.

Treebank Statistics: UD_Urdu: POS Tags: INTJ

There are 2 INTJ lemmas (0%), 2 INTJ types (0%) and 2 INTJ tokens (0%).
Out of 16 observed tags, the rank of INTJ is: 16 in number of lemmas, 16 in number of types and 16 in number of tokens.

The 10 most frequent INTJ lemmas: بس، ذرا

The 10 most frequent INTJ types:  بس، ذرا

The 10 most frequent ambiguous lemmas: بس (<tt>NOUN</tt> 19, <tt>PROPN</tt> 3, <tt>INTJ</tt> 1)

The 10 most frequent ambiguous types:  بس (<tt>NOUN</tt> 14, <tt>PROPN</tt> 2, <tt>INTJ</tt> 1)

بس

<tt>NOUN</tt> 14: پولیس بس ڈرائیور کو حراست مےں لے لیا اور پوچھ تاچھ شروع کر دی ہے ۔

<tt>PROPN</tt> 2: ایر فرانس کی پرواز 330 ایر بس اے 216 447 مسافروں اور 12 ارکان عملہ کے ساتھ روانہ ہوئی تھی ۔

<tt>INTJ</tt> 1: بس اس تنہائی کے عالم مےں اےک یاد آواز بن کر سماعت سے ٹکرائی ۔

Morphology

The form / lemma ratio of INTJ is 1.000000 (the average of all parts of speech is 1.101810).

The 1st highest number of forms (1) was observed with the lemma "بس": بس.

The 2nd highest number of forms (1) was observed with the lemma "ذرا": ذرا.

INTJ does not occur with any features.

Relations

INTJ nodes are attached to their parents using 1 different relations: <tt>advmod</tt> (2; 100% instances)

Parents of INTJ nodes belong to 1 different parts of speech: <tt>VERB</tt> (2; 100% instances)

2 (100%) INTJ nodes are leaves.

The highest child degree of a INTJ node is 0.

© 2014–2021
            Universal Dependencies contributors.
            Site powered by Annodoc and brat
.


text:
title: Upgrading to Version 4.0
short_title: Version 4.0
order: 3
categories: upgrading
nav_order: 41
---

A major change in ufo from version 3 to 4 is that the ECS service is now created by CloudFormation. If you have an existing ECS service deployed by ufo version 3, when you deploy your app again with ufo version 4, there will be a new additional ECS service created. Here is the recommended upgrade path.

## Upgrade Steps Summary

The upgrade path recommended here should result in zero downtime. It is effectively a blue/green deployment with a DNS switchover.

1. Run `ufo upgrade v3to4` in your project folder.
2. Check the changed files.
3. Run `ufo ship SERVICE`.
4. Confirm your new service is working. `ufo ps` and `ufo apps` is useful.
5. Switch the DNS to the new service's endpoint.
6. Confirm everything on the new service works.
7. Destroy the old ECS service with the ECS console. Do not destroy it with `ufo destroy` as the `ufo destroy` command will destroy the newly created service.

Note, with ufo version 4, load balancers are supported and automatically created for web services. If you want to use the existing load balancer, you can do so by specifying `--elb existing-target-group-arn`.

### ufo upgrade v3to4

It is recommended that you run the `ufo upgrade v3to4` command with the network options specified. Please substitute the command with the vpc id and subnets for your setup.  Example:

    $ ufo upgrade v3to4 --vpc-id vpc-111 --ecs-subnets subnet-111 subnet-222 --elb-subnets subnet-333 subnet-444 --force
    Upgrading structure of your current project to the new ufo version 4 project structure
          append  .dockerignore
          append  .gitignore
           force  .ufo/params.yml
          create  .ufo/settings/cfn/default.yml
          create  .ufo/settings/network/default.yml
    Upgrade complete.

If you run the upgrade command without specified options, then ufo will detect and use the default vpc and subnets, which might not be what you want.  Inspect the files and verify that they are what you desired.

### Verify changed files

File | Changes
--- | ---
.ufo/params.yml | The create_service and update_service sections have been removed. The options handed by CloudFormation and can be customized with `.ufo/settings/cfn/default.yml`. If you have used these options for Fargate support, you no longer need to worry about them.  The generated CloudFormation template detects if the task definition uses Fargate and handles it for you.
.ufo/settings/cfn/default.yml | Starter cfn settings file.
.ufo/settings/network/default.yml | This generated file will have the vpc and subnets that you specified above.  You can change them directly in this file to control what network settings ufo uses.

{% include prev_next.md %}


text:
require "guard/plugin"
require "guard/dsl_describer"
require "formatador"

RSpec.describe Guard::DslDescriber do
  let(:interactor) { instance_double(Guard::Interactor) }
  let(:env) { double("ENV") }

  let(:session) { instance_double("Guard::Internals::Session") }
  let(:plugins) { instance_double("Guard::Internals::Plugins") }
  let(:groups) { instance_double("Guard::Internals::Groups") }
  let(:state) { instance_double("Guard::Internals::State") }

  before do
    allow(session).to receive(:groups).and_return(groups)
    allow(session).to receive(:plugins).and_return(plugins)
    allow(state).to receive(:session).and_return(session)
    allow(Guard).to receive(:state).and_return(state)

    allow(env).to receive(:[]).with("GUARD_NOTIFY_PID")
    allow(env).to receive(:[]).with("GUARD_NOTIFY")
    allow(env).to receive(:[]).with("GUARD_NOTIFIERS")
    allow(env).to receive(:[]=).with("GUARD_NOTIFIERS", anything)

    allow(Guard::Notifier).to receive(:turn_on)

    stub_const "Guard::Test", class_double("Guard::Plugin")
    stub_const "Guard::Another", class_double("Guard::Plugin")

    @output = ""

    # Strip escape sequences
    allow(STDOUT).to receive(:tty?).and_return(false)

    # Capture formatador output
    Thread.current[:formatador] = Formatador.new
    allow(Thread.current[:formatador]).to receive(:print) do |msg|
      @output << msg
    end
  end

  describe "#list" do
    let(:result) do
      <<-OUTPUT
  +---------+-----------+
  | Plugin  | Guardfile |
  +---------+-----------+
  | Another | ✔         |
  | Even    | ✘         |
  | More    | ✘         |
  | Test    | ✔         |
  +---------+-----------+
      OUTPUT
    end

    let(:another) { instance_double("Guard::Plugin", title: "Another") }
    let(:test) { instance_double("Guard::Plugin", title: "Test") }

    before do
      allow(plugins).to receive(:all).with("another").and_return([another])
      allow(plugins).to receive(:all).with("test").and_return([test])
      allow(plugins).to receive(:all).with("even").and_return([])
      allow(plugins).to receive(:all).with("more").and_return([])

      allow(Guard::PluginUtil).to receive(:plugin_names) do
        %w(test another even more)
      end
    end

    it "lists the available Guards declared as strings or symbols" do
      subject.list
      expect(@output).to eq result
    end
  end

  describe ".show" do
    let(:result) do
      <<-OUTPUT
  +---------+---------+--------+-------+
  | Group   | Plugin  | Option | Value |
  +---------+---------+--------+-------+
  | Default | Test    | a      | :b    |
  |         |         | c      | :d    |
  +---------+---------+--------+-------+
  | A       | Test    | x      | 1     |
  |         |         | y      | 2     |
  +---------+---------+--------+-------+
  | B       | Another |        |       |
  +---------+---------+--------+-------+
      OUTPUT
    end

    before do
      allow(groups).to receive(:all).and_return [
        instance_double("Guard::Group", name: :default, title: "Default"),
        instance_double("Guard::Group", name: :a, title: "A"),
        instance_double("Guard::Group", name: :b, title: "B"),
      ]

      allow(plugins).to receive(:all).with(group: :default) do
        options = { a: :b, c: :d }
        [instance_double("Guard::Plugin", title: "Test", options: options)]
      end

      allow(plugins).to receive(:all).with(group: :a) do
        options = { x: 1, y: 2 }
        [instance_double("Guard::Plugin", title: "Test", options: options)]
      end

      allow(plugins).to receive(:all).with(group: :b).and_return [
        instance_double("Guard::Plugin", title: "Another", options: [])
      ]
    end

    it "shows the Guards and their options" do
      subject.show
      expect(@output).to eq result
    end
  end

  describe ".notifiers" do
    let(:result) do
      <<-OUTPUT
  +----------------+-----------+------+--------+-------+
  | Name           | Available | Used | Option | Value |
  +----------------+-----------+------+--------+-------+
  | gntp           | ✔         | ✔    | sticky | true  |
  +----------------+-----------+------+--------+-------+
  | terminal_title | ✘         | ✘    |        |       |
  +----------------+-----------+------+--------+-------+
      OUTPUT
    end

    before do
      allow(Guard::Notifier).to receive(:supported).and_return(
        gntp: ::Notiffany::Notifier::GNTP,
        terminal_title: ::Notiffany::Notifier::TerminalTitle
      )

      allow(Guard::Notifier).to receive(:connect).once.ordered
      allow(Guard::Notifier).to receive(:detected).
        and_return([{ name: :gntp, options: { sticky: true } }])

      allow(Guard::Notifier).to receive(:disconnect).once.ordered
    end

    it "properly connects and disconnects" do
      expect(Guard::Notifier).to receive(:connect).once.ordered
      expect(::Guard::Notifier).to receive(:detected).once.ordered.and_return [
        { name: :gntp, options: { sticky: true } }
      ]

      expect(Guard::Notifier).to receive(:disconnect).once.ordered

      subject.notifiers
    end

    it "shows the notifiers and their options" do
      subject.notifiers
      expect(@output).to eq result
    end
  end
end