473,785 Members | 2,784 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Puzzling OO design problem

I'm looking for a design to a problem I came across, which goes like
this (no, it's not homework):

1. There is a (single inheritance) hierarchy of domain classes, say
A<-B<-..<-Z (arrows point to the parent in the inheritance tree).
2. This hierarchy evolved over time to different versions for each
class. So for example, version's 1 hierarchy would be A_v1 <-B_v1
<-..<-Z_v1.
3. At runtime, only one version is selected by a factory function.

Up to this point, the inheritance graph would be the following:

A <- A_V1 ... <- A_Vn
^ ^ ^
| | |
B <- B_V1 ... <- B_Vn
.. . .
.. . .
.. . .
^ ^ ^
| | |
Z <- Z_V1 ... <- Z_Vn
This could be implemented either with multiple inheritance (e.g.
B_V1(B,A_V1)) or using the bridge design pattern |Z| times, one per
each row. Both solutions would be acceptable; there are no ambiguities
caused by the multiple inheritance (or they are resolved properly
whenever they occur).

Now the problem is that there are 'holes' in this inheritance lattice:
Not all versions introduced new variations of all types; for instance
B_V5 could be missing, meaning that the most recent earlier version of
B would be used in version 5 (say B_V2). My first thought was to create
all the missing classes dynamically, but it's somewhat obscure and it
may not be that simple. Is there a more elegant solution, either a
general design pattern or some clever python metaprogramming hack ?

George

Jul 18 '05 #1
18 1985
On Fri, Apr 08, 2005 at 04:42:52PM -0700, George Sakkis wrote:
I'm looking for a design to a problem I came across, which goes like
this (no, it's not homework):

1. There is a (single inheritance) hierarchy of domain classes, say
A<-B<-..<-Z (arrows point to the parent in the inheritance tree).
2. This hierarchy evolved over time to different versions for each
class. So for example, version's 1 hierarchy would be A_v1 <-B_v1
<-..<-Z_v1.
3. At runtime, only one version is selected by a factory function.

Up to this point, the inheritance graph would be the following:

A <- A_V1 ... <- A_Vn
^ ^ ^
| | |
B <- B_V1 ... <- B_Vn
. . .
. . .
. . .
^ ^ ^
| | |
Z <- Z_V1 ... <- Z_Vn
This could be implemented either with multiple inheritance (e.g.
B_V1(B,A_V1)) or using the bridge design pattern |Z| times, one per
each row. Both solutions would be acceptable; there are no ambiguities
caused by the multiple inheritance (or they are resolved properly
whenever they occur).

Now the problem is that there are 'holes' in this inheritance lattice:
Not all versions introduced new variations of all types; for instance
B_V5 could be missing, meaning that the most recent earlier version of
B would be used in version 5 (say B_V2). My first thought was to create
all the missing classes dynamically, but it's somewhat obscure and it
may not be that simple. Is there a more elegant solution, either a
general design pattern or some clever python metaprogramming hack ?


Err, you might want to explain what these things do instead of an
abstract description of how you are doing it. It looks like you are
using inheritance in the normal way _and_ you are using it to handle
versioning of some kind (maybe stable interface releases? I don't know).

Let us know what parts need inheritance for, and what you have
just been using a side effect of inheritance for as a convenience
(versioning, I think).

A more concrete example would be easier to comment on, if possible
do a simple one (maybe just two classes with two versions each).

-jackdied
Jul 18 '05 #2
> Err, you might want to explain what these things do instead of an
abstract description of how you are doing it. It looks like you are
using inheritance in the normal way _and_ you are using it to handle
versioning of some kind (maybe stable interface releases? I don't know).
Let us know what parts need inheritance for, and what you have
just been using a side effect of inheritance for as a convenience
(versioning, I think).

A more concrete example would be easier to comment on, if possible
do a simple one (maybe just two classes with two versions each).

-jackdied


I intentionally abstracted the problem to remove the irrelevant
details, but here's a more concrete (though still simplified) example.
I hope it is more clear now.

George

#============== ===============

def worldModelFacto ry(version):
if version < 2: return WorldModel()
else: return WorldModel_v2()

class WorldModel(obje ct):

def __init__(self):
self.ourGoal = self.FieldObjec t(x=-50, y=0)
self.theirGoal = self.FieldObjec t(x=+50, y=0)
self.ball = self.MovableObj ect()
self.teammates = [self.Player(i) for i in xrange(1,12)]
self.opponents = [self.Player(i) for i in xrange(1,12)]

class FieldObject(obj ect):
def __init__(self, id=None, x=0, y=0):
self.id = id
self._pos = (x,y)
def position(self):
'''Get or estimate the current position.'''
return self._pos

class MovableObject(F ieldObject):
def speed(self):
'''Get or estimate the current speed.'''
# [implementation snipped]

class Player(MovableO bject):
def passBall(self,p ower,teammate):
'''Pass the ball to the teammate.'''
# [implementation snipped]
class WorldModel_v2(W orldModel):

class FieldObject(Wor ldModel.FieldOb ject):
'''New implementation of FieldObject.'''
def position(self):
# [new implementation snipped]
pass

class MovableObject(W orldModel.Movab leObject, FieldObject):
'''MovableObjec t didn't change since the previous version. The
only reason for this class is to make
WorldModel_v2.F ieldObject
accessible to WorldModel_v2.P layer.
'''
pass

class Player(WorldMod el.Player, MovableObject):
'''New implementation of Player.'''
def passBall(self,p ower,teammate):
# WorldModel_v2.F ieldObject.posi tion() should be called
myPosition = self.position()
# [new implementation snipped]

#============== ===============

Jul 18 '05 #3
On Fri, Apr 08, 2005 at 06:40:54PM -0700, George Sakkis wrote:
Err, you might want to explain what these things do instead of an
abstract description of how you are doing it. It looks like you are
using inheritance in the normal way _and_ you are using it to handle
versioning of some kind (maybe stable interface releases? I don't know).

Let us know what parts need inheritance for, and what you have
just been using a side effect of inheritance for as a convenience
(versioning, I think).

A more concrete example would be easier to comment on, if possible
do a simple one (maybe just two classes with two versions each).

-jackdied


I intentionally abstracted the problem to remove the irrelevant
details, but here's a more concrete (though still simplified) example.
I hope it is more clear now.


<boiled down version of George's exmaple>
def worldModelFacto ry(version):
if version < 2: return WorldModel()
else: return WorldModel_v2()

class WorldModel_v1(o bject):
class Player(object):
def foo(self): pass # v1 implementation of foo()

class WorldModel_v2(o bject):
class Player(WorldMod el_v2.Player):
def foo(self): pass # v2 implementation of foo()
So you are using the WorldModel_* classes as a namespace to hold a
set of classes that might inherit and extend or redefine the previous
classes in a WorldModel_* namespace. This seems to do what you wanted
in your original post, namely if a class is defined in v1 but not in v2
that v2 would just use v1's implementation. WorldModel_v2 will inherit
Player from _v1 by default, so that should work OK out of the box.

So you should be fine there, but I think your question is more practical
than "what is the proper OO way to do it?" which is a bit of a shibboleth
in python. We like "what is easiest and readable?" So here are some
practical recommendations (well, at least that's my intention).

Are you using the *_v1 naming convention for backwards compatibility?
Backwards compatibility is a giant pain in the ass, I notice you are
posting from a .edu address so if this is just something you are working
on by yourself or in a small group drop the versioning aspects from the
code. Talking to the other people in the group is easier.
From your example (which I over-pruned) it looks like you are using

the WorldModel namespace to define parameters for running an iteration
of a game. The classes under "WorldModel " are something like
the rules/physics definition (MovableObject) , coordinates of the team-A
goalpost, coordinates of the team-B goalpost, team-A strategy (Player),
and team-B strategy (also Player). WorldModel would be the gameboard.

If so, make WorldModel just a board - drop putting Player etc under it
as a namespace, and give it a run() function that takes parameters.
Name the Player derivatives as PlayerDumb, PlayerSmart, PlayerAggressiv e
etc, you'll probably have a lot more of those than goals or physics rules.
The actual main routine would look something like

ob = WorldModel() # standard 100x100 board
winner = ob.run(physics= MovableObject, # defines friction and gravity
team_a_goal=(50 ,25),
team_b_goal=(5, 5),
team_a_strategy =PlayerDumb,
team_b_strategy =PlayerAggressi ve,
)
print "Winner is ", winner

I wrote more than I meant to, but the basic idea is don't use classes
when you don't need to - it just makes things more complex. That
should give you more time to tackle the interesting parts (player
strategies, I'd imagine).

-jackdied
Jul 18 '05 #4
> <boiled down version of George's exmaple>

I'm not sure if it was clear to you, but my problem is the dummy
WorldModel_v1.M ovableObject class. It doesn't do anything by itself,
but it has to be in the inheritance chain to make its descendants work
properly.
Are you using the *_v1 naming convention for backwards compatibility?
Backwards compatibility is a giant pain in the ass, I notice you are
posting from a .edu address so if this is just something you are working on by yourself or in a small group drop the versioning aspects from the code.


Sure, if there was a single version there would be no need for this
post, but that's not the point; backwards compatibilty is part of the
sad reality. I'm trying to write a client for a framework that has gone
through 9 protocol version changes so far and now goes for the 10th.
There are 5-7 different game object classes, so this makes 50-70
classes overall for the ten versions. Most of them would be dummy like
the WorldModel_v1.M ovableObject in the example. So the candidate
solutions so far are:
1. Write the dummy classes by hand.
2. Generate them on the fly using some metaprogramming technique
(introspection/metaclass/?)
3. Find an appropriate design pattern that avoids the need for the
dummy classes.

Any ideas for (2) or (3) ?

George

Jul 18 '05 #5
George Sakkis <gs*****@rutger s.edu> wrote:
1. There is a (single inheritance) hierarchy of domain classes, say
A<-B<-..<-Z (arrows point to the parent in the inheritance tree).
2. This hierarchy evolved over time to different versions for each
class. So for example, version's 1 hierarchy would be A_v1 <-B_v1
<-..<-Z_v1.
3. At runtime, only one version is selected by a factory function. Up to this point, the inheritance graph would be the following:

A <- A_V1 ... <- A_Vn
^ ^ ^
| | |
B <- B_V1 ... <- B_Vn
. . .
. . .
. . .
^ ^ ^
| | |
Z <- Z_V1 ... <- Z_Vn
Interesting problem.
This could be implemented either with multiple inheritance (e.g.
B_V1(B,A_V1))
To help myself thinking about that, let's make a somewhat complicated
example, somewhere in the middle of the graph, with the possibility of
introducing a hole at B3. I also shorten A_Vn to An etc. Consider the
subgraph (with nonstandard annotations of method definition after the bar
(to save space) as explained below):

A2 | f <- A3 | f
^ ^
| |
B2 <- B3
^ ^
| |
C2 | g <- C3 | h

Assume a method g that is present in C2 but not changed in C3. Now g
calls a method f, which is inherited unchanged in C2 from A2 (and not
changed in B2, B3 or C3, either), but changed in A3. Finally, let h
call g in C3. As here the "inheritanc e columns" have "priority", one
would expect then g to call f in A3, and not in A2, for example.

So what you need is that every method, even if not originating from
the "real" class, is looked up first in the column above the "real"
class, then in the column left to that, and so on.

Ok. Multiple inheritance can often select priority for conflicting
methods. If you can specify yhat tou want "column priority" for
each class, you're fine.
or using the bridge design pattern |Z| times, one per each row.
When I read your description above, I also thought immediately
"bridge pattern", but then I tried to write down details,
and got stuck. How would you do it?
Now the problem is that there are 'holes' in this
inheritance lattice: Not all versions introduced new variations of
all types; [...] My first thought was to create all the missing classes dynamically,
but it's somewhat obscure and it may not be that simple. Is there a
more elegant solution, either a general design pattern or some
clever python metaprogramming hack ?


In the most general case, you need to access time the whole "upper
left" subgraph at class creation, collect all methods defined in this
subgraph with "column priority", and overwrite or add to that any
methods defined in the newly defined class.

I don't know enough about the intricacies of Python's class creation
to make a concrete suggestion, but I'd think that would be possible
with the help of __metaclass__. You would need some sort of
repository for the complete inheritance. One way to do that would
be to create the chain A ... Z first, letting A inherit from some
special class with __metaclass__ set, and then store an array
of all versions somewhere inside the class namespace.

You'd also need some special syntax to create a new version of a class
(say, again inheriting from some special class with __metaclass__
set). You could set the version inside the class definition, and then
let the __metaclass__ routine disable the normal inheritance
mechanism, and add missing methods as appropriate.

This could for example look like

class A(Versioning):
...

class B(A):
...

class C(B):
def h ...
...

class A2(NewVersion,A ):
__version__ = 2
def f(): ...

class B2(NewVersion,B ):
__version__ = 2

class C2(NewVersion,C ):
__version__ = 2
def g(): ... f() ...

class A3(NewVersion,A ):
__version__ = 3
def f(): ...

class C3(NewVersion,C ):
__version__ = 3
def h(): ... g() ...

with a hole at B3, as in the example. C3 will get g from C2 and f from
A3, and hence the call chain will work correctly. Also, C3 will have no
base classes (or maybe only the __metaclass__ ones), the inherited
class A, B, C are just used by the class creation process to find
out where to look for the inheritance matrix.

Others who know more about the class creation mechanism will no doubt
improve this suggestion, point out my errors, and tell you how to
implement it :-) Note that you're basically completely changing the
normal inheritance mechanism, and the class objects will be larger,
because they'll have to copy all the necessary methods.

I cannot think of any pattern that would give similar flexibility.

- Dirk
Jul 18 '05 #6
George Sakkis wrote:
<boiled down version of George's exmaple>

I'm not sure if it was clear to you, but my problem is the dummy
WorldModel_v1.M ovableObject class. It doesn't do anything by itself,
but it has to be in the inheritance chain to make its descendants work
properly.

George,

since you explicit allowed metaprogramming hacks :-), how about something like
this (not tested beyond what you see):

class WorldVersion(ty pe):
"""WorldVer sion instances are World classes
If a World inherits from another World: Field, Movable, Player
automatically inherit from their corresponding superclasses"""

def __new__(self, name, bases, clsdict):
clslist = set(["Field", "Movable", "Player"])
baseworld = bases[0]
if type(baseworld) is self:
for cls in clslist:
base = getattr(basewor ld,cls)
target = clsdict.setdefa ult(cls, base)
if base is target:
continue
oldbases = list(target.__b ases__)
if base in target.__bases_ _:
continue
try:
oldbases[oldbases.index( object)] = base
except ValueError:
oldbases.append (base)
target = type(target.__n ame__, tuple(oldbases) ,
dict(target.__d ict__))
clsdict[cls] = target

return type.__new__(se lf,name, bases, clsdict)

class World1(object):
__metaclass__ = WorldVersion
class Field(object):
def position(self):
print "Positionin g in World1"
class Movable(Field):
def move(self):
print "Moving in World1"
class Player(Movable) :
def passBall(self):
print "Passing in World1"

class World2(World1):
__metaclass__ = WorldVersion
class Field(object):
def position(self):
print "Positionin g in World2"
class Movable(Field): # You still need placeholder classes
# but they are trivial
pass
class Player(Movable) :
def passBall(self):
print "Passing in World2"

class World3(World2):
__metaclass__ = WorldVersion
class Player(object):
def passBall(self):
print "Passing in World3"

p3 = World3.Player()
p3.move() Moving in World1 p3.position() Positioning in World2 p3.passBall() Passing in World2


Michael

Jul 18 '05 #7
"Michael Spencer" <ma**@telcopart ners.com> wrote:

George,

since you explicit allowed metaprogramming hacks :-), how about something like this (not tested beyond what you see):

[snipped]


Nice try, but ideally all boilerplate classes would rather be avoided
(at least being written explicitly). Also, it is not obvious in your
solution why and which placeholder classes have to be written (like
World2.Movable) and which do not. By the way, my current working
solution involves copying and pasting verbatim these classes :-) Below
is an abstracted example; note that the 'declaration string' of each
original class is exactly the same across all different versions after
the first (e.g. "class B(PreviousNames pace.B, A)").
#============== =============== =============== ==========
# version_1.py

class Namespace:
class A(object):
def foo(self): return "version_1.foo( )"
class B(A):
def bar(self): return "version_1.bar( )"
class C(B):
def zen(self): return "version_1.zen( )"
#============== =============== =============== ==========
# version_2.py

from version_1 import Namespace as PreviousNamespa ce
class Namespace(Previ ousNamespace):
class A(PreviousNames pace.A):
def foo(self): return "version_2.foo( )"
class B(PreviousNames pace.B, A):
pass
class C(PreviousNames pace.C, B):
pass
#============== =============== =============== ==========
# version_3.py

from version_2 import Namespace as PreviousNamespa ce
class Namespace(Previ ousNamespace):
class A(PreviousNames pace.A):
pass
class B(PreviousNames pace.B, A):
def bar(self): return "version_3.bar( )"
class C(PreviousNames pace.C, B):
pass

#============== =============== =============== ==========
# test.py
# command: python test.py <#version>

def NamespaceFactor y(version):
return __import__("ver sion_%d" % version).Namesp ace

print NamespaceFactor y(2).B().foo() # "version_2.foo( )"
print NamespaceFactor y(3).C().bar() # "version_3.bar( )"

import sys, inspect
namespace = NamespaceFactor y(int(sys.argv[1]))
# print the __mro__ of each 'inner' class
for name,cls in inspect.getmemb ers(namespace,
inspect.isclass ):
print cls
for ancestor in cls.__mro__:
print "\t", ancestor

#============== =============== =============== ==========

George

Jul 18 '05 #8
George Sakkis wrote:

Nice try, but ideally all boilerplate classes would rather be avoided
(at least being written explicitly).
It depends on how much magic you are prepared to accept; this goal is somewhat
in conflict with the next one...

Also, it is not obvious in your solution why and which placeholder classes have to be written (like
World2.Movable) and which do not.
It is systematic, if not obvious. You need place holder classes only if you
need to propagate new methods within a given world. More magic would make this
even less obvious.

By the way, my current working solution involves copying and pasting verbatim these classes :-)

It appears to be basically the same as mine except you spell out the previous
version explicitly (not that that's bad!)

Have you considered a 'macro' solution composing source? If I were handling so
many versions, I would want a complete class definition for each version rather
than having to scan many sources for each implementation.

Michael

Jul 18 '05 #9
Dirk Thierbach <dt********@use net.arcornews.d e> wrote:
Ok. Multiple inheritance can often select priority for conflicting
methods. If you can specify yhat tou want "column priority" for
each class, you're fine.


On second thought, I had doubts. Consider the following scenario:

A2 | f <- A3
^ ^
| |
B2 | f <- B3
^ ^
| |
C2 <- C3 | g

Assume g calls f. Since f is defined in B version 2, it should taken
over unchanged into B version 3, and that should be the version g
calls. However, with multiple inheritance doing depth-first search,
giving the "upper" class priority over the "left", the first path
searched is B3 - A3 - A2, and hence it finds f at A2. A quick test
confirms this for old-style classes, which failed in exactly that
way. But with new-style classes, it works, and finds f at B2 instead.

So I dug through the documentation and found that new-style classes
compute a monotonic linearization of the inheritance graph, observing
local precedence order, using the algorithm also used in Dylan
described here:

http://www.webcom.com/haahr/dylan/li...-oopsla96.html

And this algorithm will even work correctly if one leaves out B3
in the example above, inheriting directly as in C3(A3,C2), because
the ordering constraint that A2 comes before B2 will still be
valid in the linearization for C3.

However, in the following case (shortening the notation even more)
it will fail, if a method defined at C3 is looked up at D4:

A1 - A2 - A3 - A4 - ...
| | | |
B1 - B2 - + - B4 - ...
| | | |
C1 - + - C3 - + - ...
| | | |
D1 - D2 - + - D4 - ...
| | | |

The solution is simply to include C3 in the list of parents of D4, as
in D4(C3,B4,D2). So for every hole in a column, you have to include
the first class (or classes, if the hole spans multiple rows) to the
left of the hole as parents if the class just below the hole, in order
from bottom to top. This adds the missing constraints, and should
solve the problem without any need to write __metaclass__ stuff.

Interesting question. I learned a lot while thinking about that.

- Dirk
Jul 18 '05 #10

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

Similar topics

2
1590
by: Dfenestr8 | last post by:
Hi. I have a problem with a subroutine in a cgi script that's supposed to return the byte location at the end of a file, which the script then stores as a hidden input on a web form. Unfortunately, even though it works fine in the python shell, in the cgi-script it always returns "0". That's no use to me at all. Here's the subroutine......
1
6078
by: Robert Brown | last post by:
I have a deadlock that's happening on one oracle instance but cannot be reproduced on any other. It is always caused by the same SQL statement colliding with itself and only happens under very high load. The statement is DELETE from userlogins WHERE numlogins <= 0 the schema for the userlogins table is
5
1366
by: fn | last post by:
Does anyone have possible explanations for the following results? select count(*) from tablename >>> 2,500,000 select count(*) from tablename where fieldname is null >>> 2,400,000 select count(*) from tablename where fieldname is not null >>> 900,000
3
3151
by: Omer van Kloeten | last post by:
The Top Level Design: The class Base is a factory class with a twist. It uses the Assembly/Type classes to extract all types that inherit from it and add them to the list of types that inherit from it. During run time, using a static method, the class creates an instance of the derived class using the Activator class and returns it. This design pattern is very similar to the design pattern applied by the Assembly class. The twist is...
6
1639
by: oeyvind toft | last post by:
I have a frameset consisting of 3 frames: top, left and right. In top frame: body onload calls a js init function to set (or resets) values in textareas etc...in all frames. In right frame: A large textarea for dynamicly updated text. Problem: When clicking the browser 'update' this doesnt work: myTextAreaOnTheRight = ""; UNLESS I put an alert(anything) before the statement.
1
1854
by: Christopher P. Winter | last post by:
I'm seeing some unexpected behavior with Text-indent, as shown on this page: http://www.chris-winter.com/Digressions/HP_Kayak/My_Kayak.html I set up the following style rules for footnotes: DIV.FootRule { Border-bottom: 1px Solid Gray; Margin-bottom: 2px; Text-align: Left; Width: 20% }
9
1259
by: Sue & Bill | last post by:
I attach the following code and output. I Add an object to a Collection. I modified a property of the object. The item in the Collection gets modifed also. Can you help me determine where I have gone wrong. Thanks. public class Shape { protected Size _size; protected Point _location;
9
3662
by: AceKnocks | last post by:
I am working on a framework design problem in which I have to design a C++ based framework capable of solving three puzzles for now but actually it should work with a general puzzle of any kind and I need your able help in this activity. Objective - In this activity you will design a framework capable of solving any puzzle of a specific type and, as a test of this framework, use the framework to solve a very simple puzzle. In this first...
2
9842
by: existential.philosophy | last post by:
This is a new problem for me: I have some queries that open very slowly in design view. My benchmark query takes about 20 minutes to open in design view. That same query takes about 20 minutes to open in datasheet view. As an experiment, I deleted all rows in all tables; after that, the query took only seconds to open in both design view and datasheet view. From these facts, I conclude that Access is evaluating the query when I go to...
0
9480
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
10327
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10151
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...
0
8973
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
6740
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
5381
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...
1
4053
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3647
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2879
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.