Issues With Pickle Module¶
This article describes various limitations on what data can be stored using the “pickle” module from a WSGI application script file. This arises due to the fact that a WSGI application script file is not treated exactly the same as a standard Python module.
Note that these limitations only apply to the WSGI application script file
which is the target of the WSGIScriptAlias, AddHandler or Action
directives. Any standard Python modules or packages which make up an
application and which are being imported from directories located in
sys.path
using the ‘import’ statement are not affected.
Packing And Script Reloading¶
The first source of problems and limitations is how the operation of the “pickle” serialisation routine is affected by the ability of mod_wsgi to automatically reload WSGI application script files. The particular types of data which are known to be affected are function objects and class objects.
To illustrate the problems and where they arise, consider the following output from an interactive Python session:
>>> import pickle
>>> def a(): pass
...
>>> pickle.dumps(a)
'c__main__\na\np0\n.'
>>> z = a
>>> pickle.dumps(z)
'c__main__\na\np0\n.'
As can be seen, it is possible to pickle a function object. This can be done even through a copy of the function object by reference, although in that case the pickled object still refers to the original function object.
If now the original function object is deleted however, and the copy of the function object is pickled, a failure will occur:
>>> del a
>>> pickle.dumps(z)
... <deleted>
pickle.PicklingError: Can't pickle <function a at 0x612b0>: it's not found as __main__.a
Traceback (most recent call last):
The exception has been raised because the original function object was deleted from where it was created. It occurs because the copy of the original function object is still internally identified by the name which it was assigned at the point of creation. The “pickle” serialisation routine will check that the original object as identified by the name still exists. If it doesn’t exist, it will refuse to serialise the object.
Creating a new function object in place of the original function object does not eliminate the problem, although it does result in a different sort of exception:
>>> def a(): pass
...
>>> pickle.dumps(z)
... <deleted>
pickle.PicklingError: Can't pickle <function a at 0x612b0>: it's not the same object as __main__.a
Traceback (most recent call last):
In this case, the “pickle” serialisation routine recognises that “a” exists but realises that it is actually a different function object from which the “z” copy was originally made.
Where the problems start occuring with mod_wsgi is if the function object being saved was itself a copy of some function object which is held outside of the module the function object was defined in. If the module holding the original function object was actually the WSGI application script file and it was reloaded because of the automatic script reloading mechanism, an attempt to pickle the object will fail. This is because the original function object which had been copied from will have been replaced by a new one when the script was reloaded.
This sort of problem, although it will not occur for an instance of a class, will occur for the class object itself:
>>> class B: pass
...
>>> b=B()
>>> pickle.dumps(b)
'(i__main__\nB\np0\n(dp1\nb.'
>>> del B
>>> pickle.dumps(b)
'(i__main__\nB\np0\n(dp1\nb.'
>>> class B: pass
...
>>> pickle.dumps(B)
'c__main__\nB\np0\n.'
>>> C = B
>>> pickle.dumps(C)
'c__main__\nB\np0\n.'
>>> del B
>>> pickle.dumps(C)
... <deleted>
pickle.PicklingError: Can't pickle <class __main__.B at 0x53ab0>: it's not found as __main__.B
Traceback (most recent call last):
Note though that for the case of a class instance, an appropriate class object must exist at the same location when the serialised object is being restored:
>>> class B: pass
...
>>> b = B()
>>> pickle.loads(pickle.dumps(b))
<__main__.B instance at 0x41e40>
>>> del B
>>> pickle.loads(pickle.dumps(b))
... <delete>
AttributeError: 'module' object has no attribute 'B'
Traceback (most recent call last):
Unpacking And Module Names¶
The second problem derives from how the mod_wsgi script loading mechanism
does not make use of the standard Python module importing mechanism. This
is necessary as the standard Python module importing mechanism requires
every loaded module to have a unique name, with each module residing in
sys.modules
under that name. Further, that name must be able to be
used to import the module.
The mod_wsgi script loading mechanism does not place modules in
sys.modules
under their original name so as to allow multiple modules
with the same name in different directories and also to avoid having to use
the “.py” extension for script files.
The consequence though of modules not residing in sys.modules
under
their original name is that function objects and class objects within such
a module may not be able to converted back into objects from their
serialised form. This is because “pickle” when attempting to import a
module automatically if the module isn’t already loaded will not be
able to load the WSGI application script file.
The problem can be seen in the following output from an interactive Python session:
>>> exec "class C: pass" in m.__dict__
>>> c = m.C()
>>> pickle.dumps(c)
'(im\nC\np0\n(dp1\nb.'
>>> pickle.loads(pickle.dumps(c))
<m.C instance at 0x9a0d0>
>>> del sys.modules["m"]
>>> pickle.loads(pickle.dumps(c))
... <deleted>
ImportError: No module named m
Traceback (most recent call last):
Summary Of Limitations¶
Although the first problem described above could be avoided by disabling
script reloading, there is no way to work around the second problem
resulting from how mod_wsgi names modules when stored in sys.modules
.
In practice, what this means is that neither function objects, class objects or instances of classes which are defined in a WSGI application script file should be stored using the “pickle” module.
In order to ensure that no strange problems at all are likely to occur, it is suggested that only basic builtin Python types, ie., scalars, tuples, lists and dictionaries, be stored using the “pickle” module from a WSGI application script file. That is, avoid any type of object which has user defined code associated with it.
Note that this limitation only applies to the WSGI application script file, it doesn’t apply to normal Python modules imported using the Python “import” statement.


NUnit isolates test assemblies from its own code and from one another by use of separate Processes and AppDomains.
By default, NUnit loads each test assembly into a separate Process under the control of the program. This allows NUnit to ensure that each assembly is loaded in the environment for which it was built. Within the agent process, NUnit's own code runs in the primary AppDomain while the tests run in a separate AppDomain.
If desired, multiple test assemblies may be loaded into the same process and even the same domain by use of the -process and -domain command-line options. See for more information.


But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure.
I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally.
Recent Comments
Adam Roger
I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself.
Marry Lumb
I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself.


Home
About Us
Contact
My Profile
Demographics
Daily Log
Appointments
Medical History
Providers
Prescriptions
Reports
Insurance
Logout
Daily Log
Date:
Time:
Blood Pressure:
Blood Sugar:
Heart Rate:
Submit
I have a bike
I have a bike
Systolic (mmHg)
Diastolic (mmHg)
Result
Submit
Blood Pressure
Blood Sugar
Heart Rate


Implementing a custom source connector for Table API and SQL - Part Two
September 7, 2021 - Ingo Buerk Daisy TsangIn part one of this tutorial, you learned how to build a custom source connector for Flink. In part two, you will learn how to integrate the connector with a test email inbox through the IMAP protocol and filter out emails using Flink SQL.
Goals #
Part two of the tutorial will teach you how to:
- integrate a source connector which connects to a mailbox using the IMAP protocol
- use Jakarta Mail, a Java library that can send and receive email via the IMAP protocol
- write Flink SQL and execute the queries in the Ververica Platform for a nicer visualization
You are encouraged to follow along with the code in this repository. It provides a boilerplate project that also comes with a bundled docker-compose setup that lets you easily run the connector. You can then try it out with Flink’s SQL client.
Prerequisites #
This tutorial assumes that you have:
- followed the steps outlined in part one of this tutorial
- some familiarity with Java and objected-oriented programming
Understand how to fetch emails via the IMAP protocol #
Now that you have a working source connector that can run on Flink, it is time to connect to an email server via IMAP (an Internet protocol that allows email clients to retrieve messages from a mail server) so that Flink can process emails instead of test static data.
You will use Jakarta Mail, a Java library that can be used to send and receive email via IMAP. For simplicity, authentication will use a plain username and password.
This tutorial will focus more on how to implement a connector for Flink. If you want to learn more about the details of how IMAP or Jakarta Mail work, you are encouraged to explore a more extensive implementation at this repository. It offers a wide range of information to be read from emails, as well as options to ingest existing emails alongside new ones, connecting with SSL, and more. It also supports different formats for reading email content and implements some connector abilities such as reading metadata.
In order to fetch emails, you will need to connect to the email server, register a listener for new emails and collect them whenever they arrive, and enter a loop to keep the connector running.
Add configuration options - server information and credentials #
In order to connect to your IMAP server, you will need at least the following:
- hostname (of the mail server)
- port number
- username
- password
You will start by creating a class to encapsulate the configuration options. You will make use of Lombok to help with some boilerplate code. By adding the @Data
and @SuperBuilder
annotations, Lombok will generate these for all the fields of the immutable class.
import lombok.Data;
import lombok.experimental.SuperBuilder;
import javax.annotation.Nullable;
import java.io.Serializable;
@Data
@SuperBuilder(toBuilder = true)
public class ImapSourceOptions implements Serializable {
private static final long serialVersionUID = 1L;
private final String host;
private final @Nullable Integer port;
private final @Nullable String user;
private final @Nullable String password;
}
Now you can add an instance of this class to the ImapSource
and ImapTableSource
classes previously created (in part one) so it can be used there. Take note of the column names with which the table has been created. This will help later. You will also switch the source to be unbounded now as we will change the implementation in a bit to continuously listen for new emails.
Hint
The column names would be "subject" and "content" with the SQL executed in part one:
CREATE TABLE T (subject STRING, content STRING) WITH ('connector' = 'imap');
import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
import org.apache.flink.table.data.RowData;
import java.util.List;
import java.util.stream.Collectors;
public class ImapSource extends RichSourceFunction<RowData> {
private final ImapSourceOptions options;
private final List<String> columnNames;
public ImapSource(
ImapSourceOptions options,
List<String> columnNames
) {
this.options = options;
this.columnNames = columnNames.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
}
// ...
}
import org.apache.flink.table.connector.source.DynamicTableSource;
import org.apache.flink.table.connector.source.ScanTableSource;
import java.util.List;
public class ImapTableSource implements ScanTableSource {
private final ImapSourceOptions options;
private final List<String> columnNames;
public ImapTableSource(
ImapSourceOptions options,
List<String> columnNames
) {
this.options = options;
this.columnNames = columnNames;
}
// …
@Override
public ScanRuntimeProvider getScanRuntimeProvider(ScanContext ctx) {
final boolean bounded = false;
final ImapSource source = new ImapSource(options, columnNames);
return SourceFunctionProvider.of(source, bounded);
}
@Override
public DynamicTableSource copy() {
return new ImapTableSource(options, columnNames);
}
// …
}
Finally, in the ImapTableSourceFactory
class, you need to create a ConfigOption<>
for the hostname, port number, username, and password. Then you need to report them to Flink. Host, user, and password are mandatory and can be added to requiredOptions()
; the port is optional and can be added to optionalOptions()
instead.
import org.apache.flink.configuration.ConfigOption;
import org.apache.flink.configuration.ConfigOptions;
import org.apache.flink.table.factories.DynamicTableSourceFactory;
import java.util.HashSet;
import java.util.Set;
public class ImapTableSourceFactory implements DynamicTableSourceFactory {
public static final ConfigOption<String> HOST = ConfigOptions.key("host").stringType().noDefaultValue();
public static final ConfigOption<Integer> PORT = ConfigOptions.key("port").intType().noDefaultValue();
public static final ConfigOption<String> USER = ConfigOptions.key("user").stringType().noDefaultValue();
public static final ConfigOption<String> PASSWORD = ConfigOptions.key("password").stringType().noDefaultValue();
// …
@Override
public Set<ConfigOption<?>> requiredOptions() {
final Set<ConfigOption<?>> options = new HashSet<>();
options.add(HOST);
options.add(USER);
options.add(PASSWORD);
return options;
}
@Override
public Set<ConfigOption<?>> optionalOptions() {
final Set<ConfigOption<?>> options = new HashSet<>();
options.add(PORT);
return options;
}
// …
}
Now take a look at the createDynamicTableSource()
function in the ImapTableSourceFactory
class. Recall that previously (in part one) you used a small helper utility TableFactoryHelper, that Flink offers which ensures that required options are set and that no unknown options are provided. You can now use it to automatically make sure that the required options of hostname, port number, username, and password are all provided when creating a table using this connector. The helper function will throw an error message if one required option is missing. You can also use it to access the provided options (getOptions()
), convert them into an instance of the ImapTableSource
class created earlier, and provide the instance to the table source:
import java.util.List;
import java.util.stream.Collectors;
import org.apache.flink.table.factories.DynamicTableSourceFactory;
import org.apache.flink.table.factories.FactoryUtil;
import org.apache.flink.table.catalog.Column;
public class ImapTableSourceFactory implements DynamicTableSourceFactory {
// ...
@Override
public DynamicTableSource createDynamicTableSource(Context ctx) {
final FactoryUtil.TableFactoryHelper factoryHelper = FactoryUtil.createTableFactoryHelper(this, ctx);
factoryHelper.validate();
final ImapSourceOptions options = ImapSourceOptions.builder()
.host(factoryHelper.getOptions().get(HOST))
.port(factoryHelper.getOptions().get(PORT))
.user(factoryHelper.getOptions().get(USER))
.password(factoryHelper.getOptions().get(PASSWORD))
.build();
final List<String> columnNames = ctx.getCatalogTable().getResolvedSchema().getColumns().stream()
.filter(Column::isPhysical)
.map(Column::getName)
.collect(Collectors.toList());
return new ImapTableSource(options, columnNames);
}
}
Hint
Ideally, you would use connector metadata instead of column names. You can refer again to the accompanying repository which does implement this using metadata fields.
To test these new configuration options, run:
$ cd testing/
$ ./build_and_run.sh
Once you see the Flink SQL client start up, execute the following statements to create a table with your connector:
CREATE TABLE T (subject STRING, content STRING) WITH ('connector' = 'imap');
SELECT * FROM T;
This time it will fail because the required options are not provided:
[ERROR] Could not execute SQL statement. Reason:
org.apache.flink.table.api.ValidationException: One or more required options are missing.
Missing required options are:
host
password
user
Connect to the source email server #
Now that you have configured the required options to connect to the email server, it is time to actually connect to the server.
Going back to the ImapSource
class, you first need to convert the options given to the table source into a Properties object, which is what you can pass to the Jakarta library. You can also set various other properties here as well (i.e. enabling SSL).
The specific properties that the Jakarta library understands are documented here.
import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
import org.apache.flink.table.data.RowData;
import java.util.Properties;
public class ImapSource extends RichSourceFunction<RowData> {
// …
private Properties getSessionProperties() {
Properties props = new Properties();
props.put("mail.store.protocol", "imap");
props.put("mail.imap.auth", true);
props.put("mail.imap.host", options.getHost());
if (options.getPort() != null) {
props.put("mail.imap.port", options.getPort());
}
return props;
}
}
Now create a method (connect()
) which sets up the connection:
import jakarta.mail.*;
import com.sun.mail.imap.IMAPFolder;
import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
import org.apache.flink.table.data.RowData;
public class ImapSource extends RichSourceFunction<RowData> {
// …
private transient Store store;
private transient IMAPFolder folder;
private void connect() throws Exception {
final Session session = Session.getInstance(getSessionProperties(), null);
store = session.getStore();
store.connect(options.getUser(), options.getPassword());
final Folder genericFolder = store.getFolder("INBOX");
folder = (IMAPFolder) genericFolder;
if (!folder.isOpen()) {
folder.open(Folder.READ_ONLY);
}
}
}
You can now use this method to connect to the mail server when the source is created. Create a loop to keep the source running while collecting email counts. Lastly, implement methods to cancel and close the connection:
import jakarta.mail.*;
import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
import org.apache.flink.streaming.api.functions.source.SourceFunction;
import org.apache.flink.table.data.RowData;
public class ImapSource extends RichSourceFunction<RowData> {
private transient volatile boolean running = false;
// …
@Override
public void run(SourceFunction.SourceContext<RowData> ctx) throws Exception {
connect();
running = true;
// TODO: Listen for new messages
while (running) {
// Trigger some IMAP request to force the server to send a notification
folder.getMessageCount();
Thread.sleep(250);
}
}
@Override
public void cancel() {
running = false;
}
@Override
public void close() throws Exception {
if (folder != null) {
folder.close();
}
if (store != null) {
store.close();
}
}
}
There is a request trigger to the server in every loop iteration. This is crucial as it ensures that the server will keep sending notifications. A more sophisticated approach would be to make use of the IDLE protocol.
Note
Since the source is not checkpointable, no state fault tolerance will be possible.
Collect incoming emails #
Now you need to listen for new emails arriving in the inbox folder and collect them. To begin, hardcode the schema and only return the email’s subject. Fortunately, Jakarta provides a simple hook (addMessageCountListener()
) to get notified when new messages arrive on the server. You can use this in place of the “TODO” comment above:
import jakarta.mail.*;
import jakarta.mail.event.MessageCountAdapter;
import jakarta.mail.event.MessageCountEvent;
import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
import org.apache.flink.table.data.GenericRowData;
import org.apache.flink.table.data.StringData;
import org.apache.flink.table.data.RowData;
public class ImapSource extends RichSourceFunction<RowData> {
@Override
public void run(SourceFunction.SourceContext<RowData> ctx) throws Exception {
// …
folder.addMessageCountListener(new MessageCountAdapter() {
@Override
public void messagesAdded(MessageCountEvent e) {
collectMessages(ctx, e.getMessages());
}
});
// …
}
private void collectMessages(SourceFunction.SourceContext<RowData> ctx, Message[] messages) {
for (Message message : messages) {
try {
ctx.collect(GenericRowData.of(StringData.fromString(message.getSubject())));
} catch (MessagingException ignored) {}
}
}
}
Now build the project again and start up the SQL client:
$ cd testing/
$ ./build_and_run.sh
This time, you will connect to a GreenMail server which is started as part of the setup:
CREATE TABLE T (
subject STRING
) WITH (
'connector' = 'imap',
'host' = 'greenmail',
'port' = '3143',
'user' = 'alice',
'password' = 'alice'
);
SELECT * FROM T;
The query above should now run continuously but no rows will be produced since it is a test server. You need to first send an email to the server. If you have mailx installed, you can do so by executing in your terminal:
$ echo "This is the email body" | mailx -Sv15-compat \
-s"Email Subject" \
-Smta="smtp://alice:alice@localhost:3025" \
<EMAIL_ADDRESS>The row “Email Subject” should now have appeared as a row in your output. Your source connector is working!
However, since you are still hard-coding the schema produced by the source, defining the table with a different schema will produce errors. You want to be able to define which fields of an email interest you and then produce the data accordingly. To do this, you will use the list of column names from earlier and then look at it when you collect the emails.
import org.apache.flink.table.data.GenericRowData;
import org.apache.flink.table.data.RowData;
import org.apache.flink.table.data.TimestampData;
public class ImapSource extends RichSourceFunction<RowData> {
private void collectMessages(SourceFunction.SourceContext<RowData> ctx, Message[] messages) {
for (Message message : messages) {
try {
collectMessage(ctx, message);
} catch (MessagingException ignored) {}
}
}
private void collectMessage(SourceFunction.SourceContext<RowData> ctx, Message message)
throws MessagingException {
final GenericRowData row = new GenericRowData(columnNames.size());
for (int i = 0; i < columnNames.size(); i++) {
switch (columnNames.get(i)) {
case "SUBJECT":
row.setField(i, StringData.fromString(message.getSubject()));
break;
case "SENT":
row.setField(i, TimestampData.fromInstant(message.getSentDate().toInstant()));
break;
case "RECEIVED":
row.setField(i, TimestampData.fromInstant(message.getReceivedDate().toInstant()));
break;
// ...
}
}
ctx.collect(row);
}
}
You should now have a working source where you can select any of the columns that are supported. Try it out again in the SQL client, but this time specifying all the columns (“subject”, “sent”, “received”) supported above:
CREATE TABLE T (
subject STRING,
sent TIMESTAMP(3),
received TIMESTAMP(3)
) WITH (
'connector' = 'imap',
'host' = 'greenmail',
'port' = '3143',
'user' = 'alice',
'password' = 'alice'
);
SELECT * FROM T;
Use the mailx
command from earlier to send emails to the GreenMail server and you should see them appear. You can also try selecting only some of the columns, or write more complex queries.
Test the connector with a real mail server on the Ververica Platform #
If you want to test the connector with a real mail server, you can import it into Ververica Platform Community Edition. To begin, make sure that you have the Ververica Platform up and running.
Since the example connector in this blog post is still a bit limited, you will use the finished connector in this repository instead. You can clone that repository and build it the same way to obtain the JAR file.
For this example, let’s connect to a Gmail account. This requires SSL and comes with an additional caveat that you need to enable two-factor authentication and create an application password to use instead of your real password.
First, head to SQL → Connectors. There you can create a new connector by uploading your JAR file. The platform will detect the connector options automatically. Afterwards, go back to the SQL Editor and you should now be able to use the connector.
Ververica Platform - SQL Editor
Summary #
Apache Flink is designed for easy extensibility and allows users to access many different external systems as data sources or sinks through a versatile set of connectors. It can read and write data from databases, local and distributed file systems.
Flink also exposes APIs on top of which custom connectors can be built. In this two-part blog series, you explored some of these APIs and concepts and learned how to implement your own custom source connector that can read in data from an email inbox. You then used Flink to process incoming emails through the IMAP protocol and wrote some Flink SQL.


Form Elements
Input Types
Most common form control, text-based input fields. Includes support for all HTML5 types: text
, password
, datetime
, datetime-local
, date
, month
, time
, week
, number
, email
, url
, search
, tel
, and color
.
Input Types
Most common form control, text-based input fields. Includes support for all HTML5 types: text
, password
, datetime
, datetime-local
, date
, month
, time
, week
, number
, email
, url
, search
, tel
, and color
.


{{template "header" . }} Welcome Back! Login to your dashboard with your registered email address and password. Username Password Trust this computer for 30 days. Forgot Password? Login Don’t have an account? Sign Up here If you are not able to sign in, please contact us. {{template "footer" . }}
Login to your dashboard with your registered email address and password.
Don’t have an account? Sign Up here


With Urbi 1 Gostai introduced a revolutionary means to program robots: a domain specific scripting language that brings together the efficiency of C++, and the flexibility of a dynamic language. Urbi 1 was designed pragmatically, based on user requests and feedback. That's how Urbi 1 was made useful, and how it met its users expectations. Yet, because of this iterative design process, it suffers a number of limitations.
To address these issues, Gostai launched the Urbi 2 project months ago. We are happy to announce that Urbi 2 is up and running. It will be made available for technical preview in the near future. In the meanwhile, let us show you some of the changes we made in Urbi. For a start, we will focus on the changes of the Object-Orientation support in Urbi, later articles will cover other facets of the Urbi 2 system.
What follows is implemented, runs, and can be done at home in total safety.
Full Object Orientation Support
- Everything is an object.
In the 1.x series there were several kinds of entities: numbers, lists, strings, images, etc. and objects. In the 2.x series, everything is an object, including the atomic values. For instance "foo" evaluates into an object that derives from String.
- Objects are dictionaries of slots.
Objects are implemented as associative arrays: a mapping from symbols to objects.
- The distinction between value and function is blurred.
From a software engineering point of view, the client (i.e., the "caller") should not know how the provider (i.e., the "callee") is implemented. In particular, it is an implementation detail whether object.feature is an attribute, or a function taking no argument. Therefore, parentheses are not needed to invoke functions that do not have argument (other that self)[source language='c++']
# 0-ary functions and attributes behave equally.
var feature = 42;
[11648000] 42
feature;
[11680000] 42
feature();
[11712000] 42
feature(42);
[11776000:error] !!! 8.1-11: expected 0 arguments, given 1
feature = function () { 42 };
[11872000] function () {
42
}
feature;
[12000000] 42
feature();
[12128000] 42
feature(42);
[12192000:error] !!! 10.1-11: expected 0 arguments, given 1
feature = function (x) { x };
[12256000] function (x) {
x
}
feature;
[12288000:error] !!! 26.1-7: expected 1 arguments, given 0
feature();
[12288000:error] !!!28.1-9: expected 1 arguments, given 0
feature(42);
[12384000] 42
[/source]
- Functions are first-class citizens.
In other words, functions are objects and can be manipulated like any other type of object. For instance you may copy a function from an object to another. Be careful though that by default code is evaluated, see the following example.[source language='c++']
var counter_ = 0;
[09856000] 0
var counter = function () { counter_ += 1; };
[09952000] function () {
counter_ . '+='(1);
}
counter;
[10080000] 1
counter;
[10208000] 2
var counter2 = counter;
[10368000] 3
counter2;
[10400000] 3
counter2;
[10432000] 3
var counter3 = getSlot("counter");
[10528000] function () {
counter_ . '+='(1);
}
counter3;
[10656000] 4
counter3;
[10784000] 5
counter;
[10912000] 6
[/source]
- Arbitrary identifiers.
Identifiers can be composed of any sequence of characters enclosed between ', but some sequences behave magically.
- Regular identifiers.
Traditional identifiers (MyObject, my_function_2, SomeVariableName etc.) need no quotes.
- Traditional connectives.
Connectives such as +, *, <= and so forth, when used unquoted behave as usual (e.g., 1 < 2), but between quotes, they behave like regular function names (e.g., 1.'<'(2)).
- Fewer primitives, more expressive power.
The basic connectives, such as +, *, <= and so forth, are regular functions that the user can freely define. For instance Person.'<' = function (rhs) { name < rhs.name } define the < between Person.
- Objects can be arbitrarily nested.
The previous limitations of the language are alleviated, and the . connective can now be freely used. For instance:[source language='c++']
robot.leg("rear-left").joint("knee").value
[/source]
- Name spaces.
There is no global name space in the Urbi language: there are no global variables or functions in the traditional sense. Rather,
the Urbi world is a network of objects that use each other (either via inheritance, or via aggregation). To reach a particular object, for instance Object from which all the objects derive, one uses a series of local names starting from the current object.For instance true is defined as a member of Object.Constants, which is a prototype of Object (i.e., Object "derives" from Object.Constants). Since every object derives from Object, the true is available from anywhere.
- Lobbies.
Sessions with the Urbi server, via files or via network connections, are handled via "lobbies". Lobbies implement the local scope: variables introduced during the interaction are only visible from this lobby. Nevertheless, because lobbies are connected to the rest of the Urbi network of objects, the user can introduce new features in the common space, for instance by extending Object. The user may also provide access to
his/her own lobby by giving it a name in an object that is reachable from the other lobbies.
- An object can have any number of prototypes.
Multiple inheritance is fully supported. This allows to factor common code. For instance the object Orderable provides implementations of ordered comparators in terms of each other (e.g., function '>=' (rhs) { rhs < self }), and Comparable relates == and !=. If your
object provides == and <, then running object.addProto(Comparable);object.addProto(Orderable); provides the others.
There is much more to come, expect new posts in the near future and
stay tuned!


JACOB'S LADDER (1990)
A film review by Steve Kong Edited by Steve Kong Copyright 1999 Steve Kong
Jacob's Ladder is a film that will take you down that dark tunnel with the light at the end. But, the trip down the dark tunnel is not pleasant. Jacob's Ladder takes us through the turmoil of the tunnel through the eyes of its main character Jacob (Tim Robbins) Singer.
As the film opens, Jacob is in a quiet village in Vietnam. It's the middle of the Vietnam War, but Jacob's group seems to have found some quiet time. A joint is passed around, there's idle chatter, and there's nothing serious on the horizon. That is until there is movement in the tree line.  No one knows what's happening, not even the audience. This mass confusion is a foreshadowing for the rest of the film. As the combat comes to an end, an unseen enemy bayonets Jacob in the abdomen.
Flash forward a few years past the war, Jacob is on a subway train riding home. He's now a postman with a doctorate degree in philosophy. He's divorced from his wife and is living with a beautiful co-worker, Jezebel (Elizabeth Pena). Everything seems fine for Jacob, but it's not. He starts to see images of demons. Little glimpses at first things that wouldn't make much sense but wouldn't arouse your attention either but as the days pass, the demonic images continue to haunt him, they get darker and more intense.
Jacob's only handle on what is happening to him is through his chiropractor Louis (Danny Aiello).
The structure of Jacob's Ladder is brilliant, though not original. This structure, which I can't name because it will ruin the film experience for those who haven't seen it yet, has been used in books before and can be misused. But, writer Bruce Joel Rubin puts together a script that takes your emotions and drains them, leaving even the happiest person depressed. There is a hope-filled ending, but the truest form of this film is of death. Throughout the film we, like Jacob, are unsure of what really happened during the attack in Vietnam. Jacob, halfway through the film, asks, `Am I dead?' And we're left to think if he is or not.
The film explores not life, but death. What really happens during those last fleeting moments of life? What really are demons and angels? Rubin who wrote the crowd-pleaser film Ghost takes a big risk with writing Jacob's Ladder. This is a film that is, in every way, un-Hollywood. Jacob's Ladder is as original as movies come. Kudos to Rubin for writing this amazing film.
Adrian Lyne who is known more for his commercial films such as Flashdance tackles this film with the utmost honesty. Showing Jacob's struggles with what is happening around and to him unfiltered. Lyne tones down the supernatural portions of Rubin's script and brings a real-worldness to the film, making the film that much more horrific. The images that Lyne presents on screen are of Hell on Earth. Lyne doesn't rely on gore or slashers to scare you, but lets the story and the images put the fear into you. This film can be seen as either a trip straight to Hell or a journey to Heaven. It just depends on how you look it.
Tim Robbins is perfectly cast as Jacob. Robbins has innocence in his face that is used well to show the reaction to the chaos that has suddenly filled his life. As Jacob's life is spiraling down to Hell, Robins is able to bring us with him on this dark journey. And by the end of the film we are with Jacob as the ultimate happens. Robbins's portrayal of Jacob is dead on. Kudos to Robbins for a brilliant performance. Elizabeth Pena also turns in a wonderful performance as Jezebel the mysterious woman in Jacob's life. The mere name that is given to her character makes for some interesting Biblical imagery.
I saw this film nine years ago while I was still in high school. The film, at the time, influenced me much on how I look at life and how I look at films. And although I enjoy the current crop of films that are being turned out, there hasn't been any film as daring as Jacob's Ladder to do what it does -- Jacob's Ladder gets into your head, it twists things around and leaves you reeling. Instead of using special effects Jacob's Ladder uses ideas, images, and quick glimpses to horrify you. Once in your head, Jacob's Ladder is there for good.
 The film is not a happy experience, but it is one that shows just what gets created when filmmakers are willing to take risks. The script by Bruce Joel Rubin and the steady handed direction from Adrian Lyne coupled with the imagery shot by Jeffrey Kimball all work to frighten you psychologically. These elements also work to make you think, and by the end of the film I'll guarantee you that you'll be thinking and mulling over the film for a long time to come. Don't Miss Jacob's Ladder. I screened the special edition of Jacob's Ladder available on DVD. After watching the film, let me know what you think about what happened to Jacob.
--- Steve Kong<EMAIL_ADDRESS>a guy with a helluva attitude who loves the cinema. i'm your hard boiled movie guide.
http://boiledmovies.sbay.com/
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


Testing your OpenAPI Contract with Spectator
Matt Trask • February 13, 2021
Read Time: 7 mins
laravel programmingNear the end of last year, a package was released from Adam Campbell that integrated with the Laravel test runner and allowing for a developer to take the OpenAPI spec file (or contract) and run tests against it. Let's first take a look at the API I built.
National Parks API
One thing I have found a love for is the American National Parks system. Various areas in the country preserved for their beauty, the landscapes range from lakes to valleys; mountains and forests; volcanos and deserts. It is my goal to visit every single national park in the United States. When I thought about writing this blog post, I figured building a quick API for the National Parks would be fun, and it was. While it's not deployed yet, the code is viewable here. Right now there are two operations supported: GET /api/national-parks
and GET /api/national-parks/{uuid}
. As of now, it is just the designated National Parks, but considering the United States has national forests, national military parks, historic places and more, the API will more than likely expand to support those as well as POST, PUT, and DELETE
operations.
A sample response (limited to 5 objects for brevity):
"data": [
{
"parkUuid": "0b6124e0-53ae-46f2-8a12-d5d6bafd51d0",
"name": "Acadia",
"yearEstablished": 1916,
"state": "Maine",
"lastUpdated": "2021-02-13T17:20:25.000000Z"
},
{
"parkUuid": "b4670075-c753-4abb-9e01-655bd62deacd",
"name": "American Somoa",
"yearEstablished": 1988,
"state": "American Somoa",
"lastUpdated": "2021-02-13T17:20:25.000000Z"
},
{
"parkUuid": "428cc8cd-b118-4ff9-9ba2-31892d9be9f5",
"name": "Arches",
"yearEstablished": 1929,
"state": "Utah",
"lastUpdated": "2021-02-13T17:20:25.000000Z"
},
{
"parkUuid": "7aa48240-06f8-4d8a-a596-aa087afae234",
"name": "Badlands",
"yearEstablished": 1939,
"state": "South Dakota",
"lastUpdated": "2021-02-13T17:20:25.000000Z"
},
{
"parkUuid": "5a14dcb1-6bb7-4ef1-99be-0a75092200b7",
"name": "Big Bend",
"yearEstablished": 1944,
"state": "Texas",
"lastUpdated": "2021-02-13T17:20:25.000000Z"
}
],
"links": {
"first": "http:\/\/localhost\/api\/national-parks?page=1",
"last": "http:\/\/localhost\/api\/national-parks?page=13",
"prev": null,
"next": "http:\/\/localhost\/api\/national-parks?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 13,
"links": [
{
"url": null,
"label": "« Previous",
"active": false
},
{
"url": "http:\/\/localhost\/api\/national-parks?page=1",
"label": 1,
"active": true
},
{
"url": "http:\/\/localhost\/api\/national-parks?page=2",
"label": 2,
"active": false
},
{
"url": "http:\/\/localhost\/api\/national-parks?page=3",
"label": 3,
"active": false
},
{
"url": "http:\/\/localhost\/api\/national-parks?page=4",
"label": 4,
"active": false
},
{
"url": "http:\/\/localhost\/api\/national-parks?page=5",
"label": 5,
"active": false
},
{
"url": "http:\/\/localhost\/api\/national-parks?page=6",
"label": 6,
"active": false
},
{
"url": "http:\/\/localhost\/api\/national-parks?page=7",
"label": 7,
"active": false
},
{
"url": "http:\/\/localhost\/api\/national-parks?page=8",
"label": 8,
"active": false
},
{
"url": "http:\/\/localhost\/api\/national-parks?page=9",
"label": 9,
"active": false
},
{
"url": "http:\/\/localhost\/api\/national-parks?page=10",
"label": 10,
"active": false
},
{
"url": "http:\/\/localhost\/api\/national-parks?page=11",
"label": 11,
"active": false
},
{
"url": "http:\/\/localhost\/api\/national-parks?page=12",
"label": 12,
"active": false
},
{
"url": "http:\/\/localhost\/api\/national-parks?page=13",
"label": 13,
"active": false
},
{
"url": "http:\/\/localhost\/api\/national-parks?page=2",
"label": "Next »",
"active": false
}
],
"path": "http:\/\/localhost\/api\/national-parks",
"per_page": "5",
"to": 5,
"total": 63
}
}
Along with this, I have created an OpenAPI Contract as well. While I won't dive deep into OpenAPI this time, the big takeaway to know is that the OpenAPI document is a contract created that you the API developer agree to support. Documenting your responses and abiding by the contract you've laid out is a fantastic way to develop trust with your API consumers.
A sample of the contract:
In the contract I am promising a few things:
- The response data object will always follow the example in the image with an array of objects under a
data
key, HATEOAS links under alinks
object, and meta data about pagination under ameta
object. - supported query params for the following: state, year, and count. This allows the API to be filtered by state, parks established by a certain year, and or by a specified amount.
Using Spectator
Up until now, most developers using Laravel are hopefully familiar with testing their APIs. Laravel provides a rich API to test HTTP actions and Spectator ties in very nicely with those. The best part is that Spectator also allows us to clean up our tests by removing some asserts. In order to use Spectator, you need to first run
composer require --dev hotmeteor/spectator && php artisan vendor:publish --provider="Spectator\SpectatorServiceProvider"
which will publish the config. Looking in your config file for Spectator, you have a few options:
return [
/*
|--------------------------------------------------------------------------
| Default Spec Source
|--------------------------------------------------------------------------
|
| Here you may specify the default spec source that should be used
| by the framework.
|
*/
'default' => env('SPEC_SOURCE', 'local'),
/*
|--------------------------------------------------------------------------
| Sources
|--------------------------------------------------------------------------
|
| Here you may configure as many sources as you wish, and you
| may even configure multiple source of the same type. Defaults have
| been setup for each driver as an example of the required options.
|
*/
'sources' => [
'local' => [
'source' => 'local',
'base_path' => env('SPEC_PATH'),
],
'remote' => [
'source' => 'remote',
'base_path' => env('SPEC_PATH'),
'params' => env('SPUR_URL_PARAMS', ''),
],
'github' => [
'source' => 'github',
'base_path' => env('SPEC_PATH'),
'repo' => env('SPEC_GITHUB_REPO'),
'token' => env('SPEC_GITHUB_TOKEN'),
],
],
/*
|--------------------------------------------------------------------------
| Paths
|--------------------------------------------------------------------------
|
| Configure path defaults, like prefixes.
|
*/
'path_prefix' => '',
];
Nothing out of the ordinary, and for this example I am using the local
option. At work, we use the remote
option with our Github Actions which works really well too.
After all of this has been configured, and it takes minutes or so, we can start developing and testing.
First, lets take a look at a test before we use Spectator.
public function testCanGetParksWithoutSpectator(): void
{
$res = $this->json(
'GET',
'/api/national-parks'
);
$res->assertOk()
->assertJson([
'data' => true,
'meta' => true,
'links' => true,
])
->assertHeader('ETag')
->assertJsonCount(15, 'data')
->assertJsonCount(4, 'links')
->assertJsonCount(8, 'meta');
}
In the example above, we are asserting many things, all of which we promise in our contract. What does this test look like with Spectator though?
use Spectator\Spectator;
public function testCanGetParks(): void
{
Spectator::using('openapi.yml');
$res = $this->json(
'GET',
'/api/national-parks'
);
$res->assertValidRequest()
->assertValidResponse(200);
}
The API for Spectator is clean, and removes a lot of the assertions I was preforming before hand. Why can I do this? Because the two methods Spectator provides,
assertValidRequest()
and assertValidResponse()
handle it all for us. Under the hood, Spectator takes the spec file we have told it to use with the Spectator::using('openapi.yml');
accessor and runs a check on both the request and response. Now, for this request I dont have a body or headers I am checking for, but the response has a body I have agreed to with the contract. Had I created a POST
action, the request validation assertion would have been incredibly useful to make sure my request body matches what the contract states it should be. You aren't limited to just these two assertions either, you have the full suite of Laravel HTTP JSON assertions and more at the ready. However because I completed the contract with both models of the parks object and meta object, Spectator will use those to compare the response from the API to what I say it should be.
Spectator is another tool in the API developers tool box, and a powerful one at that. It has helped us uncover bugs in our SOA project at work, and freed up time we would normally spend testing so we can move on to working on other problems. You can find the repo here where Adam does a wonderful job managing the issues and pull requests.
If you are looking to start a new API with Laravel adding Spectator, the Primitive/OpenAPI-Initializer package to scaffold your contract, and Stoplight's Studio and Spectral for desiging and linting your contract; to your project will help you develop faster and with more confidence that your API will respond the correct way.
Cheers!


“The haddock… amongst marine animals, is supposed, throughout maritime Europe, to be a privileged fish : even in austere Scotland every child can point out the impression of St Peter's thumb, by which, from age to age, it is distinguished from fishes having, otherwise, an external resemblance. All domesticated cattle, having the benefit of man's guardianship and care, are believed, throughout England and Germany, to go down upon their knees at one particular moment on Christmas Eve, when the fields are covered in darkness, when no eye looks down but that of God, and when the exact anniversary hour revolves of the angelic song, once rolling over the fields and flocks of Palestine.”
Hargrave Jennings, Curious Things Of The Outside World, Last Fire (1861)


Dame Julie Andrews: I needed therapy after Mary Poppins success
Dame Julie Andrews has said she needed therapy following the success of Mary Poppins.
The British star scooped a best actress Academy Award for her role as the magical nanny in her first Hollywood film.
“l kept the Oscar in the attic for a very long time because I thought I’d been given it as a ‘Welcome to Hollywood’ and I didn’t feel worthy of it,” the 84-year-old told The Graham Norton Show.
“So much early success sent me into therapy and analysis.”
The Sound Of Music star said: “I learnt you have to do it right and honour the films you are making.
“It’s a huge gift, but a lot of obligation.”
The actress has previously said that therapy “saved my life, in a way” after going for personal reasons and because she did not feel she had “clarity”.
“Sadly, I separated from my lovely first husband (Tony Walton), and separations were always inevitable and the marriage was over and my head was so full of clutter and garbage,” she has said.
Dame Julie told Norton she was “very lucky” not to have had any unpleasant encounters with men during her career.
“I married (director) Blake Edwards soon after arriving in Hollywood and it protected me from ever getting into that predicament,” she said.
Norton’s BBC One chat show this week also featured Jennifer Aniston, Reese Witherspoon, Sir Ian McKellen and singer Dua Lipa.
Revealing that she kept a few souvenirs from her breakout role in Legally Blonde, Witherspoon said: “I kept the whole wardrobe including 77 pairs of Jimmy Choo shoes.
“I had it written in my contract! I didn’t touch them until the 15th anniversary and then had a lot of fun trying them on with my daughter.”
The Graham Norton Show airs on BBC One on Friday November 1 at 10.35pm.
READ MORE
Check out the stars as they dress to chill for Jonathan Ross' annual Halloween party


In this assignment, you'll analyze a collection of data sets from the San Francisco Open Data Portal and Zillow. The data sets have been stored in the SQLite database sf_data.sqlite
, which you can download here. The database contains the following tables:
| Table | Description |
|---|---|
crime |
Crime reports dating back to 2010. |
mobile_food_locations |
List of all locations where mobile food vendors sell. |
mobile_food_permits |
List of all mobile food vendor permits. More details here. |
mobile_food_schedule |
Schedules for mobile food vendors. |
noise |
Noise complaints dating back to August 2015. |
parking |
List of all parking lots. |
parks |
List of all parks. |
schools |
List of all schools. |
zillow |
Zillow rent and housing statistics dating back to 1996. More details here. |
The mobile_food_
tables are explicitly connected through the locationid
and permit
columns. The other tables are not connected, but you may be able to connect them using dates, latitude/longitude, or postal codes.
Shapefiles for US postal codes are available here. These may be useful for converting latitude/longitude to postal codes.
Shapefiles for San Francisco Neighborhoods are available here.
Exercise 1.1. Which mobile food vendor(s) sells at the most locations?
import pandas as pd
from matplotlib import pyplot as plt
import sqlalchemy as sqla
import sqlite3
%matplotlib inline
plt.style.use('ggplot')
conn0 = sqlite3.connect('sf_data.sqlite')
c = conn0.cursor()
c.execute("""select * from mobile_food_locations""")
c.fetchone()
c.execute("""select * from mobile_food_permits""")
c.fetchone()
c.description
pd.read_sql_query("""select * from mobile_food_permits where Applicant = 'Liang Bai Ping' """, conn0)
pd.read_sql_query("""select "permit","Status","Applicant","FacilityType",count(*) as "loc.number" from
(select * from mobile_food_schedule join mobile_food_permits
on mobile_food_schedule."permit" = mobile_food_permits."permit")
group by "permit"
order by "loc.number" desc
""", conn0).iloc[0:10]
pd.read_sql_query("""select "permit","Status","FacilityType","Applicant",count(*) as "loc.number" from
(select * from mobile_food_schedule join mobile_food_permits
on mobile_food_schedule."permit" = mobile_food_permits."permit"
where mobile_food_permits.Status =='APPROVED')
group by "permit"
order by "loc.number" desc
""", conn0).iloc[0:10]
May's Catering whose permit is 17MFF-0110 sells in most places after it is permitted by the authority.
Parks' Catering whose permit is 16MFF-0051 sells in most places currently.
Exercise 1.2. Ask and use the database to analyze 5 questions about San Francisco. For each question, write at least 150 words and support your answer with plots. Make a map for at least 2 of the 5 questions.
You should try to come up with some questions on your own, but these are examples of reasonable questions:
Please make sure to clearly state each of your questions in your submission.
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import scipy.stats as ss
import numpy as np
from matplotlib.patches import Circle, Wedge, Polygon
from matplotlib.colors import LinearSegmentedColormap
import geopandas as gpd
1.2.1-Which parts of the city are the most and least expensive?
I found the the most and least expensive by making a pandas table "avgHprice" that sorted the averaging ZriPerSqft_AllHomes and MedianSoldPricePerSqft_AllHomes in Table Zillow after groupby RegionName. Based on the table "avgHprice", then I made a scatter plot of the four variables in the avgHprice table, and marking "RegionName" to few points that have the max and min values in each variables. Such that, I found that the most expensive "RegionName" by Medium Sold Price is 94104.
However, other data for this region is missing. So considering other variables, the most expensive "RegionName" is 94105, and least expensive "RegionName" are 94124. To check the results, I mapped the avgerage values of four variables in each region, the map also supported results.
Relatively, 94105 have highest ZriPerSqft_AllHomes, MedianSoldPricePerSqft_AllHomes and Turnover, though the PricetoRentRatio is not the highest.
Relatively, 94124 have the lowest ZriPerSqft_AllHomes, MedianSoldPricePerSqft_AllHomes and Turnover, though the PricetoRentRatio is at an average level.
c.execute("""select * from zillow
""")
c.fetchone() #zipcode, time,
Hprice = pd.read_sql_query("select * from zillow",conn0)
Hprice.describe()
avgHprice = Hprice.groupby(['RegionName'])['RegionName','ZriPerSqft_AllHomes','MedianSoldPricePerSqft_AllHomes'
,'PriceToRentRatio_AllHomes','Turnover_AllHomes'].mean()
avgHprice.head()
avgHprice.sort_values(['ZriPerSqft_AllHomes'], ascending=0).head()
avgHprice.sort_values(['MedianSoldPricePerSqft_AllHomes'], ascending=0).head()
avgHprice.sort_values(['PriceToRentRatio_AllHomes'], ascending=0).head()
plt.scatter(avgHprice['ZriPerSqft_AllHomes'], avgHprice['PriceToRentRatio_AllHomes'],
alpha=0.5,
s=30*avgHprice['Turnover_AllHomes'],
c=avgHprice['MedianSoldPricePerSqft_AllHomes'],
label='Turnover_AllHomes')
plt.xlabel('ZriPerSqft_AllHomes')
plt.ylabel('PriceToRentRatio_AllHomes')
plt.legend(loc='upper center', bbox_to_anchor=(0.5, -0.15),
fancybox=True, shadow=True, ncol=5)
#plt.colorbar()
plt.title('Comparison of ZriPerSqft, Turnover,\n PriceToRentRatio and MedianSoldPricePerSqft \n in each Region')
cbar = plt.colorbar(ticks = [300,400,500,600,700,800,900])
cbar.ax.set_yticklabels(['Low: 300','400', '500','600', '700', '800','900'])
cbar.set_label(r'MedianSoldPricePerSqft');
for i, txt in zip(range(0,len(avgHprice['RegionName'])),avgHprice['RegionName']):
if i in list([0,19,24,18,4]):
plt.annotate(txt, (avgHprice['ZriPerSqft_AllHomes'].iloc[i],avgHprice['PriceToRentRatio_AllHomes'].iloc[i]+0.5))
avgHprice.iloc[[0,19,24,18,4]]
def draw_sf_zip(width=2e7,proj='merc'):
figsize = [10,10]; dpi=80
fig = plt.figure(1, figsize = figsize, dpi = dpi)
ax = fig.add_subplot(111)
bmap = Basemap(width=width,height=width,projection=proj,
llcrnrlon=-122.6,llcrnrlat=37.6,urcrnrlon=-122.3,urcrnrlat=37.9,
resolution='h', #f for full
lat_0 = 37.7,
lon_0=-122.4, ax = ax)
bmap.drawcoastlines()
bmap.drawmapboundary()
bmap.readshapefile('cb_2015_us_zcta510_500k','zipcode')
return ax, fig, bmap
def find(lst = bmap.zipcode_info[0:100], key="GEOID10", value=['84536','94929']):
index = []
for i, dic in enumerate(lst):
if dic[key] in value:
index.append(i)
return index
list0=avgHprice['RegionName'].tolist()
list1=[]
for i in list0:
list1.append(str(i))
Zindex = find(lst = bmap.zipcode_info[:], value =list1[:])
ax, fig, bmap = draw_sf_zip()
ax.set_title('SF divided by Zipcode')
list1[4] #list([0,19,24,18,4])
def mapHprice(value = 'ZriPerSqft_AllHomes'):
table0= avgHprice[[value,'RegionName']]
table0 = table0.dropna()
list0 = avgHprice['RegionName'].tolist()
rank = ss.rankdata(avgHprice[value].tolist())
n = len(rank)
rank = rank/float(n)
ax, fig, zmap = draw_sf_zip()
for (i, z) in zip(range(0,25),Zindex):
pp = Polygon(zmap.zipcode[z],facecolor=(1.,1.-rank[i]**2.,0.),
alpha=.3,zorder=1)
ax.add_patch(pp)
annotx =[]
annoty =[]
if i in list([0,19,24,18,4]): #add annotation to the most the least expensive region
for t in zmap.zipcode[z][:]: #calculate the center of area in one region
annotx.append(t[0])
annoty.append(t[1])
zipx = sum(annotx) / float(len(annotx))
zipy = sum(annoty) / float(len(annoty))
plt.annotate(list1[i], xy=(zipx-950,zipy),size=10,weight = 'black')
plt.title(value + ' in SF')
#plt.show()
mapHprice()
plt.show()
mapHprice('MedianSoldPricePerSqft_AllHomes')
mapHprice('Turnover_AllHomes')
plt.show()
1.2.2-Which parts of the city are the most dangerous (and at what times)?
To find the most dangerous parts in the city, I mapped a heatmap of the crime number. As the plot below show, Southern dstrict is the most dangerous place in SF. The crime number is almost 200000. Also, by using the barplot, the crime number in Southern district is much higher than other district in SF.
Crime = pd.read_sql_query("select * from crime",conn0)
Crime.head()
def draw_sf(width=2e7,proj='merc'):
figsize = [10,10]; dpi=80
fig = plt.figure(1, figsize = figsize, dpi = dpi)
ax = fig.add_subplot(111)
bmap = Basemap(width=width,height=width,projection=proj,
llcrnrlon=-122.53,llcrnrlat=37.67,urcrnrlon=-122.33,urcrnrlat=37.85,
resolution='h', #f for full
lat_0 = 37.5,
lon_0=-122.5)
bmap.drawcoastlines()
bmap.drawmapboundary(fill_color='white')
#bmap.fillcontinents(color='white',lake_color='white')
bmap.readshapefile('geo_export_772ba198-1646-427d-8190-94c324b75364','SFFindNeighborhoods')
return ax, fig, bmap
ax, fig, bmap = draw_sf()
lons = list(Crime['Lon'])
lats = list(Crime['Lat'])
x,y = bmap(lons, lats)
#bmap.plot(x, y, 'o', markersize=5 ,markeredgecolor="none", alpha=0.33)
db = 0.003 # bin padding
lon_bins = np.linspace(min(lons)-db, max(lons)+db, 10+1) # 10 bins
lat_bins = np.linspace(min(lats)-db, max(lats)+db, 13+1) # 13 bins
density, _, _ = np.histogram2d(lats, lons, [lat_bins, lon_bins])
# Turn the lon/lat of the bins into 2 dimensional arrays ready
# for conversion into projected coordinates
lon_bins_2d, lat_bins_2d = np.meshgrid(lon_bins, lat_bins)
# convert the bin mesh to map coordinates:
xs, ys = bmap(lon_bins_2d, lat_bins_2d) # will be plotted using pcolormesh
# ######################################################################
# define custom colormap, white -> nicered, #E6072A = RGB(0.9,0.03,0.16)
cdict = {'red': ( (0.0, 1.0, 1.0),
(1.0, 0.9, 1.0) ),
'green':( (0.0, 1.0, 1.0),
(1.0, 0.03, 0.0) ),
'blue': ( (0.0, 1.0, 1.0),
(1.0, 0.16, 0.0) ) }
custom_map = LinearSegmentedColormap('custom_map', cdict)
plt.register_cmap(cmap=custom_map)
# add histogram squares and a corresponding colorbar to the map:
plt.pcolormesh(xs, ys, density, cmap="custom_map")
cbar = plt.colorbar(orientation='horizontal', shrink=0.625, aspect=20, fraction=0.2,pad=0.02)
cbar.set_label('Number of Crimes',size=18)
#plt.clim([0,100])
bmap.plot(x, y, 'o', markersize=1,#zorder=6,
markerfacecolor='#424FA4',markeredgecolor="none", alpha=0.03)
# http://matplotlib.org/basemap/api/basemap_api.html#mpl_toolkits.basemap.Basemap.drawmapscale
#bmap.drawmapscale(-119-6, 37-7.2, -119-6, 37-7.2, 500, barstyle='fancy', yoffset=20000)
plt.title('Distribution of Crimes in San Francisco')
plt.annotate('Southern', xy=bmap.SFFindNeighborhoods[21][1],
color ='black',weight = 'black', size = 13, alpha =0.7)
plt.show()
Crime.groupby(['PdDistrict']).size().plot(kind = 'Bar')
As for most dangerous time in SF, I ploted the histogram of crime case time. From the histogram, it is clear that the most dangerous time in a day is around 6pm. Crime case number starts to increase from 5am and increases until 18-19pm, then drops.
times = pd.DatetimeIndex(Crime.Datetime)
grouped = Crime.groupby([times.hour, times.minute])
plt.hist(times.hour, bins = 12)
plt.title('Histogram of Crime Time in One Day')
plt.xlabel('Hours in one Day')
plt.ylabel('Frequancy')
plt.show()
1.2.3 -Are noise complaints and mobile food vendors related?
The noise complaints are not very much related with mobile food vendors.
The barplot of noise complaints type shows that only few complaints is about mobile food vendors. Also, from the heatmap marking the noise number and vendors, we can see that the density of noise complaints are not very high associated with the distribution of vendors, especially in southern part of the city. Though in the areas where there are a lot of complaints, the number of vendors is large. However, it is not the opposite, in areas where there is a lot of vendors, the density of complaints are not always high. So the association between them is not very high.
c.execute("""select * from mobile_food_locations
""")
c.fetchone()
c.description
Noise = pd.read_sql_query("select * from noise",conn0)
Noise = Noise.dropna()
Noise.head()
Noise.groupby(['Type']).size()
Noise.groupby(['Type']).size().plot(kind='Bar')
Vendors = pd.read_sql_query("select * from mobile_food_locations",conn0)
Vendors = Vendors.dropna()
Vendors.head()
ax, fig, bmap = draw_sf()
lons = list(Noise['Lon'])
lats = list(Noise['Lat'])
x,y = bmap(lons, lats) #for density
lons1 = list(Vendors['Longitude'])
lats1 = list(Vendors['Latitude'])
x1,y1 = bmap(lons1, lats1) #for points
db = 0.003 # bin padding
lon_bins = np.linspace(min(lons)-db, max(lons)+db, 10+1) # 10 bins
lat_bins = np.linspace(min(lats)-db, max(lats)+db, 13+1) # 13 bins
density, _, _ = np.histogram2d(lats, lons, [lat_bins, lon_bins])
# Turn the lon/lat of the bins into 2 dimensional arrays ready
# for conversion into projected coordinates
lon_bins_2d, lat_bins_2d = np.meshgrid(lon_bins, lat_bins)
# convert the bin mesh to map coordinates:
xs, ys = bmap(lon_bins_2d, lat_bins_2d) # will be plotted using pcolormesh
# ######################################################################
# define custom colormap, white -> nicered, #E6072A = RGB(0.9,0.03,0.16)
cdict = {'red': ( (0.0, 1.0, 1.0),
(1.0, 0.9, 1.0) ),
'green':( (0.0, 1.0, 1.0),
(1.0, 0.03, 0.0) ),
'blue': ( (0.0, 1.0, 1.0),
(1.0, 0.16, 0.0) ) }
custom_map = LinearSegmentedColormap('custom_map', cdict)
plt.register_cmap(cmap=custom_map)
# add histogram squares and a corresponding colorbar to the map:
plt.pcolormesh(xs, ys, density, cmap="custom_map")
cbar = plt.colorbar(orientation='horizontal', shrink=0.625, aspect=20, fraction=0.2,pad=0.02)
cbar.set_label('Density of Noise Complaints',size=18)
#plt.clim([0,100])
# translucent blue scatter plot of epicenters above histogram:
#x,y = bmap(lons, lats)
bmap.plot(x, y, 'o', markersize=8,zorder=6, markerfacecolor='#990000',markeredgecolor="none", alpha=0.01)
# make image bigger:
#plt.gcf().set_size_inches(15,15)
plt.scatter(x[1], y[1], label = 'Noise Complaints',alpha = 0.5, color = '#990000')
plt.scatter(x1, y1, label = 'Vendors', alpha =0.5, color = '#80FF00')
plt.legend(loc='upper center', bbox_to_anchor=(0.5, -0.15),
fancybox=True, shadow=True, ncol=5)
plt.title('Distribution of Noise Complaints and \n Mobile Food Vendor in San Francisco')
plt.show()
1.2.4-What are the best times and places to find food trucks?
To find out the best times and places to find food truck, I created tables of food truck schedule from mobile_food_schedule and mobile_food_locations. Then I selected truck information based on food trucks openning time, from 0-6am, 7-12pm, 13-18pm, and 19-24pm. I ploted the locations of food trucks by their openning time into SF map.
On the map, in places around Potrero Hill and Dogpatch, I can basically find food trucks in all time slots. The marked place on the map is the best places to find food trucks
The best time to find food truck is during 7-12pm during one day.
c.execute("""select * from mobile_food_schedule""")
c.fetchone()
c.execute("DROP TABLE Truck")
#create a table of permit, FacolotyType and locationid
c.execute("""CREATE TABLE Truck
as select * from mobile_food_schedule
join mobile_food_permits
on mobile_food_schedule.permit = mobile_food_permits.permit
where mobile_food_permits.FacilityType = 'Truck' and mobile_food_permits.Status = 'APPROVED' """)
c.fetchone()
c.execute("DROP TABLE LocTime1")
#LocTime1 is vendors open from 19 to 24
c.execute("""CREATE TABLE LocTime1
AS SELECT * FROM Truck
join mobile_food_locations
on Truck.locationid = mobile_food_locations.locationid
where (StartHour >19 and StartHour<=24) or (EndHour >19 and EndHour<=24) or (StartHour <19 and EndHour >=24)
""")
#c.execute("DROP TABLE LocTime1")
LocTime1 = pd.read_sql("SELECT * FROM LocTime1", conn0)
LocTime1 = LocTime1[(LocTime1.T !=float(0)).all()]
LocTime1.head()
c.execute("DROP TABLE LocTime2")
c.execute("DROP TABLE LocTime3")
c.execute("DROP TABLE LocTime4")
#LocTime2 is vendors open from 13 to 18
c.execute("""CREATE TABLE LocTime2
AS SELECT * FROM Truck
join mobile_food_locations
on Truck.locationid = mobile_food_locations.locationid
where (StartHour >13 and StartHour<=18) or (EndHour >13 and EndHour<=18) or (StartHour <13 and EndHour >=18)
""")
#c.execute("DROP TABLE LocTime1")
LocTime2 = pd.read_sql("SELECT * FROM LocTime2", conn0)
LocTime2 = LocTime2[(LocTime2.T !=float(0)).all()]
#LocTime3 is vendors open from 7 to 12
c.execute("""CREATE TABLE LocTime3
AS SELECT * FROM Truck
join mobile_food_locations
on Truck.locationid = mobile_food_locations.locationid
where (StartHour >7 and StartHour<=12) or (EndHour >7 and EndHour<=12) or (StartHour <7 and EndHour >=12)
""")
#c.execute("DROP TABLE LocTime1")
LocTime3 = pd.read_sql("SELECT * FROM LocTime3", conn0)
LocTime3 = LocTime3[(LocTime3.T !=float(0)).all()]
#LocTime4 is vendors open from 0 to 6
c.execute("""CREATE TABLE LocTime4
AS SELECT * FROM Truck
join mobile_food_locations
on Truck.locationid = mobile_food_locations.locationid
where (StartHour >0 and StartHour<=6) or (EndHour >0 and EndHour<=6) or (StartHour <0 and EndHour >=6)
""")
#c.execute("DROP TABLE LocTime1")
LocTime4 = pd.read_sql("SELECT * FROM LocTime4", conn0)
LocTime4 = LocTime4[(LocTime4.T !=float(0)).all()]
size = 100
a =0.5
ax, fig, bmap = draw_sf()
lons3 = list(LocTime3['Longitude'])
lats3 = list(LocTime3['Latitude'])
x3,y3 = bmap(lons3, lats3) #for points
#bmap.plot(x1, y1, 'o', markersize=10,#zorder=6, markerfacecolor='#990000',markeredgecolor="none", alpha=0.15)
plt.scatter(x3, y3, label = 'Open in 7-12pm', alpha =a, color = '#990000', s =size)
lons2 = list(LocTime2['Longitude'])
lats2 = list(LocTime2['Latitude'])
x2,y2 = bmap(lons2, lats2) #for points
plt.scatter(x2, y2, label ='Open in 13-18pm', alpha =a, color = '#00ff00', s =size)
lons4 = list(LocTime4['Longitude'])
lats4 = list(LocTime4['Latitude'])
x4,y4 = bmap(lons4, lats4) #for points
plt.scatter(x4, y4, label = 'Open in 0-6am', alpha =a, color = '#0080ff', s =size)
lons1 = list(LocTime1['Longitude'])
lats1 = list(LocTime1['Latitude'])
x1,y1 = bmap(lons1, lats1) #for points
plt.scatter(x1, y1, label = 'Open in 19-24pm', alpha =a, color = '#ffff00', s =size)
plt.annotate('Potrero Hill\n Dogpatch ', xy = (max(x4), y4[1]+700),
color ='black',weight = 'black', size = 13, alpha =0.9)
plt.plot([min(x4)+2000, max(x4)], [y4[1],y4[1]+700], c = 'black')
plt.legend()
plt.title('Distribution of Mobile Food Vendors \n in San Franciscro during one Day')
plt.show()
1.2.5-Is there a relationship between housing prices and any of the other tables?
Relating previous maps to the housing price, it is easy to find that the places where crime rate and the number of noise complaints are low, the housing prices are high. Housing price is not very much related with the the number and availability of vendors. Now let's look the relationship between housing price and other tables.
By plotting the distribution map of parks, schools and parkings on the heatmap of SF housing price, we can see that the housing prices are high in places where there are many parks and schools. The housing prices are relatively low if there are many parkings.
Parks = pd.read_sql("SELECT * FROM parks", conn0).dropna()
c.execute("select * from zillow")
c.description
Parks['Parks']= pd.Series('NA', index=Parks.index)
Parks.head()
list(Parks.columns.values)
def Hprice_factor(value = 'MedianSoldPricePerSqft_AllHomes', factor = Parks, alpha0 = 0.33, size=8):
table0= avgHprice[[value,'RegionName']]
table0 = table0.dropna()
list0 = avgHprice['RegionName'].tolist()
rank = ss.rankdata(avgHprice[value].tolist())
n = len(rank)
rank = rank/float(n)
ax, fig, zmap = draw_sf_zip()
lons = list(factor['Lon'])
lats = list(factor['Lat'])
x,y = zmap(lons, lats) #mark parks
zmap.plot(x, y, 'o', markersize=size ,markerfacecolor='#ff0000' ,
markeredgecolor="none", alpha=0.33)
plt.scatter(x[1], y[1], label = list(factor.columns.values)[-1], alpha =0.8,s =50, color = '#990000')
for (i, z) in zip(range(0,25),Zindex):
pp = Polygon(zmap.zipcode[z],facecolor=(1.,1.-rank[i]**2.,0.),
alpha=.3,zorder=1)
ax.add_patch(pp)
annotx =[]
annoty =[]
if i in list([0,19,24,18,4]): #add annotation to the most the least expensive region
for t in zmap.zipcode[z][:]: #calculate the center of area in one region
annotx.append(t[0])
annoty.append(t[1])
zipx = sum(annotx) / float(len(annotx))
zipy = sum(annoty) / float(len(annoty))
plt.annotate(list1[i], xy=(zipx-950,zipy),size=10,weight = 'black')
plt.legend()
plt.title(value + ' \n and Number of ' + list(factor.columns.values)[-1] + ' in SF')
plt.show()
#return ax, fig, zmap
Hprice_factor()
Schools = pd.read_sql("SELECT * FROM schools", conn0).dropna()
Schools['Schools']= pd.Series('NA', index=Schools.index)
Schools.head()
Hprice_factor(value = 'MedianSoldPricePerSqft_AllHomes', factor = Schools, alpha0=0.05)
Parkings = pd.read_sql("SELECT * FROM parking", conn0).dropna()
Parkings['Parkings']= pd.Series('NA', index=Parkings.index)
Parkings.head()
Hprice_factor(factor = Parkings, alpha0 = 0.005, size=5)


You can now connect to your accounts below to save all goo.gl or Bitly-powered shortlinks into your own accounts, so you can track all your shortlinks whenever you want.
🔒 Shortly will never save your password.
You can then find all your goo.gl links over Google URL Shortener.
You can then find all your bit.ly or links like on.fb.me over Bitly.com.


Title of the Book
Author
Title
Revision #
Index
Chapter 1
Section 1
Subsection 1
Section 2
Chapter 2
Chapter 3
Downloads
Book
Chapters an sections


Calculate the values for the offset resistors R1 and R2.
If your negative supply is GND, set U- to 0.


In its 36th year, the Maui Invitational basketball tournament shows no sign of slowing down | Honolulu Star-Advertiser
The Maui Jim Maui Invitational, set to tip off Monday for the 36th time, wasn’t always the prestigious, high-profile college basketball tournament it is today. It actually started on the Big Island. Read more
Mahalo for reading the Honolulu Star-Advertiser!
You're reading a premium story. Read the full story with our Print & Digital Subscription.
Already a subscriber? Log in now to continue reading this story.
Print subscriber but without online access? Activate your Digital Account now.


 Yep, from the boy (and son of Bone Spurs) who fled from his own book signing at UCLA on Sunday because he was afraid that his own fans were mad at him.
Of course it didn't take long for the Twitterverse to set things straight...
Image: by DonkeyHotey - Donald Trump Jr. - Caricature, CC BY-SA 2.0, Link


"all" | all statistics |
"adj.rsq" | adjusted R-squared |
"aic" | Akaike Information Criterion |
"bic" | Bayesian Information Criterion |
"chi2" | chi-squared |
"f" | F statistic |
"ll" | log-likelihood |
"logrank" | score (logrank) test |
"lr" | likelihood ratio (LR) test |
"max.rsq" | maximum R-squared |
"n" | number of observations |
"null.dev" | null deviance |
"Mills" | Inverse Mills Ratio |
"res.dev" | residual deviance |
"rho" | rho |
"rsq" | R-squared |
"scale" | scale |
"theta" | theta |
"ser" | standard error of the regression (i.e., residual standard error) |
"sigma2" | sigma squared |
"ubre" | Un-Biased Risk Estimator |
"wald" | Wald test |
|
|


After the countdown, show a hand gesture and hold it for a moment. The computer will then make its move (don't worry, it doesn't cheat).


$trade[price] {lang payment_unit}
{lang trade_additional}
$trade[credit] {$_G['setting']['extcredits'][$_G['setting']['creditstransextra'][5]][unit]}{$_G['setting']['extcredits'][$_G['setting']['creditstransextra'][5]][title]}
$trade[costprice] {lang payment_unit}
{lang trade_additional} $trade[costcredit] {$_G[setting][extcredits][$_G['setting']['creditstransextra'][5]][unit]}{$_G[setting][extcredits][$_G['setting']['creditstransextra'][5]][title]}


返回游戏馆
Snake
Score:
0
Game Over
press
space
to begin a
new game
settings
Settings
new game
Speed:
Slow
Normal
Fast
Wall:
On
Off
Snake
new game
settings


"x" "1" "MATSUOKA,A, MATSUI,M, MIYATA,N, SOFUNI,T, ISHIDATE,M, MUTAGENICITY OF3-TERT- BUTYL-4-HYDROXYANISOLE (BHA) AND ITS METABOLITES IN SHORT-TERM TESTS INVITRO, MUTAT. RES. 241(2):125-32, 1990"


<ditavalref>
The <ditavalref>
element references a DITAVAL document that specifies
filter conditions that can be used to process a subset of the map content. Other
DITAVAL-reference domain elements can be used to imply multiple copies of the map branch
that contains them and so apply a different set of conditions to each copy.
Category: DITAVAL reference domain


×
Transfer Balance In this number(9816621340) Through Esewa or Khalti
{% for message in messages %}
×
{{ message }}
{% endfor %}
{% trans 'Catagory' %}
{% for catagory in catagories %}
{% trans catagory.title %}
{% endfor %}
{% trans 'How to Bet' %}
Step 1: First You have to register here and you will be notify in gmail and notification panel
Step 2: Then You can Deposit the balance after login. You need to transfer the money in this number<PHONE_NUMBER>) in khalti or esewa. for mor info click Here
Step 3: For Bet you can watch video which is below down or Go to the website Forzza.com
Step 4: Then You can Withdraw the balance through esewa or khalti. For more info click Here
{% trans 'How to Bet' %}
{% trans 'How to Deposit' %}
{% trans 'How to Withdraw' %}
{% trans 'Feedback' %}
{% trans 'Any comments, issues, or suggestions will be read by one of the staff' %}.
{% for message in messages %}
{% empty %}
{% endfor %}
{% endblock %}


Given a class `TheClass`, `TheClass.any_instance` returns a `Recorder`, which records stubs and message expectations for later playback on instances of `TheClass`.
Further constraints are stored in instances of [Chain](Chain).
@see AnyInstance @see Chain
@private
@private
# File lib/rspec/mocks/any_instance/recorder.rb, line 16 def initialize(klass) @message_chains = MessageChains.new @stubs = Hash.new { |hash,key| hash[key] = [] } @observed_methods = [] @played_methods = {} @klass = klass @expectation_set = false end
# File lib/rspec/mocks/any_instance/recorder.rb, line 128 def already_observing?(method_name) @observed_methods.include?(method_name) end
# File lib/rspec/mocks/any_instance/recorder.rb, line 124 def build_alias_method_name(method_name) "__#{method_name}_without_any_instance__" end
@private
# File lib/rspec/mocks/any_instance/recorder.rb, line 120 def instance_that_received(method_name) @played_methods[method_name] end
@private
# File lib/rspec/mocks/any_instance/recorder.rb, line 112 def playback!(instance, method_name) RSpec::Mocks.space.ensure_registered(instance) message_chains.playback!(instance, method_name) @played_methods[method_name] = instance received_expected_message!(method_name) if message_chains.has_expectation?(method_name) end
# File lib/rspec/mocks/any_instance/recorder.rb, line 63 def should_not_receive(method_name, &block) should_receive(method_name, &block).never end
Initializes the recording a message expectation to be played back against any instance of this object that invokes the submitted method.
@see Methods#should_receive
# File lib/rspec/mocks/any_instance/recorder.rb, line 57 def should_receive(method_name, &block) @expectation_set = true observe!(method_name) message_chains.add(method_name, PositiveExpectationChain.new(self, method_name, &block)) end
@private
# File lib/rspec/mocks/any_instance/recorder.rb, line 107 def stop_all_observation! @observed_methods.each {|method_name| restore_method!(method_name)} end
Initializes the recording a stub to be played back against any instance of this object that invokes the submitted method.
@see Methods#stub
# File lib/rspec/mocks/any_instance/recorder.rb, line 29 def stub(method_name_or_method_map, &block) if method_name_or_method_map.is_a?(Hash) method_name_or_method_map.each do |method_name, return_value| stub(method_name).and_return(return_value) end else observe!(method_name_or_method_map) message_chains.add(method_name_or_method_map, StubChain.new(self, method_name_or_method_map, &block)) end end
@private
# File lib/rspec/mocks/any_instance/recorder.rb, line 97 def stub!(*) raise "stub! is not supported on any_instance. Use stub instead." end
Initializes the recording a stub chain to be played back against any instance of this object that invokes the method matching the first argument.
@see Methods#stub_chain
# File lib/rspec/mocks/any_instance/recorder.rb, line 45 def stub_chain(*method_names_and_optional_return_values, &block) normalize_chain(*method_names_and_optional_return_values) do |method_name, args| observe!(method_name) message_chains.add(method_name, StubChainChain.new(self, *args, &block)) end end
Removes any previously recorded stubs, stub_chains or message expectations that use `method_name`.
@see Methods#unstub
# File lib/rspec/mocks/any_instance/recorder.rb, line 71 def unstub(method_name) unless @observed_methods.include?(method_name.to_sym) raise RSpec::Mocks::MockExpectationError, "The method `#{method_name}` was not stubbed or was already unstubbed" end message_chains.remove_stub_chains_for!(method_name) ::RSpec::Mocks.proxies_of(@klass).each do |proxy| stubs[method_name].each { |stub| proxy.remove_single_stub(method_name, stub) } end stubs[method_name].clear stop_observing!(method_name) unless message_chains.has_expectation?(method_name) end
@private
# File lib/rspec/mocks/any_instance/recorder.rb, line 102 def unstub!(*) raise "unstub! is not supported on any_instance. Use unstub instead." end
@api private
Used internally to verify that message expectations have been fulfilled.
# File lib/rspec/mocks/any_instance/recorder.rb, line 87 def verify if @expectation_set && !message_chains.all_expectations_fulfilled? raise RSpec::Mocks::MockExpectationError, "Exactly one instance should have received the following message(s) but didn't: #{message_chains.unfulfilled_expectations.sort.join(', ')}" end ensure stop_all_observation! ::RSpec::Mocks.space.remove_any_instance_recorder_for(@klass) end


German Embassy supports Pionier Boys’ School in Windhoek 20 Nov 2019, 08:58 by Staff Reporter Home \ Youth \ German Embassy supports Pionier Boys’ School in Windhoek - New Era Live