First pictures of Greenock 'bloodbath' murder bid couple
Finlay McIntyre and Karen Branwhite were repeatedly stabbed at their tenement home.
by Jane Hamilton, Julie Dunnett, https://www.dailyrecord.co.uk/authors/jane-hamilton/, https://www.dailyrecord.co.uk/authors/julie-gilbert/The victims of an attempted murder bid in Greenock are in a critical condition in hospital.
Karen Branwhite, 37, and Finlay McIntyre, 52, were repeatedly knifed yesterday in a “horrendous and horrific” targeted attack.
Police said they were following a positive line of inquiry as they hunted the two attackers who carried out the stabbings at about 8.45pm on Tuesday.
Detective Inspector David Wagstaff, of Greenock CID, described the latest attack as “horrendous and horrific”.
He said: “This is a despicable, targeted attack on two people. They sustained knife injuries to their bodies.”
He said the victims were both being treated in a high dependency unit in Glasgow’s Queen Elizabeth University Hospital and their condition was “critical but stable”.
Yesterday, the street was sealed off as police gathered evidence.
A resident, who did not want to be named, said: “This place is getting wild.
“I saw loads of police and the road was totally blocked off for a while. Later on, maintenance men were in cleaning the steps and outside stairs.
“It must have been like a bloodbath.”
Police are asking anyone with information on what happened to get in touch.
Wagstaff said: “The suspects arrived in a silver-coloured taxi and left in the same taxi.
“They then got out of the taxi in Kilmacolm Road, near to Blairmore Road. They were last spotted walking along Kilmacolm Road, going in the direction of Burnhead Street.”
Both suspects were wearing dark clothing and one had a baseball cap on.
Wagstaff added: “We are following positive lines of inquiry. Anyone who witnessed any suspicious behaviour on Belville Street on Tuesday night, or who may have private CCTV covering the area, is asked to come forward.
“We have a number of additional police patrols in the area. If you have any information or concerns, please speak to one of these officers.”


foo
Top-level functions summary
Unit
sectionsTest
()
Unit
seeMeAlso
()
Top-level functions
sectionsTest
fun
sectionsTest
(
)
:
Unit
Exceptions
ArrayOutOfBoundsException
sometimes
Return
It's simple void
See Also
foo.seeMeAlso
seeMeAlso
fun
seeMeAlso
(
)
:
Unit


GTM is now downloaded and installed in <%= gtm_dir %>.
To use GTM:
- Open(or create) your project in XCode
- Create a new target for running unit tests:
- Right click on your application target and choose 'Duplicate'
- Right click on the new target and select 'Get Info'
- Rename the newly created target to (EXISTING_TARGET)UnitTest
- On the 'Build' tab search for 'Product Name' and set the product name to '(EXISTING_PRODUCT)UnitTest'
- Delete 'main.m' from the Test targets's 'Compile Sources''
- Create a new group to for your test dependencies
- Right-click on your project in the 'Groups and Files' sidebar
- Click 'Add>New Group'
- Create a top level group 'Vendor'
- Under 'Vendor' group, create another group called 'Test'
- Right click on the 'Test' group and choose 'Add>Existing Files...'
- When the file dialog pops up, choose the GTM directory
- Add the newly created group to the UnitTest target
- Wire everything up together
- Add a new build phase to run our tests
- Set the script to 'sh Vendor/Test/GTM/UnitTesting/RunIPhoneUnitTest.sh'
- Add the unit tests
- Create a new Group called 'Tests'
- Add existing files from the 'Tests/Unit' directory of your project
- Select the correct target and click 'Build and Run' to launch the tests


Yoooooooo. I’m Damien. I love to build and solve things. Get in touch! dameyawn at gmail.
I like
Reading/Listening
I like to listen to books a lot using the Audible app, and I log it on Goodreads. Also, listening to lots of podcasts lately. I like:
legal
- First Mondays - casusal while technnical and good hosts; Supreme Court news, opinions, guesses and cool guests
- Law 360’s Pro Say - brief but has fun, informal hosts and current, “interesting” legal issues
- The Lawfare Podcast - more formal; recordings of panels/events
digital security
- Hackable? - investigative and lay casts - would be cool to get more interviewees and attack vectors (per topic)
fiction
- Steal the Stars - well voice-acted sci-fi story
- Fictional - This is the elementary school librarian paraphrasing classics you. Really like.
News and History
- Intercepted - Good b/c often news is approached non-biasedly, but Scahill still gets pretty biased sometimes.
- Hardcore History - I really liked listening to two of the previous series on here, but now the speculative format is kinda boring now.
 Some recent games I’ve liked are Rimworld, Brawlhalla, Stardew Valley, and Terraria. My old love is CS.
Mountain Project climbs / ticks and to-do list !
Athlink runs


--- layout: post title: 'Damned if you do, damned if you don''t' date: 2004-07-19 00:00:00 category: social ---
REPORT DAMNS POLITICAL BLOGS screams the Guardian:
"In the frequently damning report, the society says political blogging is still in its infancy. While it still has great potential to engage the electorate, the authors say, blogging forms a very minor part of public debate."
So what the report (which summarises a survey of eight - EIGHT! - people) actually says is: there's not much of it, but it could be great. Hardly "damning".


Wrap <blockquote>
around any HTML to display a quote.
In the Bible, shalom means universal flourishing, wholeness and delight – a rich state of affairs in which natural needs are satisfied and natural gifts fruitfully employed, a state of affairs that inspires joyful wonder as its Creator and Savior opens doors and welcomes the creatures in whom he delights. Shalom, in other words, is the way things ought to be. – Cornelius Plantinga


{{lab.labName}}
Search
Equipment Name
Category
Type
Lab Name
Working Rate
Non-Working Rate
+
{{equipment.equipmentName}}
{{equipment.type}}
{{equipment.equipmentType}}
{{equipment.lab.labName}}
{{equipment.workingRate}}$
{{equipment.nonworkingRate}}$
Available Units
reffered Lab
{{equipmentUnits.available_count}}
{{lab.requestedLab.labName}}
Book


| DOSE: |
1 bowl |
smoked |
Cannabis |
(plant material) |
The night starts with us leaving my house at around eight o'clock in the evening.  We smoked a bowl,
[Erowid Note: Driving while intoxicated or tripping is dangerous and irresponsible because it endangers other people. Don't do it!] drive around aimlessly for a little while, listen to the radio, so on and so forth. We then drop one guy off at his place so he can shower and do whatever else he had to do. Now we have time to kill, so after some discussion we all decide to go into New Orleans and head to a headshop.
 So we pay up, and head on out to the car. None of us notice the five-o who's now parked outside the bar. We get in our car, and my buddy whips out the bong, fills it with water and starts to check it out. He seems satisfied, so we pull out and head on about our business.
The cop who has been parked right across the street from us the whole time, leans out his window and yells,
'HEY! Put ya' head lights on!'
This shakes all of us up a little bit, but the driver flips on the lights, waves at the cop, and we're on our way. Or so we thought.
We get to the end of the street and we're in a parking lot. We donít know what to do, so the guy riding shotgun suggests that we pop a u-turn and head back out to Broadway. Sounds great, except for the fact that all the streets in uptown New Orleans are one way. This right here is the mistake that opens up a whole new can of worms. As we are headed up the street, the same cops we just encountered get out of their car, step into the street and motions for us to stop. At this point, my buddy riding shotgun throws a baggie at me with a 'Here, hold this.'
 So, I throw the bag on the floor and cover it with a t-shirt.
The cop steps to the driver's window and says
'Get out the car.' Doesnít ask for license, registration, nothing. So the driver gets out of the car and the cop asks him
'Am I going to find anything in the Car?' My friend replies
'No sir.'
The cop asked him repeatedly, but my friend held his ground.
All of the sudden the cop changes direction with his questioning.'Have you ever smoked
Marijuana before?'
'No sir.'
Now, we're all kinda buzzed, and we all look like stoners. That car stank like reefer and my buddy riding shotgun is holding an enormous bong in his lap. Im thinking,FUUUUUCCK! Were caught.
While all this is going on Iím sitting in the back, sobered up rather suddenly, trying to wrap my head around whatís going down.
As Iím sitting there, I see Drug Task Force stamped on the squad car. With our luck, we just so happen to get stopped by Narcs.
By now, both my friends are out of the car, handcuffed, with the contents of their pockets on the hood. A pack of cigarettes, lighters, wallets, car keys, the herb that was in the drivers pocket along with all our paraphernalia. Now they turn their attention to me,
'Step out of the car.'
I get out, get pressed up against the car and am cuffed.
Now they ask us, 'Are there anymore drugs in the car?  Yaíll are already going to jail, and unless you want us to destroy your car looking for it, just tell us where it is.'
This is where I made a crucial decision. I donít know about cops else where, but NOPD dudes are not to be taken lightly.
'Excuse me Officer.'
'What the hell do you want?'
'Look, man, there is a baggie and a pipe on the floor behind the passenger seat.'
'Well now we're cooking.'
The cop looks where I told him to look, and finds what I told him he was gonna find.  You're cooperative.
At this point he asks all of us our age. He starts with the driver.
'How old are you?'
'Eighteen'
'You?'
'Eighteen'
Then he asks me. 'And you?'
'Fifteen.'
'You're shitting me. Fifteen?'
'Yes Sir.'
The cop chuckled.
'Well, then tonight's your luck night.  After he put my two friends in the back of the police car, he uncuffed me, called my mother and sent me on my way with this, 'The truth shall set you free.'
These cops were sitting there in their car, eating, and we just kinda fell into their laps, so to speak.
When all was said and done I got out of there scott free, and my buddies spent a night in OPP and got off with a slap on the wrist.
 Most of them would rather forget about a dimes worth of weed then deal with the amount of paperwork that goes with it, but if I get them po'ed, all bets are off.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


Toggle navigation
Stack
Home
About Us
Portfolio
Contact US
About Us
We aim to visualise our dreams into reality and have fun at the same time.
Team
Anuj Mali
Director, Editor, Writer
Gauri Malore
Marketing
Abhijit Pachangane
Director
Aakash Shirwayya
DOP
Chinmay Sawant
Art Director
Nitin Bodade
Music
Kunal Jain
DOP
Pratik Bhojane
Content Creator, Editor
Remember Me
Forgot Password?
or
connect with
Facebook
connect with
Google
connect with
Twitter
Remember Me
Forgot Password?
or
connect with
Facebook
connect with
Google
connect with
Twitter


|
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object cetus.analysis.AnalysisPass cetus.analysis.AliasAnalysis
public class AliasAnalysis
Alias analysis is used to obtain alias sets i.e. sets of variable names that reference the same memory locations, in other words, aliases. Alias information can be flow and/or context sensitive or neither. The implementation of this analysis in Cetus provides two different levels.
Switch off alias analysis intentionally using option level 0 on the command line.
The default for alias analysis is to provide alias information
using advanced interprocedural points-to analysis. See
IPPointsToAnalysis
. Points-to analysis in Cetus is
flow as well as context sensitive i.e. the analysis provides
pointer relationships at every program point using
limited context information as well. Alias analysis can use the
sets of pointer relationships at the relevant program
point to create accurate alias sets. Interprocedural
points-to analysis further helps crucial disambiguation,
especially in the case of arrays.
The advanced interprocedural analyzer is supplemented by a
simple array-argument disambiguation analysis,
ArrayParameterAnalysis
.
PointsToAnalysis
,
IPPointsToAnalysis
,
ArrayParameterAnalysis
| Field Summary |
|---|
| Fields inherited from class cetus.analysis.AnalysisPass |
|---|
program |
| Constructor Summary | |
|---|---|
AliasAnalysis(Program program)
|
| Method Summary | |
|---|---|
void |
displayAliasMap()
Deprecated. |
java.util.Set |
get_alias_set(Statement cur_stmt,
Symbol symbol)
Returns the alias set for the given input symbol, which includes the input symbol itself. |
java.lang.String |
getPassName()
|
boolean |
isAliased(Statement stmt,
Symbol a,
java.util.Set<Symbol> bset)
Returns true if the given Symbol, a, is aliased to any symbol in the set of Symbols, bset. |
boolean |
isAliased(Statement stmt,
Symbol a,
Symbol b)
Returns true if Symbol a is aliased to Symbol b at the given statement. |
void |
start()
This provides the high-level driver for Alias analysis. |
| Methods inherited from class cetus.analysis.AnalysisPass |
|---|
run |
| Methods inherited from class java.lang.Object |
|---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
| Constructor Detail |
|---|
public AliasAnalysis(Program program)
| Method Detail |
|---|
public java.lang.String getPassName()
getPassName
in class AnalysisPass
public void start()
For other global alias analyses, this procedure traverses the IR and collects whole program alias sets. These can be supported by user-provided information regarding interprocedural assumptions.
start
in class AnalysisPass
public java.util.Set get_alias_set(Statement cur_stmt, Symbol symbol)
For advanced analysis, it uses the interface to interprocedural points-to analysis. Alias sets are created from the map returned by the points-to analyzer.
cur_stmt
- Statement used to request flow-sensitive alias
information using advanced points-to analysissymbol
- The variable symbol for which alias sets are being
requested.
@Deprecated public void displayAliasMap()
public boolean isAliased(Statement stmt, Symbol a, Symbol b)
public boolean isAliased(Statement stmt, Symbol a, java.util.Set<Symbol> bset)
|
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |


{% extends "global/Feedback.html" %} {% block explanation %} {% include "lemon_market/Question.html" %}
Solution: Payoffs for the buyer would be 45 points, for seller 1 60 points, and for seller 2 50 points.


MDW Fuse Cookbook – Table of
Contents
Prerequisites:
Get ready
for MDW OSGi development.
JBoss Fuse OSGi Container (6.1.0)
Install locally
for custom development capabilities.
Project Setup:
Use the MDW
Plug-In wizard to build a workflow-faceted Java project.
2. Build Your Workflow Project
And package your
Java code for deployment into the container.
3. Deploy Your Workflow Bundle
Install MDW
and your workflow bundle in JBoss Fuse.
Workflow Development:
Build a basic
process definition.
2. Run Your Process through Designer
Execute your
process using test data.
Use the
Document Web Service adapter activity to invoke a SOAP web service.
4. Implement a Custom Activity
Create your
own Java-based activity implementor.
5. Expose Your Process to External Systems
Register an
MDW service-oriented Event Handler to launch your process.
Create a Dynamic
Java workflow asset and reference it as a process variable.
WebApp
Development:
1. Create a Web Page to Capture User Input
Use the
plug-in wizard to create an XHTML workflow asset.
2. Create a Standalone Custom Page
Build a
completely independent page which accesses a managed bean.
3. Create a Process Launch Page
Use a custom
page to capture input and kick off a workflow process.
4. Customize List Columns and Filters
Integrate
your business data in TaskManager.
5. Override Default TaskManager Resources
Make the standard
TaskManager look exactly the way you want.
6. Design a Report and Access it through the Web
Create a
BIRT report based on workflow data.
MDW Fuse Cookbook – Prerequisites
Set Up
Eclipse on Your PC:
§
\\eldnp1515dm4.ad.qintra.com\union_station\IT\MDW\eclipse
This Eclipse package includes all
the required dependencies except the MDW Plug-In itself. All the necessary features and plug-ins from
eclipse.org (Web Tools Platform, Data Tools Platform, Maven Support, Modeling
Framework, EPF Rich Text Feature, and Business
Intelligence and Reporting Tools) are
incorporated into this bundle.
C:\eclipse_4.4.1\eclipse.exe
-vm C:\jdk1.7.0_45\bin\javaw.exe -vmargs
-Dsun.lang.ClassLoader.allowArraySyntax=true -Xms512m -Xmx1024m
-XX:MaxPermSize=256m
Recommended
Plug-Ins:
·
Gradle Build
Support (Note: Only the Gradle IDE item
is required)
http://dist.springsource.com/release/TOOLS/gradle
Optional
Plug-Ins:
·
Groovy
Eclipse Plug-In (Groovy
script syntax highlighting, auto-complete, etc.)
http://dist.springsource.org/release/GRECLIPSE/e4.4
·
Quantum DB
Plug-In (Database querying)
http://quantum.sourceforge.net/update-site
MDW Fuse Cookbook – Prerequisites
Start with a vanilla installation
of your OSGi container.
Supported OSGi
Containers:
·
JBoss Fuse 6.1.0
(requires MDW 5.5)
(If
downloading from jboss.org, make sure to choose the Full Zip option):
§ http://www.jboss.org/products/fuse/download
1.
Follow the
steps to create a separate
Fuse server instance, which is
required for MDW to be deployed (you cannot use the root instance).
2.
Add the
following lines to INSTANCE_HOME/etc/system.properties:
runtimeEnv=dev
3.
Add the MDW
and Archiva repositories to org.ops4j.pax.url.mvn.repositories in
INSTANCE_HOME/etc/org.ops4j.pax.url.mvn.cfg:
(Note: Add these repository URLs before any existing URLs, and be
careful to include the appropriate commas and line continuation backslashes)
http://archiva.corp.intranet/archiva/repository/mdw,
\
http://archiva.corp.intranet/archiva/repository/development,
\
http://archiva.corp.intranet/archiva/repository/snapshots@snapshots,
\
§
MDW Fuse Resources
On the MDW
SharePoint site, there are a number of example artifacts and an FAQ describing
common issues that can occur when deploying your workflow app on Fuse. Refer to these resources if you encounter
problems while working through this tutorial.
http://cshare.ad.qintra.com/sites/MDW/Developer%20Resources/Environment/Fuse
MDW Database:
·
MDW stores
workflow definition and runtime data in an Oracle or MySQL database. For development you can point to the shared
MDW demo environment. Otherwise you will
need to configure an instance of Oracle or MySQL with the MDW DB schema. Details are outlined in the following
SharePoint location:
§ http://cshare.ad.qintra.com/sites/MDW/Developer
Resources/MDW Database
MDW Fuse Cookbook – Project Setup
1. Create a Local MDW Workflow Project
Local projects in MDW allow you
to create custom Activity Implementors and External Event handlers, and to
override package-level configuration settings locally. Local projects require that a supported container be installed. The MDW Cloud Development Tutorial provides an in-depth comparison between
local and remote cloud projects.
You can start with a preexisting
Java project and convert it to an MDW workflow project. The following steps assume that you're
starting with a clean workspace. If
instead you already have a Java project that you wish to convert, you can
launch the conversion wizard by right-clicking on the project in Package
Explorer view and selecting Configure > Convert to MDW Workflow Project. Make sure to click the "Additional
configuration required..." link to execute the setup wizard (which will be
similar in appearance to the screenshots below). Note: converting an existing Java Project
does not automatically create artifacts such as the pom.xml or build.gradle
build files. For this reason if you
convert an existing project it's recommended that you also generate a
from-scratch example project for reference.
Launch the Workflow
Project Wizard:
·
From the
Eclipse menu select File > New > Project... > MDW Projects > Local Workflow
Project. Type a project name and select the
JBoss Fuse container, and then click Next.
·
Populate the
container-specific Server Settings page.
If you're using a specific container instance other than the root, enter
the instance path for the Server Location.
The SSH port should match the value specified in etc/org.apache.karaf.shell.cfg. The default user/password for instance-level
containers is karaf/karaf. For root
level there is no default user/password, and this must be set up in
etc/users.properties.
·
Enter the
connection information for your MDW database.
The default values correspond to the MDW Development Sandbox environment
(the password is "mdwdemo").
·
When you
click Finish the wizard will create a Java project with the MDW Workflow
project facet. Depending on what you
selected for you project's build tool, it will also be configured for Gradle or
Maven build integration.
Deploy MDW on Your Fuse Server:
·
One way to
deploy an OSGi bundle into Fuse is to manually copy it into the
"deploy" directory in your container instance. However, during iterative development it is far
more convenient to integrate with the Eclipse build process so that your
changes can be published automatically.
For this we'll use the Eclipse Servers view (Window > Show View >
Other > Server > Servers).
·
Right-click
in Servers view and select New > Server.
Select JBoss > Fuse 6.0 for the server type. The server name can be anything, but if you
ever use multiple servers in the same workspace it's handy to reference your
project name and/or instance name.
·
If this is
the first Fuse 6.0 server you've configured, you'll be prompted for the
container root information.
·
Click Next
again to configure your Fuse server instance.
·
Click Next one
more time. Since you’ve not built your
project yet, do not select anything to be added to the Server yet in the Add
and Remove page. Click Finish.
MDW Fuse Cookbook – Project Setup
2. Build Your Workflow Project
Perform the Gradle
Build for Your Project:
·
In Eclipse
Java perspective, show the Gradle Tasks view by selecting Window > Show View
> Other > Gradle > Gradle Tasks.
From the Project dropdown in this view, make sure your workflow project
is selected, and double-click on the "build" task. (Note: if you chose Maven as your build tool
in step 1, then you'll follow a different procedure described in the MDW ServiceMix Cookbook).
Gradle produces your bundle jar
file in the build/libs directory of your project. You can inspect the generated jar file in
this directory along with its MANIFEST.MF to get a feel for how the OSGi bundle
is packaged. The Gradle build also copies
the mdw property file (src/main/resources/etc/com.centurylink.mdw.cfg) with
your environment-specific settings into the etc directory of your Fuse instance. This configuration file is required by the
MDW Framework runtime engine. You can
see how this is accomplished by opening the build.gradle file in the root of
your project and searching for the copyConfig task.
From here on, you can perform
your builds directly through the Eclipse mechanism (ctrl-B). An occasional step that may be required to
synchronize your Eclipse project build path with your Gradle dependencies is to
right-click on the project in Package Explorer and select Gradle > Refresh
Dependencies.
MDW Fuse Cookbook – Project Setup
3. Deploy Your Workflow Bundle
Start Your Server and Open a
Karaf Command Console:
·
Since you
configured your server in Step 1, you can start and stop Fuse from within
Eclipse.
Start the server by
right-clicking on it in Servers view and selecting Start from the menu:
You should
see output in the Server Console view. You
can ignore the following error which is due to a known Fuse bug:
Error in initialization script: Command
not found: shell:if
(You can avoid this error message
on your next restart by commenting out the last line in
FUSE_HOME/etc/shell.init.script).
·
Once the
server is started, you'll be able to open a Karaf command window. By default this runs in a standard Windows
command shell. However, if you have Putty installed you can gain a great deal more
flexibility by telling Eclipse to use Putty for your Karaf window. To accomplish this, from the menu select
Window > Preferences > MDW > Server Runner. Then browse for the location of your
putty.exe executable file and click OK.
·
Now locate
the Server Console view and click on the
Install the MDW Dependencies:
·
MDW also
needs a JMS connection factory. First
make sure the ActiveMQ Blueprint feature is installed by typing the following
in the Karaf console:
addUrl
mvn:org.apache.activemq/activemq-karaf/5.9.0.redhat-610379/xml/features
features:install activemq-blueprint
·
MDW depends
on a number of OSGi bundles, some of which are custom versions hosted in the
CenturyLink corporate Archiva repository.
These can be easily installed via the mdw-dependencies feature through
the following commands in the Karaf console (Note: replace 5.5.xx with
the mdw.version property from your build.gradle file):
addUrl mvn:com.centurylink.mdw/mdw/5.5.xx/xml/dependencies
features:install
mdw-fuse-dependencies
·
Now deploy
the MDW example ActiveMQ broker configuration by right-clicking on the following
link and selecting "Save target as…" to download this file into the
deploy directory of your Fuse instance:
·
Your server
needs to be restarted to apply these changes.
Shutdown Fuse by clicking on the
Install the
MDW Feature:
·
In the
client shell window run these commands to install the MDW OSGi Bundles (replace
5.5.xx with your MDW version). Anytime
you upgrade to a new MDW build, you'll have to uninstall the previous feature and
install the updated one (when it comes time to upgrade, refer to Help >
Cheat Sheets > MDW Workflow > MDW Updates).
addUrl mvn:com.centurylink.mdw/mdw/5.5.xx/xml/features
features:install mdw
·
When the MDW
runtime engine starts up, it precompiles some Dynamic Java workflow assets
(described in later sections). You can
safely ignore any Dynamic Java compilation errors. You can also ignore errors like "org.apache.camel.FailedToCreateRouteException:
Failed to create route…". There's
more about MDW Camel Integration in later sections as well.
·
Test MDW
Access:
§
Access the
MDWHub webapp locally to confirm the install:
Deploy Your Workflow Bundle in Fuse:
·
Right-click
on your server in Servers view and select Add and Remove… from the menu. Add your workflow project to the configured
elements.
·
When you
make changes to your project’s source code, an Eclipse build will trigger an
automatic hot deployment to Fuse (you can double-click on the server in Servers
view to edit publishing options). Test a
code change by opening the WorkflowBundleActivator.java file that was generated
by the workflow project wizard. Edit the
logging output in the start() method so that it says something different, then
save (if Eclipse autobuild is in effect the save triggers a build
automatically; otherwise type ctrl-b to build).
A Gradle build is NOT required.
Within a few seconds Fuse should pick up your change and redeploy, and
you'll see your modified logging output when the bundle is activated.
·
Aside from
whatever custom logging you've added, you should see something like the
following in the Server Console view:
[(i)20130705.11:50:09.671
~21] Starting workflow bundle com.centurylink.myFuse [(i)20130705.11:50:10.343
~21] Registering com.centurylink.mdw.common.provider.ActivityProvider with
unique alias 'myFuseActivities' from bundle com.centurylink.myFuse [(i)20130705.11:50:10.343
~21] Registering com.centurylink.mdw.common.provider.EventHandlerProvider
with unique alias 'myFuseEventHandlers' from bundle com.centurylink.myFuse [(i)20130705.11:50:10.343
~21] Registering
com.centurylink.mdw.common.provider.VariableTranslatorProvider with unique
alias 'myFuseVariableTranslators' from bundle com.centurylink.myFuse [(i)20130705.11:50:10.343
~21] Startup complete for workflow bundle com.centurylink.myFuse
Note: for
subsequent server startups, to prevent premature deployment of your workflow
bundle (before the MDW bundles have successfully deployed), it's a good idea to
set a bundle startup level in the Fuse Karaf console. The syntax is as follows:
bundle-level <my_bundle_id> 80
(This one-time step sets your bundle's
startup level to 80, greater than the range of startup levels specified in the
mdw feature install file).
MDW Fuse Cookbook – Workflow Development
Open the
Designer Perspective in Eclipse:
·
From the
Eclipse menu select Window > Open Perspective > Other > MDW Designer.
·
For detailed
documentation covering Designer functionality, refer to the User Guide:
§
http://cshare.ad.qintra.com/sites/MDW/User%20Documentation/MDW%20Designer%20User%20Guide.doc
Ensure
Permissions:
·
To follow
the steps in this section of the Tutorial you need to be granted the appropriate
roles in the MDW database you're pointed to.
You can view your current privileges by clicking on the Permissions
property tab for the project. An
administrator can grant you the appropriate access using the MDW Task Manager
webapp. For a detailed discussion of
this topic, refer to the "Roles and Permissions" section of the MDW Designer User Guide.
Create a
Workflow Package:
·
Expand the
project tree in Process Explorer. This
triggers Designer to load the high-level definition data contained in the
environment. The MDW development cloud sandbox
database contains quite a few process definitions and workflow artifacts so
this may take a minute or so to complete.
·
The
top-level branches in the project tree represent workflow packages. Your work should be incorporated in a
dedicated package, which will be used for managing resources. For further details refer to the Eclipse
Cheat Sheet (Help > Cheat Sheets > MDW Workflow > Importing, Exporting
and Versioning).
·
Create your
workflow package by right-clicking on your workflow project in Process Explorer
and selecting New > MDW Package.
Note: best practice is to ensure that your package name does not contain
spaces since it may incorporate dynamic Java or Groovy resources.
Create the
Process:
·
Right-click
on your new package in Process Explorer and select New > MDW Process. Enter the process name and description, and
click Finish.
Add some
Variables:
·
In the
Properties View, select the Variables tab for the process and add an input
variable (orderDoc) and two local variables (orderNumber and validationResult)
with types as depicted below.
Add Custom
Logic with Groovy Script:
·
From the
Toolbox View, drag the activity whose icon is labeled "Execute Script"
onto your canvas and insert it into your process flow between the Start and
Stop activities. Change the label for
this new activity to say "Perform Validation".
Tip: To draw a link (or
"transition" in MDW terminology) between activities on the designer
canvas, hold down the Shift key on your keyboard, Click on the upstream
activity, and continue holding down the mouse left click button while Dragging
the cursor to the downstream activity ("shift-click-drag").
·
Right-click
on the activity and select Edit Script from the menu. The default scripting language for MDW is
Groovy (although you can change this in Script property tab for the activity). Update the Groovy script for your activity to
resemble the following:
import
org.w3c.dom.Node; Node
orderNumNode = orderDoc.getFirstChild().getFirstChild().getNextSibling(); orderNumber
= orderNumNode.getFirstChild().getNodeValue(); validationResult
= orderNumNode.getLocalName().equals("orderNumber"); return validationResult;
When you
save the updated Groovy scrip you'll be presented with a message dialog
reminding you that your process definition should be saved to persist your
local changes back to the cloud. And
when you save the process definition your lock on the process may be
released. If this happens the canvas
will take on the appearance of a read-only process. Locking is the mechanism Designer uses to
prevent multiple simultaneous modifications.
If required you can re-lock the process from the Properties view Locking
tab.
Add Multiple
Activity Outcomes:
·
Add another
outbound transition from your "Perform Validation" activity. Assign Result Code values of
"true" and "false" to the respective outgoing transitions
as illustrated below. Save your process
definition. The return value from your
Groovy script drives which of these two transitions will be traversed at
runtime. Save your process design with
these changes.
MDW Fuse Cookbook – Workflow Development
2. Run Your Process through Designer
Display the
Launch Configuration Dialog:
· Right-click on your process in Process Explorer view and Select Run. Designer will present the launch dialog and open a connection to Fuse to confirm that the server is running (required for launching a process).
Populate the
Input Variable:
·
Select the
Variables tab in the launch dialog, and populate the orderDoc variable with the
following content.
Launch and
View an Instance:
·
Click Run on
the launch dialog to run an instance of your process. You can open the process instance by
right-clicking on your process in Process Explorer view and selecting View
Instances. The latest instance will
appear at the top of the Process Instances view, and you can double-click on
the instance to open its runtime view. In
the process instance view you should see that the new instance traversed down
the happy path with a validation outcome equal to 'true'.
·
Click on the
Variables tab in the Properties view for the process instance to inspect the
runtime variable values.
Dynamically
Change Script Code and Rerun:
·
Change the Groovy
source so that validation expects an order number that begins with a digit:
validationResult =
orderNumNode.getLocalName().equals("orderNumber") &&
Character.isDigit(orderNumber.charAt(0));
·
Save your
process, and launch by right-clicking and selecting Run. Your previous value for orderDoc should be
remembered. Click the Run button on the
launch dialog. This time when your
process instance finishes executing, the validation result should reflect
'false'. Note that for your source code
changes to take effect you did not need to republish or redeploy; the changes
were automatically picked up and dynamically compiled by the runtime engine.
MDW Fuse Cookbook – Workflow Development
MDW comes with the Document Web
Service Activity for consuming document-style services hosted by external
providers. In this exercise we'll invoke
the GetEmployee service hosted in the MDW Development Cloud (and this service
itself is implemented as an MDW workflow process; the sections ahead describe
how to create and expose a service process).
Use the
Document Web Service Activity:
·
Open the
same process definition you started building in the sections above. Add another String variable called customerId,
and an Integer variable called discountPercent.
Edit the script in Perform Validation to assign the customerId variable according
to a node in the input document:
·
Drag the
Document Web Service activity onto the design canvas and insert it downstream
of Perform Validation. Label the web
service activity "Check Employee", and give it two separate outcomes
corresponding to true and false, just like the validation activity.
On the
Design tab of the service, set the Endpoint/WSDL URL to : http://lxdenvmtc143.dev.qintra.com:7021/MDWWeb/SOAP.
Add Pre and
Post Script:
·
In adapter
activities such as the Document Web Service activity, you can associate script
to be executed before and after the service call. Prescript can be used to build the service
request, and postscript can be used for processing the response. Double-click on the Check Employee activity
and select the Script property tab. Edit
the prescript to return a request that includes the customerId variable:
return '''<GetEmployee> <sapId>''' + customerId
+ '''</sapId> </GetEmployee>''';
·
Add new
process variables to hold the service request (name=employeeServiceRequest,
type=com.centurylink.mdw.model.StringDocument) and response
(name=employeeServiceResponse, type=org.w3c.dom.Document). On the Design tab of the Check Employee web
service activity, select these new variables in the Request Variable and Response
Variable dropdowns respectively. Edit
the postscript so that it assigns a value to discountPercent based on the
response:
import
org.w3c.dom.Node; import
org.w3c.dom.NodeList; NodeList
nodes = employeeServiceResponse.getFirstChild().getChildNodes(); String
firstName = null; String
lastName = null; for (int i = 0; i
< nodes.getLength(); i++) { Node node = nodes.item(i); if ("firstName".equals(node.getLocalName())) firstName =
node.getFirstChild().getNodeValue(); else if ("lastName".equals(node.getLocalName())) lastName =
node.getFirstChild().getNodeValue(); } if (firstName
!= null && lastName != null) { println 'Found employee: ' + firstName
+ ' ' + lastName; discountPercent = 10; return true; } else { println 'Employee not found: ' + customerId; discountPercent = 0; return false; }
Save and Run
Your Process:
·
Save the
modified process. When prompted, elect
to "Save as new minor version".
Whenever a process design that has runtime instances is changed
structurally (new activities or transitions), it is highly recommended that you
increment the version number so that Designer can correctly display runtime
data in the process instance view.
·
Right-click
on a blank spot in the designer canvas and select Run to open the launch
configuration dialog. On the Variables
tab change the value for orderDoc to include a valid orderNumber (with a digit
as the first character), and also your CenturyLink SAP ID for the customerId:
<order>
<orderNumber>012345678</orderNumber>
<customerId>DHO115360</customerId> </order>
·
Right-click
again on a blank spot and select View Instances. Double-click the instance to open it. It should reflect that the service was
invoked, your SAP ID was found, and the discountPercent variable should be set
to 10. Double-click on the Check
Employee activity in the process instance.
On the Instance property tab, double-click on the instance row to
display the raw SOAP request and response:
MDW Fuse Cookbook – Workflow Development
4. Implement a Custom Activity
Run the
Activity Creation Wizard:
·
Expand your
project in Process Explorer view. If you
don't already have a workflow package for your work, create one by selecting
File > New > MDW Package from the menu.
Right-click on your package and select New > Activity > General
Activity.
·
Note the
distinction between your workflow package and the Java package that appears in
the following screenshot. Your workflow
package contains your processes, assets and dynamic code. The Java package for your custom implementor
resolves to the location of the generated source code in your local Java
project on your hard drive.
·
When you
click Finish the wizard will generate a skeleton activity implementor and
register it in the database so that it will appear in the Toolbox for inclusion
in your processes.
·
Edit the
generated Java code for your activity and save.
package
com.centurylink.myservicemix; import
com.centurylink.mdw.common.utilities.logger.StandardLogger.LogLevel; import
com.centurylink.mdw.common.utilities.timer.Tracked; import
com.centurylink.mdw.workflow.activity.DefaultActivityImpl; import com.centurylink.mdw.activity.ActivityException; @Tracked(LogLevel.TRACE) public class
MyCustomActivity extends DefaultActivityImpl { @Override public void execute() throws
ActivityException { this.loginfo("Doing
something important..."); } }
Add Your
Custom Activity to a Process:
Open
Designer Perspective and find your process definition from Step 2. From the Toolbox view drag your new custom
activity onto the Designer canvas and position it upstream of the existing
script activity. Change the activity
label from the default value and save the process.
Run the
Modified Process:
·
Perform an
Eclipse build (either by autobuild or ctrl-b) and wait until the Server Console
displays the registration output for your bundle's ActivityProvider (which
indicates that your updated bundle has finished deploying).
·
Right-click
on the process and select Run to open the launch dialog. After the process instance is launched you
should see the custom activity log output in your Server Console view.
MDW Fuse Cookbook – Workflow Development
5. Expose Your Process to External Systems
Create an
MDW Service Process:
·
Right-click
on your workflow package in Process Explorer view and select New > MDW
Process. Name your process something
like "My Service Process" and click Finish. In the design canvas, right click on the
process title and select Show Properties.
Then on the Design property tab for your process check the box labeled
"Service Process". In MDW
terminology this designates your process as one that runs synchronously and is
able to generate a response in real time.
For more background on Service Processes, click on the context help link
"Process Configuration Help".
·
Add two
process variables of type org.w3c.dom.Document, an Input variable called
"request" and an Output variable called "response".
·
Drag a
Dynamic Java activity from the Toolbox view onto your canvas, label it
"Hello Response", and insert it into your flow between the Start and
Stop activities. On the Java property tab
for this activity, select "response" as writable. Click "Edit Java Code" and paste
the following to overwrite the body of the execute() method (you'll learn more
about Dynamic Java in the following section).
public Object
execute(Map<String,Object> variables) throws
JavaExecutionException { try { // use XPath to select elements org.w3c.dom.Document request =
(org.w3c.dom.Document)variables.get("request"); javax.xml.xpath.XPath xpath =
javax.xml.xpath.XPathFactory.newInstance().newXPath(); // get the root node name javax.xml.xpath.XPathExpression expr
= xpath.compile("/"); org.w3c.dom.NodeList nodeList =
(org.w3c.dom.NodeList)expr.evaluate(request,
javax.xml.xpath.XPathConstants.NODESET); String rootName =
nodeList.item(0).getChildNodes().item(0).getLocalName(); // get the 'name' value expr = xpath.compile("//name"); nodeList =
(org.w3c.dom.NodeList)expr.evaluate(request,
javax.xml.xpath.XPathConstants.NODESET); String name =
nodeList.item(0).getChildNodes().item(0).getNodeValue(); String reply = "<" + rootName + "Response>\n " + "<reply>Hello, " + name + "!</reply>\n" + "</" + rootName + "Response>"; variables.put("response",
com.centurylink.mdw.xml.DomHelper.toDomDocument(reply)); return null; } catch (Throwable t) { throw new
JavaExecutionException(t.getMessage(), t); } }
·
The
"request" variable is implicitly bound to the contents of the
incoming service request. The
"response" variable that this code populates is the basis for what
will be returned to external systems that invoke your workflow process through
a service call.
·
Before
exposing your process as a service, you can test it in Designer using a process
launch configuration (right-click and select Run…). Populate the "request" input
variable with a value like the following (substitute your name in both the root
element name and the child node value).
<HelloDon> <name>Don Oakes</name> </HelloDon>
·
On the
launch configuration Process tab, select the Synchronous radio button. In the Response Variable dropdown select
"response", so that the Designer plug-in will display your generated
response in the console.
·
The response
displayed in the Process Launch Response console should look something like
this:
<HelloDonResponse> <reply>Hello, Don
Oakes!</reply> </HelloDonResponse>
·
If you
encounter a NoClassDefFoundError for a class in package javax.xml.xpath, then you'll need to add this to the Import-Package
declaration in your build.gradle or pom.xml build file. Once you've successfully launched your
service process, view the latest instance to confirm the values for the request
and response variables.
Create an
External Event Handler:
·
MDW services
are registered using a protocol-neutral mechanism based on the request document
content. This registration is what we
refer to as an External Event Handler (later you'll learn how to use an
alternate registration method based on Apache Camel routes). Once you register an event handler, then by
default it's exposed over all the available transport channels that MDW
supports (SOAP, REST, JMS, etc). For
more information about this mechanism, refer to Help Topic: MDW Designer Help
> Coding and Development > Listeners and External Event Handlers.
·
Right-click
on your workflow package in Process Explorer view and select New > External
Event Handler. For the Handler Action
type the name of the service process you created in the previous step. For the Message Pattern enter an XPath
expression that matches your request document.
In effect, you are telling MDW to launch your service process whenever
it receives a request whose document content matches the configured message
pattern. Note that if a request is
received that matches multiple registered event handlers, then it is undefined
which of those handlers will be invoked.
For this reason it is imperative that you make the XPath expression
unique so that it does not match requests it is not intended to handle (and
therefore hijack those requests from their intended handler).
·
In Process
Explorer view your event handler appears labeled as its associated message
pattern. You can test it by
right-clicking on it and selecting Run, and then filling in the External Event
Request in the launch dialog. When you
run this way Designer submits the request document over HTTP to the MDW RESTful
listener, so it not only tests your process flow but it also tests your Event
Handler registration as well.
·
After
successfully invoking your External Event Handler, you should see the expected
response in the console view, and you should also find that a new instance of
your service process was created.
Implement a
SOAP Web Service:
·
The easiest
way to expose your process as a SOAP service is to create a document-style WSDL
workflow asset that describes it. In
Process Explorer view, right-click on your workflow package and select New >
XML Document. Name it something
appropriate for your service, and select the language as WSDL.
·
Edit the
content of your WSDL to look something like the following (with appropriate
substitutions based on your request and response).
<?xml version="1.0"
encoding="UTF-8"?> <wsdl:definitions name="wsdl-first" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://mdw-servicemix.centurylink.com" targetNamespace="http://mdw-servicemix.centurylink.com"> <wsdl:types> <xsd:schema> <xsd:element name="HelloDon"> <xsd:complexType> <xsd:sequence> <xsd:element name="name" type="xsd:string"
/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="HelloDonResponse"> <xsd:complexType>
<xsd:sequence> <xsd:element name="reply" type="xsd:string"
/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> </wsdl:types> <wsdl:message name="HelloDonRequest"> <wsdl:part name="payload" element="HelloDon"
/> </wsdl:message> <wsdl:message name="HelloDonResponse"> <wsdl:part name="payload" element="HelloDonResponse"
/> </wsdl:message> <wsdl:portType name="Hello"> <wsdl:operation name="Hello"> <wsdl:input message="tns:HelloDonRequest"
/> <wsdl:output message="tns:HelloDonResponse"
/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="HelloSOAPBinding" type="tns:Hello"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"
/> <wsdl:operation name="Hello"> <wsdl:input> <soap:body use="literal"
/> </wsdl:input> <wsdl:output> <soap:body use="literal"
/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="HelloService"> <wsdl:port binding="tns:HelloSOAPBinding" name="soap"> <soap:address location="${MDWFramework.MDWDesigner/services.url}/SOAP/DonsWorkflowPackage/HelloDon.wsdl"
/> </wsdl:port> </wsdl:service> </wsdl:definitions>
·
Note that
this URL is parameterized in the WSDL <soap:address> so that at runtime
it will be substituted with the appropriate base URL for the specific
environment where it's served from
·
Once you
save the WSDL you should be able to access it in your browser from a location similar
to:
http://localhost:8181/MDWWeb/SOAP/DonsWorkflowPackage/HelloDon.wsdl
Invoke Your
Service:
·
The MDWHub
System tab includes a utility that you can use to test your service. Access MDWHub in your browser through a URL
like this (TODO: update screenshot):
Click on the System tab and the HTTP
Poster navigation link (if you don't see the System tab you'll need to be
granted Site Admin permissions for the environment where you're testing). The submittal URL for HTTP Poster defaults to
the MDW REST endpoint, so change the context root from REST to SOAP as
illustrated in the screenshot below.
Populate the Message Body with something like the following:
<?xml version="1.0"
encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <HelloDon> <name>Donald</name> </HelloDon> </soap:Body> </soap:Envelope>
Click on the Send Message button,
and your service process should be executed and you should see a SOAP response
like in this screenshot:
If you have trouble getting Site
Admin access, or you prefer to use another tool like SoapUI or SOAtest, you can
accomplish the same thing by just making sure the endpoint URL is like that in
the screenshot and that your request content inside the SOAP body matches your
registered External Event Handler.
Register
Your Service through a Camel Route:
·
Apache Camel is an "integration framework" that
enables you to link together services through declarative route definitions. As an alternative to the traditional MDW
External Event Handler registration described above, you may choose to expose
your service through a Camel route. The
advantages of this include the advanced transport and filtering
capabilities that Camel supports. For
example, Camel goes beyond the basic XPath message filtering provided by MDW
event handlers to enable filtering according to request header values or even
by complex scripting language expressions.
·
Among other
ways, a Camel route can be defined using a Spring configuration file. When you ran the MDW Eclipse wizard to create
your workflow project back in Project Setup, a Spring config file named
bundle-context.xml was generated for you under
src/main/resources/META-INF/spring. This
file gets embedded into the META-INF directory of your workflow bundle. You could declare your MDW Camel route in
bundle-context.xml, but then you'd be missing out on one of the major benefits
of using MDW: dynamicism. Instead, we'll
create a separate child Spring configuration as a workflow asset that can be
changed without requiring that your bundle be redeployed. In fact, Spring configuration assets in MDW can
be used to inject any Spring-enabled entity into your OSGi bundle context.
·
Right-click on
your workflow package in Process Explorer view, and select New > Camel
Route. Name your route and make sure and
select "Standalone Route" for the Language.
Then update the generated content
with something like the following and save:
<?xml version="1.0"
encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi" xmlns:ctx="http://www.springframework.org/schema/context" xmlns:camel="http://camel.apache.org/schema/spring" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/osgi
http://www.springframework.org/schema/osgi/spring-osgi-1.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd"> <camel:camelContext xmlns="http://camel.apache.org/schema/spring"
xmlns:foo="http://centurylink.com/foo"> <!-- MDW REST Web Service to Launch
a Process --> <route> <from uri="mdw:REST/HelloDon"/> <to uri="mdw:process?name=Dons
Service Process" pattern="InOut"
/> </route> </camel:camelContext> <!-- MDW camel component --> <bean id="mdw"
class="com.centurylink.mdw.camel.MdwComponent"
/> </beans>
The sole route declared within this
camelContext tells the MDW Camel component to register a REST-based web service
and launch Dons Service Process when invoked.
In order for the "mdw:" URI pattern to be supported, the MDW
component bean is declared. Notice that
with the "from" URI in an MDW Camel route you have the option of
specifying a specific endpoint URL path (REST/HelloDon), in contrast to the
standard MDW External Event handler which all use the same endpoint.
· In order for the framework to identify the correct parent Spring app context to associate with your asset, you'll need to set a configuration parameter to tie your workflow package to your OSGi bundle. Right-click on your workflow package in Process Explorer and select Show Properties. Select the Configuration property tab and under Environments click the Add button and enter the name "dev". Add a property named OsgiBundleSymbolicName and under dev assign the value from the symbolicName in your project's build.gradle or pom.xml build file.
Click the Save button to persist this package
configuration setting for your dev environment.
Invoke Your Service through REST:
·
In order to
make use of MDW Camel support, you'll need to add the following dependency to
your build.gradle file:
compile group: "com.centurylink.mdw", name: "mdw-camel", version: mdwVersion
… or in your
pom.xml:
<dependency> <groupId>com.centurylink.mdw</groupId> <artifactId>mdw-camel</artifactId> <version>${mdw.version}</version> </dependency>
Also, since all the wiring magic is
done by reflection, you'll need to explicitly add the following import under
the Import-Package section:
instruction "Import-Package", ... "com.centurylink.mdw.camel", ...
.. or in your pom.xml:
<Import-Package> ... com.centurylink.mdw.camel, ...
Then perform a Gradle or Maven build
to pick up this new dependency.
·
Also, since mdw-camel
is an optional feature, you'll need to install it by typing the following
command at the karaf command prompt:
features:install
camel-cxf
features:install mdw-camel
·
As before
with your SOAP request, you can use MDW Hub's HTTP Poster facility (TODO:
update screenshot) to submit your REST request to the server. The URL should include the path you assigned
in the "from" URI in your Camel route Spring asset.
MDW Fuse Cookbook – Workflow Development
Dynamic Java gives you the
ability to incorporate custom Java logic in your workflow without having to redeploy
your OSGi bundle every time this logic changes.
This gives you the flexibility to rapidly respond to changing business requirements. Dynamic Java artifacts are examples of MDW
Workflow Assets, which are resources that can be changed on the fly as part of
an agile development procedure.
Naturally this power is meant to be used in a responsible and accountable
manner. To this end all workflow assets
provide a common set of features, including:
·
LDAP-based authorization
control
·
Versioning
with comments, history, archiving and rollback
·
Asset
locking to prevent simultaneous modification
·
Rigorous
audit logging to track user changes
·
Import and
export procedures for migrating between environments
·
Custom
attributes allow user-configurable options such as
In the steps below you'll use
Dynamic Java to perform the logic in an activity and to populate a process
variable based on a custom object type.
Create Java
Source Asset:
·
Expand your
project in Process Explorer view, right-click on your workflow package and
select New > Java Source. Name the
Java Source class something like "DonsOrder", and Click Finish to
create a skeletal implementation.
·
Populate the
class definition with the following to require that order numbers begin with a
numeric digit, and save (electing to keep the asset locked and not to increment
the version).
package
DonsWorkflowPackage; import
org.w3c.dom.Document; import org.w3c.dom.Node; public class DonsOrder implements
java.io.Serializable { private String orderNumber; public String
getOrderNumber() { return orderNumber; } private String customerId; public String
getCustomerId() { return customerId; } private boolean valid; public boolean isValid() { return valid; } private String error; public String
getError() { return error; } public
DonsOrder(Document orderDoc) { Node orderNumNode =
orderDoc.getFirstChild().getFirstChild().getNextSibling(); this.orderNumber =
orderNumNode.getFirstChild().getNodeValue(); this.customerId =
orderNumNode.getNextSibling().getNextSibling().getFirstChild().getNodeValue(); } public boolean validate() { if (!Character.isDigit(orderNumber.charAt(0))) { valid = false; error = "Order numbers must begin
with a numeric digit"; } else { valid = true; error = null; } return valid; } public String
toString() { return "orderNumber=" + orderNumber
+ "
customerId=" + customerId; } public boolean equals(Object o) { if (!(o instanceof DonsOrder)) return false; DonsOrder order = (DonsOrder)o; return orderNumber.equals(order.orderNumber) && customerId.equals(order.customerId); } }
Use a
Dynamic Java Activity:
·
Open the non-service
process definition you created back in steps 1 through 3. Add a local process variable of type
"java.lang.Object" and call it "order". Delete the orderNumber, customerId and
validationResult variables since the order state is now encapsulated in your
Dynamic Java object.
·
Drag a
Dynamic Java Activity from the toolbox and insert it at the beginning of your
flow (immediately downstream of the Start activity). Name it "Parse Order Request". On the Java property tab for this activity,
make the order object variable writable.
·
On the same
tab click the "Edit Java Code" hyperlink, and override the execute() method as follows:
public Object
execute(Map<String, Object> variables) throws
JavaExecutionException { DonsOrder order = new DonsOrder((org.w3c.dom.Document)variables.get("orderDoc")); System.out.println("order
number: " + order.getOrderNumber()); variables.put("order", order); return null; }
The return value from this method
drives the subsequent process flow, just as with the script activity. A null return value indicates that the
process should traverse the default (no-label) outbound transition.
·
Update the
"Perform Validation" script activity with the following simplified
code which takes advantage of the behavior of your Dynamic Java object.
boolean result = order.validate(); if (!result) System.out.println("Validation
error: " + order.getError()); return result;
Save and
Execute your Process:
·
Save your
process with an incremented version, and run it with something like the
following order input document so that validation will fail.
<order> <orderNumber>A12345678</orderNumber>
<customerId>DHO115360</customerId> </order>
·
Right-click
somewhere in the design canvas and select View Instances. View the most recent process instance to
confirm that it followed the expected path.
Click on the Variables property tab and double-click the order variable
to see its value. Note: the value
displayed is governed by your toString() implementation. In Dynamic Java objects you should always
implement toString() and equals() methods.
MDW Fuse Cookbook – WebApp Development
MDW comes with a fully functional
TaskManager webapp geared for end-user interaction with workflow processes
through Manual Task activities. Usage is
described in the TaskManager User Guide. This
out-of-the-box (or standard) TaskManager is specifically designed to be
extended, and allows for multiple degrees of customization. At a basic level, you can customize the display
for a particular task as discussed in Step 1 below. However, you can
also expose a completely customized TaskManager by overriding default resources
as in Step 5. Any
TaskManager page, template, image, stylesheet, managed bean, action controller,
etc. can be overridden with a custom version.
This enables you to leverage any prebuilt Task Manager functionality
while delivering a completely customized webapp to suit your specific needs.
1. Create a Web Page to Capture User Input
Add a Manual
Task to the Process:
·
Start with
the workflow process you built in the preceding Workflow Development section of
this guide. Drag a Custom Manual Task
activity onto the design canvas and insert it into the 'false' outcome path
from the validation Script activity.
Label the manual task activity something like "Dons Manual Acknowledge". In the Properties view for the activity,
select the Design tab and set the task name to something like "Dons
Acknowledgement". Set Task Due In to
8 hours. Click the Workgroups tab and
select at least one workgroup to which you belong.
·
Add two more
local variables to the process: ackDate (with type=java.util.Date) and
ackComment (with type=java.lang.String).
·
When you
save your process you'll be prompted to increment the version. Since this process already has instances, and
in the meantime you've changed it structurally (by adding activities and
transitions), it's highly recommended that you increment the version number
when saving.
Create a
Custom Web Page:
·
A custom web
page is an example of a Workflow Asset. The MDW
plug-in provides a wizard-based interface for creating different types of
workflow assets. To create a JSF
Facelet-format custom page, right-click on your package in Process Explorer and
select New > Page. Enter a page name like
donsOrderAck.xhtml (by convention, it's nice to use .xhtml in your page name,
but it's not strictly necessary since the engine recognizes the page type by
the selected Language). Select
customTaskContent as the page template, and click Finish.
·
Paste the
following contents into your new Facelet page and then save. This page illustrates usage of the implicit
"process" managed bean. This
represents the workflow process associated with the manual task, and provides
two-way access to the process variable values.
Another implicit bean that's useful in the context of a manual task is
named "task". This is an
instance of the framework class FullTaskInstance, and provides access to
standard task-related values such as Due Date.
<?xml version="1.0"
encoding="ISO-8859-1" ?> <!DOCTYPE html
PUBLIC "-//W3C//DTD
XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:mdw="http://www.centurylink.com/mdw/jsf" xmlns:rich="http://richfaces.org/rich" xmlns:a4j="http://richfaces.org/a4j"> <ui:composition template="/facelets/layout/baseTask.xhtml"> <ui:define name="taskData"> <rich:panel header="Order
Acknowledgement" styleClass="mdw_defaultPanel"
style="width:800px;"> <h:panelGrid columns="2"
width="100%" cellpadding="6"
cellspacing="2" columnClasses="mdw_label,mdw_value"> <h:outputLabel for="orderNum"
value="Order Number:"/> <h:outputText id="orderNum"
value="#{process.variables.order.orderNumber}"
style="font-weight:bold" /> <h:outputLabel for="ackDate"
value="Date:" /> <rich:calendar id="ackDate"
value="#{process.variables.ackDate}" inputClass="mdw_value" inputStyle="margin-top:-2px;" buttonClass="mdw_calendarBtn" /> <h:outputLabel for="ackComments"
value="Details:" /> <h:inputTextarea id="ackComments"
wrap="off" value="#{process.variables.ackComment}"
rows="6" styleClass="mdw_textAreaInput"
style="width:680px;" /> </h:panelGrid> </rich:panel> </ui:define> </ui:composition> </html>
·
Save the
XHTML page, return to your process design, select the manual task, and display
the Design tab in its Properties view.
In the Custom Page dropdown select the page you just created. Save the process.
Launch the
Process to View your Custom Page:
·
Run the
process so that it flows to the new manual task activity. View the latest instance and you'll see that
execution has halted awaiting user input through your custom page.
·
Access
TaskManager by right-clicking on the top-level workflow project in Process
Explorer view and selecting Web > Task Manager.
·
If you've
not already done so, click the Admin tab to add yourself to a workgroup
associated with the manual task in your process (user-group relationships are
cached in the browser session, so you'll need to close your browser and
relaunch to pick up any changes).
·
Click on the
Workgroup Tasks tab in Task Manager.
Locate the newly-created instance, click its checkbox, and select Claim
in the Action menu.
·
You'll be
navigated to the My Tasks tab where you should see the instance you just
claimed. Click on the Task ID link for
the row to view the custom page. Enter
values in the Order Acknowledgement section, and select Complete in the Task Action
menu.
·
Return to
Designer Perspective in Eclipse, right click in the process instance and select
"Refresh". Flow should have
progressed beyond the manual task activity.
View the variables tab to confirm that the values you entered for
ackDate and ackComments are reflected.
MDW Fuse Cookbook – WebApp Development
2. Create a Standalone Custom
Page
Your requirements may call for
webapp functionality that has nothing to do with standard TaskManager. You can create custom pages that don't depend
on MDW at all. You have the ability to
access workflow process data if desired, and to leverage the stylesheets and
templates provided by TaskManager. But
you can also start completely from scratch if you'd like, or you can
mix-and-match to leverage MDW but with a web user interface that you develop
from the ground up.
Create a
Managed Bean Dynamic Java Object:
·
The secret
to including custom logic in your webapp is Dynamic Java. Within your custom pages you can use the
standard Java expression language syntax to access and update any data that
needs to be displayed by leveraging the JSF Managed Bean annotations. Right-click on your workflow package in
Process Explorer and select New > Java Source. Name your Dynamic Java source asset something
like "DonsHelper.java" and click Finish. Add the following JSF annotations to the
generated class:
@ManagedBean(name="donsHelper") @SessionScoped public class DonsHelper implements
java.io.Serializable {
This
declares your class to be a JSF managed bean in session scope with a logical
name of "donsHelper". You'll
probably notice right away that these annotations are not recognized by the
Java compiler in Eclipse. They are
provided by the Java ServerFaces API, which until now has not been a part of
your project. Add the following
dependency in your build.gradle build file:
providedCompile group: "javax.faces", name:
"javax.faces-api", version:"2.0"
… or in your
pom.xml:
<dependency> <groupId>javax.faces</groupId> <artifactId>javax.faces-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency>
Once you've
saved your build file, Eclipse should be able to discover the necessary imports
if you open your Dynamic Java class and type Ctrl-Shift-O (or Source >
Organize Imports).
·
Now add the
following declarations and methods inside your Dynamic Java class and save:
private String something; public String
getSomething() { return something; } public void
setSomething(String something) { this.something = something; } public Object
doSomething() { System.out.println("something:
"
+ something); javax.faces.context.FacesContext
facesContext = javax.faces.context.FacesContext.getCurrentInstance(); facesContext.addMessage(null, new
javax.faces.application.FacesMessage("Did something.")); return null; }
MDW scans for managed beans on TaskManager
startup, so to pick up and compile your Dynamic Java, you'll need to restart
the mdw-taskmgr bundle from karaf:
list | grep mdw
restart
<taskmgr_bundleid>
Create a
Custom Page that Uses Your Managed Bean:
·
Right-click
on your workflow package in Process Explorer and select New > Page. Name it something like donsPage.xhtml, select
"blank" as the template, and click Finish. Paste in some content like the following
(substituting the logical name of your helper bean in the expressions):
<?xml version="1.0"
encoding="ISO-8859-1" ?> <!DOCTYPE html
PUBLIC "-//W3C//DTD
XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:a4j="http://richfaces.org/a4j" xmlns:rich="http://richfaces.org/rich" xmlns:mdw="http://www.centurylink.com/mdw/jsf"> <ui:composition> <rich:panel header="Very
Important"> <h:form> <h:outputLabel for="somethingInput"
value="Something:"/> <h:inputText id="somethingInput"
value="#{donsHelper.something}" /> <br/> <h:commandButton value="Do
Something" action="#{donsHelper.doSomething}"
style="margin:5px" /> </h:form> </rich:panel> <h:messages style="color:red;font-weight:bold;" /> </ui:composition> </html>
·
Save your
page and access it in your browser by right-clicking on it in Process Explorer
and selecting Run. Note: when you save a workflow asset in Designer, this triggers a
server cache refresh. Due to the
proliferation of workflow assets in the MDW sandbox environment, this can take
some time (during which you'll see output in your Server Console view). Any changes you make to your page are
dynamically applied, but they may not be reflected in your browser until the
server cache refresh has completed.
·
Enter a
value for the text input in your form and click the button. You should see a message indicating that your
action was performed on the server.
In your
Server Console view you should also be able to see output showing the captured
value for the user-entered data.
Use Custom
Layout Templates and Web Resources:
·
TODO.
Add a Custom
Navigation Outcome:
·
TODO.
MDW Fuse Cookbook – WebApp Development
3. Create a Process Launch Page
View the
Auto-Generated Process Launch Page:
·
TODO.
Create a
Custom Page for Launching a Process
·
TODO.
MDW Fuse Cookbook – WebApp Development
4. Customize List Columns and
Filters
TODO
MDW Fuse Cookbook – WebApp Development
5. Override Default TaskManager
Resources
TODO
MDW Fuse Cookbook – WebApp Development
6. Design a Report and Access it through the Web
MDW uses the BIRT
open-source reporting framework. BIRT includes a report-designer plug-in for
Eclipse, as well as an embeddable runtime that enables reports to be displayed in
an MDW webapp.
Create a
BIRT Report Based on the Tasks Data Template:
·
To create a
new BIRT Report, right-click on your package and select New > Report. Name the report, select the Tasks data
template, and then click finish.
·
The wizard
will create a basic manual tasks report.
You'll notice that there are a couple of new views available in the
Designer perspective: the Data Explorer and Palette views:
You'll use
these views in building your report design.
Comprehensive documentation is available under help topic BIRT Report
Developer Guide. However, we'll walk
through a few of the basic steps.
Confirm the
Data Source and Data Set for your Report:
·
The report
creation wizard set up an initial Data Source based on the database connection
parameters for your workflow project. To
view these parameters, expand the Data Sources element in Data Explorer view
and double-click on the MDWDataSource.
·
Because you
chose the Tasks template, the wizard also created an initial task-centric
dataset. Expand the Data Sets element
and double-click on the MDWDataSet.
You'll see the SQL query which selects the raw task data. In the Data Set dialog, select Preview
Results node for a quick glimpse at the actual result set that will be used to
generate the report.
Preview the
Unmodified Report:
·
In the lower
portion of the main Report Design editor, there are a number of tabs to enable
editing of different aspects of the report.
Click on the Preview tab to see what the out-of-the-box report looks
like. This prebuilt report includes a
single user-entered parameter, Start Date.
The first time you preview the report you'll be prompted to enter a
value, and you can just leave the default.
This report demonstrates some aggregation techniques, so you'll notice
that each type of manual task is summarized according to how many instances
exist for each status.
If you scan
the report output you should be able to locate instances of the manual tasks
you created in Step 1 of this section. Note that only tasks which have been assigned
appear in this report.
View the
Report through the Web:
·
End users
generally access reports via the web. To
enable this capability you'll need to install the optional mdw-reports feature
from the karaf command line:
features:install mdw-reports
·
Once this
feature is installed you can view your report in your browser by right-clicking
on it in Process Explorer and selecting Run.
User-entered parameters are captured in the Filters panel, and the
most-recently entered values are remembered as browser cookies. Values for filters can also be passed as URL
parameters. This enables custom webapps
to embed links which drill directly into a report with pre-specified values
depending on the context.
Modify the
Report to Show Oldest Due Date:
·
In Designer
perspective, click on the layout tab at the bottom of the Report Design
editor. Double-click on the column
heading labeled "Avg Due Date".
Change the label to read "Oldest Due Date".
·
Find the
aggregation cell called "Due Date Agg" and double-click it to open
the Aggregation Builder dialog. Select
"MIN" in the Function dropdown.
Select the Preview tab in the editor, which
will prompt you to save the report workflow asset. The preview should reflect your changes. Changes are picked up by the web viewer dynamically,
without needing to redeploy or refresh.
You can also verify your changes in your browser by right-clicking on
the report and selecting Run.


Argemone spp. (Prickly Poppy)
| DOSE: |
repeated |
smoked |
Argemone spp. |
(leaves) |
| |
repeated |
smoked |
Argemone spp. |
(seeds) |
I didn't see any information on Prickly Poppy so I decided to test it out. So I bought an ounce of Prickly Poppy foliage off of an online smoke shop. I gained interest in Prickly Poppy after hearing about it from a friend. We went camping in the desert, and found some growing wildly on the side of the road. Prickly Poppy supposedly grows all over the deserts of the south and southwest. Whenever I find myself driving around Borego Springs, in California, I keep my eyes open for a white flowering plant growing on the roadsides.
The high of the Prickly Poppy is surprisingly similar to Cannabis. It gives a warm, buzzing sensation in the chest area, similar to a body high from Cannabis. Some sites online said that it produces euphoria, but I have to disagree. There was very little euphoria, the high was not mental at all, and more physical. It is short lasting, only about an hour long.
The seeds are believed to give a psychedelic effect when smoked, but I found this not to be true, seeds are more potent than the leaf material however. They tend to explode when heated. Some sites also say that Prickly Poppy can only be smoked once a day, due to some sort of rapid tolerance. Personally I have smoked prickly poppy numerous times a day and felt the effects, but they were much less pronounced.
Overall Prickly Poppy is a good legal high. Very relaxing, would mix very well with cannabis.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


QuickStart¶
Build Image Search In 5 Minutes¶
[6]:
collection_name = 'pokemon_images'
documents = []
for i in range(1, 20):
documents.append({
'image': 'https://assets.pokemon.com/assets/cms2/img/pokedex/full/{}.png'.format(f'{i:03}'),
'pokemon_id' : str(i),
'_id': i
})
[7]:
#1. specify the vdb client
from vectorai.client import ViClient
vi_client = ViClient(username, api_key, url)
vi_client.delete_collection(collection_name)
#2. specify an image encoder
from vectorai.models.deployed import ViImage2Vec
image_encoder = ViImage2Vec(username, api_key, url)
Logged in. Welcome public-demo. To view list of available collections, call list_collections() method.
[7]:
{'status': 'complete', 'message': 'pokemon_images deleted'}
[8]:
#3. insert the documents and encode images simultaneously
# using jobs means that the encoding process takes place on our servers as opposed to your computer
use_jobs = False
if use_jobs:
vi_client.insert_documents(collection_name, documents)
job = vi_client.encode_image_job(collection_name, 'image')
vi_client.wait_till_jobs_complete(collection_name, job['job_id'], job['job_name'])
else:
vi_client.insert_documents(collection_name, documents, models={'image':image_encoder.encode})
[8]:
{'inserted_successfully': 19, 'failed': 0, 'failed_document_ids': []}
[9]:
#4. search
search_results = vi_client.search(collection_name,
image_encoder.encode('https://assets.pokemon.com/assets/cms2/img/pokedex/full/003.png'),
'image_vector_', page_size=5)
#4.2 first result is the query audio itself
vi_client.show_json(search_results, image_fields=['image'], image_width=150)
[9]:
| _id | image | pokemon_id | insert_date_ | _search_score | |
|---|---|---|---|---|---|
| 0 | 3 | 3 | 2020-10-02T07:07:18.799559 | 1.000000 | |
| 1 | 2 | 2 | 2020-10-02T07:07:18.797693 | 0.920337 | |
| 2 | 1 | 1 | 2020-10-02T07:07:18.795655 | 0.838996 | |
| 3 | 17 | 17 | 2020-10-02T07:07:30.587841 | 0.835111 | |
| 4 | 16 | 16 | 2020-10-02T07:07:30.585399 | 0.813012 |
[10]:
#5 recommendation by id
search_by_id_results = vi_client.search_by_id(collection_name, '2', 'image_vector_', page_size=5)
#5.2 first result is the id's audio itself
vi_client.show_json(search_by_id_results, image_fields=['image'], image_width=150)
[10]:
| _id | image | pokemon_id | insert_date_ | _search_score | |
|---|---|---|---|---|---|
| 0 | 2 | 2 | 2020-10-02T07:07:18.797693 | 1.000000 | |
| 1 | 3 | 3 | 2020-10-02T07:07:18.799559 | 0.920337 | |
| 2 | 1 | 1 | 2020-10-02T07:07:18.795655 | 0.895991 | |
| 3 | 7 | 7 | 2020-10-02T07:07:18.807199 | 0.839945 | |
| 4 | 17 | 17 | 2020-10-02T07:07:30.587841 | 0.833277 |
Build Audio Search in 5 Minutes¶
Building Audio search is easy with Vi!
[11]:
collection_name = 'audio_quickstart'
#create the documents
documents = []
for i in range(1, 1001):
documents.append({
'audio': 'https://vecsearch-bucket.s3.us-east-2.amazonaws.com/voices/common_voice_en_{}.wav'.format(i),
'name' : 'common_voice_en_{}.wav'.format(i),
'_id': i
})
[12]:
#1. specify the vdb client
from vectorai.client import ViClient
vi_client = ViClient(username, api_key, url)
vi_client.delete_collection(collection_name)
#2. specify an audio encoder
from vectorai.models.deployed import ViAudio2Vec
audio_encoder = ViAudio2Vec(username, api_key, url)
Logged in. Welcome public-demo. To view list of available collections, call list_collections() method.
[12]:
{'status': 'complete', 'message': 'audio_quickstart deleted'}
[13]:
#3. insert the documents and encode audio simultaneously
use_jobs = True
if use_jobs:
vi_client.insert_documents(collection_name, documents)
job = vi_client.encode_audio_job(collection_name, 'audio')
vi_client.wait_till_jobs_complete(collection_name, job['job_id'], job['job_name'])
else:
vi_client.insert_documents(collection_name, documents, models={'audio':audio_encoder.encode})
d:\kda\vectorai\vectorai\read.py:351: UserWarning: Potential issue. Cannot find a vector field. Check that the vector field is _vector_.
"Potential issue. Cannot find a vector field. Check that the vector field is _vector_."
[13]:
{'inserted_successfully': 1000, 'failed': 0, 'failed_document_ids': []}
{'status': 'Finished'}
[13]:
'Done'
[14]:
import IPython.display as ipd
#4. search
search_results = vi_client.search(collection_name, audio_encoder.encode(documents[0]['audio']),
'audio_vector_', page_size=5)
vi_client.show_json(search_results, audio_fields=['audio'])
[14]:
| _id | name | insert_date_ | audio | _search_score | |
|---|---|---|---|---|---|
| 0 | 1 | common_voice_en_1.wav | 2020-10-02T07:07:34.725378 | 1.000000 | |
| 1 | 12 | common_voice_en_12.wav | 2020-10-02T07:07:34.726100 | 0.893219 | |
| 2 | 32 | common_voice_en_32.wav | 2020-10-02T07:07:35.271638 | 0.891373 | |
| 3 | 20 | common_voice_en_20.wav | 2020-10-02T07:07:35.046128 | 0.882336 | |
| 4 | 15 | common_voice_en_15.wav | 2020-10-02T07:07:34.726251 | 0.877323 |
[15]:
#5 recommendation by id
search_by_id_results = vi_client.search_by_id(collection_name, '2', 'audio_vector_', page_size=5)
vi_client.show_json(search_by_id_results, audio_fields=['audio'])
[15]:
| _id | name | insert_date_ | audio | _search_score | |
|---|---|---|---|---|---|
| 0 | 2 | common_voice_en_2.wav | 2020-10-02T07:07:34.725536 | 1.000000 | |
| 1 | 40 | common_voice_en_40.wav | 2020-10-02T07:07:35.272603 | 0.884632 | |
| 2 | 3 | common_voice_en_3.wav | 2020-10-02T07:07:34.725629 | 0.879187 | |
| 3 | 14 | common_voice_en_14.wav | 2020-10-02T07:07:34.726200 | 0.874556 | |
| 4 | 21 | common_voice_en_21.wav | 2020-10-02T07:07:35.046224 | 0.865409 |
Build Text QA Search in 5 minutes¶
[16]:
%pip install datasets
Requirement already satisfied: datasets in c:\users\jacky\anaconda3\lib\site-packages (1.0.1)
Requirement already satisfied: filelock in c:\users\jacky\anaconda3\lib\site-packages (from datasets) (3.0.12)
Requirement already satisfied: dill in c:\users\jacky\anaconda3\lib\site-packages (from datasets) (<IP_ADDRESS>)
Requirement already satisfied: pyarrow>=0.17.1 in c:\users\jacky\anaconda3\lib\site-packages (from datasets) (1.0.0)
Requirement already satisfied: requests>=2.19.0 in c:\users\jacky\anaconda3\lib\site-packages (from datasets) (2.22.0)
Requirement already satisfied: numpy>=1.17 in c:\users\jacky\anaconda3\lib\site-packages (from datasets) (1.19.1)
Requirement already satisfied: pandas in c:\users\jacky\anaconda3\lib\site-packages (from datasets) (0.25.2)
Requirement already satisfied: tqdm>=4.27 in c:\users\jacky\anaconda3\lib\site-packages (from datasets) (4.36.1)
Requirement already satisfied: xxhash in c:\users\jacky\anaconda3\lib\site-packages (from datasets) (2.0.0)
Requirement already satisfied: certifi>=2017.4.17 in c:\users\jacky\anaconda3\lib\site-packages (from requests>=2.19.0->datasets) (2020.6.20)
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\users\jacky\anaconda3\lib\site-packages (from requests>=2.19.0->datasets) (1.24.2)
Requirement already satisfied: idna<2.9,>=2.5 in c:\users\jacky\anaconda3\lib\site-packages (from requests>=2.19.0->datasets) (2.8)
Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\users\jacky\anaconda3\lib\site-packages (from requests>=2.19.0->datasets) (3.0.4)
Requirement already satisfied: pytz>=2017.2 in c:\users\jacky\anaconda3\lib\site-packages (from pandas->datasets) (2019.3)
Requirement already satisfied: python-dateutil>=2.6.1 in c:\users\jacky\anaconda3\lib\site-packages (from pandas->datasets) (2.8.0)
Requirement already satisfied: six>=1.5 in c:\users\jacky\anaconda3\lib\site-packages (from python-dateutil>=2.6.1->pandas->datasets) (1.12.0)
Note: you may need to restart the kernel to use updated packages.
[ ]:
collection_name = 'squad'
#use huggingface's datasets library to download squad
import datasets
squad_dataset = datasets.load_dataset('squad')
documents = [{'_id':str(n), **d} for n, d in enumerate(squad_dataset['validation'])]
vi_client.delete_collection(collection_name)
[1]:
#1. specify the vdb client
from vectorai.client import ViClient
vi_client = ViClient(username, api_key, url)
vi_client.delete_collection(collection_name)
#2. specify a text encoder
from vectorai.models.deployed import ViText2Vec
text_encoder = ViText2Vec(username, api_key, 'https://api.vctr.ai')
[20]:
#3. insert the documents and encode text simultaneously
use_jobs = True
if use_jobs:
vi_client.insert_documents(collection_name, documents)
job = vi_client.encode_text_job(collection_name, 'question')
vi_client.wait_till_jobs_complete(collection_name, job['job_id'], job['job_name'])
else:
vi_client.insert_documents(collection_name, documents, models={'question':text_encoder}, use_bulk_encode=True)
d:\kda\vectorai\vectorai\read.py:351: UserWarning: Potential issue. Cannot find a vector field. Check that the vector field is _vector_.
"Potential issue. Cannot find a vector field. Check that the vector field is _vector_."
[20]:
{'inserted_successfully': 10570, 'failed': 0, 'failed_document_ids': []}
{'status': 'Finished'}
[20]:
'Done'
[21]:
#4. search
search_results = vi_client.search(collection_name,
text_encoder.encode('who was the winner for nfl fifty'),
'question_vector_', page_size=5)
#4.2 first result is the query text itself
vi_client.results_to_df(search_results)
[21]:
| _id | question | answers | context | insert_date_ | id | title | _search_score | |
|---|---|---|---|---|---|---|---|---|
| 0 | 11 | Who won Super Bowl 50? | {'answer_start': [177, 177, 177], 'text': ['De... | Super Bowl 50 was an American football game to... | 2020-10-02T07:47:06.947313 | 56beace93aeaaa14008c91df | Super_Bowl_50 | 0.798744 |
| 1 | 24 | Who won Super Bowl 50? | {'answer_start': [177, 177, 177], 'text': ['De... | Super Bowl 50 was an American football game to... | 2020-10-02T07:47:07.285182 | 56d20362e7d4791d009025eb | Super_Bowl_50 | 0.798744 |
| 2 | 3 | Which NFL team won Super Bowl 50? | {'answer_start': [177, 177, 177], 'text': ['De... | Super Bowl 50 was an American football game to... | 2020-10-02T07:47:06.946694 | 56be4db0acb8001400a502ef | Super_Bowl_50 | 0.763209 |
| 3 | 55 | Who was the Super Bowl 50 MVP? | {'answer_start': [248, 248, 252], 'text': ['Vo... | The Broncos took an early lead in Super Bowl 5... | 2020-10-02T07:47:07.759154 | 56be4eafacb8001400a50302 | Super_Bowl_50 | 0.754090 |
| 4 | 26 | Which team won Super Bowl 50. | {'answer_start': [177, 177, 177], 'text': ['De... | Super Bowl 50 was an American football game to... | 2020-10-02T07:47:07.285403 | 56d600e31c85041400946eb0 | Super_Bowl_50 | 0.742759 |
[22]:
#5 recommendation by id
search_by_id_results = vi_client.search_by_id(collection_name, documents[50]['_id'], 'question_vector_', page_size=5)
#5.2 first result is the id's text itself
vi_client.results_to_df(search_by_id_results)
[22]:
| _id | question | answers | context | insert_date_ | id | title | _search_score | |
|---|---|---|---|---|---|---|---|---|
| 0 | 50 | Who did Denver beat in the 2015 AFC Championsh... | {'answer_start': [372, 368, 372], 'text': ['Ne... | The Panthers finished the regular season with ... | 2020-10-02T07:47:07.758767 | 56d6017d1c85041400946ec1 | Super_Bowl_50 | 1.000000 |
| 1 | 48 | Who did Denver beat in the AFC championship? | {'answer_start': [372, 368, 372], 'text': ['Ne... | The Panthers finished the regular season with ... | 2020-10-02T07:47:07.758541 | 56d2045de7d4791d009025f6 | Super_Bowl_50 | 0.960072 |
| 2 | 331 | Who did the Broncos beat to win their division... | {'answer_start': [25, 25, 36], 'text': ['Pitts... | The Broncos defeated the Pittsburgh Steelers i... | 2020-10-02T07:47:12.209038 | 56d99f99dc89441400fdb628 | Super_Bowl_50 | 0.923735 |
| 3 | 330 | Who did the Broncos defeat in the AFC Champion... | {'answer_start': [192, 192, 204], 'text': ['Ne... | The Broncos defeated the Pittsburgh Steelers i... | 2020-10-02T07:47:12.208876 | 56d7018a0d65d214001982c5 | Super_Bowl_50 | 0.915792 |
| 4 | 328 | Who did the Broncos beat in the divisional game? | {'answer_start': [25, 21, 36], 'text': ['Pitts... | The Broncos defeated the Pittsburgh Steelers i... | 2020-10-02T07:47:11.956089 | 56d7018a0d65d214001982c2 | Super_Bowl_50 | 0.906187 |
[23]:
#6 hybrid search combining traditional and nlp vector search
search_results = vi_client.hybrid_search(collection_name, 'Peyton Men',
text_encoder.encode('Peyton Men'),
['question_vector_'], ['question'],
traditional_weight=0.015,
page_size=5)
vi_client.results_to_df(search_results)
[23]:
| _id | question | answers | context | insert_date_ | id | title | _search_score | |
|---|---|---|---|---|---|---|---|---|
| 0 | 258 | How old was Peyton Manning in 2015? | {'answer_start': [817, 817, 817], 'text': ['39... | Following their loss in the divisional round o... | 2020-10-02T07:47:11.000830 | 56bf301c3aeaaa14008c9550 | Super_Bowl_50 | 0.641220 |
| 1 | 276 | How may yards did Peyton Manning throw? | {'answer_start': [77, 77, 77], 'text': ['2,249... | Manning finished the year with a career-low 67... | 2020-10-02T07:47:11.239195 | 56bf38383aeaaa14008c956c | Super_Bowl_50 | 0.634783 |
| 2 | 270 | What was Peyton Manning's passer rating for th... | {'answer_start': [44, 44, 44], 'text': ['67.9'... | Manning finished the year with a career-low 67... | 2020-10-02T07:47:11.238646 | 56beb57b3aeaaa14008c9279 | Super_Bowl_50 | 0.617874 |
| 3 | 252 | Who did Peyton Manning play for as a rookie? | {'answer_start': [641, 637, 654], 'text': ['In... | Following their loss in the divisional round o... | 2020-10-02T07:47:10.760423 | 56beb4e43aeaaa14008c9267 | Super_Bowl_50 | 0.612926 |
| 4 | 356 | Peyton Manning took how many different teams t... | {'answer_start': [57, 57, 57, 57], 'text': ['t... | Peyton Manning became the first quarterback ev... | 2020-10-02T07:47:12.428915 | 56d704430d65d214001982de | Super_Bowl_50 | 0.611716 |
[ ]:


Arrow
Idea
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s
Idea
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s
Idea
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s
Lorem Ipsum is simply dummy text of the printing
and typesetting industry.
Lorem Ipsum has been the industry's
standard dummy text ever since the 1500s
Ahmed Yehia Kadry
Developer
Ahmed Yehia Kadry
Developer
Ahmed Yehia Kadry
Developer
Ahmed Yehia Kadry
Developer
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s
Lorem Ipsum is simply dummy text of the printing and
typesetting industry.
Lorem Ipsum has been the
industry's standard dummy text ever since the 1500s


The MultitouchInputMode class provides values for the
inputMode property in the flash.ui.Multitouch class. These
values set the type of touch events the Flash runtime dispatches when the
user interacts with a touch-enabled device.
Constructors
GESTURE
Specifies that TransformGestureEvent, PressAndTapGestureEvent, and
GestureEvent events are dispatched for the related user interaction
supported by the current environment, and other touch events(such as a
simple tap) are interpreted as mouse events.
NONE
Specifies that all user contact with a touch-enabled device is interpreted
as a type of mouse event.


Preparation time
less than 30 mins
Cooking time
10 to 30 mins
Serves
Serves 1
Dietary
Preheat the grill to medium.
For the stuffed mushrooms, heat a little olive oil in a frying pan, add the mushrooms stalk-side down and fry over a gentle heat for 2-3 minutes. Turn over, crumble over the Stilton and season with salt and freshly ground black pepper and continue to fry for 2-3 minutes. Place on a baking tray and place under the grill until the cheese has just melted.
For the creamy leeks, heat the olive oil in a small saucepan, add the leeks and sauté over a gentle heat for 3-4 minutes. Add the garlic and cook for one minute. Add the chives and cream, season with salt and freshly ground black pepper and heat through. Remove from the heat and keep warm.
For the croutons, heat the olive oil in a frying pan, add the garlic and cook over a gentle heat for 1-2 minutes. Add the bread cubes and fry until golden.
To serve, place the mushrooms onto a serving plate, pour around the creamy leeks and scatter with the garlic croutons.


Creates a HTTP client object.
The name of the host to send requests to, such as a domain name or IP.
Whether to send requests to the host via HTTPS or plain HTTP. When true
, the client will use HTTPS.
The name of the host to send requests to, such as a domain name or IP.
Holds the response headers of the last request made as a key->value map. Keys written to this object MUST be lowercase.
Whether to send requests to the host via HTTPS or plain HTTP. When true
, the client will use HTTPS.
Resets the lastResponseHeaders
property. Called before every request send with sendRequest
.
Ensures that a url string only contains the url path, but not the base url of this http client.
Generates a full URL containing the hostname and a normalized url path.
The url path to append to the client's hostname. The url path will be normalized.
Returns the hostname this http client sends requests to.
Returns the http client's protocol as a string.
Returns a response header value from the last request that was made. Returns undefined
if no header field with this name exists or if no requests were made yet.
The name of the header to get. This is case insensitive.
Returns true
if the http client uses HTTPS, false
if it uses HTTP.
Converts a key->value object to a query string.
Sends a request and returns the response as an object.
The path (relative to the client's hostname) to send the request to.
The HTTP method to send the request with.
A key->value map that holds the parameters to send along with the request.
A key->value map that holds request headers to be sent.
Sends a request and returns the response as an object.
The path (relative to the client's hostname) to send the request to.
The HTTP method to send the request with.
A key->value map that holds the parameters to send along with the request.
A key->value map that holds request headers to be sent.
Stores a response header.
The name of the header.
The header's value.
Converts a HttpMethod
enum value to a string.
The HttpMethod
enum value to convert to a string.
Checks whether a value is a valid HttpMethod
enum value.
The value to check.
Normalizes a host name.
Normalizes a URL path.
Checks whether XMLHttpRequest
is supported.
Generated using TypeDoc
HTTP client objects can send requests to a host and return the response. For simplicity, they only support one host name at a time, which has to be set when the client object is created. This avoids having to add the host name to every call against the
sendRequest
method.


Issue 80
Welcome to another issue of Haskell Weekly!  This is a weekly summary of what’s going on in its community.
Want to see something featured in Haskell Weekly? We love contributions! Tweet us at @HaskellWeekly or open a pull request.
Featured
-
I’ve just released HLint 2.0.10, which includes a rule to recognize uses of
foldr
that should really bemap
. As an example:foldr (\curr acc -> (+1) curr : acc) []
Can be rewritten as:map (\curr -> (+1) curr)
-
Computing with impossible types
Edward Kmett recently posted a puzzling gist seemingly showing that at the type level, the
()
kind has more than one inhabitant. The goal of this post is to explain what’s going on. -
Authorization in Servant: Walkthrough
This article is about
servant-server
0.11’sexperimental-auth
which is still in experimental stage. Deployment in production is not encouraged. And yes, I know aboutservant-auth
but I haven’t read it thoroughly, yet. -
We wanted to try out some of these new (to us) ideas to see how they would gel together and whether we would want to use any of them in production. What follows is my account of using David Reaver’s event-sourcing/CQRS library, Eventful, to build our email sign-up backend.
-
Organizing our effects effectively
We’ll observe some of the weaknesses of this system, and how we can improve on them. This week will focus on an approach with type classes and monad transformers. In a couple weeks, we’ll consider free monads, and how we can use them.
-
Semantic integrity checks are the next generation of semantic versioning
The Dhall configuration language just added support for “semantic integrity checks”. This post explains what “semantic integrity check” means, motivates the new feature, and compares to semantic versioning.
-
On types and intent: How much can we communicate using types?
Instead of fighting, we should strive together to find a deeper understanding of the principles and trade-off that are involved when writing and evolving code. I would like to make such attempt today by opening a conversation on the communicative power of types.
-
Proofs and programs and rhetoric
When such a person reads the statement in question, it comes across as being a self-satisfied kind of ivory-tower sentiment. Which — not at all coincidentally! — is exactly the impression that many working programmers have of functional programmers.
-
Functional programming provides many advantages, and its popularity has been increasing as a result. However, each programming paradigm comes with its own unique jargon and FP is no exception. By providing a glossary, we hope to make learning FP easier.
-
Sum of heights in a binary tree
Every year when teaching data structures I always forget how to analyze the cost of building a binary heap, which amounts to summing the heights of all the nodes in a full binary tree. So I’m writing down the (lovely) proof here in the hopes that I will remember it next time.
Jobs
-
Functional programmers at Myrtle Software
Myrtle is looking for skilled developers to join our growing development team and assist with the development of our core compiler technology. Ideally candidates would have an interest in either efficient hardware design and/or machine learning models and frameworks.
In brief
Package of the week
This week’s package of the week is Smudge, a language for describing state machines as well as a compiler that interprets and validates those descriptions to generate code and documentation for them.
Call for participation
- dejafu: Add named-thread variants of the withAsync functions
- hadrian: Put cWarnings in a different file
- servant-checked-exceptions: add note about having to be careful with letting aeson derive FromJSON and ToJSON instances
Events
- November 9: Haskell Hackers: The South SF Bay Haskell User Group: Jon Coens: Hotswapping Haskell
- November 10: Austin Types, Theorems, and Programming Languages: Going through Software Foundations by Benjamin Pierce
- November 13: Vancouver Functional Programmers: Haskell peer study group
- November 14: Intersections KW: Functional abstractions in Haskell
- November 15: Noisebridge Hackerspace: Philip Wadler guest talk on functional programming and type theory
- November 16: Categorical Databases: Intro to categories and functors by David Spivak