473,688 Members | 3,093 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

pre-PEP generic objects

I promised I'd put together a PEP for a 'generic object' data type for
Python 2.5 that allows one to replace __getitem__ style access with
dotted-attribute style access (without declaring another class). Any
comments would be appreciated!

Thanks!

Steve

----------------------------------------------------------------------
Title: Generic Object Data Type
Version: $Revision: 1.0 $
Last-Modified: $Date: 2004/11/29 16:00:00 $
Author: Steven Bethard <st************ @gmail.com>
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 29-Nov-2004
Python-Version: 2.5
Post-History: 29-Nov-2004
Abstract
========

This PEP proposes a standard library addition to support the simple
creation of 'generic' objects which can be given named attributes
without the need to declare a class. Such attribute-value mappings are
intended to complement the name-value mappings provided by Python's
builtin dict objects.
Motivation
==========

Python's dict objects provide a simple way of creating anonymous
name-value mappings. These mappings use the __getitem__ protocol to
access the value associated with a name, so that code generally appears
like::

mapping['name']

Occasionally, a programmer may decide that dotted-attribute style access
is more appropriate to the domain than __getitem__ style access, and
that their mapping should be accessed like::

mapping.name

Currently, if a Python programmer makes this design decision, they are
forced to declare a new class, and then build instances of this class.
When no methods are to be associated with the attribute-value mappings,
declaring a new class can be overkill. This PEP proposes adding a
simple type to the standard library that can be used to build such
attribute-value mappings.

Providing such a type allows the Python programmer to determine which
type of mapping is most appropriate to their domain and apply this
choice with minimal effort. Some of the suggested uses include:
Returning Named Results
-----------------------

It is often appropriate for a function that returns multiple items to
give names to the different items returned. The type suggested in this
PEP provides a simple means of doing this that allows the returned
values to be accessed in the usual attribute-style access::
def f(x): ... return Bunch(double=2* x, squared=x**2)
... y = f(10)
y.double 20 y.squared 100
Representing Hierarchical Data
------------------------------

The type suggested in this PEP also allows a simple means of
representing hierarchical data that allows attribute-style access::
x = Bunch(spam=Bunc h(rabbit=1, badger=[2, 3, 4]), ham='neewom')
x.spam.badger [2, 3, 4] x.ham 'neewom'
Rationale
=========

As Bunch objects are intended primarily to replace simple classes,
simple Bunch construction was a primary concern. As such, the Bunch
constructor supports creation from keyword arguments, dicts, and
sequences of (attribute, value) pairs::
Bunch(eggs=1, spam=2, ham=3) Bunch(eggs=1, ham=3, spam=2) Bunch({'eggs':1 , 'spam':2, 'ham':3}) Bunch(eggs=1, ham=3, spam=2) Bunch([('eggs',1), ('spam',2), ('ham',3)]) Bunch(eggs=1, ham=3, spam=2)

To allow attribute-value mappings to be easily combined, the update
method of Bunch objects supports similar arguments.

If Bunch objects are used to represent hierarchical data, comparison of
such objects becomes a concern. For this reason, Bunch objects support
object equality::
x = Bunch(parrot=Bu nch(lumberjack= True, spam=42), peng='shrub')
y = Bunch(peng='shr ub', parrot=Bunch(sp am=42, lumberjack=True ))
z = Bunch(parrot=Bu nch(lumberjack= True), peng='shrub')
x == y True x == z False

Additionally, to allow users of the Bunch type to convert other
hierarchical data into Bunch objects, a frommapping classmethod is
supported. This can be used, for example, to convert an XML DOM tree
into a tree of nested Bunch objects::
import xml.dom.minidom
def getitems(elemen t): ... if not isinstance(elem ent, xml.dom.minidom .Element):
... raise TypeError('item s only retrievable from Elements')
... if element.attribu tes:
... for key, value in element.attribu tes.items():
... yield key, value
... children = {}
... for child in element.childNo des:
... if child.nodeType == xml.dom.minidom .Node.TEXT_NODE :
... text_list = children.setdef ault('text', [])
... text_list.appen d(child.nodeVal ue)
... else:
... children.setdef ault(child.node Name, []).append(
... Bunch.frommappi ng(child, getitems=getite ms))
... for name, child_list in children.items( ):
... yield name, child_list
... doc = xml.dom.minidom .parseString("" "\ ... <xml>
... <a attr_a="1">
... a text 1
... <b attr_b="2" />
... <b attr_b="3"> b text </b>
... a text 2
... </a>
... <c attr_c="4"> c text </c>
... </xml>""") b = Bunch.frommappi ng(doc.document Element, getitems=getite ms)
b.a[0].b[1] Bunch(attr_b=u' 3', text=[u' b text '])

Note that support for the various mapping methods, e.g.
__(get|set|del) item__, __len__, __iter__, __contains__, items, keys,
values, etc. was intentionally omitted as these methods did not seem to
be necessary for the core uses of an attribute-value mapping. If such
methods are truly necessary for a given use case, this may suggest that
a dict object is a more appropriate type for that use.
Reference Implementation
=============== =========

(This will be replaced with a link to a SF patch when I think I've
made all the necessary corrections)::

import operator as _operator

class Bunch(object):
"""Bunch([bunch|dict|seq], **kwds) -> new bunch with specified
attributes

The new Bunch object's attributes are initialized from (if
provided) either another Bunch object's attributes, a
dictionary, or a sequence of (name, value) pairs, then from the
name=value pairs in the keyword argument list.

Example Usage: Bunch(eggs=1, spam=2, ham=3) Bunch(eggs=1, ham=3, spam=2) Bunch({'eggs':1 , 'spam':2, 'ham':3}) Bunch(eggs=1, ham=3, spam=2) Bunch([('eggs',1), ('spam',2), ('ham',3)]) Bunch(eggs=1, ham=3, spam=2) Bunch(Bunch(egg s=1, spam=2), ham=3) Bunch(eggs=1, ham=3, spam=2)
"""

def __init__(self, *args, **kwds):
"""Initiali zes a Bunch instance."""
self.update(*ar gs, **kwds)

def __eq__(self, other):
"""x.__eq__ (y) <==> x == y"""
return (isinstance(oth er, self.__class__)
and self.__dict__ == other.__dict__)

def __repr__(self):
"""x.__repr __() <==> repr(x)

If all attribute values in this bunch (and any nested
bunches) are reproducable with eval(repr(x)), then the Bunch
object is also reproducable for eval(repr(x)).
"""
return '%s(%s)' % (self.__class__ .__name__,
', '.join('%s=%r' % (k, v)
for k, v
in self.__dict__.i tems()))

def update(self, *args, **kwds):
"""update([bunch|dict|seq], **kwds) -> None

Updates a Bunch object's attributes from (if provided)
either another Bunch object's attributes, a dictionary, or a
sequence of (name, value) pairs, then from the name=value
pairs in the keyword argument list.
"""
if len(args) == 1:
other, = args
if isinstance(othe r, self.__class__) :
other = other.__dict__
try:
self.__dict__.u pdate(other)
except TypeError:
raise TypeError('cann ot update Bunch with %s' %
type(other).__n ame__)
elif len(args) != 0:
raise TypeError('expe cted 1 argument, got %i' %
len(args))
self.__dict__.u pdate(kwds)

@classmethod
def frommapping(cls , mapping, getitems=None):
"""Create a Bunch object from a (possibly nested) mapping.

Note that, unlike the Bunch constructor, frommapping
recursively converts all mappings to bunches.

Example Usage: Bunch.frommappi ng({'eggs':1,

... 'spam':{'ham':2 , 'badger':3}})
Bunch(eggs=1, spam=Bunch(ham= 2, badger=3))

Keyword Arguments:
mapping -- a mapping object
getitems -- a function that takes the mapping as a parameter
and returns an iterable of (key, value) pairs. If not
provided, the items method on the mapping object will be
used, or (key, mapping[key]) values will be generated if
the mapping object does not provide an items method.

Note that getitems will be applied recursively to each value
in the mapping. It should raise a TypeError if it is
applied to an object for which it cannot produce
(key, value) pairs.
"""
# determine which items() method to use
if getitems is None:
try:
getitems = type(mapping).i tems
except AttributeError:
getitems = _items
# build the Bunch from the mapping, recursively
result = cls()
for key, value in getitems(mappin g):
try:
value = cls.frommapping (value, getitems=getite ms)
except TypeError:
pass
setattr(result, key, value)
return result
def _items(mapping) :
"""Produces (key, value) pairs from a mapping object.

Intended for use with mapping objects that do not supply an
items method.
"""
for key in mapping:
yield key, mapping[key]
Open Issues
===========
What should the type be named? Some suggestions include 'Bunch',
'Record' and 'Struct'.

Where should the type be placed? The current suggestion is the
collections module.
References
==========

...
Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End:
Jul 18 '05 #1
49 2876
Steven Bethard wrote:
Currently, if a Python programmer makes this design decision, they are
forced to declare a new class, and then build instances of this class.


FORCED to create a new class, and FORCED to create instances of
their own class instead of your class? without this, Python must surely
be unusable. no wonder nobody's ever managed to use it for anything.

</F>

Jul 18 '05 #2
Steven Bethard wrote:
def*__eq__(self ,*other):
"""x.__eq__(y)* <==>*x*==*y"" "
return*(isinsta nce(other,*self .__class__)
and*self.__dict __*==*other.__d ict__)


This results in an asymmetry:
from bunch import Bunch
class B(Bunch): pass .... B().__eq__(Bunc h()) False Bunch().__eq__( B()) True

With indirect use of __eq__() this puzzling behaviour disappears:
B() == Bunch() False Bunch() == B()

False

Whether this is intended, I don't know. If someone can enlighten me...

In any case I would prefer self.__class__ == other.__class__ over
isinstance().

Peter
Jul 18 '05 #3
Steven Bethard <st************ @gmail.com> wrote:
I promised I'd put together a PEP for a 'generic object' data type for
Python 2.5 that allows one to replace __getitem__ style access with
dotted-attribute style access (without declaring another class). Any
comments would be appreciated!


This sounds very much like this class which I've used to convert perl
programs to python

class Hash:
def __init__(self, **kwargs):
for key,value in kwargs.items():
setattr(self, key, value)
def __getitem__(sel f, x):
return getattr(self, x)
def __setitem__(sel f, x, y):
setattr(self, x, y)

My experience from using this is that whenever I used Hash(), I found
that later on in the refinement of the conversion it became its own
class.

So my take on the matter is that this encourages perl style
programming (just ram it in a hash, and write lots of functions acting
on it) rather than creating a specific class for the job which is dead
easy in python anyway and to which you can attach methods etc.

YMMV ;-)

--
Nick Craig-Wood <ni**@craig-wood.com> -- http://www.craig-wood.com/nick
Jul 18 '05 #4
The proposed use cases sound more appropriate for a "named tuple" than any sort
of dictionary. (This may have been mentioned in previous discussions. I wasn't
keeping track of those, though)

Notice that I've used 'fromPairs' rather than 'fromMapping', since consistent
order matters for a tuple. Comparison semantics are inherited directly from
tuple, and don't care about names (they're only interested in values).

Also, it seems like there has to be a better way to do the "opposite of zip()"
in fromPairs(), but I sure as hell can't think of it.

Cheers,
Nick.
a = named_tuple(['x', 'y'], (3, 8))
a named_tuple(['x', 'y'], (3, 8)) a.x 3 a.y 8 str(a) '(3, 8)' b = named_tuple.fro mPairs(sorted({ 'x':3, 'y':8}.items()) )
b named_tuple(['x', 'y'], (3, 8)) b.x 3 b.y 8 str(b) '(3, 8)' a == b True


And the code for the above:

class named_tuple(tup le):
def __new__(cls, names, *args):
self = tuple.__new__(c ls, *args)
self._names = dict(zip(names, range(len(names ))))
return self

@staticmethod
def fromPairs(items ):
names = [x[0] for x in items]
values = [x[1] for x in items]
return named_tuple(nam es, values)

def __getattr__(sel f, attr):
if attr in self._names:
return self[self._names[attr]]
else:
return tuple.__getattr __(attr)

def __repr__(self):
return "named_tuple(%s , %s)" % (str(self.names ()),
str(tuple.__rep r__(self)))

def __str__(self):
return tuple.__repr__( self)

def names(self):
return sorted(self._na mes.keys(), key=self._names .__getitem__)
Jul 18 '05 #5
On Tue, 30 Nov 2004 22:30:21 +1000, Nick Coghlan <nc******@email .com> wrote:
The proposed use cases sound more appropriate for a "named tuple" than any sort
of dictionary. (This may have been mentioned in previous discussions. I wasn't
keeping track of those, though)


I agree with it. I was involved in that discussion, and got the the
point of listing a few desired features. As I am currently involved
into other project, I left it as it was, but I'll resume working as
soon as I can. I really think that both (generic objects and named
tuples) are slighly different but still very similar approaches to the
same problem, so some sort of "unificatio n" of the efforts may be
interesting.

But there's something more important: while reading this document, and
some of the replies, it became clear that the main point is to
understand whether this proposed feature (in any possible
implementation) is in fact useful enough to deserve a place in the
standard library, and also if it represents a good coding style. With
some risk of being way too simplistic, it's something like this:

-- The people that is favorable to this implementation argue that one
should not be required to create a new class just to return a bunch of
results.

-- The people that is against it point out that, as soon as you start
returning multiple values, it's probable that you'll need to implement
a class anyway, so it's better off to do it sooner and forget generics
(or named tuples) entirely.

I see some parallels between this discussion and another one about
polymorphism. It's considered good Python practice to rely on
interfaces, or protocols, when designing the call signature of a
function or method. So if you receive an arbitrary object, you should
not check if it's a descendand of some abstract parent type; that's
just too rigid, and forces people to deal with complex multiple
inheritance stuff, and that's really not needed in Python. There is a
better way: just check if it exposes the desired interface, or
protocol. The adaptation framework (as described by PEP 246, and
extended by the PyProtocols package) is a nice implementation of this
concept.

A "generic" return object is just like this, but for a different
scenario: an adaptable return value, that doesn't enforce a class
signature when assigning the return value of a function or method.
It's perfectly symmetrical to the usage of interfaces on call. I think
that's a better, and much more powerful argument for the
implementation of a generic class, and also, for some supporting
machinery for it.

Extending this reasoning, generic return objects (implemented either
as dictionary based, or as named tuples) could be seen as "adaptable"
return values. Upon return, one could get such a temporary structure
and assign its members into another, more complex class, that would
accept fields of the same name, but possibly include other fields and
extra functionality. For example: a function that returns a complex
time structure does not need to return a "time class". It may return a
generic, or named tuple, which is in turn can be assigned to an object
that exposes a 'compatible' assignment interface. This assignment can
be done by a method of the generic clas itself, according either to
the names of the member of the generics, or the order of the tuple,
depending on the scenario.

For now, that's all that I have to contribute into this discussion.
There's also a lot of stuff in the c.l.py archives regarding named
tuples and also generics that is surely worth checking.

--
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: ca********@gmai l.com
mail: ca********@yaho o.com
Jul 18 '05 #6
Fredrik Lundh wrote:
Steven Bethard wrote:
Currently, if a Python programmer makes this design decision, they are
forced to declare a new class, and then build instances of this class.
FORCED to create a new class, and FORCED to create instances of
their own class instead of your class?


I don't see any way to produce the same behavior without *someone* (the
user or the stdlib) declaring a class. If you see a way to do this
without a class declared somewhere, please let me know how...
without this, Python must surely be unusable.
I definitely agree. Python without classes would be quite unpleasant to
use.
no wonder nobody's ever managed to use it for anything.


Yeah, I don't think anyone's managed to use Python without classes for
years, especially since things like int, str, etc. were converted to types.

Steve
Jul 18 '05 #7
Peter Otten wrote:
Steven Bethard wrote:
def __eq__(self, other):
"""x.__eq__ (y) <==> x == y"""
return (isinstance(oth er, self.__class__)
and self.__dict__ == other.__dict__)
This results in an asymmetry:

[snip]
Whether this is intended, I don't know. If someone can enlighten me...

In any case I would prefer self.__class__ == other.__class__ over
isinstance().


Unintended. I'll switch to
self.__class__ == other.__class__
or
type(self) == type(other)
Any preference?

Steve
Jul 18 '05 #8
Nick Craig-Wood wrote:
Steven Bethard <st************ @gmail.com> wrote:
I promised I'd put together a PEP for a 'generic object' data type for
Python 2.5 that allows one to replace __getitem__ style access with
dotted-attribute style access (without declaring another class). Any
comments would be appreciated!
My experience from using this is that whenever I used Hash(), I found
that later on in the refinement of the conversion it became its own
class.


This has also generally been my experience, though I'm not sure it's as
true for the XML DOM to Bunch translation. Did you use Hash() in the
same way for hierarchical data?
So my take on the matter is that this encourages perl style
programming (just ram it in a hash, and write lots of functions acting
on it) rather than creating a specific class for the job which is dead
easy in python anyway and to which you can attach methods etc.


You'll note that the (pre-)PEP explicitly notes that this object is
intended only for use when no methods are associated with the attributes:

"When no methods are to be associated with the attribute-value mappings,
declaring a new class can be overkill."

I do understand your point though -- people might not use Bunch in the
way it's intended. Of course, those same people can already do the same
thing with a dict instead (e.g. write a bunch of functions to handle a
certain type of dict). If someone wants to write Perl in Python,
there's not much we can really do to stop them...

Steve
Jul 18 '05 #9
Nick Coghlan wrote:
The proposed use cases sound more appropriate for a "named tuple" than
any sort of dictionary. (This may have been mentioned in previous
discussions. I wasn't keeping track of those, though)
For the return values, yeah, a "named tuple" is probably at least as
appropriate. I'm not sure a "named tuple" is necessary for the
hierarchical data. (It wasn't for me in my DOM to Bunch example.)

I saw the "named tuple" thread slowly die, mainly because the most ideal
solution:

(name1:val1, name2:val2)

requires a change in Python's syntax, which is a tough route to go.

This PEP isn't attempting to solve the "named tuple" problem, though if
that thread picks back up again and produces a solution that also solves
the problems here, I'm more than willing to merge the two PEPs.

Note that I'm not trying to solve all the problems that a "named tuple"
could solve -- just the problem of converting __getattr__ syntax to
dotted-attribute syntax without the need to declare a class.
Notice that I've used 'fromPairs' rather than 'fromMapping', since
consistent order matters for a tuple. Comparison semantics are inherited
directly from tuple, and don't care about names (they're only interested
in values).
frommapping was intended to handle the recursive (hierarchical data)
case. (Perhaps it needs a better name to clarify this...) The shallow
conversion was handled in the Bunch constructor. I don't see that your
named_tuple type handles the recursive case, does it?

Also, it seems like there has to be a better way to do the "opposite of
zip()" in fromPairs(), but I sure as hell can't think of it.


I think zip(*) is usually the inverse of zip():

..>>> zip(*sorted({'x ':3, 'y':8}.items()) )
..[('x', 'y'), (3, 8)]

Steve
Jul 18 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

21
10211
by: Headless | last post by:
I've marked up song lyrics with the <pre> tag because it seems the most appropriate type of markup for the type of data. This results in inefficient use of horizontal space due to UA's default rendering of <pre> in a fixed width font. To change that I'd have to specify a proportional font family, thereby falling into the size pitfall that is associated with any sort of author specified font family: a) If I specify a sans serif font...
3
3794
Pre
by: Neal | last post by:
A few questions about pre... When presenting preformatted text using the white-space: pre; property/value, Opera renders long lines at small viewport widths as exiting the borders of the element, IE6 extends the element to contain the line. Both necessitate horizontal scrolling. 1) Is one considered incorrect, or are both fair interpretations of the recommendation?
7
18530
by: Alan Illeman | last post by:
How do I set several different properties for PRE in a CSS stylesheet, rather than resorting to this: <BODY> <PRE STYLE="font-family:monospace; font-size:0.95em; width:40%; border:red 2px solid; color:red;
2
2785
by: Buck Turgidson | last post by:
I want to have a css with 2 PRE styles, one bold with large font, and another non-bold and smaller font. I am new to CSS (and not exactly an expert in HTML, for that matter). Is there a way to do this in CSS? <STYLE TYPE="text/css"> pre{ font-size:xx-large;
5
718
by: Michael Shell | last post by:
Greetings, Consider the XHTML document attached at the end of this post. When viewed under Firefox 1.0.5 on Linux, highlighting and pasting (into a text editor) the <pre> tag listing will preserve formatting (white space and line feeds). However, this is not true when doing the same with the <code> tag listing (it will all be pasted on one line with multiple successive spaces treated as a single space) despite the fact that...
8
3778
by: Jarno Suni not | last post by:
It seems to be invalid in HTML 4.01, but valid in XHTML 1.0. Why is there the difference? Can that pose a problem when such a XHTML document is served as text/html?
7
2741
by: Rocky Moore | last post by:
I have a web site called HintsAndTips.com. On this site people post tips using a very simply webform with a multi line TextBox for inputing the tip text. This text is encode to HTML so that no tags will remain making the page safe (I have to convert the linefeeds to <BR>s because the Server.EncodeHTML does not do that it seems). The problem is that users can use a special tag when editing the top to specify an area of the tip that will...
9
5540
by: Eric Lindsay | last post by:
I can't figure how to best display little snippets of shell script using <pre>. I just got around to organising to bulk validate some of my web pages, and one of the problems occurs with Bash shell pieces like this: <pre><code> #!/bin/sh ftp -i -n ftp.server.com&lt; &lt;EOF user username password epsv4 cd /
14
3625
by: Schraalhans Keukenmeester | last post by:
I am building a default sheet for my linux-related pages. Since many linux users still rely on/prefer viewing textmode and unstyled content I try to stick to the correct html tags to pertain good readibility on browsers w/o css-support. For important notes, warnings etc I use the <pre> tag, which shows in a neat bordered box when viewed with css, and depending on its class a clarifying background-image is shown. I would like the...
0
8594
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8528
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
8947
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
8783
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
7621
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5810
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4321
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4547
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
2219
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.