text:
Apache NiFi
Record-Oriented Data with NiFi
Apache NiFi 1.2.0 introduces powerful new capabilities for dealing with records/messages/events. Here, we provide an introduction to these capabilities.[Read More]
Posted at 02:18PM May 21, 2017 by email@example.com in Dataflow | $text.get("macro.weblog.comments")[$commentCount]
Getting Syslog Events to HBase
Getting Syslog Events to HBase
In the Apache NiFi 0.4.0 release there are several new integration points including processors for interacting with Syslog and HBase. In this post we'll demonstrate how to use NiFi to receive messages from Syslog over UDP, and store those messages in HBase.
The flow described in this post was created using Apache NiFi 0.4.0, rsyslog 5.8.10, and Apache HBase 1.1.2.
Setting up Syslog
In order for NiFi to receive syslog messages, rsyslog needs to forward messages to a port that NiFi will be listening on. Forwarding of messages can be configured in rsyslog.conf, generally located in /etc on most Linux operating systems.
Edit rsyslog.conf and add the following line:
*.* @localhost:7780
This tells rsyslog to forward all messages over UDP to localhost port 7780. A double '@@' can be used to forward over TCP.
Restart rsyslog for the changes to take effect:
/etc/init.d/rsyslog restart
Shutting down system logger: [ OK ]
Starting system logger: [ OK ]
Setting up HBase
In order to store the syslog messages, we'll create an HBase table called 'syslog' with one column family called 'msg'. From the command line enter the following:
hbase shell
create 'syslog', {NAME => 'msg'}
Configure an HBase Client Service
The HBase processors added in Apache NiFi 0.4.0 use a controller service to interact with HBase. This allows the processors to remain unchanged when the HBase client changes, and allows a single NiFi instance to support multiple versions of the HBase client. NiFi's class-loader isolation provided in NARs, allows a single NiFi instance to interact with HBase instances of different versions at the same time.
The HBase Client Service can be configured by providing paths to external configuration files, such as hbase-site.xml, or by providing several properties directly in the processor. For this example we will take the latter approach. From the Controller Services configuration window in NiFi, add an HBase_1_1_2_ClientService with the following configuration (adjusting values appropriately for your system):
After configuring the service, enable it in order for it to be usable by processors:
Building the Dataflow
The dataflow we are going build will consist of the following components:
- ListenSyslog for receiving syslog messages over UDP
- UpdateAttribute for renaming attributes and creating a row id for HBase
- AttributesToJSON for creating a JSON document from the syslog attributes
- PutHBaseJSON for inserting each JSON document as a row in HBase
The overall flow looks like the following:
Lets walk through the configuration of each processor...
Set the Port to the same port that rsyslog is forwarding messages to, in this case 7780. Leave everything else as the default values.
With a Max Batch Size of "1" and Parse Messages as "true", each syslog message will be emitted as a single FlowFile, with the content of the FlowFile being the original message, and the results of parsing the message being stored as FlowFile attributes.
The attributes we will be interested in are:
- syslog.priority
- syslog.severity
- syslog.facility
- syslog.version
- syslog.timestamp
- syslog.hostname
- syslog.sender
- syslog.body
- syslog.protocol
- syslog.port
The attributes produced by ListenSyslog all start with "syslog." which keeps them nicely namespaced in NiFi. However, we are going to use these attribute names as column qualifiers in HBase. We don't really need this prefix since we will already be with in a syslog table.
Add a property for each syslog attribute to remove the prefix, and use the Delete Attributes Expression to remove the original attributes. In addition, create an id attribute of the form "timestamp_uuid" where timestamp is the long representation of the timestamp on the syslog message, and uuid is the uuid of the FlowFile in NiFi. This id attribute will be used as the row id in HBase.
The expression language for the id attribute is:
${syslog.timestamp:toDate('MMM d HH:mm:ss'):toNumber()}_${uuid}
Set the Destination to "flowfile-content" so that the JSON document replaces the FlowFile content, and set Include Core Attributes to "false" so that the standard NiFi attributes are not included.
Select the HBase Client Service we configured earlier and set the Table Name and Column Family to "syslog" and "msg" based on the table we created earlier. In addition set the Row Identifier Field Name to "id" to instruct the processor to use the id field from the JSON for the row id.
Verifying the Flow
From a terminal we can send a test message to syslog using the logger utility:
logger "this is a test syslog message"
Using the HBase shell we can inspect the contents of the syslog table:
hbase shell
hbase(main):002:0> scan 'syslog'
29704815000_84f91b21-d35f-4a24-8e0e-aaed4a521c13 column=msg:body, timestamp=1449775215481,
value=root: this is a test message
29704815000_84f91b21-d35f-4a24-8e0e-aaed4a521c13 column=msg:hostname, timestamp=1449775215481,
29704815000_84f91b21-d35f-4a24-8e0e-aaed4a521c13 column=msg:port, timestamp=1449775215481,
29704815000_84f91b21-d35f-4a24-8e0e-aaed4a521c13 column=msg:protocol, timestamp=1449775215481,
29704815000_84f91b21-d35f-4a24-8e0e-aaed4a521c13 column=msg:sender, timestamp=1449775215481,
29704815000_84f91b21-d35f-4a24-8e0e-aaed4a521c13 column=msg:timestamp, timestamp=1449775215481,
value=Dec 10 19:20:15
29704815000_84f91b21-d35f-4a24-8e0e-aaed4a521c13 column=msg:version, timestamp=1449775215481,
1 row(s) in 0.1120 seconds
Performance Considerations
In some cases the volume of syslog messages being pushed to ListenSyslog may be very high. There are several options to help scale the processing depending on the given use-case.
Concurrent Tasks
ListenSyslog has a background thread reading messages as fast as possible and placing them on a blocking queue to be de-queued and processed by the onTrigger method of the processor. By increasing the number of concurrent tasks for the processor, we can scale up the rate at which messages are processed, ensuring new messages can continue to be queued.
One of the more expensive operations during the processing of a message is parsing the message in order to provide the the attributes. Parsing messages is controlled on the processor through a property and can be turned off in cases where the attributes are not needed, and the original message just needs to be delivered somewhere.
In cases where parsing the messages is not necessary, an additional option is batching many messages together during one call to onTrigger. This is controlled through the Batch Size property which defaults to "1". This would be appropriate in cases where having individual messages is not necessary, such as storing the messages in HDFS where you need them batched into appropriately sized files.
In addition to parsing messages directly in ListenSyslog, there is also a ParseSyslog processor. An alternative to the flow described in the post would be to have ListenSyslog produce batches of 100 messages at a time, followed by SplitText, followed by ParseSyslog. The tradeoff here is that we can scale the different components independently, and take advantage of backpressure between processors.
At this point you should be able to get your syslog messages ingested into HBase and can experiment with different configurations. The template for this flow can be found here.
We would love to hear any questions, comments, or feedback that you may have!
Learn more about Apache NiFi and feel free to leave comments here or e-mail us at email@example.com.
Posted at 01:39PM Dec 16, 2015 by bbende in Dataflow | $text.get("macro.weblog.comments")[$commentCount]
Indexing Tweets with NiFi and Solr
Indexing Tweets with NiFi and Solr
This post will cover how to use Apache NiFi to pull in the public stream of tweets from the Twitter API, identify specific tweets of interest, and deliver those tweets to Solr for indexing. The example developed here was built against Apache NiFi 0.3.0 and Apache Solr 5.3.
In addition, you will also need to create a Twitter application for accessing their API. A good set of instructions for doing that can be found in this article - How to Create a Twitter App in 8 Easy Steps.
Setting up Solr
For this example we will start Solr in cloud mode, and create a tweets collection based off the data-driven configuration provided by Solr. The data-driven configuration allows Solr to create fields on the fly based off the incoming data, and is a good place to start for quickly prototyping. The following two commands can be used to get Solr running and create the collection:
./bin/solr start -c
./bin/solr create_collection -c tweets -d data_driven_schema_configs -shards 1 -replicationFactor 1
At this point we should have a running Solr instance on port 8983, with an embedded ZooKeeper on port 9983. Navigate to http://localhost:8983/solr/#/~cloud in your browser to verify Solr is running and the tweets collection was created sucessfully.
Building the Dataflow
The dataflow we are going build in NiFi will consist of the following processors:
- GetTwitter for accessing the Twitter API and producing FlowFiles containing JSON Tweets
- EvaluateJsonPath for extracting values from JSON documents into FlowFile attributes
- RouteOnAttribute for making decisions about incoming FlowFiles based on their attributes
- MergeContent for merging together many JSON documents to a single document
- PutSolrContentStream for streaming JSON documents to Solr
Lets walk through the configuration of each processor...
Set the end-point to the Sample Endpoint and fill in the credentials corresponding with the Twitter application you created earlier.
For this example we are going to specify a language of "en" to get only English tweets.
Now we want to extract the text and language of each tweet into FlowFile attributes in order to make decisions on these values later. Set the Destination property to "flowfile-attribute" and add two user-defined properties using the New Property icon on the top right. The name of the property will be the FlowFile attribute name, and the value is the JSON path we would like to extract from the Tweet. This will allow us to access these values later by using expression language, such as ${twitter.text} or ${twitter.lang}.
At this point we would like to ensure we are only indexing tweets we are interested. So we add a user-defined property called "tweet" and specify the following expression language as the value:
The first part of this expression filters out all the tweets which have an empty message. This occurs frequently as some of the JSON documents coming through the end-point are not actual tweets. The second part of the expression ensures that we are only selecting english tweets. We already set GetTwitter to filter on "en", but if we hadn't, the language could be used here to route different languages to different relationships. Any tweets matching the above conditions will be routed to the "tweet" relationship based on the property we defined, and anything else will be routed to the "unmatched" relationship. We can auto-terminate the "unmatched" relationship to have the non-matching FlowFiles discarded.
In this example we could send the JSON documents from RouteOnAttribute directly to Solr, but in most real world scenarios accessing the Solr cluster will require network communication, and it will likely produce better performance if we batch together multiple JSON documents into a single request to reduce the amount requests sent over the network. The MergeContent processor is a powerful processor that was built just for this scenario in mind, and is capable of merging FlowFiles based on a number of criteria such as the number of FlowFiles, or their age. MergeContent also performs merges in a streaming manner and as a result is capable of merging a significant number of FlowFiles without worrying about exceeding memory constraints.
To configure MergeContent, set a Minimum and Maximum Number of entries, as well as a Max Bin Age to trigger a merge in cases where no new data has come in for a period of time. Also set the Delimiter Strategy to "Text", and specify the Header, Footer, and Demarcator as [ , ] respectively. This allows us to create a large JSON document composed of many incoming documents.
Configure PutSolrContentStream to point to the Solr instance we started earlier by setting the Solr Type to "Cloud" and the Solr Location to the embedded ZooKeeper that was started earlier (localhost:9983). Also specify a Commit Within of "1000" to commit the incoming documents every second (this may not be needed if you set autoCommit settings in your solrconfig.xml).
Any user-defined properties will get sent to Solr on the request as key value pairs, so we need to tell Solr how to transform the incoming JSON document into a Solr document. A good explanation of how this JSON to Solr mapping works can be found here, and an explanation of the user-defined properties can be found here.
For this example we will provide the following mappings:
- split=/ to treat each child JSON document that we merged together as individual Solr documents
- id:/id to map the id field of the JSON to the id field in the Solr schema (already defined)
- twitter_text_t:/text to map the text field of the JSON to a dynamic field of type text_general in Solr
- twitter_username_s:/user/name to map the user of the tweet to a dynamic string field in Solr
- twitter_created_at_s:/created_at to map the creation date string to a dynamic string field in Solr
- twitter_timestamp_ms_tl:/timestamp_ms to map the timestamp to a dynamic trie-long field in Solr
The naming conventions of the fields allow us to leverage dynamic fields in Solr. Dynamic fields take effect by using a suffix on the field name to indicate the field type, so the "_t" on "twitter_text_t" tells Solr that this field will map to a text_general field type. It is possible to not provide any field mappings and just send the JSON to Solr, and let Solr guess the field types on the fly. However, in that case all of the fields would get added as multiValued fields, and multiValued fields can't be used in a sorting clause which would prevent us from sorting on the timestamp. So we opt for the dynamic fields here.
Also worth noting, this processor has two failure relationships. The regular "failure" relationship is for failures that would generally require some intervention to resolve, such as an invalid document being submitted. The "connection_failure" relationship is for failures related to communication issues between NiFi and Solr. A typical approach in a production scenario would be to route the "connection_failure" back to itself to retry during connection failures, and to route the "failure" relationship to a PutFile processor that could write out failed documents for later inspection.
At this point you should be able to hit Start on your processors and start seeing tweets flowing to Solr, happy indexing!
A template of the flow created in this example can be found here. We would love to hear any questions, comments, or feedback that you may have!
Learn more about Apache NiFi and feel free to leave comments here or e-mail us at email@example.com.
Posted at 04:35PM Sep 21, 2015 by bbende in Dataflow | $text.get("macro.weblog.comments")[$commentCount]
Stream Processing: NiFi and Spark
Stream Processing: NiFi and Spark
Without doubt, Apache Spark has become wildly popular for processing large quantities of data. One of the key features that Spark provides is the ability to process data in either a batch processing mode or a streaming mode with very little change to your code. Batch processing is typically performed by reading data from HDFS. There have been a few different articles posted about using Apache NiFi (incubating) to publish data HDFS. This article does a great job of explaining how to accomplish this.
In many contexts, though, operating on the data as soon as it is available can provide great benefits. In order to provide the right data as quickly as possible, NiFi has created a Spark Receiver, available in the 0.0.2 release of Apache NiFi. This post will examine how we can write a simple Spark application to process data from NiFi and how we can configure NiFi to expose the data to Spark.
Incorporating the Apache NiFi Receiver into your Spark application is pretty easy. First, you'll need to add the Receiver to your application's POM:
That's all that is needed in order to be able to use the NiFi Receiver. So now we'll look at how to use the Receiver in your code.
The NiFi Receiver is a Reliable Java Receiver. This means that if we lose a node after it pulls the data from NiFi, the data will not be lost. Instead, another node will simply pull and process the data. In order to create a NiFi Receiver, we need to first create a configuration that tells the Receiver where to pull the data from. The simplest form is to just tell the config where NiFi is running and which Port to pull the data from:
SiteToSiteClientConfig config = new SiteToSiteClient.Builder()
.portName("Data For Spark")
To briefly explain the terminology here, NiFi refers to its mechanism for transferring data between clusters or instances as Site-to-Site. It exposes options for pushing data or pulling, so that the most appropriate approach can be used for each situation. Spark doesn't supply a mechanism to have data pushed to it - instead, it wants to pull data from other sources. In NiFi, this data can be exposed in such a way that a receiver can pull from it by adding an Output Port to the root process group. For Spark, we will use this same mechanism - we will use this Site-to-Site protocol to pull data from NiFi's Output Ports. In order for this to work, we need two pieces of information: the URL to connect to NiFi and the name of the Output Port to pull data from.
If the NiFi instance to connect to is clustered, the URL should be that of the NiFi Cluster Manager. In this case, the Receiver will automatically contact the Cluster Manager to determine which nodes are in the cluster and will automatically start pulling data from all nodes. The Receiver automatically determines by communicating with the Cluster Manager which nodes have the most data backed up and will pull from those nodes more heavily than the others. This information is automatically updated periodically so that as new nodes are added to the cluster or nodes leave the cluster, or if the nodes become more or less bogged down, the Receiver will automatically adjust to handle this.
Next, we need to instruct the Receiver which Port
to pull data from. Since NiFi can have many different Output Ports, we need to provide either a Port Identifier or a Port Name. If desired, we can also configure communications
timeouts; SSL information for secure data transfer, authentication, and authorization; compression; and preferred batch sizes. See the JavaDocs for the
for more information.
Once we have constructed this configuration object, we can now create the Receiver:
SparkConf sparkConf = new SparkConf().setAppName("NiFi-Spark Streaming example");
JavaStreamingContext ssc = new JavaStreamingContext(sparkConf, new Duration(1000L));
// Create a JavaReceiverInputDStream using a NiFi receiver so that we can pull data from
// specified Port
JavaReceiverInputDStream packetStream =
ssc.receiverStream(new NiFiReceiver(config, StorageLevel.MEMORY_ONLY()));
This gives us a
JavaReceiverInputDStream of type
NiFiDataPacket is a simple construct that packages an arbitrary byte array with a map of Key/Value pairs (referred to as attributes) that correspond to the data.
As an example, we can process the data without paying attention to the attributes:
// Map the data from NiFi to text, ignoring the attributes
JavaDStream text = packetStream.map(new Function() {
public String call(final NiFiDataPacket dataPacket) throws Exception {
return new String(dataPacket.getContent(), StandardCharsets.UTF_8);
Or we can make use of the attributes:
// Extract the 'uuid' attribute
JavaDStream text = packetStream.map(new Function() {
public String call(final NiFiDataPacket dataPacket) throws Exception {
return dataPacket.getAttributes().get("uuid");
So now we have our Receiver ready to pull data from NiFi. Let's look at how we can configure NiFi to expose this data.
First, NiFi has to be configured to allow site-to-site communication. This is accomplished by setting the
nifi.remote.input.socket.port property
in the nifi.properties file to the desired port to use for site-to-site (if this value is changed, it will require a restart of NiFi for the changes to take effect).
Now that NiFi is setup to allow site-to-site, we will build a simple flow to feed data to Spark. We will start by adding two GetFile processors to the flow. One will
pick up from
/data/in/notifications and the other will pick up from
Next, let's assume that we want to assign different priorities to the data that is picked up from each directory. Let's assign a priority of "1" (the highest priority)
to data coming from the
analysis directory and assign a lower priority to the data from the
notifications directory. We can use
the UpdateAttribute processor to do this. Drag the Processor onto the graph and configure it. In the Settings tab, we set the name to "Set High Priority". In the
Properties tab, we have no properties available. However, there's a button in the top-right of the dialog that says "New Property." Clicking that button lets us
add a property with the name
priority and a value of
1. When we click OK, we see it added to the table:
Let's click Apply and add another UpdateAttribute processor for the data coming from the
notifications directory. Here, we will add a property
with the name
priority but give it a value of
2. After configuring these processor and connecting the GetFile processors to them,
we end up with a graph that looks like this:
Now, we want to combine all of the data into a single queue so that we can prioritize it before sending the data to Spark. We do this by adding a Funnel to the graph and connecting both of the UpdateAttribute processors to the Funnel:
Now we can add an Output Port that our Spark Streaming application can pull from. We drag an Output Port onto our graph. When prompted for a name, we will name it
Data For Spark, as this is the name that we gave to our Spark Streaming application. Once we connect the Funnel to the Output Port, we have a graph
like this:
We haven't actually told NiFi to prioritize the data yet, though. We've simply added an attribute named
priority. To prioritize the data based on that, we can
right-click on the connection that feeds the Output Port and choose Configure. From the Settings tab, we can drag the PriorityAttributePrioritizer from the list of Available Prioritizers
to the list of Selected Prioritizers:
Once we click Apply, we're done. We can start all of the components and we should see the data start flowing to our Spark Streaming application:
Now any data that appears in our
/data/in/notifications or
/data/in/analysis directory will make its way to our streaming application!
By using NiFi's Output Port mechanism, we are able to create any number of different named Output Ports, as well. This allows you, as a NiFi user, to choose exactly which data gets exposed to Spark. Additionally, if NiFi is configured to be secure, each Output Port can be configured to provide the data to only the hosts and users that are authorized.
Let's consider, though, that this data has significant value for processing in a streaming fashion as soon as we have the data, but it may also be of value to a batch processing analytic. This is easy to handle, as well. We can add a MergeContent processor to our graph and configure it to merge data into 64-128 MB TAR files. Then, when we have a full TAR file, we can push the data to HDFS. We can configure MergeContent to make these bundles like so:
We can then send the merged files to PutHDFS and auto-terminate the originals. We can feed all the data from our Funnel to this MergeContent processor, and this will allow us to dual-route all data to both HDFS (bundled into 64-128 MB TAR files) and to Spark Streaming (making the data available as soon as possible with very low latency):
We would love to hear any questions, comments, or feedback that you may have!
Learn more about Apache NiFi and feel free to leave comments here or e-mail us at email@example.com.
Posted at 01:10PM Mar 19, 2015 by firstname.lastname@example.com in Dataflow | $text.get("macro.weblog.comments")[$commentCount]
Say Good-Bye to Canned Data
Say Good-Bye to Canned Data
We've all been there. After months of development and exhaustive testing, our killer new web service (or app or analytic or what have you) is ready for production! We've tested it with all of the random data that we've mocked up, including all of the samples that we've concocted to ensure that it handles every bad input that we can imagine. We've handled it all well, so it's time to deploy to production. So we do. And all is great!
Until an hour later, when our logs start filling with errors because, despite all of our due diligence in testing, we never could have envisioned getting that as input. And now we're in a mad frenzy to fix our problem, because we're now responsible for all of the errors that are happening in production.
If there's one thing that I've learned in my years as a software developer, it's that no matter how diligent we are in testing our code, we get data in production that we just haven't accounted for.
So what can we do about it? Test with live production data!
Now I'm not suggesting that we skip the testing phase all together and go straight into production - quite the opposite really. I'm just suggesting that we test "smarter, not harder." One of the benefits of Apache NiFi (incubating) is that it allows us to have real-time command and control of our data. It allows us to change our dataflow in just a few minutes to send multiple copies of our data to anywhere we want, while providing different reliability guarantees and qualities of service to different parts of our flow. So let's look at how we might accomplish this.
Let's assume that we typically get our feed of data to our web service from NiFi in a flow that looks something like this:
Now let's say that we want to send a duplicate copy of this data feed to our "staging" environment that is running the new version of our web service - or a new web service all together. We can simply copy and paste the InvokeHTTP processor that we're using to send the data to our production instance (select the processor and press Ctrl-C, Ctrl-V to copy and paste) and then right-click on the new one and choose "Configure..." In the Properties tab, we will change the URL to point to our staging instance. Now, all we have to do is draw a second connection from the preceding processor to our newly created InvokeHTTP. We will give it the same relationship that feeds the production instance - "splits." And now any data that goes to our production instance will also be sent to our staging environment:
Of course, since we know this is a staging environment, it may not be as powerful as the production instance and it may not handle the entire stream of live data. What we really would like to do is send only about 20% of our data to our staging environment. So how can we accomplish that? We can easily insert a DistributeLoad Processor just ahead of our new InvokeHTTP processor, like so:
We can now configure the DistributeLoad Processor to have two relationships. We want 80% of the load to go to relationship "1" and 20% to go to relationship "2." We can accomplish this by adding two user-defined properties. We right-click on DistributeLoad and choose "Configure..." In the Properties tab, click the icon to add the first property. We give it the name "1" and a value of 80. Then we click OK and add another property. This time, we give the property the name "2" and a value of "20":
Now, all we have to do is go to the Settings Tab and choose to Auto-Terminate Relationship 1. This will throw away 80% percent of our data. (Not to worry, we don't actually make copies of this data just to throw away 80% of it. The actual work required to "clone" a FlowFile is very small, as it doesn't actually copy any of the content but rather just creates a new pointer to the content.) Now we add a Connection from DistributeLoad to InvokeHTTP and use Relationship "2." Start the Processors, and we've now got 20% of the data being pushed to our staging environment:
Now, we have just one more concern that we need to think about. Since we're sending data to our staging area, which may go down pretty often, as we are debugging and testing things, won't the data backup in NiFi on our production dataflow? At what point is this going to cause a problem?
This is where my former comment about NiFi offering "different Quality of Service guarantees to different parts of the flow" comes in. For this endpoint, we just want to try to send the data and if it can't handle the data, we don't want to risk causing issues in our production environment. To ensure that this happens, we right-click on the connection that feeds the new InvokeHTTP processor and click "Configure..." (You'll have to first stop the connection's source and destination processors in order to modify it). In the settings tab here, we have an option for "File expiration." The default is "0 sec," which means that the data will not age off. Let's change this value to 3 minutes.
Now, when we click Apply, we can see that the Connection's label has a small "clock" icon on it, indicating that the connection has an expiration set.
Any FlowFile in the connection that becomes more than 3 minutes old will automatically be deleted. This means that we will buffer up to three minutes worth of data in our production instance to send to staging environment but no more. We still will not expire any data that is waiting to go to the production instance. Because of this capability, we can extend our example a bit to perform load testing as well. While in this example we decided that we only wanted to send 20% of our data to the staging environment, we could easily remove the DistributeLoad processor all together. In this way, we will send 100% of our production data to the staging environment, as long as it is able to handle the data rate. However, if it falls behind, it won't hurt our production servers because they'll destroy any data more than 3 minutes old. If concerns were to arise, we can disable this in a matter of seconds: simply stop the DistributeLoad processor and the SplitText processor feeding it, remove the connection between them, and restart the SplitText processor.
As always, I'd love to hear feedback in the Comments section about how we could improve, or how you've solved similar problems.
Posted at 01:43PM Feb 02, 2015 by firstname.lastname@example.com in Dataflow | $text.get("macro.weblog.comments")[$commentCount]
Apache NiFi: Thinking Differently About Dataflow
Apache NiFi: Thinking Differently About DataFlow
Recently a question was posed to the Apache NiFi (Incubating) Developer Mailing List about how best to use Apache NiFi to perform Extract, Transform, Load (ETL) types of tasks. The question was "Is it possible to have NiFi service setup and running and allow for multiple dataflows to be designed and deployed (running) at the same time?"
The idea here was to create several disparate dataflows that run alongside one another in parallel. Data comes from Source X and it's processed this way. That's one dataflow. Other data comes from Source Y and it's processed this way. That's a second dataflow entirely. Typically, this is how we think about dataflow when we design it with an ETL tool. And this is a pretty common question for new NiFi users. With NiFi, though, we tend to think about designing dataflows a little bit differently. Rather than having several disparate, "stovepiped" flows, the preferred approach with NiFi is to have several inputs feed into the same dataflow. Data can then be easily routed (via RouteOnAttribute, for example) to "one-off subflows" if need be.
One of the benefits to having several disparate dataflows, though, is that it makes it much easier to answer when someone comes to you and says "I sent you a file last week. What did you do with it?" or "How do you process data that comes from this source?" You may not know exactly what happened to a specific file that they sent you, step-by-step, because of the different decision points in the flow, but at least you have a good idea by looking at the layout of the dataflow.
So we can avoid merging the data if we would like. For the sake of an example, let's assume that we have 4 different data sources. For each of them, they are going to send us some text data that needs to be pushed into HDFS. Maybe it's compressed, maybe it's not. So your flow will look like this:
Now, let's say that that you've got a new requirement. When you're sending text data to HDFS, each file that is pushed to HDFS needs to have 1,000 lines of text or less (yes, that's a contrived example and that's probably never a good idea, but the point is valid.) Now, consider how much work it is to make all of those modifications. And let's hope that you don't miss any!
If we continue down this path, this can get hairy quickly, as we have several different dataflows side-by-side on the same graph. In order to aid in the visual representation, we can use Process Groups to provide a nice logical separation. If we do that for each of those, we end up with something like:
We can then double-click each of those Process Groups and see/edit what's inside. But we still have the issue of having to change 4 different flows to make the change mentioned.
So let us consider the alternate approach of merging it all into a single dataflow, and we end up with a flow like this:
Now, we have all of the data going to a single stream. If we want to update it, we just insert one new Processor:
And we're done. We don't have to make this change to insert a SplitText processor 3 more times.
The concern that we have here, though, as mentioned earlier, is that if all of the data is mixed together, as the dataflow grows larger, how do we know what happens to data that came from Source X, for example?
This is where the Data Provenance feature comes in. In the top right-hand corner there's a toolbar with 8 icons. The 4th one is the Provenance icon (). If we click on that, we can then search for data that has been processed. For this example, let's simply searched for RECEIVE events.
This shows us all of the RECEIVE events that this instance of NiFi has seen within the time range searched:
If we click the Lineage Graph icon () on the right, for the first file, we see exactly what happened to this piece of data:
We see that a RECEIVE event occurred, and that generated a FlowFile. That FlowFile's attributes were then modified, its content was modified, and then the FlowFile was forked, and dropped. At this point, we can right-click on each of these event nodes and choose to view the details of the event. For the RECEIVE event, we see:
From here, we can see that the RECEIVE event took place at 16:55:51 EST on 01/11/2015. The component that reported the event was named "Data From Source X" and was a GetFile Processor. We can also see that the URI of the data was file:/C:/temp/in/debug/LICENSE.gz. If we follow the lineage of that FlowFile, we see that the next event is an ATTRIBUTES_MODIFIED Event:
Since the event is of type ATTRIBUTES_MODIFIED, it immediately begs the question "What attributes were modified?" So clicking the "Attributes" tab shows us this:
As with any Provenance Event, we can see all of the attributes that were present on the FlowFile when the event occurred. Of interest here, we can see that the value of the "mime.type" attribute was changed from "No value set" (the attribute didn't exist) to "application/gzip". The next event in our lineage is a CONTENT_MODIFIED Event. If we view the details here, we will see:
Here, we can see that the content was modified by a Processor named Decompress. This makes sense, since the previous Event showed us that the MIME Type was "application/gzip". After decompressing the data, we arrive at a FORK Event:
This event shows us that the FORK happened by the SplitText Processor. That is, the SplitText Processor broke a large FlowFile into many smaller FlowFiles. On the right-hand side of this dialog, we see that the file was broken into six different "child" FlowFiles. This is where things get fun! If we then close this dialog, we can right-click on the FORK Event and choose the "Expand" option. This will then pull back the lineage for each of those children, providing us with a more holistic view of what happened to this piece of data:
Now, we can see that each of those six children was sent somewhere. Viewing the details of these events shows us where they were sent:
The first file, for instance, was sent via the PutHDFS Processor with the filename "/nifi/blogs/thinking-differently/LICENSE.gz". This occurred at 16:55:53 EST on 01/11/2015. We can also see in this dialog the "Lineage Duration" was "00:00:02.712" or 2.712 seconds. The "Lineage Duration" field tells us how long elapsed between the time when the original source data was received and the time at which this event occurred.
Finally, we have the DROP event. The DROP event signifies the end of line for a FlowFile. If we look at the details of this event, we see:
Of note here, we see that the DROP event was emitted by PutHDFS. That is, PutHDFS was the last component in NiFi to process this piece of information. We can also see in the "Details" field why the FlowFile was dropped: it was Auto-terminated by the "success" relationship.
NiFi's Data Provenance capability allows us to understand exactly what happens to each piece of data that is received. We are given a directed graph that shows when a FlowFile was received, when it was modified, when it was routed in a particular way, and when and where it was sent - as well as which component performed the action. We are also able to see, for each event, the attributes (or metadata) associated with the data so that we can understand why the particular event occurred. Additionally, when many pieces of data are merged together or a single piece of data is split apart, we are able to understand fully the provenance of this data from the that it was received until the time at which it exited the flow. This makes it very easy to answer the question "I sent you a file last week. What did you do with it?" while providing a much more holistic view of the enterprise dataflow than would be available if we used many disparate flows.
Hopefully this post helps you to understand not only the way that we like to setup the flows with NiFi but also the benefits that we have as a result and the features that allow us to overcome any challenges that this approach may create.
Posted at 12:44PM Jan 12, 2015 by email@example.com in Dataflow | $text.get("macro.weblog.comments")[$commentCount]
Integrating Apache NiFi with Kafka
Integrating Apache NiFi with Apache Kafka
A couple of weeks ago, Joey Echeverria wrote a fantastic blog post about how to get started with Apache NiFi (Incubating), available at http://ingest.tips/2014/12/22/getting-started-with-apache-nifi/ . In it, Joey outlines how to quickly build a simple dataflow that automatically picks up any data from the /dropbox directory on your computer and pushes the data to HDFS. He then goes on to use the ExecuteStream Processor to make use of the Kite SDK's ability to push CSV data into Hadoop.
In this blog post, we will expand upon Joey's example to build a dataflow that's a bit more complicated and illustrate a few additional features of Apache NiFi. If you haven't already read Joey's blog, we would recommend you read it before following along here, as this post assumes that you have a very basic understanding of NiFi, such as what NiFi is and how to add a Processor to the graph.
We will continue with the MovieLens dataset, this time using the "MovieLens 10M" dataset, which contains "10 million ratings and 100,000 tag applications applied to 10,000 movies by 72,000 users." However, rather than downloading this dataset and placing the data that we care about in the /dropbox directory, we will use NiFi to pull the data directly from the MovieLens site.
To do this, we first drag a Processor onto the graph. When we do this, we are given the option of choosing many different types of Processors. We know that we want to retrieve data from an HTTP address, so we will search for Processors of interest by choosing the "by tag" option for the filter and typing "http":
This narrows the list of Processors to just a few. We can quickly see the GetHTTP Processor. Clicking on the Processor shows a description of the Processor just below: "Fetches a file via HTTP." This sounds like a good fit, so we click the "Add" button to add it to the graph. Next, we need to configure the Processor to pull the data that we are interested in. Right-clicking the Processor and clicking the "Configure" menu option provides us a dialog with a "Properties" tab. Here, we can enter the URL to fetch the data from (http://files.grouplens.org/datasets/movielens/ml-10m.zip) and enter the filename to use when downloading it:
We can leave the other properties as they are for the sake of this blog post. In a real environment, you may have an interest in changing timeout values, providing authentication, etc. We do, however, want to look at the "Scheduling" tab. By default, Processors are scheduled to run as fast as they can. While this is great for most high-volume dataflows, we wouldn't be very good clients if we continually hit the website nonstop as fast as we can - and I doubt that those responsible for the site would appreciate it very much. In order to avoid this, we go to the "Scheduling" tab and change the "Run Schedule" setting from "0 sec" to something more reasonable - say "10 mins". This way, we will check for new data from the website every 10 minutes. If the E-Tag changes or the Last Modified date changes, then we will pull the data again. Otherwise, we won't continue to pull the data.
Next, we know that the data is in ZIP format, based on the URL. We will want to unzip the data to interact with each file individually. Again, we can drag a Processor to the graph and filter by the tag "zip." We see that the UnpackContent processor can handle ZIP files. We add it to the graph and configure its Properties as we did for GetHTTP. This time, there is only one property: Packing Format. We change it to "zip" and click "Apply."
Next, we need to send the data from GetHTTP to UnpackContent. We drag a Connection between the Processors and include the "success" relationship, as that is the only relationship defined by GetHTTP. Now that we've unzipped the data, the README tells us that the actual data included in the zip is in 3 files: movies.dat, ratings.dat, and tags.dat. We don't really care about the rest of the data in the zip file, so we will use a RouteOnAttribute to throw it out. We'll configure our RouteOnAttribute with the following properties:
We will connect the "success" relationsihp of UnpackContent to RouteOnAttribute. We don't care about the original FlowFile - we only want the unpacked data. And if the Unpack fails, then there's not much we can do, so we will configure UnpackContent and in the Settings tab choose to Auto-terminate the "original" and "failure" relationships. Likewise, we don't care about anything routed to the "unmatched" relationship on the RouteOnAttribute, so we will Auto-terminate that relationship as well.
Now, we can just decide what to do with the "movies", "ratings", and "tags" relationships. For the sake of this post, let's go ahead and push all of this data to HDFS with a PutHDFS Processor. We add a PutHDFS Processor and configure it as Joey's blog instructs. We then drag a Connection from RouteOnAttribute to PutHDFS and choose all three of these relationships.
For PutHDFS, once we have successfully sent the data, there is nothing else to do, so we Auto-terminate the "success" relationship. However, if there's a problem sending the data, we don't want to lose this data. We can then connect the PutHDFS' "failure" relationship back to the PutHDFS Processor. Now, if we fail to send the data we will keep retrying until we are successful.
Now, we're ready to send some data to Kafka. Let's assume that we want only the data in the `movies.dat` file to go to Kafka. We can drag a Processor onto the graph and filter by the tag "kafka." We see two Processors: GetKafka and PutKafka. Since we want to send the data, we will use PutKafka. To send the movies data, we simply draw a Connection from the RouteOnAttribute Processor to PutKafka and choose only the "movies" relationship. NiFi will take care of cloning the FlowFile in a way that's very efficient so that no data is actually copied.
We configure PutKafka by Auto-terminating "success" and looping "failure" back to itself as with PutHDFS. Now let's look at the Properties tab. We have to choose a Kafka Topic to send the data to and a list of 1 or more Kafka servers to send to. We'll set the Known Brokers to "localhost:9092" (assuming this is running on the same box as Kafka) and set the Kafka Topic to "movies". Since the data is a CSV file, we know that it is new-line delimited. By default, NiFi will send the entire contents of a FlowFile to Kafka as a single message. However, we want each line in our CSV file to be a new message on the Kafka Topic. We accomplish this by setting the "Message Delimiter" property to "\n". At this point, our flow should look something like this:
And now we're ready to start our flow!
We can press Ctrl+A to select all and then click the Start button in the middle toolbar to start everything running. While the flow is running, we can right-click on the canvas and select "Refresh Status" to update all of the stats shown on the Processors. Then we will see in the top-right-hand corner of GetHTTP a "1" indicating that there is currently a single task running for this Processor. Once this task is finished, the data will be routed to the UnpackContent Processor, then the RouteOnAttribute Processor. At this point, some of the data will be destroyed because RouteOnAttribute will route it to "unmatched." The rest will go to the PutHDFS Processor, while only the "movies.dat" file will be sent to the PutKafka Processor. If we keep clicking "Refresh Status" as the data is processing, we will see each of these steps happening.
We've now successfully setup a dataflow with Apache NiFi that pulls the largest of the available MovieLens datasets, unpacks the zipped contents, grooms the unwanted data, routes all of the pertinent data to HDFS, and finally sends a subset of this data to Apache Kafka.
In Part Two of this series, we will look at how we can consume data from Kafka using NiFi, as well as how we can see what data we've pulled and what we've done with that data. Until then, please feel free to leave any questions, comments, or feedback in the Comments section.
Posted at 07:29PM Jan 10, 2015 by email@example.com in Dataflow | $text.get("macro.weblog.comments")[$commentCount]


text:
Lilly O'Brate, an only child, and her mother, a single mom, lead pretty normal lives. But when Lilly finds herself walking to school on a scorching day in Oklahoma, normal becomes out of the question. She finds herself on a journey of sorrow, love, betrayal, and a downright irritating brother and his three hot housemates. Finding out that they're vampires does nothing to help her situation. Especially when their creator is doing everything he can to disrupt her life and everything she holds dear. In Kidnapped by Vampires? But it's My Time of the Month!, Lilly learns what it's like to love even when she knows it's someone she shouldn't, and even when all that she knows is not what it seems.
UJustJelly Jul 07, 2014
I feel for ya. That prescription medicine is the stuff though! If it doesn't make the pain go away, it makes you sleep.
ArielLovesYou101 Mar 25, 2014
lol that's totally me. I get mine really bad and have tos tay home for three days from schiil
Psychotic_Devil Aug 28, 2013
I used to have camps. Visited the doc's 2X! I really wouldn't like describe.......good book
Lady0fthelake Jul 05, 2013
Well, you have managed to make me fall in love with this book in the first page.
CuteBearsLOL Apr 08, 2013
When I get my time of the month it's nearly as bad as this... It's really bad
pipperhaliwell Aug 06, 2012
uh bonus points for her listing to carrie underwood lol seems pretty great so far

subset: commoncrawl


text:
Auto enthusiasts know that luxury is built into each Land Rover, and know that only the best replacement Defender 110 parts will suffice when repairs are needed. Make no mistake, you didn't buy your Defender 110 unless you understood you would be getting long-lasting quality and a trusted brand both impeccably combined into one vehicle. It's not all the time that you realize that you have to buy a replacement Ball Joint to fix your vehicle. Land Rover automobile owners have come to expect a certain level of versatility when driving their Defender 110 around town.
If steering weren't important, then all of our roads would be completely straight and there would be no need to turn. One key advancement from the 20th century that has improved how we steer is the Land Rover Defender 110 ball joint. Connected to our control arms, ball joints are a vast improvement over king pinsbecause they allow for rotation in three dimensions rather than just forward and backward. Moving away from the limited motion of simply two directions, ball joints allow full flexibility for your vehicle.
Procuring new Land Rover parts from www.carpartsdiscount.com means you are getting the best deal on the absolute greatest original and aftermarket replacement Defender 110 parts on the internet. Don't let a Ball Joint repair spell the end of your car, truck, or SUV, and don't gamble with its condition by installing anything but the highest quality replacement parts. Buy all the car parts you will ever need from carpartsdiscount.com and realize incredible savings on all your upcoming repairs. Just choose your year from the list below to find the right Land Rover Defender 110 Ball Joint for your 1993 model.


text:
Let us know when your receive great advice so we can thank our lawyers and point others with similar questions in the right direction.Got it!
i was injured in a slip and fall accident and 10 years ago was slightly injured in an automobile accident i have a felony and 3 misdemeaners my lawyer is trying to say a jury will not award me compisation in court do to the criminal history and is saying the injury may be related to the past automobile accident because of things that i sayed to hospitals over 3 to 5 years ago but the injuries of slip and fall could of made the past injuries worse my doctor and therepy bills are $52,000.00 this time and they r trying to get me to settle for $45,00.00 and my lawyer is trying to tell me that a jury will not rule in my favor is this accurate or is my lawyer just trying to screw me because of my felony for cocaine and failure to id and theft under $20.00
If the convictions come in at trial it is doubtful that a jury will award you more than medicals. Sometimes they will believe you injured yourself or were on drugs when you were injured even though there are no records to prove that. Depending on your lawyers ability to reduce the medical bills this may or may not be a fair settlement. But at the end of the day it is your option. Guaranteed money versus rolling the dice e and getting zero.
Know YOUR Rights. Take Action Now. CALL 855-648-4695. Legal disclaimer:This message does not constitute legal advice and does not create an attorney-client relationship. Any statements are made for general informational purposes and do not constitute legal advice. Mr. Crockett is licensed in Texas in Illinois only.Ask a similar question
You fail to state where your injury occurred, but since you are from Dallas, I will assume that you reside in the D/FW area. You need to look at Texas Rule of Evidence 609, which in general states that for the purpose of attacking the credibility of a witness, evidence that the witness was convicted of a felony, or crime of moral turpitude (lying/cheating/stealing), is admissble if the probative value outweighs the preducial effect. However, the conviction is not admissible if the conviction occurred greater than 10 years ago, unless the judge decides that the probabtive value outweighs the prejudicial effect. The long and short of this is that "yes" your criminal conduct can be used against your in court to demonstrate that you are not a trustworthy person.
This is important because in a civil jury trial you are asking the jury to award you money based on your claims of injury, which includes money for pain and suffering. Should the jury think you are prone to you break the law. In my experience there are juries out there that simply will not award money to convicts, as to be a juror you must not have ever committed such a crime. So gernerally speaking, you will not get a jury of your peers, as your peers are persons with felong convcitions.
Further, Texas is a law and order state. Most judges will permit Rule 609 evidence to be submitted to the jury. Further, counties like Collin, Wise and Tarrant are extremely conservative and winning a slip and fall case in them, regardless of the facts, is rare. You should listen to your lawyer. And "no" your lawyer is not trying to take advantage of you. In my opinion he is giving you sound advice, which is what you hired him to do. He did not create the facts, he can only present them.Ask a similar question
Juries don't like to hear this stuff, and it could sway them against you. Your lawyer would be in the best position to advise you.Ask a similar question
Your attorney can test the admissibility of your convictions through a motion in limine, pretrial. If the judge rules against you, you know the information is coming in. Speak with your attorney further.
Legal Disclaimer:
If this information has been helpful, please indicate below.
Mr. Lundeen is licensed to practice law in Florida and Vermont. The response herein is not legal advice and does not create an attorney/client relationship. The response is in the form of legal education and is intended to provide general information about the matter within the question. Oftentimes the question does not include significant and important facts and timelines that, if known, could significantly change the reply and make it unsuitable. Mr. Lundeen strongly advises the questioner to confer with an attorney in your state in order to ensure proper advice is received.
This ans. does not create an attorney/client relationship.Ask a similar question
Discuss with your lawyer ASAP. Generally, I would file a Motion with the Court to bar any such evidence from the jury.
The above is general information only and is not legal advice. The information provided does not form an attorney-client relationship, and should not be relied upon to take or refrain from taking any action. I am not your attorney until we sign a retainer agreement.Ask a similar question
Immigration Medical expenses for personal injury Pain and suffering Premises liability for personal injuries Personal injury Personal injury settlement Evidence for personal injury cases Witness testimony and personal injuries Types of personal injuries Slip and fall injuries Property liability Criminal defense Felony crime Criminal charges for theft Criminal record Evidence
Sign up to receive a 3-part series of useful information and advice about personal injury law.
Post a free question on our public forum.Ask a Question
- or -
Search for lawyers by reviews and ratings.Find a Lawyer


text:
Thanks to mobile phones, it is now possible to stay in touch with your loved ones even when you're away from each other. If you are dating, you might be wondering how you can use modern means of communication to spice up your relationship. There are many romantic things to say to your boyfriend in a text; you just have to figure out what you want to say and then say it in the sweetest way!
Texts are indeed the preferred way to keep in touch with your boyfriend or girlfriend especially with the younger generation. The reason why texts are so popular is because you can send them anytime and anywhere. Unlike calls, you don't have to worry about catching the other person in an awkward moment such as in the middle of a meeting. A text is discreet and it will not cause any interruptions.
Texts are also great as they allow you to write your feelings and thoughts and express them in a way that you would not be able to verbally. Your boyfriend can also look at the text whenever he misses you. It will be a constant reminder of you. Now, understanding why texts are great is the easy part. Coming up with something romantic to say is the hard part. Of course, when you're in a relationship finding something to say to the other person should come naturally. However, for some people this is easier said than done.
One of the romantic things to say to your boyfriend in a text is to tell him how much you appreciate him. Men love to be appreciated by the women in their lives. It makes them feel great. Do not waste the opportunity to make your boyfriend feel loved and special. Just one text telling him how much he brightens your life should be enough.
Amazon Price: $30.00 Buy Now
(price as of Jun 19, 2016)
You could try saying something like "You are the best thing that's happened to me this year. You make every ordinary day something special." He will be extremely flattered.
If you love teasing each other, texts are a great way to continue this fun. The best couples are those who are able to poke fun at each other. Inject some humor in your relationship by sending him funny texts about something silly he did or said. You could even make fun of a weird thing that he likes. Of course, you should first make sure that the jokes do not offend him.
For instance, you could send him this text "Dying to hear another one of your jokes, baby" This should be funny if you both agree he's terrible at telling jokes.
Long distance can take its toll even on the most stable relationships. If you are in a long distance relationship, make use of texts to keep in touch. Of course, phone calls should be included too. Some romantic things to say to your boyfriend in a text include reminding him how much you love him and miss him and how you wish he were there with you.
You can reminisce about how you met; this always makes for a good walk down memory lane, especially because there's always his story and her story. You can use texts to beat the emotional turmoil created by long distance. Keeping in touch throughout the day will make you feel as if you're in one room, just the two of you.
Amazon Price: $23.95 Buy Now
(price as of Jun 19, 2016)
You can ignite the fire in a relationship through the use of texts. Most people find it awkward to engage in phone sex. Sharing your bedroom thoughts with your boyfriend verbally might not be easy for everyone. However, with texts you don't have to feel awkward. You can share your most brazen romantic thoughts with him without feeling uneasy.
And most often than not, he'll be more than willing to play your game. If you live together, you can send him this text while he's away at work "Bring a good bottle of wine and some strawberries, honey. I'll bring the lingerie" Just imagining what your plans are for later will drive him crazy.
Texts are a great way to check on your boyfriend during the day. It feels great to have someone check on you just because they love you and care for you that much. You don't even have to say much. Something as simple as "I'm thinking of you, love. Have a great day" will put a smile on his face. See, coming up with romantic things to say to your boyfriend in a text is not rocket science.


text: This news item expired on Tuesday, October 9, 2012 so the information below could be outdated or incorrect. Tuesday, October 9 at 1pm Leicester Library 1561 Alexander Road 250-6480 The book to be discussed is "Back When We Were Grownups" by Anne Tyler. All interested readers are welcome to attend.


text:
It only takes a minute to get started. Fill out our uncomplicated sign up form and login to the site.
This step is up to you but will greatly increase your chances of your profile getting read by other members. Let people know a bit about yourself, your pasttimes and atach your nicest photo of yourself.
Use our website's cutting-edge search to locate over 60s members who match your criteria. Or just look through listings and locate members that arouse your interest.
Discovered someone who you like the look of? Send a letter to them or just a wink and see if they're interested. With a little luck you'll be on your way to locating that special someone for you.
You won't regret it


text:
Flat Battery? Get a great value replacement in Hendon with Who Can Fix My Car TODAY!
Enter Your Registration to compare prices and get a new Lada Battery fitted now!
Flat Battery? Get a great value replacement in Hendon with Who Can Fix My Car TODAY!
Shahid went out of his way to assist me . I would highly recommend his establishment to anyone.
I had a big dent on the RHS side back wheel arc of my car. A good professional job that was done at a reasonable price. Definitely recommend Shahid and his team.
Very good service. Shahid and his men were awesome. Had a full service done all looks good. There are so many crooks around now a days. I will drive the car around the next few weeks hopefully all is well. If all is good they will see me more often via MOT AND SERVICING. Thanks guys.
All round good garage. With good mechanics
Stayed late on a bank holiday weekend, fixed my car promptly. Great service from great guys.
they were quick, honest, competitive on price and nice to deal with. I would recommend using them
Great service. Very professional and experts in what they do. Highly recommend.
Professional and very polite. Job finished in the time they said they would complete, and no extra costs. Would use them again.
Awesome garage! Good and fast service and really nice & friendly guys. Really reasonable pricing and honest work, highly recommended. Thanks Al and Patrick!
very professional and polite
Definitely Recommend this garage, great staff, very welcoming and friendly, gives honest advice and good service. Extra things were done without charge. A++++++++
You cannot trust them either..they didn't make oil change and they charge me 30£ for that job, what didn't do, some unreliable..i'm sitting customer room and i cannot see, what they do..watch out this garage..i cannot recommended them ! They try to charge brake discs too, discs not always need to change same time, when pads..
Job could have been done a little bit quicker but very good service overall!
Happy with the service provided. Job done well.
Good service and pleasant staff
New clutch, one new tyre and a few other little bits, highly recommend, good service and kept me updated throughout
Alex was friendly and informative, I would recommend this garage. My car was fixed within 24 hours which was great and as an extra bonus i was also provided a courtesy car which was very handy. This garage will be my go-to garage from now. Thank you very much.
absolutely superb service from Alex. highly recommended and i will continue to use for all my cars. the guy was very honest and fair and treated us better then most main dealers. Southgate motor engineering is a example to how all garages should do business.customer for life
had my car remapped stage 1 from 122 bhp - 142 bhp Made a really nice change to the car with the extra power, great work at a great garage, would recommend 100%
Absolutely brilliant service. Quoted and delivered work faster than expected. Would definitely recommend.
great job
Had some extra work done
They did a great job and it was all done very quickly. I'd certainly go back.
Great, final bill ended up being less than what was quoted!
Excellent customer service


text:
|Message view
|« Date » · « Thread »
|« Date » · « Thread »
|"Banck, Arent-Jan" <ajba...@informatica.com>
|RE: Add / remove ProjectNotifiers using XML-RPC in Continuum 1.0.3
|Tue, 23 Oct 2007 12:41:37 GMT
Notifiers are indeed missing in ProjectReader. After adding the code I found that calling continuum.getProjects does not set the developers and notifiers. When calling continuum.getProject for an individual project, these are set as expected. Looks like this is a bug in getProjects. Stepping through ProjectReader I found it is very buggy. For example all boolean fields are populated with Boolean.getBoolean(system property lookup method) instead of Boolean.valueOf, causing all booleans to be set as false. Considering this, would it be wise to get into this/patch for 1.0.x, or see it as a dead-end for 1.0.x and wait/go for 1.1? Thanks, Arent-Jan -----Original Message----- From: Emmanuel Venisse [mailto:firstname.lastname@example.com] Sent: Tuesday, October 23, 2007 1:17 PM To: firstname.lastname@example.com Subject: Re: Add / remove ProjectNotifiers using XML-RPC in Continuum 1.0.3 I don't think it's possible. Some features was missing in 1.0.3. You can checkout the code of 1.0.3 and create a patch. Emmanuel Banck, Arent-Jan a écrit : > Hi, > I am trying to use the XML-RPC API to manage the notifiers for a > project, but am unsuccessful doing so. > When adding notifiers in the web-ui, and iterating over the > projects/notifiers, list of notifiers length is always zero. > I am using SampleClient.java as basis, code snippet: > projects = pr.readProjects(); > for ( int i = 0; i < projects.length; i++ ) > { > System.out.println( projects[i] + " - Name=" + > projects[i].getName() ); > > List notifiers = projects[i].getNotifiers(); > System.out.println(notifiers.size()); // Always zero > > When trying to add a notifier by creating a new one and adding it by: > projects[i].addNotifier(newNotifier); > the notifier doesn't seem to get added. > > Am I missing something here, what to do to get this working? > > Thanks, > > Arent-Jan >
|View raw message


text:
John Michael Montgomery Hold On To Me
Hold On To Me is a song by American country singer John Michael Montgomery from the album Leave a Mark. The single reached the Billboard Top 100 chart.
The official music video for Hold On To Me premiered on YouTube at the end of September 1998. Watch John Michael Montgomery perform the song.
Hold On To Me Lyrics
The lyrics to Hold On To Me were written by Blair Daly and Will Rambeaux.Top Country Songs


text:
Watch Young Big titted Cutie Knows How To Work Cock by HD Sex Club Porn Video
Related Videos
- 29:37Look at DAT BOOTY on Brianna Brooks Get Pounded96% Like3 weeks ago
- 18:44Kinky Boricua is Turned-on For Boner92% Like2 years ago
- 22:00Vanessa Lane Wants Daily Portion Of Cum85% Like2 years ago
- 25:28Hairy Honey With Firm Muff Gets Banged & Creamed81% Like2 years ago
- 23:28Sexy Squirter Cytheria Takes A Hot Oozing Pussy Creampie86% Like10 months ago
- 22:26Panty Sniffer Fucks Punished Daughter83% Like4 years ago
- 17:09Latin Slut Is Ready to Fuck Anyone92% Like7 months ago
- 28:45Vanessa Lane Pays For Lunch92% Like3 weeks ago
- 6:14Mature Amateur Facial Cumshots In The Changing Room100% Like3 years ago
- 26:41Vanessa Lane Drilled In Her Stinking Ass96% Like3 years ago
- 28:54COUGAR Nicole Moore Pays With Cunt86% Like10 months ago
- 25:07Hot Slut Ass Fucked By Two Hung Studs79% Like2 years ago
Enjoy Young Big titted Cutie Knows How To Work Cock video offered by HD Sex Club Tube . Also you can add this free Sex video to your favorites or Add Young Big titted Cutie Knows How To Work Cock to your site, to your blog using the embed codes of the Porn Video, pin it or share it to social networks (facebook, twitter , tumblr, google + ,delicious, digg , rebbit etc) or post it to adult forums. Be An Active Member of HD-SexClub.com tube and connect with other community members


text:
Handbuch ItemsMore than 100 items were found
RentList Price:$172.95
RentList Price:$203.95
List Price:$115.95
Kanon in Konstruktion Und Dekonstruktion: Kanonisierungsprozesse religioser Texte von der Antike bis zur Gegenwart (German Edition)List Price:$238.00
Cytologie und Lymphadenitis (Handbuch der speziellen pathologischen Anatomie und Histologie / Blut, Knochenmark, Lymphknoten, Milz.) (German Edition)List Price:$69.95
RentList Price:$122.95
List Price:$147.00
Indian Islamic Architecture: Forms and Typologies, Sites and Monuments (Handbook of Oriental Studies/Handbuch Der Orientalistik. Section 2 India)List Price:$153.00
List Price:$96.59
Plexus und Meningen. Saccus vasculosus (Handbuch der mikroskopischen Anatomie des Menschen Handbook of Mikroscopic Anatomy / Nervensystem) (German Edition)RentList Price:$59.99
BookRenter.com's 5-Star Satisfaction Guarantee
We strive to deliver the best value to our customers and ensure complete satisfaction for all our textbook rentals.
- You can return your online books for any reason within our refund period – no questions asked.
- Every order is available for express shipping, and return shipping is always free.
- You'll be happy with the quality of your books (or we'll ship you another one on our dime).
- You can extend your rental up to 14 days – at the same cheap daily rental rate.
- If you decide to keep the book it will never cost more than the purchase price.
As always, you have access to over 5 million titles. Plus, you can choose from 5 rental periods, so you only pay for what you'll use. And if you ever run into trouble, our top-notch U.S. based Customer Service team is ready to help by email, chat or phone.
* Free shipping excludes HI, AK and PR.
Semester Guarantee
Order now and we'll cover you through the end of the semester!
We're automatically extending 125-day rental orders toMay 21, 2012*. It's our way of giving those of you who plan ahead a special "Thank You."
For all your procrastinators, the Semester Guarantee program lasts through January 11, 2012, so get going!
*It can take up to 24 hours for the extension to appear in your account.
**BookRenter reserves the right to terminate this promotion at any time.
BookRenter.com's Fast Shipping Both Ways
With Standard Shipping for the continental U.S., you'll receive your order in 3-7 business days.
Need it faster? Our shipping page details our Express & Express Plus options.
Shipping for rental returns is free. Simply print your prepaid shipping label available from the returns page under My Account. For more information see the How to Return page.


text:
Login/Create Account
Check Out the new Remax App
Ask About This Home
Renovated Cape Cod facing the water with beautiful views of the Potomac! This home is situated on a double lot- with fenced yard and a one car garage- Brand New Kitchen/Appliances/Floors Refinished/Paint/Windows/(Roof. Siding/HVAC all within last 3 years) New bathrooms/with Ceramic Tile-Playroom/Bonus Room Upstairs-Buy your second home or purchase this as a rental investment!


text:
Unable to send, receive, encrypt and decrypt email messages.
This can be due if a standalone client is trying to communicate with PGP Universal Server as a managed client.
1. Check if the PGP Universal version and PGP Desktop version are the latest version.
Terms of use for this information are found in Legal Notices.
Terms of use for this information are found in Legal Notices.
Login to Subscribe
Please login to set up your subscription.
Get support for your product, with downloads, knowledge base articles, documentation, and more.
Maximize your product competency and validate technical knowledge to gain the most benefit from your IT investments.
Submit a suspected infected file to Symantec.
Report a suspected erroneous detection (false positive).
Set default language
Do you wish to save this as your future site?


text:
Latest gameson glulo.com
Raven Queen Real Haircuts- Played: 1,923 times
In Ever After High you get to be a Royal or a Rebel, and Raven wants to prove that she won't walk in her mother's footsteps with a spelltacular new bold haircut. Help this Rebel reinvent her look by using the most glamorous colors to dye her hair. Cut, curl or magically make the hair grow back, then dress her up to add the finishing touches.
Use your mouse to play this game.


text:
ED Magedson – Founder
Ripoff Report
hair club for men and women235 YORKLAND BLV,SUITE 1000 TORONTO, Ontario Canada
Does your business have a bad reputation?
Fix it the right way.
Corporate Advocacy Program™
This report was posted on Ripoff Report on 07/29/2012 03:29 PM and is a permanent record located here: http://www.ripoffreport.com/reports/hair-club-for-men-and-women/toronto-ontario-m2j-4y8/hair-club-for-men-and-women-hcfmw-hair-club-for-men-and-womens-conspiracy-lies-deceptio-919293. The posting time indicated is Arizona local time. Arizona does not observe daylight savings so the post time may be Mountain or Pacific depending on the time of year.
Ripoff Report has an exclusive license to this report. It may not be copied without the written permission of Ripoff Report. READ: Foreign websites steal our content
Click Here to read other Ripoff Reports on hair club for men and women
If you would like to see more Rip-off Reports on this company/individual, search here:Search Tips
In order to assure the best results in your search:
#1 Author of original report
SUBMITTED: Sunday, August 12, 2012POSTED: Sunday, August 12, 2012
Are you an owner, employee or ex-employee with either negative or positive information about the company or individual, or can you provide "insider information" on this company?
Advertisers above have met our
strict standards for business conduct.


text:
Does this restaurant specialise in Southwestern style food?
Does this restaurant accept bookings?
Is this restaurant wheelchair accessible?
Is this restaurant good for breakfast?
Is this restaurant good for lunch?
Is this restaurant good for dinner?
Is this restaurant good for business meetings?
Does this restaurant have a full bar?
Is this restaurant appropriate for Kids?
Is this restaurant good for large groups?
Thanks for helping!
The food was good but nothing to write home about. The service was slow and staff was average. Prices was average for around town.
This is a very causal but first class Mexican grille. Beautifully renovated. Food, service, ambiance, it's all there. Fairly priced.
Shared a plate of ribs with salad. Good atmosphere and friendly staff. Would advise staff that a salad should be completed before bringing main course. Only complaint as Ramona lacked dining options, and I was pleasantly surprised that Nuevo Grill offered BBQ ribs, as well as steak and the typical Mexican food.
This is our "Go-To" restaurant in Ramona. I love their Chicken Tortilla Soup. I also like the out-door dinning if we want to bring our dog. The chip are wonderful. Over all it is a great reasonable priced restaurant.
Nuevo Grill is a favorite of ours. It never fails to serve a tasty and large plate. Almost always have a doggy bag for the next day's lunch! 5 stars for food and friendly staff.
This was a return visit. The food quality was very good. The waitress we had today however seemed less than capable. VERY SLOW.
We were having a special dinner on this day after picking our daughter up from the airport who had come home for college break, we entered the restaurant and were seated promptly and within a few minutes were ordering our beverages, when they arrived the order was incorrect giving my daughter a margarita which was completely opposite of what she...
This is a local Mexican restaurant which has a nice selection of entres'. The food is suited mostly for "gringos" who enjoy great flavor without the "heat". They offer a full bar. The service is usually very good and the food comes to the table nice and hot. Portions are plentiful and there's no need to go hungry.
We have always had great lunches here. Absolutely love the grilled fish tacos. These might be my all time favorite. Plenty of choices of beverages. Beers on tap. Many menu items. Even somethings for people who want burgers. Service was great. I really like not having to ask for a refill. Located in a really nice shopping area. Plenty of...
I've been coming here for over 10 years. This restaurant recently had a much needed facelift. While it now looks good unfortunately they haven't done anything about the cooks. In the past the waitresses knew us and were very friendly but they have mostly gone now and a younger staff now waits tables. Younger does not mean better. I would...
Own or manage this property? Claim your listing for free to respond to reviews, update your profile and much more.


text:
|Message view
|« Date » · « Thread »
|« Date » · « Thread »
|"Justin Erenkrantz" <jus...@erenkrantz.com>
|Re: Geronimo request for ASF hosted machines
|Tue, 10 Jun 2008 15:00:05 GMT
On Tue, Jun 10, 2008 at 6:28 AM, Kevan Miller <firstname.lastname@example.com> wrote: > A few weekends back, I installed Ubuntu and worked with it a bit. I didn't > see any big issues. There'll be a bit of a change, from what some are used > to, but nothing major, IMO. Good to hear! Just to ensure you that things aren't being dropped on my end, I've started the quote process with Dell for the two boxes per the specs we talked about earlier. I'll be presenting the quote to the Board at its next meeting for approval. If all goes well, we'll be able to start the ordering and build-out process in late June - so rough ETA would be sometime in July depending upon Dell's order pipeline and how quickly we can set up a new co-lo. Thanks. -- justin
|View raw message


text:
National Naval Medical Center, Bethesda, MD
To compare isoniazid resistant mycobacterium tuberculosis (INHr-TB) treatment outcomes using a biweekly versus daily therapy.METHOD: We retrospectively reviewed all cases of INH resistant and INH-SM resistant TB at a county health department from Dec 1991 to Jan 2003. We included cases with 6 or more months of drug therapy consisting primarily of rifampin(R), pyrazinamide(Z), and ethambutol(E) and active follow up after completion of treatment for 6 months or greater. Fisher exact tests and unpaired t tests were used to assess for statistically significant differences between the biweekly and daily therapy cohorts.
A total of 61 INHr-TB cases were identified. Forty cases met inclusion criteria.Standard daily therapy was given to 17 patients, of which 8 cases were directly observed therapy (DOT), with a mean duration of treatment of 249 days (179–538). Ten cases were pulmonary, 5 were extrapulmonary, and 2 combined. Sputum culture conversion averaged 29 days. Average active follow up was 15 months (6–32) with one patient relapsing 3 months after completion of treatment.Intermittent therapy was given to 23 patients (23 DOT), either biweekly(22) or triweekly(1) with a mean duration of therapy of 230 days (179–391). Sixteen were pulmonary, 5 extrapulmonary, and 2 combined. Two patients were converted to daily therapy due to adverse effects. Sputum culture conversion averaged 40 days. Average active follow up was 12 months (6–26) with no relapses or deaths in this group.No statistically significant difference was seen in treatment length, follow up, or outcomes between the two treatment groups.CONCLUSIONS: Compared to traditional daily therapy, biweekly dosing with RZE appears to be equally effective in those that tolerate the higher doses.
Biweekly therapy has the advantage of overall cost savings and patient convenience with equivalent outcomes compared to traditional daily therapy.
R. Browning, None.
Tuesday, October 28, 2003
Become a CHEST member and receive a FREE subscription as a benefit of membership.
Individuals can purchase this article on ScienceDirect.
Individuals can purchase a subscription to the journal.
Individuals can purchase a subscription to the journal or buy individual articles.
Learn more about membership or Purchase a Full Subscription.
Institutional access is now available through ScienceDirect and can be purchased at myelsevier.com.
Some tools below are only available to our subscribers or users with an online account.
Download citation file:
Web of Science® Times Cited:
Customize your page view by dragging & repositioning the boxes below.
Enter your username and email address. We'll send you a reminder to the email address on record.
Athens and Shibboleth are access management services that provide single sign-on to protected resources. They replace the multiple user names and passwords necessary to access subscription-based content with a single user name and password that can be entered once per session. It operates independently of a user's location or IP address. If your institution uses Athens or Shibboleth authentication, please contact your site administrator to receive your user name and password.