diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/cosNotification | |
download | otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2 otp-84adefa331c4159d432d22840663c38f155cd4c1.zip |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/cosNotification')
98 files changed, 26065 insertions, 0 deletions
diff --git a/lib/cosNotification/AUTHORS b/lib/cosNotification/AUTHORS new file mode 100644 index 0000000000..55d8059989 --- /dev/null +++ b/lib/cosNotification/AUTHORS @@ -0,0 +1,4 @@ +Original Authors: +Niclas Eklund + +Contributors: diff --git a/lib/cosNotification/Makefile b/lib/cosNotification/Makefile new file mode 100644 index 0000000000..980f36191f --- /dev/null +++ b/lib/cosNotification/Makefile @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include vsn.mk +VSN=$(COSNOTIFICATION_VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- +# SUB_DIRECTORIES = src test examples doc/src +# At the moment we don't have any example programs. +SUB_DIRECTORIES = src doc/src + +SPECIAL_TARGETS = + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_subdir.mk diff --git a/lib/cosNotification/doc/html/.gitignore b/lib/cosNotification/doc/html/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/cosNotification/doc/html/.gitignore diff --git a/lib/cosNotification/doc/man3/.gitignore b/lib/cosNotification/doc/man3/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/cosNotification/doc/man3/.gitignore diff --git a/lib/cosNotification/doc/man6/.gitignore b/lib/cosNotification/doc/man6/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/cosNotification/doc/man6/.gitignore diff --git a/lib/cosNotification/doc/pdf/.gitignore b/lib/cosNotification/doc/pdf/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/cosNotification/doc/pdf/.gitignore diff --git a/lib/cosNotification/doc/src/CosNotification.xml b/lib/cosNotification/doc/src/CosNotification.xml new file mode 100644 index 0000000000..22e9bcb27c --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotification.xml @@ -0,0 +1,234 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2002</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotification</title> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2002-02-05</date> + <rev>PA1</rev> + </header> + <module>CosNotification</module> + <modulesummary>This module export functions which return QoS and Admin Properties constants.</modulesummary> + <description> + <p>To get access to all definitions include necessary <c>hrl</c> files by using: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + </description> + <funcs> + <func> + <name>'EventReliability'() -> string()</name> + <fsummary>Return the EventReliability QoS identifier</fsummary> + <desc> + <p>This function returns the EventReliability QoS identifier</p> + </desc> + </func> + <func> + <name>'BestEffort'() -> short()</name> + <fsummary>Return the BestEffort QoS value</fsummary> + <desc> + <p>This function returns the BestEffort QoS value.</p> + </desc> + </func> + <func> + <name>'Persistent'() -> short()</name> + <fsummary>Return the Persistent QoS value</fsummary> + <desc> + <p>This function returns the Persistent QoS value.</p> + </desc> + </func> + <func> + <name>'ConnectionReliability'() -> string()</name> + <fsummary>Return the ConnectionReliability QoS identifier</fsummary> + <desc> + <p>This function returns the ConnectionReliability QoS identifier.</p> + </desc> + </func> + <func> + <name>'Priority'() -> string()</name> + <fsummary>Return the Priority QoS identifier</fsummary> + <desc> + <p>This function returns the Priority QoS identifier.</p> + </desc> + </func> + <func> + <name>'LowestPriority'() -> short()</name> + <fsummary>Return the LowestPriority QoS value</fsummary> + <desc> + <p>This function returns the LowestPriority QoS value.</p> + </desc> + </func> + <func> + <name>'HighestPriority'() -> short()</name> + <fsummary>Return the HighestPriority QoS value</fsummary> + <desc> + <p>This function returns the HighestPriority QoS value.</p> + </desc> + </func> + <func> + <name>'DefaultPriority'() -> short()</name> + <fsummary>Return the DefaultPriority QoS value</fsummary> + <desc> + <p>This function returns the DefaultPriority QoS value.</p> + </desc> + </func> + <func> + <name>'StartTime'() -> string()</name> + <fsummary>Return the StartTime QoS identifier</fsummary> + <desc> + <p>This function returns the StartTime QoS identifier.</p> + </desc> + </func> + <func> + <name>'StopTime'() -> string()</name> + <fsummary>Return the StopTime QoS identifier</fsummary> + <desc> + <p>This function returns the StopTime QoS identifier.</p> + </desc> + </func> + <func> + <name>'Timeout'() -> string()</name> + <fsummary>Return the Timeout QoS identifier</fsummary> + <desc> + <p>This function returns the Timeout QoS identifier.</p> + </desc> + </func> + <func> + <name>'OrderPolicy'() -> string()</name> + <fsummary>Return the OrderPolicy QoS identifier</fsummary> + <desc> + <p>This function returns the OrderPolicy QoS identifier.</p> + </desc> + </func> + <func> + <name>'AnyOrder'() -> short()</name> + <fsummary>Return the AnyOrder QoS value</fsummary> + <desc> + <p>This function returns the AnyOrder QoS value.</p> + </desc> + </func> + <func> + <name>'FifoOrder'() -> short()</name> + <fsummary>Return the FifoOrder QoS value</fsummary> + <desc> + <p>This function returns the FifoOrder QoS value.</p> + </desc> + </func> + <func> + <name>'PriorityOrder'() -> short()</name> + <fsummary>Return the PriorityOrder QoS value</fsummary> + <desc> + <p>This function returns the PriorityOrder QoS value.</p> + </desc> + </func> + <func> + <name>'DeadlineOrder'() -> short()</name> + <fsummary>Return the DeadlineOrder QoS value</fsummary> + <desc> + <p>This function returns the DeadlineOrder QoS value.</p> + </desc> + </func> + <func> + <name>'DiscardPolicy'() -> string()</name> + <fsummary>Return the DiscardPolicy QoS identifier</fsummary> + <desc> + <p>This function returns the DiscardPolicy QoS identifier.</p> + </desc> + </func> + <func> + <name>'LifoOrder'() -> short()</name> + <fsummary>Return the LifoOrder QoS value</fsummary> + <desc> + <p>This function returns the LifoOrder QoS value.</p> + </desc> + </func> + <func> + <name>'RejectNewEvents'() -> short()</name> + <fsummary>Return the RejectNewEvents QoS value</fsummary> + <desc> + <p>This function returns the RejectNewEvents QoS value.</p> + </desc> + </func> + <func> + <name>'MaximumBatchSize'() -> string()</name> + <fsummary>Return the MaximumBatchSize QoS identifier</fsummary> + <desc> + <p>This function returns the MaximumBatchSize QoS identifier.</p> + </desc> + </func> + <func> + <name>'PacingInterval'() -> string()</name> + <fsummary>Return the PacingInterval QoS identifier</fsummary> + <desc> + <p>This function returns the PacingInterval QoS identifier.</p> + </desc> + </func> + <func> + <name>'StartTimeSupported'() -> string()</name> + <fsummary>Return the StartTimeSupported QoS identifier</fsummary> + <desc> + <p>This function returns the StartTimeSupported QoS identifier.</p> + </desc> + </func> + <func> + <name>'StopTimeSupported'() -> string()</name> + <fsummary>Return the StopTimeSupported QoS identifier</fsummary> + <desc> + <p>This function returns the StopTimeSupported QoS identifier.</p> + </desc> + </func> + <func> + <name>'MaxEventsPerConsumer'() -> string()</name> + <fsummary>Return the MaxEventsPerConsumer QoS identifier</fsummary> + <desc> + <p>This function returns the MaxEventsPerConsumer QoS identifier.</p> + </desc> + </func> + <func> + <name>'MaxQueueLength'() -> string()</name> + <fsummary>Return the MaxQueueLength Admin identifier</fsummary> + <desc> + <p>This function returns the MaxQueueLength Admin identifier.</p> + </desc> + </func> + <func> + <name>'MaxConsumers'() -> string()</name> + <fsummary>Return the MaxConsumers Admin identifier</fsummary> + <desc> + <p>This function returns the MaxConsumers Admin identifier.</p> + </desc> + </func> + <func> + <name>'MaxSuppliers'() -> string()</name> + <fsummary>Return the MaxSuppliers Admin identifier</fsummary> + <desc> + <p>This function returns the MaxSuppliers Admin identifier.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotification_AdminPropertiesAdmin.xml b/lib/cosNotification/doc/src/CosNotification_AdminPropertiesAdmin.xml new file mode 100644 index 0000000000..6e2a102051 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotification_AdminPropertiesAdmin.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotification_­AdminPropertiesAdmin</title> + <shorttitle>..._AdminPropertiesAdmin</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotification_AdminPropertiesAdmin</module> + <modulesummary>This module implements the OMG CosNotification::AdminPropertiesAdmin interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>All objects, which inherit this interface, export functions described in this module.</p> + </description> + <funcs> + <func> + <name>get_admin(Object) -> AdminProperties</name> + <fsummary>Return a list of <c>AdminProperties</c>associated with the target object</fsummary> + <type> + <v>Object = #objref</v> + <v>AdminProperties = [AdminProperty]</v> + <v>AdminProperty = #'CosNotification_Property'{name, value}</v> + <v>name = string()</v> + <v>value = #any</v> + </type> + <desc> + <p>This operation returns sequence of name-value pairs which encapsulates the + current administrative properties of the target object.</p> + </desc> + </func> + <func> + <name>set_admin(Object, AdminProperties) -> Reply</name> + <fsummary>Update the <c>AdminProperties</c>for the target object</fsummary> + <type> + <v>Object = #objref</v> + <v>AdminProperties = [AdminProperty]</v> + <v>AdminProperty = #'CosNotification_Property'{name, value}</v> + <v>name = string()</v> + <v>value = #any</v> + <v>Reply = ok | {'EXCEPTION', CosNotification_UnsupportedAdmin}</v> + </type> + <desc> + <p>As input, this operation accepts a sequence of name-value pairs encapsulating the + desired administrative settings for the target object. If it is not possible to + set the given properties the exception <c>UnsupportedAdmin</c> will be raised.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotification_QoSAdmin.xml b/lib/cosNotification/doc/src/CosNotification_QoSAdmin.xml new file mode 100644 index 0000000000..b7c19f664b --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotification_QoSAdmin.xml @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>CosNotification_QoSAdmin</title> + <prepared></prepared> + <docno></docno> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotification_QoSAdmin</module> + <modulesummary>This module implements the OMG CosNotification::QoSAdmin interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>All objects, which inherit this interface, export functions described in this module.</p> + </description> + <funcs> + <func> + <name>get_qos(Object) -> Reply</name> + <fsummary>Return a list of name-value pairs which encapsulates the current QoS settings for the target object</fsummary> + <type> + <v>Object = #objref</v> + <v>Reply = [QoSProperty]</v> + <v>QoSProperty = #'CosNotification_Property'{name, value}</v> + <v>name = string()</v> + <v>value = #any</v> + </type> + <desc> + <p>This operation returns a list of name-value pairs which encapsulates the current QoS settings + for the target object.</p> + </desc> + </func> + <func> + <name>set_qos(Object, QoS) -> Reply</name> + <fsummary>Change the QoS settings for the target object</fsummary> + <type> + <v>Object = #objref</v> + <v>QoS = [QoSProperty]</v> + <v>QoSProperty = #'CosNotification_Property'{name, value}</v> + <v>name = string()</v> + <v>value = #any</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotification_UnsupportedQoS'{qos_err}}</v> + <v>qos_err = PropertyErrorSeq</v> + <v>PropertyErrorSeq = [PropertyError]</v> + <v>PropertyError = #'CosNotification_PropertyError'{code, name, available_range}</v> + <v>code = 'UNSUPPORTED_PROPERTY' | 'UNAVAILABLE_PROPERTY' | 'UNSUPPORTED_VALUE' | 'UNAVAILABLE_VALUE' | 'BAD_PROPERTY' | 'BAD_TYPE' | 'BAD_VALUE'</v> + <v>name = string()</v> + <v>available_range = PropertyRange</v> + <v>PropertyRange = #CosNotification_PropertyRange{low_val, high_val}</v> + <v>low_val = high_val = #any</v> + </type> + <desc> + <p>To alter the current QoS settings for the target object this function must be used. + If it is not possible to set the requested QoS the <c>UnsupportedQoS</c> + exception is raised, which includes a sequence of <c>PropertyError</c>'s + describing which QoS, possible range and why is not allowed.</p> + </desc> + </func> + <func> + <name>validate_qos(Object, QoS) -> Reply</name> + <fsummary>Validate if the supplied QoS properties is valid for the target object </fsummary> + <type> + <v>Object = #objref</v> + <v>QoS = [QoSProperty]</v> + <v>QoSProperty = #'Property'{name, value}</v> + <v>name = string()</v> + <v>value = #any</v> + <v>Reply = {ok, NamedPropertyRangeSeq} | {'EXCEPTION', CosNotification_UnsupportedQoS{}}</v> + <v>NamedPropertyRangeSeq = [NamedPropertyRange]</v> + <v>NamedPropertyRange = #CosNotification_NamedPropertyRange{name, range}</v> + <v>name = string()</v> + <v>range = #CosNotification_PropertyRange{low_val, high_val}</v> + <v>low_val = #any</v> + <v>high_val = #any</v> + </type> + <desc> + <p>The purpose of this operations is to check if a QoS setting is supported + by the target object and if so, the operation returns additional properties + which could be optionally added as well.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ConsumerAdmin.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ConsumerAdmin.xml new file mode 100644 index 0000000000..2cdb2d54a8 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ConsumerAdmin.xml @@ -0,0 +1,242 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyChannelAdmin_­ConsumerAdmin</title> + <shorttitle>..._ConsumerAdmin</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_ConsumerAdmin</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::ConsumerAdmin interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifySubscribe</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>_get_MyID(ConsumerAdmin) -> AdminID</name> + <fsummary>Return the target object's Id</fsummary> + <type> + <v>ConsumerAdmin = #objref</v> + <v>AdminID = long()</v> + </type> + <desc> + <p>The ID returned by the creating channel is equal to the value encapsulated by + this readonly attribute.</p> + </desc> + </func> + <func> + <name>_get_MyChannel(ConsumerAdmin) -> Channel</name> + <fsummary>Return the ancestor channel</fsummary> + <type> + <v>ConsumerAdmin = #objref</v> + <v>Channel = #objref</v> + </type> + <desc> + <p>The creating channel's reference is maintained by this readonly attribute.</p> + </desc> + </func> + <func> + <name>_get_MyOperator(ConsumerAdmin) -> OpType</name> + <fsummary>Return the filtering schema used by the target object</fsummary> + <type> + <v>ConsumerAdmin = #objref</v> + <v>OpType = 'AND_OP' | 'OR_OP'</v> + </type> + <desc> + <p>When <c>ConsumerAdmin's</c> are created an operation type, + i.e., <c>'AND_OP'</c> or <c>'OR_OP'</c>, is supplied, which determines + the semantics used by the target object concerning evaluation against + any associated <c>Filter</c> objects.</p> + </desc> + </func> + <func> + <name>_get_priority_filter(ConsumerAdmin) -> MappingFilter</name> + <fsummary>Return the associated priority <c>MappingFilter</c></fsummary> + <type> + <v>ConsumerAdmin = MappingFilter = #objref</v> + </type> + <desc> + <p>If set, this operation returns the associated priority <c>MappingFilter</c>, otherwise + a <c>NIL</c> object reference is returned.</p> + </desc> + </func> + <func> + <name>_set_priority_filter(ConsumerAdmin, MappingFilter) -> ok</name> + <fsummary>Set the priority <c>MappingFilter</c></fsummary> + <type> + <v>ConsumerAdmin = MappingFilter = #objref</v> + </type> + <desc> + <p>To associate a priority <c>MappingFilter</c> with the target object this operation + must be used.</p> + </desc> + </func> + <func> + <name>_get_lifetime_filter(ConsumerAdmin) -> MappingFilter</name> + <fsummary>Return the associated lifetime <c>MappingFilter</c></fsummary> + <type> + <v>ConsumerAdmin = MappingFilter = #objref</v> + </type> + <desc> + <p>Unless a lifetime <c>MappingFilter</c> have been associated with the target object + a <c>NIL</c> object reference is returned by this operation.</p> + </desc> + </func> + <func> + <name>_set_lifetime_filter(ConsumerAdmin, MappingFilter) -> ok</name> + <fsummary>Set the lifetime <c>MappingFilter</c></fsummary> + <type> + <v>ConsumerAdmin = MappingFilter = #objref</v> + </type> + <desc> + <p>This operation associate a lifetime <c>MappingFilter</c> with the target object.</p> + </desc> + </func> + <func> + <name>_get_pull_suppliers(ConsumerAdmin) -> ProxyIDSeq</name> + <fsummary>Return a list of all associated pull supplier Id:s</fsummary> + <type> + <v>ConsumerAdmin = #objref</v> + <v>ProxyIDSeq = [ProxyID]</v> + <v>ProxyID = long()</v> + </type> + <desc> + <p>This readonly attribute maintains the Id's for all <c>PullProxies</c> created + by the target object and still alive.</p> + </desc> + </func> + <func> + <name>_get_push_suppliers(ConsumerAdmin) -> ProxyIDSeq</name> + <fsummary>Return a list of all associated push supplier Id:s</fsummary> + <type> + <v>ConsumerAdmin = #objref</v> + <v>ProxyIDSeq = [ProxyID]</v> + <v>ProxyID = long()</v> + </type> + <desc> + <p>This attribute is similar to the <c>_get_pull_suppliers</c> attribute but maintains + the Id's for all <c>PushProxies</c> created by the target object and still alive.</p> + </desc> + </func> + <func> + <name>get_proxy_supplier(ConsumerAdmin, ProxyID) -> Reply</name> + <fsummary>Return the proxy supplier with matching Id</fsummary> + <type> + <v>ConsumerAdmin = #objref</v> + <v>ProxyID = long()</v> + <v>Reply = Proxy | {'EXCEPTION', #'CosNotifyChannelAdmin_ProxyNotFound'{}}</v> + <v>Proxy = #objref</v> + </type> + <desc> + <p>If a proxy with the given Id exists the reference to the object is returned, but if + the object have terminated, or an incorrect Id is supplied, an exception is raised.</p> + </desc> + </func> + <func> + <name>obtain_notification_pull_supplier(ConsumerAdmin, ConsumerType) -> Reply</name> + <fsummary>Create a supplier proxy</fsummary> + <type> + <v>ConsumerAdmin = #objref</v> + <v>ConsumerType = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'</v> + <v>Reply = {Proxy, ProxyID}</v> + <v>Proxy = #objref</v> + <v>ProxyID = long()</v> + </type> + <desc> + <p>Determined by the parameter <c>ConsumerType</c>, a proxy which will + accept events of the defined type is created. Along with the object reference an + Id is returned. </p> + </desc> + </func> + <func> + <name>obtain_pull_supplier(ConsumerAdmin) -> Proxy</name> + <fsummary>Create a supplier proxy</fsummary> + <type> + <v>ConsumerAdmin = #objref</v> + <v>Proxy = #objref</v> + </type> + <desc> + <p>This operation creates a new proxy which accepts <c>#any{}</c> events.</p> + </desc> + </func> + <func> + <name>obtain_notification_push_supplier(ConsumerAdmin, ConsumerType) -> Reply</name> + <fsummary>Create a supplier proxy</fsummary> + <type> + <v>ConsumerAdmin = #objref</v> + <v>ConsumerType = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'</v> + <v>Reply = {Proxy, ProxyID}</v> + <v>Proxy = #objref</v> + <v>ProxyID = long()</v> + </type> + <desc> + <p>A proxy which accepts events of the type described by the parameter <c>ConsumerType</c> + is created by this operation. A unique Id is returned as an out parameter.</p> + </desc> + </func> + <func> + <name>obtain_push_supplier(ConsumerAdmin) -> Proxy</name> + <fsummary>Create a supplier proxy</fsummary> + <type> + <v>ConsumerAdmin = #objref</v> + <v>Proxy = #objref</v> + </type> + <desc> + <p>The object created by this function is a proxy which accepts <c>#any{}</c> events.</p> + </desc> + </func> + <func> + <name>destroy(ConsumerAdmin) -> ok</name> + <fsummary>Terminate the target object and all its children</fsummary> + <type> + <v>ConsumerAdmin = #objref</v> + </type> + <desc> + <p>To terminate the target object this operation should be used. The associated + <c>Channel</c> will be notified.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannel.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannel.xml new file mode 100644 index 0000000000..b6af2e2ca3 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannel.xml @@ -0,0 +1,226 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>CosNotifyChannelAdmin_­EventChannel</title> + <shorttitle>..._EventChannel</shorttitle> + <prepared></prepared> + <docno></docno> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_EventChannel</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::EventChannel interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotification_AdminPropertiesAdmin">CosNotification_AdminPropertiesAdmin</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>_get_MyFactory(Channel) -> ChannelFactory</name> + <fsummary>Return the factory object which created the target object</fsummary> + <type> + <v>Channel = #objref</v> + <v>ChannelFactory = #objref</v> + </type> + <desc> + <p>This readonly attribute maintains the reference of the event channel + factory that created the target channel.</p> + </desc> + </func> + <func> + <name>_get_default_consumer_admin(Channel) -> ConsumerAdmin</name> + <fsummary>Return the default consumer admin associated with the target object</fsummary> + <type> + <v>Channel = #objref</v> + <v>ConsumerAdmin = #objref</v> + </type> + <desc> + <p>This is a readonly attribute which maintains a reference to a default + <c>ConsumerAdmin</c> object associated with the target object.</p> + </desc> + </func> + <func> + <name>_get_default_supplier_admin(Channel) -> SupplierAdmin</name> + <fsummary>Return the default supplier admin associated with the target object</fsummary> + <type> + <v>Channel = #objref</v> + <v>SupplierAdmin = #objref</v> + </type> + <desc> + <p>This is a readonly attribute which maintains a reference to a default + <c>SupplierAdmin</c> object associated with the target object.</p> + </desc> + </func> + <func> + <name>_get_default_filter_factory(Channel) -> FilterFactory</name> + <fsummary>Return the default filter factory associated with the target object</fsummary> + <type> + <v>Channel = #objref</v> + <v>FilterFactory = #objref</v> + </type> + <desc> + <p>The default <c>FilterFactory</c> associated with the target channel + is maintained by this readonly attribute.</p> + </desc> + </func> + <func> + <name>new_for_consumers(Channel, OpType) -> Return</name> + <fsummary>Create a new <c>ConsumerAdmin</c>object</fsummary> + <type> + <v>Channel = #objref</v> + <v>OpType = 'AND_OP' | 'OR_OP'</v> + <v>Return = {ConsumerAdmin, AdminID}</v> + <v>ConsumerAdmin = #objref</v> + <v>AdminID = long()</v> + </type> + <desc> + <p>This operation creates a new instance of a <c>ConsumerAdmin</c> and supplies + an Id which may be used when invoking other operations exported by this module. + The returned object will inherit the Quality of Service properties of the + target channel.</p> + </desc> + </func> + <func> + <name>for_consumers(Channel) -> ConsumerAdmin</name> + <fsummary>Create a new <c>ConsumerAdmin</c>object</fsummary> + <type> + <v>Channel = #objref</v> + <v>ConsumerAdmin = #objref</v> + </type> + <desc> + <p>A new new instance of a <c>ConsumerAdmin</c> object is created but no + Id is returned. The returned object's operation type, i.e., <c>'AND_OP'</c> or <c>'OR_OP'</c>, + will be set to the value of the configuration parameter <c>filterOp</c>. + The target object's Quality of Service properties will be inherited by the + returned <c>ConsumerAdmin</c>.</p> + </desc> + </func> + <func> + <name>new_for_suppliers(Channel, OpType) -> Return</name> + <fsummary>Create a new <c>SupplierAdmin</c>object</fsummary> + <type> + <v>Channel = #objref</v> + <v>OpType = 'AND_OP' | 'OR_OP'</v> + <v>Return = {SupplierAdmin, AdminID}</v> + <v>SupplierAdmin = #objref</v> + <v>AdminID = long()</v> + </type> + <desc> + <p>Enables us to create a new instance of a <c>SupplierAdmin</c>. An Id, which + may be used when invoking other operations exported by this module, is also + returned. The current Quality of Service settings associated with the target + object will be inherited by the <c>SupplierAdmin</c>.</p> + </desc> + </func> + <func> + <name>for_suppliers(Channel) -> SupplierAdmin</name> + <fsummary>Create a new <c>SupplierAdmin</c>object</fsummary> + <type> + <v>Channel = #objref</v> + <v>SupplierAdmin = #objref</v> + </type> + <desc> + <p>To create a new <c>SupplierAdmin</c> with the target object's current + Quality of Service settings we can use this function. The returned object's + operation type (<c>'AND_OP'</c> or <c>'OR_OP'</c>) will be determined by the + configuration variable <c>filterOp</c>.</p> + </desc> + </func> + <func> + <name>get_consumeradmin(Channel, AdminID) -> ConsumerAdmin</name> + <fsummary>Return the <c>ConsumerAdmin</c>matching AdminID</fsummary> + <type> + <v>Channel = #objref</v> + <v>AdminID = long()</v> + <v>ConsumerAdmin = #objref | {'EXCEPTION', #'CosNotifyChannelAdmin_AdminNotFound'{}}</v> + </type> + <desc> + <p>If the given Id is associated with a <c>ConsumerAdmin</c> the object reference + is returned. If such association never existed or the <c>ConsumerAdmin</c> + have terminated an exception is raised.</p> + </desc> + </func> + <func> + <name>get_supplieradmin(Channel, AdminID) -> SupplierAdmin</name> + <fsummary>Return the <c>SupplierAdmin</c>matching AdminID</fsummary> + <type> + <v>Channel = #objref</v> + <v>AdminID = long()</v> + <v>SupplierAdmin = #objref | {'EXCEPTION', #'CosNotifyChannelAdmin_AdminNotFound'{}}</v> + </type> + <desc> + <p>Equal to the operation <c>get_consumeradmin/2</c> but a reference to + a <c>SupplierAdmin</c> is returned.</p> + </desc> + </func> + <func> + <name>get_all_consumeradmins(Channel) -> Reply</name> + <fsummary>Return a list of all <c>ConsumerAdmins</c>, currently active, Id:s</fsummary> + <type> + <v>Channel = #objref</v> + <v>Reply = [AdminID]</v> + <v>AdminID = long()</v> + </type> + <desc> + <p>To get access to all <c>ConsumerAdmin</c> Id's created by the target object, and still + alive, this operation could be invoked.</p> + </desc> + </func> + <func> + <name>get_all_supplieradmins(Channel) -> Reply</name> + <fsummary>Return a list of all <c>SupplierAdmins</c>, currently active, Id:s</fsummary> + <type> + <v>Channel = #objref</v> + <v>Reply = [AdminID]</v> + <v>AdminID = long()</v> + </type> + <desc> + <p>Equal to the operation <c>get_all_consumeradmins/1</c> but returns + a list of all <c>SupplierAdmin</c> object ID's.</p> + </desc> + </func> + <func> + <name>destroy(Channel) -> ok</name> + <fsummary>Terminate the channel and all its children</fsummary> + <type> + <v>Channel = #objref</v> + </type> + <desc> + <p>The <c>destroy</c> operation will terminate the target channel and + all associated Admin objects.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannelFactory.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannelFactory.xml new file mode 100644 index 0000000000..01976954e7 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannelFactory.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>CosNotifyChannelAdmin_­EventChannelFactory</title> + <shorttitle>..._EventChannelFactory</shorttitle> + <prepared></prepared> + <docno></docno> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_EventChannelFactory</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::EventChannelFactory interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + </description> + <funcs> + <func> + <name>create_channel(ChannelFactory, InitialQoS, InitialAdmin) -> Return</name> + <fsummary>Create a new channel</fsummary> + <type> + <v>ChannelFactory = #objref</v> + <v>InitialQoS = CosNotification::QoSProperties</v> + <v>InitialAdmin = CosNotification::AdminProperties</v> + <v>Return = {EventChannel, ChannelID}</v> + <v>EventChannel = #objref</v> + <v>ChannelID = long()</v> + </type> + <desc> + <p>This operation creates a new event channel. Along with the channel + reference an id is returned which can be used when invoking other + operations exported by this module. The Quality of Service argument + supplied will be inherited by objects created by the channel. For more + information about QoS settings see the <c>User's Guide</c>.</p> + <p>If no QoS- and/or Admin-properties are supplied (i.e. empty list), + the <em>default</em> settings will be used. For more information, see the + User's Guide.</p> + </desc> + </func> + <func> + <name>get_all_channels(ChannelFactory) -> ChannelIDSeq</name> + <fsummary>Return all Id:s for channels, currently alive, created by the target object</fsummary> + <type> + <v>ChannelFactory = #objref</v> + <v>ChannelIDSeq = [long()]</v> + </type> + <desc> + <p>This operation returns a id sequence of all channel's created by this ChannelFactory.</p> + </desc> + </func> + <func> + <name>get_event_channel(ChannelFactory, ChannelID) -> Return</name> + <fsummary>Return the channel object associated with the given Id</fsummary> + <type> + <v>ChannelFactory = #objref</v> + <v>ChannelID = long()</v> + <v>Retrurn = EventChannel | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v> + <v>EventChannel = #objref</v> + </type> + <desc> + <p>This operation returns the EventChannel associated with the given id. If no channel is + associated with the id, i.e., never existed or have been terminated, an exception is raised.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyConsumer.xml new file mode 100644 index 0000000000..69b1e78b82 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyConsumer.xml @@ -0,0 +1,128 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyChannelAdmin_­ProxyConsumer</title> + <shorttitle>..._ProxyConsumer</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_ProxyConsumer</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::ProxyConsumer interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>_get_MyType(ProxyConsumer) -> ProxyType</name> + <fsummary>Return the proxy type</fsummary> + <type> + <v>ProxyConsumer = #objref</v> + <v>ProxyType = 'PUSH_ANY' | 'PULL_ANY' | 'PUSH_STRUCTURED' | 'PULL_STRUCTURED' | 'PUSH_SEQUENCE' | 'PULL_SEQUENCE'</v> + </type> + <desc> + <p>This readonly attribute maintains the enumerant describing the which type the target object + is. </p> + </desc> + </func> + <func> + <name>_get_MyAdmin(ProxyConsumer) -> AdminObject</name> + <fsummary>return the associated <c>Admin</c>object</fsummary> + <type> + <v>ProxyConsumer = AdminObject = #objref</v> + </type> + <desc> + <p>This readonly attribute maintains the admin's reference which created the target object.</p> + </desc> + </func> + <func> + <name>obtain_subscription_types(ProxyConsumer, ObtainInfoMode) -> EventTypeSeq</name> + <fsummary>Administer subscription types</fsummary> + <type> + <v>ProxyConsumer = #objref</v> + <v>ObtainInfoMode = 'ALL_NOW_UPDATES_OFF' | 'ALL_NOW_UPDATES_ON' | 'NONE_NOW_UPDATES_OFF' | 'NONE_NOW_UPDATES_ON'</v> + <v>EventTypeSeq = [EventType]</v> + <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v> + <v>domain_name = type_name = string()</v> + </type> + <desc> + <p>Depending on the input parameter <c>ObtainInfoMode</c>, this operation may return a + sequence of the <c>EventTypes</c> the target object is interested in receiving. + If <c>'ALL_NOW_UPDATES_OFF'</c> or <c>'ALL_NOW_UPDATES_ON'</c> is given a sequence will + be returned, otherwise not. If <c>'ALL_NOW_UPDATES_OFF'</c> or <c>'NONE_NOW_UPDATES_OFF'</c> + are issued the target object will not inform the associated <c>NotifySubscribe</c> object + when an update occurs. <c>'ALL_NOW_UPDATES_ON'</c> or <c>'NONE_NOW_UPDATES_ON'</c> will + result in that update information will be sent.</p> + </desc> + </func> + <func> + <name>validate_event_qos(ProxyConsumer, QoSProperties) -> Reply</name> + <fsummary>Check if certain Quality of Service properties can be added to events in the current context of the target object</fsummary> + <type> + <v>ProxyConsumer = #objref</v> + <v>QoSProperties = [QoSProperty]</v> + <v>QoSProperty = #'CosNotification_Property'{name, value}</v> + <v>name = string()</v> + <v>value = #any</v> + <v>Reply = {ok, NamedPropertyRangeSeq} | {'EXCEPTION', CosNotification_UnsupportedQoS{qos_err}}</v> + <v>NamedPropertyRangeSeq = [NamedPropertyRange]</v> + <v>NamedPropertyRange = #CosNotification_NamedPropertyRange{name, range}</v> + <v>name = string()</v> + <v>range = #CosNotification_PropertyRange{low_val, high_val}</v> + <v>low_val = #any</v> + <v>high_val = #any</v> + <v>qos_err = PropertyErrorSeq</v> + <v>PropertyErrorSeq = [PropertyError]</v> + <v>PropertyError = #'CosNotification_PropertyError'{code, name, available_range}</v> + <v>code = 'UNSUPPORTED_PROPERTY' | 'UNAVAILABLE_PROPERTY' | 'UNSUPPORTED_VALUE' | 'UNAVAILABLE_VALUE' | 'BAD_PROPERTY' | 'BAD_TYPE' | 'BAD_VALUE'</v> + <v>name = string()</v> + <v>available_range = PropertyRange</v> + <v>PropertyRange = #CosNotification_PropertyRange{low_val, high_val}</v> + <v>low_val = high_val = #any</v> + </type> + <desc> + <p>To check if certain Quality of Service properties can be added to events in + the current context of the target object this operation should be used. If we + cannot support the required settings an exception describing why will be raised.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullConsumer.xml new file mode 100644 index 0000000000..29dc59871d --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullConsumer.xml @@ -0,0 +1,113 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyChannelAdmin_­ProxyPullConsumer</title> + <shorttitle>..._ProxyPullConsumer</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_ProxyPullConsumer</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::ProxyPullConsumer interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotifyComm_NotifyPublish">CosNotifyComm_NotifyPublish</seealso></p> + </item> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyChannelAdmin_ProxyConsumer">CosNotifyChannelAdmin_ProxyConsumer</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>connect_any_pull_supplier(ProxyPullConsumer, PullSupplier) -> Reply</name> + <fsummary>Connect a supplier to the proxy</fsummary> + <type> + <v>ProxyPullConsumer = #objref</v> + <v>PullSupplier = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}}</v> + </type> + <desc> + <p>This operation connects the given <c>PullSupplier</c> to the target object. + If a client is already connected the <c>AlreadyConnected</c> exception + will be raised. The client must support the operations <c>pull</c> and + <c>try_pull</c>, otherwise the <c>TypeError</c> exception is raised.</p> + </desc> + </func> + <func> + <name>suspend_connection(ProxyPullConsumer) -> Reply</name> + <fsummary>Suspend the connection between the client and the proxy</fsummary> + <type> + <v>ProxyPullConsumer = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v> + </type> + <desc> + <p>If we want to temporarily suspend the connection with the target object this + operation must be sued. If the connection already have been suspended or + no client have been connected an exception is raised.</p> + </desc> + </func> + <func> + <name>resume_connection(ProxyPullConsumer) -> Reply</name> + <fsummary>Resume a previously suspended connection with the proxy</fsummary> + <type> + <v>ProxyPullConsumer = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyActive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v> + </type> + <desc> + <p>If The connection have been suspended earlier we can invoke this operation to + reinstate the connection. If the connection already is active or no client + have been connected to the target object an exception is raised.</p> + </desc> + </func> + <func> + <name>disconnect_pull_consumer(ProxyPullConsumer) -> ok</name> + <fsummary>Close the connection and terminate the proxy</fsummary> + <type> + <v>ProxyPullConsumer = #objref</v> + </type> + <desc> + <p>Invoking this operation disconnects the client from the target object which + then terminates and inform its administrative parent.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullSupplier.xml new file mode 100644 index 0000000000..daa0f3cc49 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullSupplier.xml @@ -0,0 +1,112 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyChannelAdmin_­ProxyPullSupplier</title> + <shorttitle>..._ProxyPullSupplier</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_ProxyPullSupplier</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::ProxyPullSupplier interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifySubscribe</seealso></p> + </item> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyChannelAdmin_ProxySupplier">CosNotifyChannelAdmin_ProxySupplier</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>connect_any_pull_consumer(ProxyPullSupplier, PullConsumer) -> Reply</name> + <fsummary>Connect a consumer to the proxy</fsummary> + <type> + <v>ProxyPullSupplier = #objref</v> + <v>PullConsumer = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}}</v> + </type> + <desc> + <p>This operation connects the given <c>PullConsumer</c> to the target object. + If a connection already exists the <c>AlreadyConnected</c> exception is + raised.</p> + </desc> + </func> + <func> + <name>pull(ProxyPullSupplier) -> Reply</name> + <fsummary>Pull an Any event from the proxy</fsummary> + <type> + <v>ProxyPullSupplier = #objref</v> + <v>Reply = #any | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v> + </type> + <desc> + <p>This operation pulls next <c>#any{}</c> event, and blocks, if the target object + have no events to forward, until an event can be delivered. If no client have + been connected the <c>Disconnected</c> exception is raised.</p> + </desc> + </func> + <func> + <name>try_pull(ProxyPullSupplier) -> Reply</name> + <fsummary>Try and pull an Any event from the proxy</fsummary> + <type> + <v>ProxyPullSupplier = #objref</v> + <v>Reply = {#any, HasEvent} | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v> + <v>HasEvent = boolean()</v> + </type> + <desc> + <p>This operation pulls next event, but do not block if the target object + have no event to forward. If no client have + been connected the <c>Disconnected</c> exception is raised.</p> + </desc> + </func> + <func> + <name>disconnect_pull_supplier(ProxyPullSupplier) -> ok</name> + <fsummary>Close the connection and terminate the proxy</fsummary> + <type> + <v>ProxyPullSupplier = #objref</v> + </type> + <desc> + <p>Invoking this operation will cause the target object to close the connection and terminate.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushConsumer.xml new file mode 100644 index 0000000000..63d3f53101 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushConsumer.xml @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyChannelAdmin_­ProxyPushConsumer</title> + <shorttitle>..._ProxyPushConsumer</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_ProxyPushConsumer</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::ProxyPushConsumer interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotifyComm_NotifyPublish">CosNotifyComm_NotifyPublish</seealso></p> + </item> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyChannelAdmin_ProxyConsumer">CosNotifyChannelAdmin_ProxyConsumer</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>connect_any_push_supplier(ProxyPushConsumer, PushSupplier) -> Reply</name> + <fsummary>Connect a supplier to the proxy</fsummary> + <type> + <v>ProxyPushConsumer = #objref</v> + <v>PushSupplier = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}}</v> + </type> + <desc> + <p>This operation connects a <c>PushSupplier</c> to the target object. If + a connection already exists the <c>AlreadyConnected</c> exception is raised.</p> + </desc> + </func> + <func> + <name>push(ProxyPushConsumer, Event) -> Reply</name> + <fsummary>Push an Any event to the proxy</fsummary> + <type> + <v>ProxyPushConsumer = #objref</v> + <v>Event = #any</v> + <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v> + </type> + <desc> + <p>This operation pushes an <c>#any{}</c> event to the target object. If no client + have been connected the <c>Disconnected</c> exception is raised.</p> + </desc> + </func> + <func> + <name>disconnect_push_consumer(ProxyPushConsumer) -> ok</name> + <fsummary>Close the connection and terminate the proxy</fsummary> + <type> + <v>ProxyPushConsumer = #objref</v> + </type> + <desc> + <p>Invoking this operation will cause the target object to close the connection and + terminate.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushSupplier.xml new file mode 100644 index 0000000000..54d100c353 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushSupplier.xml @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyChannelAdmin_­ProxyPushSupplier</title> + <shorttitle>..._ProxyPushSupplier</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_ProxyPushSupplier</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::ProxyPushSupplier interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifySubscribe</seealso></p> + </item> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmi</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyChannelAdmin_ProxySupplier">CosNotifyChannelAdmin_ProxySupplier</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>connect_any_push_consumer(ProxyPushSupplier, PushConsumer) -> Reply</name> + <fsummary>Connect a consumer to the proxy</fsummary> + <type> + <v>ProxyPushSupplier = #objref</v> + <v>PushConsumer = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}}</v> + </type> + <desc> + <p>This operation connects a <c>PushConsumer</c> to the target object. If + a connection already exists or the given client does not support + the operation <c>push</c> an exception, <c>AlreadyConnected</c> and + <c>TypeError</c> respectively, is raised.</p> + </desc> + </func> + <func> + <name>suspend_connection(ProxyPushSupplier) -> Reply</name> + <fsummary>Suspend the connection between the proxy and the client</fsummary> + <type> + <v>ProxyPushSupplier = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v> + </type> + <desc> + <p>This operation suspends the connection with the client object. If the connection + already is suspended or no client have been associated an exception is raised.</p> + </desc> + </func> + <func> + <name>resume_connection(ProxyPushSupplier) -> Reply</name> + <fsummary>Resume a previously suspended connection with the proxy</fsummary> + <type> + <v>ProxyPullConsumer = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v> + </type> + <desc> + <p>If a connection have been suspended earlier, calling this operation will resume the connection. + If the connection already is active or no client have been connected an exception is raised.</p> + </desc> + </func> + <func> + <name>disconnect_push_supplier(ProxyPushSupplier) -> ok</name> + <fsummary>Close the connection and terminate the proxy</fsummary> + <type> + <v>ProxyPushSupplier = #objref</v> + </type> + <desc> + <p>This operation cause the target object to close the connection and terminate.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxySupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxySupplier.xml new file mode 100644 index 0000000000..daf2aab388 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxySupplier.xml @@ -0,0 +1,175 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyChannelAdmin_­ProxySupplier</title> + <shorttitle>..._ProxySupplier</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_ProxySupplier</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::ProxySupplier interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>_get_MyType(ProxySupplier) -> ProxyType</name> + <fsummary>Return the proxy type</fsummary> + <type> + <v>ProxySupplier = #objref</v> + <v>ProxyType = 'PUSH_ANY' | 'PULL_ANY' | 'PUSH_STRUCTURED' | 'PULL_STRUCTURED' | 'PUSH_SEQUENCE' | 'PULL_SEQUENCE'</v> + </type> + <desc> + <p>This readonly attribute maintains the enumerant describing the which type the target object + is.</p> + </desc> + </func> + <func> + <name>_get_MyAdmin(ProxySupplier) -> AdminObject</name> + <fsummary>Return the target object's associated <c>Admin</c>object</fsummary> + <type> + <v>ProxySupplier = #objref</v> + <v>AdminObject = #objref</v> + </type> + <desc> + <p>This readonly attribute maintains the admin's reference which created the target object.</p> + </desc> + </func> + <func> + <name>_get_priority_filter(ProxySupplier) -> MappingFilter</name> + <fsummary>Return the target object's associated priority <c>MappingFilter</c></fsummary> + <type> + <v>ProxySupplier = #objref</v> + <v>MappingFilter = #objref</v> + </type> + <desc> + <p>This operation returns the associated priority MappingFilter. + If no such object exist a <c>NIL</c> reference is returned.</p> + </desc> + </func> + <func> + <name>_set_priority_filter(ProxySupplier, MappingFilter) -> ok</name> + <fsummary>Set the target object's associated priority <c>MappingFilter</c></fsummary> + <type> + <v>ProxySupplier = #objref</v> + <v>MappingFilter = #objref</v> + </type> + <desc> + <p>This operation associate a new priority MappingFilter with the target object.</p> + </desc> + </func> + <func> + <name>_get_lifetime_filter(ProxySupplier) -> MappingFilter</name> + <fsummary>Return the target object's associated lifetime <c>MappingFilter</c></fsummary> + <type> + <v>ProxySupplier = #objref</v> + <v>MappingFilter = #objref</v> + </type> + <desc> + <p>This operation returns the associated lifetime MappingFilter. + If no such object exist a <c>NIL</c> reference is returned.</p> + </desc> + </func> + <func> + <name>_set_lifetime_filter(ProxySupplier, MappingFilter) -> ok</name> + <fsummary>Set the target object's associated lifetime <c>MappingFilter</c></fsummary> + <type> + <v>ProxySupplier = #objref</v> + <v>MappingFilter = #objref</v> + </type> + <desc> + <p>This operation associate a new lifetime MappingFilter with the target object.</p> + </desc> + </func> + <func> + <name>obtain_offered_types(ProxySupplier, ObtainInfoMode) -> EventTypeSeq</name> + <fsummary>Administer the type of events the proxy supplies</fsummary> + <type> + <v>ProxySupplier = #objref</v> + <v>ObtainInfoMode = 'ALL_NOW_UPDATES_OFF' | 'ALL_NOW_UPDATES_ON' | 'NONE_NOW_UPDATES_OFF' | 'NONE_NOW_UPDATES_ON'</v> + <v>EventTypeSeq = [EventType]</v> + <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v> + <v>domain_name = type_name = string()</v> + </type> + <desc> + <p>Depending on the input parameter <c>ObtainInfoMode</c>, this operation may return a + sequence of the <c>EventTypes</c> the target object is interested in receiving. + If <c>'ALL_NOW_UPDATES_OFF'</c> or <c>'ALL_NOW_UPDATES_ON'</c> is given a sequence will + be returned, otherwise not. If <c>'ALL_NOW_UPDATES_OFF'</c> or <c>'NONE_NOW_UPDATES_OFF'</c> + are issued the target object will not inform the associated <c>NotifySubscribe</c> object + when an update occurs. <c>'ALL_NOW_UPDATES_ON'</c> or <c>'NONE_NOW_UPDATES_ON'</c> will + result in that update information will be sent.</p> + </desc> + </func> + <func> + <name>validate_event_qos(ProxySupplier, QoSProperties) -> Reply</name> + <fsummary>Check if the QoS properties can be set</fsummary> + <type> + <v>ProxySupplier = #objref</v> + <v>QoSProperties = [QoSProperty]</v> + <v>QoSProperty = #'CosNotification_Property'{name, value}</v> + <v>name = string()</v> + <v>value = #any</v> + <v>Reply = {ok, NamedPropertyRangeSeq} | {'EXCEPTION', CosNotification_UnsupportedQoS{qos_err}}</v> + <v>NamedPropertyRangeSeq = [NamedPropertyRange]</v> + <v>NamedPropertyRange = #CosNotification_NamedPropertyRange{name, range}</v> + <v>name = string()</v> + <v>range = #CosNotification_PropertyRange{low_val, high_val}</v> + <v>low_val = #any</v> + <v>high_val = #any</v> + <v>qos_err = PropertyErrorSeq</v> + <v>PropertyErrorSeq = [PropertyError]</v> + <v>PropertyError = #'CosNotification_PropertyError'{code, name, available_range}</v> + <v>code = 'UNSUPPORTED_PROPERTY' | 'UNAVAILABLE_PROPERTY' | 'UNSUPPORTED_VALUE' | 'UNAVAILABLE_VALUE' | 'BAD_PROPERTY' | 'BAD_TYPE' | 'BAD_VALUE'</v> + <v>name = string()</v> + <v>available_range = PropertyRange</v> + <v>PropertyRange = #CosNotification_PropertyRange{low_val, high_val}</v> + <v>low_val = high_val = #any</v> + </type> + <desc> + <p>To check if certain Quality of Service properties can be added to events in + the current context of the target object this operation should be used. If we + cannot support the required settings an exception describing why will be raised.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml new file mode 100644 index 0000000000..aa9fae47df --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml @@ -0,0 +1,112 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyChannelAdmin_­SequenceProxyPullConsumer</title> + <shorttitle>..._SequenceProxyPullConsumer</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_SequenceProxyPullConsumer</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::SequenceProxyPullConsumer interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotifyComm_NotifyPublish">CosNotifyComm_NotifyPublish</seealso></p> + </item> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyChannelAdmin_ProxyConsumer">CosNotifyChannelAdmin_ProxyConsumer</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>connect_sequence_pull_supplier(SequenceProxyPullConsumer, PullSupplier) -> Reply</name> + <fsummary>Connect a supplier to the proxy</fsummary> + <type> + <v>SequenceProxyPullConsumer = #objref</v> + <v>PullSupplier = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}}</v> + </type> + <desc> + <p>This operation connects a <c>PullSupplier</c> to the target object. If a + connection already exists or the supplied client does not support the functions + <c>pull_structured_events</c> and <c>try_pull_structured_events</c> an exception + is raised.</p> + </desc> + </func> + <func> + <name>suspend_connection(SequenceProxyPullConsumer) -> Reply</name> + <fsummary>Suspend the connection with the proxy</fsummary> + <type> + <v>SequenceProxyPullConsumer = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v> + </type> + <desc> + <p>If a connection exist, invoking this operation will suspend the connection + until instructed otherwise. Otherwise, no client have been connected or this operation + already have been invoked an exception is raised.</p> + </desc> + </func> + <func> + <name>resume_connection(SequenceProxyPullConsumer) -> Reply</name> + <fsummary>Resume a previously suspended connection with the proxy</fsummary> + <type> + <v>SequenceProxyPullConsumer = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v> + </type> + <desc> + <p>If an connection have been suspended this operation must be used to resume the + connection. If the connection already is active or no client have been connected an + exception is raised.</p> + </desc> + </func> + <func> + <name>disconnect_sequence_pull_consumer(SequenceProxyPullConsumer) -> ok</name> + <fsummary>Close connection and terminate the proxy</fsummary> + <type> + <v>SequenceProxyPullConsumer = #objref</v> + </type> + <desc> + <p>This operation close the connection to the client and terminates the target object.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml new file mode 100644 index 0000000000..a46c53c9c1 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml @@ -0,0 +1,146 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyChannelAdmin_­SequenceProxyPullSupplier</title> + <shorttitle>..._SequenceProxyPullSupplier</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_SequenceProxyPullSupplier</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::SequenceProxyPullSupplier interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifySubscribe</seealso></p> + </item> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyChannelAdmin_ProxySupplier">CosNotifyChannelAdmin_ProxySupplier</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>connect_sequence_pull_consumer(SequenceProxyPullSupplier, PullConsumer) -> Reply</name> + <fsummary>Connect a consumer to the proxy</fsummary> + <type> + <v>SequenceProxyPullSupplier = #objref</v> + <v>PullConsumer = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}}</v> + </type> + <desc> + <p>This operation connects a <c>PullConsumer</c> to the target object. If a connection + already exists an exception is raised.</p> + </desc> + </func> + <func> + <name>pull_structured_events(SequenceProxyPullSupplier, MaxEvents) -> Reply</name> + <fsummary>Pull structured events from the proxy</fsummary> + <type> + <v>SequenceProxyPullSupplier = #objref</v> + <v>MaxEvents = long()</v> + <v>Reply = EventBatch | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v> + <v>EventBatch = [StructuredEvent]</v> + <v>StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body}</v> + <v>header = EventHeader</v> + <v>filterable_data = [#'CosNotification_Property'{name, value}]</v> + <v>name = string()</v> + <v>value = #any</v> + <v>remainder_of_body = #any</v> + <v>EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header}</v> + <v>fixed_header = FixedEventHeader</v> + <v>variable_header = OptionalHeaderFields</v> + <v>FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name}</v> + <v>event_type = EventType</v> + <v>event_name = string()</v> + <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v> + <v>domain_name = type_name = string()</v> + <v>OptionalHeaderFields = [#'CosNotification_Property'{name, value}]</v> + </type> + <desc> + <p>A client use this operation to pull next event sequence of maximum length + <c>MaxEvents</c>. This operation is blocking and will not reply until the + requested amount of events can be delivered or the QoS property <c>PacingInterval</c> + is reached. For more information see the <c>User's Guide</c>.</p> + </desc> + </func> + <func> + <name>try_pull_structured_events(SequenceProxyPullSupplier, MaxEvents) -> Reply</name> + <fsummary>Try to pull structured events from the proxy</fsummary> + <type> + <v>SequenceProxyPullSupplier = #objref</v> + <v>MaxEvents = long()</v> + <v>Reply = {EventBatch, HasEvent} | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v> + <v>HasEvent = boolean()</v> + <v>EventBatch = [StructuredEvent]</v> + <v>StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body}</v> + <v>header = EventHeader</v> + <v>filterable_data = [#'CosNotification_Property'{name, value}]</v> + <v>name = string()</v> + <v>value = #any</v> + <v>remainder_of_body = #any</v> + <v>EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header}</v> + <v>fixed_header = FixedEventHeader</v> + <v>variable_header = OptionalHeaderFields</v> + <v>FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name}</v> + <v>event_type = EventType</v> + <v>event_name = string()</v> + <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v> + <v>domain_name = type_name = string()</v> + <v>OptionalHeaderFields = [#'CosNotification_Property'{name, value}]</v> + </type> + <desc> + <p>This operation pulls an event sequence of the maximum length <c>MaxEvents</c>, + but do not block if the target object have no events to forward. The outparameter, + <c>HasEvent</c> is true if the sequence contain any events.</p> + </desc> + </func> + <func> + <name>disconnect_sequence_pull_supplier(SequenceProxyPullSupplier) -> ok</name> + <fsummary>Close the connection and terminate the proxy</fsummary> + <type> + <v>SequenceProxyPullSupplier = #objref</v> + </type> + <desc> + <p>This operation cause the target object to close the connection and terminate.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml new file mode 100644 index 0000000000..964d212715 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>CosNotifyChannelAdmin_­SequenceProxyPushConsumer</title> + <shorttitle>..._SequenceProxyPushConsumer</shorttitle> + <prepared></prepared> + <docno></docno> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_­SequenceProxyPushConsumer</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::SequenceProxyPushConsumer interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotifyComm_NotifyPublish">CosNotifyComm_NotifyPublish</seealso></p> + </item> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyChannelAdmin_ProxyConsumer">CosNotifyChannelAdmin_ProxyConsumer</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>connect_sequence_push_supplier(SequenceProxyPushConsumer, PushSupplier) -> Reply</name> + <fsummary>Connect a supplier to the proxy</fsummary> + <type> + <v>SequenceProxyPushConsumer = #objref</v> + <v>PushSupplier = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}}</v> + </type> + <desc> + <p>This operation connects a <c>PushSupplier</c> to the target object. If a + connection already exists the <c>AlreadyConnected</c> exception is raised.</p> + </desc> + </func> + <func> + <name>push_structured_events(SequenceProxyPushConsumer, EventBatch) -> Reply</name> + <fsummary>Push a structured event to the proxy</fsummary> + <type> + <v>SequenceProxyPushConsumer = #objref</v> + <v>EventBatch = [StructuredEvent]</v> + <v>StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body}</v> + <v>header = EventHeader</v> + <v>filterable_data = [#'CosNotification_Property'{name, value}]</v> + <v>name = string()</v> + <v>value = #any</v> + <v>remainder_of_body = #any</v> + <v>EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header}</v> + <v>fixed_header = FixedEventHeader</v> + <v>variable_header = OptionalHeaderFields</v> + <v>FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name}</v> + <v>event_type = EventType</v> + <v>event_name = string()</v> + <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v> + <v>domain_name = type_name = string()</v> + <v>OptionalHeaderFields = [#'CosNotification_Property'{name, value}]</v> + <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v> + </type> + <desc> + <p>A client must use this operation when it wishes to push a new sequence of events + to the target object. If no connection exists the <c>Disconnected</c> exception + is raised.</p> + </desc> + </func> + <func> + <name>disconnect_sequence_push_consumer(SequenceProxyPushConsumer) -> ok</name> + <fsummary>Close connection and terminate the proxy</fsummary> + <type> + <v>SequenceProxyPushConsumer = #objref</v> + </type> + <desc> + <p>This operation cause the target object to close the connection and terminate.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml new file mode 100644 index 0000000000..60dfa2c230 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyChannelAdmin_­SequenceProxyPushSupplier</title> + <shorttitle>..._SequenceProxyPushSupplier</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_­SequenceProxyPushSupplier</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::SequenceProxyPushSupplier interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifySubscribe</seealso></p> + </item> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyChannelAdmin_ProxySupplier">CosNotifyChannelAdmin_ProxySupplier</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>connect_sequence_push_consumer(SequenceProxyPushSupplier, PushConsumer) -> Reply</name> + <fsummary>Connect a consumer to the proxy</fsummary> + <type> + <v>SequenceProxyPushSupplier = #objref</v> + <v>PushConsumer = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}}</v> + </type> + <desc> + <p>This operation connects a <c>PushConsumer</c> to the target object. If a + connection already exists or the function <c>psuh_structured_events</c> + is not supported the exceptions <c>AlreadyConnected</c> or + <c>TypeError</c> will be raised respectively.</p> + </desc> + </func> + <func> + <name>suspend_connection(SequenceProxyPushSupplier) -> Reply</name> + <fsummary>Suspend the connection between the client and the target object</fsummary> + <type> + <v>SequenceProxyPushSupplier = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v> + </type> + <desc> + <p>This operation suspends the connection between the client and the target object. + If no connection exists or the connection is already suspended an exception is raised.</p> + </desc> + </func> + <func> + <name>resume_connection(SequenceProxyPushSupplier) -> Reply</name> + <fsummary>Resume a previously suspended connection with the proxy</fsummary> + <type> + <v>SequenceProxyPullConsumer = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v> + </type> + <desc> + <p>If the connection have previously been suspended this operation must used + if we want to resume the connection. If no object have been connected or the connection + already is active an exception is raised.</p> + </desc> + </func> + <func> + <name>disconnect_sequence_push_supplier(SequenceProxyPushSupplier) -> ok</name> + <fsummary>Close the connection and terminate the proxy</fsummary> + <type> + <v>SequenceProxyPushSupplier = #objref</v> + </type> + <desc> + <p>This operation cause the target object to close the connection and terminate.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml new file mode 100644 index 0000000000..070f9a3b92 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyChannelAdmin_­StructuredProxyPullConsumer</title> + <shorttitle>..._StructuredProxyPullConsumer</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_­StructuredProxyPullConsumer</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPullConsumer interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotifyComm_NotifyPublish">CosNotifyComm_NotifyPublish</seealso></p> + </item> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyChannelAdmin_ProxyConsumer">CosNotifyChannelAdmin_ProxyConsumer</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>connect_structured_pull_supplier(StructuredProxyPullConsumer, PullSupplier) -> Reply</name> + <fsummary>Connect a supplier to the proxy</fsummary> + <type> + <v>StructuredProxyPullConsumer = #objref</v> + <v>PullSupplier = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}}</v> + </type> + <desc> + <p>This operation connects a <c>PullSupplier</c> to the target object. If a connection + already exists or the given client object does not support the functions + <c>pull_structured_event</c> and <c>try_pull_structured_event</c> an exception is raised.</p> + </desc> + </func> + <func> + <name>suspend_connection(StructuredProxyPullConsumer) -> Reply</name> + <fsummary>Suspend the connection between the target object and its client</fsummary> + <type> + <v>StructuredProxyPullConsumer = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v> + </type> + <desc> + <p>This operation suspends the connection between the target object and its client. + If no connection exists or already suspended an exception is raised.</p> + </desc> + </func> + <func> + <name>resume_connection(StructuredProxyPullConsumer) -> Reply</name> + <fsummary>Resume a previously suspended connection with the proxy</fsummary> + <type> + <v>StructuredProxyPullConsumer = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v> + </type> + <desc> + <p>If the connection have been suspended this operation must be used if we want + to resume the connection. If the connection already are active or no connection + have been created an exception is raised.</p> + </desc> + </func> + <func> + <name>disconnect_structured_pull_consumer(StructuredProxyPullConsumer) -> ok</name> + <fsummary>Close the connection and terminate the proxy</fsummary> + <type> + <v>StructuredProxyPullConsumer = #objref</v> + </type> + <desc> + <p>This operation cause the target object to close the connection and terminate.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml new file mode 100644 index 0000000000..4a454b224a --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml @@ -0,0 +1,140 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyChannelAdmin_­StructuredProxyPullSupplier</title> + <shorttitle>..._StructuredProxyPullSupplier</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_­StructuredProxyPullSupplier</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPullSupplier interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifySubscribe</seealso></p> + </item> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyChannelAdmin_ProxySupplier">CosNotifyChannelAdmin_ProxySupplier</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>connect_structured_pull_consumer(StructuredProxyPullSupplier, PullConsumer) -> Reply</name> + <fsummary>Connect a consumer to the proxy</fsummary> + <type> + <v>StructuredProxyPullSupplier = #objref</v> + <v>PullConsumer = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}}</v> + </type> + <desc> + <p>This operation connects a <c>PullConsumer</c> to the target object. If a connection + already exists the <c>AlreadyConnected</c> exception is raised.</p> + </desc> + </func> + <func> + <name>pull_structured_event(StructuredProxyPullSupplier) -> Reply</name> + <fsummary>Pull a structured event from the proxy</fsummary> + <type> + <v>StructuredProxyPullSupplier = #objref</v> + <v>Reply = StructuredEvent | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v> + <v>StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body}</v> + <v>header = EventHeader</v> + <v>filterable_data = [#'CosNotification_Property'{name, value}]</v> + <v>name = string()</v> + <v>value = #any</v> + <v>remainder_of_body = #any</v> + <v>EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header}</v> + <v>fixed_header = FixedEventHeader</v> + <v>variable_header = OptionalHeaderFields</v> + <v>FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name}</v> + <v>event_type = EventType</v> + <v>event_name = string()</v> + <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v> + <v>domain_name = type_name = string()</v> + <v>OptionalHeaderFields = [#'CosNotification_Property'{name, value}]</v> + </type> + <desc> + <p>This operation pulls next event from the target object; if an event cannot + be delivered this function blocks until an event arrives.</p> + </desc> + </func> + <func> + <name>try_pull_structured_event(StructuredProxyPullSupplier) -> Reply</name> + <fsummary>Try to pull a structured event from the proxy</fsummary> + <type> + <v>StructuredProxyPullSupplier = #objref</v> + <v>Reply = {StructuredEvent, HasEvent} | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v> + <v>HasEvent = boolean()</v> + <v>StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body}</v> + <v>header = EventHeader</v> + <v>filterable_data = [#'CosNotification_Property'{name, value}]</v> + <v>name = string()</v> + <v>value = #any</v> + <v>remainder_of_body = #any</v> + <v>EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header}</v> + <v>fixed_header = FixedEventHeader</v> + <v>variable_header = OptionalHeaderFields</v> + <v>FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name}</v> + <v>event_type = EventType</v> + <v>event_name = string()</v> + <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v> + <v>domain_name = type_name = string()</v> + <v>OptionalHeaderFields = [#'CosNotification_Property'{name, value}]</v> + </type> + <desc> + <p>This operation try to pull next event from the target object. If no event have arrived + an empty event is returned and the out parameter <c>HasEvent</c> is set to false. Otherwise, + the boolean flag is set to true and an valid event is returned.</p> + </desc> + </func> + <func> + <name>disconnect_structured_pull_supplier(StructuredProxyPullSupplier) -> ok</name> + <fsummary>Close connection and terminate the proxy</fsummary> + <type> + <v>StructuredProxyPullSupplier = #objref</v> + </type> + <desc> + <p>This operation cause the target object to close the connection and terminate.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml new file mode 100644 index 0000000000..db7f1ddb44 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyChannelAdmin_­StructuredProxyPushConsumer</title> + <shorttitle>..._StructuredProxyPushConsumer</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_­StructuredProxyPushConsumer</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPushConsumer interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotifyComm_NotifyPublish">CosNotifyComm_NotifyPublish</seealso></p> + </item> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyChannelAdmin_ProxyConsumer">CosNotifyChannelAdmin_ProxyConsumer</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>connect_structured_push_supplier(StructuredProxyPushConsumer, PushSupplier) -> Reply</name> + <fsummary>Connect a supplier to the proxy</fsummary> + <type> + <v>StructuredProxyPushConsumer = #objref</v> + <v>PushSupplier = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}}</v> + </type> + <desc> + <p>This operation connects a <c>PushSupplier</c> to the target object. If a connection + already exists an exception is raised.</p> + </desc> + </func> + <func> + <name>push_structured_event(StructuredProxyPushConsumer, StructuredEvent) -> Reply</name> + <fsummary>Push a structured event to the proxy</fsummary> + <type> + <v>StructuredProxyPushConsumer = #objref</v> + <v>StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body}</v> + <v>header = EventHeader</v> + <v>filterable_data = [#'CosNotification_Property'{name, value}]</v> + <v>name = string()</v> + <v>value = #any</v> + <v>remainder_of_body = #any</v> + <v>EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header}</v> + <v>fixed_header = FixedEventHeader</v> + <v>variable_header = OptionalHeaderFields</v> + <v>FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name}</v> + <v>event_type = EventType</v> + <v>event_name = string()</v> + <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v> + <v>domain_name = type_name = string()</v> + <v>OptionalHeaderFields = [#'CosNotification_Property'{name, value}]</v> + <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v> + </type> + <desc> + <p>When a client want to push a new event to the target object this operation must be used.</p> + </desc> + </func> + <func> + <name>disconnect_structured_push_consumer(StructuredProxyPushConsumer) -> ok</name> + <fsummary>Close the connection and terminate the proxy</fsummary> + <type> + <v>StructuredProxyPushConsumer = #objref</v> + </type> + <desc> + <p>This operation cause the target object to close the connection and terminate.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml new file mode 100644 index 0000000000..b2dab10998 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyChannelAdmin_­StructuredProxyPushSupplier</title> + <shorttitle>..._StructuredProxyPushSupplier</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_­StructuredProxyPushSupplier</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPushSupplier interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifySubscribe</seealso></p> + </item> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyChannelAdmin_ProxySupplier">CosNotifyChannelAdmin_ProxySupplier</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>connect_structured_push_consumer(StructuredProxyPushSupplier, PushConsumer) -> Reply</name> + <fsummary>Connect a consumer to the proxy</fsummary> + <type> + <v>StructuredProxyPushSupplier = #objref</v> + <v>PushConsumer = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}}</v> + </type> + <desc> + <p>This operation connects a <c>PushConsumer</c> to the target object. If + a connection already exists or the function <c>push_structured_event</c> + is not supported by the client object an exception is raised.</p> + </desc> + </func> + <func> + <name>suspend_connection(StructuredProxyPushSupplier) -> Reply</name> + <fsummary>Suspend the connection with the target object</fsummary> + <type> + <v>StructuredProxyPushSupplier = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v> + </type> + <desc> + <p>This operation suspends the connection with the target object. If no connection + exists or the connection already is suspended an exception is raised.</p> + </desc> + </func> + <func> + <name>resume_connection(StructuredProxyPushSupplier) -> Reply</name> + <fsummary>Resume a previously suspended connection</fsummary> + <type> + <v>StructuredProxyPullConsumer = #objref</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v> + </type> + <desc> + <p>If the connection with the target object have been suspended this function + must be used to resume the connection. If no client have been connected or + the connection is active an exception is raised.</p> + </desc> + </func> + <func> + <name>disconnect_structured_push_supplier(StructuredProxyPushSupplier) -> ok</name> + <fsummary>Close the connection and terminate the target object</fsummary> + <type> + <v>StructuredProxyPushSupplier = #objref</v> + </type> + <desc> + <p>This operation cause the target object to close the connection and terminate.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SupplierAdmin.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SupplierAdmin.xml new file mode 100644 index 0000000000..0f262accb8 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SupplierAdmin.xml @@ -0,0 +1,195 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyChannelAdmin_­SupplierAdmin</title> + <shorttitle>..._SupplierAdmin</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyChannelAdmin_SupplierAdmin</module> + <modulesummary>This module implements the OMG CosNotifyChannelAdmin::SupplierAdmin interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module also exports the functions described in:</p> + <list type="bulleted"> + <item> + <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifyPublish</seealso></p> + </item> + <item> + <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p> + </item> + </list> + </description> + <funcs> + <func> + <name>_get_MyID(SupplierAdmin) -> AdminID</name> + <fsummary>Return the objects Id</fsummary> + <type> + <v>SupplierAdmin = #objref</v> + <v>AdminID = long()</v> + </type> + <desc> + <p>When a <c>SupplierAdmin</c> object is created it is given a unique Id + by the creating channel. This readonly attribute maintains this Id.</p> + </desc> + </func> + <func> + <name>_get_MyChannel(SupplierAdmin) -> Channel</name> + <fsummary>Return the objects associated channel</fsummary> + <type> + <v>SupplierAdmin = #objref</v> + <v>Channel = #objref</v> + </type> + <desc> + <p>The creating channel's reference is maintained by this readonly attribute.</p> + </desc> + </func> + <func> + <name>_get_MyOperator(SupplierAdmin) -> OpType</name> + <fsummary>Return the filter scheme</fsummary> + <type> + <v>SupplierAdmin = #objref</v> + <v>OpType = 'AND_OP' | 'OR_OP'</v> + </type> + <desc> + <p>The Operation Type, which determines the semantics the target object will + use for any associated <c>Filters</c>, is maintained by this readonly attribute.</p> + </desc> + </func> + <func> + <name>_get_pull_consumers(SupplierAdmin) -> ProxyIDSeq</name> + <fsummary>Return all associated pull consumers Id:s</fsummary> + <type> + <v>SupplierAdmin = #objref</v> + <v>ProxyIDSeq = [ProxyID]</v> + <v>ProxyID = long()</v> + </type> + <desc> + <p>A sequence of all associated <c>PullProxy</c> Id's is maintained by this + readonly attribute.</p> + </desc> + </func> + <func> + <name>_get_push_consumers(SupplierAdmin) -> ProxyIDSeq</name> + <fsummary>Return all associated push consumers Id:s</fsummary> + <type> + <v>SupplierAdmin = #objref</v> + <v>ProxyIDSeq = [ProxyID]</v> + <v>ProxyID = long()</v> + </type> + <desc> + <p>This operation returns all <c>PushProxy</c> Id's created by the target + object.</p> + </desc> + </func> + <func> + <name>get_proxy_consumer(SupplierAdmin, ProxyID) -> Reply</name> + <fsummary>Return the Proxy which corresponds to the given Id</fsummary> + <type> + <v>SupplierAdmin = #objref</v> + <v>ProxyID = long()</v> + <v>Reply = Proxy | {'EXCEPTION', #'CosNotifyChannelAdmin_ProxyNotFound'{}}</v> + <v>Proxy = #objref</v> + </type> + <desc> + <p>The Proxy which corresponds to the given Id is returned by this operation.</p> + </desc> + </func> + <func> + <name>obtain_notification_pull_consumer(SupplierAdmin, SupplierType) -> Reply</name> + <fsummary>Create a new proxy</fsummary> + <type> + <v>SupplierAdmin = #objref</v> + <v>SupplierType = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'</v> + <v>Reply = {Proxy, ProxyID}</v> + <v>Proxy = #objref</v> + <v>ProxyID = long()</v> + </type> + <desc> + <p>This operation creates a new proxy and returns its object reference along with its ID. + The <c>SupplierType</c> parameter determines the event type accepted by the proxy.</p> + </desc> + </func> + <func> + <name>obtain_pull_consumer(SupplierAdmin) -> Proxy</name> + <fsummary>Create a new proxy</fsummary> + <type> + <v>SupplierAdmin = #objref</v> + <v>Proxy = #objref</v> + </type> + <desc> + <p>A proxy which accepts <c>#any{}</c> events is created by this operation.</p> + </desc> + </func> + <func> + <name>obtain_notification_push_consumer(SupplierAdmin, SupplierType) -> Reply</name> + <fsummary>Create a new proxy</fsummary> + <type> + <v>SupplierAdmin = #objref</v> + <v>SupplierType = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'</v> + <v>Reply = {Proxy, ProxyID}</v> + <v>Proxy = #objref</v> + <v>ProxyID = long()</v> + </type> + <desc> + <p>Determined by the <c>SupplierType</c> parameter a compliant proxy is created and + its object reference along with its Id is returned by this operation.</p> + </desc> + </func> + <func> + <name>obtain_push_consumer(SupplierAdmin) -> Proxy</name> + <fsummary>Create a new proxy</fsummary> + <type> + <v>SupplierAdmin = #objref</v> + <v>Proxy = #objref</v> + </type> + <desc> + <p>A proxy which accepts <c>#any{}</c> events is created by this operation.</p> + </desc> + </func> + <func> + <name>destroy(SupplierAdmin) -> ok</name> + <fsummary>Terminate the target object</fsummary> + <type> + <v>SupplierAdmin = #objref</v> + </type> + <desc> + <p>This operation terminates the SupplierAdmin object and notifies the creating channel + that the target object no longer is active.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyComm_NotifyPublish.xml b/lib/cosNotification/doc/src/CosNotifyComm_NotifyPublish.xml new file mode 100644 index 0000000000..427ca87810 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyComm_NotifyPublish.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyComm_NotifyPublish</title> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyComm_NotifyPublish</module> + <modulesummary>This module implements the OMG CosNotifyComm::NotifyPublish interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>All objects, which inherit this interface, export functions described in this module.</p> + </description> + <funcs> + <func> + <name>offer_change(Object, Added, Removed) -> Reply</name> + <fsummary>Inform the target object which type of events the supplier will deliver</fsummary> + <type> + <v>Object = #objref</v> + <v>Added = Removed = EventTypeSeq</v> + <v>EventTypeSeq = [type]</v> + <v>Reply = ok | {'EXCEPTION', CosNotifyComm_InvalidEventType{type}}</v> + <v>type = #'CosNotification_EventType'{domain_name, type_name}</v> + <v>domain_name = type_name = string()</v> + </type> + <desc> + <p>Objects supporting this interface can be informed by supplier objects about + which type of events that will be delivered in the future. This operation + accepts two parameters describing new and old event types respectively. + If any of the supplied event type names is syntactically incorrect an exception + is raised.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyComm_NotifySubscribe.xml b/lib/cosNotification/doc/src/CosNotifyComm_NotifySubscribe.xml new file mode 100644 index 0000000000..1ed7f860c0 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyComm_NotifySubscribe.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyComm_­NotifySubscribe</title> + <shorttitle>..._NotifySubscribe</shorttitle> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyComm_NotifySubscribe</module> + <modulesummary>This module implements the OMG CosNotifyComm::NotifySubscribe interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>All objects, which inherit this interface, export functions described in this module.</p> + </description> + <funcs> + <func> + <name>subscription_change(Object, Added, Removed) -> Reply</name> + <fsummary>Inform the target object which event types the client will and will not accept in the future</fsummary> + <type> + <v>Object = #objref</v> + <v>Added = Removed = EventTypeSeq</v> + <v>EventTypeSeq = [type]</v> + <v>Reply = ok | {'EXCEPTION', CosNotifyComm_InvalidEventType{type}}</v> + <v>type = #'CosNotification_EventType'{domain_name, type_name}</v> + <v>domain_name = type_name = string()</v> + </type> + <desc> + <p>This operation takes as input two sequences of event type names + specifying events the client will and will not accept in the future + respectively.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyFilter_Filter.xml b/lib/cosNotification/doc/src/CosNotifyFilter_Filter.xml new file mode 100644 index 0000000000..dd894f2fea --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyFilter_Filter.xml @@ -0,0 +1,222 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>CosNotifyFilter_Filter</title> + <prepared></prepared> + <docno></docno> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyFilter_Filter</module> + <modulesummary>This module implements the OMG CosNotifyFilter::Filter interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + </description> + <funcs> + <func> + <name>_get_constraint_grammar(Filter) -> Grammar</name> + <fsummary>Return which type of Grammar the Filter uses</fsummary> + <type> + <v>Filter = #objref</v> + <v>Grammar = string()</v> + </type> + <desc> + <p>This operation returns which type of Grammar the Filter uses. Currently, only <c>"EXTENDED_TCL"</c> is supported.</p> + </desc> + </func> + <func> + <name>add_constraints(Filter, ConstraintExpSeq) -> Reply</name> + <fsummary>Add new constraints to the filter</fsummary> + <type> + <v>Filter = #objref</v> + <v>ConstraintExpSeq = [Constraint]</v> + <v>ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr}</v> + <v>event_types = #'CosNotification_EventTypeSeq'{}</v> + <v>constraint_expr = string()</v> + <v>Reply = ConstraintInfoSeq | {'EXCEPTION', #'CosNotifyFilter_InvalidConstraint'{constr}}</v> + <v>constr = ConstraintExp</v> + <v>ConstraintInfoSeq = [ConstraintInfo]</v> + <v>ConstraintInfo = #'CosNotifyFilter_ConstraintInfo'{constraint_expression, constraint_id}</v> + <v>constraint_expression = ConstraintExp</v> + <v>constraint_id = long()</v> + </type> + <desc> + <p>Initially, Filters do not contain any constraints, hence, all events will be forwarded. + The <c>add_constraints/2</c> operation allow us to add constraints to the target object.</p> + </desc> + </func> + <func> + <name>modify_constraints(Filter, ConstraintIDSeq, ConstraintInfoSeq) -> Reply</name> + <fsummary>Modify existing constraints</fsummary> + <type> + <v>Filter = #objref</v> + <v>ConstraintIDSeq = [ConstraintID]</v> + <v>ConstraintID = long()</v> + <v>ConstraintInfoSeq = [ConstraintInfo]</v> + <v>ConstraintInfo = #'CosNotifyFilter_ConstraintInfo'{constraint_expression, constraint_id}</v> + <v>constraint_expression = ConstraintExp</v> + <v>constraint_id = long()</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotifyFilter_InvalidConstraint'{constr}} | {'EXCEPTION', #'CosNotifyFilter_ConstraintNotFound'{id}}</v> + <v>constr = ConstraintExp</v> + <v>id = long()</v> + <v>ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr}</v> + <v>event_types = #'CosNotification_EventTypeSeq'{}</v> + <v>constraint_expr = string()</v> + </type> + <desc> + <p>This operation is invoked by a client in order to modify the constraints associated + with the target object. The constraints related to the Id's in the parameter sequence + <c>ConstraintIDSeq</c> will, if all values are valid, be deleted. The <c>ConstraintInfoSeq</c> + parameter contains of Id-Expression pairs and a constraint matching one of the unique + Id's will, if all input values are correct, be updated. If the parameters contain incorrect + data en exception will be raised.</p> + </desc> + </func> + <func> + <name>get_constraints(Filter, ConstraintIDSeq) -> Reply</name> + <fsummary>Return all constraints which match the supplied Ids</fsummary> + <type> + <v>Filter = #objref</v> + <v>ConstraintIDSeq = [ConstraintID]</v> + <v>ConstraintID = long()</v> + <v>Reply = ConstraintInfoSeq | {'EXCEPTION', #'CosNotifyFilter_ConstraintNotFound'{id}}</v> + <v>ConstraintInfoSeq = [ConstraintInfo]</v> + <v>ConstraintInfo = #'CosNotifyFilter_ConstraintInfo'{constraint_expression, constraint_id}</v> + <v>constraint_expression = ConstraintExp</v> + <v>constraint_id = id = long()</v> + </type> + <desc> + <p>This operation return a sequence of ConstraintInfo's, related to the given ConstraintID's, + associated with the target object.</p> + </desc> + </func> + <func> + <name>get_all_constraints(Filter) -> ConstraintInfoSeq</name> + <fsummary>Return all constraints associated with the target object</fsummary> + <type> + <v>Filter = #objref</v> + <v>ConstraintInfoSeq = [ConstraintInfo]</v> + <v>ConstraintInfo = #'CosNotifyFilter_ConstraintInfo'{constraint_expression, constraint_id}</v> + <v>constraint_expression = ConstraintExp</v> + <v>constraint_id = long()</v> + </type> + <desc> + <p>All constraints, and their unique Id, associated with the target object will be returned by this operation.</p> + </desc> + </func> + <func> + <name>remove_all_constraints(Filter) -> ok</name> + <fsummary>Remove all constraints associated with the target object</fsummary> + <type> + <v>Filter = #objref</v> + </type> + <desc> + <p>All constraints associated with the target object are removed by this operation and, since + the the target object no longer contain any constraints, true will always be the result of + any match operation.</p> + </desc> + </func> + <func> + <name>destroy(Filter) -> ok</name> + <fsummary>Terminate the target object</fsummary> + <type> + <v>Filter = #objref</v> + </type> + <desc> + <p>This operation terminates the target object.</p> + </desc> + </func> + <func> + <name>match(Filter, Event) -> Reply</name> + <fsummary>Match the Any event if it satisfies at least one constraint</fsummary> + <type> + <v>Filter = #objref</v> + <v>Event = #any</v> + <v>Reply = boolean() | {'EXCEPTION', #'CosNotifyFilter_UnsupportedFilterableData'{}}</v> + </type> + <desc> + <p>This operation accepts an <c>#any{}</c> event and returns <c>true</c> if it satisfies + at least one constraint. If the event contains data of the wrong type, e.g., should be + a string() but in fact i a short(), an exception is raised.</p> + </desc> + </func> + <func> + <name>match_structured(Filter, Event) -> Reply</name> + <fsummary>Match the structured event if it satisfies at least one constraint</fsummary> + <type> + <v>Filter = #objref</v> + <v>Event = #'CosNotification_StructuredEvent'{}</v> + <v>Reply = boolean() | {'EXCEPTION', #'CosNotifyFilter_UnsupportedFilterableData'{}}</v> + </type> + <desc> + <p>This operation is similar to the <c>match</c> operation but accepts structured + events instead.</p> + </desc> + </func> + <func> + <name>attach_callback(Filter, NotifySubscribe) -> CallbackID</name> + <fsummary>Connect NotifySubscribe object, which should be informed when the target object's constraints are updated</fsummary> + <type> + <v>Filter = #objref</v> + <v>NotifySubscribe = #objref</v> + <v>CallbackID = long()</v> + </type> + <desc> + <p>This operation connects a NotifySubscribe object, which should be informed + when the target object's constraints are updated. A unique Id is returned + which must be stored if we ever want to detach the callback object in the future.</p> + </desc> + </func> + <func> + <name>detach_callback(Filter, CallbackID) -> Reply</name> + <fsummary>Disconnect the NotifySubscribe object with the given Id</fsummary> + <type> + <v>Filter = #objref</v> + <v>CallbackID = long()</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotifyFilter_CallbackNotFound'{}}</v> + </type> + <desc> + <p>If the target object has an associated callback that matches the supplied + Id it will be removed and longer informed of any updates. If no object + with a matching Id is found an exception is raised.</p> + </desc> + </func> + <func> + <name>get_callbacks(Filter) -> CallbackIDSeq</name> + <fsummary>Return all NotifySubscribe Id's associated with the target object</fsummary> + <type> + <v>Filter = #objref</v> + <v>CallbackIDSeq = [CallbackID]</v> + <v>CallbackID = long()</v> + </type> + <desc> + <p>This operation returns a sequence of all connected NotifySubscribe object Id's. + If no callbacks are associated with the target object the list will be empty.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyFilter_FilterAdmin.xml b/lib/cosNotification/doc/src/CosNotifyFilter_FilterAdmin.xml new file mode 100644 index 0000000000..ebbba8763d --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyFilter_FilterAdmin.xml @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyFilter_FilterAdmin</title> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyFilter_FilterAdmin</module> + <modulesummary>This module implements the OMG CosNotifyFilter::FilterAdmin interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>All objects, which inherit this interface, export functions described in this module.</p> + </description> + <funcs> + <func> + <name>add_filter(Object, Filter) -> FilterID</name> + <fsummary>Add a new filter to the target object</fsummary> + <type> + <v>Object = #objref</v> + <v>Filter = #objref</v> + <v>FilterID = long()</v> + </type> + <desc> + <p>This operation connects a new <c>Filter</c> to the target object. This <c>Filter</c> will, together + with other associated <c>Filters</c>, be used to select events to forward. A unique Id is + returned and should be used if we no longer want to consult the given <c>Filter</c>.</p> + </desc> + </func> + <func> + <name>remove_filter(Object, FilterID) -> ok</name> + <fsummary>Remove a filter associated with the target object</fsummary> + <type> + <v>Object = #objref</v> + <v>FilterID = long()</v> + </type> + <desc> + <p>If a certain <c>Filter</c> no longer should be associated with the target object + this operation must be used. Events will no longer be tested against the <c>Filter</c> + associated with the given Id.</p> + </desc> + </func> + <func> + <name>get_filter(Object, FilterID) -> Reply</name> + <fsummary>Return the filter with the given Id</fsummary> + <type> + <v>Object = #objref</v> + <v>FilterID = long()</v> + <v>Reply = Filter | {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}</v> + <v>Filter = #objref</v> + </type> + <desc> + <p>If the target object is associated with a <c>Filter</c> matching the given Id the + reference will be returned. If no such <c>Filter</c> is known by the target object + an exception is raised.</p> + </desc> + </func> + <func> + <name>get_all_filters(Object) -> FilterIDSeq</name> + <fsummary>Return a list of all filter Id:s associated with the target object</fsummary> + <type> + <v>Object = #objref</v> + <v>FilterIDSeq = [FilterID]</v> + <v>FilterID = long()</v> + </type> + <desc> + <p>Id's for all <c>Filter</c> objects associated with the target object is + returned by this operation.</p> + </desc> + </func> + <func> + <name>remove_all_filters(Object) -> ok</name> + <fsummary>Remove all filters from the target object</fsummary> + <type> + <v>Object = #objref</v> + </type> + <desc> + <p>If we want to remove all <c>Filters</c> associated with the target object we can use this function.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyFilter_FilterFactory.xml b/lib/cosNotification/doc/src/CosNotifyFilter_FilterFactory.xml new file mode 100644 index 0000000000..c4712e481f --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyFilter_FilterFactory.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>CosNotifyFilter_FilterFactory</title> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyFilter_FilterFactory</module> + <modulesummary>This module implements the OMG CosNotifyFilter::FilterFactory interface.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + </description> + <funcs> + <func> + <name>create_filter(FilterFactory, Grammar) -> Reply</name> + <fsummary>Create a <c>Filter</c>object</fsummary> + <type> + <v>FilterFactory = #objref</v> + <v>Grammar = string()</v> + <v>Reply = Filter | {'EXCEPTION', #'CosNotifyFilter_InvalidGrammar'{}}</v> + <v>Filter = #objref</v> + </type> + <desc> + <p>This operation creates a new Filter object, under the condition + that Grammar given is supported. Currently, only <c>"EXTENDED_TCL"</c> is supported.</p> + </desc> + </func> + <func> + <name>create_mapping_filter(FilterFactory, Grammar) -> Reply</name> + <fsummary>Create a <c>MappingFilter</c>object</fsummary> + <type> + <v>FilterFactory = #objref</v> + <v>Grammar = string()</v> + <v>Reply = MappingFilter | {'EXCEPTION', #'CosNotifyFilter_InvalidGrammar'{}}</v> + <v>Filter = #objref</v> + </type> + <desc> + <p>This operation creates a new MappingFilter object, under the condition + that Grammar given is supported. Currently, only <c>"EXTENDED_TCL"</c> is supported.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/CosNotifyFilter_MappingFilter.xml b/lib/cosNotification/doc/src/CosNotifyFilter_MappingFilter.xml new file mode 100644 index 0000000000..f5c6a75f3e --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyFilter_MappingFilter.xml @@ -0,0 +1,227 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>CosNotifyFilter_MappingFilter</title> + <prepared></prepared> + <docno></docno> + <checked></checked> + <date>2000-02-01</date> + <rev>1.0</rev> + </header> + <module>CosNotifyFilter_MappingFilter</module> + <modulesummary>This module implements the OMG CosNotifyFilter::MappingFilter interface.</modulesummary> + <description> + <p>The main purpose of this module is to match events against associated + constraints and return the value for the first constraint that returns + true for the given event. If all constraints return false the default value + will be returned.</p> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + </description> + <funcs> + <func> + <name>_get_constraint_grammar(MappingFilter) -> Grammar</name> + <fsummary>Return which type of Grammar the MappingFilter uses</fsummary> + <type> + <v>MappingFilter = #objref</v> + <v>Grammar = string()</v> + </type> + <desc> + <p>This operation returns which type of Grammar the MappingFilter uses. + Currently, only <c>"EXTENDED_TCL"</c> is supported.</p> + </desc> + </func> + <func> + <name>_get_value_type(MappingFilter) -> CORBA::TypeCode</name> + <fsummary>Return the <c>CORBA::TypeCode</c>of the default value associated with the target object</fsummary> + <type> + <v>MappingFilter = #objref</v> + </type> + <desc> + <p>This readonly attribute maintains the <c>CORBA::TypeCode</c> of the default value + associated with the target object.</p> + </desc> + </func> + <func> + <name>_get_default_value(MappingFilter) -> #any</name> + <fsummary>Return the <c>#any{}</c> default value associated with the target object</fsummary> + <type> + <v>MappingFilter = #objref</v> + </type> + <desc> + <p>This readonly attribute maintains the <c>#any{}</c> default value associated with + the target object.</p> + </desc> + </func> + <func> + <name>add_mapping_constraints(MappingFilter, MappingConstraintPairSeq) -> Reply</name> + <fsummary>Add new mapping constraints</fsummary> + <type> + <v>MappingFilter = #objref</v> + <v>MappingConstraintPairSeq = [MappingConstraintPair]</v> + <v>MappingConstraintPair = #'CosNotifyFilter_MappingConstraintPair'{constraint_expression, result_to_set}</v> + <v>constraint_expression = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr}</v> + <v>event_types = #'CosNotification_EventTypeSeq'{}</v> + <v>constraint_expr = string()</v> + <v>result_to_set = #any</v> + <v>Reply = MappingConstraintInfoSeq | {'EXCEPTION', #'CosNotifyFilter_InvalidConstraint'{constr}} | {'EXCEPTION', #'CosNotifyFilter_InvalidValue'{constr, value}}</v> + <v>constr = ConstraintExp</v> + <v>ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr}</v> + <v>event_types = #'CosNotification_EventTypeSeq'{}</v> + <v>constraint_expr = string()</v> + <v>MappingConstraintInfoSeq = [MappingConstraintInfo]</v> + <v>MappingConstraintInfo = #'CosNotifyFilter_MappingConstraintInfo'{constraint_expression, constraint_id, value}</v> + <v>constraint_expression = ConstraintExp</v> + <v>constraint_id = long()</v> + <v>value = #any</v> + </type> + <desc> + <p>This operation add new mapping constraints, which will be used when trying to override + Quality of Service settings defined in the given event. If a constraint return true the + associated value will be returned, otherwise the default value.</p> + </desc> + </func> + <func> + <name>modify_constraints(MappingFilter, ConstraintIDSeq, MappingConstraintInfoSeq) -> Reply</name> + <fsummary>Modify the constraints associated with the target object</fsummary> + <type> + <v>MappingFilter = #objref</v> + <v>ConstraintIDSeq = [ConstraintID]</v> + <v>ConstraintID = long()</v> + <v>MappingConstraintInfoSeq = [MappingConstraintInfo]</v> + <v>MappingConstraintInfo = #'CosNotifyFilter_MappingConstraintInfo'{constraint_expression, constraint_id, value}</v> + <v>constraint_expression = ConstraintExp</v> + <v>constraint_id = long()</v> + <v>value = #any</v> + <v>ConstraintInfoSeq = [ConstraintInfo]</v> + <v>ConstraintInfo = #'CosNotifyFilter_ConstraintInfo'{constraint_expression, constraint_id}</v> + <v>constraint_expression = ConstraintExp</v> + <v>constraint_id = long()</v> + <v>Reply = ok | {'EXCEPTION', #'CosNotifyFilter_InvalidConstraint'{constr}} | {'EXCEPTION', #'CosNotifyFilter_ConstraintNotFound'{id}} | {'EXCEPTION', #'CosNotifyFilter_InvalidValue'{constr, value}}</v> + <v>constr = ConstraintExp</v> + <v>id = long()</v> + <v>value = #any</v> + <v>ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr}</v> + <v>event_types = #'CosNotification_EventTypeSeq'{}</v> + <v>constraint_expr = string()</v> + </type> + <desc> + <p>The <c>ConstraintIDSeq</c> supplied should relate to constraints the caller wishes to + remove. If any of the supplied Id's are not found an exception will be raised. This + operation also accepts a sequence of <c>MappingConstraintInfo</c> which will be added. + If the target object cannot modify the constraints as requested an exception is raised + describing which constraint, and why, could not be updated.</p> + </desc> + </func> + <func> + <name>get_mapping_constraints(MappingFilter, ConstraintIDSeq) -> Reply</name> + <fsummary>Return the target object's associated constraints with given ID:s</fsummary> + <type> + <v>MappingFilter = #objref</v> + <v>ConstraintIDSeq = [ConstraintID]</v> + <v>ConstraintID = long()</v> + <v>Reply = MappingConstraintInfoSeq | {'EXCEPTION', #'CosNotifyFilter_ConstraintNotFound'{id}}</v> + <v>MappingConstraintInfoSeq = [MappingConstraintInfo]</v> + <v>MappingConstraintInfo = #'CosNotifyFilter_MappingConstraintInfo'{constraint_expression, constraint_id, value}</v> + <v>constraint_expression = ConstraintExp</v> + <v>ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr}</v> + <v>event_types = #'CosNotification_EventTypeSeq'{}</v> + <v>constraint_expr = string()</v> + <v>constraint_id = id = long()</v> + <v>value = #any</v> + </type> + <desc> + <p>When adding a new constraint a unique Id is returned, which is accepted as input for this + operation. The associated constraint is returned, but if no such Id exists an exception is raised. </p> + </desc> + </func> + <func> + <name>get_all_mapping_constraints(MappingFilter) -> MappingConstraintInfoSeq</name> + <fsummary>Return the target object's all associated constraints</fsummary> + <type> + <v>MappingFilter = #objref</v> + <v>MappingConstraintInfoSeq = [MappingConstraintInfo]</v> + <v>MappingConstraintInfo = #'CosNotifyFilter_MappingConstraintInfo'{constraint_expression, constraint_id, value}</v> + <v>constraint_expression = ConstraintExp</v> + <v>ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr}</v> + <v>event_types = #'CosNotification_EventTypeSeq'{}</v> + <v>constraint_expr = string()</v> + <v>constraint_id = long()</v> + <v>value = #any</v> + </type> + <desc> + <p>This operation returns a sequence of all unique Id's associated with the target object. + If no constraint have been added the sequence will be empty.</p> + </desc> + </func> + <func> + <name>remove_all_mapping_constraints(MappingFilter) -> ok</name> + <fsummary>Remove all constraints associated with the target object</fsummary> + <type> + <v>MappingFilter = #objref</v> + </type> + <desc> + <p>This operation removes all constraints associated with the target object.</p> + </desc> + </func> + <func> + <name>destroy(MappingFilter) -> ok</name> + <fsummary>Terminate the target object</fsummary> + <type> + <v>MappingFilter = #objref</v> + </type> + <desc> + <p>This operation terminates the target object. Remember to remove + this Filter from the objects it have been associated with.</p> + </desc> + </func> + <func> + <name>match(MappingFilter, Event) -> Reply</name> + <fsummary>Evaluate the given Any event with the Filter's constraints</fsummary> + <type> + <v>MappingFilter = #objref</v> + <v>Event = #any</v> + <v>Reply = {boolean(), #any} | {'EXCEPTION', #'CosNotifyFilter_UnsupportedFilterableData'{}}</v> + </type> + <desc> + <p>This operation evaluates <c>Any</c> events with the Filter's constraints, + and returns the value to use. The value is the default value if all constraints + returns false and the value associated with the first constraint returning true.</p> + </desc> + </func> + <func> + <name>match_structured(MappingFilter, Event) -> Reply</name> + <fsummary>Evaluate the given structured event with the Filter's constraints</fsummary> + <type> + <v>MappingFilter = #objref</v> + <v>Event = #'CosNotification_StructuredEvent'{}</v> + <v>Reply = {boolean(), #any} | {'EXCEPTION', #'CosNotifyFilter_UnsupportedFilterableData'{}}</v> + </type> + <desc> + <p>Similar to <c>match/2</c> but accepts a structured event as input.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/Makefile b/lib/cosNotification/doc/src/Makefile new file mode 100644 index 0000000000..6abcf0ef1d --- /dev/null +++ b/lib/cosNotification/doc/src/Makefile @@ -0,0 +1,254 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(COSNOTIFICATION_VSN) +APPLICATION=cosNotification + +# ---------------------------------------------------- +# Include dependency +# ---------------------------------------------------- + +ifndef DOCSUPPORT +include make.dep +endif + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_APPLICATION_FILES = ref_man.xml +XML_REF3_FILES = \ + cosNotificationApp.xml \ + CosNotifyChannelAdmin_EventChannelFactory.xml \ + CosNotifyChannelAdmin_EventChannel.xml \ + CosNotification.xml \ + CosNotification_QoSAdmin.xml \ + CosNotification_AdminPropertiesAdmin.xml \ + CosNotifyChannelAdmin_ConsumerAdmin.xml \ + CosNotifyChannelAdmin_SupplierAdmin.xml \ + CosNotifyComm_NotifyPublish.xml \ + CosNotifyComm_NotifySubscribe.xml \ + CosNotifyFilter_FilterAdmin.xml \ + CosNotifyFilter_FilterFactory.xml \ + CosNotifyFilter_Filter.xml \ + CosNotifyFilter_MappingFilter.xml \ + CosNotifyChannelAdmin_ProxyConsumer.xml \ + CosNotifyChannelAdmin_ProxySupplier.xml \ + CosNotifyChannelAdmin_ProxyPullConsumer.xml \ + CosNotifyChannelAdmin_ProxyPullSupplier.xml \ + CosNotifyChannelAdmin_ProxyPushConsumer.xml \ + CosNotifyChannelAdmin_ProxyPushSupplier.xml \ + CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml \ + CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml \ + CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml \ + CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml \ + CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml \ + CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml \ + CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml \ + CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml \ + + + +XML_PART_FILES = \ + part.xml \ + part_notes.xml +XML_CHAPTER_FILES = \ + ch_contents.xml \ + ch_introduction.xml \ + ch_install.xml \ + ch_system.xml \ + ch_BNF.xml \ + ch_QoS.xml \ + ch_example.xml \ + notes.xml + +BOOK_FILES = book.xml + +TECHNICAL_DESCR_FILES = + +GIF_FILES = \ + book.gif \ + notes.gif \ + ref_man.gif \ + user_guide.gif \ + eventstructure.gif \ + notificationFlow.gif + +PS_FILES = + +# ---------------------------------------------------- + +INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html) + +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + +INFO_FILE = ../../info +EXTRA_FILES = summary.html.src \ + $(DEFAULT_GIF_FILES) \ + $(DEFAULT_HTML_FILES) \ + $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) + +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) + +ifdef DOCSUPPORT + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +else + +TEX_FILES_BOOK = \ + $(BOOK_FILES:%.xml=%.tex) +TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ + $(XML_APPLICATION_FILES:%.xml=%.tex) +TEX_FILES_USERS_GUIDE = \ + $(XML_CHAPTER_FILES:%.xml=%.tex) + +TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf + +TOP_PS_FILE = $(APPLICATION)-$(VSN).ps + +$(TOP_PDF_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ + +$(TOP_PS_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ + +endif + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +ifdef DOCSUPPORT + +docs: pdf html man + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: gifs $(HTML_REF_MAN_FILE) + +clean clean_docs: + rm -rf $(HTMLDIR)/* + rm -f $(MAN3DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +else + +ifeq ($(DOCTYPE),pdf) +docs: pdf +else +ifeq ($(DOCTYPE),ps) +docs: ps +else +docs: html gifs man +endif +endif + +pdf: $(TOP_PDF_FILE) + +ps: $(TOP_PS_FILE) + +html: $(HTML_FILES) $(INTERNAL_HTML_FILES) + +clean clean_docs clean_tex: + rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) + rm -f $(HTML_FILES) $(MAN3_FILES) + rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) + rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) + +endif + +man: $(MAN3_FILES) + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +$(INDEX_TARGET): $(INDEX_SRC) + sed -e 's;%VSN%;$(VSN);' $(INDEX_SRC) > $(INDEX_TARGET) + +debug opt: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +ifdef DOCSUPPORT + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(HTMLDIR)/* \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 +else + +ifeq ($(DOCTYPE),pdf) +release_docs_spec: pdf + $(INSTALL_DIR) $(RELEASE_PATH)/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf +else +ifeq ($(DOCTYPE),ps) +release_docs_spec: ps + $(INSTALL_DIR) $(RELEASE_PATH)/ps + $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps +else +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 + +endif +endif + +endif + +release_spec: + diff --git a/lib/cosNotification/doc/src/book.gif b/lib/cosNotification/doc/src/book.gif Binary files differnew file mode 100644 index 0000000000..94b3868792 --- /dev/null +++ b/lib/cosNotification/doc/src/book.gif diff --git a/lib/cosNotification/doc/src/book.xml b/lib/cosNotification/doc/src/book.xml new file mode 100644 index 0000000000..fe311ee57c --- /dev/null +++ b/lib/cosNotification/doc/src/book.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>cosNotification</title> + <prepared>Niclas Eklund</prepared> + <docno></docno> + <date>2000-01-31</date> + <rev>1.0</rev> + </header> + <insidecover> + </insidecover> + <pagetext>cosNotification</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> + <applications> + <xi:include href="ref_man.xml"/> + </applications> + <releasenotes> + <xi:include href="notes.xml"/> + </releasenotes> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/lib/cosNotification/doc/src/ch_BNF.xml b/lib/cosNotification/doc/src/ch_BNF.xml new file mode 100644 index 0000000000..545280a1f4 --- /dev/null +++ b/lib/cosNotification/doc/src/ch_BNF.xml @@ -0,0 +1,456 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Filters and the Constraint Language BNF</title> + <prepared></prepared> + <docno></docno> + <date>2000-04-13</date> + <rev></rev> + <file>ch_BNF.xml</file> + </header> + + <section> + <title>Filters and the Constraint Language BNF</title> + <p>This chapter describes, the grammar supported by + <seealso marker="CosNotifyFilter_Filter">CosNotifyFilter_Filter</seealso> and + <seealso marker="CosNotifyFilter_MappingFilter">CosNotifyFilter_MappingFilter</seealso>, + and how to create and use filter objects. + </p> + + <section> + <title>How to create filter objects</title> + <p>To be able to filter events we must create a filter and associate + it with one, or more, of the administrative or proxy objects. In the example + below, we choose to associate the filter with a ConsumerAdmin object.</p> + <code type="none"> +FilterFactory = cosNotificationApp:start_filter_factory(), +Filter = 'CosNotifyFilter_FilterFactory': + create_filter(FilterFactory,"EXTENDED_TCL"), +ConstraintInfoSeq = 'CosNotifyFilter_Filter': + add_constraints(Filter, ConstraintExpSeq), +FilterID = 'CosNotifyChannelAdmin_ConsumerAdmin': + add_filter(AdminConsumer, Filter), + </code> + <p><c>"EXTENDED_TCL"</c> is the only grammar supported by Orber Notification + Service.</p> + <p>Depending on which operation type the Admin object uses, i.e., + <c>'AND_OP'</c> or <c>'OR_OP'</c>, events will be tested using the + associated filter. The operation properties are:</p> + <p></p> + <list type="bulleted"> + <item> + <p>'AND_OP' - must be approved by the proxy's <em>and</em> its parent admin's + filters. If all filters associated with an object (Admin or Proxy) + return false the event will be discarded. In this situation it is pointless + to try and verify with the other object's associated filters since the outcome + still would be the same.</p> + </item> + <item> + <p>'OR_OP' - if one of the object's (Admin or Proxy) filters return true, the event + will not be checked against any other filter associated with a proxy or its + parent admin. If a object's associated filters all return false, + the event will be forwarded to related proxies/admins, and + tested against any associated filters.</p> + </item> + </list> + <p>Initially, filters are empty and will always return true. Hence, we must + add constraints by using <c>'CosNotifyFilter_Filter':add_constraints/2</c>. + As input, the second argument must be a sequence of:</p> + <code type="none"> +#'CosNotifyFilter_ConstraintExp'{ + event_types = [#'CosNotification_EventType'{ + domain_name = string(), + type_name = string()}], + constraint_expr = string()} + </code> + <p>The <c>event_types</c> describes which types of events that should be matched using + the associated <c>constraint_expr</c>.</p> + <p>If a constraint expression is supposed to apply for all events, then the <c>type_name</c> can + be set to the special event type <c>%ALL</c> in a constraint's event type sequence. The + <c>domain_name</c> should be <c>""</c> or <c>"*"</c>.</p> + <p>In the following sections we will take a closer look on how to write + constraint expressions.</p> + </section> + + <section> + <title>The CosNotification Constraint Language</title> + <p>The constraint language supported by the Notification Service is:</p> + <code type="none"><![CDATA[ +<constraint> := /* empty */ + | <bool> + +<bool> := <bool_or> + +<bool_or> := <bool_or> or <bool_and> + | <bool_and> + +<bool_and> := <bool_and> and <bool_compare> + | <bool_compare> + +<bool_compare> := <expr_in> == <expr_in> + | <expr_in> != <expr_in> + | <expr_in> < <expr_in> + | <expr_in> <= <expr_in> + | <expr_in> > <expr_in> + | <expr_in> >= <expr_in> + | <expr_in> + +<expr_in> := <expr_twiddle> in <Ident> /* sequence only */ + | <expr_twiddle> + | <expr_twiddle> in $ <Component> /* sequence only */ + +<expr_twiddle> := <expr> ~ <expr> /* string data types only */ + | <expr> + +<expr> := <expr> + <term> + | <expr> - <term> + | <term> + +<term> := <term> * <factor_not> + | <term> / <factor_not> + | <factor_not> + +<factor_not> := not <factor> + | <factor> + +<factor> := ( <bool_or> ) + | exist <Ident> + | <Ident> + | <Number> + | - <Number> + | <String> + | TRUE + | FALSE + | + <Number> + | exist $ <Component> + | $ <Component> + | default $ <Component> /* discriminated unions only */ + +<Component> := /* empty */ + | . <CompDot> + | <CompArray> + | <CompAssoc> + | <Ident> <CompExt> /* run-time variable */ + +<CompExt> := /* empty */ + | . <CompDot> + | <CompArray> + | <CompAssoc> + +<CompDot> := <Ident> <CompExt> + | <CompPos> + | <UnionPos> + | _length /* only valid for arrays or sequences */ + | _d /* discriminated unions only */ + | _type_id /* only valid if possible to obtain */ + | _repos_id /* only valid if possible to obtain */ + +<CompArray> := [ <Digits> ] <CompExt> + +<CompAssoc> := ( <Ident> ) <CompExt> + +<CompPos> := <Digits> <CompExt> + +<UnionPos> := ( <UnionVal> ) <CompExt> + +<UnionVal> := /* empty */ + | <Digits> + | - <Digits> + | + <Digits> + | <String> + +/* Character set issues */ +<Ident> :=<Leader> <FollowSeq> + | \\ < Leader> <FollowSeq> + +<FollowSeq> := /* <empty> */ + | <FollowSeq> <Follow> + +<Number> := <Mantissa> + | <Mantissa> <Exponent> + +<Mantissa> := <Digits> + | <Digits> . + | . <Digits> + | <Digits> . <Digits> + +<Exponent> := <Exp> <Sign> <Digits> + +<Sign> := + + | - + +<Exp> := E + | e + +<Digits> := <Digits> <Digit> + | <Digit> + +<String> := ' <TextChars> ' + +<TextChars> := /* <empty> */ + | <TextChars> <TextChar> + +<TextChar> := <Alpha> + | <Digit> + | <Other> + | <Special> + +<Special> := \\\\ + | \\' + +<Leader> := <Alpha> + +<Follow> := <Alpha> + | <Digit> + | _ + +<Alpha> is the set of alphabetic characters [A-Za-z] +<Digit> is the set of digits [0-9] +<Other> is the set of ASCII characters that are not <Alpha>, <Digit>, or <Special> + ]]></code> + <p>In the absence of parentheses, the following precedence relations hold :</p> + <list type="ordered"> + <item><c>()</c>, <c>exist</c>, <c>default</c>, <c>unary-sign</c></item> + <item><c>not</c></item> + <item><c>*</c>, <c>/</c></item> + <item><c>+</c>, <c>-</c></item> + <item><c>~</c></item> + <item><c>in</c></item> + <item><c>==</c>, <c>!=</c>, <c><![CDATA[<]]></c>, <c><![CDATA[<=]]></c>, <c>></c>, <c>>=</c></item> + <item><c>and</c></item> + <item><c>or</c></item> + </list> + </section> + + <section> + <title>The Constraint Language Data Types</title> + <p>The Notification Service Constraint Language, defines how to write + constraint expressions, which can be used to filter events. The + representation does, however, differ slightly from ordinary Erlang terms.</p> + <p>When creating a <c>ConstraintExp</c>, the field <c>constraint_expr</c> must be + set to contain a string, e.g., <c><![CDATA["1 < 2"]]></c>. The Notification Service Constraint + Language, is designed to be able to filter structured and unstructured events + using the same constraint expression. The Constraint Language Types and Operations + can be divided into two sub-groups:</p> + <list type="bulleted"> + <item> + <p>Basic - arithmetics, strings, constants, numbers etc.</p> + </item> + <item> + <p>Complex - accessing members of complex data types, such as unions.</p> + </item> + </list> + <p>Some of the basic types, e.g., integer, are self explanatory. Hence, they are not described further.</p> + <table> + <row> + <cell align="center" valign="middle"><em>Type/Operation</em></cell> + <cell align="center" valign="middle"><em>Examples</em></cell> + <cell align="center" valign="middle"><em>Description</em></cell> + </row> + <row> + <cell align="left" valign="middle"><c>string</c></cell> + <cell align="left" valign="middle"><c>"'MyString'"</c></cell> + <cell align="left" valign="middle">Strings are represented as a sequence of zero or more <c><![CDATA[<TextChar>]]></c>s enclosed in single quotes, e.g., <c>'string'</c>.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>~</c></cell> + <cell align="left" valign="middle"><c>"'Sring1' ~ 'String2'"</c></cell> + <cell align="left" valign="middle">The operator <c>~</c>is called the substring operator and mean "String1 is contained within String2".</cell> + </row> + <row> + <cell align="left" valign="middle"><c>boolean</c></cell> + <cell align="left" valign="middle"><c>"TRUE == (('lang' ~ 'Erlang' + 'fun' ~ 'functional') >= 2)"</c></cell> + <cell align="left" valign="middle">Booleans may only be TRUE or FALSE, i.e., only capital letters. Expressions which evaluate to TRUE or FALSE can be summed up and matched, where TRUE equals 1 and FALSE 0.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>sequence</c></cell> + <cell align="left" valign="middle"><c>"myIntegerSequence[2]"</c></cell> + <cell align="left" valign="middle">The BNF use C/C++ notation, i.e., the example will return the <em>third</em>element.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>_length</c></cell> + <cell align="left" valign="middle"><c>"myIntegerSequence._length"</c></cell> + <cell align="left" valign="middle">Returns the length of an sequence or array.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>in</c></cell> + <cell align="left" valign="middle"><c>"'Erlang' in $.FunctionalLanguages­StringSeq"</c></cell> + <cell align="left" valign="middle">Returns <c>TRUE</c>if a given element is found in the given sequence. The element must be of a simple type and the same as the sequence is defined to contain.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>$</c></cell> + <cell align="left" valign="middle"><c>"$ == 40"</c></cell> + <cell align="left" valign="middle">Denote the current event as well as any run-time variables. If the event is unstructured and its contained value 40, the example will return <c>TRUE</c>.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>.</c></cell> + <cell align="left" valign="middle"><c>"$.MyStructMember == 40"</c></cell> + <cell align="left" valign="middle">The structure member operator <c>.</c>may be used to reference its members when the data refers to a named structure, discriminated union, or CORBA::Any data structure.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>_type_id</c></cell> + <cell align="left" valign="middle"><c>"$._type_id == 'MyStruct'"</c></cell> + <cell align="left" valign="middle">Returns the unscoped IDL type name of the component. This operation is only valid if said information can be obtained.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>_repos_id</c></cell> + <cell align="left" valign="middle"><c>"$._repos_id == 'IDL:MyModule/MyStruct:1.0'"</c></cell> + <cell align="left" valign="middle">Returns the RepositoryId of the component. This operation is only valid if said information can be obtained.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>_d</c></cell> + <cell align="left" valign="middle"><c>"$.eventUnion._d"</c></cell> + <cell align="left" valign="middle">May only be used when accessing discriminated unions and refers to the discriminator.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>exist</c></cell> + <cell align="left" valign="middle"><c>"exist $.eventUnion._d and $.eventUnion._d == 10"</c></cell> + <cell align="left" valign="middle">To avoid that a filtering of an event fails due to that, for example, we try to compare a union discriminator which does not exist, we can use this operator.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>default</c></cell> + <cell align="left" valign="middle"><c>"default $.eventUnion._d"</c></cell> + <cell align="left" valign="middle">If the <c>_d</c>operation is in conjunction with the <c>default</c>operation, TRUE will be returned if the union has a default member that is active.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>union</c></cell> + <cell align="left" valign="middle"><c>"$.(0) == 5"</c>eq. <c>"$.('zero') == 5"</c></cell> + <cell align="left" valign="middle">When the component refers to a union, with one of the cases defined as <c>case 0: short zero;</c>, we use <c>0</c>or <c>'zero'</c>. The result of the example is <c>TRUE</c>if the union has a discriminator set to <c>0</c>and the value <c>5</c>. If more than one case is defined to be<c>'zero'</c>, <c>$.('zero')</c>accepts both; <c>$.(0)</c>only returns <c>TRUE</c>if the discriminator is set to <c>0</c>. Leaving out the identifier, i.e., <c>$.()</c>, refers to the default value.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>name-value pairs</c></cell> + <cell align="left" valign="middle"><c>"$.NameValueSeq('myID') == 5"</c>eq.<c>"$.NameValueSeq[1].name == 'myID' and $.NameValueSeq[1].value == 5"</c></cell> + <cell align="left" valign="middle">The Notification service makes extensive use of <c>name-value pairs</c>sequences within structured events, which allow us to via the identifier <c>name</c>access its <c>value</c>, as shown in the example.</cell> + </row> + <tcaption>Table 1: Type and Operator Examples</tcaption> + </table> + <p>In the next section we will take a closer look at how it is possible to write constraints using + different types of notation etc.</p> + </section> + + <section> + <title>Accessing Data In Events</title> + <p>To filter events, the supplied constraints must describe the contents of + the events and desired values. We can, for example, state that we are only + interested in receiving events which are of type <em>CommunicationsAlarm</em>. + To be able to achieve this, the constraint must contain information + that points out which fields to compare with. Figure one illustrates a conceptual overview of a + structured event. The exact definition is found in the <c>CosNotification.idl</c> file.</p> + <marker id="eventstructure"></marker> + <image file="eventstructure.gif"> + <icaption> +Figure 1: The structure of a structured event.</icaption> + </image> + <p>The Notification Service supports different constraint expressions + notation:</p> + <list type="bulleted"> + <item> + <p>Fully scoped, e.g., "$.header.fixed_header.event_type.type_name == 'CommunicationsAlarm'"</p> + </item> + <item> + <p>Short hand, e.g., "$type_name == 'CommunicationsAlarm'"</p> + </item> + <item> + <p>Positional Notation, e.g., "$.0.0.0.1 == 'CommunicationsAlarm'"</p> + </item> + </list> + <note> + <p>Which notation to use is up to the user, however, the fully scoped may + be easier to understand, but in some cases, if received from an ORB that do not populate ID:s of + named parts, the positional notation is the only option.</p> + </note> + <note> + <p>If a constraint, which access fields in a structured event structure, + is supposed to handle unstructured events as well, the CORBA::Any must contain + the same type of members.</p> + </note> + <p>How to filter against the fixed header fields, is described in the + table below.</p> + <table> + <row> + <cell align="center" valign="middle">Field</cell> + <cell align="center" valign="middle">Fully Scoped Constraint</cell> + <cell align="center" valign="middle">Short Hand Constraint</cell> + </row> + <row> + <cell align="left" valign="middle">type_name</cell> + <cell align="left" valign="middle">"$.header.fixed_header.event_­type.type_name == 'Type'"</cell> + <cell align="left" valign="middle">"$type_name == 'Type'"</cell> + </row> + <row> + <cell align="left" valign="middle">domain_name</cell> + <cell align="left" valign="middle">"$.header.fixed_header.event_­type.domain_name == 'Domain'"</cell> + <cell align="left" valign="middle">"$domain_name == 'Domain'"</cell> + </row> + <row> + <cell align="left" valign="middle">event_name</cell> + <cell align="left" valign="middle">"$.header.fixed_header.event_­name == 'Event'"</cell> + <cell align="left" valign="middle">"$event_name == 'Event'"</cell> + </row> + <tcaption>Table 2: Fixed Header Constraint Examples</tcaption> + </table> + <p>If we are only interested in receiving events regarding 'Domain', 'Event' + and 'Type', the constraint can look like + <c>"$domain_name == 'Domain' and $event_name == 'Event' and $type_name == 'Type'"</c>.</p> + <p>The variable event header consists of a sequence of <em>name-value pairs</em>. One way to filter on these are to use a constraint that looks + like <c>"($.header.variable_header[1].name == 'priority' and $.header.variable_header[1].value > 0)"</c>. An easier way to + accomplish the same result is to use a constraint that treats the name-value + pair as an associative array, i.e., when given a name the corresponding + value is returned. Hence, instead we can use + <c>"$.header.variable_header(priority) > 0"</c>.</p> + <p>Accessing the event body is done in the same way as for the event header + fields. The user must, however, be aware of, that if a run-time variable + (<c>$variable</c>) is used data in the event header may take precedence. + The order of precedence is:</p> + <list type="ordered"> + <item>Reserved, e.g., <c>$curtime</c></item> + <item>A simple-typed member of <c>$.header.fixed_header</c>.</item> + <item>Properties in <c>$.header.variable_header</c>.</item> + <item>Properties in <c>$.filterable_data</c>.</item> + <item>If no match is found it is translated to <c>$.variable</c>.</item> + </list> + </section> + + <section> + <title>Mapping Filters</title> + <p>Mapping Filters may only be associated with Consumer Administrators or Proxy + Suppliers. The purpose of a Mapping Filter is to override Quality of Service + settings.</p> + <p>Initially, Mapping Filters are empty and will always return true. Hence, we must + add constraints by using <c>'CosNotifyFilter_MappingFilter':add_mapping_constraints/2</c>. + If a constraint matches, the associated value will be used instead of the + related Quality of Service system settings.</p> + <p>As input, the second argument must be a sequence of:</p> + <code type="none"> +#'CosNotifyFilter_MappingConstraintPair'{ + constraint_expression = #'CosNotifyFilter_ConstraintExp'{ + event_types = [#'CosNotification_EventType'{ + domain_name = string(), + type_name = string()}], + constraint_expr = string()}, + result_to_set = any()} + </code> + </section> + </section> +</chapter> + diff --git a/lib/cosNotification/doc/src/ch_QoS.xml b/lib/cosNotification/doc/src/ch_QoS.xml new file mode 100644 index 0000000000..fbc8622a62 --- /dev/null +++ b/lib/cosNotification/doc/src/ch_QoS.xml @@ -0,0 +1,251 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Quality Of Service and Admin Properties</title> + <prepared></prepared> + <docno></docno> + <date>2000-05-29</date> + <rev></rev> + <file>ch_QoS.xml</file> + </header> + + <section> + <title>Quality Of Service and Admin Properties</title> + <p>This chapter explains the allowed properties for + <seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso> and + <seealso marker="CosNotification_AdminPropertiesAdmin">CosNotification_AdminPropertiesAdmin</seealso>. + </p> + + <section> + <title>Quality Of Service</title> + <p>The cosNotification application supports the following QoS settings:</p> + <table> + <row> + <cell align="center" valign="middle"><em>QoS</em></cell> + <cell align="center" valign="middle"><em>Range</em></cell> + <cell align="center" valign="middle"><em>Default</em></cell> + </row> + <row> + <cell align="left" valign="middle">EventReliability</cell> + <cell align="left" valign="middle">BestEffort/Persistent</cell> + <cell align="left" valign="middle">BestEffort</cell> + </row> + <row> + <cell align="left" valign="middle">ConnectionReliability</cell> + <cell align="left" valign="middle">BestEffort/Persistent</cell> + <cell align="left" valign="middle">BestEffort</cell> + </row> + <row> + <cell align="left" valign="middle">Priority</cell> + <cell align="left" valign="middle">+/-32767</cell> + <cell align="left" valign="middle">0</cell> + </row> + <row> + <cell align="left" valign="middle">OrderPolicy</cell> + <cell align="left" valign="middle">Any-, Fifo-, Priority- and Deadline-Order</cell> + <cell align="left" valign="middle">PriorityOrder</cell> + </row> + <row> + <cell align="left" valign="middle">DiscardPolicy</cell> + <cell align="left" valign="middle">RejectNewEvents, Any-, Fifo-, Lifo-, Priority- and Deadline-Order</cell> + <cell align="left" valign="middle">RejectNewEvents</cell> + </row> + <row> + <cell align="left" valign="middle">MaximumBatchSize</cell> + <cell align="left" valign="middle">long() > 0</cell> + <cell align="left" valign="middle">1</cell> + </row> + <row> + <cell align="left" valign="middle">PacingInterval</cell> + <cell align="left" valign="middle">TimeBase::TimeT (see cosTime)</cell> + <cell align="left" valign="middle">0</cell> + </row> + <row> + <cell align="left" valign="middle">StartTimeSupported</cell> + <cell align="left" valign="middle">boolean</cell> + <cell align="left" valign="middle">false</cell> + </row> + <row> + <cell align="left" valign="middle">StopTimeSupported</cell> + <cell align="left" valign="middle">boolean</cell> + <cell align="left" valign="middle">false</cell> + </row> + <row> + <cell align="left" valign="middle">MaxEventsPerConsumer</cell> + <cell align="left" valign="middle">long() > 0</cell> + <cell align="left" valign="middle">100</cell> + </row> + <row> + <cell align="left" valign="middle">Timeout</cell> + <cell align="left" valign="middle">TimeBase::TimeT (see cosTime)</cell> + <cell align="left" valign="middle">No timeout</cell> + </row> + <tcaption>Table 1: Supported QoS Settings</tcaption> + </table> + <br></br> + <br></br> + <br></br> + <br></br> + <p><em>Comments on the table 'Supported QoS Settings':</em></p> + <taglist> + <tag><em>EventReliability</em></tag> + <item>To allow full Persistent EventReliability, every event must + be stored in a stable storage which would create a relatively + huge overhead. Hence, only lightweight version of the Persistent + QoS is supported. The configuration parameters <c>max_events</c>, + <c>interval_events</c> and <c>timeout_events</c> determine + the behavior of this setting.</item> + <tag><em>ConnectionReliability</em></tag> + <item>If this QoS is set to BestEffort and a client object returns anything + other than <c>ok</c> to its associated Proxy, the Proxy will discard + all events and terminate. Using Persistent and anything other than <c>ok</c> + is returned, events will be dropped but the proxy will retry later when + next delivery is due. A child may not have Persistent while its parent + has BestEffort QoS set, e.g., Proxy vs. Admin. If <c>OBJECT_NOT_EXIST</c>, + <c>NO_PERMISSION</c> or <c>CosEventComm_Disconnected</c> is thrown, + the associated object will terminate even if this parameter is + set to Persistent.</item> + <tag><em>Priority</em></tag> + <item>This QoS will treat all events as if they have the Priority equal to + current value, unless the event itself contains a Priority setting, + this event will be treated accordingly. Note: for this property to + have any effect, the DiscardPolicy and/or OrderPolicy must be set + to PriorityOrder.</item> + <tag><em>OrderPolicy</em></tag> + <item>If set to PriorityOrder, events with the highest Priority will be + delivered first. Deadline order will forward events with shortest + expiry time first. If two events have the same priority, they will be + delivered in FIFO-order.</item> + <tag><em>DiscardPolicy</em></tag> + <item>If set to PriorityOrder and MaxEventsPerConsumer limit is + reached, events + with the lowest Priority will be discarded first. Deadline order will + discard events with shortest expiry time first.</item> + <tag><em>MaximumBatchSize</em></tag> + <item>Only valid if the object is supposed to handle a sequence of structured + events and determines the largest amount of events that may be passed + each time.</item> + <tag><em>PacingInterval</em></tag> + <item>Determines how long an object will wait before forwarding a structured + event sequence of length equal to, or less than MaximumBatchSize. + If set to 0, which is the default behavior, no timeout is used and + the events are forwarded when the MaximumBatchSize is reached.</item> + <tag><em>StartTimeSupported</em></tag> + <item>If set to true events which contains the QoS Property <c>StartTime</c> + (TimeBase::UtcT - absolute time) will not be delivered until the + StartTime value have been exceeded. See also the <c>cosTime</c> application.</item> + <tag><em>StopTimeSupported</em></tag> + <item>If set to true, events which contain the QoS Properties <c>StopTime</c> + (TimeBase::UtcT - absolute time) or <c>Timeout</c> (TimeBase::TimeT - + relative time) will be discarded if the object has not been able to + deliver the event in time. See also the <c>cosTime</c> application.</item> + <tag><em>MaxEventsPerConsumer</em></tag> + <item>The maximum number of events the associated object may store before discarding + events in the way described by the DiscardPolicy.</item> + <tag><em>Timeout</em></tag> + <item>If this QoS property is not included in the event, and the Property + <c>StopTimeSupported</c> equals true, this setting will be applied + if events cannot be delivered within its time limit.</item> + </taglist> + <warning> + <p>Several of the above QoS Properties can be changed during run-time but we strongly advice + not to since, if a relatively large amount of events are waiting for delivery, some of the + QoS settings would require a total reorder of the events. The QoS property <c>ConnectioReliability</c> + may <em>never</em> be updated during run-time since it may cause deadlock. Run-time, in this case, + means activating the Channel by sending the first event.</p> + </warning> + </section> + + <section> + <title>Setting Quality Of Service</title> + <p>Assume we have a Consumer Admin object which we want to change + the current Quality of Service. Typical usage:</p> + <code type="none"> +QoSPersistent = + [#'CosNotification_Property' + {name='CosNotification':'ConnectionReliability'(), + value=any:create(orber_tc:short(), + 'CosNotification':'Persistent'())}], +'CosNotification_QoSAdmin':set_qos(Ch, QoSPersistent), + </code> + <p>If it is not possible to set the requested QoS the <c>UnsupportedQoS</c> + exception is raised, which includes a sequence of <c>PropertyError</c>'s + describing which QoS, possible range and why is not allowed. The error + codes are:</p> + <list type="bulleted"> + <item>UNSUPPORTED_PROPERTY - QoS not supported for this type of target object.</item> + <item>UNAVAILABLE_PROPERTY - due to current QoS settings the given property + is not allowed.</item> + <item>UNSUPPORTED_VALUE - property value out of range; valid range is returned.</item> + <item>UNAVAILABLE_VALUE - due to current QoS settings the given value is + not allowed; valid range is returned.</item> + <item>BAD_PROPERTY - unrecognized property.</item> + <item>BAD_TYPE - type of supplied property is incorrect.</item> + <item>BAD_VALUE - illegal value.</item> + </list> + <p>The CosNotification_QoSAdmin interface also supports an operation + called <c>validate_qos/2</c>. The purpose of this operations is to check + if a QoS setting is supported by the target object and if so, the operation + returns additional properties which could be optionally added as well.</p> + </section> + + <section> + <title>Admin Properties</title> + <p>The cosNotification application supports the following Admin Properties:</p> + <table> + <row> + <cell align="center" valign="middle"><em>Property</em></cell> + <cell align="center" valign="middle"><em>Range</em></cell> + <cell align="center" valign="middle"><em>Default</em></cell> + </row> + <row> + <cell align="left" valign="middle">MaxQueueLength</cell> + <cell align="left" valign="middle">0</cell> + <cell align="left" valign="middle">0</cell> + </row> + <row> + <cell align="left" valign="middle">MaxConsumers</cell> + <cell align="left" valign="middle">long() >= 0</cell> + <cell align="left" valign="middle">0</cell> + </row> + <row> + <cell align="left" valign="middle">MaxSuppliers</cell> + <cell align="left" valign="middle">long() >= 0</cell> + <cell align="left" valign="middle">0</cell> + </row> + <tcaption>Table 2: Supported Admin Properties</tcaption> + </table> + <p>According to the OMG specification the default values for Admin Properties + is supposed to be <c>0</c>, which means that no limit applies to these + properties.</p> + <note> + <p>Admin Properties can only be set on a Channel Object level, i.e., + they will not have an impact on any Admin or Proxy Objects. Currently, + setting the Admin Property <c>MaxQueueLength</c> have no effect since + we cannot discard events accordingly to the Quality of Service Property + <c>DiscardPolicy</c>.</p> + </note> + </section> + </section> +</chapter> + diff --git a/lib/cosNotification/doc/src/ch_contents.xml b/lib/cosNotification/doc/src/ch_contents.xml new file mode 100644 index 0000000000..e5505951bf --- /dev/null +++ b/lib/cosNotification/doc/src/ch_contents.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>The cosNotification Application</title> + <prepared>Niclas Eklund</prepared> + <docno></docno> + <date>2000-01-31</date> + <rev>1.0</rev> + <file>ch-contents.xml</file> + </header> + + <section> + <title>Content Overview</title> + <p>The cosNotification documentation is divided into three sections: + </p> + <list type="bulleted"> + <item> + <p>PART ONE - The User's Guide + <br></br> +Description of the cosNotification Application including + services and a small tutorial demonstrating + the development of a simple service.</p> + </item> + <item> + <p>PART TWO - Release Notes + <br></br> +A concise history of cosNotification.</p> + </item> + <item> + <p>PART THREE - The Reference Manual + <br></br> + A quick reference guide, including a + brief description, to all the functions available in cosNotification.</p> + </item> + </list> + </section> + + <section> + <title>Brief Description of the User's Guide</title> + <p>The User's Guide contains the following parts:</p> + <list type="bulleted"> + <item> + <p>cosNotification overview</p> + </item> + <item> + <p>cosNotification installation</p> + </item> + <item> + <p>A tutorial example</p> + </item> + </list> + </section> +</chapter> + diff --git a/lib/cosNotification/doc/src/ch_example.xml b/lib/cosNotification/doc/src/ch_example.xml new file mode 100644 index 0000000000..8cb12bd241 --- /dev/null +++ b/lib/cosNotification/doc/src/ch_example.xml @@ -0,0 +1,169 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>cosNotification Examples</title> + <prepared>Niclas Eklund</prepared> + <docno></docno> + <date>2000-01-31</date> + <rev>A</rev> + <file>ch_example.xml</file> + </header> + + <section> + <title>A Tutorial on How to Create a Simple Service</title> + + <section> + <title>Interface Design</title> + <p>To use the cosNotification application <em>clients</em> must be implemented. + There are twelve types of clients: </p> + <list type="bulleted"> + <item>Structured Push Consumer</item> + <item>Sequence Push Consumer </item> + <item>Any Push Consumer</item> + <item>Structured Pull Consumer</item> + <item>Sequence Pull Consumer</item> + <item>Any Pull Consumer</item> + <item>Structured Push Supplier</item> + <item>Sequence Push Supplier</item> + <item>Any Push Supplier</item> + <item>Structured Pull Supplier</item> + <item>Sequence Pull Supplier</item> + <item>Any Pull Supplier</item> + </list> + <p>The interfaces for these participants are defined in <em>CosNotification.idl</em> + and <em>CosNotifyComm.idl</em>.</p> + </section> + + <section> + <title>Generating a Client Interface</title> + <p>We start by creating an interface which inherits from the correct interface, e.g., <em>CosNotifyComm::SequencePushConsumer</em>. Hence, + we must also implement all operations defined in the SequencePushConsumer interface. The IDL-file could look like: </p> + <code type="c"><![CDATA[ +#ifndef _MYCLIENT_IDL +#define _MYCLIENT_IDL +#include <CosNotification.idl> +#include <CosNotifyComm.idl> + +module myClientImpl { + + interface ownInterface:CosNotifyComm::SequencePushConsumer { + + void ownFunctions(in any NeededArguments) + raises(Systemexceptions,OwnExceptions); + + }; +}; + +#endif + ]]></code> + <p>Run the IDL compiler on this file by calling the <c>ic:gen/1</c> function. + This will produce the API named <c>myClientImpl_ownInterface.erl</c>. + After generating the API stubs and the server skeletons it is time to + implement the servers and if no special options are sent + to the IDl compiler the file name is <c>myClientImpl_ownInterface_impl.erl</c>.</p> + <p>The callback module must contain the necessary functions inherited from + <em>CosNotification.idl</em> and <em>CosNotifyComm.idl</em>.</p> + </section> + + <section> + <title>How to Run Everything</title> + <p>Below is a short transcript on how to run cosNotification. </p> + <code type="none"> + +%% Start Mnesia and Orber +mnesia:delete_schema([node()]), +mnesia:create_schema([node()]), +orber:install([node()]), +mnesia:start(), +orber:start(), + +%% If cosEvent not installed before it is necessary to do it now. +cosEventApp:install(), + +%% Install cosNotification in the IFR. +cosNotificationApp:install(30), + +%% Register the application specific Client implementations +%% in the IFR. +'oe_myClientImpl':'oe_register'(), + +%% Start the cosNotification application. +cosNotificationApp:start(), + +%% Start a factory using the default configuration +ChFac = cosNotificationApp:start_factory(), +%% ... or use configuration parameters. +ChFac = cosNotificationApp:start_factory([]), + +%% Create a new event channel. Note, if no QoS- anr/or Admin-properties +%% are supplied (i.e. empty list) the default settings are used. +{Ch, ChID} = 'CosNotifyChannelAdmin_EventChannelFactory': + create_channel(ChFac, DefaultQoS, DefaultAdmin), + +%% Retrieve a SupplierAdmin and a Consumer Admin. +{AdminSupplier, ASID}= + 'CosNotifyChannelAdmin_EventChannel':new_for_suppliers(Ch, 'OR_OP'), +{AdminConsumer, ACID}= +\011'CosNotifyChannelAdmin_EventChannel':new_for_consumers(Ch,'OR_OP'), + +%% Use the corresponding Admin object to get access to wanted Proxies + +%% Create a Push Consumer Proxie, i.e., the Client Push Supplier will +%% push events to this Proxy. +{StructuredProxyPushConsumer,ID11}= 'CosNotifyChannelAdmin_SupplierAdmin': + obtain_notification_push_consumer(AdminSupplier, 'STRUCTURED_EVENT')), + +%% Create Push Suppliers Proxies, i.e., the Proxy will push events to the +%% registered Push Consumers. +{ProxyPushSupplier,I4D}='CosNotifyChannelAdmin_ConsumerAdmin': + obtain_notification_push_supplier(AdminConsumer, 'ANY_EVENT'), +{StructuredProxyPushSupplier,ID5}='CosNotifyChannelAdmin_ConsumerAdmin': + obtain_notification_push_supplier(AdminConsumer, 'STRUCTURED_EVENT'), +{SequenceProxyPushSupplier,ID6}='CosNotifyChannelAdmin_ConsumerAdmin': + obtain_notification_push_supplier(AdminConsumer, 'SEQUENCE_EVENT'), + +%% Create application Clients. We can, for example, start the Clients +%% our selves or look them up in the naming service. This is application +%% specific. +SupplierClient = ... +ConsumerClient1 = ... +ConsumerClient2 = ... +ConsumerClient3 = ... + +%% Connect each Client to corresponding Proxy. +'CosNotifyChannelAdmin_StructuredProxyPushConsumer': + connect_structured_push_supplier(StructuredProxyPushConsumer, SupplierClient), +'CosNotifyChannelAdmin_ProxyPushSupplier': + connect_any_push_consumer(ProxyPushSupplier, ConsumerClient1), +'CosNotifyChannelAdmin_StructuredProxyPushSupplier': + connect_structured_push_consumer(StructuredProxyPushSupplier, ConsumerClient2), +'CosNotifyChannelAdmin_SequenceProxyPushSupplier': + connect_sequence_push_consumer(SequenceProxyPushSupplier, ConsumerClient3), + </code> + <p>The example above, exemplifies a notification system where the SupplierClient + in some way generates event and pushes them to the proxy. The push supplier + proxies will eventually push the events to each ConsumerClient.</p> + </section> + </section> +</chapter> + diff --git a/lib/cosNotification/doc/src/ch_install.xml b/lib/cosNotification/doc/src/ch_install.xml new file mode 100644 index 0000000000..3463815bc5 --- /dev/null +++ b/lib/cosNotification/doc/src/ch_install.xml @@ -0,0 +1,146 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Installing cosNotification</title> + <prepared>Niclas Eklund</prepared> + <docno></docno> + <date>2000-01-31</date> + <rev></rev> + <file>ch-install.xml</file> + </header> + + <section> + <title>Installation Process </title> + <p>This chapter describes how to install <seealso marker="cosNotificationApp">cosNotificationApp</seealso> + in an Erlang Environment. + </p> + + <section> + <title>Preparation</title> + <p>Before starting the installation process for cosNotification, + the application Orber must be running.</p> + </section> + + <section> + <title>Configuration</title> + <p>When using the Notification Service the <c>cosNotification</c> application + first must be installed using <c>cosNotificationApp:install()</c> or + <c>cosNotificationApp:install(Seconds)</c>, followed by <c>cosNotificationApp:start()</c>.</p> + <p>Then the <seealso marker="CosNotifyChannelAdmin_EventChannelFactory">Event Channel Factory</seealso> + must be started:</p> + <list type="bulleted"> + <item><c>cosNotificationApp:start_global_factory()</c> - starts and returns a reference to a factory using default configuration parameters. + This operation should be used for a multi-node Orber.</item> + <item><c>cosNotificationApp:start_global_factory(Options)</c> - starts and returns a reference to a factory using given configuration parameters. + This operation should be used for a multi-node Orber.</item> + <item><c>cosNotificationApp:start_factory()</c> - starts and returns a reference to a factory using default configuration parameters.</item> + <item><c>cosNotificationApp:start_factory(Options)</c> - starts and returns a reference to a factory using given configuration parameters.</item> + </list> + <p>The following options exist:</p> + <list type="bulleted"> + <item><c>{pullInterval, Seconds}</c> - determine how often Proxy Pull + Consumers will check for new events with the client application. The + default value is 20 seconds.</item> + <item><c>{filterOp, OperationType}</c> - determine which type of Administrator + objects should be started, i.e., <c>'OR_OP'</c> or <c>'AND_OP'</c>. + The default value is <c>'OR_OP'</c>.</item> + <item><c>{timeService, TimeServiceObj | 'undefined'}</c> - to be able to use + Start and/or Stop QoS this option must be used. See the function <c>start_time_service/2</c> + in the <c>cosTime</c> application. The default value is <c>'undefined'</c>.</item> + <item><c>{filterOp, OperationType}</c> - determine which type of Administrator + objects should be started, i.e., <c>'OR_OP'</c> or <c>'AND_OP'</c>. + The default value is <c>'OR_OP'</c>.</item> + <item><c>{gcTime, Seconds}</c> - this option determines how often, for example, proxies + will garbage collect expired events. The default value is 60.</item> + <item><c>{gcLimit, Amount}</c> - determines how many events will be stored before, for + example, proxies will garbage collect expired events. The default value is 50. This + option is tightly coupled with the QoS property <c>MaxEventsPerConsumer</c>, i.e., + the <c>gcLimit</c> should be less than <c>MaxEventsPerConsumer</c> and greater than 0.</item> + </list> + <p>It is possible to define a set of global configuration parameters:</p> + <table> + <row> + <cell align="center" valign="middle"><em>Key</em></cell> + <cell align="center" valign="middle"><em>Range</em></cell> + <cell align="center" valign="middle"><em>Default</em></cell> + </row> + <row> + <cell align="left" valign="middle">type_check</cell> + <cell align="left" valign="middle">true | false</cell> + <cell align="left" valign="middle">true</cell> + </row> + <row> + <cell align="left" valign="middle">notify</cell> + <cell align="left" valign="middle">atom() | false</cell> + <cell align="left" valign="middle">false</cell> + </row> + <row> + <cell align="left" valign="middle">max_events</cell> + <cell align="left" valign="middle">integer() > 0</cell> + <cell align="left" valign="middle">50</cell> + </row> + <row> + <cell align="left" valign="middle">interval_events</cell> + <cell align="left" valign="middle">integer() > 0</cell> + <cell align="left" valign="middle">10000 milliseconds</cell> + </row> + <row> + <cell align="left" valign="middle">timeout_events</cell> + <cell align="left" valign="middle">integer() > interval_events</cell> + <cell align="left" valign="middle">3000000 milliseconds</cell> + </row> + <tcaption>Global Configuration Parameters</tcaption> + </table> + <p><em>Comments on the table 'Global Configuration Parameters':</em></p> + <taglist> + <tag><em>type_check</em></tag> + <item>Determine if supplied IOR:s shall be type checked, i.e. invoking + corba_object:is_a/2, or not.</item> + <tag><em>notify</em></tag> + <item>The given value shall point to an existing module exporting + a function (arity 1) called <em>terminated</em>. This operation + is invoked when a proxy terminates and the argument is a list + containing <c>{proxy, IOR}</c>, <c>{client, IOR}</c> and + <c>{reason, term()}</c>. The return value is ignored.</item> + <tag><em>max_events</em></tag> + <item>If a supplier proxy has not been able to push events to a + consumer and the queue exceeds this limit, then the proxy will + terminate. For this option to have any effect, the + <c>EventReliability</c> and <c>ConnectionReliability</c> QoS + parameters must be set to <c>Persistent</c>. For more information, + see also the <seealso marker="ch_QoS">QoS</seealso> chapter.</item> + <tag><em>interval_events</em></tag> + <item>The same requirements as for <c>max_events</c>. When a supplier + proxy detects problems when trying to push events, this parameter + determines how often it should try to call the consumer.</item> + <tag><em>timeout_events</em></tag> + <item>The same requirements as for <c>max_events</c>. If the + proxy has not been able to contact the consumer and this + time-limit is reached, then the proxy will terminate.</item> + </taglist> + <p>The Factory is now ready to use. For a more detailed description see + <seealso marker="ch_example">Examples</seealso>.</p> + </section> + </section> +</chapter> + diff --git a/lib/cosNotification/doc/src/ch_introduction.xml b/lib/cosNotification/doc/src/ch_introduction.xml new file mode 100644 index 0000000000..63e4a58bd5 --- /dev/null +++ b/lib/cosNotification/doc/src/ch_introduction.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Introduction to cosNotification</title> + <prepared>Niclas Eklund</prepared> + <docno></docno> + <date>2000-01-31</date> + <rev></rev> + <file>ch_introduction.xml</file> + </header> + + <section> + <title>Overview</title> + <p>The cosNotification application is a Notification Service compliant with the <url href="http://www.omg.org">OMG</url> + Notification Service CosNotification. + </p> + + <section> + <title>Purpose and Dependencies</title> + <p><em>cosNotification</em> is dependent on <em>Orber-3.1.7</em> or later, + which provides CORBA functionality in an Erlang environment, + <em>cosTime-1.0.1</em> or later and IDL-files to be compiled using <em>IC-4.0.4</em> or later.</p> + </section> + + <section> + <title>Prerequisites</title> + <p>To fully understand the concepts presented in the + documentation, it is recommended that the user is familiar + with distributed programming, CORBA and the Orber application. + </p> + <p>Recommended reading includes books recommended by the <em>OMG</em> + and <em>Open Telecom Platform Documentation Set</em>. It is also + helpful to have read <em>Concurrent Programming in Erlang</em>.</p> + </section> + </section> +</chapter> + diff --git a/lib/cosNotification/doc/src/ch_system.xml b/lib/cosNotification/doc/src/ch_system.xml new file mode 100644 index 0000000000..126bba5f0b --- /dev/null +++ b/lib/cosNotification/doc/src/ch_system.xml @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>The Notification Service Components</title> + <prepared>Niclas Eklund</prepared> + <docno></docno> + <date>2000-04-13</date> + <rev></rev> + <file>ch_system.xml</file> + </header> + + <section> + <title>The Notification Service Components</title> + <p>This chapter describes the Notification Service Components and how they + interact.</p> + + <section> + <title>Components</title> + <p>There are seven components in the OMG Notification Service architecture. + These are described below: </p> + <marker id="notificationFlow"></marker> + <image file="notificationFlow.gif"> + <icaption> +Figure 1: The Notification Service Components.</icaption> + </image> + <list type="bulleted"> + <item><em>Event Channel:</em> acts as a factory for Administrator objects. + Allows clients to set Administrative Properties.</item> + <item><em>Supplier Administrators:</em> acts as a factory for Proxy Consumers. + Administrators are started as <c>'AND_OP'-</c> or <c>'OR_OP'-</c>type, + which determines if events must be validated using both the Administrators + associated Filter and/or its Proxy children Filters.</item> + <item><em>Consumer Administrators:</em> acts in the same way as Supplier Administrators + but handle Proxy Suppliers.</item> + <item><em>Consumer Proxy:</em> is connected to a client application. Can be + started as <c>Pull</c> or <c>Push</c> object. If the proxy is Push style + the client application must push events to the Proxy, otherwise the Proxy is + supposed to Pull events. The <c>CosNotification::AdminProperties</c> is + used to set the pacing interval.</item> + <item><em>Supplier Proxy:</em> Acts in a similar way as the Consumer Proxy, but + if started as a <c>Push</c> proxy it will push events to the client + application.</item> + <item><em>Filters:</em> used to filter events. May be associated with Proxies + and Administrators.</item> + <item><em>Mapping Filters:</em> used to override events Quality of Service + settings. Can only be associated with Consumer Administrators and + Proxy Suppliers.</item> + </list> + <p>When a Proxy is started it is set to accept <c>CORBA::Any</c>, + <c>CosNotification::StructuredEvent</c> or <c>CosNotification::EventBatch</c> + (a sequence of structured events).</p> + <p>If a Proxy is supposed to deliver structured events to a client application + and receives an <c>CORBA::Any</c> event, the event is converted to a + structured event with <c>type_name</c> set to <c>"%ANY"</c> and the + event is stored in <c>remainder_of_body</c>.</p> + <p>If a Proxy is supposed to deliver <c>CORBA::Any</c> events to a client application + and receives a structured event, the event is stored in an Any type. The + Any Type Code will be equal to the <c>CosNotification::StructuredEvent</c> + Type Code.</p> + </section> + </section> +</chapter> + diff --git a/lib/cosNotification/doc/src/cosNotificationApp.xml b/lib/cosNotification/doc/src/cosNotificationApp.xml new file mode 100644 index 0000000000..08bac7f810 --- /dev/null +++ b/lib/cosNotification/doc/src/cosNotificationApp.xml @@ -0,0 +1,308 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>cosNotificationApp</title> + <prepared>Niclas Eklund</prepared> + <responsible>Niclas Eklund</responsible> + <docno></docno> + <approved>Niclas Eklund</approved> + <checked></checked> + <date>2000-01-31</date> + <rev>PA1</rev> + </header> + <module>cosNotificationApp</module> + <modulesummary>The main module of the cosNotification application.</modulesummary> + <description> + <p>To get access to the record definitions for the structures use: <br></br> +<c>-include_lib("cosNotification/include/*.hrl").</c></p> + <p>This module contains the functions for starting and stopping the application.</p> + </description> + <funcs> + <func> + <name>install() -> Return</name> + <fsummary>Install the cosNotification application</fsummary> + <type> + <v>Return = ok | {'EXCEPTION', E}</v> + </type> + <desc> + <p>This operation installs the cosNotification application.</p> + </desc> + </func> + <func> + <name>install(Seconds) -> Return</name> + <fsummary>Install the cosNotification application</fsummary> + <type> + <v>Return = ok | {'EXCEPTION', E}</v> + </type> + <desc> + <p>This operation installs the cosNotification application using <c>Seconds</c> + delay between each block, currently 6, of IFR-registrations. This approach + spreads the IFR database access over a period of time to allow other + applications to run smother.</p> + </desc> + </func> + <func> + <name>install_event() -> Return</name> + <fsummary>Install the necessary cosEvent interfaces</fsummary> + <type> + <v>Return = ok | {'EXCEPTION', E}</v> + </type> + <desc> + <p>This operation, which may <em>only</em> be used if it is impossible to + upgrade to <em>cosEvent-2.0</em> or later, installs the necessary + cosEvent interfaces. If cosEvent-2.0 is available, use + <c>cosEventApp:install()</c> instead.</p> + </desc> + </func> + <func> + <name>install_event(Seconds) -> Return</name> + <fsummary>Install the necessary cosEvent interfaces</fsummary> + <type> + <v>Return = ok | {'EXCEPTION', E}</v> + </type> + <desc> + <p>This operation, which may <em>only</em> be used if it is impossible to + upgrade to <em>cosEvent-2.0</em> or later, installs the necessary cosEvent + interfaces using <c>Seconds</c> delay between each block of + IFR-registrations. If cosEvent-2.0 is available, use + <c>cosEventApp:install()</c> instead.</p> + </desc> + </func> + <func> + <name>uninstall() -> Return</name> + <fsummary>Uninstall the cosNotification application</fsummary> + <type> + <v>Return = ok | {'EXCEPTION', E}</v> + </type> + <desc> + <p>This operation uninstalls the cosNotification application.</p> + </desc> + </func> + <func> + <name>uninstall(Seconds) -> Return</name> + <fsummary>Uninstall the cosNotification application</fsummary> + <type> + <v>Return = ok | {'EXCEPTION', E}</v> + </type> + <desc> + <p>This operation uninstalls the cosNotification application using <c>Seconds</c> + delay between each block, currently 6, of IFR-unregistrations. This approach + spreads the IFR database access over a period of time to allow other + applications to run smother.</p> + </desc> + </func> + <func> + <name>uninstall_event() -> Return</name> + <fsummary>Uninstall the inherited cosEvent interfaces</fsummary> + <type> + <v>Return = ok | {'EXCEPTION', E}</v> + </type> + <desc> + <p>This operation uninstalls the inherited cosEvent interfaces. If cosEvent + is in use this function may not be used. This function may only be used if + <c>cosNotificationApp:install_event/1/2</c> was used. If not, use + <c>cosEventApp:uninstall()</c> instead.</p> + </desc> + </func> + <func> + <name>uninstall_event(Seconds) -> Return</name> + <fsummary>Uninstall the inherited cosEvent interfaces</fsummary> + <type> + <v>Return = ok | {'EXCEPTION', E}</v> + </type> + <desc> + <p>This operation uninstalls the inherited cosEvent interfaces, using <c>Seconds</c> + delay between each block of IFR-unregistrations. If cosEvent + is in use this function may not be used. This function may only be used if + <c>cosNotificationApp:install_event/1/2</c> was used. If not, use + <c>cosEventApp:uninstall()</c> instead.</p> + </desc> + </func> + <func> + <name>start() -> Return</name> + <fsummary>Start the cosNotification application</fsummary> + <type> + <v>Return = ok | {error, Reason}</v> + </type> + <desc> + <p>This operation starts the cosNotification application.</p> + </desc> + </func> + <func> + <name>stop() -> Return</name> + <fsummary>Stop the cosNotification application</fsummary> + <type> + <v>Return = ok | {error, Reason}</v> + </type> + <desc> + <p>This operation stops the cosNotification application.</p> + </desc> + </func> + <func> + <name>start_global_factory() -> ChannelFactory</name> + <fsummary>Start a global channel factory as default</fsummary> + <type> + <v>ChannelFactory = #objref</v> + </type> + <desc> + <p>This operation creates a + <seealso marker="CosNotifyChannelAdmin_EventChannelFactory">Event Channel Factory</seealso> + should be used for a multi-node Orber. + The Factory is used to create a new + <seealso marker="CosNotifyChannelAdmin_EventChannel">channel</seealso>. </p> + </desc> + </func> + <func> + <name>start_global_factory(Options) -> ChannelFactory</name> + <fsummary>Start a global channel factory with options</fsummary> + <type> + <v>Options = [Option]</v> + <v>Option = {pullInterval, Seconds} | {filterOp, Op} | {gcTime, Seconds} | {gcLimit, Anount} | {timeService, #objref}</v> + <v>ChannelFactory = #objref</v> + </type> + <desc> + <p>This operation creates a + <seealso marker="CosNotifyChannelAdmin_EventChannelFactory">Event Channel Factory</seealso> and + should be used for a multi-node Orber. + The Factory is used to create a new + <seealso marker="CosNotifyChannelAdmin_EventChannel">channel</seealso>. </p> + <p></p> + <list type="bulleted"> + <item><c>{pullInterval, Seconds}</c> - determine how often Proxy Pull + Consumers will check for new events with the client application. The + default value is 20 seconds.</item> + <item><c>{filterOp, OperationType}</c> - determine which type of Administrator + objects should be started, i.e., <c>'OR_OP'</c> or <c>'AND_OP'</c>. + The default value is <c>'OR_OP'</c>.</item> + <item><c>{timeService, TimeServiceObj | 'undefined'}</c> - to be able to use + Start and/or Stop QoS this option must be used. See the function <c>start_time_service/2</c> + in the <c>cosTime</c> application. The default value is <c>'undefined'</c>.</item> + <item><c>{filterOp, OperationType}</c> - determine which type of Administrator + objects should be started, i.e., <c>'OR_OP'</c> or <c>'AND_OP'</c>. + The default value is <c>'OR_OP'</c>.</item> + <item><c>{gcTime, Seconds}</c> - this option determines how often, for example, proxies + will garbage collect expired events. The default value is 60.</item> + <item><c>{gcLimit, Amount}</c> - determines how many events will be stored before, for + example, proxies will garbage collect expired events. The default value is 50. This + option is tightly coupled with the QoS property <c>MaxEventsPerConsumer</c>, i.e., + the <c>gcLimit</c> should be less than <c>MaxEventsPerConsumer</c> and greater than 0.</item> + </list> + </desc> + </func> + <func> + <name>start_factory() -> ChannelFactory</name> + <fsummary>Start a channel factory as default</fsummary> + <type> + <v>ChannelFactory = #objref</v> + </type> + <desc> + <p>This operation creates a + <seealso marker="CosNotifyChannelAdmin_EventChannelFactory">Event Channel Factory</seealso>. + The Factory is used to create a new + <seealso marker="CosNotifyChannelAdmin_EventChannel">channel</seealso>. </p> + </desc> + </func> + <func> + <name>start_factory(Options) -> ChannelFactory</name> + <fsummary>Start a channel factory with options</fsummary> + <type> + <v>Options = [Option]</v> + <v>Option = {pullInterval, Seconds} | {filterOp, Op} | {gcTime, Seconds} | {gcLimit, Amount} | {timeService, #objref}</v> + <v>ChannelFactory = #objref</v> + </type> + <desc> + <p>This operation creates a + <seealso marker="CosNotifyChannelAdmin_EventChannelFactory">Event Channel Factory</seealso>. + The Factory is used to create a new + <seealso marker="CosNotifyChannelAdmin_EventChannel">channel</seealso>. </p> + </desc> + </func> + <func> + <name>stop_factory(ChannelFactory) -> Reply</name> + <fsummary>Terminate the target object</fsummary> + <type> + <v>ChannelFactory = #objref</v> + <v>Reply = ok | {'EXCEPTION', E}</v> + </type> + <desc> + <p>This operation stop the target channel factory.</p> + </desc> + </func> + <func> + <name>start_filter_factory() -> FilterFactory</name> + <fsummary>Start a filter factory</fsummary> + <type> + <v>FilterFactory = #objref</v> + </type> + <desc> + <p>This operation creates a + <seealso marker="CosNotifyFilter_FilterFactory">Filter Factory</seealso>. + The Factory is used to create a new + <seealso marker="CosNotifyFilter_Filter">Filter's</seealso> and + <seealso marker="CosNotifyFilter_MappingFilter">MappingFilter's</seealso>. </p> + </desc> + </func> + <func> + <name>stop_filter_factory(FilterFactory) -> Reply</name> + <fsummary>Terminate the target object</fsummary> + <type> + <v>FilterFactory = #objref</v> + <v>Reply = ok | {'EXCEPTION', E}</v> + </type> + <desc> + <p>This operation stop the target filter factory.</p> + </desc> + </func> + <func> + <name>create_structured_event(Domain, Type, Event, VariableHeader, FilterableBody, BodyRemainder) -> Reply</name> + <fsummary>Create a structured event</fsummary> + <type> + <v>Domain = string()</v> + <v>Type = string()</v> + <v>Event = string()</v> + <v>VariableHeader = [CosNotification::Property]</v> + <v>FilterableBody = [CosNotification::Property]</v> + <v>BodyRemainder = #any data-type</v> + <v>Reply = CosNotification::StructuredEvent | {'EXCEPTION', E}</v> + </type> + <desc> + <p>An easy way to create a structured event is to use this function. + Simple typechecks are performed and if one of the arguments is not + correct a 'BAD_PARAM' exception is thrown.</p> + </desc> + </func> + <func> + <name>type_check() -> Reply</name> + <fsummary>Return the value of the configuration parameter type_check</fsummary> + <type> + <v>Reply = true | false</v> + </type> + <desc> + <p>This operation returns the value of the configuration parameter + <c>type_check</c>.</p> + </desc> + </func> + </funcs> + +</erlref> + diff --git a/lib/cosNotification/doc/src/eventstructure.gif b/lib/cosNotification/doc/src/eventstructure.gif Binary files differnew file mode 100644 index 0000000000..879c96f980 --- /dev/null +++ b/lib/cosNotification/doc/src/eventstructure.gif diff --git a/lib/cosNotification/doc/src/eventstructure.ps b/lib/cosNotification/doc/src/eventstructure.ps new file mode 100644 index 0000000000..a9ace9a703 --- /dev/null +++ b/lib/cosNotification/doc/src/eventstructure.ps @@ -0,0 +1,2462 @@ +%!PS-Adobe-3.0 +%%Creator: (ImageMagick) +%%Title: (eventstructure.ps) +%%CreationDate: (Tue Apr 18 13:35:41 2000) +%%BoundingBox: 131 284 481 508 +%%DocumentData: Clean7Bit +%%LanguageLevel: 1 +%%Orientation: Portrait +%%PageOrder: Ascend +%%Pages: 1 +%%EndComments + +%%BeginDefaults +%%PageOrientation: Portrait +%%EndDefaults + +%%BeginProlog +% +% Display a color image. The image is displayed in color on +% Postscript viewers or printers that support color, otherwise +% it is displayed as grayscale. +% +/buffer 512 string def +/byte 1 string def +/color_packet 3 string def +/pixels 768 string def + +/DirectClassPacket +{ + % + % Get a DirectClass packet. + % + % Parameters: + % red. + % green. + % blue. + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/DirectClassImage +{ + % + % Display a DirectClass image. + % + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { DirectClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayDirectClassPacket } image + } ifelse +} bind def + +/GrayDirectClassPacket +{ + % + % Get a DirectClass packet; convert to grayscale. + % + % Parameters: + % red + % green + % blue + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/GrayPseudoClassPacket +{ + % + % Get a PseudoClass packet; convert to grayscale. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassPacket +{ + % + % Get a PseudoClass packet. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassImage +{ + % + % Display a PseudoClass image. + % + % Parameters: + % class: 0-PseudoClass or 1-Grayscale. + % + currentfile buffer readline pop + token pop /class exch def pop + class 0 gt + { + currentfile buffer readline pop + token pop /depth exch def pop + /grays columns 8 add depth sub depth mul 8 idiv string def + columns rows depth + [ + columns 0 0 + rows neg 0 rows + ] + { currentfile grays readhexstring pop } image + } + { + % + % Parameters: + % colors: number of colors in the colormap. + % colormap: red, green, blue color packets. + % + currentfile buffer readline pop + token pop /colors exch def pop + /colors colors 3 mul def + /colormap colors string def + currentfile colormap readhexstring pop pop + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { PseudoClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayPseudoClassPacket } image + } ifelse + } ifelse +} bind def + +/DisplayImage +{ + % + % Display a DirectClass or PseudoClass image. + % + % Parameters: + % x & y translation. + % x & y scale. + % label pointsize. + % image label. + % image columns & rows. + % class: 0-DirectClass or 1-PseudoClass. + % compression: 0-RunlengthEncodedCompression or 1-NoCompression. + % hex color packets. + % + gsave + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + x y translate + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + currentfile buffer readline pop + token pop /pointsize exch def pop + /Helvetica findfont pointsize scalefont setfont + x y scale + currentfile buffer readline pop + token pop /columns exch def + token pop /rows exch def pop + currentfile buffer readline pop + token pop /class exch def pop + currentfile buffer readline pop + token pop /compression exch def pop + class 0 gt { PseudoClassImage } { DirectClassImage } ifelse + grestore + showpage +} bind def +%%EndProlog +%%Page: 1 1 +%%PageBoundingBox: 131 284 481 508 +%%BeginData: +DisplayImage +131 284 +350.000000 224.000000 +12 +350 224 +1 +1 +1 +8 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99553300 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000335599ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff990000000000224444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444422000000000099ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffee00eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd11 +000033aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa33000011dd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee00eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa00aaffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff66000044eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffee44000066ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffaa00aaffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff770077ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffee000011eeffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee110000eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770077ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff330033ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffbb000066ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff660000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffff33 +0033ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee0000 +00eeffffffffffffffffffffffffffffffffffffffffffffffffffffff88000077ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffeebbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77000099ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee000000eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffaa440044aaffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa00ff +ffffffffffffffffffffffffffffffffffffff22ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffaa440044aaffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff7777007777ffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffff7777007777ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff33bb00bb33ffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffee44004400ee441155ccffbb22770077440077ff221166ffaa33 +ffbb22660077ffffffffffffbb22660077ff221166ffbb22770077440077ee440044ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff33bb00bb33ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffee00ff00ff00eeff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +66ccffdd0044ccffcc22ffff00ffee00ffee00ffaaff00ffff00ffff00ffdd00ffffffff +ffffff00ffdd00ffaaff00ffff00ffee00ffee0077000000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffee00ff00ff00eeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffaa44ff00ff44aaffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff0000eeffff00 +ffff00ffff00ffff00ff779900ffff00ffff00ffff00ffffffffffffff00ffff00ff7799 +00ffff00ffff00ffff0044eeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffaa44ff00ff44aaffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff7777ff00ff7777ffffffffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff2277ffff003388ffee33ffff00ffff00ffff0088 +33ff00ffff00ffff00ffff00ffffffffffffff00ffff008833ff00ffff00ffff00ffff00 +6677ffeebbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffff77 +77ff00ff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff33bb +ff00ffbb33ffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffbb22006633b1552222ccff550077cc0077aa008500772277bb00ccbb00dd +aa00eeffffffffffbb00ddaa008f00772277550077cc0077aa00b1220066ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffff33bbff00ffbb33ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffee00ffff00ffff00eeffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffee00ffff00ffff00eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffaa44ffff00ffff44aaffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000000077ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +ffffffffaa44ffff00ffff44aaffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff9999ffff00ffff9999ffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff9999ffff00ff +ff9999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff77000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000bbffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +eebbffffffffffffffffffffffffffffffffffffffffffffffeebbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff +ffffffdd0011000022ffff22ffffffffffffffffffffffffffffaa00ffffffee00ddffff +aa00eeffffffffffffffffffffffffaa00ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff00ffffffaaff +ffffffffffffffffffffffffffffffffff00ffffffff00ffffffff00ffffffffffffffff +ffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff00ffffffffffffffffff00ffffbbbbffaa33ff6611775555ee44 +0044ffee44004400ffffffff00ffffffff00ffee440044ff221166ffee44004400ffee44 +004499227777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +00ffffffffffffffffff00000000bbffff00ffff8866aaff77000000bb66ccffdd00ffff +ffff000000000000ff77000000bbaaff00ff66ccffdd00ff77000000bb00ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff +00ffffeeddffff00ffffff00ccff44eeffffff00ffffff00ffffffff00ffffffff00ff44 +eeffffff779900ff00ffffff00ff44eeffffff00ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffddffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff00ffffffffffffffffff00ffffffffffff00ffff +88bb33ff6677ffeebb2277ffff00ffffffff00ffffffff00ff6677ffee6433ff00ff2277 +ffff00ff6677ffeebb00ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffee22ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff00ffffffffffffffffbb0000bbffffffbb00ccbb66ff004496220066ffbb +22006633ddffffbb0099eeddaa00ddcc2200669900772277bb22006633ddcc220066aa00 +55ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff440000881177cc448f22661199ffee440044ffffffffffffbb22 +660077ff221166ffbb22770077440077ffee440044ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff00ffff22dddd99ff00eeaa22ff77000000bbffffffffffff00ffdd00ffaaff00ffff00 +ffee00ffee00ff77000000bbffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff887799ffff00 +ffff00ff44eeffffffffffffffffff00ffff00ff779900ffff00ffff00ffff00ff44eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00ffffee2288ffff00ffcc44ff6677ffeebbff +ffffffffff00ffff008833ff00ffff00ffff00ffff00ff6677ffeebbffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff2266ffff77ccffff002222ccffcc220066ffffffffffffbb00ddaa008f +00772277550077cc0077aa00ddcc220066ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff99ffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff7744ccffffff00ffffffff +ffffffffff000000000077ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff1100eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffccffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff77000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000bbffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffff9999ffff00ffff9999ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffaa44ffff00ffff44aaffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffee00ffff00ffff00eeffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffff33bbff +00ffbb33ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffffffffffffffffffffffffffffff7777ff00ff7777ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffddffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffaa44ff00ff44aaffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffee22ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffee00ff00ff00eeffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffee440044ff4411eeee55df440044ffbb22660077440000ffffff +ffffffbb22660077ff221166ffbb22770077440077ee440044ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff33bb00bb33ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +77000000bbee22ddddaa77000000bbff00ffdd00ff00ffffffffffffffff00ffdd00ffaa +ff00ffff00ffee00ffee0077000000bbffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7777007777ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff44eeffffffff997799ff +44eeffffffff00ffff00ff00ffffffffffffffff00ffff00ff779900ffff00ffff00ffff +0044eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffaa440044aaffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff6677ffeebbffee3399ff6677ffeebbff00ffff00 +ff00ffffffffffffffff00ffff008833ff00ffff00ffff00ffff006677ffeebbffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee000000eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffcc220066ffffff66ddffcc220066ffbb00ddaa00ee2266ffffffffffffbb +00ddaa008f00772277550077cc0077aa00b1220066ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff330033ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff770077ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000000077ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffaa00aaffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffee00ee +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff77000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee +bbffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffdd0011000022ffffffffffffffffffffffffffffffffffff +ddffffffee00ddffffaa00eeffffffffffffffffffffffffffaa00ffffffffffffffffff +ffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffee00eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff00ffffffaaffffffffffffffffffffffffffffffffffee22ffffffff00ffffffff +00ffffffffffffffffffffffffffffff00ffffffffffffffffffffffff00ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffaa00aaffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffddbbff44 +11eeee55df440044ffbb22660077ff440000ffffff00ffffffff00ffee440044ffff2211 +66ffee44004400ee440044ff99227777ffffff00ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770077ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff00000000bbffee22ddddaa77000000bbff +00ffdd00ffff00ffffffff000000000000ff77000000bbffaaff00ff66ccffdd00770000 +00bbff00ffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffff33 +0033ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff00ffffeeddffff997799ff44eeffffffff00ffff00ffff00ffffff +ff00ffffffff00ff44eeffffffff779900ff00ffffff0044eeffffffff00ffffffffff00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffeebbffffffffffee2233ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffff +ffffffffffffffffffeebbffffffffffee2233ffffffffffffffffffffffffffffffffbb +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee000000eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +ffffffeebbffee3399ff6677ffeebbff00ffff00ffff00ffffffff00ffffffff00ff6677 +ffeebb8833ff00ff2277ffff006677ffeebbff00ffffffffff00ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffaa +00ffffffffff66ee77ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffaa +00ffffffffff66ee77ffffffffffffffffffffffffffffffcc00ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffaa440044aaffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffbb0077110000ddffff66ddff +cc220066ffbb00ddaa00eeff2266ffffbb0099eeddaa00ddcc220066ff9900772277bb22 +006633b1220066ffaa0055ffffffff00ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffff00ffffffffff11ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff7777ffffffffffffffffffffffffffff00ffffffffff11ffffff +ffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffff7777007777ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffee441155ccff00660077ff440000bbffffffffffbb22660077ff +221166ffbb22770077440077ee440044ffffffffffffffffffffffffffffffffffffffff +7777ffffffffffffffffee441155ccff00660077ff440000bbffffffffff4411eeee55ee +221166ffff00ff9900bb0000ee440044ffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff33bb00bb33ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +44ccffcc22ff00eecc00ffff00ffffffffffffffff00ffdd00ffaaff00ffff00ffee00ff +ee0077000000bbffffffffffffffffffffffffffffffffffffff7777ffffffffffffffff +44ccffcc22ff00eecc00ffff00ffffffffffffffee22ddddaaffaaff00ffff00ffff00ff +ff0077000000bbffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffee00ff00ff00eeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffff00eeffff00ff00ffff00 +ffff00ffffffffffffffff00ffff00ff779900ffff00ffff00ffff0044eeffffffffffff +ffffffffffffffffffffffffffffffff7777ffffffffffffffff00eeffff00ff00ffff00 +ffff00ffffffffffffffff997799ffff779900ffff00ffff00ffff0044eeffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffaa44ff00ff44aaffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffff3388ffee33ff00ffff00ffff00ffffffffffffff +ff00ffff008833ff00ffff00ffff00ffff006677ffeebbffffffffffffffffffffffffff +ffffffffffff7777ffffffffffffffff3388ffee33ff00ffff00ffff00ffffffffffffff +ffee3399ff8833ff00ffff00ffff00ffee006677ffeebbffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffff77 +77ff00ff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffcc552222ccaa00ddaa00eebb0000ffffffffffffbb00ddaa008f00772277 +550077cc0077aa00b1220066ffffffffffffffffffffffffffffffffffffffff7777ffff +ffffffffffffcc552222ccaa00ddaa00eebb0000ffffffffffffffff66ddff9900772277 +bb00ccff33118844cc220066ffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffff33bbff00ffbb33ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffee00ffff00ffff00eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +000000000077ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffff +000000000077ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +ffffffffaa44ffff00ffff44aaffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff9999ffff00ff +ff9999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff77000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000bbffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffeebbffffffffffee2233ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffff +ffffffffffffffffffeebbffffffffffee2233ffffffffffffffffffffffffffffffffbb +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffaa +00ffffffffff66ee77ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffaa +00ffffffffff66ee77ffffffffffffffffffffffffffffffcc00ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffff00ffffffffff11ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff7777ffffffffffffffffffffffffffff00ffffffffff11ffffff +ffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffee441155ccff00660077ff440000bbffffffffffbb22660077ff +221166ffbb22770077440077ee440044ffffffffffffffffffffffffffffffffffffffff +7777ffffffffffffffffee441155ccff00660077ff440000bbffffffffff4411eeee55ee +221166ffff00ff9900bb0000ee440044ffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +44ccffcc22ff00eecc00ffff00ffffffffffffffff00ffdd00ffaaff00ffff00ffee00ff +ee0077000000bbffffffffffffffffffffffffffffffffffffff7777ffffffffffffffff +44ccffcc22ff00eecc00ffff00ffffffffffffffee22ddddaaffaaff00ffff00ffff00ff +ff0077000000bbffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffeebbffffffffbbffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffeebbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffff00eeffff00ff00ffff00 +ffff00ffffffffffffffff00ffff00ff779900ffff00ffff00ffff0044eeffffffffffff +ffffffffffffffffffffffffffffffff7777ffffffffffffffff00eeffff00ff00ffff00 +ffff00ffffffffffffffff997799ffff779900ffff00ffff00ffff0044eeffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff00ffffffff4400aaffff9944eeffffffffffffffffff22ff +ffffffffffaa00ffffffcc00ffffffffffffffffffee00ddffffaa00eeffffffffffffff +ffffffffffaa00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffff3388ffee33ff00ffff00ffff00ffffffffffffff +ff00ffff008833ff00ffff00ffff00ffff006677ffeebbffffffffffffffffffffffffff +ffffffffffff7777ffffffffffffffff3388ffee33ff00ffff00ffff00ffffffffffffff +ffee3399ff8833ff00ffff00ffff00ffee006677ffeebbffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff00ffffffffff7766ffffcc99ffffffffffffffffffffffffffffffffffff00ffffff +ff00ffffffffffffffffffff00ffffffff00ffffffffffffffffffffffffffff00ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffcc552222ccaa00ddaa00eebb0000ffffffffffffbb00ddaa008f00772277 +550077cc0077aa00b1220066ffffffffffffffffffffffffffffffffffffffff7777ffff +ffffffffffffcc552222ccaa00ddaa00eebb0000ffffffffffffffff66ddff9900772277 +bb00ccff33118844cc220066ffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffdd00 +ddff77ffffff221166ff9922775033ffff221166ffff005511aaff00ffee440044ffffff +ffff00ffffffff00ffee440044ff221166ffee44004400ffee44004499227777ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff00ffffffffffff6677ee77ffffffaaff00ff +ff00ffff00ffffaaff00ffff00eebb22ff00ff77000000bbffffffff000000000000ff77 +000000bbaaff00ff66ccffdd00ff77000000bb00ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +000000000077ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffff +000000000077ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff00ffffffffffffdd1188ddffffff779900ffff00ffff00ffff779900 +ffff00ffff00ff00ff44eeffffffffffffff00ffffffff00ff44eeffffff779900ff00ff +ffff00ff44eeffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff +ffffffffffff4444ffffff8833ff00ffff00ffff00ff8833ff00ffff00ffee44ff00ff66 +77ffeebbffffffff00ffffffff00ff6677ffee6433ff00ff2277ffff00ff6677ffeebb00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffbb99ffff +ff9900772277aa0055bb00cc9900772277ff222244ccbb00cccc220066ffffffffbb0099 +eeddaa00ddcc2200669900772277bb22006633ddcc220066aa0055ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff77000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000bbffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffdd22ffdd22dd22ffdd22ffdd +22ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff77000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000bbffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99 +99ffff00ffff9999ffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffff9999ffff00ffff9999ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffaa44ffff00ffff44aaffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffaa44ffff00ffff44aaffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffee00ffff00ffff00eeffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffee00ffff00ffff00eeffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff33bbff00ffbb33ffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffff33bbff +00ffbb33ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ff00 +ff7777ffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffeebbffffffffffee2233ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffff +ffffffffffffffffffeebbffffffffffee2233ffffffffffffffffffffffffffffffffbb +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffffffffffffffffffffffffffffff7777ff00ff7777ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffaa44ff00ff44aaffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffaa +00ffffffffff66ee77ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffaa +00ffffffffff66ee77ffffffffffffffffffffffffffffffcc00ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffaa44ff00ff44aaffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee00ff00ff00eeffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffff00ffffffffff11ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff7777ffffffffffffffffffffffffffff00ffffffffff11ffffff +ffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffee00ff00ff00eeffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff33bb00bb33ffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffee441155ccff00660077ff440000bbffffffffffbb22660077ff +221166ffbb22770077440077ee440044ffffffffffffffffffffffffffffffffffffffff +7777ffffffffffffffffee441155ccff00660077ff440000bbffffffffff4411eeee55ee +221166ffff00ff9900bb0000ee440044ffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff33bb00bb33ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777007777ffff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +44ccffcc22ff00eecc00ffff00ffffffffffffffff00ffdd00ffaaff00ffff00ffee00ff +ee0077000000bbffffffffffffffffffffffffffffffffffffff7777ffffffffffffffff +44ccffcc22ff00eecc00ffff00ffffffffffffffee22ddddaaffaaff00ffff00ffff00ff +ff0077000000bbffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7777007777ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffaa440044aaffffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffff00eeffff00ff00ffff00 +ffff00ffffffffffffffff00ffff00ff779900ffff00ffff00ffff0044eeffffffffffff +ffffffffffffffffffffffffffffffff7777ffffffffffffffff00eeffff00ff00ffff00 +ffff00ffffffffffffffff997799ffff779900ffff00ffff00ffff0044eeffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffaa440044aaffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffee000000eeffffffffffffffffffffffffffffffffffffffffffff +ffffffffff88000077ffffffffffffff3388ffee33ff00ffff00ffff00ffffffffffffff +ff00ffff008833ff00ffff00ffff00ffff006677ffeebbffffffffffffffffffffffffff +ffffffffffff7777ffffffffffffffff3388ffee33ff00ffff00ffff00ffffffffffffff +ffee3399ff8833ff00ffff00ffff00ffee006677ffeebbffffffffffffffffffffffffff +ffffffffff77000099ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee000000eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +330033ffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb000066ff +ffffffffffffcc552222ccaa00ddaa00eebb0000ffffffffffffbb00ddaa008f00772277 +550077cc0077aa00b1220066ffffffffffffffffffffffffffffffffffffffff7777ffff +ffffffffffffcc552222ccaa00ddaa00eebb0000ffffffffffffffff66ddff9900772277 +bb00ccff33118844cc220066ffffffffffffffffffffffffffffffffffffff660000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff330033ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff770077ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffee000011eeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffee110000eeffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff770077ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffaa00aaffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff66000044eeffffffffffffffffffffffffffffffffffffff +000000000077ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffff +000000000077ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffee44000066ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffaa00aaffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee00eeffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffdd11000033aaffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa33 +000011ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee00ee +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000099ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff9900000000000a1313131313131313131313131313131313131313 +131313131313131313131313131313131313131313131313131313131313131313131313 +131313131313131309091313131313131313131313131313131313131313131313131313 +131313131313131313131313131313131313131313131313131313131313131313131313 +131307000000000099ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffee00eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd11 +000033aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa33000011dd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee00eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa00aaffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff66000044eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffee44000066ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffaa00aaffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff770077ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffee000011eeffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee110000eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770077ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff330033ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffbb000066ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff660000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffff33 +0033ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee0000 +00eeffffffffffffffffffffffffffffffffffffffffffffffffffffff88000077ffffff +ffffffffffee2233ffffffeebbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffff +ffffffffffee2233ffffffeebbffffffffffffffffffffffffffffffffffbbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77000099ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee000000eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffaa440044aaffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffff66ee77ffff +ffaa00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffff66ee77ffff +ffaa00ffffffffffffffffffffffffffffffffcc00ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffaa440044aaffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff7777007777ffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffff11ffffffffffff00ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff7777ffffffffffffffffff11ffffffffffff00ffffffffffffff +ffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffff7777007777ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff33bb00bb33ffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffff440000bbee44004400ffffffffffbb22660077ffff221166ffbb +22770077440077ee440044ffffffffffffffffffffffffffffffffffffffffffffffffff +7777ffffffffffffffff440000bbee44004400ffffffffff4411eeee55eeff221166ffff +00ff9900bb0000ee440044ffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff33bb00bb33ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffee00ff00ff00eeff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ff00ffff66ccffdd00ffffffffffff00ffdd00ffffaaff00ffff00ffee00ffee00770000 +00bbffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffff +ff00ffff66ccffdd00ffffffffffee22ddddaaffffaaff00ffff00ffff00ffff00770000 +00bbffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffee00ff00ff00eeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffaa44ff00ff44aaffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffff00ffff00ffffff00ff +ffffffffff00ffff00ffff779900ffff00ffff00ffff0044eeffffffffffffffffffffff +ffffffffffffffffffffffffffffffff7777ffffffffffffffffff00ffff00ffffff00ff +ffffffffff997799ffffff779900ffff00ffff00ffff0044eeffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffaa44ff00ff44aaffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff7777ff00ff7777ffffffffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffff00ffff2277ffff00ffffffffffff00ffff00ff +8833ff00ffff00ffff00ffff006677ffeebbffffffffffffffffffffffffffffffffffff +ffffffffffff7777ffffffffffffffffff00ffff2277ffff00ffffffffffffee3399ffff +8833ff00ffff00ffff00ffee006677ffeebbffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffff77 +77ff00ff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff33bb +ff00ffbb33ffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffbb0000ffbb22006633ddffffffffbb00ddaa00ee9900772277550077cc00 +77aa00b1220066ffffffffffffffffffffffffffffffffffffffffffffffffff7777ffff +ffffffffffffbb0000ffbb22006633ddffffffffffff66ddffff9900772277bb00ccff33 +118844cc220066ffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffff33bbff00ffbb33ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffee00ffff00ffff00eeffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffee00ffff00ffff00eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffaa44ffff00ffff44aaffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffff0000000000 +77ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffff0000000000 +77ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +ffffffffaa44ffff00ffff44aaffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff9999ffff00ffff9999ffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff9999ffff00ff +ff9999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff77000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000bbffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffee2233ffffffeebbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffff +ffffffffffee2233ffffffeebbffffffffffffffffffffffffffffffffffbbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffff66ee77ffff +ffaa00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffff66ee77ffff +ffaa00ffffffffffffffffffffffffffffffffcc00ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffff11ffffffffffff00ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff7777ffffffffffffffffff11ffffffffffff00ffffffffffffff +ffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffff440000bbee44004400ffffffffffbb22660077ffff221166ffbb +22770077440077ee440044ffffffffffffffffffffffffffffffffffffffffffffffffff +7777ffffffffffffffff440000bbee44004400ffffffffff4411eeee55eeff221166ffff +00ff9900bb0000ee440044ffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ff00ffff66ccffdd00ffffffffffff00ffdd00ffffaaff00ffff00ffee00ffee00770000 +00bbffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffff +ff00ffff66ccffdd00ffffffffffee22ddddaaffffaaff00ffff00ffff00ffff00770000 +00bbffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff +ffbbffffffffffffffffffffffffffffffffffeebbffffffffffbbffffffffffffffffff +ffffffffffffffffffffffffffffffeebbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffff00ffff00ffffff00ff +ffffffffff00ffff00ffff779900ffff00ffff00ffff0044eeffffffffffffffffffffff +ffffffffffffffffffffffffffffffff7777ffffffffffffffffff00ffff00ffffff00ff +ffffffffff997799ffffff779900ffff00ffff00ffff0044eeffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff00ffffffffdd0011000022ff22ffcc00ffffddffffffffff +ffffffffffffffffffaa00ffffffffcc00ffffffffffffffff440033002299ffffffffff +ffffffffffaa00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffff00ffff2277ffff00ffffffffffff00ffff00ff +8833ff00ffff00ffff00ffff006677ffeebbffffffffffffffffffffffffffffffffffff +ffffffffffff7777ffffffffffffffffff00ffff2277ffff00ffffffffffffee3399ffff +8833ff00ffff00ffff00ffee006677ffeebbffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff00ffffffffff00ffffffaaffffffff00ffee22ffffffffffffffffffffffffffffff +00ffffffffff00ffffffffffffffffff00ffffbb00ffffffffffffffffffffff00ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffbb0000ffbb22006633ddffffffffbb00ddaa00ee9900772277550077cc00 +77aa00b1220066ffffffffffffffffffffffffffffffffffffffffffffffffff7777ffff +ffffffffffffbb0000ffbb22006633ddffffffffffff66ddffff9900772277bb00ccff33 +118844cc220066ffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff00ff +ffbbbbaa33ffff00ff440000ee440044ff99227777221166ffff005511aaffff00ffee44 +0044ffffffff00ffffaa33ffee441155ccffee44004400881177cc44eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff00ffffffffff00000000bbff00ffff00ffff +00ff77000000bbff00ffffaaff00ffff00eebb22ffff00ff77000000bbffffff00777722 +99ff44ccffcc22ff66ccffdd00ff22dddd99ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffff0000000000 +77ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffff0000000000 +77ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff00ffffffffff00ffffeeddff00ffff00ffff00ff44eeffffffff00ff +ff779900ffff00ffff00ffff00ff44eeffffffffffff00ffffee00ff00eeffff00ff00ff +ffff00ff887799ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff +ffffffff00ffffffffff00ffff00ffff00ff6677ffeebbff00ff8833ff00ffff00ffee44 +ffff00ff6677ffeebbffffff00ffffee00ff3388ffee33ff2277ffff00ffee2288ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffbb0000bbffffbb +00ccbb00ccff2266cc220066ffaa00559900772277ff222244ccffbb00cccc220066ffff +ffbb0033224499ffcc552222ccffbb22006633ddff77ccffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff77000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000bbffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff99ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffeebbffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +44ccffffffffffffffffffffffffffffffffffffffdd0011000022ffffffffffffffffff +ffffffffffffffffffddffffff440033002299ffffffffffffffffffffaa00ffffffffff +ffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff00ffffffaaffffffffffffffffffffffffffffffffffee22 +ffffffff00ffffbb00ffffffffffffffffffffff00ffffffffffffffff00ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff00ffffddbbff4411eeee55df440044ffbb22660077ff440000ffffff00ffffaa33ff +ffee441155ccee44004400881177cc44eeffff00ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000bbffee22 +ddddaa77000000bbff00ffdd00ffff00ffffffff0077772299ffff44ccffcc2266ccffdd +00ff22dddd99ffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff00ffffeeddffff997799ff44eeffffffff00 +ffff00ffff00ffffffff00ffffee00ffff00eeffff0000ffffff00ff887799ffffffff00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff00ffffffeebbffee3399ff6677ffeebbff00ffff00ffff00ffffffff +00ffffee00ffff3388ffee332277ffff00ffee2288ffffffff00ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb0077 +110000ddffff66ddffcc220066ffbb00ddaa00eeff2266ffffbb0033224499ffffcc5522 +22ccbb22006633ddff77ccffffffff00ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99 +ffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff7744ccffffffffff00ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffdd22ffdd22dd22ffdd22ffdd +22ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff77000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000bbffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffff9999ffff00ffff9999ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffaa44ffff00ffff44aaffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffee00ffff00ffff00eeffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffff33bbff +00ffbb33ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffee2233ffffffeebbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffff +ffffffffffee2233ffffffeebbffffffffffffffffffffffffffffffffffbbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffffffffffffffffffffffffffffff7777ff00ff7777ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffff66ee77ffff +ffaa00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffff66ee77ffff +ffaa00ffffffffffffffffffffffffffffffffcc00ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffaa44ff00ff44aaffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffff11ffffffffffff00ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff7777ffffffffffffffffff11ffffffffffff00ffffffffffffff +ffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffee00ff00ff00eeffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffff440000bbee44004400ffffffffffbb22660077ffff221166ffbb +22770077440077ee440044ffffffffffffffffffffffffffffffffffffffffffffffffff +7777ffffffffffffffff440000bbee44004400ffffffffff4411eeee55eeff221166ffff +00ff9900bb0000ee440044ffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff33bb00bb33ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ff00ffff66ccffdd00ffffffffffff00ffdd00ffffaaff00ffff00ffee00ffee00770000 +00bbffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffff +ff00ffff66ccffdd00ffffffffffee22ddddaaffffaaff00ffff00ffff00ffff00770000 +00bbffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7777007777ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffff00ffff00ffffff00ff +ffffffffff00ffff00ffff779900ffff00ffff00ffff0044eeffffffffffffffffffffff +ffffffffffffffffffffffffffffffff7777ffffffffffffffffff00ffff00ffffff00ff +ffffffffff997799ffffff779900ffff00ffff00ffff0044eeffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffaa440044aaffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffff00ffff2277ffff00ffffffffffff00ffff00ff +8833ff00ffff00ffff00ffff006677ffeebbffffffffffffffffffffffffffffffffffff +ffffffffffff7777ffffffffffffffffff00ffff2277ffff00ffffffffffffee3399ffff +8833ff00ffff00ffff00ffee006677ffeebbffffffffffffffffffffffffffffffffffff +ffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee000000eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffbb0000ffbb22006633ddffffffffbb00ddaa00ee9900772277550077cc00 +77aa00b1220066ffffffffffffffffffffffffffffffffffffffffffffffffff7777ffff +ffffffffffffbb0000ffbb22006633ddffffffffffff66ddffff9900772277bb00ccff33 +118844cc220066ffffffffffffffffffffffffffffffffffffffffffffffff770000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff330033ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff770077ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffff0000000000 +77ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffff0000000000 +77ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffaa00aaffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffee00ee +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff77000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99 +99ffff00ffff9999ffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff770000 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffaa44ffff00ffff44aaffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffee00ffff00ffff00eeffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff33bbff00ffbb33ffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff770000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ff00 +ff7777ffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffeebbffffffffffff +ffffffffffffffffffffffffffffffee2233ffffffffffeebbffffffffffffffffffffff +eebbffffffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffeebbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffaa44ff00ff44aaffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff22ffffffffffffffffffaa00ffffffffffffffffffffffffffffffff +ffffffffff66ee77ffffffffffaa00ffffffffffffffffffffffaa00ffffffffffffffff +ffffffffffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff00ffffffffdd0011002299ffffffffffffffffff +ffffffffffffffffffffff22ffffffffffffffff22ffffffffffffffffffffffffffff44 +0033002299ffffffffffffffffffffaa00ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee00ff00ff00eeffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff11ffffffff +ffffffff00ffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff +ffffffffffffffffff770000bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff00ffffffffff00ffffbb00ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffbb00ffffffffff +ffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff33bb00bb33ffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff99227777ee440044bb22770077440077ffff221166ffaa33ffbb22660077ee44004400 +ee440044ff99227777ffffffffffee441155ccff440000bbffffffffffff005511aaee44 +1155ccee44004400ff881177cc44eeffffffffffffffffffffffffffffffffffffffff77 +0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff +ffff00ffff9933ffee440044ffbb22770077440077ff221166ffaa33ffbb22660077ffaa +33ffbb22660077ee44114411ffffffff00ffffaa33ffee441155ccffee44004400881177 +cc44eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777007777ffff +ffffffffffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff77000000bb +00ffee00ffee00ffffaaff00ffff00ffff00ffdd0066ccffdd0077000000bbff00ffffff +ffffffff44ccffcc22ffff00ffffffffffffffff00eebb2244ccffcc2266ccffdd00ffff +22dddd99ffffffffffffffffffffffffffffffffffffffffff770000bbffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff00ffffffffff00773377eeff7700 +0000bbff00ffee00ffee00ffaaff00ffff00ffff00ffdd00ffff00ffff00ffdd007744ff +33ddffffffff0077772299ff44ccffcc22ff66ccffdd00ff22dddd99ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffaa440044aaffffffffffffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff00ffff44eeffffff00ffff00ffff00ffff77 +9900ffff00ffff00ffff0000ffffff0044eeffffffff00ffffffffffffff00eeffff00ff +ff00ffffffffffffffff00ffff0000eeffff0000ffffff00ffff887799ffffffffffffff +ffffffffffffffffffffffffffffff770000bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff00ffffffffff00ff7755ffff44eeffffffff00ffff00ffff +00ff779900ffff00ffff00ffff00ffff00ffff00ffff00aa22ee00ffffffffff00ffffee +00ff00eeffff00ff00ffffff00ff887799ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffee000000eeffffffffffffffffffffffffffffffffffffffffffff +ffffffffff88000077ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff00ffff6677ffeebb00ffff00ffff00ff8833ff00ffff00ffff00ffff +002277ffff006677ffeebbff00ffffffffffffff3388ffee33ffff00ffffffffffffffff +00ffee443388ffee332277ffff00ffffee2288ffffffffffffffffffffffffffffffffff +ffffffffff77000099ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff00ffffffffff00ffff3377ff6677ffeebbff00ffff00ffff008833ff00ffff00ffff +00ffff00ffff00ffff00ffff00ff775599ffffffffff00ffffee00ff3388ffee33ff2277 +ffff00ffee2288ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +330033ffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb000066ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa0055 +ffcc220066550077cc0077aa00dd9900772277bb00ccbb00ddaa00af22006633b1220066 +ffaa0055ffffffffffffcc552222ccffbb0000ffffffffffffff222244cccc552222ccbb +22006633ddffff77ccffffffffffffffffffffffffffffffffffffffffffff660000bbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffbb00aa +eeee1188cc220066ff550077cc0077aa008500772277bb00ccbb00ddaa00eebb00ccbb00 +ddaa009f224455aaffffffbb0033224499ffcc552222ccffbb22006633ddff77ccffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff770077ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffee000011eeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99ffff +ffffffffffffffffffffffffffffffffffffffffee110000eeffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99ddddbb00ffff +ffffffffffffffffffffffffffffffffffffffffff99ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffaa00aaffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff66000044eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff000000000077ffffffffffffffff00 +0000000077ffffffffffffffffffffffffffffffff7744ccffffffffffffffffffffffff +ffffffffffffffffffee44000066ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff11bbff9977ffffffffffffffffffffffff +ffffffffffffffffff7744ccffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee00eeffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffdd11000033aaffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa33 +000011ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffcc221177ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000099ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff995544444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444433445599ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +%%EndData +%%PageTrailer +%%Trailer +%%BoundingBox: 131 284 481 508 +%%EOF diff --git a/lib/cosNotification/doc/src/fascicules.xml b/lib/cosNotification/doc/src/fascicules.xml new file mode 100644 index 0000000000..0678195e07 --- /dev/null +++ b/lib/cosNotification/doc/src/fascicules.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE fascicules SYSTEM "fascicules.dtd"> + +<fascicules> + <fascicule file="part" href="part_frame.html" entry="no"> + User's Guide + </fascicule> + <fascicule file="ref_man" href="ref_man_frame.html" entry="yes"> + Reference Manual + </fascicule> + <fascicule file="part_notes" href="part_notes_frame.html" entry="no"> + Release Notes + </fascicule> + <fascicule file="" href="../../../../doc/print.html" entry="no"> + Off-Print + </fascicule> +</fascicules> + diff --git a/lib/cosNotification/doc/src/make.dep b/lib/cosNotification/doc/src/make.dep new file mode 100644 index 0000000000..031a2b3e98 --- /dev/null +++ b/lib/cosNotification/doc/src/make.dep @@ -0,0 +1,48 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: CosNotification.tex CosNotification_AdminPropertiesAdmin.tex \ + CosNotification_QoSAdmin.tex CosNotifyChannelAdmin_ConsumerAdmin.tex \ + CosNotifyChannelAdmin_EventChannel.tex CosNotifyChannelAdmin_EventChannelFactory.tex \ + CosNotifyChannelAdmin_ProxyConsumer.tex CosNotifyChannelAdmin_ProxyPullConsumer.tex \ + CosNotifyChannelAdmin_ProxyPullSupplier.tex \ + CosNotifyChannelAdmin_ProxyPushConsumer.tex \ + CosNotifyChannelAdmin_ProxyPushSupplier.tex \ + CosNotifyChannelAdmin_ProxySupplier.tex CosNotifyChannelAdmin_SequenceProxyPullConsumer.tex \ + CosNotifyChannelAdmin_SequenceProxyPullSupplier.tex \ + CosNotifyChannelAdmin_SequenceProxyPushConsumer.tex \ + CosNotifyChannelAdmin_SequenceProxyPushSupplier.tex \ + CosNotifyChannelAdmin_StructuredProxyPullConsumer.tex \ + CosNotifyChannelAdmin_StructuredProxyPullSupplier.tex \ + CosNotifyChannelAdmin_StructuredProxyPushConsumer.tex \ + CosNotifyChannelAdmin_StructuredProxyPushSupplier.tex \ + CosNotifyChannelAdmin_SupplierAdmin.tex CosNotifyComm_NotifyPublish.tex \ + CosNotifyComm_NotifySubscribe.tex CosNotifyFilter_Filter.tex \ + CosNotifyFilter_FilterAdmin.tex CosNotifyFilter_FilterFactory.tex \ + CosNotifyFilter_MappingFilter.tex book.tex \ + ch_BNF.tex ch_QoS.tex ch_contents.tex ch_example.tex \ + ch_install.tex ch_introduction.tex ch_system.tex \ + cosNotificationApp.tex part.tex ref_man.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +book.tex: ref_man.xml + +# ---------------------------------------------------- +# Pictures that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: eventstructure.ps + +book.dvi: notificationFlow.ps + diff --git a/lib/cosNotification/doc/src/notes.gif b/lib/cosNotification/doc/src/notes.gif Binary files differnew file mode 100644 index 0000000000..e000cca26a --- /dev/null +++ b/lib/cosNotification/doc/src/notes.gif diff --git a/lib/cosNotification/doc/src/notes.xml b/lib/cosNotification/doc/src/notes.xml new file mode 100644 index 0000000000..c66be87c7c --- /dev/null +++ b/lib/cosNotification/doc/src/notes.xml @@ -0,0 +1,391 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>cosNotification Release Notes</title> + <prepared></prepared> + <docno></docno> + <approved></approved> + <checked></checked> + <date>2000-01-31</date> + <rev>A</rev> + <file>notes.xml</file> + </header> + + <section> + <title>cosNotification 1.1.12</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p> + The documentation is now built with open source tools (xsltproc and fop) + that exists on most platforms. One visible change is that the frames are removed.</p> + <p> + Own Id: OTP-8201 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.1.11</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Obsolete guards, e.g. record vs is_record, has been changed + to avoid compiler warnings.</p> + <p>Own id: OTP-7987</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.1.10</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Updated file headers.</p> + <p>Own id: OTP-7837 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.1.9</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Documentation source included in open source releases.</p> + <p>Own id: OTP-7595 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.1.8</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The CosNotification proxy objects ignored the gcLimit option, instead + the gcTime value was used.</p> + <p>Own id: OTP-7553 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.1.7</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Updated file headers.</p> + <p>Own id: OTP-7011</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.1.6</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The documentation source has been converted from SGML to XML.</p> + <p>Own id: OTP-6754</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.1.5</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Minor Makefile changes.</p> + <p>Own id: OTP-6701</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.1.4</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Removed some unused code.</p> + <p>Own id: OTP-6527</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.1.3</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>A user can now define the QoS EventReliability to be + Persistent. Note, this is only a lightweight version + and events will be lost if a proxy is terminated.</p> + <p>Own id: OTP-5923</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.1.2</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Possible to configure cosNotification not to type check, + by invoking corba_object:is_a/2, supplied IOR:s. When + a type check fails, the feedback has been improved.</p> + <p>Own id: OTP-5823 Aux Id: seq10143</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.1.1</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The app-file contained duplicated modules.</p> + <p>Own id: OTP-4976</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.1</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The stub/skeleton-files generated by IC have been improved, + i.e., depending on the IDL-files, reduced the size of the + erl- and beam-files and decreased dependencies off Orber's + Interface Repository. It is necessary to re-compile all IDL-files + and use COS-applications, including Orber, compiled with + IC-4.2.</p> + <p>Own id: OTP-4576</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.0.6</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The exception CosNotifyFilter::InvalidValue, raised by the operation + CosNotifyFilter::MappingFilter::add_mapping_constraints, did not contain + correct data in the body. Hence, it was not possible to pass this + exception to another ORB.</p> + <p>Own Id: OTP-4412</p> + </item> + <item> + <p>It was not possible to set the QoS property PacingInterval to zero and + the default value was not compliant with the OMG specification. The + default value for MaximumBatchSize have also been changed du to the + same reason.</p> + <p>Own Id: OTP-4413, OTP-4414</p> + </item> + </list> + </section> + + <section> + <title>Incompatibilities</title> + <list type="bulleted"> + <item> + <p>The default value, for the QoS properties PacingInterval and MaximumBatchSize, + have been changed to zero (i.e. no timeout) and 1 respectively, which is + compliant with the OMG specification.</p> + <p>Own Id: OTP-4413, OTP-4414</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.0.5</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>If one tries to set an unavailable/incorrect property or property value, an + exception is thrown. In some cases the exception was not correct, which + would cause problems if communicating via IIOP.</p> + <p>Own Id: OTP-4340</p> + </item> + <item> + <p>When using Filter's, with the QoS OrderPolicy set to FifoOrder, + and passing a sequence of structured events, they could be + delivered in the wrong order.</p> + <p>Own Id: OTP-4272</p> + </item> + <item> + <p>If Filter's where attached to Supplier proxies it could cause + the Proxy to terminate.</p> + <p>Own Id: OTP-4272</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.0.4</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>When passing event sequences, the PushSuppliers and PullSuppliers + could crash if the objects had Filter objects associated and + only a subset of the sequences where approved. </p> + <p>Own Id: OTP-4099</p> + </item> + <item> + <p>SupplierAdmin's did not filter any events, even though Filter objects + had been attached to the SupplierAdmin.</p> + <p>Own Id: OTP-4098</p> + </item> + <item> + <p>If one used the '_get_default_supplier_admin'/1, exported by the + CosNotifyChannelAdmin_EventChannel-module, it resulted in a loop + which overloaded the channel. This is no longer the case.</p> + <p>Own Id: OTP-4086</p> + </item> + <item> + <p>If one used the '_get_default_filter_factory'/1, exported by the + CosNotifyChannelAdmin_EventChannel-module, a new instance was created + each time. Now fixed.</p> + <p>Own Id: OTP-4092</p> + </item> + </list> + </section> + + <section> + <title>Incompatibilities</title> + <list type="bulleted"> + <item> + <p>The include paths for <c>CosNotification.idl</c> have been changed. + Hence, if you include this file in your own IDL-files you must + update your paths to also point to where the cosEvent IDL-files are + stored.</p> + <p>Own Id: OTP-4093</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.0.3</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>It is now possible to start global channel factories.</p> + <p>Own Id: OTP-4078</p> + </item> + <item> + <p>The Orber, version 3.2.5 or later, configuration parameter + orber_debug_level can now be used to generate reports when abnormal + situations occurs. For more information consult the Orber User's Guide. + Note, it is not recommended to use this option for delivered systems + since some of the reports is not to be considered as errors. + The value of orber_debug_level must be 3, or higher, for reports to + be generated.</p> + <p>Own Id: OTP-4077, OTP-3962</p> + </item> + </list> + </section> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>When using the cosEvent API accessing a cosNotification admins + the objects returned by the functions obtain_push_supplier, + obtain_pull_supplier, obtain_push_consumer and obtain_pull_consumer + was not of the correct type. Due to the interface change + it is not possible to upgrade during runtime.</p> + <p>Own Id: OTP-4079</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosNotification 1.0.2</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>First release of the cosNotification application.</p> + <p>Own Id: -</p> + </item> + </list> + </section> + </section> +</chapter> + diff --git a/lib/cosNotification/doc/src/notificationFlow.gif b/lib/cosNotification/doc/src/notificationFlow.gif Binary files differnew file mode 100644 index 0000000000..31d6ee97fb --- /dev/null +++ b/lib/cosNotification/doc/src/notificationFlow.gif diff --git a/lib/cosNotification/doc/src/notificationFlow.ps b/lib/cosNotification/doc/src/notificationFlow.ps new file mode 100644 index 0000000000..4215e66d80 --- /dev/null +++ b/lib/cosNotification/doc/src/notificationFlow.ps @@ -0,0 +1,4372 @@ +%!PS-Adobe-3.0 +%%Creator: (ImageMagick) +%%Title: (notificationFlow.ps) +%%CreationDate: (Tue Apr 18 11:01:08 2000) +%%BoundingBox: 105 212 506 579 +%%DocumentData: Clean7Bit +%%LanguageLevel: 1 +%%Orientation: Portrait +%%PageOrder: Ascend +%%Pages: 1 +%%EndComments + +%%BeginDefaults +%%PageOrientation: Portrait +%%EndDefaults + +%%BeginProlog +% +% Display a color image. The image is displayed in color on +% Postscript viewers or printers that support color, otherwise +% it is displayed as grayscale. +% +/buffer 512 string def +/byte 1 string def +/color_packet 3 string def +/pixels 768 string def + +/DirectClassPacket +{ + % + % Get a DirectClass packet. + % + % Parameters: + % red. + % green. + % blue. + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/DirectClassImage +{ + % + % Display a DirectClass image. + % + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { DirectClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayDirectClassPacket } image + } ifelse +} bind def + +/GrayDirectClassPacket +{ + % + % Get a DirectClass packet; convert to grayscale. + % + % Parameters: + % red + % green + % blue + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/GrayPseudoClassPacket +{ + % + % Get a PseudoClass packet; convert to grayscale. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassPacket +{ + % + % Get a PseudoClass packet. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassImage +{ + % + % Display a PseudoClass image. + % + % Parameters: + % class: 0-PseudoClass or 1-Grayscale. + % + currentfile buffer readline pop + token pop /class exch def pop + class 0 gt + { + currentfile buffer readline pop + token pop /depth exch def pop + /grays columns 8 add depth sub depth mul 8 idiv string def + columns rows depth + [ + columns 0 0 + rows neg 0 rows + ] + { currentfile grays readhexstring pop } image + } + { + % + % Parameters: + % colors: number of colors in the colormap. + % colormap: red, green, blue color packets. + % + currentfile buffer readline pop + token pop /colors exch def pop + /colors colors 3 mul def + /colormap colors string def + currentfile colormap readhexstring pop pop + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { PseudoClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayPseudoClassPacket } image + } ifelse + } ifelse +} bind def + +/DisplayImage +{ + % + % Display a DirectClass or PseudoClass image. + % + % Parameters: + % x & y translation. + % x & y scale. + % label pointsize. + % image label. + % image columns & rows. + % class: 0-DirectClass or 1-PseudoClass. + % compression: 0-RunlengthEncodedCompression or 1-NoCompression. + % hex color packets. + % + gsave + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + x y translate + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + currentfile buffer readline pop + token pop /pointsize exch def pop + /Helvetica findfont pointsize scalefont setfont + x y scale + currentfile buffer readline pop + token pop /columns exch def + token pop /rows exch def pop + currentfile buffer readline pop + token pop /class exch def pop + currentfile buffer readline pop + token pop /compression exch def pop + class 0 gt { PseudoClassImage } { DirectClassImage } ifelse + grestore + showpage +} bind def +%%EndProlog +%%Page: 1 1 +%%PageBoundingBox: 105 212 506 579 +%%BeginData: +DisplayImage +105 212 +401.000000 367.000000 +12 +401 367 +1 +1 +1 +8 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff995511000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000115599ffffffffffffffffffcc2200000022444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444442200000022ccffffffffffffcc110044aaffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffaa440011ccffffffffff220066ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff660022ffffffff990044ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff440099ffffff +5500aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa +0055ffffff1100ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff0011ffffff0022ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff0033ffffff0044ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff00 +44ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +44ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044 +ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +bbaa7777664444667777aabbffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffcc7744002244777777aaaa7777774422004477ccffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee88221166aaeeffffffffffffffffffffffffeeaa66112288eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ff +ffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffdd771166aaffffffffffffffffffffffffffffffffffffffffaa661177dd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff771166ddffffffffffffffffffffffffffffffffffffffffffff +ffffdd661177ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffbb2244ccffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffcc4422bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff771188ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff881177ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffee4433ccffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffcc3344eeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee3366eeffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffee6633eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffee3366ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff66 +33eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffff +ff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee3366ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff6633eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff4466ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff6644ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff7733eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffee3377ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffbb11ccffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffcc11bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff2288ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff8822ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff7744ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4477 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffdd11ccffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffcc11ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff +0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff7766ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff6677ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee11ddffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffdd11eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +8866ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff6688ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff22aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffaa33ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffcc11ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff11ccffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff7766ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +6677ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff44aaffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffaa44ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff00 +44ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00eeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffee00ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +44ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb22ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff22bbffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa44ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff44aaffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff7777ffffffffffffffffffffffffffffffffffffeebbffffffffffffffffffffffff +ffffffffffffffffffffffffffbbffffffffffffffffffffffff7777ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff7777ffffffffffffffffffffffffaa3300226677aa00ffffffffffffff +ffffffffffffffffffffffffffffffffffcc00ffffffffffffffffffffffff7777ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff6677ffffffffffffffffffffffaa44ccffffff77ff00ffff +ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffff +7766ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff44aaffffffffffffffffffffff22ddffffffff +eeff00660077ffff221166bb22660077ffbb22660077ee440044ffff00ffffffffffffff +ffffffffffaa44ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff44aaffffffffffffffffffffff00 +ffffffffffffff00eecc00ffffaaff00ff00ffdd00ffff00ffdd0077000000bbff00ffff +ffffffffffffffffffffaa44ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044 +ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff6677ffffffffffffff +ffffffff22bbffffffffffff00ffff00ffff779900ff00ffff00ffff00ffff0044eeffff +ffff00ffffffffffffffffffffffff7766ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffff +ffffffffffffffffff8833eeffffffccff00ffff00ff8833ff00ff00ffff00ffff00ffff +006677ffeebbff00ffffffffffffffffffffffff7777ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff7777ffffffffffffffffffffffffaa55330055ccaa00ddaa00ee990077225800ddaa00 +eebb00ddaa00bf220066ffbb00ccffffffffffffffffffffff7777ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffaa44ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44aaffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb +3333bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffbb22ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff22 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffdd551199991155ddffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00eeffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffee770077eeffffee770077eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff44aaffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffaa44ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff992244ddffffffffffffdd442299ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ff +ffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff7766ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff6677ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffbb4422bbffffffffffffffffffffbb2244bbffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc11ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff11ccffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffdd661188ffffffffffffffffffffffffffff881166 +ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff22aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffaa33ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff771166eeffffffffffffffffffffffffff +ffffffee661177ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff8866ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff6688ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffaa2244ccffffffffffffffffffff +ffffffffffffffffffffcc4422aaffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee11ddffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd11eeffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffcc4422aaffffffffffffff +ffffffffffffffffffffffffffffffffffaa2244ccffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff7766ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +6677ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0077ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff7700ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffdd11ccffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffcc11ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffff +ff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7744ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff4477ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff22 +88ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff8822ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffbb11ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffcc11bbffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff7733eeffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffee3377ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff4466ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff6644ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff +ffbbffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffee3366ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6633eeffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffdd00110000 +22ffff22ffcc00ffffddffffffffffffffffffffffffffff00ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffee3366ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6633 +eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff +ff00ffffffaaffffffffff00ffee22ffffffffffffffffffffffffffff00ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff +0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee3366 +eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffee6633eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff00ffff00ffffbbbbffaa33ffff00ff440000ee4400449922777788331188ff00ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee4433ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffcc3344eeffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff00ffff00000000bbffff00ffff00ffff00ff77000000bb00ffff1188 +ee99ff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff771188ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff881177ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff00ffff00ffffeeddffff00ffff00ffff00ff44eeffffff +00ffffbb4444ccff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffbb2244ccffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffcc4422bbffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff00ffff00ffffffffffff00ffff00ffff00ff +6677ffeebb00ffff55ee9911ff00ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff771166ddffffffffffffffffff +ffffffffffffffffffffffffffffffdd661177ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff00ffbb0000bbffffffbb00ccbb +00ccff2266cc220066aa0055ff11002277ff00ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd771166aaffff +ffffffffffffffffffffffffffffffffffffaa661177ddffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee88331166aaeeffffffffffffffffffffffffeeaa66113388eeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff00 +44ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffcc7744002244777777aaaa7777774422004477ccffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +44ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffbbaa7777664444667777aabbffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff7799ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff0077ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff7700ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffcc4422aaffffffffffffffffffffffffffffff +ffffffffffffffffffaa2244ccffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffaa2244ccffffffffffffffff +ffffffffffffffffffffffffcc4422aaffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff771166eeff +ffffffffffffffffffffffffffffffee661177ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff0044ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffdd661188ffffffffffffffffffffffffffff881166ddffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff0044ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffbb4422bbffffffffffffffffffffbb2244bbffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044 +ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff0044ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff992244ddffffffffffffdd442299ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffee770077eeffffee770077eeffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd551199991155dd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb +3333bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +bbaa7777664444667777aabbffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +bbaa7777664444667777aabbffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffcc7744002244777777aaaa7777774422004477ccffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff0044ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffcc7744002244777777aaaa7777774422004477ccffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee88221166aaeeffffffffffffffffffffffffeeaa66112288eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff0040ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee88221166aaeeffffffffffffffffffffffffeeaa66112288eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ff +ffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffdd771166aaffffffffffffffffffffffffffffffffffffffffaa661177dd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffee000eeeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffdd771166aaffffffffffffffffffffffffffffffffffffffffaa661177dd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff771166ddffffffffffffffffffffffffffffffffffffffffffff +ffffdd661177ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffee33000033eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff771166ddffffffffffffffffffffffffffffffffffffffffffff +ffffdd661177ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffbb2244ccffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffcc4422bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffbb2244ccffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffcc4422bbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff771188ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff881177ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033ee +ee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff771188ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff881177ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffee4433ccffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffcc3344eeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee +330033eeffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffee4433ccffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffcc3344eeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee3366eeffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffee6633eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee330033eeffffffffee330033eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee3366eeffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffee6633eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffee3366ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff66 +33eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffee330033eeffffffffffffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffee3366ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff66 +33eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffff +ff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee3366ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff6633eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffee330033eeffffffffffffffffee330033eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee3366ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff6633eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff4466ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff6644ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff4466ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff6644ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff7733eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffee3377ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff7733eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffee3377ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffbb11ccffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffcc11bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffff +ffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffbb11ccffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffcc11bbffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff2288ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff8822ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffff +ffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff2288ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff8822ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff7744ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4477 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033ee +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff7744ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4477 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffdd11ccffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffcc11ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee +330033eeffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffdd11ccffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffcc11ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff +0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff7766ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff6677ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff7766ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff6677ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee11ddffff +ffffffffffffffffffffeeffffffffffffffffffffffffffffffffffffbbffffffffffff +ffffffffffffffffffffffffffffdd11eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee11ddffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffdd11eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +8866ffffffffffffffffffff33116644ffffffffffffffffffffffffffffffffffcc00ff +ff22ffffffffffffffffffffffffffffffffffff6688ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +8866ffffffffffaa3300226677ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff6688ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff22aaffffffffffffffffffff00eeff99ffffffffffffffffffffffffffffff +ffffff00ffffffffffffffffffffffffffffffffffffffffffaa33ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff22aaffffffffaa44ccffffff77ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffaa33ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffcc11ffffffffffffffffffffff4455eeffff9900bb000099226611 +99ff9922661199ff00ffaa33ffee440044ff99227777ffffffffffffffffff11ccffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffcc11ffffffffff22ddffffffffeeffee441155ccbb22660077ff88 +3311889900bb0000bb22770077440077ffee44004499227777ffffffffffff11ccffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff7766ffffffffffffffffffffffee5511ccffff00ffff +00ff00eeaa22ffff00eeaa22ff00ffff00ff77000000bbff00ffffffffffffffffffffff +6677ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff7766ffffffffff00ffffffffffffff44ccffcc22ff00 +ffdd00ff1188ee99ff00ffff00ff00ffee00ffee00ff77000000bb00ffffffffffffffff +6677ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff44aaffffffffffffffffffffeeffff9922 +ffff00ffff00ff00ffff00ffff00ffff00ff00ffff00ff44eeffffffff00ffffffffffff +ffffffffffaa44ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff44aaffffffffff22bbffffffffffff00ee +ffff00ff00ffff00ffbb4444ccff00ffff00ff00ffff00ffff00ff44eeffffff00ffffff +ffffffffffaa44ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff00 +44ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00eeffffffffffffffffffff +7788ffff00ffff00ffee00ff00ffcc44ffff00ffcc44ff00ffff00ff6677ffeebbff00ff +ffffffffffffffffffffee00ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033ee +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff00eeffffffffff8833eeffff +ffccff3388ffee33ff00ffff00ff55ee9911ff00ffee00ff00ffff00ffff00ff6677ffee +bb00ffffffffffffffffee00ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +44ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb22ffffffffffff +ffffffffffbb22000099ffff33118844ff002222ccffff002222ccbb00ccbb00cccc2200 +66ffaa0055ffffffffffffffffffffff22bbffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee +330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb22ffffffffffff +ffaa55330055ccffcc552222ccbb00ddaa00ee11002277ff33118844550077cc0077aa00 +ddcc220066aa0055ffffffffffffffff22bbffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa44ff +ffffffffffffffffffffffffffffffffffffffffffff00ffffffffff00ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff44aaffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa44ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff44aaffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff7777ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffff1100eeffff +ff1100eeffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff6677ffffffffffffffffffffffffffffffffffffffffffff +ffffccffffffffffccffffffffffffffffffffffffffffffffffffffffffffffffffffff +7766ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff6677ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +7766ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff44aaffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffaa44ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff44aaffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffaa44ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff44aaffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffaa44ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff44aaffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffaa44ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044 +ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff6677ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff7766ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff6677ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff7766ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffff +ffffffffffffffffffffffffffffffffffffffffffffffffeebbffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033ee +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffff +ffffffffffffffffffffffffffffffffffffffffffffffffeebbffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff7777ffffffffffffffffffffffffffffffffffff77ccffffffffffffaa00ffffffffff +ffffffffff22ffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee +330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff7777ffffffffffffffffffffffffffffffffffff77ccffffffffffffaa00ffffffffff +ffffffffff22ffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffaa44ffffffffffffffffffffffffffffffffffff6666ffffffffffffff00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44aaffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffaa44ffffffffffffffffffffffffffffffffffff6666ffffffffffffff00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44aaffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffbb22ffffffffffffffffffffffffffffffffffaaee22ddffff +ee44004400ffbb22770077440077aa33ffbb22660077ffffffffffffffffffffffffff22 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffbb22ffffffffffffffffffffffffffffffffffaaee22ddffff +ee44004400ffbb22770077440077aa33ffbb22660077ffffffffffffffffffffffffff22 +bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00eeffffffffffffffffffffffffffffffff99 +ff9966ffff66ccffdd00ffff00ffee00ffee00ff00ffff00ffdd00ffffffffffffffffff +ffffffee00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00eeffffffffffffffffffffffffffffffff99 +ff9966ffff66ccffdd00ffff00ffee00ffee00ff00ffff00ffdd00ffffffffffffffffff +ffffffee00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff44aaffffffffffffffffffffffff +ffffffbb00000011eeff00ffffff00ffff00ffff00ffff00ff00ffff00ffff00ffffffff +ffffffffffffffffaa44ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff44aaffffffffffffffffffffffff +ffffffbb00000011eeff00ffffff00ffff00ffff00ffff00ff00ffff00ffff00ffffffff +ffffffffffffffffaa44ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ff +ffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff7766ffffffffffffff +ffffffffffffffff66ffffff4477ff2277ffff00ffff00ffff00ffff00ff00ffff00ffff +00ffffffffffffffffffffffff6677ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff7766ffffffffffffff +ffffffffffffffff66ffffff4477ff2277ffff00ffff00ffff00ffff00ff00ffff00ffff +00ffffffffffffffffffffffff6677ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc11ffff +ffffffffffffffffffffffffaa33ccffbb3311ddbb22006633dd550077cc0077aa00a300 +ccbb00ddaa00eeffffffffffffffffffffff11ccffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc11ffff +ffffffffffffffffffffffffaa33ccffbb3311ddbb22006633dd550077cc0077aa00a300 +ccbb00ddaa00eeffffffffffffffffffffff11ccffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff22aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffaa33ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff22aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffaa33ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff8866ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff6688ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033ee +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff8866ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff6688ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee11ddffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd11eeffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee +330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee11ddffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd11eeffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff7766ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +6677ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff7766ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +6677ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffdd11ccffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffcc11ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffdd11ccffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffcc11ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffff +ff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7744ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff4477ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7744ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff4477ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff22 +88ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff8822ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff22 +88ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff8822ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffbb11ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffcc7b11bbffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffbb11ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffcc11bbffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff7733eeffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffee100048ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff7733eeffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffee3377ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff4466ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff3e000099ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff4466ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff6644ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffee3366ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff66338f000099 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033ee +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffee3366ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6633eeffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffee3366ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6633 +eeff99000099ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee +330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffeeee3366ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6633 +eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff +0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee3366 +eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffee6633eeffffff99000099ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee3366ee3366 +eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffee6633eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee4433ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffcc3344eeffffffffff99000099ffffffffffffffffffffffffffffffffffff +ffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee33 +0033eeee4433ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffcc3344eeffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff771188ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff881177ffffffffffffffff99000099ffffffffffffffffffffffff +ffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffee330033eeffffff771188ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff881177ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffbb2244ccffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffcc4422bbffffffffffffffffffff99000099ffffffffffff +ffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffbb2244ccffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffcc4422bbffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff771166ddffffffffffffffffff +ffffffffffffffffffffffffffffffdd661177ffffffffffffffffffffffffff99000099 +ffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffee330033eeffffffffffffffff771166ddffffffffffffffffff +ffffffffffffffffffffffffffffffdd661177ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd771166aaffff +ffffffffffffffffffffffffffffffffffffaa661177ddffffffffffffffffffffffffff +ffff99000099ffffffffffffffffffffffffffffffffffee330033eeffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffff +ffffffffffffffffffffffffffffee330033eeffffffffffffffffffffdd771166aaffff +ffffffffffffffffffffffffffffffffffffaa661177ddffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee88331166aaeeffffffffffffffffffffffffeeaa66113388eeffffffffffffffffffff +ffffffffffffffff99000099ffffffffffffffffffffffffffffffee330033eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffff +ee88331166aaeeffffffffffffffffffffffffeeaa66113388eeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff00 +44ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffcc7744002244777777aaaa7777774422004477ccffffffffffffffff +ffffffffffffffffffffffffffff99000099ffffffffffffffffffffffffffee330033ee +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffff +ffffffffffffffffcc7744002244777777aaaa7777774422004477ccffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +44ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffbbaa7777664444667777aabbffffffffffffff +ffffffffffffffffffffffffffffffffffffffff99000099ffffffffffffffffffffffee +330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffffffffffffffffffffffee330033eeffffffffff +ffffffffffffffffffffffffffffffffffbbaa7777664444667777aabbffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff99000099ffffffffffff +ffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99000099 +ffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffee33 +0033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff99000099ffffffffffee330033eeffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffff +ffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff99000099ffffffee330033eeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeff +ffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff990000ccffee330033eeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7700bbee330033eeffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffee330033eeffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044 +ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff7700af330033eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7700260033ee +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330033df330033eeffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff70 +000033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee33000b0033eeffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffbb3333bbffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee26002deeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee33000bdfff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffdd551199991155ddffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffee770077eeffffee770077eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff992244ddffffffffff +ffdd442299ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ff +ffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb4422bbffff +ffffffffffffffffbb2244bbffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd6611 +88ffffffffffffffffffffffffffff881166ddffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff771166eeffffffffffffffffffffffffffffffffee661177ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffaa2244ccffffffffffffffffffffffffffffffffffffffffcc4422aaffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033ee +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffcc4422aaffffffffffffffffffffffffffffffffffffffffffffffffaa +2244ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee +330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff0077ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff7700ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffff +ff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff +ffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff00ffffffffffffffffffffffffbbffffffffffffffffffffffffffffffff +ff00ffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff00ffdd0011000022ffff22ffcc00ffffddffffffffffffffff +ffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffee330033ee +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff00ffff00ffffffaaffffffffff00ffee22ffffff +ffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffee +330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff +0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff00ffff00ffffbbbbffaa33ffff00ff +440000ee4400449922777788331188ff00ffffffffffffffffffffffffffffffffffffff +ffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff00000000bbffff +00ffff00ffff00ff77000000bb00ffff1188ee99ff00ffffffffffffffffffffffffffff +ffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff00ff +ffeeddffff00ffff00ffff00ff44eeffffff00ffffbb4444ccff00ffffffffffffffffff +ffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +00ffff00ffffffffffff00ffff00ffff00ff6677ffeebb00ffff55ee9911ff00ffffffff +ffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff00ffbb0000bbffffffbb00ccbb00ccff2266cc220066aa0055ff11002277ff +00ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff00ffffffffffffffffffffffffffffffffffee330033eeffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff00ffffffffffffffffffffffffffffffffee330033eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff00 +44ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffee330033ee +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +44ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffee +330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0077ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff7700ffffffffffffffffffff +ffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc +4422aaffffffffffffffffffffffffffffffffffffffffffffffffaa2244ccffffffffff +ffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffaa2244ccffffffffffffffffffffffffffffffffffffffffcc4422aaffff +ffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff771166eeffffffffffffffffffffffffffffffffee6611 +77ffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffdd661188ffffffffffffffffffffffffff +ff881166ddffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffbb4422bbffffffffffff +ffffffffbb2244bbffffffffffffffffffffffffffffffee330033eeffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044 +ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff992244 +ddffffffffffffdd442299ffffffffffffffffffffffffffffffffee330033eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee770077eeffffee770077eeffffffffffffffffffffffffffffffffee330033ee +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330033eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffdd551199991155ddffffffffffffffffffffffffffffffffffee +330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee330033eeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffbb3333bbffffffffffffffffffffffffffffff +ffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee330033eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffbbaa7777664444667777aabbffffffffffff +ffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ee330033eeffffffffffffffffffffffffffbbaa7777664444667777aabbffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffcc7744002244777777aaaa777777442200 +4477ccffffffffffffffffee330033eeffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee330033eeffffffffffffffffcc7744002244777777aaaa777777442200 +4477ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffee88221166aaeeffffffffffffffff +ffffffffeeaa66112288eeffffffffee330033eeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffee330033eeffffffffee88221166aaeeffffffffffffffff +ffffffffeeaa66112288eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ff +ffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffdd771166aaffffffffffffff +ffffffffffffffffffffffffffaa661177ddffff770033eeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee330000000000381166aaffffffffffffff +ffffffffffffffffffffffffffaa661177ddffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff771166ddffffffff +ffffffffffffffffffffffffffffffffffffffffdd661177ffff77eeffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffee55444420053eddffffffff +ffffffffffffffffffffffffffffffffffffffffdd661177ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb2244ccff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffcc4422bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb2244ccff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffcc4422bbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +1188ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8811 +77ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +1188ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8811 +77ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffee4433ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffcc3344eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffee4433ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffcc3344eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee3366eeffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffee6633eeffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffee3366eeffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffee6633eeffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffee3366ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff6633eeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffee3366ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff6633eeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffff +ff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffee3366ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff6633eeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffee3366ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff6633eeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff4466ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6644ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff4466ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6644ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff7733eeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee33 +77ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff7733eeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee33 +77ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffbb11ccffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffcc11bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffbb11ccffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffcc11bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2288ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff8822ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2288ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff8822ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +7744ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff4477ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +7744ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff4477ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffdd11ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffcc11ddffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffdd11ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffcc11ddffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff +0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff7766ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff6677ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff7766ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff6677ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffee11ddffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd11eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffee11ddffffffffffffffffffffffffeeffffffffffffff +ffffffffffffffffffffffbbffffffffffffffffffffffffffffffffffffffffdd11eeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff8866ffffffffffaa3300226677ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff6688ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff8866ffffffffffffffffffff33116644ffff +ffffffffffffffffffffffffffffffcc00ffff22ffffffffffffffffffffffffffffffff +ffff6688ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff22aaffffffffaa44ccffffff77 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffaa33ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff22aaffffffffffffffffffff00 +eeff99ffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffff +ffffffffffffffaa33ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffcc11ffffffffff22dd +ffffffffeeffee441155ccbb22660077ff883311889900bb0000bb22770077440077ffee +44004499227777ffffffffffff11ccffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffcc11ffffffffffffff +ffffffff4455eeffff9900bb00009922661199ff9922661199ff00ffaa33ffee440044ff +99227777ffffffffffffffffff11ccffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7766ffff +ffffff00ffffffffffffff44ccffcc22ff00ffdd00ff1188ee99ff00ffff00ff00ffee00 +ffee00ff77000000bb00ffffffffffffffff6677ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7766ffff +ffffffffffffffffffee5511ccffff00ffff00ff00eeaa22ffff00eeaa22ff00ffff00ff +77000000bbff00ffffffffffffffffffffff6677ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff44aaffffffffff22bbffffffffffff00eeffff00ff00ffff00ffbb4444ccff00ffff00 +ff00ffff00ffff00ff44eeffffff00ffffffffffffffffaa44ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff44aaffffffffffffffffffffeeffff9922ffff00ffff00ff00ffff00ffff00ffff00ff +00ffff00ff44eeffffffff00ffffffffffffffffffffffaa44ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff00 +44ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff00eeffffffffff8833eeffffffccff3388ffee33ff00ffff00ff55ee9911 +ff00ffee00ff00ffff00ffff00ff6677ffeebb00ffffffffffffffffee00ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff00eeffffffffffffffffffff7788ffff00ffff00ffee00ff00ffcc44ffff +00ffcc44ff00ffff00ff6677ffeebbff00ffffffffffffffffffffffee00ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +44ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffbb22ffffffffffffffaa55330055ccffcc552222ccbb00ddaa00 +ee11002277ff33118844550077cc0077aa00ddcc220066aa0055ffffffffffffffff22bb +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffbb22ffffffffffffffffffffffbb22000099ffff33118844ff00 +2222ccffff002222ccbb00ccbb00cccc220066ffaa0055ffffffffffffffffffffff22bb +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffaa44ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff44aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffaa44ffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff44aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffff +ffffffffffffffffff00ffffffffff00ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffff +ffffffffffffffffffffffffff1100eeffffff1100eeffffffffffffffffffffffffffff +ffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6677ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff7766ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6677ffffffff +ffffffffffffffffffffffffffffffffffffffffccffffffffffccffffffffffffffffff +ffffffffffffffffffffffffffffffffffff7766ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44 +aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffaa44ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff44 +aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffaa44ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff44aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa44ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff44aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa44ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044 +ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff6677ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7766ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff6677ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7766ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffdd001100 +33aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffff +dd00110033aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffff +ffff00ffffaa11ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffaa44ffffffffffffffffffff +ffffffffffff00ffffaa11ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff44aaffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffaa44ffffffffffffffffffff +ffffffffffffff00ffffbb3399227777ee441155cc6611775555ff881177cc44eeffffff +ffffffffffffffffffffffff44aaffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb22ffffffffff +ffffffffffffffffffffff00ffffbb3399227770441155ccff6611775555881177cc44ee +ffffffffffffffffffffffffffffffffff22bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb22ffffffffff +ffffffffffffffffffffffff00660055eeff00ffff44ccffcc22ff8866aaffffff22dddd +99ffffffffffffffffffffffffffffffff22bbffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +eeffffffffffffffffffffffffffffff00660055eeff00ff44ccffcc22ffff8866aaffff +22dddd99ffffffffffffffffffffffffffffffffffee00ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +eeffffffffffffffffffffffffffffffff00ffffffffff00ffff00eeffff00ffff00ccff +ffff887799ffffffffffffffffffffffffffffffffee00ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff44aaffffffffffffffffffffffffffffff00ffffffffff00ff00eeffff00ffff +ff00ccffff887799ffffffffffffffffffffffffffffffffffffaa44ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff44aaffffffffffffffffffffffffffffffff00ffffffffff00ffff3388ffee33 +ff88bb33ffffffee2288ffffffffffffffffffffffffffffffffaa44ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ff +ffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff7766ffffffffffffffffffffffffffffff00ffffffffff00ff3388 +ffee33ffff88bb33ffffee2288ffffffffffffffffffffffffffffffffffff6677ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff7766ffffffffffffffffffffffffffffffbb0000bbffffaa0055ff +cc552222ccbb66ff0044bbffff77ccffffffffffffffffffffffffffffffff6677ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffcc11ffffffffffffffffffffffffffffbb0000bbffff +aa0055cc552222ccffbb66ff0044bbff77ccffffffffffffffffffffffffffffffffffff +11ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffcc11ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff99ffffffffffffffffffffffffffffffffff +11ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff22aaffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff99ffffffffffffffffffffffffffff +ffffffffaa33ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff22aaffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff7744ccffffffffffffffffffffffff +ffffffffaa33ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff8866ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff7744ccffffffffffffffffff +ffffffffffffffffff6688ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff8866ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff6688ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee11ddffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffdd11eeffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee11ddffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffdd11eeffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +7766ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff6677ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +7766ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff6677ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffdd11ccffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffcc11ddffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffdd11ccffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffcc11ddffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffff +ff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff7744ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff4477ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff7744ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff4477ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff2288ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8822ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff2288ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8822ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffbb11ccffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc +11bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffbb11ccffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc +11bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7733eeffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee3377ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7733eeffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee3377ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4466 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff6644ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4466 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff6644ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee3366ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff6633eeffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffee3366ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff6633eeffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffee3366ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff6633eeffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffee3366ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff6633eeffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff +0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffee3366eeffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffee6633eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffee3366eeffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffee6633eeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffee4433ccffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffcc3344eeffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffee4433ccffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffcc3344eeffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff771188ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff881177ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff771188ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff881177ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb22 +44ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc4422bbffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb22 +44ccffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc4422bbffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff771166ddffffffffffffffffffffffffffffffffffffffffffffffffdd6611 +77ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff771166ddffffffffffffffffffffffffffffffffffffffffffffffffdd6611 +77ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffdd771166aaffffffffffffffffffffffffffffffffffffffff +aa661177ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffdd771166aaffffffffffffffffffffffffffffffffffffffff +aa661177ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee88331166aaeeffffffffffffffffffffff +ffeeaa66113388eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffee88331166aaeeffffffffffffffffffffff +ffeeaa66113388eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff00 +44ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffcc7744002244777777aa +aa7777774422004477ccffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffcc7744002244777777aa +aa7777774422004477ccffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +44ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb +aa7777664444667777aabbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb +aa7777664444667777aabbffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffa3a3ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffa3a3ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff4850ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff4850ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff3838ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff3838ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff1818ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff1818ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffee0000eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffee0000eeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa0000 +aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa0000 +aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044 +ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff77000077ffffffffffffffffffffffffffffffffffffffffffffffeebbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff77000077ffffffffffffffffffffffffffffffffffffffbbffffbbffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff33000033ffffffffffffffdd00110033aaffffffffffffffffffffaa00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff33000033ffffffffffffffdd00110033aaffffffffffcc00ffcc00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffee00080800eeffffffffffffff00ffffaa11ffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffee00080800eeffffffffffffff00ffffaa11ffffffffffff00 +ffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffaa00282800aaffffffffffffff00ffffbb339900 +bb000088331188ffff00660077ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffaa00282800aaffffffffffffff00ffffbb339900 +bb0000ff00ffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770040400077ffffffffffffff0066 +0055eeff00ffff001188ee99ffff00eecc00ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff770040400077ffffffffffffff0066 +0055eeff00ffff00ff00ffff00ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff330060600033ffffffff +ffffff00ffffffffff00ffff00bb4444ccffff00ffff00ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff330060600033ffffffff +ffffff00ffffffffff00ffff00ff00ffff00ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee0011777711 +00eeffffffffffff00ffffffffff00ffee0055ee9911ffff00ffff00ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee0011777711 +00eeffffffffffff00ffffffffff00ffee00ff00ffff00ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ff +ffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa +005577775500aaffffffffffbb0000bbffffff3311884411002277ffaa00ddaa00eeffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa +005577775500aaffffffffffbb0000bbffffff33118844bb00ccbb00ccffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff7700887777880077ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff7700887777880077ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffddee7777eeddffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffddee7777eeddffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffff +ff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff +0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff0044ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0044ffffff00 +22ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +77ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77 +77ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +33ffffff1100ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff0011ffffff5500aaffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffaa0055ffffff990044ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff440099ffffffff220066ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff660022ffffffffffcc110044aaffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffaa440011ccffffffffffffcc22000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000022ccffffffffffffff +ffff99551133444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444442020 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444442020 +444444444444444444444444444444444444444444444444444444444444444444444444 +4444444444444444444444444444444444444444444444444444444433115599ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffbbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffdd0011000022ffffffffffffffffffffffffffffffffffddff +ffffffdd0011000022cc00ffffffffffffffffffffffffffffffffffee0011337777ffff +ff22ffffffffffffffffffffffffffffffddffff22ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00ffffffaaffffffffffffffffffffffffffff +ffffee22ffffffffff00ffffffaaff00ffffffffffffffffffffffffffffffffffff00ff +ffff8877ffffffffffffffffffffffffffffffffffee22ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff00ffffddbbff4411eeee55df4400 +44ffbb22660077440000ffffffff00ffffbbbbff00ffee441155cc8833dd5555ff77bbff +ffffff00ffffffee11ffaa33ff99227770440044ffee771155ee440000aa33ffee441155 +ccbb22660077ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000bbffee22dd +ddaa77000000bbff00ffdd00ff00ffffffffff00000000bbff00ff44ccffcc22ee22ffaa +66ff88ffffffffff00ffffffff00ffff00ffff00ff77000000bb77ccffaaddff00ffff00 +ff44ccffcc22ff00ffdd00ffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffee +ddffff997799ff44eeffffffff00ffff00ff00ffffffffff00ffffeeddff00ff00eeffff +00ff66aa7722ddaaffffffffff00ffffffee00ffff00ffff00ff44eeffffff00ffffffff +ff00ffff00ff00eeffff00ff00ffff00ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff00ffffffeebbffee3399ff6677ffeebbff00ffff00ff00ffffffffff00ffffffffff00 +ff3388ffee33ffcc44998855eeffffffffff00ffffff7755ffff00ffff00ff6677ffeebb +2266ffeeccff00ffff00ff3388ffee33ff00ffff00ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffff7777ffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb66bb7777bb66bb +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffbb0077110000ddffff66ddffcc220066ffbb00ddaa00ee2266ffffffbb0000 +bbffffbb00cccc552222ccffff55ffee66ffffffffffbb0022116677eeffbb00ccaa0055 +cc220066ffcc220077ffff2266bb00cccc552222ccbb00ddaa00eeffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb66bb7777bb66bb +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff880077 +7777770088ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff880077 +7777770088ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffcc003377773300ccffffffffffffffffffffffffffffffffffbbffffbbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffff77aaeeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffcc003377773300ccffffffffffffffffffffffffffffffffffffffffffeebbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff110070700011ffffffffffffdd00110033aaffffffffffcc00ffcc00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffdd0000003377aaeeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff110070700011ffffffffffffdd00110033aaffffffffffffffffffff +aa00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff550050500055ffffffffffffff00ffffaa11ffffffffff +ff00ffff00ffffffffffffffffffffffffffffffffffffffff4444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444440251705 +000000000e202e4044444499ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffff550050500055ffffffffffffff00ffffaa11ffffffffff +ffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff880038380088ffffffffffffff00ffffbb33 +9900bb0000ff00ffff00ffffffffffffffffffffffffffffffffffffffff000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000070ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff880038380088ffffffffffffff00ffffbb33 +9900bb000088331188ffff00660077ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffcc00181800ccffffffffffffff +00660055eeff00ffff00ff00ffff00ffffffffffffffffffffffffffffffffffffffff00 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000070ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffcc00181800ccffffffffffffff +00660055eeff00ffff001188ee99ffff00eecc00ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff11000011ffffff +ffffffffff00ffffffffff00ffff00ff00ffff00ffffffffffffffffffffffffffffffff +ffffffff4444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444440251705000000000e202e4044444499ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff11000011ffffff +ffffffffff00ffffffffff00ffff00bb4444ccffff00ffff00ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5500 +0055ffffffffffffffff00ffffffffff00ffee00ff00ffff00ffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffdd0000003377aaeeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5500 +0055ffffffffffffffff00ffffffffff00ffee0055ee9911ffff00ffff00ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff88000088ffffffffffffffbb0000bbffffff33118844bb00ccbb00ccffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffff77aaeeffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff88000088ffffffffffffffbb0000bbffffff3311884411002277ffaa00ddaa00ee +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffcc0000ccffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffcc0000ccffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff0808ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffff0808ffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff2828ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffff2828ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff4040ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff4040ffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6060ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6060ffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd00110000 +22ffffffffffffffffffffffffffffffffffffddffffff4400bbffffffffffffffffffff +ffffffffffffffffddffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffdd0011000022ffffff +ffffffffffffffffffffffffffffddffffffffffbb77117766ccffffffffffffffddffff +ffffffffffffffffffffffddffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff00ffffffaaffffffffffffffffffffffffffffffffffee22ffffffff00ffffffffffff +ffffffffffffffffffffffffee22ffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff +ffaaffffffffffffffffffffffffffffffffee22ffffffffaa55ffffffcc44ffffffffff +ffee22ffffffffffffffffffffffffee22ffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff00ffffddbbff4411eeee55df440044ffbb22660077ff440000ffffff00ff +ffbb226600779922661199ff9900bb0000440000ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffff00ffffddbbff4411eeee55df440044ffbb22660077440000ffffff22ddffffffff00 +ff9900bb000044000099226611999900bb0000ff440000ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffff00000000bbffee22ddddaa77000000bbff00ffdd00ffff00ff +ffffff00ffffff00ffdd00ff00eeaa22ffff00ffff00ff00ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff00000000bbffee22ddddaa77000000bbff00ffdd00ff00ffffffff00ff +ffffffff00ffff00ffff00ff00ffff00eeaa22ff00ffff00ffff00ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff00ffffeeddffff997799ff44eeffffffff00ffff +00ffff00ffffffff00ffffff00ffff00ff00ffff00ffff00ffff00ff00ffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff00ffffeeddffff997799ff44eeffffffff00ffff00ff00ff +ffffff22bbffffffee22ffff00ffff00ff00ffff00ffff00ff00ffff00ffff00ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff00ffffffeebbffee3399ff6677ffee +bbff00ffff00ffff00ffffffff00ffffff00ffff00ff00ffcc44ffff00ffee00ff00ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffff00ffffffeebbffee3399ff6677ffeebbff00ff +ff00ff00ffffffffaa33eeffffaa77ffff00ffee00ff00ffff00ffcc44ff00ffee00ffff +00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffbb0077110000ddffff66dd +ffcc220066ffbb00ddaa00eeff2266ffffbb000077bb00ddaa00ee002222ccffff331188 +44ff2266ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffbb0077110000ddffff66ddffcc2200 +66ffbb00ddaa00ee2266ffffffffaa66443377ffffff33118844ff2266ff002222ccff33 +118844ffff2266ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff1100eeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffff1100eeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffccffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffccffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +%%EndData +%%PageTrailer +%%Trailer +%%BoundingBox: 105 212 506 579 +%%EOF diff --git a/lib/cosNotification/doc/src/part.xml b/lib/cosNotification/doc/src/part.xml new file mode 100644 index 0000000000..06ae875c01 --- /dev/null +++ b/lib/cosNotification/doc/src/part.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>cosNotification User's Guide</title> + <prepared>Niclas Eklund</prepared> + <docno></docno> + <date>2000-01-31</date> + <rev>1.0</rev> + </header> + <description> + <p>The <em>cosNotification</em> application is an Erlang implementation + of the OMG CORBA Notification Service.</p> + </description> + <xi:include href="ch_contents.xml"/> + <xi:include href="ch_introduction.xml"/> + <xi:include href="ch_install.xml"/> + <xi:include href="ch_system.xml"/> + <xi:include href="ch_BNF.xml"/> + <xi:include href="ch_QoS.xml"/> + <xi:include href="ch_example.xml"/> +</part> + diff --git a/lib/cosNotification/doc/src/part_notes.xml b/lib/cosNotification/doc/src/part_notes.xml new file mode 100644 index 0000000000..af262c3d0e --- /dev/null +++ b/lib/cosNotification/doc/src/part_notes.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>cosNotification Release Notes</title> + <prepared>Niclas Eklund</prepared> + <docno></docno> + <date>2000-01-31</date> + <rev>1.0</rev> + </header> + <description> + <p>The cosNotification Application is an Erlang implementation of the OMG + CORBA Notification Service.</p> + </description> + <xi:include href="notes.xml"/> +</part> + diff --git a/lib/cosNotification/doc/src/ref_man.gif b/lib/cosNotification/doc/src/ref_man.gif Binary files differnew file mode 100644 index 0000000000..b13c4efd53 --- /dev/null +++ b/lib/cosNotification/doc/src/ref_man.gif diff --git a/lib/cosNotification/doc/src/ref_man.xml b/lib/cosNotification/doc/src/ref_man.xml new file mode 100644 index 0000000000..1cf77c3c7f --- /dev/null +++ b/lib/cosNotification/doc/src/ref_man.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE application SYSTEM "application.dtd"> + +<application xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>cosNotification Reference Manual</title> + <prepared>Niclas Eklund</prepared> + <docno></docno> + <date>2000-01-31</date> + <rev>1.0</rev> + </header> + <description> + <p>The <em>cosNotification</em> application is an Erlang implementation + of the OMG CORBA Notification Service.</p> + </description> + <xi:include href="cosNotificationApp.xml"/> + <xi:include href="CosNotifyChannelAdmin_EventChannelFactory.xml"/> + <xi:include href="CosNotifyChannelAdmin_EventChannel.xml"/> + <xi:include href="CosNotification.xml"/> + <xi:include href="CosNotification_QoSAdmin.xml"/> + <xi:include href="CosNotification_AdminPropertiesAdmin.xml"/> + <xi:include href="CosNotifyChannelAdmin_ConsumerAdmin.xml"/> + <xi:include href="CosNotifyChannelAdmin_SupplierAdmin.xml"/> + <xi:include href="CosNotifyComm_NotifyPublish.xml"/> + <xi:include href="CosNotifyComm_NotifySubscribe.xml"/> + <xi:include href="CosNotifyFilter_FilterAdmin.xml"/> + <xi:include href="CosNotifyFilter_FilterFactory.xml"/> + <xi:include href="CosNotifyFilter_Filter.xml"/> + <xi:include href="CosNotifyFilter_MappingFilter.xml"/> + <xi:include href="CosNotifyChannelAdmin_ProxyConsumer.xml"/> + <xi:include href="CosNotifyChannelAdmin_ProxySupplier.xml"/> + <xi:include href="CosNotifyChannelAdmin_ProxyPullConsumer.xml"/> + <xi:include href="CosNotifyChannelAdmin_ProxyPullSupplier.xml"/> + <xi:include href="CosNotifyChannelAdmin_ProxyPushConsumer.xml"/> + <xi:include href="CosNotifyChannelAdmin_ProxyPushSupplier.xml"/> + <xi:include href="CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml"/> + <xi:include href="CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml"/> + <xi:include href="CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml"/> + <xi:include href="CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml"/> + <xi:include href="CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml"/> + <xi:include href="CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml"/> + <xi:include href="CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml"/> + <xi:include href="CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml"/> +</application> + diff --git a/lib/cosNotification/doc/src/summary.html.src b/lib/cosNotification/doc/src/summary.html.src new file mode 100644 index 0000000000..92ade4f9cd --- /dev/null +++ b/lib/cosNotification/doc/src/summary.html.src @@ -0,0 +1 @@ +Orber OMG Notification Service
\ No newline at end of file diff --git a/lib/cosNotification/doc/src/user_guide.gif b/lib/cosNotification/doc/src/user_guide.gif Binary files differnew file mode 100644 index 0000000000..e6275a803d --- /dev/null +++ b/lib/cosNotification/doc/src/user_guide.gif diff --git a/lib/cosNotification/ebin/.gitignore b/lib/cosNotification/ebin/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/cosNotification/ebin/.gitignore diff --git a/lib/cosNotification/examples/.gitignore b/lib/cosNotification/examples/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/cosNotification/examples/.gitignore diff --git a/lib/cosNotification/include/.gitignore b/lib/cosNotification/include/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/cosNotification/include/.gitignore diff --git a/lib/cosNotification/info b/lib/cosNotification/info new file mode 100644 index 0000000000..1b634eb124 --- /dev/null +++ b/lib/cosNotification/info @@ -0,0 +1,3 @@ +group: orb +short: Orber OMG Notification Service + diff --git a/lib/cosNotification/priv/.gitignore b/lib/cosNotification/priv/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/cosNotification/priv/.gitignore diff --git a/lib/cosNotification/src/CosEvent.cfg b/lib/cosNotification/src/CosEvent.cfg new file mode 100644 index 0000000000..e3399139a4 --- /dev/null +++ b/lib/cosNotification/src/CosEvent.cfg @@ -0,0 +1,20 @@ +{this, "CosEventChannelAdmin::EventChannel"}. +{{handle_info, "CosEventChannelAdmin::EventChannel"}, true}. +{this, "CosEventChannelAdmin::EventChannelFactory"}. +{{handle_info, "CosEventChannelAdmin::EventChannelFactory"}, true}. +{this, "CosEventChannelAdmin::SupplierAdmin"}. +{{handle_info, "CosEventChannelAdmin::SupplierAdmin"}, true}. +{this, "CosEventChannelAdmin::ConsumerAdmin"}. +{{handle_info, "CosEventChannelAdmin::ConsumerAdmin"}, true}. +{this, "CosEventChannelAdmin::ProxyPushSupplier"}. +{{handle_info, "CosEventChannelAdmin::ProxyPushSupplier"}, true}. +{{impl, "CosEventChannelAdmin::ProxyPushSupplier"}, "PusherSupplier_impl"}. +{this, "CosEventChannelAdmin::ProxyPullSupplier"}. +{{handle_info, "CosEventChannelAdmin::ProxyPullSupplier"}, true}. +{{impl, "CosEventChannelAdmin::ProxyPullSupplier"}, "PullerSupplier_impl"}. +{this, "CosEventChannelAdmin::ProxyPushConsumer"}. +{{handle_info, "CosEventChannelAdmin::ProxyPushConsumer"}, true}. +{{impl, "CosEventChannelAdmin::ProxyPushConsumer"}, "PusherConsumer_impl"}. +{this, "CosEventChannelAdmin::ProxyPullConsumer"}. +{{handle_info, "CosEventChannelAdmin::ProxyPullConsumer"}, true}. +{{impl, "CosEventChannelAdmin::ProxyPullConsumer"}, "PullerConsumer_impl"}. diff --git a/lib/cosNotification/src/CosNotification.cfg b/lib/cosNotification/src/CosNotification.cfg new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/cosNotification/src/CosNotification.cfg diff --git a/lib/cosNotification/src/CosNotification.idl b/lib/cosNotification/src/CosNotification.idl new file mode 100644 index 0000000000..e080b44b0c --- /dev/null +++ b/lib/cosNotification/src/CosNotification.idl @@ -0,0 +1,146 @@ +#ifndef _COS_NOTIFICATION_IDL_ +#define _COS_NOTIFICATION_IDL_ + +#pragma prefix "omg.org" + +#include"CosEventChannelAdmin.idl" +#include"CosEventComm.idl" + +module CosNotification { + typedef string Istring; + typedef Istring PropertyName; + typedef any PropertyValue; + struct Property { + PropertyName name; + PropertyValue value; + }; + typedef sequence<Property> PropertySeq; + // The following are the same, but serve different purposes. + typedef PropertySeq OptionalHeaderFields; + typedef PropertySeq FilterableEventBody; + typedef PropertySeq QoSProperties; + typedef PropertySeq AdminProperties; + struct EventType { + string domain_name; + string type_name; + }; + typedef sequence<EventType> EventTypeSeq; + struct PropertyRange { + PropertyValue low_val; + PropertyValue high_val; + }; + struct NamedPropertyRange { + PropertyName name; + PropertyRange range; + }; + + typedef sequence<NamedPropertyRange> NamedPropertyRangeSeq; + + enum QoSError_code { + UNSUPPORTED_PROPERTY, + UNAVAILABLE_PROPERTY, + UNSUPPORTED_VALUE, + UNAVAILABLE_VALUE, + BAD_PROPERTY, + BAD_TYPE, + BAD_VALUE + }; + + struct PropertyError { + QoSError_code code; + PropertyName name; + PropertyRange available_range; + }; + + typedef sequence<PropertyError> PropertyErrorSeq; + exception UnsupportedQoS { PropertyErrorSeq qos_err; }; + exception UnsupportedAdmin { PropertyErrorSeq admin_err; }; + + // Define the Structured Event structure + struct FixedEventHeader { + EventType event_type; + string event_name; + }; + struct EventHeader { + FixedEventHeader fixed_header; + OptionalHeaderFields variable_header; + }; + + struct StructuredEvent { + EventHeader header; + FilterableEventBody filterable_data; + any remainder_of_body; + }; // StructuredEvent + + typedef sequence<StructuredEvent> EventBatch; + + // The following constant declarations define the standard + // QoS property names and the associated values each property + // can take on. The name/value pairs for each standard property + // are grouped, beginning with a string constant defined for the + // property name, followed by the values the property can take on. + const string EventReliability = "EventReliability"; + const short BestEffort = 0; + const short Persistent = 1; + const string ConnectionReliability = "ConnectionReliability"; + + // Can take on the same values as EventReliability + const string Priority = "Priority"; + const short LowestPriority = -32767; + const short HighestPriority = 32767; + const short DefaultPriority = 0; + const string StartTime = "StartTime"; + + // StartTime takes a value of type TimeBase::UtcT. + const string StopTime = "StopTime"; + // StopTime takes a value of type TimeBase::UtcT. + const string Timeout = "Timeout"; + // Timeout takes on a value of type TimeBase::TimeT + const string OrderPolicy = "OrderPolicy"; + const short AnyOrder = 0; + const short FifoOrder = 1; + const short PriorityOrder = 2; + const short DeadlineOrder = 3; + const string DiscardPolicy = "DiscardPolicy"; + // DiscardPolicy takes on the same values as OrderPolicy, plus + const short LifoOrder = 4; + const short RejectNewEvents = 5; + const string MaximumBatchSize = "MaximumBatchSize"; + // MaximumBatchSize takes on a value of type long + const string PacingInterval = "PacingInterval"; + // PacingInterval takes on a value of type TimeBase::TimeT + const string StartTimeSupported = "StartTimeSupported"; + // StartTimeSupported takes on a boolean value + const string StopTimeSupported = "StopTimeSupported"; + // StopTimeSupported takes on a boolean value + const string MaxEventsPerConsumer = "MaxEventsPerConsumer"; + // MaxEventsPerConsumer takes on a value of type long + + interface QoSAdmin { + QoSProperties get_qos(); + void set_qos ( in QoSProperties qos) + raises ( UnsupportedQoS ); + void validate_qos (in QoSProperties required_qos, + out NamedPropertyRangeSeq available_qos ) + raises ( UnsupportedQoS ); + }; // QosAdmin + + // Admin properties are defined in similar manner as QoS + // properties. The only difference is that these properties + // are related to channel administration policies, as opposed + // message quality of service + const string MaxQueueLength = "MaxQueueLength"; + // MaxQueueLength takes on a value of type long + const string MaxConsumers = "MaxConsumers"; + // MaxConsumers takes on a value of type long + const string MaxSuppliers = "MaxSuppliers"; + // MaxSuppliers takes on a value of type long + interface AdminPropertiesAdmin { + AdminProperties get_admin(); + void set_admin (in AdminProperties admin) + raises ( UnsupportedAdmin); + };// AdminPropertiesAdmin +}; // CosNotification + +#endif /* ifndef _COS_NOTIFICATION_IDL_ */ + diff --git a/lib/cosNotification/src/CosNotification_Common.erl b/lib/cosNotification/src/CosNotification_Common.erl new file mode 100644 index 0000000000..0e0f1da0d5 --- /dev/null +++ b/lib/cosNotification/src/CosNotification_Common.erl @@ -0,0 +1,1210 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%-------------------------------------------------------------------- +%% File : CosNotification_Common.erl +%% Purpose : +%%-------------------------------------------------------------------- + +-module('CosNotification_Common'). + + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). + +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%% External MISC +-export([get_option/3, + create_name/2, + create_name/1, + create_id/0, + create_id/1, + is_debug_compiled/0, + type_check/2, + send_stubborn/5, + create_link/3, + disconnect/3, + do_disconnect/3, + notify/1]). + +%% Internal AdminProperties +-export([init_adm/1, + set_adm/2, + 'MaxQueueLength'/6, + 'MaxConsumers'/6, + 'MaxSuppliers'/6]). +%% Internal QoS +-export([init_qos/1, + set_qos/5, + validate_qos/5, + validate_event_qos/2, + 'EventReliability'/6, + 'ConnectionReliability'/6, + 'Priority'/6, + 'StartTimeSupported'/6, + 'StopTimeSupported'/6, + 'Timeout'/6, + 'OrderPolicy'/6, + 'DiscardPolicy'/6, + 'MaximumBatchSize'/6, + 'PacingInterval'/6, + 'MaxEventsPerConsumer'/6]). + +%%--------------- DEFINITIONS OF CONSTANTS ------------------- +%%--------------- EXTERNAL MISC FUNCTIONS -------------------- +%%------------------------------------------------------------ +%% function : create_link +%% Arguments: Module - which Module to call +%% Env/ArgList - ordinary oe_create arguments. +%% Returns : +%% Exception: +%% Effect : Necessary since we want the supervisor to be a +%% 'simple_one_for_one'. Otherwise, using for example, +%% 'one_for_one', we have to call supervisor:delete_child +%% to remove the childs startspecification from the +%% supervisors internal state. +%%------------------------------------------------------------ +create_link(Module, Env, ArgList) -> + Module:oe_create_link(Env, ArgList). + +%%-----------------------------------------------------------% +%% function : get_option +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +get_option(Key, OptionList, DefaultList) -> + case lists:keysearch(Key, 1, OptionList) of + {value,{Key,Value}} -> + Value; + _ -> + case lists:keysearch(Key, 1, DefaultList) of + {value,{Key,Value}} -> + Value; + _-> + {error, "Invalid option"} + end + end. +%%-----------------------------------------------------------% +%% function : create_name/2 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +create_name(Name,Type) -> + {MSec, Sec, USec} = erlang:now(), + lists:concat(['oe_',node(),'_',Type,'_',Name,'_',MSec, '_', Sec, '_', USec]). + +%%-----------------------------------------------------------% +%% function : create_name/1 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +create_name(Type) -> + {MSec, Sec, USec} = erlang:now(), + lists:concat(['oe_',node(),'_',Type,'_',MSec, '_', Sec, '_', USec]). + +%%------------------------------------------------------------ +%% function : create_id/0 +%% Arguments: - +%% Returns : id (long) =/= 0 +%% Both default Admin:s have the unique id 0 (OMG spec, 98-11-01, +%% Notification p 148), hence, we may not return 0. +%% Exception: +%% Purpose : Throughout the CosNotification service we use, +%% according to the OMG specification, id:s (long), +%% which must be "unique", to retrieve object references. +%% For example: CosNotifyChannelAdmin::ChannelId/AdminID. +%%------------------------------------------------------------ +create_id(-1) -> + 1; +create_id( 2147483647) -> + -2147483648; +create_id(OldID) -> + OldID+1. + +create_id() -> + {_A,_B,C}=now(), + C. + +%%-----------------------------------------------------------% +%% function : type_check +%% Arguments: Obj - objectrefernce to test. +%% Mod - Module which contains typeID/0. +%% Returns : 'ok' or raises exception. +%% Effect : +%%------------------------------------------------------------ +type_check(Obj, Mod) -> + case cosNotificationApp:type_check() of + false -> + ok; + _ -> + case catch corba_object:is_a(Obj,Mod:typeID()) of + true -> + ok; + false -> + orber:dbg("[~p] CosNotification_Common:type_check(~p);~n" + "The supplied Object is not or does not inherrit from: ~p", + [?LINE, Obj, Mod], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}); + {'EXCEPTION', E} -> + orber:dbg("[~p] CosNotification_Common:type_check(~p, ~p);~n" + "Failed due to: ~p", + [?LINE, Obj, Mod, E], ?DEBUG_LEVEL), + corba:raise(E); + What -> + orber:dbg("[~p] CosNotification_Common:type_check(~p, ~p);~n" + "Failed due to: ~p", + [?LINE, Obj, Mod, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end + end. + + +%%-----------------------------------------------------------% +%% function : notify +%% Arguments: Items - [Item] +%% Item - {proxy, IOR} | {client, IOR} | {reason, term()} +%% Returns : 'ok' or raises exception. +%% Effect : +%%------------------------------------------------------------ +notify(Items) -> + case cosNotificationApp:notify() of + false -> + ok; + Module -> + catch Module:terminated(Items), + ok + end. + + +%%------------------------------------------------------------ +%% function : send_stubborn +%% Arguments: M - module +%% F - function +%% A - arguments +%% MaxR - Maximum no retries +%% Wait - sleep Wait seconds before next try. +%% Returns : see effect +%% Exception: +%% Effect : Retries repeatidly untill anything else besides +%% 'EXIT', 'COMM_FAILURE' or 'OBJECT_NOT_EXIST' +%%------------------------------------------------------------ + +send_stubborn(M, F, A, MaxR, Wait) when is_list(A) -> + send_stubborn(M, F, A, MaxR, Wait, 0); +send_stubborn(M, F, A, MaxR, Wait) -> + send_stubborn(M, F, [A], MaxR, Wait, 0). +send_stubborn(M, F, A, MaxR, _Wait, MaxR) -> + orber:dbg("[~p] CosNotification_Common:send_stubborn( ~p ~p ~p ~p).~n" + "Failed to deliver the event.~n", [?LINE, M,F,A,MaxR], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}); +send_stubborn(M, F, A, MaxR, Wait, Times) -> + ?debug_print("~p:~p(~p) # of retries: ~p~n", [M,F,A, Times]), + case catch apply(M,F,A) of + {'EXCEPTION', E} when is_record(E, 'COMM_FAILURE')-> + NewTimes = Times +1, + timer:sleep(Wait), + send_stubborn(M, F, A, MaxR, Wait, NewTimes); + {'EXIT', _} -> + NewTimes = Times +1, + timer:sleep(Wait), + send_stubborn(M, F, A, MaxR, Wait, NewTimes); + Other -> + Other + end. + + +%%-----------------------------------------------------------% +%% function : disconnect +%% Arguments: Module - one of the interfaces defined in CosEventComm. +%% Function - the appropriate disconnect function. +%% Object - the client object reference. +%% Returns : ok +%% Exception: +%% Effect : If the process would try to diconnect itself it could +%% result in a deadlock. Hence, we spawn a new process to do it. +%%------------------------------------------------------------ +disconnect(Module, Function, Object) -> + spawn(?MODULE, do_disconnect, [Module, Function, Object]), + ok. + +do_disconnect(Module, Function, Object) -> + catch Module:Function(Object), + ?DBG("Disconnect ~p:~p(..).~n", [Module, Function]), + ok. + + + +%%------------------------------------------------------------ +%% function : is_debug_compiled +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ + +-ifdef(debug). + is_debug_compiled() -> true. +-else. + is_debug_compiled() -> false. +-endif. + + +%%------------------------------------------------------------ +%%--------------- AdminPropertiesAdmin ----------------------- +%%------------------------------------------------------------ +%%------------------------------------------------------------ +%% function : init_adm +%% Arguments: Wanted - requested Admins to be set. +%% Returns : #'CosNotification_UnsupportedAdmin'{} | +%% {NewAdmProperties, [MaxQ, MaxC, MaxS]} +%% Effect : may only be used when creating a channel!!!!!!!! +%%------------------------------------------------------------ +init_adm(Wanted) -> + {NewA,_} = set_properties(Wanted, ?not_DEFAULT_ADMINPROPERTIES, channelAdm, + ?not_SUPPORTED_ADMINPROPERTIES, [], [], + false, false, false), + {NewA, [extract_value(NewA, ?not_MaxQueueLength), + extract_value(NewA, ?not_MaxConsumers), + extract_value(NewA, ?not_MaxSuppliers)]}. + +set_adm(Wanted, Current) -> + {NewA,_} = set_properties(Wanted, Current, channelAdm, + ?not_SUPPORTED_ADMINPROPERTIES, + [], [], false, false, false), + {NewA, [extract_value(NewA, ?not_MaxQueueLength), + extract_value(NewA, ?not_MaxConsumers), + extract_value(NewA, ?not_MaxSuppliers)]}. + +'MaxQueueLength'(Req,channelAdm,_, _, _, _) -> admin_ok(Req). +'MaxConsumers'(Req,channelAdm,_, _, _, _)-> admin_ok(Req). +'MaxSuppliers'(Req,channelAdm,_, _, _, _)-> admin_ok(Req). + +admin_ok(Req) -> + case any:get_value(Req#'CosNotification_Property'.value) of + Val when is_integer(Val) andalso Val >= 0 -> + {ok, Req}; + _ -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end. + + +%%------------------------------------------------------------ +%%--------------- QOS FUNCTIONS ------------------------------ +%%------------------------------------------------------------ +%%------------------------------------------------------------ +%% function : init_qos +%% Arguments: Wanted - requested QoS to be set. +%% Returns : see set_properties/9 +%% Effect : may only be used when creating a channel!!!!!!!! +%%------------------------------------------------------------ +init_qos(Wanted) -> + LQS = set_local_qos(?not_DEFAULT_QOS, ?not_CreateInitQoS()), + set_properties(Wanted, ?not_DEFAULT_QOS, channel, ?not_SUPPORTED_QOS, + [], [], false, [], LQS). + +%%------------------------------------------------------------ +%% function : set_qos/5 +%% Arguments: Wanted - requested QoS to be set. +%% Current - current QoS OMG style +%% LQS - local representation of QoS. +%% Type - channel | admin | proxy +%% Parent - Factory if Channel, Channel if Admin etc +%% Childs - Admins if Channel etc +%% Returns : see set_properties/9 +%%------------------------------------------------------------ +set_qos(Wanted, {Current, LQS}, proxy, Parent, _) -> + set_properties(Wanted, Current, proxy, ?not_SUPPORTED_QOS, [], [], Parent, false,LQS); +set_qos(Wanted, {Current, LQS}, admin, Parent, Childs) -> + set_properties(Wanted, Current, admin, ?not_SUPPORTED_QOS, [], [], Parent, Childs,LQS); +set_qos(Wanted, {Current, LQS}, channel, _, Childs) -> + set_properties(Wanted, Current, channel, ?not_SUPPORTED_QOS, [], [], false, Childs,LQS). + +%%------------------------------------------------------------ +%% function : +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : ok - if requested equal to current value. +%% {ok, Req, LQS} - if new and allowed QoS +%% {unsupported,#'CosNotification_PropertyError'{}} otherwise. +%% Effect : +%%------------------------------------------------------------ +'EventReliability'(Req,channel, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of + {Val, Val, _, _} -> + %% Is the value requested. + ok; + {Val, _, Val, _} -> + {ok, Req, LQS}; + {Val, _, _, Val} -> + {ok, Req, LQS}; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end; +'EventReliability'(Req,_,_,_,_,_) -> + %% only valid to set this QoS for channels (or per-event). + {unsupported, + #'CosNotification_PropertyError'{ + code = 'UNAVAILABLE_PROPERTY', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + }. + +%%------------------------------------------------------------ +%% function : 'ConnectionReliability'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +%% The most complex QoS to set is ConnectionReliability, and the reason for this +%% is that we cannot set the Channel to offer best effort while its children +%% offer persistent. A child may only offer Persistent if its parent do, which +%% is why we must check the following: +%% +%% # Persistent Change to Best Effort +%% _____ +%% | | (1) -> Check if children BE +%% |Chann| (2) ok <- +%% ----- +%% | +%% _____ +%% | | (3) -> Check if children BE +%% |Admin| (4) Check if parent Pers. <- +%% ----- +%% | +%% _____ +%% | | (5) -> ok +%% |Proxy| (6) Check if parent Pers. <- +%% ----- +%% NOTE: a parent always exists but we may change the QoS before creating any +%% childrens. The cases (2) and (5) is always ok, i.e., no need to confirm +%% with parent or children. +%%------------------------------------------------------------ +'ConnectionReliability'(Req, channel, _Curr, _Parent, Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of + {Val, Val, _, _} -> + %% Is the value requested. + ok; + {Val, P, Val, P} -> + %% Requested is BestEffort, Current Persistent => (1) + check_with_relatives(Childs, Req, LQS); + {Val, B, B, Val} -> + %% Requested is Persistent, Current BestEffort => (2) + {ok, Req, LQS}; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end; +'ConnectionReliability'(Req, admin, _Curr, Parent, Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of + {Val, Val, _, _} -> + %% Is the value requested. + ok; + {Val, P, Val, P} -> + %% Requested is BestEffort, Current Persistent => (3) + check_with_relatives(Childs, Req, LQS); + {Val, B, B, Val} -> + %% Requested is Persistent, Current BestEffort => (4) + check_with_relatives([Parent], Req, LQS); + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end; +'ConnectionReliability'(Req, proxy, _Curr, Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of + {Val, Val, _, _} -> + %% Is the value requested. + ok; + {Val, P, Val, P} -> + %% Requested is BestEffort, Current Persistent => (5) + {ok, Req, LQS}; + {Val, B, B, Val} -> + %% Requested is Persistent, Current BestEffort => (6) + check_with_relatives([Parent], Req, LQS); + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end. + +%%------------------------------------------------------------ +%% function : 'Priority'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'Priority'(Req, _Type, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetPriority(LQS), ?not_HighestPriority, ?not_LowestPriority} of + {Val, Val, _, _} -> + ok; + {Val, _, H, L} when Val =< H, Val >= L -> + {ok, Req, LQS}; + {_, _, H, L} -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), L), + high_val=any:create(orber_tc:short(), H) + } + } + } + end. + +%%------------------------------------------------------------ +%% function : 'StartTimeSupported'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'StartTimeSupported'(Req, _Type, _Curr, _, _, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetStartTimeSupported(LQS)} of + {Val, Val} -> + ok; + {Val, _} when Val =/= true, Val =/= false -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:boolean(), false), + high_val=any:create(orber_tc:boolean(), true) + } + } + }; + _-> + {ok, Req, LQS} + end. + +%%------------------------------------------------------------ +%% function : 'StopTimeSupported'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'StopTimeSupported'(Req, _Type, _Curr, _, _, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetStopTimeSupported(LQS)} of + {Val, Val} -> + ok; + {Val, _} when Val =/= true, Val =/= false -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:boolean(), false), + high_val=any:create(orber_tc:boolean(), true) + } + } + }; + _-> + {ok, Req, LQS} + end. + +%%------------------------------------------------------------ +%% function : 'Timeout'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'Timeout'(Req, _Type, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetTimeout(LQS)} of + {Val, Val} -> + ok; + {Val, _} when Val >= ?not_MinTimeout, Val =< ?not_MaxTimeout -> + {ok, Req, LQS}; + {Val, _} when is_integer(Val) -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinTimeout), + high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxTimeout) + } + } + }; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end. + +%%------------------------------------------------------------ +%% function : 'OrderPolicy'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'OrderPolicy'(Req, _Type, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetOrderPolicy(LQS), 'CosNotification':'AnyOrder'(), + 'CosNotification':'PriorityOrder'()} of + {Val, Val,_,_} -> + ok; + {Val, _, L, H} when Val >= L, Val =< H -> + {ok, Req, LQS}; + {Val, _, L, H} when is_integer(Val) -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), L), + high_val=any:create(orber_tc:short(), H) + } + } + }; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end. + + +%%------------------------------------------------------------ +%% function : 'DiscardPolicy'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'DiscardPolicy'(Req, _Type, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetDiscardPolicy(LQS), ?not_AnyOrder, ?not_PriorityOrder} of + {Val, Val,_,_} -> + ok; + {Val, _, L, H} when Val >= L, Val =< H -> + {ok, Req, LQS}; + {Val, _, L, H} when is_integer(Val) -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), L), + high_val=any:create(orber_tc:short(), H) + } + } + }; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end. + +%%------------------------------------------------------------ +%% function : 'DiscardPolicy'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'MaximumBatchSize'(Req, _Type, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetMaximumBatchSize(LQS)} of + {Val, Val} -> + ok; + {Val, _} when Val >= ?not_MinBatchSize, Val =< ?not_MaxBatchSize -> + {ok, Req, LQS}; + {Val, _} when is_integer(Val) -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinBatchSize), + high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxBatchSize) + } + } + }; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'UNSUPPORTED_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:long(), ?not_MinBatchSize), + high_val=any:create(orber_tc:long(), ?not_MaxBatchSize) + } + } + } + end. + +%%------------------------------------------------------------ +%% function : 'PacingInterval'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Comment : PacingInterval is defined to be: +%% * TimeBase::UtcT (p 57, 2.5.5, OMG TC Document telecom/98-11-01) +%% * TimeBase::TimeT (p 189, appendix B, OMG TC Document telecom/98-11-01) +%% This implementation use TimeBase::TimeT, especially since +%% TimeBase::UtcT contains information which are of no importance. +%% When writing this, the OMG homepage contained no information +%% regarding this. +%%------------------------------------------------------------ +'PacingInterval'(Req, _Type, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetPacingInterval(LQS)} of + {Val, Val} -> + ok; + {Val, _} when Val >= ?not_MinPacing, Val =< ?not_MaxPacing -> + {ok, Req, LQS}; + {Val, _} when is_integer(Val) -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinPacing), + high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxPacing) + } + } + }; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end. + +%%------------------------------------------------------------ +%% function : 'MaxEventsPerConsumer'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'MaxEventsPerConsumer'(Req, _Type, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetMaxEventsPerConsumer(LQS)} of + {Val, Val} -> + ok; + {Val, _} when is_integer(Val) andalso + Val >= ?not_MinConsumerEvents andalso + Val =< ?not_MaxConsumerEvents -> + {ok, Req, LQS}; + {Val, _} when is_integer(Val) -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinConsumerEvents), + high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxConsumerEvents) + } + } + }; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'UNSUPPORTED_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:long(), ?not_MinConsumerEvents), + high_val=any:create(orber_tc:long(), ?not_MaxConsumerEvents) + } + } + } + end. + +%%------------------------------------------------------------ +%% function : validate_qos/5 +%% Arguments: Wanted - requested QoS to be set. +%% Curr - current QoS OMG style and LQS, local +%% representation of QoS, grouped as {OMGQ, LQS} +%% Type - channel | admin | proxy +%% Parent - Factory if Channel, Channel if Admin etc +%% Childs - Admins if Channel etc +%% Returns : NamedPropertySeq | #'CosNotification_UnsupportedQoS'{} +%% case 1 if all supported, case 2 if at least 1 QoS not +%% supported. +%% See also p59, 2.5.6.4, OMG TC Document telecom/98-11-01. Quote: +%% "If the supplied QoS is supported, it returns additional QoS +%% properties which could be optionally added as well." +%%------------------------------------------------------------ +validate_qos(Wanted, Curr, Type, Parent, Childs) -> + %% If not supported this function will raise an exception, which we should + %% not catch, but all we need to is to raise the exception as it is. + {_, LQS}=set_qos(Wanted, Curr, Type, Parent, Childs), + NewNPR = check_limits(LQS, ?not_QOS_LIMITS), + remove_qos(Wanted, LQS, NewNPR). + +remove_qos([], _, NPR) -> + NPR; +remove_qos([H|T], LQS, NPR) -> + NewNPR=remove(NPR, H#'CosNotification_Property'.name), + remove_qos(T, LQS, NewNPR). + +check_limits(LQS, NPR) -> + case {?not_GetEventReliability(LQS), ?not_GetConnectionReliability(LQS), + ?not_Persistent, ?not_BestEffort} of + {P,P,P,_B} -> + New = #'CosNotification_NamedPropertyRange' + {name=?not_EventReliability, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), ?not_BestEffort), + high_val=any:create(orber_tc:short(), ?not_BestEffort) + }}, + NewNPR=change(NPR, ?not_EventReliability, New), + remove(NewNPR, ?not_ConnectionReliability); + {_,B,_P,B} -> + remove(NPR, ?not_EventReliability); + {B,P,P,B} -> + New = #'CosNotification_NamedPropertyRange' + {name=?not_ConnectionReliability, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), ?not_BestEffort), + high_val=any:create(orber_tc:short(), ?not_BestEffort) + }}, + change(NPR, ?not_ConnectionReliability, New) + end. + +%%------------------------------------------------------------ +%% function : validate_event_qos/2 +%% Arguments: Wanted - requested QoS to be set. +%% Curr - LQS, local representation of QoS +%% Returns : NamedPropertySeq | #'CosNotification_UnsupportedQoS'{} +%% case 1 if all supported, case 2 if at least 1 QoS not +%% supported. +%%------------------------------------------------------------ +validate_event_qos(Wanted, Curr) -> + v_e_q_helper(Wanted, Curr, []), + []. +v_e_q_helper([], _Curr, []) -> + %% Parsed all and foynd no conflicts. + ok; +v_e_q_helper([], _Curr, Unsupp) -> + %% Not possible to use these requested QoS. + corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Unsupp}); + +%%--- EventReliability ---%% +v_e_q_helper([#'CosNotification_Property'{name=?not_EventReliability, + value=#any{value=?not_BestEffort}}|T], Curr, Unsupp) -> + %% Always ok. + v_e_q_helper(T, Curr, Unsupp); +v_e_q_helper([#'CosNotification_Property'{name=?not_EventReliability, + value=#any{value=?not_Persistent}}|T], Curr, Unsupp) + when ?not_GetConnectionReliability(Curr) =/= ?not_BestEffort, + ?not_GetEventReliability(Curr) =/= ?not_BestEffort, + ?not_GetStopTimeSupported(Curr) =/= true -> + v_e_q_helper(T, Curr, Unsupp); +v_e_q_helper([#'CosNotification_Property'{name=?not_EventReliability}|T], + Curr, Unsupp) -> + %% Impossible to set to Persistent if the connection reliability is best effort. + v_e_q_helper(T, Curr, [#'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', name = ?not_EventReliability, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null)}}|Unsupp]); + +%%--- Priority ---%% +v_e_q_helper([#'CosNotification_Property'{name=?not_Priority, value=#any{value=V}}|T], Curr, + Unsupp) -> + if + ?not_GetOrderPolicy(Curr) =/= ?not_AnyOrder, + ?not_GetOrderPolicy(Curr) =/= ?not_Priority, + ?not_GetDiscardPolicy(Curr) =/= ?not_Priority -> + %% No use setting Priority since it's not currently used. + v_e_q_helper(T, Curr, [#'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', name = ?not_Priority, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + }}|Unsupp]); + V =< ?not_HighestPriority, V >= ?not_LowestPriority -> + v_e_q_helper(T, Curr, Unsupp); + true -> + v_e_q_helper(T, Curr, [#'CosNotification_PropertyError' + {code = 'BAD_VALUE', name = ?not_Priority, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), + ?not_LowestPriority), + high_val=any:create(orber_tc:short(), + ?not_HighestPriority)}}|Unsupp]) + end; + +%%--- StartTime ---%% +v_e_q_helper([#'CosNotification_Property'{name=?not_StartTime}|T], Curr, Unsupp) + when ?not_GetStartTimeSupported(Curr) =/= false, + ?not_GetEventReliability(Curr) =/= ?not_Persistent -> + v_e_q_helper(T, Curr, Unsupp); +v_e_q_helper([#'CosNotification_Property'{name=?not_StartTime}|T], Curr, Unsupp) -> + v_e_q_helper(T, Curr, [#'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', name = ?not_StartTime, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + }}|Unsupp]); + +%%--- StopTime ---%% +v_e_q_helper([#'CosNotification_Property'{name=?not_StopTime}|T], Curr, Unsupp) + when ?not_GetStopTimeSupported(Curr) =/= false, + ?not_GetEventReliability(Curr) =/= ?not_Persistent -> + v_e_q_helper(T, Curr, Unsupp); +v_e_q_helper([#'CosNotification_Property'{name=?not_StopTime}|T], Curr, Unsupp) -> + v_e_q_helper(T, Curr, [#'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', name = ?not_StopTime, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + }}|Unsupp]); + +%%--- Timeout ---%% +v_e_q_helper([#'CosNotification_Property'{name=?not_Timeout}|T], Curr, Unsupp) + when ?not_GetStopTimeSupported(Curr) =/= false, + ?not_GetEventReliability(Curr) =/= ?not_Persistent -> + v_e_q_helper(T, Curr, Unsupp); +v_e_q_helper([#'CosNotification_Property'{name=?not_Timeout}|T], Curr, Unsupp) -> + v_e_q_helper(T, Curr, [#'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', name = ?not_Timeout, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + }}|Unsupp]); + +%%--- Unknown Event QoS ---%% +v_e_q_helper([#'CosNotification_Property'{name=Name}|T], Curr, Unsupp) -> + %% Unsupported property. + v_e_q_helper(T, Curr, [#'CosNotification_PropertyError' + {code = 'BAD_PROPERTY', name = Name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + }}|Unsupp]); +v_e_q_helper(What, _, _) -> + %% Not a Property struct. + orber:dbg("[~p] CosNotification_Common:v_e_q_helper(~p);~n" + "Not a CosNotification_Property struct.", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%-------------- QOS HELP FUNCTIONS -------------------------- +%%------------------------------------------------------------ +%% function : set_properties/9 +%% Arguments: Wanted - requested QoS to be set. +%% Current - current QoS OMG style +%% Type - channel | admin | proxy +%% Supported - List of supported QoS +%% Unsupp - acc +%% NewQoS - acc +%% Parent - Factory if Channel, Channel if Admin etc +%% Childs - Admins if Channel etc +%% LQS - local representation of QoS. +%% Returns : {NewOMGStyleQoS, NewLocalQoS} | #'CosNotification_UnsupportedQoS'{} +%%------------------------------------------------------------ +set_properties([], Curr, channelAdm, _, [], NewQoS,_,_,LAS) -> + merge_properties(NewQoS, Curr, LAS); +set_properties([], Curr, _, _, [], NewQoS,_,_,LQS) -> + %% set_local_qos and merge_properties are help functions found at the end of QoS + %% functions. + NewLQS = set_local_qos(NewQoS, LQS), + merge_properties(NewQoS, Curr, NewLQS); +set_properties([], _, channelAdm, _, Unsupp, _,_,_,_) -> + corba:raise(#'CosNotification_UnsupportedAdmin'{admin_err = Unsupp}); +set_properties([], _, _, _, Unsupp, _,_,_,_) -> + corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Unsupp}); + +set_properties([Req|Tail], Curr, Type, Supported, Unsupp, NewQoS, Parent, Childs,LQS) -> + %% set_values and is_supported are help functions found at the end of QoS + %% functions. + case set_values(is_supported(Supported, Req), Req, Type, Curr, Parent, Childs,LQS) of + {unsupported, U} -> + set_properties(Tail, Curr, Type, Supported, [U|Unsupp], NewQoS, Parent, Childs,LQS); + {ok, S, NewLQS} -> + set_properties(Tail, Curr, Type, Supported, Unsupp, [S|NewQoS], Parent, Childs,NewLQS); + {ok, S} -> + set_properties(Tail, Curr, Type, Supported, Unsupp, [S|NewQoS], Parent, Childs,LQS); + ok -> + set_properties(Tail, Curr, Type, Supported, Unsupp, NewQoS, Parent, Childs,LQS) + end. + + +set_values(unsupported,Req,_,_,_,_,_) -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_PROPERTY', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + }; +set_values({ok, Func}, Req, Type, Curr, Parent, Childs, LQS) -> + ?MODULE:Func(Req, Type, Curr, Parent, Childs, LQS). + +%% Update OMG style QoS list with new values. +merge_properties([], NewCurrQoS, LQS) -> + {NewCurrQoS, LQS}; +merge_properties([H|T], Curr, LQS) -> + merge_properties(T, lists:keyreplace(H#'CosNotification_Property'.name, %% get key. + #'CosNotification_Property'.name, %% get index. + Curr, H), LQS). + +%% Is the Property S among our supported QoS? +is_supported([], _) -> + unsupported; +is_supported([{Name, Func}|_], #'CosNotification_Property'{name=Name}) -> + {ok, Func}; +is_supported([_|T], S) -> + is_supported(T, S). + +%% Find matching S-Property from a list of OMG style QoS +extract([], _) -> unsupported; +extract([H|_T], S) when H#'CosNotification_Property'.name== + S#'CosNotification_Property'.name -> + {ok, H}; +extract([_|T], S) -> extract(T,S). + +%% Find matching Property name from a list of OMG style QoS +extract_value([], _) -> unsupported; +extract_value([H|_T], Key) when H#'CosNotification_Property'.name== Key -> + {ok, any:get_value(H#'CosNotification_Property'.value)}; +extract_value([_|T], Key) -> extract(T,Key). + +%% Remove matching S-QoS from a list of OMG style QoS +remove(List, Key) -> + lists:keydelete(Key, + #'CosNotification_NamedPropertyRange'.name, %% get index. + List). + +change(List, Key, New) -> + lists:keyreplace(Key, + #'CosNotification_NamedPropertyRange'.name, %% get index. + List, New). +%% Get QoS from supplied objects and check if it's the same as S. +check_with_relatives([], S, LQS) -> + {ok, S, LQS}; +check_with_relatives([undefined|T], S, LQS) -> + check_with_relatives(T, S, LQS); +check_with_relatives([H|T], S, LQS) -> + case catch extract('CosNotification_QoSAdmin':get_qos(H), S) of + {ok, S} -> + check_with_relatives(T, S, LQS); + _-> + %% Varioues reasons for this case (Object not responding, not supported) + {unsupported, + #'CosNotification_PropertyError'{ + code = 'UNAVAILABLE_PROPERTY', + name = S#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end. + +%% Set new values to locally defined representation of QoS. Using this approach is +%% necessary since we must state the record-field at compile-time. +set_local_qos([], LQS) -> LQS; +set_local_qos([#'CosNotification_Property'{name=N,value=V}|T], LQS) -> + NewLQS = + case N of + "EventReliability" -> + ?not_SetEventReliability(LQS, any:get_value(V)); + "ConnectionReliability" -> + ?not_SetConnectionReliability(LQS, any:get_value(V)); + "Priority" -> + ?not_SetPriority(LQS, any:get_value(V)); + "Timeout" -> + ?not_SetTimeout(LQS, any:get_value(V)); + "OrderPolicy" -> + ?not_SetOrderPolicy(LQS, any:get_value(V)); + "DiscardPolicy" -> + ?not_SetDiscardPolicy(LQS, any:get_value(V)); + "MaximumBatchSize" -> + ?not_SetMaximumBatchSize(LQS, any:get_value(V)); + "PacingInterval" -> + ?not_SetPacingInterval(LQS, any:get_value(V)); + "StartTimeSupported" -> + ?not_SetStartTimeSupported(LQS, any:get_value(V)); + "StopTimeSupported" -> + ?not_SetStopTimeSupported(LQS, any:get_value(V)); + "MaxEventsPerConsumer" -> + ?not_SetMaxEventsPerConsumer(LQS, any:get_value(V)) + end, + set_local_qos(T, NewLQS). + +%%%%%%%%%%%%%%%%% END QOS FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%% + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/CosNotification_Definitions.hrl b/lib/cosNotification/src/CosNotification_Definitions.hrl new file mode 100644 index 0000000000..755b07cd5d --- /dev/null +++ b/lib/cosNotification/src/CosNotification_Definitions.hrl @@ -0,0 +1,340 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosNotification_Definitions.hrl +%% Purpose : +%%---------------------------------------------------------------------- + +-ifndef(COSNOTIFICATION_DEFINITIONS_HRL). +-define(COSNOTIFICATION_DEFINITIONS_HRL, true). + +%% ---------------- General comment ------------------------------------ +%% ******* README ******** +%% The prefix 'not' is short for notification, and is used to separate locally +%% defined macros from the global ones, i.e., do NOT confuse this with a negation!! +%% +%% In this file you find globally used data structures, constants etc. +%% + +%%--------------- INCLUDES --------------------------------------------- + +%%-------- Constants ------------------------------------------------- +-define(not_SupportedGrammars, ["EXTENDED_TCL"]). + +%% !!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +%% +%% If OMG redefines the values for the constants the definitions +%% below must be redefined!! +%% +%% !!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +-define(not_BestEffort, 0). +-define(not_Persistent, 1). +-define(not_EventReliability, "EventReliability"). +-define(not_ConnectionReliability, "ConnectionReliability"). +-define(not_Priority, "Priority"). +-define(not_LowestPriority, -32767). +-define(not_HighestPriority, 32767). +-define(not_DefaultPriority, 0). +-define(not_StartTime, "StartTime"). +-define(not_StopTime, "StopTime"). +-define(not_Timeout, "Timeout"). +-define(not_OrderPolicy, "OrderPolicy"). +-define(not_AnyOrder, 0). +-define(not_FifoOrder, 1). +-define(not_PriorityOrder, 2). +-define(not_DeadlineOrder, 3). +-define(not_DiscardPolicy, "DiscardPolicy"). +-define(not_LifoOrder, 4). +-define(not_RejectNewEvents, 5). +-define(not_MaximumBatchSize, "MaximumBatchSize"). +-define(not_PacingInterval, "PacingInterval"). +-define(not_StartTimeSupported, "StartTimeSupported"). +-define(not_StopTimeSupported, "StopTimeSupported"). +-define(not_MaxEventsPerConsumer, "MaxEventsPerConsumer"). +-define(not_MaxQueueLength, "MaxQueueLength"). +-define(not_MaxConsumers, "MaxConsumers"). +-define(not_MaxSuppliers, "MaxSuppliers"). + +%%--------------- QOS DEFINITIONS ---------------------------- +%% Limits for QoS. These are our own limits. +-define(not_MaxBatchSize, 10000). +-define(not_MinBatchSize, 1). +-define(not_MinTimeout, 0). +-define(not_MaxTimeout, 100000000000). +-define(not_MinPacing, 0). +-define(not_MaxPacing, 100000000000). +-define(not_MinConsumerEvents, 1). +-define(not_MaxConsumerEvents, 10000). + +-define(not_QOS_LIMITS, +[#'CosNotification_NamedPropertyRange' + {name=?not_EventReliability, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), ?not_BestEffort), + high_val=any:create(orber_tc:short(), ?not_Persistent) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_ConnectionReliability, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), ?not_BestEffort), + high_val=any:create(orber_tc:short(), ?not_Persistent) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_Priority, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), ?not_LowestPriority), + high_val=any:create(orber_tc:short(), ?not_HighestPriority) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_StartTimeSupported, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:boolean(), false), + high_val=any:create(orber_tc:boolean(), true) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_StopTimeSupported, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:boolean(), false), + high_val=any:create(orber_tc:boolean(), true) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_Timeout, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinTimeout), + high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxTimeout) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_OrderPolicy, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), ?not_AnyOrder), + high_val=any:create(orber_tc:short(), ?not_PriorityOrder) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_DiscardPolicy, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), ?not_AnyOrder), + high_val=any:create(orber_tc:short(), ?not_PriorityOrder) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_MaximumBatchSize, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:long(), ?not_MinBatchSize), + high_val=any:create(orber_tc:long(), ?not_MaxBatchSize) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_PacingInterval, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinPacing), + high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxPacing) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_MaxEventsPerConsumer, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:long(), ?not_MinConsumerEvents), + high_val=any:create(orber_tc:long(), ?not_MaxConsumerEvents) + }} +]. + + + +%% Local record used internally, and the reason for this is we get faster +%% access to QoS settings. +-record(qos, {'EventReliability', + 'ConnectionReliability', + 'Priority', + 'StartTimeSupported', + 'StopTimeSupported', + 'Timeout', + 'OrderPolicy', + 'DiscardPolicy', + 'MaximumBatchSize', + 'PacingInterval', + 'MaxEventsPerConsumer'}). + +%% Global (OMG) representation of QoS. +-define(not_DEFAULT_QOS, +[#'CosNotification_Property'{name=?not_MaximumBatchSize, + value=any:create(orber_tc:long(), 1)}, + #'CosNotification_Property'{name=?not_PacingInterval, + value=any:create(orber_tc:unsigned_long_long(), 0)}, + #'CosNotification_Property'{name=?not_Timeout, + value=any:create(orber_tc:unsigned_long_long(), 0)}, + #'CosNotification_Property'{name=?not_MaxEventsPerConsumer, + value=any:create(orber_tc:long(), 100)}, + #'CosNotification_Property'{name=?not_OrderPolicy, + value=any:create(orber_tc:short(), + ?not_PriorityOrder)}, + #'CosNotification_Property'{name=?not_EventReliability, + value=any:create(orber_tc:short(), + ?not_BestEffort)}, + #'CosNotification_Property'{name=?not_ConnectionReliability, + value=any:create(orber_tc:short(), + ?not_BestEffort)}, + #'CosNotification_Property'{name=?not_DiscardPolicy, + value=any:create(orber_tc:short(), + ?not_RejectNewEvents)}, + #'CosNotification_Property'{name=?not_StartTimeSupported, + value=any:create(orber_tc:boolean(), false)}, + #'CosNotification_Property'{name=?not_StopTimeSupported, + value=any:create(orber_tc:boolean(), false)}, + #'CosNotification_Property'{name=?not_Priority, + value=any:create(orber_tc:short(), ?not_DefaultPriority)}]). + +%%--------------- QOS CREATORS ------------------------------- +-define(not_CreateInitQoS(), #qos{}). + +%%--------------- QOS DESTRUCTORS ---------------------------- +-define(not_DestroyQoS(Q), ok). + +%%--------------- QOS SELECTORS ------------------------------ +-define(not_GetEventReliability(Q), Q#qos.'EventReliability'). +-define(not_GetConnectionReliability(Q), Q#qos.'ConnectionReliability'). +-define(not_GetPriority(Q), Q#qos.'Priority'). +-define(not_GetStartTimeSupported(Q), Q#qos.'StartTimeSupported'). +-define(not_GetStopTimeSupported(Q), Q#qos.'StopTimeSupported'). +-define(not_GetTimeout(Q), Q#qos.'Timeout'). +-define(not_GetOrderPolicy(Q), Q#qos.'OrderPolicy'). +-define(not_GetDiscardPolicy(Q), Q#qos.'DiscardPolicy'). +-define(not_GetMaximumBatchSize(Q), Q#qos.'MaximumBatchSize'). +-define(not_GetPacingInterval(Q), Q#qos.'PacingInterval'). +-define(not_GetMaxEventsPerConsumer(Q), Q#qos.'MaxEventsPerConsumer'). + +%%--------------- QOS MODIFIERS ------------------------------ +-define(not_SetEventReliability(Q,D), Q#qos{'EventReliability'=D}). +-define(not_SetConnectionReliability(Q,D), Q#qos{'ConnectionReliability'=D}). +-define(not_SetPriority(Q,D), Q#qos{'Priority'=D}). +-define(not_SetStartTimeSupported(Q,D), Q#qos{'StartTimeSupported'=D}). +-define(not_SetStopTimeSupported(Q,D), Q#qos{'StopTimeSupported'=D}). +-define(not_SetTimeout(Q,D), Q#qos{'Timeout'=D}). +-define(not_SetOrderPolicy(Q,D), Q#qos{'OrderPolicy'=D}). +-define(not_SetDiscardPolicy(Q,D), Q#qos{'DiscardPolicy'=D}). +-define(not_SetMaximumBatchSize(Q,D), Q#qos{'MaximumBatchSize'=D}). +-define(not_SetPacingInterval(Q,D), Q#qos{'PacingInterval'=D}). +-define(not_SetMaxEventsPerConsumer(Q,D), Q#qos{'MaxEventsPerConsumer'=D}). + +%%--------------- StructuredEvent CREATORS ------------------- +-define(not_CreateSE(StrD,StrT,StrE,PSeqV,PSeqF,AnyR), +#'CosNotification_StructuredEvent'{header = + #'CosNotification_EventHeader'{fixed_header = + #'CosNotification_FixedEventHeader'{event_type = + #'CosNotification_EventType'{domain_name=StrD, + type_name=StrT}, + event_name = StrE}, + variable_header = PSeqV}, + filterable_data = PSeqF, + remainder_of_body = AnyR}). +%% Can be used in guards. +-define(not_isConvertedAny(E), + (((E#'CosNotification_StructuredEvent'.header) + #'CosNotification_EventHeader'.fixed_header) + #'CosNotification_FixedEventHeader'.event_type) + #'CosNotification_EventType'.type_name == "%ANY"). +%% Can NOT be used in guards!!!!! +-define(not_isConvertedStructured(E), + any:get_typecode(E) == 'CosNotification_StructuredEvent':tc()). + +%%--------------- StructuredEvent DESTRUCTORS ---------------- +-define(not_DestroySE(E), ok). + +%%--------------- StructuredEvent SELECTORS ------------------ +-define(not_GetSEHeader(E), E#'StructuredEvent'.header). +-define(not_GetSEFixedHeader(E), E#'StructuredEvent'.header). + +%%--------------- StructuredEvent MODIFIERS ------------------ + +%%-------- QoS support ----------------------------------------------- +-define(not_SUPPORTED_QOS, +[{?not_EventReliability, 'EventReliability'}, + {?not_ConnectionReliability, 'ConnectionReliability'}, + {?not_Priority, 'Priority'}, + {?not_StartTimeSupported, 'StartTimeSupported'}, + {?not_StopTimeSupported, 'StopTimeSupported'}, + {?not_Timeout, 'Timeout'}, + {?not_OrderPolicy, 'OrderPolicy'}, + {?not_DiscardPolicy, 'DiscardPolicy'}, + {?not_MaximumBatchSize, 'MaximumBatchSize'}, + {?not_PacingInterval, 'PacingInterval'}, + {?not_MaxEventsPerConsumer, 'MaxEventsPerConsumer'}]). + +%%-------- ADMINPROPERTIESADMIN -------------------------------------- + +%% According to the OMG TC Document telecom/98-11-01, p 63 (section 2.5.7), the +%% default-value for these 3 admin properties is zero, which means that no limit +%% applies to that property. +-define(not_DEFAULT_ADMINPROPERTIES, +[#'CosNotification_Property'{name=?not_MaxQueueLength, + value=any:create(orber_tc:long(), 0)}, + #'CosNotification_Property'{name=?not_MaxConsumers, + value=any:create(orber_tc:long(), 0)}, + #'CosNotification_Property'{name=?not_MaxSuppliers, + value=any:create(orber_tc:long(), 0)}]). + +-define(not_SUPPORTED_ADMINPROPERTIES, +[{?not_MaxQueueLength, 'MaxQueueLength'}, + {?not_MaxConsumers, 'MaxConsumers'}, + {?not_MaxSuppliers, 'MaxSuppliers'}]). + + +%%-------- MISC -------------------------------------------------------- + +-define(not_DEFAULT_SETTINGS, [{pullInterval, 20}, + {filterOp, 'OR_OP'}, + {gcTime, 60}, + {gcLimit, 50}, + {timeService, undefined}, + {typecheck, true}, + {tty, false}, + {logfile, false}, + {server_options, []}]). +-define(not_CreateDBKey, term_to_binary({now(), node()})). + +-define(DEBUG_LEVEL, 3). + +-ifdef(debug). + +-define(debug_print(F,A), io:format("[~p(~p)] "++F,[?MODULE, ?LINE]++A)). +-define(DBG(F,A), io:format("[~p(~p)] "++F,[?MODULE, ?LINE]++A)). +-define(not_TypeCheck(O,I), ok). +%-define(not_TypeCheck(O,M), 'CosNotification_Common':type_check(O,M)). + +-else. + +-define(debug_print(F,A), ok). +-define(DBG(F,A), ok). +-define(not_TypeCheck(O,I), ok). + +-endif. + + + +-endif. +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin.cfg b/lib/cosNotification/src/CosNotifyChannelAdmin.cfg new file mode 100644 index 0000000000..8647b281a2 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyChannelAdmin.cfg @@ -0,0 +1,60 @@ +{this, "CosNotifyChannelAdmin::EventChannel"}. +{from, "CosNotifyChannelAdmin::EventChannel"}. +{{handle_info, "CosNotifyChannelAdmin::EventChannel"}, true}. +{this, "CosNotifyChannelAdmin::EventChannelFactory"}. +{from, "CosNotifyChannelAdmin::EventChannelFactory"}. +{{handle_info, "CosNotifyChannelAdmin::EventChannelFactory"}, true}. +{this, "CosNotifyChannelAdmin::SupplierAdmin"}. +{from, "CosNotifyChannelAdmin::SupplierAdmin"}. +{{handle_info, "CosNotifyChannelAdmin::SupplierAdmin"}, true}. +{this, "CosNotifyChannelAdmin::ConsumerAdmin"}. +{from, "CosNotifyChannelAdmin::ConsumerAdmin"}. +{{handle_info, "CosNotifyChannelAdmin::ConsumerAdmin"}, true}. +{this, "CosNotifyChannelAdmin::StructuredProxyPushSupplier"}. +{from, "CosNotifyChannelAdmin::StructuredProxyPushSupplier"}. +{{handle_info, "CosNotifyChannelAdmin::StructuredProxyPushSupplier"}, true}. +{{impl, "CosNotifyChannelAdmin::StructuredProxyPushSupplier"}, "PusherSupplier_impl"}. +{this, "CosNotifyChannelAdmin::StructuredProxyPullSupplier"}. +{from, "CosNotifyChannelAdmin::StructuredProxyPullSupplier"}. +{{handle_info, "CosNotifyChannelAdmin::StructuredProxyPullSupplier"}, true}. +{{impl, "CosNotifyChannelAdmin::StructuredProxyPullSupplier"}, "PullerSupplier_impl"}. +{this, "CosNotifyChannelAdmin::ProxyPushSupplier"}. +{from, "CosNotifyChannelAdmin::ProxyPushSupplier"}. +{{handle_info, "CosNotifyChannelAdmin::ProxyPushSupplier"}, true}. +{{impl, "CosNotifyChannelAdmin::ProxyPushSupplier"}, "PusherSupplier_impl"}. +{this, "CosNotifyChannelAdmin::ProxyPullSupplier"}. +{from, "CosNotifyChannelAdmin::ProxyPullSupplier"}. +{{handle_info, "CosNotifyChannelAdmin::ProxyPullSupplier"}, true}. +{{impl, "CosNotifyChannelAdmin::ProxyPullSupplier"}, "PullerSupplier_impl"}. +{this, "CosNotifyChannelAdmin::SequenceProxyPushSupplier"}. +{from, "CosNotifyChannelAdmin::SequenceProxyPushSupplier"}. +{{handle_info, "CosNotifyChannelAdmin::SequenceProxyPushSupplier"}, true}. +{{impl, "CosNotifyChannelAdmin::SequenceProxyPushSupplier"}, "PusherSupplier_impl"}. +{this, "CosNotifyChannelAdmin::SequenceProxyPullSupplier"}. +{from, "CosNotifyChannelAdmin::SequenceProxyPullSupplier"}. +{{handle_info, "CosNotifyChannelAdmin::SequenceProxyPullSupplier"}, true}. +{{impl, "CosNotifyChannelAdmin::SequenceProxyPullSupplier"}, "PullerSupplier_impl"}. +{this, "CosNotifyChannelAdmin::StructuredProxyPushConsumer"}. +{from, "CosNotifyChannelAdmin::StructuredProxyPushConsumer"}. +{{handle_info, "CosNotifyChannelAdmin::StructuredProxyPushConsumer"}, true}. +{{impl, "CosNotifyChannelAdmin::StructuredProxyPushConsumer"}, "PusherConsumer_impl"}. +{this, "CosNotifyChannelAdmin::StructuredProxyPullConsumer"}. +{from, "CosNotifyChannelAdmin::StructuredProxyPullConsumer"}. +{{handle_info, "CosNotifyChannelAdmin::StructuredProxyPullConsumer"}, true}. +{{impl, "CosNotifyChannelAdmin::StructuredProxyPullConsumer"}, "PullerConsumer_impl"}. +{this, "CosNotifyChannelAdmin::ProxyPushConsumer"}. +{from, "CosNotifyChannelAdmin::ProxyPushConsumer"}. +{{handle_info, "CosNotifyChannelAdmin::ProxyPushConsumer"}, true}. +{{impl, "CosNotifyChannelAdmin::ProxyPushConsumer"}, "PusherConsumer_impl"}. +{this, "CosNotifyChannelAdmin::ProxyPullConsumer"}. +{from, "CosNotifyChannelAdmin::ProxyPullConsumer"}. +{{handle_info, "CosNotifyChannelAdmin::ProxyPullConsumer"}, true}. +{{impl, "CosNotifyChannelAdmin::ProxyPullConsumer"}, "PullerConsumer_impl"}. +{this, "CosNotifyChannelAdmin::SequenceProxyPushConsumer"}. +{from, "CosNotifyChannelAdmin::SequenceProxyPushConsumer"}. +{{handle_info, "CosNotifyChannelAdmin::SequenceProxyPushConsumer"}, true}. +{{impl, "CosNotifyChannelAdmin::SequenceProxyPushConsumer"}, "PusherConsumer_impl"}. +{this, "CosNotifyChannelAdmin::SequenceProxyPullConsumer"}. +{from, "CosNotifyChannelAdmin::SequenceProxyPullConsumer"}. +{{handle_info, "CosNotifyChannelAdmin::SequenceProxyPullConsumer"}, true}. +{{impl, "CosNotifyChannelAdmin::SequenceProxyPullConsumer"}, "PullerConsumer_impl"}. diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin.idl b/lib/cosNotification/src/CosNotifyChannelAdmin.idl new file mode 100644 index 0000000000..b345ff5423 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyChannelAdmin.idl @@ -0,0 +1,275 @@ +#ifndef _COS_NOTIFYCHANNELADMIN_IDL_ +#define _COS_NOTIFYCHANNELADMIN_IDL_ + +#pragma prefix "omg.org" + +#include<cosNotificationAppComm.idl> +#include<CosNotifyFilter.idl> +#include<CosNotifyComm.idl> +#include<CosNotification.idl> + +module CosNotifyChannelAdmin { + exception ConnectionAlreadyActive {}; + exception ConnectionAlreadyInactive {}; + exception NotConnected {}; + // Forward declarations + interface ConsumerAdmin; + interface SupplierAdmin; + interface EventChannel; + interface EventChannelFactory; + + enum ProxyType { + PUSH_ANY, + PULL_ANY, + PUSH_STRUCTURED, + PULL_STRUCTURED, + PUSH_SEQUENCE, + PULL_SEQUENCE}; + + enum ObtainInfoMode { + ALL_NOW_UPDATES_OFF, + ALL_NOW_UPDATES_ON, + NONE_NOW_UPDATES_OFF, + NONE_NOW_UPDATES_ON}; + + interface ProxyConsumer : CosNotification::QoSAdmin, CosNotifyFilter::FilterAdmin { + readonly attribute ProxyType MyType; + readonly attribute SupplierAdmin MyAdmin; + + CosNotification::EventTypeSeq obtain_subscription_types(in ObtainInfoMode mode); + + void validate_event_qos (in CosNotification::QoSProperties required_qos, + out CosNotification::NamedPropertyRangeSeq available_qos) + raises (CosNotification::UnsupportedQoS); + }; // ProxyConsumer + + interface ProxySupplier : CosNotification::QoSAdmin, CosNotifyFilter::FilterAdmin { + readonly attribute ProxyType MyType; + readonly attribute ConsumerAdmin MyAdmin; + attribute CosNotifyFilter::MappingFilter priority_filter; + attribute CosNotifyFilter::MappingFilter lifetime_filter; + + CosNotification::EventTypeSeq obtain_offered_types(in ObtainInfoMode mode); + + void validate_event_qos (in CosNotification::QoSProperties required_qos, + out CosNotification::NamedPropertyRangeSeq available_qos) + raises (CosNotification::UnsupportedQoS); + }; // ProxySupplier + + interface ProxyPushConsumer : ProxyConsumer, CosNotifyComm::PushConsumer, + CosEventChannelAdmin::ProxyPushConsumer { + void connect_any_push_supplier (in CosEventComm::PushSupplier push_supplier) + raises(CosEventChannelAdmin::AlreadyConnected); + }; // ProxyPushConsumer + + interface StructuredProxyPushConsumer : ProxyConsumer, CosNotifyComm::StructuredPushConsumer { + void connect_structured_push_supplier (in CosNotifyComm::StructuredPushSupplier push_supplier) + raises(CosEventChannelAdmin::AlreadyConnected); + }; // StructuredProxyPushConsumer + + interface SequenceProxyPushConsumer : ProxyConsumer, CosNotifyComm::SequencePushConsumer { + void connect_sequence_push_supplier (in CosNotifyComm::SequencePushSupplier push_supplier) + raises(CosEventChannelAdmin::AlreadyConnected); + }; // SequenceProxyPushConsumer + + interface ProxyPullSupplier : ProxySupplier, CosNotifyComm::PullSupplier, + CosEventChannelAdmin::ProxyPullSupplier, oe_CosNotificationComm::Event { + void connect_any_pull_consumer (in CosEventComm::PullConsumer pull_consumer) + raises(CosEventChannelAdmin::AlreadyConnected); + }; // ProxyPullSupplier + + interface StructuredProxyPullSupplier : ProxySupplier, CosNotifyComm::StructuredPullSupplier, + oe_CosNotificationComm::Event { + void connect_structured_pull_consumer (in CosNotifyComm::StructuredPullConsumer pull_consumer) + raises(CosEventChannelAdmin::AlreadyConnected); + }; // StructuredProxyPullSupplier + + interface SequenceProxyPullSupplier : ProxySupplier, CosNotifyComm::SequencePullSupplier, + oe_CosNotificationComm::Event { + void connect_sequence_pull_consumer (in CosNotifyComm::SequencePullConsumer pull_consumer) + raises(CosEventChannelAdmin::AlreadyConnected); + }; // SequenceProxyPullSupplier + + interface ProxyPullConsumer : ProxyConsumer, CosNotifyComm::PullConsumer, + CosEventChannelAdmin::ProxyPullConsumer { + void connect_any_pull_supplier (in CosEventComm::PullSupplier pull_supplier) + raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises(ConnectionAlreadyInactive, NotConnected); + + void resume_connection() + raises(ConnectionAlreadyActive, NotConnected); + }; // ProxyPullConsumer + + interface StructuredProxyPullConsumer : ProxyConsumer, CosNotifyComm::StructuredPullConsumer { + void connect_structured_pull_supplier (in CosNotifyComm::StructuredPullSupplier pull_supplier) + raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises(ConnectionAlreadyInactive, NotConnected); + + void resume_connection() + raises(ConnectionAlreadyActive, NotConnected); + }; // StructuredProxyPullConsumer + + interface SequenceProxyPullConsumer : ProxyConsumer, CosNotifyComm::SequencePullConsumer { + void connect_sequence_pull_supplier (in CosNotifyComm::SequencePullSupplier pull_supplier) + raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises(ConnectionAlreadyInactive, NotConnected); + + void resume_connection() + raises(ConnectionAlreadyActive, NotConnected); + }; // SequenceProxyPullConsumer + + interface ProxyPushSupplier : ProxySupplier, CosNotifyComm::PushSupplier, + CosEventChannelAdmin::ProxyPushSupplier, oe_CosNotificationComm::Event { + void connect_any_push_consumer (in CosEventComm::PushConsumer push_consumer) + raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises(ConnectionAlreadyInactive, NotConnected); + + void resume_connection() + raises(ConnectionAlreadyActive, NotConnected); + }; // ProxyPushSupplier + + interface StructuredProxyPushSupplier : ProxySupplier, CosNotifyComm::StructuredPushSupplier, + oe_CosNotificationComm::Event { + void connect_structured_push_consumer (in CosNotifyComm::StructuredPushConsumer push_consumer) + raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises(ConnectionAlreadyInactive, NotConnected); + + void resume_connection() + raises(ConnectionAlreadyActive, NotConnected); + }; // StructuredProxyPushSupplier + + interface SequenceProxyPushSupplier : ProxySupplier, CosNotifyComm::SequencePushSupplier, + oe_CosNotificationComm::Event { + void connect_sequence_push_consumer (in CosNotifyComm::SequencePushConsumer push_consumer) + raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises(ConnectionAlreadyInactive, NotConnected); + + void resume_connection() + raises(ConnectionAlreadyActive, NotConnected); + }; // SequenceProxyPushSupplier + + + typedef long ProxyID; + typedef sequence <ProxyID> ProxyIDSeq; + + enum ClientType { + ANY_EVENT, + STRUCTURED_EVENT, + SEQUENCE_EVENT}; + + enum InterFilterGroupOperator { + AND_OP, + OR_OP }; + + typedef long AdminID; + typedef sequence<AdminID> AdminIDSeq; + + exception AdminNotFound {}; + exception ProxyNotFound {}; + + struct AdminLimit { + CosNotification::PropertyName name; + CosNotification::PropertyValue value; + }; + + exception AdminLimitExceeded { AdminLimit admin_property_err; }; + + interface ConsumerAdmin : CosNotification::QoSAdmin, CosNotifyComm::NotifySubscribe, + CosNotifyFilter::FilterAdmin, CosEventChannelAdmin::ConsumerAdmin, + oe_CosNotificationComm::Event { + readonly attribute AdminID MyID; + readonly attribute EventChannel MyChannel; + readonly attribute InterFilterGroupOperator MyOperator; + attribute CosNotifyFilter::MappingFilter priority_filter; + attribute CosNotifyFilter::MappingFilter lifetime_filter; + readonly attribute ProxyIDSeq pull_suppliers; + readonly attribute ProxyIDSeq push_suppliers; + + ProxySupplier get_proxy_supplier (in ProxyID proxy_id) + raises (ProxyNotFound); + + ProxySupplier obtain_notification_pull_supplier (in ClientType ctype, out ProxyID proxy_id) + raises (AdminLimitExceeded); + + ProxySupplier obtain_notification_push_supplier (in ClientType ctype, out ProxyID proxy_id) + raises (AdminLimitExceeded); + + void destroy(); + }; // ConsumerAdmin + + interface SupplierAdmin : CosNotification::QoSAdmin, CosNotifyComm::NotifyPublish, + CosNotifyFilter::FilterAdmin, CosEventChannelAdmin::SupplierAdmin , + oe_CosNotificationComm::Event { + readonly attribute AdminID MyID; + readonly attribute EventChannel MyChannel; + readonly attribute InterFilterGroupOperator MyOperator; + readonly attribute ProxyIDSeq pull_consumers; + readonly attribute ProxyIDSeq push_consumers; + + ProxyConsumer get_proxy_consumer (in ProxyID proxy_id) + raises (ProxyNotFound); + + ProxyConsumer obtain_notification_pull_consumer (in ClientType ctype, out ProxyID proxy_id) + raises (AdminLimitExceeded); + + ProxyConsumer obtain_notification_push_consumer (in ClientType ctype, out ProxyID proxy_id) + raises (AdminLimitExceeded); + + void destroy(); + }; // SupplierAdmin + + interface EventChannel : CosNotification::QoSAdmin, CosNotification::AdminPropertiesAdmin, + CosEventChannelAdmin::EventChannel, + oe_CosNotificationComm::Event { + readonly attribute EventChannelFactory MyFactory; + readonly attribute ConsumerAdmin default_consumer_admin; + readonly attribute SupplierAdmin default_supplier_admin; + readonly attribute CosNotifyFilter::FilterFactory default_filter_factory; + + ConsumerAdmin new_for_consumers(in InterFilterGroupOperator op, out AdminID id); + + SupplierAdmin new_for_suppliers(in InterFilterGroupOperator op, out AdminID id); + + ConsumerAdmin get_consumeradmin (in AdminID id) + raises (AdminNotFound); + + SupplierAdmin get_supplieradmin (in AdminID id) + raises (AdminNotFound); + + AdminIDSeq get_all_consumeradmins(); + + AdminIDSeq get_all_supplieradmins(); + }; // EventChannel + + typedef long ChannelID; + typedef sequence<ChannelID> ChannelIDSeq; + exception ChannelNotFound {}; + + interface EventChannelFactory { + EventChannel create_channel (in CosNotification::QoSProperties initial_qos, + in CosNotification::AdminProperties initial_admin, + out ChannelID id) + raises(CosNotification::UnsupportedQoS, CosNotification::UnsupportedAdmin); + + ChannelIDSeq get_all_channels(); + + EventChannel get_event_channel (in ChannelID id) + raises (ChannelNotFound); + }; // EventChannelFactory +}; // CosNotifyChannelAdmin + + +#endif /* ifndef _COS_NOTIFYCHANNELADMIN_IDL_ */ + diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin_ConsumerAdmin_impl.erl b/lib/cosNotification/src/CosNotifyChannelAdmin_ConsumerAdmin_impl.erl new file mode 100644 index 0000000000..5ac8c810ea --- /dev/null +++ b/lib/cosNotification/src/CosNotifyChannelAdmin_ConsumerAdmin_impl.erl @@ -0,0 +1,670 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%------------------------------------------------------------------- +%% File : CosNotifyChannelAdmin_ConsumerAdmin_impl.erl +%% Purpose : +%%------------------------------------------------------------------- + +-module('CosNotifyChannelAdmin_ConsumerAdmin_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%%----- CosNotifyChannelAdmin::ConsumerAdmin ----------------- +-export([get_proxy_supplier/4, + obtain_notification_pull_supplier/4, + obtain_notification_push_supplier/4, + destroy/3]). + +%%----- Inherit from CosNotification::QoSAdmin --------------- +-export([get_qos/3, + set_qos/4, + validate_qos/4]). + +%%----- Inherit from CosNotifyComm::NotifySubscribe ---------- +-export([subscription_change/5]). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ------------ +-export([add_filter/4, + remove_filter/4, + get_filter/4, + get_all_filters/3, + remove_all_filters/3]). + +%%----- Inherit from CosEventChannelAdmin::ConsumerAdmin ----- +-export([obtain_push_supplier/3, + obtain_pull_supplier/3]). + +%% Attributes (external) +-export(['_get_MyID'/3, + '_get_MyChannel'/3, + '_get_MyOperator'/3, + '_get_priority_filter'/3, + '_set_priority_filter'/4, + '_get_lifetime_filter'/3, + '_set_lifetime_filter'/4, + '_get_pull_suppliers'/3, + '_get_push_suppliers'/3]). + +%%--------------- Internal ----------------------------------- +%%----- Inherit from cosNotificationComm --------------------- +-export([callAny/5, + callSeq/5]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {myId, + myChannel, + myChannelPid, + myOperator, + myFilters = [], + mySuppliers = [], + idCounter = 0, + priorityFilter, + lifetimeFilter, + etsR, + qosGlobal, + qosLocal, + options}). + +%% Data structures constructors +-define(get_InitState(_MyID, _MyCh, _MyChP, _MyOp, _PFil, _LFil, _QoS, _LQS, _O), + #state{myId = _MyID, + myChannel = _MyCh, + myChannelPid = _MyChP, + myOperator = _MyOp, + priorityFilter = _PFil, + lifetimeFilter = _LFil, + qosGlobal = _QoS, + qosLocal = _LQS, + options = _O, + etsR = ets:new(oe_ets, [set, protected])}). + +%% Data structures selectors +-define(get_PushSupplierIDs(S), find_ids(S#state.mySuppliers, pusher)). +-define(get_PullSupplierIDs(S), find_ids(S#state.mySuppliers, puller)). +-define(get_AllSuppliers(S), S#state.mySuppliers). +-define(get_AllSupplierRefs(S), find_refs(S#state.mySuppliers)). +-define(get_Supplier(S, I), find_obj(lists:keysearch(I,1,S#state.mySuppliers), + supplier)). + +-define(get_MyID(S), S#state.myId). +-define(get_MyChannel(S), S#state.myChannel). +-define(get_MyChannelPid(S), S#state.myChannelPid). +-define(get_MyOperator(S), S#state.myOperator). +-define(get_PrioFilter(S), S#state.priorityFilter). +-define(get_LifeFilter(S), S#state.lifetimeFilter). +-define(get_GlobalQoS(S), S#state.qosGlobal). +-define(get_LocalQoS(S), S#state.qosLocal). +-define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}). +-define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters), + filter)). +-define(get_AllFilter(S), S#state.myFilters). +-define(get_AllFilterID(S), find_ids(S#state.myFilters)). +-define(get_Options(S), S#state.options). +-define(get_IdCounter(S), S#state.idCounter). + +%% Data structures modifiers +-define(set_PrioFilter(S,D), S#state{priorityFilter=D}). +-define(set_LifeFilter(S,D), S#state{lifetimeFilter=D}). +-define(set_LocalQoS(S,D), S#state{qosLocal=D}). +-define(set_GlobalQoS(S,D), S#state{qosGlobal=D}). +-define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}). +-define(add_PushSupplier(S,I,R,P),S#state{mySuppliers=[{I,R,P,pusher}|S#state.mySuppliers]}). +-define(add_PullSupplier(S,I,R,P),S#state{mySuppliers=[{I,R,P,puller}|S#state.mySuppliers]}). +-define(del_Supplier(S,I), S#state{mySuppliers= + lists:keydelete(I, 1, + S#state.mySuppliers)}). +-define(del_SupplierRef(S,O), S#state{mySuppliers= + lists:keydelete(O, 2, + S#state.mySuppliers)}). +-define(del_SupplierPid(S,P), S#state{mySuppliers= + lists:keydelete(P, 3, + S#state.mySuppliers)}). +-define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}). +-define(del_Filter(S,I), S#state{myFilters= + delete_filter(lists:keydelete(I, 1, + S#state.myFilters), + S#state.myFilters)}). +-define(del_AllFilter(S), S#state{myFilters=[]}). +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id( + S#state.idCounter)). + +%% MISC +-define(is_PersistentConnection(S), + ?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent). +-define(is_PersistentEvent(S), + ?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent). +-define(is_ANDOP(S), S#state.myOperator == 'AND_OP'). + +%%----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%----------------------------------------------------------- + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + case Info of + {'EXIT', Pid, Reason} when ?get_MyChannelPid(State) == Pid -> + ?DBG("PARENT CHANNEL: ~p TERMINATED.~n",[Reason]), + {stop, Reason, State}; + {'EXIT', Pid, normal} -> + {noreply, ?del_SupplierPid(State, Pid)}; + _Other -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([MyId, MyChannel, MyChannelPid, MyOperator, InitQoS, LQS, Options]) -> + process_flag(trap_exit, true), + PriorityFilter = corba:create_nil_objref(), + LifeTimeFilter = corba:create_nil_objref(), + {ok, ?get_InitState(MyId, MyChannel, MyChannelPid, MyOperator, + PriorityFilter, LifeTimeFilter, InitQoS, LQS, Options)}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%----- CosNotifyChannelAdmin_ConsumerAdmin attributes ------ +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_MyID' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyID'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyID(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyChannel' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyChannel'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyChannel(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyOperator' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyOperator'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyOperator(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_priority_filter' +%% Type : read and write +%% Returns : +%%----------------------------------------------------------- +'_get_priority_filter'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_PrioFilter(State), State}. + +'_set_priority_filter'(_OE_THIS, _OE_FROM, State, PrioFilter) -> + {reply, ok, ?set_PrioFilter(State, PrioFilter)}. + +%%----------------------------------------------------------% +%% Attribute: '_get_lifetime_filter' +%% Type : read and write +%% Returns : +%%----------------------------------------------------------- +'_get_lifetime_filter'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_LifeFilter(State), State}. +'_set_lifetime_filter'(_OE_THIS, _OE_FROM, State, LifeFilter) -> + {reply, ok, ?set_LifeFilter(State, LifeFilter)}. + +%%----------------------------------------------------------% +%% Attribute: '_get_pull_suppliers' +%% Type : readonly +%% Returns : ProxyIDSeq +%%----------------------------------------------------------- +'_get_pull_suppliers'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_PullSupplierIDs(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_push_suppliers' +%% Type : readonly +%% Returns : ProxyIDSeq +%%----------------------------------------------------------- +'_get_push_suppliers'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_PushSupplierIDs(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% function : get_proxy_supplier +%% Arguments: ProxyID - unique identifier (long) +%% Returns : ObjRef | {'EXCEPTION', #'ProxyNotFound'{}} +%%----------------------------------------------------------- +get_proxy_supplier(_OE_THIS, _OE_FROM, State, Proxy_id) -> + {reply, ?get_Supplier(State, Proxy_id), State}. + +%%----------------------------------------------------------% +%% function : obtain_notification_pull_supplier +%% Arguments: Ctype - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' +%% Returns : A Proxy of the requested type. +%%----------------------------------------------------------- +obtain_notification_pull_supplier(OE_THIS, _OE_FROM, State, Ctype) -> + %% Choose which module to use. + {Mod, Type} = + case Ctype of + 'ANY_EVENT' -> + {'CosNotifyChannelAdmin_ProxyPullSupplier', 'PULL_ANY'}; + 'STRUCTURED_EVENT' -> + {'CosNotifyChannelAdmin_StructuredProxyPullSupplier', 'PULL_STRUCTURED'}; + 'SEQUENCE_EVENT' -> + {'CosNotifyChannelAdmin_SequenceProxyPullSupplier', 'PULL_SEQUENCE'}; + _ -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:" + "obtain_notification_pull_supplier(~p);~n" + "Incorrect enumerant", + [?LINE, Ctype], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end, + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case Mod:oe_create_link([Type, OE_THIS, self(), ?get_GlobalQoS(State), + ?get_LocalQoS(State), ?get_MyChannel(State), + ?get_Options(State), ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, PrRef} -> + ProxyID = ?new_Id(State), + NewState = ?add_PullSupplier(State, ProxyID, PrRef, Pid), + {reply, {PrRef, ProxyID}, ?set_IdCounter(NewState, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:" + "obtain_notification_pull_supplier();~n" + "Unable to create: ~p/~p~n" + "Reason: ~p", [?LINE, Mod, Type, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : obtain_notification_push_supplier +%% Arguments: Ctype - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' +%% Returns : A Proxy of the requested type. +%%----------------------------------------------------------- +obtain_notification_push_supplier(OE_THIS, _OE_FROM, State, Ctype) -> + %% Choose which module to use. + {Mod, Type} = + case Ctype of + 'ANY_EVENT' -> + {'CosNotifyChannelAdmin_ProxyPushSupplier', 'PUSH_ANY'}; + 'STRUCTURED_EVENT' -> + {'CosNotifyChannelAdmin_StructuredProxyPushSupplier', 'PUSH_STRUCTURED'}; + 'SEQUENCE_EVENT' -> + {'CosNotifyChannelAdmin_SequenceProxyPushSupplier', 'PUSH_SEQUENCE'}; + _ -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:" + "obtain_notification_push_supplier(~p);~n" + "Incorrect enumerant", [?LINE, Ctype], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end, + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case Mod:oe_create_link([Type, OE_THIS, self(), ?get_GlobalQoS(State), + ?get_LocalQoS(State), ?get_MyChannel(State), + ?get_Options(State), ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, PrRef} -> + ProxyID = ?new_Id(State), + NewState = ?add_PushSupplier(State, ProxyID, PrRef, Pid), + {reply, {PrRef, ProxyID}, ?set_IdCounter(NewState, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:obtain_notification_push_supplier();~n" + "Unable to create: ~p/~p~n" + "Reason: ~p", + [?LINE, Mod, Type, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + + +%%----------------------------------------------------------% +%% function : destroy +%% Arguments: - +%% Returns : ok +%%------------------------------------------------------------ +destroy(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, State}. + +%%----- Inherit from CosNotification::QoSAdmin -------------- +%%----------------------------------------------------------% +%% function : get_qos +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +get_qos(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalQoS(State), State}. + +%%----------------------------------------------------------% +%% function : set_qos +%% Arguments: QoS - CosNotification::QoSProperties, i.e., +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +set_qos(_OE_THIS, _OE_FROM, State, QoS) -> + {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State), + admin, ?get_MyChannel(State), + ?get_AllSupplierRefs(State)), + {reply, ok, ?set_BothQoS(State, NewQoS, LQS)}. + +%%----------------------------------------------------------% +%% function : validate_qos +%% Arguments: Required_qos - CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) -> + QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State), + admin, ?get_MyChannel(State), + ?get_AllSupplierRefs(State)), + {reply, {ok, QoS}, State}. + +%%----- Inherit from CosNotifyComm::NotifySubscribe --------- +%%----------------------------------------------------------* +%% function : subscription_change +%% Arguments: +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyComm_InvalidEventType'{type}} +%%----------------------------------------------------------- +subscription_change(_OE_THIS, _OE_FROM, State, _Added, _Removed) -> + ?DBG("CALLBACK INFORMED: ~p ~p~n",[_Added, _Removed]), + {reply, ok, State}. + +%%----- Inherit from CosNotifyFilter::FilterAdmin ----------- +%%----------------------------------------------------------% +%% function : add_filter +%% Arguments: Filter - CosNotifyFilter::Filter +%% Returns : FilterID - long +%%----------------------------------------------------------- +add_filter(_OE_THIS, _OE_FROM, State, Filter) -> + 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'), + FilterID = ?new_Id(State), + NewState = ?set_IdCounter(State, FilterID), + {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}. + +%%----------------------------------------------------------% +%% function : remove_filter +%% Arguments: FilterID - long +%% Returns : ok +%%----------------------------------------------------------- +remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ok, ?del_Filter(State, FilterID)}; +remove_filter(_,_,_,_) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_filter +%% Arguments: FilterID - long +%% Returns : Filter - CosNotifyFilter::Filter | +%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}} +%%----------------------------------------------------------- +get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ?get_Filter(State, FilterID), State}; +get_filter(_,_,_,_) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_all_filters +%% Arguments: - +%% Returns : Filter - CosNotifyFilter::FilterIDSeq +%%----------------------------------------------------------- +get_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_AllFilterID(State), State}. + +%%----------------------------------------------------------% +%% function : remove_all_filters +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ok, ?del_AllFilter(State)}. + +%%----- Inherit from CosEventChannelAdmin::ConsumerAdmin ---- +%%----------------------------------------------------------% +%% function : obtain_push_supplier +%% Arguments: - +%% Returns : ProxyPushSupplier +%%----------------------------------------------------------- +obtain_push_supplier(OE_THIS, _OE_FROM, State) -> + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_create_link(['PUSH_ANY', OE_THIS, + self(), + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_MyChannel(State), + ?get_Options(State), + ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, PrRef} -> + ProxyID = ?new_Id(State), + NewState = ?add_PushSupplier(State, ProxyID, PrRef, Pid), + {reply, PrRef, ?set_IdCounter(NewState, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:obtain_push_supplier();~n" + "Unable to create: CosNotifyChannelAdmin_ProxyPushSupplier~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : obtain_pull_supplier +%% Arguments: - +%% Returns : ProxyPullSupplier +%%----------------------------------------------------------- +obtain_pull_supplier(OE_THIS, _OE_FROM, State) -> + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_create_link(['PULL_ANY', OE_THIS, + self(), + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_MyChannel(State), + ?get_Options(State), + ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, PrRef} -> + ProxyID = ?new_Id(State), + NewState = ?add_PullSupplier(State, ProxyID, PrRef, Pid), + {reply, PrRef, ?set_IdCounter(NewState, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:obtain_pull_supplier();~n" + "Unable to create: CosNotifyChannelAdmin_ProxyPullSupplier~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +%% To match suppliers +find_obj({value, {_,Obj,_,_}},_) -> Obj; +%% To match filters +find_obj({value, {_,Obj}},_) -> Obj; +find_obj(_, supplier) -> {'EXCEPTION', #'CosNotifyChannelAdmin_ProxyNotFound'{}}; +find_obj(_, filter) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}. + +find_ids(List) -> + find_ids(List, [], false). +find_ids(List, Type) -> + find_ids(List, [], Type). + +find_ids([], Acc, _) -> + Acc; +find_ids([{I,_}|T], Acc, Type) -> + find_ids(T, [I|Acc], Type); +find_ids([{I,_,_,Type}|T], Acc, Type) -> + find_ids(T, [I|Acc], Type); +find_ids([{_I,_,_,_}|T], Acc, Type) -> + find_ids(T, Acc, Type); +find_ids(What, _, _) -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:find_ids();~n" + "Id corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +find_refs(List) -> + find_refs(List, []). + +find_refs([], Acc) -> + Acc; +find_refs([{_,R,_,_}|T], Acc) -> + find_refs(T, [R|Acc]); +find_refs(What, _) -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:find_refs();~n" + "Reference corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +%% Delete a single filter. +%% The list do not differ, i.e., no filter removed, raise exception. +delete_filter(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{}); +delete_filter(List, _) -> List. + + +%%----------------------------------------------------------- +%% function : callSeq +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callSeq(_OE_THIS, OE_FROM, State, Events, _Status) -> + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:filter_events(Events, ?get_AllFilter(State)) of + {[], _} when ?is_ANDOP(State) -> + %% Since AND it doesn't matter what the proxies 'think'. Done. + {noreply, State}; + {[], Failed} -> + %% Is OR but the Proxy may allow the events; pass on. + forward(seq, State, Failed, 'MATCH'); + {Passed, _} when ?is_ANDOP(State) -> + %% Since AND we only forward those who passed this objects filters. + forward(seq, State, Passed, 'MATCH'); + {Passed, []} -> + %% Since OR we forward and tell the proxy to do no filtering. + forward(seq, State, Passed, 'MATCHED'); + {Passed, Failed} -> + %% Since OR we forward both and instruct the proxy to check only + %% the ones that failed. + forward(seq, State, Passed, 'MATCHED'), + forward(seq, State, Failed, 'MATCH') + end. + + +%%----------------------------------------------------------- +%% function : callAny +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callAny(_OE_THIS, OE_FROM, State, Event, _Status) -> + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:filter_events([Event], ?get_AllFilter(State)) of + {[], _} when ?is_ANDOP(State) -> + %% Since AND it doesn't matter what the proxies 'think'. Done. + {noreply, State}; + {[], [Failed]} -> + %% Is OR but the Proxy may allow the event; pass on. + forward(any, State, Failed, 'MATCH'); + {[Passed], _} when ?is_ANDOP(State) -> + %% Since AND we only forward those who passed this objects filters. + forward(any, State, Passed, 'MATCH'); + {[Passed], _} -> + %% Since OR we forward and instruct the proxy to do no checks. + forward(any, State, Passed, 'MATCHED') + end. + + + +%% Forward events +forward(Type, State, Event, Status) -> + forward(Type, ?get_AllSuppliers(State), State, Event, Status). +forward(_, [], State, _, _) -> + {noreply, State}; +forward(any, [{_,H,_,_}|T], State, Event, Status) -> + case catch oe_CosNotificationComm_Event:callAny(H, Event, Status) of + ok -> + ?DBG("CONSUMERADM FORWARD ANY: ~p~n",[Event]), + forward(any, T, State, Event, Status); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n" + "Proxy no longer exists; dropping it: ~p", + [?LINE, H], ?DEBUG_LEVEL), + NewState = ?del_SupplierRef(State,H), + forward(any, T, NewState, Event, Status); + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n" + "Proxy behaves badly: ~p/~p", + [?LINE, R, H], ?DEBUG_LEVEL), + forward(any, T, State, Event, Status); + R -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n" + "Proxy behaves badly: ~p~n" + "Dropping it: ~p", [?LINE, R, H], ?DEBUG_LEVEL), + NewState = ?del_SupplierRef(State, H), + forward(any, T, NewState, Event, Status) + end; +forward(seq, [{_,H,_,_}|T], State, Event, Status) -> + case catch oe_CosNotificationComm_Event:callSeq(H, Event, Status) of + ok -> + ?DBG("CONSUMERADM FORWARD SEQUENCE: ~p~n",[Event]), + forward(seq, T, State, Event, Status); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n" + "Proxy no longer exists; dropping it: ~p", + [?LINE, H], ?DEBUG_LEVEL), + NewState = ?del_SupplierRef(State,H), + forward(seq, T, NewState, Event, Status); + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n" + "Proxy behaves badly: ~p/~p", [?LINE, R, H], ?DEBUG_LEVEL), + forward(seq, T, State, Event, Status); + R -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n" + "Proxy behaves badly: ~p~n" + "Dropping it: ~p", [?LINE, R, H], ?DEBUG_LEVEL), + NewState = ?del_SupplierRef(State, H), + forward(seq, T, NewState, Event, Status) + end. + + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannelFactory_impl.erl b/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannelFactory_impl.erl new file mode 100644 index 0000000000..872a786f92 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannelFactory_impl.erl @@ -0,0 +1,142 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%------------------------------------------------------------------- +%% File : CosNotifyChannelAdmin_EventChannelFactory_impl.erl +%% Purpose : +%%------------------------------------------------------------------- + +-module('CosNotifyChannelAdmin_EventChannelFactory_impl'). + +%%--------------- INCLUDES ----------------------------------- +%% Application files +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- IMPORTS ------------------------------------ + +%%--------------- EXPORTS ------------------------------------ +%% External +-export([create_channel/5, + get_all_channels/3, + get_event_channel/4]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {adminProp, + idCounter = 0, + options, + etsR, + server_options}). + +%%-----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: See gen_server documentation. +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + ?debug_print("INFO: ~p~n", [Info]), + case Info of + {'EXIT', Pid, normal} -> + ets:match_delete(State#state.etsR, {'_','_',Pid}), + {noreply, State}; + _Other -> + ?debug_print("TERMINATED: ~p~n",[_Other]), + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init(Options) -> + process_flag(trap_exit, true), + SO = 'CosNotification_Common':get_option(server_options, Options, ?not_DEFAULT_SETTINGS), + {ok, #state{options = Options, + etsR = ets:new(oe_ets, [set, protected]), + server_options = SO}}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% function : create_channel +%% Arguments: InitQoS +%% InitAdmin +%% Returns : Ch - Channel obj ref +%% Id - Channel Id (out-type) +%%----------------------------------------------------------- +create_channel(OE_THIS, _OE_FROM, State, InitQoS, InitAdmin) -> + {QoS, LQoS} = 'CosNotification_Common':init_qos(InitQoS), + {IAdm, LAdm} = 'CosNotification_Common':init_adm(InitAdmin), + Id = 'CosNotification_Common':create_id(State#state.idCounter), + case 'CosNotifyChannelAdmin_EventChannel':oe_create_link([OE_THIS, QoS, IAdm, + LQoS, LAdm, + State#state.options], + [{sup_child, true}|State#state.server_options]) of + {ok, Pid, Ch} -> + ets:insert(State#state.etsR, {Id,Ch,Pid}), + {reply, {Ch, Id}, State#state{idCounter=Id}}; + _ -> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : get_all_channels +%% Arguments: - +%% Returns : ChannelIDSeq - List of alive channels created +%% by this factory. +%%----------------------------------------------------------- +get_all_channels(_OE_THIS, _OE_FROM, State) -> + {reply, lists:flatten(ets:match(State#state.etsR, {'$1','_','_'})), State}. + +%%----------------------------------------------------------% +%% function : get_event_channel +%% Arguments: ChannelId +%% Returns : ChannelRef | 'CosNotifyChannelAdmin_ChannelNotFound' +%%----------------------------------------------------------- +get_event_channel(_OE_THIS, _OE_FROM, State, Id) -> + {reply, find_obj(ets:lookup(State#state.etsR, Id)), State}. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +find_obj([]) -> {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}; +find_obj([{_, Obj,_}]) -> Obj; +find_obj(_) -> {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}. + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannel_impl.erl b/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannel_impl.erl new file mode 100644 index 0000000000..f37a97c4a7 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannel_impl.erl @@ -0,0 +1,721 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%------------------------------------------------------------------- +%% File : CosNotifyChannelAdmin_EventChannel_impl.erl +%% Purpose : +%% Created : 28 Sep 1999 +%%------------------------------------------------------------------- + +-module('CosNotifyChannelAdmin_EventChannel_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%%----- CosNotifyChannelAdmin::EventChannel ------------------ +-export([new_for_consumers/4, + new_for_suppliers/4, + get_consumeradmin/4, + get_supplieradmin/4, + get_all_consumeradmins/3, + get_all_supplieradmins/3]). + +%% Attributes (external) +-export(['_get_MyFactory'/3, + '_get_default_consumer_admin'/3, + '_get_default_supplier_admin'/3, + '_get_default_filter_factory'/3]). + +%%----- Inherit from CosNotification::QoSAdmin --------------- +-export([get_qos/3, + set_qos/4, + validate_qos/4]). + +%%----- Inherit from CosNotification::AdminPropertiesAdmin --- +-export([get_admin/3, + set_admin/4]). + +%%----- Inherit from CosEventChannelAdmin::EventChannel ------ +-export([for_consumers/3, + for_suppliers/3, + destroy/3]). +%%--------------- Internal ----------------------------------- +%%----- Inherit from cosNotificationComm --------------------- +-export([callAny/5, + callSeq/5]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%% Data structures +-record(state, {myFac, + myConsumers = [], + defConsumerAdmin, + defSupplierAdmin, + defConsumerAdminPid, + defSupplierAdminPid, + defFilterFac, + defFilterFacPid, + etsR, + qosLocal, + qosGlobal, + admGlobal, + options, + idCounter = 0, + 'MaxQueueLength', + 'MaxConsumers', + 'MaxSuppliers'}). +%% Data structures constructors +-define(get_InitState(My, Fil, FilPid, QoS, LQoS, GA, MQ, MC, MS, O), + #state{myFac = My, + defFilterFac = Fil, + defFilterFacPid = FilPid, + etsR = ets:new(oe_ets, [set, protected]), + qosLocal = LQoS, + qosGlobal = QoS, + admGlobal = GA, + options = O, + 'MaxQueueLength' = MQ, + 'MaxConsumers' = MC, + 'MaxSuppliers' = MS}). + +%% NOTE!!! +%% When forwarding events, the objects we will contact is ONLY ConsumerAdmins!! +%% Hence, we will store SupplierAdmins and ConsumerAdmins differently. SupplierAdmins +%% we store in our ets-table while the ConsumerAdmins will be stored on the local +%% State. + +%% Data structures selectors +-define(get_supplierAdmins(S), [S#state.defSupplierAdmin| + lists:flatten(ets:match(S#state.etsR, + {'_','$1','_'}))]). +-define(get_consumerAdmins(S), [{0, S#state.defConsumerAdmin,S#state.defConsumerAdminPid} + |S#state.myConsumers]). +-define(get_allAdmins(S), [S#state.defSupplierAdmin, + S#state.defConsumerAdmin| + lists:flatten(ets:match(S#state.etsR, + {'_','$1','_'}))++ + find_field(S#state.myConsumers, 2)]). +-define(get_consumerAdmIDs(S), [0|find_field(S#state.myConsumers, 1)]). +-define(get_supplierAdmIDs(S), [0|lists:flatten(ets:match(S#state.etsR, + {'$1','_','_'}))]). + +-define(get_supplierAdmin(S, I), find_obj(ets:lookup(S#state.etsR, I))). +-define(get_consumerAdmin(S, I), find_obj(lists:keysearch(I,1,S#state.myConsumers))). +-define(get_supplierAmount(S), ets:info(S#state.etsR, size)). +-define(get_consumerAmount(S), length(S#state.myConsumers)). + +-define(get_MyFactory(S), S#state.myFac). +-define(get_defConsumerAdm(S), S#state.defConsumerAdmin). +-define(get_defSupplierAdm(S), S#state.defSupplierAdmin). +-define(get_defConsumerAdmPid(S), S#state.defConsumerAdminPid). +-define(get_defSupplierAdmPid(S), S#state.defSupplierAdminPid). +-define(get_defFilterFac(S), S#state.defFilterFac). +-define(get_defFilterFacPid(S), S#state.defFilterFacPid). +-define(get_GlobalQoS(S), S#state.qosGlobal). +-define(get_LocalQoS(S), S#state.qosLocal). +-define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}). +-define(get_GlobalAdm(S), S#state.admGlobal). +-define(get_Options(S), S#state.options). +-define(get_MaxQueueLength(S), S#state.'MaxQueueLength'). +-define(get_MaxConsumers(S), S#state.'MaxConsumers'). +-define(get_MaxSuppliers(S), S#state.'MaxSuppliers'). +-define(get_IdCounter(S), S#state.idCounter). + +%% Data structures modifiers +-define(set_GlobalQoS(S,D), S#state{qosGlobal=D}). +-define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}). +-define(set_GlobalAdm(S,D), S#state{admGlobal=D}). +-define(set_AllAdminP(S,GD, MQ, MC, MS), + S#state{admGlobal=GD,'MaxQueueLength'=MQ, + 'MaxConsumers'=MC, 'MaxSuppliers'=MS}). +-define(set_MaxQueueLength(S,D), S#state{'MaxQueueLength'=D}). +-define(set_MaxConsumers(S,D), S#state{'MaxConsumers'=D}). +-define(set_MaxSuppliers(S,D), S#state{'MaxSuppliers'=D}). +-define(set_defConsumerAdm(S,D,P), S#state{defConsumerAdmin=D, defConsumerAdminPid=P}). +-define(set_defSupplierAdm(S,D,P), S#state{defSupplierAdmin=D, defSupplierAdminPid=P}). +-define(set_defFilterFac(S,D,P), S#state{defFilterFac=D, defFilterFacPid=P}). +-define(add_supplierAdmin(S,I,O,P), ets:insert(S#state.etsR, {I,O,P})). +-define(add_consumerAdmin(S,I,O,P), S#state{myConsumers= [{I,O,P}|S#state.myConsumers]}). +-define(del_supplierAdmin(S,I), ets:delete(S#state.etsR, I)). +-define(del_consumerAdmin(S,I), S#state{myConsumers= + lists:keydelete(I, 1, + S#state.myConsumers)}). +-define(del_consumerAdminRef(S,O), S#state{myConsumers= + lists:keydelete(O, 2, + S#state.myConsumers)}). +-define(del_AdminPid(S,P), delete_obj(S, P)). +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). +%% MISC +-define(is_UndefDefConsAdm(S), S#state.defConsumerAdmin == undefined). +-define(is_UndefDefSuppAdm(S), S#state.defSupplierAdmin == undefined). +-define(is_UndefDefFilterFac(S), S#state.defFilterFac == undefined). +-define(is_PersistentConnection(S), + ?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent). +-define(is_PersistentEvent(S), + ?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent). + +%%-----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + ?DBG("INFO: ~p~n", [Info]), + case Info of + {'EXIT', Pid, _Reason} when ?get_defConsumerAdmPid(State) == Pid -> + {noreply, ?set_defConsumerAdm(State, undefined, undefined)}; + {'EXIT', Pid, _Reason} when ?get_defSupplierAdmPid(State) == Pid -> + {noreply, ?set_defSupplierAdm(State, undefined, undefined)}; + {'EXIT', Pid, _Reason} when ?get_defFilterFacPid(State) == Pid -> + {noreply, ?set_defFilterFac(State, undefined, undefined)}; + {'EXIT', Pid, normal} -> + {noreply, ?del_AdminPid(State, Pid)}; + _Other -> + ?DBG("TERMINATED: ~p~n",[_Other]), + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([MyFac, InitQoS, InitAdmin, LocalQoS, [MaxQ, MaxC, MaxS|_], Options]) -> + process_flag(trap_exit, true), + SO = 'CosNotification_Common':get_option(server_options, Options, + ?not_DEFAULT_SETTINGS), + + ?DBG("CHANNEL INIT STATE:~n~p~n~p~n~p ~p ~p ~p~n~p~n", + [InitQoS, InitAdmin, LocalQoS,MaxQ, MaxC, MaxS, Options]), + + %% Both default Admin:s have the unique id 0 (OMG spec, 98-11-01, + %% Notification p 148), hence, no need to create a unique id. + %% We don't have acces to OE_THIS in this stage so we cannot create the objects + %% now, even though the specification states that. + %% DefConAdm = 'CosNotifyChannelAdmin_ConsumerAdmin':oe_create_link([0],[]), + %% DefSupAdm = 'CosNotifyChannelAdmin_SupplierAdmin':oe_create_link([0],[]), + + case 'CosNotifyFilter_FilterFactory':oe_create_link([], [{sup_child, true}|SO]) of + {ok, Pid, DefFiFac} -> + {ok, ?get_InitState(MyFac, DefFiFac, Pid, InitQoS, LocalQoS, + InitAdmin, MaxQ, MaxC, MaxS, Options)}; + Reason -> + {stop, Reason} + end. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%----- CosNotifyChannelAdmin_EventChannel attributes ------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_MyFactory' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyFactory'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyFactory(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_default_consumer_admin' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_default_consumer_admin'(OE_THIS, _OE_FROM, State) + when ?is_UndefDefConsAdm(State) -> + Op = 'CosNotification_Common':get_option(filterOp, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_ConsumerAdmin':oe_create_link([0, OE_THIS, + self(), Op, + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, DefConAdm} -> + {reply, DefConAdm, ?set_defConsumerAdm(State, DefConAdm, Pid)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:_get_default_consumer_admin();~n" + "Unable to create: CosNotifyChannelAdmin_ConsumerAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +'_get_default_consumer_admin'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_defConsumerAdm(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_default_supplier_admin' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_default_supplier_admin'(OE_THIS, _OE_FROM, State) + when ?is_UndefDefSuppAdm(State) -> + Op = 'CosNotification_Common':get_option(filterOp, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_SupplierAdmin':oe_create_link([0, OE_THIS, + self(), Op, + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, DefSupAdm} -> + {reply, DefSupAdm, ?set_defSupplierAdm(State, DefSupAdm, Pid)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:_get_default_supplier_admin();~n" + "Unable to create: CosNotifyChannelAdmin_SupplierAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +'_get_default_supplier_admin'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_defSupplierAdm(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_default_filter_factory' +%% Type : readonly +%% Returns : +%%---------------------------------------------------------- +'_get_default_filter_factory'(_OE_THIS, _OE_FROM, State) + when ?is_UndefDefFilterFac(State) -> + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyFilter_FilterFactory':oe_create_link([], [{sup_child, true}|SO]) of + {ok, Pid, DefFiFac} -> + {reply, DefFiFac, ?set_defFilterFac(State, DefFiFac, Pid)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:_get_default_filter_factory();~n" + "Unable to create: CosNotifyChannelAdmin_FilterFactory.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +'_get_default_filter_factory'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_defFilterFac(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% function : new_for_consumers +%% Arguments: Op - InterFilterGroupOperator: 'AND_OP' | 'OR_OP' +%% Determines if the Admin:s proxy-children will +%% use AND or OR when checking Filters. +%% Returns : ConsAdm +%% AdminId (out) +%%----------------------------------------------------------- +new_for_consumers(OE_THIS, _OE_FROM, State, Op) -> + is_admin_limit_reached(?get_MaxConsumers(State), ?get_consumerAmount(State)), + AdminId = ?new_Id(State), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_ConsumerAdmin':oe_create_link([AdminId, OE_THIS, + self(), Op, + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, AdminCo} -> + %% Due to different storage, adding a new consumer is NOT done in the + %% same way as for suppliers. + NewState = ?add_consumerAdmin(State, AdminId, AdminCo, Pid), + {reply, {AdminCo, AdminId}, ?set_IdCounter(NewState, AdminId)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:nef_for_consumers();~n" + "Unable to create: CosNotifyChannelAdmin_ConsumerAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : new_for_suppliers +%% Arguments: Op - InterFilterGroupOperator: 'AND_OP' | 'OR_OP' +%% Determines if the Admin:s proxy-children will +%% use AND or OR when checking Filters. +%% Returns : SuppAdm +%% AdminId (out) +%%----------------------------------------------------------- +new_for_suppliers(OE_THIS, _OE_FROM, State, Op) -> + is_admin_limit_reached(?get_MaxSuppliers(State), ?get_supplierAmount(State)), + AdminId = ?new_Id(State), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_SupplierAdmin':oe_create_link([AdminId, OE_THIS, + self(), Op, + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, AdminSu} -> + %% Due to different storage, adding a new supplier is NOT done in the + %% same way as for consumers. + ?add_supplierAdmin(State, AdminId, AdminSu, Pid), + {reply, {AdminSu, AdminId}, ?set_IdCounter(State, AdminId)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:new_for_suppliers();~n" + "Unable to create: CosNotifyChannelAdmin_SupplierAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : get_consumeradmin +%% Arguments: AdminId +%% Returns : ConsAdmin +%%----------------------------------------------------------- +get_consumeradmin(OE_THIS, _OE_FROM, State, 0) when ?is_UndefDefConsAdm(State) -> + Op = 'CosNotification_Common':get_option(filterOp, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_ConsumerAdmin':oe_create_link([0, OE_THIS, + self(), Op, + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, DefConAdm} -> + {reply, DefConAdm, ?set_defConsumerAdm(State, DefConAdm, Pid)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:get_consumer_admin();~n" + "Unable to create: CosNotifyChannelAdmin_ConsumerAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +get_consumeradmin(_OE_THIS, _OE_FROM, State, 0) -> + {reply, ?get_defConsumerAdm(State), State}; +get_consumeradmin(_OE_THIS, _OE_FROM, State, AdminId) when is_integer(AdminId) -> + {reply, ?get_consumerAdmin(State, AdminId), State}; +get_consumeradmin(_, _, _, What) -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:get_consumeradmin(~p);~n" + "Not an integer", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_supplieradmin +%% Arguments: AdminId +%% Returns : +%%----------------------------------------------------------- +get_supplieradmin(OE_THIS, _OE_FROM, State, 0) when ?is_UndefDefSuppAdm(State) -> + Op = 'CosNotification_Common':get_option(filterOp, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_SupplierAdmin':oe_create_link([0, OE_THIS, + self(), Op, + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, DefSupAdm} -> + {reply, DefSupAdm, ?set_defSupplierAdm(State, DefSupAdm, Pid)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:get_supplieradmin();~n" + "Unable to create: CosNotifyChannelAdmin_SupplierAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +get_supplieradmin(_OE_THIS, _OE_FROM, State, 0) -> + {reply, ?get_defSupplierAdm(State), State}; +get_supplieradmin(_OE_THIS, _OE_FROM, State, AdminId) when is_integer(AdminId) -> + {reply, ?get_supplierAdmin(State, AdminId), State}; +get_supplieradmin(_, _, _, What) -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:get_supplieradmin(~p);~n" + "Not an integer", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_all_consumeradmins +%% Arguments: - +%% Returns : AdminIDSeq - a list of all unique ID:s. +%%----------------------------------------------------------- +get_all_consumeradmins(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_consumerAdmIDs(State), State}. + +%%----------------------------------------------------------% +%% function : get_all_supplieradmins +%% Arguments: - +%% Returns : AdminIDSeq - a list of all unique ID:s. +%%----------------------------------------------------------- +get_all_supplieradmins(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_supplierAdmIDs(State), State}. + + +%%----- Inherit from CosNotification::QoSAdmin -------------- +%%----------------------------------------------------------% +%% function : get_qos +%% Arguments: - +%% Returns : CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%%----------------------------------------------------------- +get_qos(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalQoS(State), State}. + +%%----------------------------------------------------------% +%% function : set_qos +%% Arguments: QoS - CosNotification::QoSProperties, i.e., +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +set_qos(_OE_THIS, _OE_FROM, State, QoS) -> + {GQoS,LQoS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State), + channel, false, + ?get_allAdmins(State)), + {reply, ok, ?set_BothQoS(State, GQoS,LQoS)}. + +%%----------------------------------------------------------% +%% function : validate_qos +%% Arguments: Required_qos - CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS} | +%% {ok, CosNotification::NamedPropertyRangeSeq} +%%----------------------------------------------------------- +validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) -> + QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State), + channel, false, + ?get_allAdmins(State)), + {reply, {ok, QoS}, State}. + +%%----- Inherit from CosNotification::AdminPropertiesAdmin -- +%%-----------------------------------------------------------% +%% function : get_admin +%% Arguments: - +%% Returns : AdminProperties +%%----------------------------------------------------------- +get_admin(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalAdm(State), State}. + +%%----------------------------------------------------------% +%% function : set_admin +%% Arguments: Admin +%% Returns : +%%----------------------------------------------------------- +set_admin(_OE_THIS, _OE_FROM, State, Admin) -> + {GAdm,[MaxQ, MaxC, MaxS|_]} = + 'CosNotification_Common':set_adm(Admin, ?get_GlobalAdm(State)), + {reply, ok, ?set_AllAdminP(State, GAdm, MaxQ, MaxC, MaxS)}. + +%%----- Inherit from CosEventChannelAdmin::EventChannel ----- +%%----------------------------------------------------------% +%% function : for_consumers +%% Arguments: - +%% Returns : ConsAdm +%%----------------------------------------------------------- +for_consumers(OE_THIS, _OE_FROM, State) -> + is_admin_limit_reached(?get_MaxConsumers(State), ?get_consumerAmount(State)), + AdminId = ?new_Id(State), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_ConsumerAdmin':oe_create_link([AdminId, OE_THIS, + self(), 'AND_OP', + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, AdminCo} -> + %% Due to different storage, adding a new consumer is NOT done in the + %% same way as for suppliers. + NewState = ?add_consumerAdmin(State, AdminId, AdminCo, Pid), + {reply, AdminCo, ?set_IdCounter(NewState, AdminId)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:for_consumers();~n" + "Unable to create: CosNotifyChannelAdmin_ConsumerAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : for_suppliers +%% Arguments: - +%% Returns : SuppAdm +%%----------------------------------------------------------- +for_suppliers(OE_THIS, _OE_FROM, State) -> + is_admin_limit_reached(?get_MaxSuppliers(State), ?get_supplierAmount(State)), + AdminId = ?new_Id(State), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_SupplierAdmin':oe_create_link([AdminId, OE_THIS, + self(), 'AND_OP', + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, AdminSu} -> + %% Due to different storage, adding a new supplier is NOT done in the + %% same way as for consumers. + ?add_supplierAdmin(State, AdminId, AdminSu, Pid), + {reply, AdminSu, ?set_IdCounter(State, AdminId)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:for_suppliers();~n" + "Unable to create: CosNotifyChannelAdmin_SupplierAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%-----------------------------------------------------------% +%% function : destroy +%% Arguments: - +%% Returns : ok +%%------------------------------------------------------------ +destroy(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, State}. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +find_obj([]) -> {'EXCEPTION', #'CosNotifyChannelAdmin_AdminNotFound'{}}; +find_obj([{_, Obj,_}]) -> Obj; +find_obj({value, {_, Obj,_}}) -> Obj; +find_obj(_) -> {'EXCEPTION', #'CosNotifyChannelAdmin_AdminNotFound'{}}. + + +find_field(List, Field) -> + find_field(List, Field, []). + +find_field([], _, Acc) -> + Acc; +find_field([{I,_,_}|T], 1, Acc) -> + find_field(T, 1, [I|Acc]); +find_field([{_,O,_}|T], 2, Acc) -> + find_field(T, 2, [O|Acc]); +% Left out for now to avoid dialyzer warning. +%find_field([{_,_,P}|T], 3, Acc) -> +% find_field(T, 3, [P|Acc]); +find_field(What, _, _) -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:find_field();~n" + "Data corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +delete_obj(State, Pid) -> + case ets:match_object(State#state.etsR, {'_', '_', Pid}) of + [] -> + State#state{myConsumers=lists:keydelete(Pid, 3, State#state.myConsumers)}; + [{Id,_Obj,Pid}] -> + ets:delete(State#state.etsR, Id), + State + end. + +%% Test if we have reached limit for Admin objects. +is_admin_limit_reached(0, _) -> + %% When set to zero it means that there is no limit. + ok; +is_admin_limit_reached(Max, Current) when Current >= Max -> + %% The Current value do not include the default Admin objects, hence + %% we use >= instead of >. + corba:raise(#'IMP_LIMIT'{completion_status=?COMPLETED_NO}); +is_admin_limit_reached(_, _) -> + ok. + +%%----------------------------------------------------------- +%% function : callSeq +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callSeq(_OE_THIS, OE_FROM, State, Event, Status) -> + corba:reply(OE_FROM, ok), + forward(seq, State, Event, Status). + +%%----------------------------------------------------------- +%% function : callAny +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callAny(_OE_THIS, OE_FROM, State, Event, Status) -> + corba:reply(OE_FROM, ok), + forward(any, State, Event, Status). + +%% Forward events +forward(Type, State, Event, Status) -> + forward(Type, ?get_consumerAdmins(State), State, Event, Status). + +forward(_, [], State, _, _) -> + {noreply, State}; +forward(Type, [{_,undefined,_}|T], State, Event, Status) -> + %% Match if no default objects associated. + forward(Type, T, State, Event, Status); +forward(any, [{_,H,_}|T], State, Event, Status) -> + case catch oe_CosNotificationComm_Event:callAny(H, Event, Status) of + ok -> + ?DBG("CHANNEL FORWARD ANY: ~p~n",[Event]), + forward(any, T, State, Event, Status); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n" + "Admin no longer exists; dropping it: ~p", + [?LINE, H], ?DEBUG_LEVEL), + NewState = ?del_consumerAdminRef(State,H), + forward(any, T, NewState, Event, Status); + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n" + "Admin behaves badly: ~p/~p", + [?LINE, R, H], ?DEBUG_LEVEL), + forward(any, T, State, Event, Status); + R -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n" + "Admin behaves badly: ~p~n" + "Dropping it: ~p", [?LINE, R, H], ?DEBUG_LEVEL), + NewState = ?del_consumerAdminRef(State, H), + forward(any, T, NewState, Event, Status) + end; +forward(seq, [{_,H,_}|T], State, Event, Status) -> + case catch oe_CosNotificationComm_Event:callSeq(H, Event, Status) of + ok -> + ?DBG("CHANNEL FORWARD SEQUENCE: ~p~n",[Event]), + forward(seq, T, State, Event, Status); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n" + "Admin no longer exists; dropping it: ~p", + [?LINE, H], ?DEBUG_LEVEL), + NewState = ?del_consumerAdminRef(State,H), + forward(seq, T, NewState, Event, Status); + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n" + "Admin behaves badly: ~p/~p", + [?LINE, R, H], ?DEBUG_LEVEL), + forward(seq, T, State, Event, Status); + R -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n" + "Admin behaves badly: ~p~n" + "Dropping it: ~p", [?LINE, R, H], ?DEBUG_LEVEL), + NewState = ?del_consumerAdminRef(State,H), + forward(seq, T, NewState, Event, Status) + end. + + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin_SupplierAdmin_impl.erl b/lib/cosNotification/src/CosNotifyChannelAdmin_SupplierAdmin_impl.erl new file mode 100644 index 0000000000..1c3f3d8d0b --- /dev/null +++ b/lib/cosNotification/src/CosNotifyChannelAdmin_SupplierAdmin_impl.erl @@ -0,0 +1,579 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%------------------------------------------------------------------- +%% File : CosNotifyChannelAdmin_SupplierAdmin_impl.erl +%% Purpose : +%%------------------------------------------------------------------- + +-module('CosNotifyChannelAdmin_SupplierAdmin_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%%----- CosNotifyChannelAdmin::SupplierAdmin ----------------- +-export([get_proxy_consumer/4, + obtain_notification_pull_consumer/4, + obtain_notification_push_consumer/4, + destroy/3]). + +%%----- Inherit from CosNotification::QoSAdmin --------------- +-export([get_qos/3, + set_qos/4, + validate_qos/4]). + +%%----- Inherit from CosNotifyComm::NotifyPublish ------------ +-export([offer_change/5]). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ------------ +-export([add_filter/4, + remove_filter/4, + get_filter/4, + get_all_filters/3, + remove_all_filters/3]). + +%%----- Inherit from CosEventChannelAdmin::SupplierAdmin ----- +-export([obtain_push_consumer/3, + obtain_pull_consumer/3]). + +%% Attributes (external) +-export(['_get_MyID'/3, + '_get_MyChannel'/3, + '_get_MyOperator'/3, + '_get_pull_consumers'/3, + '_get_push_consumers'/3]). + +%%--------------- Internal ----------------------------------- +%%----- Inherit from cosNotificationComm --------------------- +-export([callAny/5, + callSeq/5]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {myId, + myChannel, + myChannelPid, + myOperator, + myFilters = [], + idCounter = 0, + etsR, + qosGlobal, + qosLocal, + options}). + +%% Data structures constructors +-define(get_InitState(_MyID, _MyCh, _MyChP, _MyOp, _QoS, _LQS, _O), + #state{myId = _MyID, + myChannel = _MyCh, + myChannelPid = _MyChP, + myOperator = _MyOp, + qosGlobal = _QoS, + qosLocal = _LQS, + options = _O, + etsR = ets:new(oe_ets, [set, protected])}). + +%% Data structures selectors +-define(get_PushConsumers(S), lists:flatten(ets:match(S#state.etsR, + {'_','$1','_',pusher}))). +-define(get_PullConsumers(S), lists:flatten(ets:match(S#state.etsR, + {'_','$1','_',puller}))). +-define(get_AllConsumers(S), lists:flatten(ets:match(S#state.etsR, + {'_','$1','_','_'}))). +-define(get_PushConsumerIDs(S), lists:flatten(ets:match(S#state.etsR, + {'$1','_','_',pusher}))). +-define(get_PullConsumerIDs(S), lists:flatten(ets:match(S#state.etsR, + {'$1','_','_',puller}))). + +-define(get_Consumer(S, I), find_obj(ets:lookup(S#state.etsR, I), consumer)). + +-define(get_MyID(S), S#state.myId). +-define(get_MyChannel(S), S#state.myChannel). +-define(get_MyChannelPid(S), S#state.myChannelPid). +-define(get_MyOperator(S), S#state.myOperator). +-define(get_GlobalQoS(S), S#state.qosGlobal). +-define(get_LocalQoS(S), S#state.qosLocal). +-define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}). +-define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters), + filter)). +-define(get_AllFilter(S), S#state.myFilters). +-define(get_AllFilterID(S), find_ids(S#state.myFilters)). +-define(get_Options(S), S#state.options). +-define(get_IdCounter(S), S#state.idCounter). + +%% Data structures modifiers +-define(set_LocalQoS(S,D), S#state{qosLocal=D}). +-define(set_GlobalQoS(S,D), S#state{qosGlobal=D}). +-define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}). +-define(add_PushConsumer(S,I,R,P),ets:insert(State#state.etsR, {I,R,P,pusher})). +-define(add_PullConsumer(S,I,R,P),ets:insert(State#state.etsR, {I,R,P,puller})). +-define(del_Consumer(S,I), ets:delete(S#state.etsR, I)). +-define(del_ConsumerPid(S,P), ets:match_delete(S#state.etsR, {'_','_',P,'_'})). +-define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}). +-define(del_Filter(S,I), S#state{myFilters= + delete_filter(lists:keydelete(I, 1, + S#state.myFilters), + S#state.myFilters)}). +-define(del_AllFilter(S), S#state{myFilters=[]}). +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). + +%% MISC +-define(is_PersistentEvent(S), + ?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent). +-define(is_PersistentConnection(S), + ?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent). + +%%----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%----------------------------------------------------------- + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + case Info of + {'EXIT', Pid, Reason} when ?get_MyChannelPid(State) == Pid -> + ?DBG("PARENT CHANNEL: ~p TERMINATED.~n",[Reason]), + {stop, Reason, State}; + {'EXIT', Pid, normal} -> + ?del_ConsumerPid(State, Pid), + {noreply, State}; + _Other -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([MyId, MyChannel, MyChannelPid, MyOperator, InitQoS, LQS, Options]) -> + process_flag(trap_exit, true), + {ok, ?get_InitState(MyId, MyChannel, MyChannelPid, MyOperator, InitQoS, LQS, Options)}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%----- CosNotifyChannelAdmin_ConsumerAdmin attributes ------ +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_MyID' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyID'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyID(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyChannel' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyChannel'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyChannel(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyOperator' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyOperator'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyOperator(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_pull_consumers' +%% Type : readonly +%% Returns : ProxyIDSeq +%%----------------------------------------------------------- +'_get_pull_consumers'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_PullConsumerIDs(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_push_consumers' +%% Type : readonly +%% Returns : ProxyIDSeq +%%----------------------------------------------------------- +'_get_push_consumers'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_PushConsumerIDs(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% function : get_proxy_consumer +%% Arguments: ProxyId - unique identifier (long) +%% Returns : ObjRef | {'EXCEPTION', #'ProxyNotFound'{}} +%%----------------------------------------------------------- +get_proxy_consumer(_OE_THIS, _OE_FROM, State, ProxyId) -> + {reply, ?get_Consumer(State, ProxyId), State}. + +%%----------------------------------------------------------% +%% function : obtain_notification_pull_consumer +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +obtain_notification_pull_consumer(OE_THIS, _OE_FROM, State, Ctype) -> + %% Choose which module to use. + {Mod, Type} = + case Ctype of + 'ANY_EVENT' -> + {'CosNotifyChannelAdmin_ProxyPullConsumer', 'PULL_ANY'}; + 'STRUCTURED_EVENT' -> + {'CosNotifyChannelAdmin_StructuredProxyPullConsumer', 'PULL_STRUCTURED'}; + 'SEQUENCE_EVENT' -> + {'CosNotifyChannelAdmin_SequenceProxyPullConsumer', 'PULL_SEQUENCE'}; + _ -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:" + "obtain_notification_pull_consumer(~p);~n" + "Incorrect enumerant", + [?LINE, Ctype], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end, + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch Mod:oe_create_link([Type, OE_THIS, self(), ?get_GlobalQoS(State), + ?get_LocalQoS(State), ?get_MyChannel(State), + ?get_Options(State), ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, Proxy} -> + ProxyID = ?new_Id(State), + ?add_PullConsumer(State, ProxyID, Proxy, Pid), + {reply, {Proxy, ProxyID}, ?set_IdCounter(State, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:" + "obtain_notification_pull_consumer();~n" + "Unable to create: ~p/~p~n" + "Reason: ~p", [?LINE, Mod, Type, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : obtain_notification_push_supplier +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +obtain_notification_push_consumer(OE_THIS, _OE_FROM, State, Ctype) -> + %% Choose which module to use. + {Mod, Type} = + case Ctype of + 'ANY_EVENT' -> + {'CosNotifyChannelAdmin_ProxyPushConsumer', 'PUSH_ANY'}; + 'STRUCTURED_EVENT' -> + {'CosNotifyChannelAdmin_StructuredProxyPushConsumer', 'PUSH_STRUCTURED'}; + 'SEQUENCE_EVENT' -> + {'CosNotifyChannelAdmin_SequenceProxyPushConsumer', 'PUSH_SEQUENCE'}; + _ -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:" + "obtain_notification_push_consumer(~p);~n" + "Incorrect enumerant", [?LINE, Ctype], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end, + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch Mod:oe_create_link([Type, OE_THIS, self(), ?get_GlobalQoS(State), + ?get_LocalQoS(State), ?get_MyChannel(State), + ?get_Options(State), ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, Proxy} -> + ProxyID = ?new_Id(State), + ?add_PushConsumer(State, ProxyID, Proxy, Pid), + {reply, {Proxy, ProxyID}, ?set_IdCounter(State, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:" + "obtain_notification_push_consumer();~n" + "Unable to create: ~p/~p~n" + "Reason: ~p", [?LINE, Mod, Type, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : destroy +%% Arguments: - +%% Returns : ok +%%------------------------------------------------------------ +destroy(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, State}. + +%%----- Inherit from CosNotification::QoSAdmin -------------- +%%----------------------------------------------------------% +%% function : get_qos +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +get_qos(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalQoS(State), State}. + +%%----------------------------------------------------------% +%% function : set_qos +%% Arguments: QoS - CosNotification::QoSProperties, i.e., +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +set_qos(_OE_THIS, _OE_FROM, State, QoS) -> + {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State), + admin, ?get_MyChannel(State), + ?get_AllConsumers(State)), + {reply, ok, ?set_BothQoS(State, NewQoS, LQS)}. + +%%----------------------------------------------------------% +%% function : validate_qos +%% Arguments: Required_qos - CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS} +%% {ok, CosNotification::NamedPropertyRangeSeq} +%%----------------------------------------------------------- +validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) -> + QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State), + admin, ?get_MyChannel(State), + ?get_AllConsumers(State)), + {reply, {ok, QoS}, State}. + +%%----- Inherit from CosNotifyComm::NotifyPublish ----------- +%%----------------------------------------------------------* +%% function : offer_change +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +offer_change(_OE_THIS, _OE_FROM, State, _Added, _Removed) -> + {reply, ok, State}. + +%%----- Inherit from CosNotifyFilter::FilterAdmin ----------- +%%----------------------------------------------------------% +%% function : add_filter +%% Arguments: Filter - CosNotifyFilter::Filter +%% Returns : FilterID - long +%%----------------------------------------------------------- +add_filter(_OE_THIS, _OE_FROM, State, Filter) -> + 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'), + FilterID = ?new_Id(State), + NewState = ?set_IdCounter(State, FilterID), + {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}. + +%%----------------------------------------------------------% +%% function : remove_filter +%% Arguments: FilterID - long +%% Returns : ok +%%----------------------------------------------------------- +remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ok, ?del_Filter(State, FilterID)}; +remove_filter(_,_,_,What) -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:remove_filter(~p);~n" + "Not an integer", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_filter +%% Arguments: FilterID - long +%% Returns : Filter - CosNotifyFilter::Filter | +%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}} +%%----------------------------------------------------------- +get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ?get_Filter(State, FilterID), State}; +get_filter(_,_,_,What) -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:get_filter(~p);~n" + "Not an integer", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_all_filters +%% Arguments: - +%% Returns : Filter - CosNotifyFilter::FilterIDSeq +%%----------------------------------------------------------- +get_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_AllFilterID(State), State}. + +%%----------------------------------------------------------% +%% function : remove_all_filters +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ok, ?del_AllFilter(State)}. + +%%----- Inherit from CosEventChannelAdmin::SupplierAdmin ---- +%%----------------------------------------------------------% +%% function : obtain_push_consumer +%% Arguments: - +%% Returns : ProxyPushConsumer +%%----------------------------------------------------------- +obtain_push_consumer(OE_THIS, _OE_FROM, State) -> + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_ProxyPushConsumer': + oe_create_link(['PUSH_ANY', OE_THIS, self(), ?get_GlobalQoS(State), + ?get_LocalQoS(State), ?get_MyChannel(State), + ?get_Options(State), ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, Proxy} -> + ProxyID = ?new_Id(State), + ?add_PushConsumer(State, ProxyID, Proxy, Pid), + {reply, Proxy, ?set_IdCounter(State, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:obtain_push_consumer();~n" + "Unable to create: CosNotifyChannelAdmin_ProxyPushConsumer~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : obtain_pull_consumer +%% Arguments: - +%% Returns : ProxyPullConsumer +%%----------------------------------------------------------- +obtain_pull_consumer(OE_THIS, _OE_FROM, State) -> + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_ProxyPullConsumer': + oe_create_link(['PULL_ANY', OE_THIS, self(), ?get_GlobalQoS(State), + ?get_LocalQoS(State), ?get_MyChannel(State), + ?get_Options(State), ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, Proxy} -> + ProxyID = ?new_Id(State), + ?add_PullConsumer(State, ProxyID, Proxy, Pid), + {reply, Proxy, ?set_IdCounter(State, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:obtain_push_consumer();~n" + "Unable to create: CosNotifyChannelAdmin_ProxyPullConsumer~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +find_obj([], consumer) -> {'EXCEPTION', #'CosNotifyChannelAdmin_ProxyNotFound'{}}; +find_obj([], filter) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}; +%% To match consumers +find_obj([{_,Obj,_,_}],_) -> Obj; +%% To match filters +find_obj({value, {_,Obj}},_) -> Obj; +find_obj(_,consumer) -> {'EXCEPTION', #'CosNotifyChannelAdmin_ProxyNotFound'{}}; +find_obj(_,filter) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}. + +find_ids(List) -> find_ids(List, []). +find_ids([], Acc) -> Acc; +find_ids([{I,_}|T], Acc) -> find_ids(T, [I|Acc]); +find_ids(What, _) -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:find_ids();~n" + "Id corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +%% Delete a single filter. +%% The list do not differ, i.e., no filter removed, raise exception. +delete_filter(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{}); +delete_filter(List, _) -> List. + +%%----------------------------------------------------------- +%% function : callSeq +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callSeq(_OE_THIS, OE_FROM, State, Events, _Status) -> + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:filter_events(Events, ?get_AllFilter(State)) of + {[], _} -> + {noreply, State}; + {Passed, _} -> + forward(seq, State, Passed, 'MATCHED') + end. + +%%----------------------------------------------------------- +%% function : callAny +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callAny(_OE_THIS, OE_FROM, State, Event, _Status) -> + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:filter_events([Event], ?get_AllFilter(State)) of + {[], _} -> + {noreply, State}; + {[Passed], _} -> + forward(any, State, Passed, 'MATCHED') + end. + +%% Forward events +forward(any, State, Event, Status) -> + case catch oe_CosNotificationComm_Event:callAny(?get_MyChannel(State), + Event, Status) of + ok -> + ?DBG("SUPPLIERADM FORWARD ANY: ~p~n",[Event]), + {noreply, State}; + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n" + "Channel no longer exists; terminating and dropping: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + {stop, normal, State}; + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n" + "Channel respond incorrect: ~p~n" + "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL), + {noreply, State}; + R -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n" + "Channel respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, R, Event], ?DEBUG_LEVEL), + {stop, normal, State} + end; +forward(seq, State, Event, Status) -> + case catch oe_CosNotificationComm_Event:callSeq(?get_MyChannel(State), + Event, Status) of + ok -> + ?DBG("SUPPLIERADM FORWARD SEQUENCE: ~p~n",[Event]), + {noreply, State}; + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n" + "Channel no longer exists; terminating and dropping: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + {stop, normal, State}; + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n" + "Channel respond incorrect: ~p~n" + "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL), + {noreply, State}; + R -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n" + "Channel respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, R, Event], ?DEBUG_LEVEL), + {stop, normal, State} + end. + + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/CosNotifyComm.cfg b/lib/cosNotification/src/CosNotifyComm.cfg new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyComm.cfg diff --git a/lib/cosNotification/src/CosNotifyComm.idl b/lib/cosNotification/src/CosNotifyComm.idl new file mode 100644 index 0000000000..f0386f0982 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyComm.idl @@ -0,0 +1,83 @@ +#ifndef _COS_NOTIFYCOMM_IDL_ +#define _COS_NOTIFYCOMM_IDL_ + +#pragma prefix "omg.org" + + +#include<CosNotification.idl> + +module CosNotifyComm { + exception InvalidEventType { CosNotification::EventType type; }; + + interface NotifyPublish { + void offer_change (in CosNotification::EventTypeSeq added, + in CosNotification::EventTypeSeq removed) + raises (InvalidEventType); + }; // NotifyPublish + + interface NotifySubscribe { + void subscription_change(in CosNotification::EventTypeSeq added, + in CosNotification::EventTypeSeq removed) + raises (InvalidEventType); + }; // NotifySubscribe + + interface PushConsumer : NotifyPublish, CosEventComm::PushConsumer { }; // PushConsumer + + interface PullConsumer : NotifyPublish, CosEventComm::PullConsumer { }; // PullConsumer + + interface PullSupplier : NotifySubscribe, CosEventComm::PullSupplier { }; // PullSupplier + + interface PushSupplier : NotifySubscribe, CosEventComm::PushSupplier { }; + + interface StructuredPushConsumer : NotifyPublish { + void push_structured_event(in CosNotification::StructuredEvent notification) + raises(CosEventComm::Disconnected); + + void disconnect_structured_push_consumer(); + }; // StructuredPushConsumer + + interface StructuredPullConsumer : NotifyPublish { + void disconnect_structured_pull_consumer(); + }; // StructuredPullConsumer + + interface StructuredPullSupplier : NotifySubscribe { + CosNotification::StructuredEvent pull_structured_event() + raises(CosEventComm::Disconnected); + + CosNotification::StructuredEvent try_pull_structured_event(out boolean has_event) + raises(CosEventComm::Disconnected); + + void disconnect_structured_pull_supplier(); + }; // StructuredPullSupplier + + interface StructuredPushSupplier : NotifySubscribe { + void disconnect_structured_push_supplier(); + }; // StructuredPushSupplier + + interface SequencePushConsumer : NotifyPublish { + void push_structured_events(in CosNotification::EventBatch notifications) + raises(CosEventComm::Disconnected); + + void disconnect_sequence_push_consumer(); + }; // SequencePushConsumer + + interface SequencePullConsumer : NotifyPublish { + void disconnect_sequence_pull_consumer(); + }; // SequencePullConsumer + + interface SequencePullSupplier : NotifySubscribe { + CosNotification::EventBatch pull_structured_events(in long max_number) + raises(CosEventComm::Disconnected); + CosNotification::EventBatch try_pull_structured_events(in long max_number, out boolean has_event) + raises(CosEventComm::Disconnected); + + void disconnect_sequence_pull_supplier(); + }; // SequencePullSupplier + + interface SequencePushSupplier : NotifySubscribe { + void disconnect_sequence_push_supplier(); + }; // SequencePushSupplier +}; // CosNotifyComm + +#endif /* ifndef _COS_NOTIFYCOMM_IDL_ */ + diff --git a/lib/cosNotification/src/CosNotifyFilter.cfg b/lib/cosNotification/src/CosNotifyFilter.cfg new file mode 100644 index 0000000000..167550e0f5 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyFilter.cfg @@ -0,0 +1,6 @@ +{this, "CosNotifyFilter::Filter"}. +{{handle_info, "CosNotifyFilter::Filter"}, true}. +{this, "CosNotifyFilter::MappingFilter"}. +{{handle_info, "CosNotifyFilter::MappingFilter"}, true}. +{this, "CosNotifyFilter::FilterFactory"}. +{{handle_info, "CosNotifyFilter::FilterFactory"}, true}. diff --git a/lib/cosNotification/src/CosNotifyFilter.idl b/lib/cosNotification/src/CosNotifyFilter.idl new file mode 100644 index 0000000000..c6498ddcd0 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyFilter.idl @@ -0,0 +1,140 @@ +#ifndef _COS_NOTIFYFILTER_IDL_ +#define _COS_NOTIFYFILTER_IDL_ + +#pragma prefix "omg.org" + +#include<CosNotifyComm.idl> +#include<CosNotification.idl> + +module CosNotifyFilter { + typedef long ConstraintID; + struct ConstraintExp { + CosNotification::EventTypeSeq event_types; + string constraint_expr; + }; + + typedef sequence<ConstraintID> ConstraintIDSeq; + typedef sequence<ConstraintExp> ConstraintExpSeq; + struct ConstraintInfo { + ConstraintExp constraint_expression; + ConstraintID constraint_id; + }; + typedef sequence<ConstraintInfo> ConstraintInfoSeq; + struct MappingConstraintPair { + ConstraintExp constraint_expression; + any result_to_set; + }; + typedef sequence<MappingConstraintPair> MappingConstraintPairSeq; + struct MappingConstraintInfo { + ConstraintExp constraint_expression; + ConstraintID constraint_id; + any value; + }; + typedef sequence<MappingConstraintInfo> MappingConstraintInfoSeq; + typedef long CallbackID; + typedef sequence<CallbackID> CallbackIDSeq; + exception UnsupportedFilterableData {}; + exception InvalidGrammar {}; + exception InvalidConstraint {ConstraintExp constr;}; + exception DuplicateConstraintID {ConstraintID id;}; + exception ConstraintNotFound {ConstraintID id;}; + exception CallbackNotFound {}; + exception InvalidValue {ConstraintExp constr; any value;}; + interface Filter { + readonly attribute string constraint_grammar; + ConstraintInfoSeq add_constraints (in ConstraintExpSeq constraint_list) + raises (InvalidConstraint); + + void modify_constraints (in ConstraintIDSeq del_list, + in ConstraintInfoSeq modify_list) + raises (InvalidConstraint, ConstraintNotFound); + + ConstraintInfoSeq get_constraints(in ConstraintIDSeq id_list) + raises (ConstraintNotFound); + + ConstraintInfoSeq get_all_constraints(); + + void remove_all_constraints(); + void destroy(); + boolean match (in any filterable_data) + raises (UnsupportedFilterableData); + + boolean match_structured (in CosNotification::StructuredEvent filterable_data) + raises (UnsupportedFilterableData); + + boolean match_typed (in CosNotification::PropertySeq filterable_data) + raises (UnsupportedFilterableData); + + CallbackID attach_callback (in CosNotifyComm::NotifySubscribe callback); + + void detach_callback (in CallbackID callback) + raises ( CallbackNotFound ); + + CallbackIDSeq get_callbacks(); + }; // Filter + + interface MappingFilter { + readonly attribute string constraint_grammar; + + readonly attribute CORBA::TypeCode value_type; + + readonly attribute any default_value; + + MappingConstraintInfoSeq add_mapping_constraints (in MappingConstraintPairSeq pair_list) + raises (InvalidConstraint, InvalidValue); + + void modify_mapping_constraints (in ConstraintIDSeq del_list, + in MappingConstraintInfoSeq modify_list) + raises (InvalidConstraint, InvalidValue, ConstraintNotFound); + + MappingConstraintInfoSeq get_mapping_constraints (in ConstraintIDSeq id_list) + raises (ConstraintNotFound); + + MappingConstraintInfoSeq get_all_mapping_constraints(); + + void remove_all_mapping_constraints(); + + void destroy(); + + boolean match (in any filterable_data, out any result_to_set) + raises (UnsupportedFilterableData); + + boolean match_structured (in CosNotification::StructuredEvent filterable_data, out any result_to_set) + raises (UnsupportedFilterableData); + + boolean match_typed (in CosNotification::PropertySeq filterable_data, out any result_to_set) + raises (UnsupportedFilterableData); + }; // MappingFilter + + + interface FilterFactory { + + Filter create_filter (in string constraint_grammar) + raises (InvalidGrammar); + + MappingFilter create_mapping_filter (in string constraint_grammar, in any default_value) + raises(InvalidGrammar); + }; // FilterFactory + + typedef long FilterID; + typedef sequence<FilterID> FilterIDSeq; + exception FilterNotFound {}; + + interface FilterAdmin { + FilterID add_filter (in Filter new_filter); + + void remove_filter (in FilterID filter) + raises (FilterNotFound); + + Filter get_filter (in FilterID filter) + raises (FilterNotFound); + + FilterIDSeq get_all_filters(); + + void remove_all_filters(); + }; // FilterAdmin +}; // CosNotifyFilter + + +#endif /* ifndef _COS_NOTIFYFILTER_IDL_ */ + diff --git a/lib/cosNotification/src/CosNotifyFilter_FilterFactory_impl.erl b/lib/cosNotification/src/CosNotifyFilter_FilterFactory_impl.erl new file mode 100644 index 0000000000..9a7b431513 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyFilter_FilterFactory_impl.erl @@ -0,0 +1,125 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosNotifyFilter_FilterFactory_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('CosNotifyFilter_FilterFactory_impl'). + + +%%--------------- INCLUDES ----------------------------------- +%% Application files +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- IMPORTS ------------------------------------ + +%%--------------- EXPORTS ------------------------------------ +%% External +-export([create_filter/3, + create_mapping_filter/4]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {adminProp, + etsR, + options}). + +%%-----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: See gen_server documentation. +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(_Info, State) -> + ?debug_print("INFO: ~p DATA: ~p~n", [State, _Info]), + {noreply, State}. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init(Options) -> + process_flag(trap_exit, true), + {ok, #state{options = Options}}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% function : create_filter +%% Arguments: InitGrammar - string() +%% Returns : CosNotifyFilter::Filter | +%% {'EXCEPTION', InvalidGrammar} +%%----------------------------------------------------------- +create_filter(OE_THIS, State, InitGrammar) -> + case lists:member(InitGrammar, ?not_SupportedGrammars) of + true -> + SO = 'CosNotification_Common':get_option(server_options, State#state.options, + ?not_DEFAULT_SETTINGS), + Fi='CosNotifyFilter_Filter':oe_create_link([OE_THIS, self(), + InitGrammar], + SO), + {reply, Fi, State}; + _ -> + corba:raise(#'CosNotifyFilter_InvalidGrammar'{}) + end. + +%%----------------------------------------------------------% +%% function : create_mapping_filter +%% Arguments: InitGrammar - string() +%% Returns : CosNotifyFilter::Filter | +%% {'EXCEPTION', InvalidGrammar} +%%----------------------------------------------------------- +create_mapping_filter(OE_THIS, State, InitGrammar, DefVal) -> + case lists:member(InitGrammar, ?not_SupportedGrammars) of + true -> + SO = 'CosNotification_Common':get_option(server_options, State#state.options, + ?not_DEFAULT_SETTINGS), + Fi='CosNotifyFilter_MappingFilter':oe_create_link([OE_THIS, self(), + InitGrammar, DefVal], + SO), + {reply, Fi, State}; + _ -> + corba:raise(#'CosNotifyFilter_InvalidGrammar'{}) + end. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/CosNotifyFilter_Filter_impl.erl b/lib/cosNotification/src/CosNotifyFilter_Filter_impl.erl new file mode 100644 index 0000000000..042e180170 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyFilter_Filter_impl.erl @@ -0,0 +1,670 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosNotifyFilter_Filter_impl.erl +%% Purpose : +%% Note : For an event to be forwarded it's sufficient that at least +%% one of the constraints return 'true'. +%% ALL functions in this module are internal. May NOT be used +%% externally in ANY WAY; only CosNotification system modules. +%%---------------------------------------------------------------------- + +-module('CosNotifyFilter_Filter_impl'). + +%%--------------- INCLUDES ----------------------------------- +%% Application files +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- IMPORTS ------------------------------------ + +%%--------------- EXPORTS ------------------------------------ +%% External Attributes +-export(['_get_constraint_grammar'/2]). +%% External Functions +-export([add_constraints/3, + modify_constraints/4, + get_constraints/3, + get_all_constraints/2, + remove_all_constraints/2, + destroy/2, + match/3, + match_structured/3, + match_typed/3, + attach_callback/3, + detach_callback/3, + get_callbacks/2]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%%######### MISC ########## +-define(create_ConstraintInfo(_Types, _Con, _ID), + #'CosNotifyFilter_ConstraintInfo'{ + constraint_expression = + #'CosNotifyFilter_ConstraintExp'{ + event_types = _Types, + constraint_expr = _Con}, + constraint_id = _ID + }). + +%%#### Data structures #### +-record(state, {constraint_grammar, + constraints = [], + filters = [], + callbacks = [], + idCounter = 0, + filterFactory, + factoryPid, + etsR}). + +%% Data structures constructors +-define(get_InitState(Fac, Pid, Gr), + #state{constraint_grammar=Gr, + filterFactory=Fac, + factoryPid=Pid, + etsR = ets:new(oe_ets, [bag, protected])}). + +%%------------------- Data structures selectors ------------------- +%% Grammar +-define(get_Grammar(S), S#state.constraint_grammar). +%% Callbacks +% Left out for now to avoid dialyzer warning. +%-define(get_Callback(S,I), find_obj(lists:keysearch(I, 1, S#state.callbacks), +% callback)). +-define(get_AllCallback(S), lists:map(fun({_V, C}) -> C end, + S#state.callbacks)). +-define(get_AllCallbackID(S), lists:map(fun({V, _C}) -> V end, + S#state.callbacks)). +%% ID:s +-define(get_IdCounter(S), S#state.idCounter). + +%% Constraints +-define(get_Constraint(S,I), find_obj(lists:keysearch(I, 1, S#state.constraints), + constraint)). +-define(get_AllConstraints(S), lists:map(fun({I, C, _W, _WC, _K, T}) -> + ?create_ConstraintInfo(T, C, I) + end, + S#state.constraints)). +-define(get_ConstraintAllData(S), S#state.constraints). +-define(get_ConstraintData(S,I), lists:keysearch(I, 1, S#state.constraints)). +-define(match_Type(S,I,ET), ets:lookup(S#state.etsR, {I, ET})). +%% Parse Tree +-define(get_ParseTree(S,K), find_obj(ets:lookup(S#state.etsR, K), tree)). + +%%------------------- Data structures modifiers ------------------- +%% Callbacks +-define(del_Callback(S,I), S#state{callbacks = + delete_obj(lists:keydelete(I,1, + S#state.callbacks), + S#state.callbacks, callback)}). +-define(del_AllCallbacks(S), S#state{callbacks=[]}). +-define(add_Callback(S,V,C), S#state{idCounter=V, + callbacks = [{V,C}|S#state.callbacks]}). +%% ID:s +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). + +%% Constraints +-define(del_Constraint(S, I), match_delete(S, S#state.constraints, I)). +-define(del_AllConstraints(S), clear_DB(S)). +-define(add_Constraint(S,I,C,W,_WC,K,T), S#state{constraints = + [{I, C, W, _WC, K, T}|S#state.constraints]}). +-define(set_Constraints(S,C), S#state{constraints = C}). + +-define(del_AllTypes(S), ets:match_delete(S#state.etsR, {'_','_',types})). +-define(del_Type(S,I), ets:match_delete(S#state.etsR, {{I, '_'}, '_', types})). +-define(add_Type(S,I,ET,K), ets:insert(S#state.etsR, {{I, ET}, K, types})). + +%% Parse Tree +-define(add_ParseTree(S,K,T), ets:insert(S#state.etsR, {K, T, tree})). +-define(del_ParseTree(S,K), ets:delete(S#state.etsR, K)). +-define(del_AllParseTress(S), ets:match_delete(S#state.etsR, {'_','_',tree})). + +%%------------------- MISC ---------------------------------------- +-define(is_EmptyFilter(S), S#state.constraints==[]). + +-define(InfoSeq2EventTypeSeq(L), lists:flatten( + lists:map(fun(#'CosNotifyFilter_ConstraintInfo' + {constraint_expression= + #'CosNotifyFilter_ConstraintExp' + {event_types = ET}}) -> + ET + end, + L))). + +%%-----------------------------------------------------------% +%% Function : handle_info, code_change +%% Arguments: See gen_server documentation. +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + ?debug_print("INFO: ~p DATA: ~p~n", [State, Info]), + case Info of + {'EXIT', _Pid, _Reason} -> + {noreply, State}; + _ -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% Function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([FiFac, FacPid, ConstraintGr]) -> + process_flag(trap_exit, true), + {ok, ?get_InitState(FiFac, FacPid, ConstraintGr)}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%------- Exported external attributes ---------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Function : '_get_constraint_grammar'/2 +%% Type : readonly +%% Returns : Grammar - string() +%%----------------------------------------------------------- +'_get_constraint_grammar'(_OE_THIS, State) -> + {reply, ?get_Grammar(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Function : add_constraints/3 +%% Arguments: CL - CosNotifyFilter::ConstraintExpSeq +%% Returns : CosNotifyFilter::ConstraintInfoSeq | +%% {'EXCEPTION', CosNotifyFilter::InvalidConstraint} +%%----------------------------------------------------------- +add_constraints(_OE_THIS, State, CL) -> + {NewState, Filters, Info, EventTSeq} = try_create_filters(State, CL), + NewState2=store_filters(NewState, Filters), + inform_callbacks(?get_AllCallback(NewState2), EventTSeq, []), + {reply, Info, NewState2}. + +%%----------------------------------------------------------% +%% Function : modify_constraints/4 +%% Arguments: IDs - CosNotifyFilter::ConstraintIDSeq +%% AddConstraintInfoSeq - CosNotifyFilter::ConstraintInfoSeq +%% Returns : ok | +%% {'EXCEPTION', CosNotifyFilter::InvalidConstraint} | +%% {'EXCEPTION', CosNotifyFilter::ConstraintNotFound} +%%----------------------------------------------------------- +%% The OMG specification (TC Document telecom/98-11-01, chapter +%% 3.2.1.3) states (concerning IDs): +%% +%% "If all input values supplied within a particular invocation +%% of this operation are valid, then the specific constraints +%% identified by the values contained in the first input parameter +%% will be deleted from the list of those encapsulated by the target +%% filter object." +%% +%% Hence, first we must check if all ID's exists before deleting. +modify_constraints(_OE_THIS, State, IDs, AddConstraintInfoSeq) -> + %% The following functions are 'safe', i.e., they do not alter any data. + RemoveConstraintInfoSeq = lookup_constraints(IDs, State), + lookup_constraints(AddConstraintInfoSeq, State), + {NewState, Filters, _Info, AddedEventTSeq} = + try_create_filters(State, AddConstraintInfoSeq), + RemovedEventTSeq = ?InfoSeq2EventTypeSeq(RemoveConstraintInfoSeq), + + %% We cannot change anything before our checks (see above). Hence, + %% do NOT move the following lines above this point. + NewState2 = delete_constraints(IDs, NewState), + +%% The OMG specification (TC Document telecom/98-11-01, chapter +%% 3.2.1.3) states (concerning AddConstraintInfoSeq): +%% +%% "If all input values supplied within a particular invocation of this +%% operation are valid, then the constraint expression associated with the +%% already encapsulated constraint identified by the numeric value contained +%% within each element of the input sequence will be modified to the new +%% constraint expression that is contained within the same sequence element." +%% +%% This, our interpretation, implies that ALL previous data related +%% to each unique ID should be removed and replaced by the new data. + + NewState3 = delete_constraints(AddConstraintInfoSeq, NewState2), + NewState4 = store_filters(NewState3, Filters), + inform_callbacks(?get_AllCallback(NewState4), + AddedEventTSeq, RemovedEventTSeq), + {reply, ok, NewState4}. + +%%----------------------------------------------------------% +%% Function : get_constraints/3 +%% Arguments: IDs - CosNotifyFilter::ConstraintIDSeq +%% Returns : CosNotifyFilter::ConstraintInfoSeq | +%% {'EXCEPTION', CosNotifyFilter::ConstraintNotFound} +%%----------------------------------------------------------- +get_constraints(_OE_THIS, State, IDs) -> + {reply, lookup_constraints(IDs, State), State}. + +%%----------------------------------------------------------% +%% Function : get_all_constraints/2 +%% Arguments: - +%% Returns : CosNotifyFilter::ConstraintInfoSeq +%%----------------------------------------------------------- +get_all_constraints(_OE_THIS, State) -> + {reply, ?get_AllConstraints(State), State}. + +%%----------------------------------------------------------% +%% Function : remove_all_constraints/2 +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_constraints(_OE_THIS, State) -> + {reply, ok, ?del_AllConstraints(State)}. + +%%----------------------------------------------------------% +%% Function : destroy/2 +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +destroy(_OE_THIS, State) -> + {stop, normal, ok, State}. + +%%----------------------------------------------------------% +%% Function : match/3 +%% Arguments: Event - #any{} +%% Returns : boolean() | +%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData} +%%----------------------------------------------------------- + +match(_OE_THIS, State, Event) when is_record(Event,'any'), ?is_EmptyFilter(State) -> + {reply, true, State}; +match(_OE_THIS, State, Event) when is_record(Event,'any') -> + match_any_event(State, Event, ?get_ConstraintAllData(State)); +match(_,_,What) -> + orber:dbg("[~p] CosNotifyFilter_Filter:match(~p);~n" + "Not an CORBA::Any", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% Function : match_structured/3 +%% Arguments: Event - CosNotification::StructuredEvent +%% Returns : boolean() | +%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData} +%%----------------------------------------------------------- +match_structured(_OE_THIS, State, Event) when + is_record(Event,'CosNotification_StructuredEvent') andalso ?is_EmptyFilter(State) -> + {reply, true, State}; +match_structured(_OE_THIS, State, Event) when + is_record(Event,'CosNotification_StructuredEvent') -> + match_str_event(State, Event, ?get_ConstraintAllData(State)); +match_structured(_,_,What) -> + orber:dbg("[~p] CosNotifyFilter_Filter:match_structured(~p);~n" + "Not a StructuredEvent", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------* +%% Function : match_typed/3 +%% Arguments: Data - CosNotification::PropertySeq +%% Returns : boolean() | +%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData} +%%----------------------------------------------------------- +match_typed(_OE_THIS, _State, _Data) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% Function : attach_callback/3 +%% Arguments: CB - CosNotifyComm::NotifySubscribe +%% Returns : ID - CosNotifyFilter::CallbackID +%%----------------------------------------------------------- +attach_callback(_OE_THIS, State, CB) -> + 'CosNotification_Common':type_check(CB, 'CosNotifyComm_NotifySubscribe'), + CBID = ?new_Id(State), + {reply, CBID, ?add_Callback(State, CBID, CB)}. + +%%----------------------------------------------------------% +%% Function : detach_callback/3 +%% Arguments: ID - CosNotifyFilter::CallbackID +%% Returns : ok | {'EXCEPTION', CosNotifyFilter::CallbackNotFound} +%%----------------------------------------------------------- +detach_callback(_OE_THIS, State, ID) when is_integer(ID) -> + {reply, ok, ?del_Callback(State, ID)}; +detach_callback(_,_,What) -> + orber:dbg("[~p] CosNotifyFilter_Filter:detach_callback(~p);~n" + "Not an integer", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% Function : get_callbacks/2 +%% Arguments: - +%% Returns : CosNotifyFilter::CallbackIDSeq +%%----------------------------------------------------------- +get_callbacks(_OE_THIS, State) -> + {reply, ?get_AllCallbackID(State), State}. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +%% To match callbacks +find_obj({value, {_, Obj}},_) -> Obj; +%% To match constraints +find_obj({value, {Id, Con, _, _, _, Types}}, _) -> + ?create_ConstraintInfo(Types, Con, Id); +find_obj([{_, Tree, tree}|_], tree) -> Tree; +% Left out for now to avoid dialyzer warning. +%find_obj(_,callback) -> {'EXCEPTION', #'CosNotifyFilter_CallbackNotFound'{}}; +find_obj(_,tree) -> undefined; +find_obj(_,constraint) -> error. + +%% Delete a single object. +delete_obj(List,List,callback) -> corba:raise(#'CosNotifyFilter_CallbackNotFound'{}); +delete_obj(List,_,_) -> List. + +%% Delete given object from list and all related objects in DB (parse tree and types). +match_delete(State, Constraints, ID) -> + match_delete(State, Constraints, ID, []). +match_delete(_, [], _, _) -> + error; +match_delete(State, [{ID, _Con, _Which, _WC, Key, _Types}|T], ID, Acc) -> + ?del_Type(State, ID), + ?del_ParseTree(State, Key), + {ok, ?set_Constraints(State, Acc++T)}; +match_delete(State, [H|T], ID, Acc) -> + match_delete(State, T, ID, [H|Acc]). + +%% Remove all data related with constraints; for now, since no other data +%% stored in DB, we do in a rather brutal way. +clear_DB(State) -> + catch ets:delete(State#state.etsR), + State#state{etsR = ets:new(oe_ets, [bag, protected]), constraints=[]}. + +%% Given a list of Constrain IDs we want to find the related constraints. +%% !!!!!! This function may not alter any data in DB in any way !!!!!!!!!! +lookup_constraints(IDs, State) -> + lookup_constraints(IDs, State, []). +lookup_constraints([], _State, Accum) -> + Accum; +lookup_constraints([H|T], State, Accum) + when is_record(H, 'CosNotifyFilter_ConstraintInfo') -> + case ?get_Constraint(State, H#'CosNotifyFilter_ConstraintInfo'.constraint_id) of + error -> + corba:raise(#'CosNotifyFilter_ConstraintNotFound' + {id = H#'CosNotifyFilter_ConstraintInfo'.constraint_id}); + _Con -> + %% We don't need to collect the result since the input already is of + %% the correct type, i.e., ConstraintInfoSeq + lookup_constraints(T, State, Accum) + end; +lookup_constraints([H|T], State, Accum) when is_integer(H) -> + case ?get_Constraint(State,H) of + error -> + corba:raise(#'CosNotifyFilter_ConstraintNotFound'{id=H}); + Con -> + lookup_constraints(T, State, [Con|Accum]) + end; +lookup_constraints(_, _, _) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%% Given a list of Constrain IDs we want to delet the related constraints. +%% We need also to return the ConstraintInfoSeq described related to the +%% given ID's. +delete_constraints([], State) -> + State; +delete_constraints([H|T], State) + when is_record(H, 'CosNotifyFilter_ConstraintInfo') -> + case catch ?del_Constraint(State, + H#'CosNotifyFilter_ConstraintInfo'.constraint_id) of + {ok, NewState} -> + delete_constraints(T, NewState); + Reason -> + orber:dbg("[~p] 'CosNotifyFilter_Filter':modify_constraints().~n" + "Unable to remove: ~p~n" + "Reason: ~p~n", + [?LINE, H, Reason], ?DEBUG_LEVEL), + delete_constraints(T, State) + end; +delete_constraints([H|T], State) -> + case catch ?del_Constraint(State,H) of + {ok, NewState} -> + delete_constraints(T, NewState); + Reason -> + orber:dbg("[~p] 'CosNotifyFilter_Filter':modify_constraints().~n" + "Unable to remove: ~p~n" + "Reason: ~p~n", + [?LINE, H, Reason], ?DEBUG_LEVEL), + delete_constraints(T, State) + end. + +%% Inform all registered callbacks that the constraints have changed. +%% Added and Removed must be a CosNotification::EventTypeSeq +inform_callbacks([],_,_) -> + ok; +inform_callbacks([H|T], Added, Removed) -> + case catch 'CosNotifyComm_NotifySubscribe':subscription_change(H, Added, Removed) of + ok -> + ?debug_print("INFORMED CALLBACK: ~p ADDED: ~p REMOVED: ~p", + [H, Added, Removed]), + inform_callbacks(T, Added, Removed); + Other -> + orber:dbg("[~p] 'CosNotifyComm_NotifySubscribe':subscription_change().~n" + "Unable to inform callback: ~p~n" + "Reason: ~p~n", + [?LINE, H, Other], ?DEBUG_LEVEL), + inform_callbacks(T, Added, Removed) + end. + +%%----------------------------------------------------------- +%% Function : try_create_filters/2 +%% Arguments: CL - #'CosNotifyFilter_ConstraintExp'{ +%% event_types = [#'CosNotification_EventType'{ +%% domain_name = Str, type_name = Str}] +%% constraint_expr = Str} +%% Returns : {State, AccumList} +%%----------------------------------------------------------- +%% !!!!!! This function may not alter any data in DB in any way !!!!!!!!!! +try_create_filters(State, CL) -> + try_create_filters(State, CL, [], [], []). +try_create_filters(State, [], Accum, InfoSeq, EventTSeq) -> + {State, Accum, InfoSeq, EventTSeq}; +try_create_filters(State, [#'CosNotifyFilter_ConstraintExp'{event_types = Types, + constraint_expr = Con}|T], + Accum, InfoSeq, EventTSeq) -> + case catch cosNotification_Filter:create_filter(Con) of + {ok, Tree} -> + case catch cosNotification_Filter:check_types(Types) of + true -> + ID = ?new_Id(State), + Key = ?not_CreateDBKey, + NewETSeq = Types ++ EventTSeq, + try_create_filters(?set_IdCounter(State, ID), T, + [{ID, true, [], Key, Types, Con, Tree}|Accum], + [?create_ConstraintInfo(Types, Con, ID)|InfoSeq], + NewETSeq); + {ok, Which, WC} -> + ID = ?new_Id(State), + Key = ?not_CreateDBKey, + NewETSeq = Types ++ EventTSeq, + try_create_filters(?set_IdCounter(State, ID), T, + [{ID, Which, WC, Key, Types, Con, Tree}|Accum], + [?create_ConstraintInfo(Types, Con, ID)|InfoSeq], + NewETSeq); + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; + _ -> + corba:raise(#'CosNotifyFilter_InvalidConstraint' + {constr = #'CosNotifyFilter_ConstraintExp' + {event_types = Types, constraint_expr = Con}}) + end; +try_create_filters(State, [#'CosNotifyFilter_ConstraintInfo' + {constraint_expression = #'CosNotifyFilter_ConstraintExp' + {event_types = Types, constraint_expr = Con}, + constraint_id=ID}|T], Accum, InfoSeq, EventTSeq) -> + case catch cosNotification_Filter:create_filter(Con) of + {ok, Tree} -> + case catch cosNotification_Filter:check_types(Types) of + true -> + Key = ?not_CreateDBKey, + NewETSeq = Types ++ EventTSeq, + try_create_filters(State, T, + [{ID, true, [], Key, Types, Con, Tree}|Accum], + [?create_ConstraintInfo(Types, Con, ID)|InfoSeq], + NewETSeq); + {ok, Which, WC} -> + Key = ?not_CreateDBKey, + NewETSeq = Types ++ EventTSeq, + try_create_filters(State, T, + [{ID, Which, WC, Key, Types, Con, Tree}|Accum], + [?create_ConstraintInfo(Types, Con, ID)|InfoSeq], + NewETSeq); + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; + _ -> + corba:raise(#'CosNotifyFilter_InvalidConstraint' + {constr = #'CosNotifyFilter_ConstraintExp' + {event_types = Types, constraint_expr = Con}}) + end; +try_create_filters(_,_,_,_,_) -> + %% The list contained something else but ConstraintExp. + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------- +%% Function : store_filters/4 +%% Arguments: Filters - a list of filters. +%% Returns : +%%----------------------------------------------------------- + +store_filters(State, []) -> + State; +store_filters(State, [{ID, Which, WC, Key, Types, Con, Tree}|T]) -> + ?add_ParseTree(State, Key, Tree), + write_types(State, Types, ID, Key), + store_filters(?add_Constraint(State, ID, Con, Which, WC, Key, Types), T). + + +write_types(_State, [],_, _) -> + ok; +write_types(State, [EventType|T], ID, Key) -> + ?add_Type(State, ID, EventType, Key), + ?debug_print("FILTER: ~p ~p ~p~n", [ID, Key, EventType]), + write_types(State, T, ID, Key). + +%%----------------------------------------------------------- +%% Function : match_any_event +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +match_any_event(State, _Event, []) -> + ?debug_print("FILTER REJECTED: ~p~n", [_Event]), + {reply, false, State}; +match_any_event(State, Event, [{_, _, _, _, Key, _}|T]) -> + case catch cosNotification_Filter:eval(?get_ParseTree(State,Key), Event) of + true -> + ?debug_print("FILTER APPROVED (WC): ~p~n", [Event]), + {reply, true, State}; + _ -> + match_any_event(State, Event, T) + end. + + +%%----------------------------------------------------------- +%% Function : match_str_event +%% Arguments: +%% Returns : +%%----------------------------------------------------------- + +match_str_event(State, _Event, []) -> + ?debug_print("FILTER REJECTED: ~p~n", [_Event]), + {reply, false, State}; +match_str_event(State, Event, [{ID, _Con, Which, WC, Key, _Types}|T]) -> + ET = ((Event#'CosNotification_StructuredEvent'.header) + #'CosNotification_EventHeader'.fixed_header) + #'CosNotification_FixedEventHeader'.event_type, + CheckList = + case Which of + both -> + [ET]; + domain -> + [ET, + ET#'CosNotification_EventType'{type_name=""}, + ET#'CosNotification_EventType'{type_name="*"}]; + type -> + [ET, + ET#'CosNotification_EventType'{domain_name=""}, + ET#'CosNotification_EventType'{domain_name="*"}]; + _ -> + [ET, + ET#'CosNotification_EventType'{type_name=""}, + ET#'CosNotification_EventType'{type_name="*"}, + ET#'CosNotification_EventType'{domain_name=""}, + ET#'CosNotification_EventType'{domain_name="*"}] + end, + case check_DB(State, ID, CheckList) of + false -> + %% No match, may have used wildcards, e.g., "dom*". + case catch cosNotification_Filter:match_types( + ET#'CosNotification_EventType'.domain_name, + ET#'CosNotification_EventType'.type_name, + WC) of + true -> + case catch cosNotification_Filter:eval(?get_ParseTree(State,Key), + Event) of + true -> + ?debug_print("FILTER APPROVED (WC): ~p~n", [Event]), + {reply, true, State}; + _ -> + match_str_event(State, Event, T) + end; + _-> + match_str_event(State, Event, T) + end; + Key -> + case catch cosNotification_Filter:eval(?get_ParseTree(State,Key), + Event) of + true -> + ?debug_print("FILTER APPROVED: ~p~n", [Event]), + {reply, true, State}; + _ -> + match_str_event(State, Event, T) + end + end. + +check_DB(_, _, []) -> + false; +check_DB(State, ID, [H|T]) -> + case ?match_Type(State, ID, H) of + [] -> + check_DB(State, ID, T); + [{_, K, types}|_] -> + K + end. + + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ + diff --git a/lib/cosNotification/src/CosNotifyFilter_MappingFilter_impl.erl b/lib/cosNotification/src/CosNotifyFilter_MappingFilter_impl.erl new file mode 100644 index 0000000000..f9103001f1 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyFilter_MappingFilter_impl.erl @@ -0,0 +1,578 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosNotifyFilter_MappingFilter_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('CosNotifyFilter_MappingFilter_impl'). + +%%--------------- INCLUDES ----------------------------------- +%% Application files +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- IMPORTS ------------------------------------ + +%%--------------- EXPORTS ------------------------------------ +%% External Attributes +-export(['_get_constraint_grammar'/2, + '_get_value_type'/2, + '_get_default_value'/2]). +%% External Functions +-export([add_mapping_constraints/3, + modify_mapping_constraints/4, + get_mapping_constraints/3, + get_all_mapping_constraints/2, + remove_all_mapping_constraints/2, + destroy/2, + match/3, + match_structured/3, + match_typed/3]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%%######### MISC ########## +-define(create_MappingInfo(_Types, _Con, _ID, _A), + #'CosNotifyFilter_MappingConstraintInfo'{ + constraint_expression = + #'CosNotifyFilter_ConstraintExp'{ + event_types = _Types, + constraint_expr = _Con}, + constraint_id = _ID, + value = _A + }). +%%#### Data structures #### +-record(state, {constraint_grammar, + value, + typeC, + constraints = [], + filters = [], + idCounter = 0, + filterFactory, + factoryPid, + etsR}). + +%% Data structures constructors +-define(get_InitState(Gr, DVal, FF, FP), + #state{constraint_grammar=Gr, + value = DVal, + typeC = any:get_typecode(DVal), + filterFactory = FF, + factoryPid = FP, + etsR = ets:new(oe_ets, [bag, protected])}). + +%%------------------- Data structures selectors ------------------- +%% Attributes +-define(get_Grammar(S), S#state.constraint_grammar). +-define(get_DefVal(S), S#state.value). +-define(get_DefTC(S), S#state.typeC). +-define(get_DefAny(S), S#state.value). + +%% ID:s +-define(get_IdCounter(S), S#state.idCounter). + +%% Constraints +-define(get_Constraint(S,I), find_obj(lists:keysearch(I, 1, S#state.constraints), + constraint)). +-define(get_AllConstraints(S), lists:map(fun({I, C, _W, _WC, _K, T, A}) -> + ?create_MappingInfo(T, C, I, A) + end, + S#state.constraints)). +-define(get_ConstraintAllData(S), S#state.constraints). +-define(get_ConstraintData(S,I), lists:keysearch(I, 1, S#state.constraints)). +-define(match_Type(S,I,ET), ets:lookup(S#state.etsR, {I, ET})). +%% Parse Tree +-define(get_ParseTree(S,K), find_obj(ets:lookup(S#state.etsR, K), tree)). + +%%------------------- Data structures modifiers ------------------- +%% ID:s +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). + +%% Constraints +-define(del_Constraint(S, I), match_delete(S, S#state.constraints, I)). +-define(del_AllConstraints(S), clear_DB(S)). +-define(add_Constraint(S,I,C,W,_WC,K,T,A), S#state{constraints = + [{I, C, W, _WC, K, T, A}|S#state.constraints]}). +-define(set_Constraints(S,C), S#state{constraints = C}). + +-define(del_AllTypes(S), ets:match_delete(S#state.etsR, {'_','_',types})). +-define(del_Type(S,I), ets:match_delete(S#state.etsR, {{I, '_'}, '_', types})). +-define(add_Type(S,I,ET,K), ets:insert(S#state.etsR, {{I, ET}, K, types})). + +%% Parse Tree +-define(add_ParseTree(S,K,T), ets:insert(S#state.etsR, {K, T, tree})). +-define(del_ParseTree(S,K), ets:delete(S#state.etsR, K)). +-define(del_AllParseTress(S), ets:match_delete(S#state.etsR, {'_','_',tree})). + +%%------------------- MISC ---------------------------------------- +-define(is_EmptyFilter(S), S#state.constraints==[]). +-define(is_EqualType(S,T), S#state.typeC==any:get_typecode(T)). + +%%-----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: See gen_server documentation. +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + ?debug_print("INFO: ~p DATA: ~p~n", [State, Info]), + case Info of + {'EXIT', _Pid, _Reason} -> + {noreply, State}; + _ -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([FiFac, FacPid, InitGr, DefVal]) -> + process_flag(trap_exit, true), + {ok, ?get_InitState(InitGr, DefVal, FiFac, FacPid)}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%------- Exported external attributes ---------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Function : '_get_constraint_grammar'/2 +%% Type : readonly +%% Returns : string() +%%----------------------------------------------------------- +'_get_constraint_grammar'(_OE_THIS, State) -> + {reply, ?get_Grammar(State), State}. +%%----------------------------------------------------------% +%% Function : '_get_value_type'/2 +%% Type : readonly +%% Returns : CORBA::TypeCode +%%----------------------------------------------------------- +'_get_value_type'(_OE_THIS, State) -> + {reply, ?get_DefTC(State), State}. +%%----------------------------------------------------------% +%% Function : '_get_default_value'/2 +%% Type : readonly +%% Returns : #any{} +%%----------------------------------------------------------- +'_get_default_value'(_OE_THIS, State) -> + {reply, ?get_DefVal(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Function : add_mapping_constraints/3 +%% Arguments: Pairs - CosNotifyFilter::MappingConstraintPairSeq +%% Returns : CosNotifyFilter::MappingConstraintInfoSeq | +%% {'EXCEPTION', CosNotifyFilter::InvalidConstraint} | +%% {'EXCEPTION', CosNotifyFilter::InvalidValue} +%%----------------------------------------------------------- +add_mapping_constraints(_OE_THIS, State, Pairs) -> + {NewState, Filters, Info} = try_create_filters(State, Pairs), + NewState2=store_filters(NewState, Filters), + {reply, Info, NewState2}. + +%%----------------------------------------------------------% +%% Function : modify_mapping_constraints/4 +%% Arguments: IDs - CosNotifyFilter::ConstraintIDSeq +%% Info - CosNotifyFilter::MappingConstraintInfoSeq +%% Returns : ok | +%% {'EXCEPTION', CosNotifyFilter::InvalidConstraint} | +%% {'EXCEPTION', CosNotifyFilter::InvalidValue} | +%% {'EXCEPTION', CosNotifyFilter::ConstraintNotFound} +%%----------------------------------------------------------- +modify_mapping_constraints(_OE_THIS, State, IDs, InfoSeq) -> + lookup_constraints(IDs, State), + lookup_constraints(InfoSeq, State), + {NewState, Filters, _Info} = try_create_filters(State, InfoSeq), + + %% We cannot change anything before our checks (see above). Hence, + %% do NOT move the following lines above this point. + + NewState2 = delete_constraints(IDs, NewState), + NewState3 = delete_constraints(InfoSeq, NewState2), + NewState4 = store_filters(NewState3, Filters), + {reply, ok, NewState4}. + +%%----------------------------------------------------------% +%% Function : get_mapping_constraints/3 +%% Arguments: IDs - CosNotifyFilter::ConstraintIDSeq +%% Returns : CosNotifyFilter::MappingConstraintInfoSeq | +%% {'EXCEPTION', CosNotifyFilter::ConstraintNotFound} +%%----------------------------------------------------------- +get_mapping_constraints(_OE_THIS, State, IDs) -> + {reply, lookup_constraints(IDs, State), State}. + +%%----------------------------------------------------------% +%% Function : get_all_mapping_constraints/2 +%% Arguments: - +%% Returns : CosNotifyFilter::MappingConstraintInfoSeq +%%----------------------------------------------------------- +get_all_mapping_constraints(_OE_THIS, State) -> + {reply, ?get_AllConstraints(State), State}. + +%%----------------------------------------------------------% +%% Function : remove_all_mapping_constraints/2 +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_mapping_constraints(_OE_THIS, State) -> + {reply, ok, ?del_AllConstraints(State)}. + +%%----------------------------------------------------------% +%% Function : destroy/2 +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +destroy(_OE_THIS, State) -> + {stop, normal, ok, State}. + +%%----------------------------------------------------------% +%% Function : match/3 +%% Arguments: Event - #any{} +%% Returns : boolean(), #any{} (out-type) | +%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData} +%%----------------------------------------------------------- +match(_OE_THIS, State, Event) when is_record(Event,'any') andalso ?is_EmptyFilter(State) -> + {reply, {false, ?get_DefAny(State)}, State}; +match(_OE_THIS, State, Event) when is_record(Event,'any') -> + match_any_event(State, Event, ?get_ConstraintAllData(State)); +match(_,_,_) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + + +%%----------------------------------------------------------% +%% Function : match_structured/3 +%% Arguments: Event - CosNotification::StructuredEvent +%% Returns : boolean(), #any{} (out-type) | +%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData} +%%----------------------------------------------------------- +match_structured(_OE_THIS, State, Event) when + is_record(Event,'CosNotification_StructuredEvent') andalso ?is_EmptyFilter(State) -> + {reply, {false, ?get_DefAny(State)}, State}; +match_structured(_OE_THIS, State, Event) when + is_record(Event,'CosNotification_StructuredEvent') -> + match_str_event(State, Event, ?get_ConstraintAllData(State)); +match_structured(_,_,_) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------* +%% Function : match_typed/3 +%% Arguments: Data - CosNotification::PropertySeq +%% Returns : boolean() , #any{} (out-type) | +%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData} +%%----------------------------------------------------------- +match_typed(_OE_THIS, _State, _Data) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}). + +%%--------------- LOCAL FUNCTIONS ---------------------------- +%% To match constraints +find_obj({value, {Id, Con, _, _, _, Types, Any}}, _) -> + ?create_MappingInfo(Types, Con, Id, Any); +find_obj([{_, Tree, tree}|_], tree) -> Tree; +find_obj(_,tree) -> undefined; +find_obj(_,constraint) -> error. + +%% Delete given object from list and all related objects in DB (parse tree and types). +match_delete(State, Constraints, ID) -> + match_delete(State, Constraints, ID, []). +match_delete(_, [], _, _) -> + error; +match_delete(State, [{ID, _Con, _Which, _WC, Key, _Types, _Any}|T], ID, Acc) -> + ?del_Type(State, ID), + ?del_ParseTree(State, Key), + {ok, ?set_Constraints(State, Acc++T)}; +match_delete(State, [H|T], ID, Acc) -> + match_delete(State, T, ID, [H|Acc]). + +%% Remove all data related with constraints; for now, since no other data +%% stored in DB, we do in a rather brutal way. +clear_DB(State) -> + catch ets:delete(State#state.etsR), + State#state{etsR = ets:new(oe_ets, [bag, protected]), constraints=[]}. + +%% Given a list of Constrain IDs we want to find the related constraints. +%% !!!!!! This function may not alter any data in DB in any way !!!!!!!!!! +lookup_constraints(IDs, State) -> + lookup_constraints(IDs, State, []). +lookup_constraints([], _State, Accum) -> + Accum; +lookup_constraints([H|T], State, Accum) + when is_record(H, 'CosNotifyFilter_MappingConstraintInfo') -> + case ?get_Constraint(State, H#'CosNotifyFilter_MappingConstraintInfo'.constraint_id) of + error -> + corba:raise(#'CosNotifyFilter_ConstraintNotFound' + {id = H#'CosNotifyFilter_MappingConstraintInfo'.constraint_id}); + _Con -> + %% We don't need to collect the result since the input already is of + %% the correct type, i.e., ConstraintInfoSeq + lookup_constraints(T, State, Accum) + end; +lookup_constraints([H|T], State, Accum) when is_integer(H) -> + case ?get_Constraint(State,H) of + error -> + corba:raise(#'CosNotifyFilter_ConstraintNotFound'{id=H}); + Con -> + lookup_constraints(T, State, [Con|Accum]) + end; +lookup_constraints(_, _, _) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%% Given a list of Constrain IDs we want to delet the related constraints. +%% We need also to return the ConstraintInfoSeq described related to the +%% given ID's. +delete_constraints([], State) -> + State; +delete_constraints([H|T], State) + when is_record(H, 'CosNotifyFilter_MappingConstraintInfo') -> + case catch ?del_Constraint(State, + H#'CosNotifyFilter_MappingConstraintInfo'.constraint_id) of + {ok, NewState} -> + delete_constraints(T, NewState); + Reason -> + orber:dbg("[~p] 'CosNotifyFilter_MappingFilter':modify_mapping_constraints().~n" + "Unable to remove: ~p~n" + "Reason: ~p~n", + [?LINE, H, Reason], ?DEBUG_LEVEL), + delete_constraints(T, State) + end; +delete_constraints([H|T], State) -> + case catch ?del_Constraint(State,H) of + {ok, NewState} -> + delete_constraints(T, NewState); + Reason -> + orber:dbg("[~p] 'CosNotifyFilter_MappingFilter':modify_mapping_constraints().~n" + "Unable to remove: ~p~n" + "Reason: ~p~n", + [?LINE, H, Reason], ?DEBUG_LEVEL), + delete_constraints(T, State) + end. + +%%----------------------------------------------------------- +%% Function : try_create_filters/2 +%% Arguments: CL - #'CosNotifyFilter_MappingConstraintPair{ +%% constraint_expression = +%% #'CosNotifyFilter_ConstraintExp'{ +%% event_types = +%% [#'CosNotification_EventType'{ +%% domain_name = Str, type_name = Str}] +%% constraint_expr = Str}, +%% result_to_set = Any} +%% Returns : {State, AccumList} +%%----------------------------------------------------------- +%% !!!!!! This function may not alter any data in DB in any way !!!!!!!!!! +try_create_filters(State, CL) -> + try_create_filters(State, CL, [], []). +try_create_filters(State, [], Accum, InfoSeq) -> + {State, Accum, InfoSeq}; +try_create_filters(State, [#'CosNotifyFilter_MappingConstraintPair' + {constraint_expression = + #'CosNotifyFilter_ConstraintExp'{event_types = Types, + constraint_expr = Con}, + result_to_set=Any}|T], Accum, InfoSeq) -> + case catch {?is_EqualType(State,Any), cosNotification_Filter:create_filter(Con)} of + {false, _} -> + corba:raise(#'CosNotifyFilter_InvalidValue' + {constr = #'CosNotifyFilter_ConstraintExp' + {event_types = Types, constraint_expr = Con}, + value=Any}); + {_, {ok, Tree}} -> + case catch cosNotification_Filter:check_types(Types) of + true -> + ID = ?new_Id(State), + Key = ?not_CreateDBKey, + try_create_filters(?set_IdCounter(State, ID), T, + [{ID, true, [], Key, Types, Con, Tree, Any}|Accum], + [?create_MappingInfo(Types, Con, ID, Any)|InfoSeq]); + {ok, Which, WC} -> + ID = ?new_Id(State), + Key = ?not_CreateDBKey, + try_create_filters(?set_IdCounter(State, ID), T, + [{ID, Which, WC, Key, Types, Con, Tree, Any}|Accum], + [?create_MappingInfo(Types, Con, ID, Any)|InfoSeq]); + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; + _ -> + corba:raise(#'CosNotifyFilter_InvalidConstraint' + {constr = #'CosNotifyFilter_ConstraintExp' + {event_types = Types, constraint_expr = Con}}) + end; +try_create_filters(State, [#'CosNotifyFilter_MappingConstraintInfo' + {constraint_expression = #'CosNotifyFilter_ConstraintExp' + {event_types = Types, constraint_expr = Con}, + constraint_id=ID, + value=Any}|T], Accum, InfoSeq) -> + case catch cosNotification_Filter:create_filter(Con) of + {ok, Tree} -> + case catch cosNotification_Filter:check_types(Types) of + true -> + Key = ?not_CreateDBKey, + try_create_filters(State, T, + [{ID, true, [], Key, Types, Con, Tree, Any}|Accum], + [?create_MappingInfo(Types, Con, ID, Any)|InfoSeq]); + {ok, Which, WC} -> + Key = ?not_CreateDBKey, + try_create_filters(State, T, + [{ID, Which, WC, Key, Types, Con, Tree, Any}|Accum], + [?create_MappingInfo(Types, Con, ID, Any)|InfoSeq]); + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; + _ -> + corba:raise(#'CosNotifyFilter_InvalidConstraint' + {constr = #'CosNotifyFilter_ConstraintExp' + {event_types = Types, constraint_expr = Con}}) + end; +try_create_filters(_,_,_,_) -> + %% The list contained something else but ConstraintExp. + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------- +%% Function : store_filters/4 +%% Arguments: Filters - a list of filters. +%% Returns : +%%----------------------------------------------------------- + +store_filters(State, []) -> + State; +store_filters(State, [{ID, Which, WC, Key, Types, Con, Tree, Any}|T]) -> + ?add_ParseTree(State, Key, Tree), + write_types(State, Types, ID, Key), + store_filters(?add_Constraint(State, ID, Con, Which, WC, Key, Types, Any), T). + + +write_types(_State, [],_, _) -> + ok; +write_types(State, [EventType|T], ID, Key) -> + ?add_Type(State, ID, EventType, Key), + ?debug_print("FILTER: ~p ~p ~p~n", [ID, Key, EventType]), + write_types(State, T, ID, Key). + +%%----------------------------------------------------------- +%% Function : match_any_event +%% Arguments: Event - #any{} +%% Returns : +%%----------------------------------------------------------- +match_any_event(State, _Event, []) -> + ?debug_print("FILTER REJECTED: ~p~n", [_Event]), + {reply, {false, ?get_DefAny(State)}, State}; +match_any_event(State, Event, [{_, _, _, _, Key, Any}|T]) -> + case catch cosNotification_Filter:eval(?get_ParseTree(State,Key), Event) of + true -> + ?debug_print("FILTER APPROVED (WC): ~p~n", [Event]), + {reply, {true, Any}, State}; + _ -> + match_any_event(State, Event, T) + end. + + +%%----------------------------------------------------------- +%% Function : match_str_event +%% Arguments: +%% Returns : +%%----------------------------------------------------------- + +match_str_event(State, _Event, []) -> + ?debug_print("FILTER REJECTED: ~p~n", [_Event]), + {reply, {false, ?get_DefAny(State)}, State}; +match_str_event(State, Event, [{ID, _Con, Which, WC, Key, _Types, Any}|T]) -> + ET = ((Event#'CosNotification_StructuredEvent'.header) + #'CosNotification_EventHeader'.fixed_header) + #'CosNotification_FixedEventHeader'.event_type, + CheckList = + case Which of + both -> + [ET]; + domain -> + [ET, + ET#'CosNotification_EventType'{type_name=""}, + ET#'CosNotification_EventType'{type_name="*"}]; + type -> + [ET, + ET#'CosNotification_EventType'{domain_name=""}, + ET#'CosNotification_EventType'{domain_name="*"}]; + _ -> + [ET, + ET#'CosNotification_EventType'{type_name=""}, + ET#'CosNotification_EventType'{type_name="*"}, + ET#'CosNotification_EventType'{domain_name=""}, + ET#'CosNotification_EventType'{domain_name="*"}] + end, + case check_DB(State, ID, CheckList) of + false -> + %% No match, may have used wildcards, e.g., "dom*". + case catch cosNotification_Filter:match_types( + ET#'CosNotification_EventType'.domain_name, + ET#'CosNotification_EventType'.type_name, + WC) of + true -> + case catch cosNotification_Filter:eval(?get_ParseTree(State,Key), + Event) of + true -> + ?debug_print("FILTER APPROVED (WC): ~p~n", [Event]), + {reply, {true, Any}, State}; + _ -> + match_str_event(State, Event, T) + end; + _-> + match_str_event(State, Event, T) + end; + Key -> + case catch cosNotification_Filter:eval(?get_ParseTree(State,Key), + Event) of + true -> + ?debug_print("FILTER APPROVED: ~p~n", [Event]), + {reply, {true, Any}, State}; + _ -> + match_str_event(State, Event, T) + end + end. + +check_DB(_, _, []) -> + false; +check_DB(State, ID, [H|T]) -> + case ?match_Type(State, ID, H) of + [] -> + check_DB(State, ID, T); + [{_, K, types}|_] -> + K + end. +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ + diff --git a/lib/cosNotification/src/CosTypedEvent.idl b/lib/cosNotification/src/CosTypedEvent.idl new file mode 100644 index 0000000000..d77c37731a --- /dev/null +++ b/lib/cosNotification/src/CosTypedEvent.idl @@ -0,0 +1,57 @@ +#ifndef _COS_TYPED_EVENT_IDL_ +#define _COS_TYPED_EVENT_IDL_ + +#pragma prefix "omg.org" + +#include<CosEvent.idl> + +module CosTypedEventComm { + + interface TypedPushConsumer : CosEventComm::PushConsumer { + Object get_typed_consumer(); + }; + + interface TypedPullSupplier : CosEventComm::PullSupplier { + Object get_typed_supplier(); + }; +}; + +module CosTypedEventChannelAdmin { + + exception InterfaceNotSupported {}; + exception NoSuchImplementation {}; + typedef string Key; + + + interface TypedProxyPushConsumer : + CosEventChannelAdmin::ProxyPushConsumer, + CosTypedEventComm::TypedPushConsumer { }; + + interface TypedProxyPullSupplier : + CosEventChannelAdmin::ProxyPullSupplier, + CosTypedEventComm::TypedPullSupplier { }; + + interface TypedSupplierAdmin : + CosEventChannelAdmin::SupplierAdmin { + TypedProxyPushConsumer obtain_typed_push_consumer(in Key supported_interface) + raises(InterfaceNotSupported); + CosEventChannelAdmin::ProxyPullConsumer obtain_typed_pull_consumer (in Key uses_interface) + raises(NoSuchImplementation); + }; + + interface TypedConsumerAdmin : + CosEventChannelAdmin::ConsumerAdmin { + TypedProxyPullSupplier obtain_typed_pull_supplier(in Key supported_interface) + raises (InterfaceNotSupported); + CosEventChannelAdmin::ProxyPushSupplier obtain_typed_push_supplier(in Key uses_interface) + raises(NoSuchImplementation); + }; + + interface TypedEventChannel { + TypedConsumerAdmin for_consumers(); + TypedSupplierAdmin for_suppliers(); + void destroy (); + }; +}; + +#endif /* ifndef _COS_TYPED_EVENT_IDL_ */ diff --git a/lib/cosNotification/src/CosTypedNotification.idl b/lib/cosNotification/src/CosTypedNotification.idl new file mode 100644 index 0000000000..882cde16e0 --- /dev/null +++ b/lib/cosNotification/src/CosTypedNotification.idl @@ -0,0 +1,109 @@ +#ifndef _COS_TYPED_NOTIFICATION_IDL_ +#define _COS_TYPED_NOTIFICATION_IDL_ + +#pragma prefix "omg.org" + +#include<CosNotifyChannelAdmin.idl> +#include<CosTypedEvent.idl> +#include<CosNotification.idl> + +module CosTypedNotifyComm { + interface TypedPushConsumer : CosTypedEventComm::TypedPushConsumer, CosNotifyComm::NotifyPublish { }; // TypedPushConsumer + + interface TypedPullSupplier : CosTypedEventComm::TypedPullSupplier, CosNotifyComm::NotifySubscribe { }; // TypedPullSupplier +}; // CosTypedNotifyComm + + +module CosTypedNotifyChannelAdmin { + // Forward declaration + interface TypedEventChannelFactory; + typedef string Key; + interface TypedProxyPushConsumer : CosNotifyChannelAdmin::ProxyConsumer, CosTypedNotifyComm::TypedPushConsumer { + void connect_typed_push_supplier (in CosEventComm::PushSupplier push_supplier) + raises (CosEventChannelAdmin::AlreadyConnected); + }; // TypedProxyPushConsumer + + interface TypedProxyPullSupplier : CosNotifyChannelAdmin::ProxySupplier, CosTypedNotifyComm::TypedPullSupplier { + void connect_typed_pull_consumer (in CosEventComm::PullConsumer pull_consumer) + raises (CosEventChannelAdmin::AlreadyConnected); + }; // TypedProxyPullSupplier + + interface TypedProxyPullConsumer : CosNotifyChannelAdmin::ProxyConsumer, CosNotifyComm::PullConsumer { + void connect_typed_pull_supplier (in CosTypedEventComm::TypedPullSupplier pull_supplier) + raises (CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises (CosNotifyChannelAdmin::ConnectionAlreadyInactive, CosNotifyChannelAdmin::NotConnected); + + void resume_connection() + raises (CosNotifyChannelAdmin::ConnectionAlreadyActive, CosNotifyChannelAdmin::NotConnected); + }; // TypedProxyPullConsumer + + interface TypedProxyPushSupplier : CosNotifyChannelAdmin::ProxySupplier, CosNotifyComm::PushSupplier { + void connect_typed_push_consumer (in CosTypedEventComm::TypedPushConsumer push_consumer) + raises (CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises (CosNotifyChannelAdmin::ConnectionAlreadyInactive, CosNotifyChannelAdmin::NotConnected); + + void resume_connection() + raises (CosNotifyChannelAdmin::ConnectionAlreadyActive, CosNotifyChannelAdmin::NotConnected); + }; // TypedProxyPushSupplier + + interface TypedConsumerAdmin : CosNotifyChannelAdmin::ConsumerAdmin, CosTypedEventChannelAdmin::TypedConsumerAdmin { + TypedProxyPullSupplier obtain_typed_notification_pull_supplier(in Key supported_interface, + out CosNotifyChannelAdmin::ProxyID proxy_id) + raises( CosTypedEventChannelAdmin::InterfaceNotSupported, CosNotifyChannelAdmin::AdminLimitExceeded ); + + TypedProxyPushSupplier obtain_typed_notification_push_supplier(in Key uses_interface, + out CosNotifyChannelAdmin::ProxyID proxy_id) + raises(CosTypedEventChannelAdmin::NoSuchImplementation, CosNotifyChannelAdmin::AdminLimitExceeded); + }; // TypedConsumerAdmin + + interface TypedSupplierAdmin : CosNotifyChannelAdmin::SupplierAdmin, CosTypedEventChannelAdmin::TypedSupplierAdmin { + TypedProxyPushConsumer obtain_typed_notification_push_consumer(in Key supported_interface, + out CosNotifyChannelAdmin::ProxyID proxy_id) + raises( CosTypedEventChannelAdmin::InterfaceNotSupported, CosNotifyChannelAdmin::AdminLimitExceeded); + TypedProxyPullConsumer obtain_typed_notification_pull_consumer(in Key uses_interface, + out CosNotifyChannelAdmin::ProxyID proxy_id ) + raises(CosTypedEventChannelAdmin::NoSuchImplementation, CosNotifyChannelAdmin::AdminLimitExceeded); + }; // TypedSupplierAdmin + + interface TypedEventChannel : CosNotification::QoSAdmin, CosNotification::AdminPropertiesAdmin, + CosTypedEventChannelAdmin::TypedEventChannel { + readonly attribute TypedEventChannelFactory MyFactory; + readonly attribute TypedConsumerAdmin default_consumer_admin; + readonly attribute TypedSupplierAdmin default_supplier_admin; + readonly attribute CosNotifyFilter::FilterFactory default_filter_factory; + + TypedConsumerAdmin new_for_typed_notification_consumers(in CosNotifyChannelAdmin::InterFilterGroupOperator op, + out CosNotifyChannelAdmin::AdminID id); + + TypedSupplierAdmin new_for_typed_notification_suppliers(in CosNotifyChannelAdmin::InterFilterGroupOperator op, + out CosNotifyChannelAdmin::AdminID id); + + TypedConsumerAdmin get_consumeradmin (in CosNotifyChannelAdmin::AdminID id ) + raises (CosNotifyChannelAdmin::AdminNotFound); + + TypedSupplierAdmin get_supplieradmin (in CosNotifyChannelAdmin::AdminID id) + raises (CosNotifyChannelAdmin::AdminNotFound); + + CosNotifyChannelAdmin::AdminIDSeq get_all_consumeradmins(); + + CosNotifyChannelAdmin::AdminIDSeq get_all_supplieradmins(); + }; // TypedEventChannel + + interface TypedEventChannelFactory { + TypedEventChannel create_typed_channel (in CosNotification::QoSProperties initial_QoS, + in CosNotification::AdminProperties initial_admin, + out CosNotifyChannelAdmin::ChannelID id) + raises( CosNotification::UnsupportedQoS, CosNotification::UnsupportedAdmin); + + CosNotifyChannelAdmin::ChannelIDSeq get_all_typed_channels(); + + TypedEventChannel get_typed_event_channel (in CosNotifyChannelAdmin::ChannelID id) + raises (CosNotifyChannelAdmin::ChannelNotFound); + }; // TypedEventChannelFactory +}; // CosTypedNotifyChannelAdmin + +#endif /* ifndef _COS_TYPED_NOTIFICATION_IDL_ */ diff --git a/lib/cosNotification/src/Makefile b/lib/cosNotification/src/Makefile new file mode 100644 index 0000000000..637c633e52 --- /dev/null +++ b/lib/cosNotification/src/Makefile @@ -0,0 +1,369 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk + +ifeq ($(TYPE),debug) +ERL_COMPILE_FLAGS += -Ddebug -W +endif + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(COSNOTIFICATION_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/cosNotification-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES = \ + CosNotification_Common \ + CosNotifyChannelAdmin_ConsumerAdmin_impl \ + CosNotifyChannelAdmin_EventChannelFactory_impl \ + CosNotifyChannelAdmin_EventChannel_impl \ + CosNotifyChannelAdmin_SupplierAdmin_impl \ + CosNotifyFilter_Filter_impl \ + CosNotifyFilter_MappingFilter_impl \ + CosNotifyFilter_FilterFactory_impl \ + PullerConsumer_impl \ + PullerSupplier_impl \ + PusherConsumer_impl \ + PusherSupplier_impl \ + cosNotificationApp \ + cosNotification_Scanner \ + cosNotification_Filter \ + cosNotification_eventDB + +ERL_FILES = $(MODULES:%=%.erl) +HRL_FILES = \ + CosNotification_Definitions.hrl + +YECC_FILES = cosNotification_Grammar.yrl + +GEN_YECC_ERL_FILES = cosNotification_Grammar.erl + +GEN_YECC_HRL_FILES = + +GEN_NOTIFICATION_ERL_FILES = \ + oe_CosNotification.erl \ + CosNotification.erl \ + CosNotification_AdminPropertiesAdmin.erl \ + CosNotification_EventHeader.erl \ + CosNotification_EventType.erl \ + CosNotification_FixedEventHeader.erl \ + CosNotification_NamedPropertyRange.erl \ + CosNotification_Property.erl \ + CosNotification_PropertyError.erl \ + CosNotification_PropertyRange.erl \ + CosNotification_QoSAdmin.erl \ + CosNotification_StructuredEvent.erl \ + CosNotification_UnsupportedAdmin.erl \ + CosNotification_UnsupportedQoS.erl \ + CosNotification_EventBatch.erl \ + CosNotification_EventTypeSeq.erl \ + CosNotification_NamedPropertyRangeSeq.erl \ + CosNotification_PropertyErrorSeq.erl \ + CosNotification_PropertySeq.erl + +GEN_CHANNELADMIN_ERL_FILES = \ + oe_CosNotifyChannelAdmin.erl \ + CosNotifyChannelAdmin_AdminLimit.erl \ + CosNotifyChannelAdmin_AdminLimitExceeded.erl \ + CosNotifyChannelAdmin_AdminNotFound.erl \ + CosNotifyChannelAdmin_ChannelNotFound.erl \ + CosNotifyChannelAdmin_ConnectionAlreadyActive.erl \ + CosNotifyChannelAdmin_ConnectionAlreadyInactive.erl \ + CosNotifyChannelAdmin_ConsumerAdmin.erl \ + CosNotifyChannelAdmin_EventChannel.erl \ + CosNotifyChannelAdmin_EventChannelFactory.erl \ + CosNotifyChannelAdmin_NotConnected.erl \ + CosNotifyChannelAdmin_ProxyConsumer.erl \ + CosNotifyChannelAdmin_ProxyNotFound.erl \ + CosNotifyChannelAdmin_ProxyPullConsumer.erl \ + CosNotifyChannelAdmin_ProxyPullSupplier.erl \ + CosNotifyChannelAdmin_ProxyPushConsumer.erl \ + CosNotifyChannelAdmin_ProxyPushSupplier.erl \ + CosNotifyChannelAdmin_ProxySupplier.erl \ + CosNotifyChannelAdmin_SequenceProxyPullConsumer.erl \ + CosNotifyChannelAdmin_SequenceProxyPullSupplier.erl \ + CosNotifyChannelAdmin_SequenceProxyPushConsumer.erl \ + CosNotifyChannelAdmin_SequenceProxyPushSupplier.erl \ + CosNotifyChannelAdmin_StructuredProxyPullConsumer.erl \ + CosNotifyChannelAdmin_StructuredProxyPullSupplier.erl \ + CosNotifyChannelAdmin_StructuredProxyPushConsumer.erl \ + CosNotifyChannelAdmin_StructuredProxyPushSupplier.erl \ + CosNotifyChannelAdmin_SupplierAdmin.erl \ + CosNotifyChannelAdmin_AdminIDSeq.erl \ + CosNotifyChannelAdmin_ChannelIDSeq.erl \ + CosNotifyChannelAdmin_ProxyIDSeq.erl + +GEN_NOTIFYFILTER_ERL_FILES = \ + oe_CosNotifyFilter.erl \ + CosNotifyFilter_CallbackNotFound.erl \ + CosNotifyFilter_ConstraintExp.erl \ + CosNotifyFilter_ConstraintInfo.erl \ + CosNotifyFilter_ConstraintNotFound.erl \ + CosNotifyFilter_DuplicateConstraintID.erl \ + CosNotifyFilter_Filter.erl \ + CosNotifyFilter_FilterAdmin.erl \ + CosNotifyFilter_FilterFactory.erl \ + CosNotifyFilter_FilterNotFound.erl \ + CosNotifyFilter_InvalidConstraint.erl \ + CosNotifyFilter_InvalidGrammar.erl \ + CosNotifyFilter_InvalidValue.erl \ + CosNotifyFilter_MappingConstraintInfo.erl \ + CosNotifyFilter_MappingConstraintPair.erl \ + CosNotifyFilter_MappingFilter.erl \ + CosNotifyFilter_UnsupportedFilterableData.erl \ + CosNotifyFilter_CallbackIDSeq.erl \ + CosNotifyFilter_ConstraintExpSeq.erl \ + CosNotifyFilter_ConstraintIDSeq.erl \ + CosNotifyFilter_ConstraintInfoSeq.erl \ + CosNotifyFilter_FilterIDSeq.erl \ + CosNotifyFilter_MappingConstraintInfoSeq.erl \ + CosNotifyFilter_MappingConstraintPairSeq.erl + +GEN_NOTIFYCOMM_ERL_FILES = \ + oe_CosNotifyComm.erl \ + CosNotifyComm_InvalidEventType.erl \ + CosNotifyComm_NotifyPublish.erl \ + CosNotifyComm_NotifySubscribe.erl \ + CosNotifyComm_PullConsumer.erl \ + CosNotifyComm_PullSupplier.erl \ + CosNotifyComm_PushConsumer.erl \ + CosNotifyComm_PushSupplier.erl \ + CosNotifyComm_SequencePullConsumer.erl \ + CosNotifyComm_SequencePullSupplier.erl \ + CosNotifyComm_SequencePushConsumer.erl \ + CosNotifyComm_SequencePushSupplier.erl \ + CosNotifyComm_StructuredPullConsumer.erl \ + CosNotifyComm_StructuredPullSupplier.erl \ + CosNotifyComm_StructuredPushConsumer.erl \ + CosNotifyComm_StructuredPushSupplier.erl \ + +GEN_OE_EVENTCOMM_ERL_FILES = \ + oe_cosNotificationAppComm.erl \ + oe_CosNotificationComm_Event.erl + +EXTERNAL_INC_PATH = ../include + +GEN_NOTIFICATION_HRL_FILES = \ + oe_CosNotification.hrl \ + CosNotification.hrl \ + CosNotification_AdminPropertiesAdmin.hrl \ + CosNotification_QoSAdmin.hrl \ + +EXTERNAL_GEN_NOTIFICATION_HRL_FILES = \ + $(GEN_NOTIFICATION_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%) + +GEN_CHANNELADMIN_HRL_FILES = \ + oe_CosNotifyChannelAdmin.hrl \ + CosNotifyChannelAdmin.hrl \ + CosNotifyChannelAdmin_ConsumerAdmin.hrl \ + CosNotifyChannelAdmin_EventChannel.hrl \ + CosNotifyChannelAdmin_EventChannelFactory.hrl \ + CosNotifyChannelAdmin_ProxyConsumer.hrl \ + CosNotifyChannelAdmin_ProxyPullConsumer.hrl \ + CosNotifyChannelAdmin_ProxyPullSupplier.hrl \ + CosNotifyChannelAdmin_ProxyPushConsumer.hrl \ + CosNotifyChannelAdmin_ProxyPushSupplier.hrl \ + CosNotifyChannelAdmin_ProxySupplier.hrl \ + CosNotifyChannelAdmin_SequenceProxyPullConsumer.hrl \ + CosNotifyChannelAdmin_SequenceProxyPullSupplier.hrl \ + CosNotifyChannelAdmin_SequenceProxyPushConsumer.hrl \ + CosNotifyChannelAdmin_SequenceProxyPushSupplier.hrl \ + CosNotifyChannelAdmin_StructuredProxyPullConsumer.hrl \ + CosNotifyChannelAdmin_StructuredProxyPullSupplier.hrl \ + CosNotifyChannelAdmin_StructuredProxyPushConsumer.hrl \ + CosNotifyChannelAdmin_StructuredProxyPushSupplier.hrl \ + CosNotifyChannelAdmin_SupplierAdmin.hrl \ + +EXTERNAL_GEN_CHANNELADMIN_HRL_FILES = \ + $(GEN_CHANNELADMIN_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%) + +GEN_NOTIFYFILTER_HRL_FILES = \ + oe_CosNotifyFilter.hrl \ + CosNotifyFilter.hrl \ + CosNotifyFilter_Filter.hrl \ + CosNotifyFilter_FilterAdmin.hrl \ + CosNotifyFilter_FilterFactory.hrl \ + CosNotifyFilter_MappingFilter.hrl + +EXTERNAL_GEN_NOTIFYFILTER_HRL_FILES = \ + $(GEN_NOTIFYFILTER_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%) + +GEN_NOTIFYCOMM_HRL_FILES = \ + oe_CosNotifyComm.hrl \ + CosNotifyComm.hrl \ + CosNotifyComm_NotifyPublish.hrl \ + CosNotifyComm_NotifySubscribe.hrl \ + CosNotifyComm_PullConsumer.hrl \ + CosNotifyComm_PullSupplier.hrl \ + CosNotifyComm_PushConsumer.hrl \ + CosNotifyComm_PushSupplier.hrl \ + CosNotifyComm_SequencePullConsumer.hrl \ + CosNotifyComm_SequencePullSupplier.hrl \ + CosNotifyComm_SequencePushConsumer.hrl \ + CosNotifyComm_SequencePushSupplier.hrl \ + CosNotifyComm_StructuredPullConsumer.hrl \ + CosNotifyComm_StructuredPullSupplier.hrl \ + CosNotifyComm_StructuredPushConsumer.hrl \ + CosNotifyComm_StructuredPushSupplier.hrl \ + +EXTERNAL_GEN_NOTIFYCOMM_HRL_FILES = \ + $(GEN_NOTIFYCOMM_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%) + +GEN_OE_EVENTCOMM_HRL_FILES = \ + oe_cosNotificationAppComm.hrl \ + oe_CosNotificationComm.hrl \ + oe_CosNotificationComm_Event.hrl + +GEN_ERL_FILES = \ + $(GEN_NOTIFICATION_ERL_FILES) \ + $(GEN_OE_EVENTCOMM_ERL_FILES) \ + $(GEN_NOTIFYCOMM_ERL_FILES) \ + $(GEN_NOTIFYFILTER_ERL_FILES) \ + $(GEN_CHANNELADMIN_ERL_FILES) \ + $(GEN_YECC_ERL_FILES) + +GEN_HRL_FILES = \ + $(EXTERNAL_GEN_NOTIFICATION_HRL_FILES) \ + $(GEN_OE_EVENTCOMM_HRL_FILES) \ + $(EXTERNAL_GEN_NOTIFYCOMM_HRL_FILES) \ + $(EXTERNAL_GEN_NOTIFYFILTER_HRL_FILES) \ + $(EXTERNAL_GEN_CHANNELADMIN_HRL_FILES) \ + $(GEN_YECC_HRL_FILES) + + +GEN_FILES = \ + $(GEN_HRL_FILES) \ + $(GEN_ERL_FILES) + +TARGET_FILES = \ + $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \ + $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +IDL_FILES = \ + CosNotification.idl \ + CosNotifyChannelAdmin.idl \ + CosNotifyFilter.idl \ + CosNotifyComm.idl \ + cosNotificationAppComm.idl + +APPUP_FILE = cosNotification.appup +APPUP_SRC = $(APPUP_FILE).src +APPUP_TARGET = $(EBIN)/$(APPUP_FILE) + +APP_FILE = cosNotification.app +APP_SRC = $(APP_FILE).src +APP_TARGET = $(EBIN)/$(APP_FILE) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosNotification/ebin \ + -pa $(ERL_TOP)/lib/ic/ebin\ + -pa $(ERL_TOP)/lib/orber/ebin \ + -pa $(ERL_TOP)/lib/cosEvent/ebin \ + -pa $(ERL_TOP)/lib/cosTime/ebin \ + -I$(ERL_TOP)/lib/cosEvent/src + +# The -pa option is just used temporary until erlc can handle +# includes from other directories than ../include . +ERL_COMPILE_FLAGS += \ + $(ERL_IDL_FLAGS) \ + -pa $(ERL_TOP)/lib/orber/include \ + -pa $(ERL_TOP)/lib/cosNotification/include \ + -pa $(ERL_TOP)/lib/cosEvent/include \ + -pa $(ERL_TOP)/lib/cosTime/include \ + -I$(ERL_TOP)/lib/orber/include \ + -I$(ERL_TOP)/lib/cosNotification/include \ + -I$(ERL_TOP)/lib/cosEvent/include \ + -I$(ERL_TOP)/lib/cosTime/include \ + +'{parse_transform,sys_pre_attributes}' \ + +'{attribute,insert,app_vsn,"cosNotification_$(COSNOTIFICATION_VSN)"}' + +YECC_COMPILE_FLAGS = + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) + +debug: + @${MAKE} TYPE=debug + +cleanb: + rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) + rm -f errs core *~ + +clean: + rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) + rm -f errs core *~ + +$(APP_TARGET): $(APP_SRC) + sed -e 's;%VSN%;$(VSN);' $< > $@ + +$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +docs: + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- +$(GEN_NOTIFICATION_ERL_FILES) $(EXTERNAL_GEN_NOTIFICATION_HRL_FILES): CosNotification.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotification.cfg"}' CosNotification.idl + mv $(GEN_NOTIFICATION_HRL_FILES) $(EXTERNAL_INC_PATH) +$(GEN_CHANNELADMIN_ERL_FILES) $(EXTERNAL_GEN_CHANNELADMIN_HRL_FILES): CosNotifyChannelAdmin.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyChannelAdmin.cfg"}' CosNotifyChannelAdmin.idl + mv $(GEN_CHANNELADMIN_HRL_FILES) $(EXTERNAL_INC_PATH) +$(GEN_NOTIFYFILTER_ERL_FILES) $(EXTERNAL_GEN_NOTIFYFILTER_HRL_FILES): CosNotifyFilter.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyFilter.cfg"}' CosNotifyFilter.idl + mv $(GEN_NOTIFYFILTER_HRL_FILES) $(EXTERNAL_INC_PATH) +$(GEN_OE_EVENTCOMM_ERL_FILES) $(GEN_OE_EVENTCOMM_HRL_FILES): cosNotificationAppComm.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"cosNotificationComm.cfg"}' cosNotificationAppComm.idl +$(GEN_NOTIFYCOMM_ERL_FILES) $(EXTERNAL_GEN_NOTIFYCOMM_HRL_FILES): CosNotifyComm.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyComm.cfg"}' CosNotifyComm.idl + mv $(GEN_NOTIFYCOMM_HRL_FILES) $(EXTERNAL_INC_PATH) +$(GEN_YECC_ERL_FILES) $(GEN_YECC_HRL_FILES): cosNotification_Grammar.yrl + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) $(YECC_FILES) $(RELSYSDIR)/src + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(IDL_FILES) $(YECC_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/include + $(INSTALL_DATA) $(GEN_HRL_FILES) $(RELSYSDIR)/include + +release_docs_spec: diff --git a/lib/cosNotification/src/PullerConsumer_impl.erl b/lib/cosNotification/src/PullerConsumer_impl.erl new file mode 100644 index 0000000000..fe6f9f8968 --- /dev/null +++ b/lib/cosNotification/src/PullerConsumer_impl.erl @@ -0,0 +1,773 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : PullerConsumer_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('PullerConsumer_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% cosEvent files. +-include_lib("cosEvent/include/CosEventChannelAdmin.hrl"). +-include_lib("cosEvent/include/CosEventComm.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%%----- CosNotifyChannelAdmin::ProxyPullConsumer ------------- +-export([connect_any_pull_supplier/4]). + +%%----- CosNotifyChannelAdmin::SequenceProxyPullConsumer ----- +-export([connect_sequence_pull_supplier/4]). + +%%----- CosNotifyChannelAdmin::StructuredProxyPullConsumer --- +-export([connect_structured_pull_supplier/4]). + +%%----- CosNotifyChannelAdmin::*ProxyPullConsumer ------------ +-export([suspend_connection/3, + resume_connection/3]). + +%%----- Inherit from CosNotifyChannelAdmin::ProxyConsumer ---- +-export([obtain_subscription_types/4, + validate_event_qos/4]). + +%%----- Inherit from CosNotification::QoSAdmin --------------- +-export([get_qos/3, + set_qos/4, + validate_qos/4]). + +%%----- Inherit from CosNotifyComm::NotifyPublish ------------ +-export([offer_change/5]). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ------------ +-export([add_filter/4, + remove_filter/4, + get_filter/4, + get_all_filters/3, + remove_all_filters/3]). + +%%----- Inherit from CosEventComm::PullConsumer ------------- +-export([disconnect_pull_consumer/3]). + +%%----- Inherit from CosNotifyComm::SequencePullConsumer ---- +-export([disconnect_sequence_pull_consumer/3]). + +%%----- Inherit from CosNotifyComm::StructuredPullConsumer -- +-export([disconnect_structured_pull_consumer/3]). + +%%----- Inherit from CosEventChannelAdmin::ProxyPullConsumer +-export([connect_pull_supplier/4]). + + +%% Attributes (external) CosNotifyChannelAdmin::ProxySupplier +-export(['_get_MyType'/3, + '_get_MyAdmin'/3]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {myType, + myAdmin, + myAdminPid, + myChannel, + myFilters = [], + myOperator, + idCounter = 0, + client, + qosGlobal, + qosLocal, + suspended = false, + pullTimer, + pullInterval, + publishType = false, + etsR, + eventCounter = 0, + eventDB, + this}). + +%% Data structures constructors +-define(get_InitState(_MyT, _MyA, _MyAP, _QS, _LQS, _Ch, _PI, _MyOP, _GT, _GL, _TR), + #state{myType = _MyT, + myAdmin = _MyA, + myAdminPid = _MyAP, + myChannel = _Ch, + myOperator = _MyOP, + qosGlobal = _QS, + qosLocal = _LQS, + pullInterval = _PI, + etsR = ets:new(oe_ets, [set, protected]), + eventDB = cosNotification_eventDB:create_db(_LQS, _GT, _GL, _TR)}). + +%%-------------- Data structures selectors ----------------- +%% Attributes +-define(get_MyType(S), S#state.myType). +-define(get_MyAdmin(S), S#state.myAdmin). +-define(get_MyAdminPid(S), S#state.myAdminPid). +-define(get_MyChannel(S), S#state.myChannel). +-define(get_MyOperator(S), S#state.myOperator). +%% Client Object +-define(get_Client(S), S#state.client). +%% QoS +-define(get_GlobalQoS(S), S#state.qosGlobal). +-define(get_LocalQoS(S), S#state.qosLocal). +-define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}). +%% Filters +-define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters))). +-define(get_AllFilter(S), S#state.myFilters). +-define(get_AllFilterID(S), find_ids(S#state.myFilters)). +%% Admin +-define(get_PullInterval(S), S#state.pullInterval). +-define(get_PullTimer(S), S#state.pullTimer). +-define(get_PacingInterval(S), round(?not_GetPacingInterval((S#state.qosLocal))/10000000)). +-define(get_BatchLimit(S), ?not_GetMaximumBatchSize((S#state.qosLocal))). +%% Publish +-define(get_AllPublish(S), lists:flatten(ets:match(S#state.etsR, + {'$1',publish}))). +-define(get_PublishType(S), S#state.publishType). +%% ID +-define(get_IdCounter(S), S#state.idCounter). +%% Event +-define(get_Event(S), cosNotification_eventDB:get_event(S#state.eventDB)). +-define(get_Events(S,M), cosNotification_eventDB:get_events(S#state.eventDB, M)). +-define(get_EventCounter(S), S#state.eventCounter). + +%%-------------- Data structures modifiers ----------------- +%% Client Object +-define(set_Client(S,D), S#state{client=D}). +-define(del_Client(S), S#state{client=undefined}). +-define(set_Suspended(S), S#state{client=true}). +-define(set_NotSuspended(S), S#state{client=false}). +-define(set_Unconnected(S), S#state{client=undefined}). +%% QoS +-define(set_LocalQoS(S,D), S#state{qosLocal=D}). +-define(set_GlobalQoS(S,D), S#state{qosGlobal=D}). +-define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}). +%% Filters +-define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}). +-define(del_Filter(S,I), S#state{myFilters= + delete_obj(lists:keydelete(I, 1, S#state.myFilters), + S#state.myFilters)}). +-define(del_AllFilter(S), S#state{myFilters=[]}). +%% Admin +-define(set_PullInterval(S,V), S#state{pullInterval=V}). +-define(set_PullTimer(S,T), S#state{pullTimer=T}). +%% Publish +-define(add_Publish(S,E), ets:insert(S#state.etsR, {E, publish})). +-define(del_Publish(S,E), ets:delete(S#state.etsR, E)). +-define(set_PublishType(S,T), S#state{publishType=T}). +%% ID +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). +%% Event +-define(add_Event(S,E), cosNotification_eventDB:add_event(S#state.eventDB, E)). +-define(update_EventDB(S,Q), S#state{eventDB= + cosNotification_eventDB:update(S#state.eventDB, Q)}). + +-define(set_EventCounter(S,V), S#state{eventCounter=V}). +-define(add_to_EventCounter(S,V),S#state{eventCounter=S#state.eventCounter+V}). +-define(reset_EventCounter(S), S#state{eventCounter=0}). +-define(increase_EventCounter(S),S#state{eventCounter=(S#state.eventCounter+1)}). +-define(decrease_EventCounter(S),S#state{eventCounter=S#state.eventCounter-1}). +-define(add_ToEventCounter(S,A), S#state{eventCounter=(S#state.eventCounter+A)}). +-define(sub_FromEventCounter(S,_A), S#state{eventCounter=(S#state.eventCounter-_A)}). +-define(set_EventCounterTo(S,V), S#state{eventCounter=V}). + +%%-------------- MISC ---------------------------------------- +-define(is_ANY(S), S#state.myType == 'PULL_ANY'). +-define(is_STRUCTURED(S), S#state.myType == 'PULL_STRUCTURED'). +-define(is_SEQUENCE(S), S#state.myType == 'PULL_SEQUENCE'). +-define(is_ANDOP(S), S#state.myOperator == 'AND_OP'). +-define(is_UnConnected(S), S#state.client == undefined). +-define(is_Connected(S), S#state.client =/= undefined). +-define(is_Suspended(S), S#state.suspended == true). +-define(is_NotSuspended(S), S#state.suspended == false). +-define(is_PersistentConnection(S), + ?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent). +-define(is_PersistentEvent(S), + ?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent). + +%%-----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + ?DBG("INFO: ~p~n", [Info]), + case Info of + {'EXIT', Pid, Reason} when ?get_MyAdminPid(State) == Pid-> + ?DBG("PARENT ADMIN: ~p TERMINATED.~n",[Reason]), + {stop, Reason, State}; + {'EXIT', _Pid, _Reason} -> + ?DBG("PROXYPUSHSUPPLIER: ~p TERMINATED.~n",[_Reason]), + {noreply, State}; + pull -> + try_pull_events(State); + _ -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, Options, Operator]) -> + process_flag(trap_exit, true), + Secs = timer:seconds('CosNotification_Common':get_option(pullInterval, + Options, + ?not_DEFAULT_SETTINGS)), + GCTime = 'CosNotification_Common':get_option(gcTime, Options, + ?not_DEFAULT_SETTINGS), + GCLimit = 'CosNotification_Common':get_option(gcLimit, Options, + ?not_DEFAULT_SETTINGS), + TimeRef = 'CosNotification_Common':get_option(timeService, Options, + ?not_DEFAULT_SETTINGS), + timer:start(), + {ok, ?get_InitState(MyType, MyAdmin, MyAdminPid, InitQoS, + LQS, MyChannel, Secs, Operator, GCTime, + GCLimit, TimeRef)}. + +terminate(_Reason, State) when ?is_UnConnected(State) -> + %% We are currently not connected to a client. Hence, no need for sending + %% a disconnect request. + stop_timer(State), + ok; +terminate(_Reason, State) when ?is_ANY(State) -> + stop_timer(State), + 'CosNotification_Common':disconnect('CosEventComm_PullSupplier', + disconnect_pull_supplier, + ?get_Client(State)); +terminate(_Reason, State) when ?is_SEQUENCE(State) -> + stop_timer(State), + 'CosNotification_Common':disconnect('CosNotifyComm_SequencePullSupplier', + disconnect_sequence_pull_supplier, + ?get_Client(State)); +terminate(_Reason, State) when ?is_STRUCTURED(State) -> + stop_timer(State), + 'CosNotification_Common':disconnect('CosNotifyComm_StructuredPullSupplier', + disconnect_structured_pull_supplier, + ?get_Client(State)). + +%%----------------------------------------------------------- +%%----- CosNotifyChannelAdmin_ProxyConsumer attributes ------ +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_MyType' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyType'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyType(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyAdmin' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyAdmin'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyAdmin(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----- CosEventChannelAdmin::ProxyPullConsumer ------------- +%%----------------------------------------------------------% +%% function : connect_pull_supplier +%% Arguments: Client - CosEventComm::PullSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%% Both exceptions from CosEventChannelAdmin!!! +%%----------------------------------------------------------- +connect_pull_supplier(OE_THIS, OE_FROM, State, Client) -> + connect_any_pull_supplier(OE_THIS, OE_FROM, State, Client). + +%%----- CosNotifyChannelAdmin::ProxyPullConsumer ------------ +%%----------------------------------------------------------% +%% function : connect_any_pull_supplier +%% Arguments: Client - CosEventComm::PullSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%% Both exceptions from CosEventChannelAdmin!!! +%%----------------------------------------------------------- +connect_any_pull_supplier(OE_THIS, _OE_FROM, State, Client) when ?is_ANY(State) -> + 'CosNotification_Common':type_check(Client, 'CosEventComm_PullSupplier'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + NewState = start_timer(State), + {reply, ok, NewState#state{client = Client, this = OE_THIS}} + end; +connect_any_pull_supplier(_, _, _,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::SequenceProxyPullConsumer ---- +%%----------------------------------------------------------% +%% function : connect_sequence_pull_supplier +%% Arguments: Client - CosNotifyComm::SequencePullSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%%----------------------------------------------------------- +connect_sequence_pull_supplier(OE_THIS, _OE_FROM, State, Client) when ?is_SEQUENCE(State) -> + 'CosNotification_Common':type_check(Client, 'CosNotifyComm_SequencePullSupplier'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + NewState = start_timer(State), + {reply, ok, NewState#state{client = Client, this = OE_THIS}} + end; +connect_sequence_pull_supplier(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::StructuredProxyPullConsumer -- +%%----------------------------------------------------------% +%% function : connect_structured_pull_supplier +%% Arguments: Client - CosNotifyComm::StructuredPullSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%%----------------------------------------------------------- +connect_structured_pull_supplier(OE_THIS, _OE_FROM, State, Client) when ?is_STRUCTURED(State) -> + 'CosNotification_Common':type_check(Client, 'CosNotifyComm_StructuredPullSupplier'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + NewState = start_timer(State), + {reply, ok, NewState#state{client = Client, this = OE_THIS}} + end; +connect_structured_pull_supplier(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::*ProxyPullConsumer ----------- +%%----------------------------------------------------------% +%% function : suspend_connection +%% Arguments: +%% Returns : ok | {'EXCEPTION', #'ConnectionAlreadyInactive'{}} | +%% {'EXCEPTION', #'NotConneced'{}} +%%----------------------------------------------------------- +suspend_connection(_OE_THIS, _OE_FROM, State) when ?is_Connected(State) -> + if + ?is_Suspended(State) -> + corba:raise(#'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}); + true -> + stop_timer(State), + {reply, ok, ?set_Suspended(State)} + end; +suspend_connection(_, _, _) -> + corba:raise(#'CosNotifyChannelAdmin_NotConnected'{}). + +%%----------------------------------------------------------% +%% function : resume_connection +%% Arguments: +%% Returns : ok | {'EXCEPTION', #'ConnectionAlreadyActive'{}} | +%% {'EXCEPTION', #'NotConneced'{}} +%%----------------------------------------------------------- +resume_connection(_OE_THIS, _OE_FROM, State) when ?is_Connected(State) -> + if + ?is_NotSuspended(State) -> + corba:raise(#'CosNotifyChannelAdmin_ConnectionAlreadyActive'{}); + true -> + NewState = start_timer(State), + {reply, ok, ?set_NotSuspended(NewState)} + end; +resume_connection(_, _, _) -> + corba:raise(#'CosNotifyChannelAdmin_NotConnected'{}). + +%%----- Inherit from CosNotifyChannelAdmin::ProxyConsumer --- +%%----------------------------------------------------------% +%% function : obtain_subscription_types +%% Arguments: Mode - enum 'ObtainInfoMode' (CosNotifyChannelAdmin) +%% Returns : CosNotification::EventTypeSeq +%%----------------------------------------------------------- +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_OFF') -> + {reply, ?get_AllPublish(State), ?set_PublishType(State, false)}; +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_ON') -> + {reply, ?get_AllPublish(State), ?set_PublishType(State, true)}; +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_OFF') -> + {reply, [], ?set_PublishType(State, false)}; +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_ON') -> + {reply, [], ?set_PublishType(State, true)}; +obtain_subscription_types(_,_,_,What) -> + orber:dbg("[~p] PullerConsumer:obtain_subscription_types(~p);~n" + "Incorrect enumerant", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : validate_event_qos +%% Arguments: RequiredQoS - CosNotification::QoSProperties +%% Returns : ok | {'EXCEPTION', #'UnsupportedQoS'{}} +%% AvilableQoS - CosNotification::NamedPropertyRangeSeq (out) +%%----------------------------------------------------------- +validate_event_qos(_OE_THIS, _OE_FROM, State, RequiredQoS) -> + AvilableQoS = 'CosNotification_Common':validate_event_qos(RequiredQoS, + ?get_LocalQoS(State)), + {reply, {ok, AvilableQoS}, State}. + +%%----- Inherit from CosNotification::QoSAdmin -------------- +%%----------------------------------------------------------% +%% function : get_qos +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +get_qos(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalQoS(State), State}. + +%%----------------------------------------------------------% +%% function : set_qos +%% Arguments: QoS - CosNotification::QoSProperties, i.e., +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +set_qos(_OE_THIS, _OE_FROM, State, QoS) -> + {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + NewState = ?update_EventDB(State, LQS), + {reply, ok, ?set_BothQoS(NewState, NewQoS, LQS)}. + +%%----------------------------------------------------------% +%% function : validate_qos +%% Arguments: Required_qos - CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS} +%% {ok, CosNotification::NamedPropertyRangeSeq} +%%----------------------------------------------------------- +validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) -> + QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + {reply, {ok, QoS}, State}. + +%%----- Inherit from CosNotifyComm::NotifyPublish ----------- +%%----------------------------------------------------------% +%% function : offer_change +%% Arguments: Added - #'CosNotification_EventType'{} +%% Removed - #'CosNotification_EventType'{} +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyComm_InvalidEventType'{}} +%%----------------------------------------------------------- +offer_change(_OE_THIS, _OE_FROM, State, Added, Removed) -> + cosNotification_Filter:validate_types(Added), + cosNotification_Filter:validate_types(Removed), + %% On this "side" we don't really care about which + %% type of events the client will supply. + %% Perhaps, later on, if we want to check this against Filters + %% associated with this object we may change this approach, i.e., if + %% the filter will not allow passing certain event types. But the + %% user should see to that that situation never occurs. It would add + %% extra overhead. Also see PusherSupplier- and PullerSuppler- + %% 'subscription_change'. + update_publish(add, State, Added), + update_publish(remove, State, Removed), + case ?get_PublishType(State) of + true -> + %% Perhaps we should handle exception here?! + %% Probably not. Better to stay "on-line". + catch 'CosNotifyComm_NotifySubscribe': + subscription_change(?get_Client(State), Added, Removed), + ok; + _-> + ok + end, + {reply, ok, State}. + +update_publish(_, _, [])-> + ok; +update_publish(add, State, [H|T]) -> + ?add_Publish(State, H), + update_publish(add, State, T); +update_publish(remove, State, [H|T]) -> + ?del_Publish(State, H), + update_publish(remove, State, T). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ----------- +%%----------------------------------------------------------% +%% function : add_filter +%% Arguments: Filter - CosNotifyFilter::Filter +%% Returns : FilterID - long +%%----------------------------------------------------------- +add_filter(_OE_THIS, _OE_FROM, State, Filter) -> + 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'), + FilterID = ?new_Id(State), + NewState = ?set_IdCounter(State, FilterID), + {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}. + +%%----------------------------------------------------------% +%% function : remove_filter +%% Arguments: FilterID - long +%% Returns : ok +%%----------------------------------------------------------- +remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ok, ?del_Filter(State, FilterID)}; +remove_filter(_,_,_,What) -> + orber:dbg("[~p] PullerConsumer:remove_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_filter +%% Arguments: FilterID - long +%% Returns : Filter - CosNotifyFilter::Filter | +%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}} +%%----------------------------------------------------------- +get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ?get_Filter(State, FilterID), State}; +get_filter(_,_,_,What) -> + orber:dbg("[~p] PullerConsumer:get_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_all_filters +%% Arguments: - +%% Returns : Filter - CosNotifyFilter::FilterIDSeq +%%----------------------------------------------------------- +get_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_AllFilterID(State), State}. + +%%----------------------------------------------------------% +%% function : remove_all_filters +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ok, ?del_AllFilter(State)}. + +%%----- Inherit from CosEventComm::PullConsumer ------------- +%%----------------------------------------------------------% +%% function : disconnect_pull_consumer +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_pull_consumer(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----- Inherit from CosNotifyComm::SequencePullConsumer ---- +%%----------------------------------------------------------% +%% function : disconnect_sequence_pull_consumer +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_sequence_pull_consumer(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----- Inherit from CosNotifyComm::StructuredPullConsumer ---- +%%----------------------------------------------------------% +%% function : disconnect_structured_pull_consumer +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_structured_pull_consumer(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +find_obj({value, {_, Obj}}) -> Obj; +find_obj(_) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}. + +find_ids(List) -> find_ids(List, []). +find_ids([], Acc) -> Acc; +find_ids([{I,_}|T], Acc) -> find_ids(T, [I|Acc]); +find_ids(What, _) -> + orber:dbg("[~p] PullerConsumer:find_ids();~n" + "Id corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +%% Delete a single object. +%% The list don not differ, i.e., no filter removed, raise exception. +delete_obj(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{}); +delete_obj(List,_) -> List. + +%% Start timer which send a message each time we should pull for new events. +start_timer(State) -> + case catch timer:send_interval(?get_PullInterval(State), pull) of + {ok,PullTRef} -> + ?DBG("PULL CONSUMER STARTED PULL TIMER ~p~n", + [?get_PullInterval(State)]), + ?set_PullTimer(State, PullTRef); + What -> + orber:dbg("[~p] PullerConsumer:start_timer();~n" + "Unable to invoke timer:send_interval/2: ~p", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. +stop_timer(State) -> + ?DBG("PULL CONSUMER STOPPED TIMER~n",[]), + timer:cancel(?get_PullTimer(State)). + +%% Try pull event(s); which method is determined by which type this proxy is. +try_pull_events(State) when ?is_ANY(State) -> + case catch 'CosEventComm_PullSupplier':try_pull(?get_Client(State)) of + {_,false} -> + {noreply, State}; + {Event, true} -> + case ?not_isConvertedStructured(Event) of + true -> + forward(seq, State, + cosNotification_eventDB:filter_events([any:get_value(Event)], + ?get_AllFilter(State))); + _ -> + forward(any, State, + cosNotification_eventDB:filter_events([Event], + ?get_AllFilter(State))) + end; + _-> + {noreply, State} + end; +try_pull_events(State) when ?is_SEQUENCE(State) -> + case catch 'CosNotifyComm_SequencePullSupplier': + try_pull_structured_events(?get_Client(State), ?get_BatchLimit(State)) of + {_,false} -> + {noreply, State}; + {EventSeq, true} -> + %% We cannot convert parts of the sequence to any, event though they + %% are converted from any to structured. Would be 'impossible' to send. + forward(seq, State, + cosNotification_eventDB:filter_events(EventSeq, + ?get_AllFilter(State))); + _-> + {noreply, State} + end; +try_pull_events(State) when ?is_STRUCTURED(State) -> + case catch 'CosNotifyComm_StructuredPullSupplier': + try_pull_structured_event(?get_Client(State)) of + {_,false} -> + {noreply, State}; + {Event, true} when ?not_isConvertedAny(Event) -> + forward(any, State, + cosNotification_eventDB:filter_events([Event#'CosNotification_StructuredEvent'.remainder_of_body], + ?get_AllFilter(State))); + {Event, true} -> + forward(seq, State, + cosNotification_eventDB:filter_events([Event], + ?get_AllFilter(State))); + _-> + {noreply, State} + end. + + + +%% Forward events +forward(_, State, {[], _}) when ?is_ANDOP(State) -> + %% Did not pass filtering. Since AND no need to pass on. + {noreply, State}; +forward(Type, State, {[], Failed}) -> + %% Did not pass filtering, but since OR it may pass Admin filters, hence, pass + %% on to Admin + forward(Type, State, Failed, ?get_MyAdmin(State), 'MATCH'); +forward(Type, State, {Passed, _}) when ?is_ANDOP(State) -> + %% Did pass filtering, but since AND we must pass it to Admin to check against + %% its Filters. Just ignore the ones that failed. + forward(Type, State, Passed, ?get_MyAdmin(State), 'MATCH'); +forward(Type, State, {Passed, []}) -> + %% Did pass filtering, and since OR we can pass it to the Channel directly. + forward(Type, State, Passed, ?get_MyChannel(State), 'MATCHED'); +forward(Type, State, {Passed, Failed}) -> + %% Some passed filtering, and since OR we can pass the ones that passed directly + %% to the channel and the other ones via the admin. + forward(Type, State, Passed, ?get_MyChannel(State), 'MATCHED'), + forward(Type, State, Failed, ?get_MyAdmin(State), 'MATCH'). + +forward(any, State, [Event], SendTo, Status) -> + case catch oe_CosNotificationComm_Event:callAny(SendTo, Event, Status) of + ok -> + ?DBG("PROXY FORWARD ANY: ~p~n",[Event]), + {noreply, State}; + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + orber:dbg("[~p] PullerConsumer:forward();~n" + "Admin/Channel no longer exists; terminating and dropping: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] PullerConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL), + {noreply, State}; + R -> + orber:dbg("[~p] PullerConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, R, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, R}]), + {stop, normal, State} + end; +forward(seq, State, Event, SendTo, Status) -> + case catch oe_CosNotificationComm_Event:callSeq(SendTo, Event, Status) of + ok -> + ?DBG("PROXY FORWARD SEQUENCE: ~p~n",[Event]), + {noreply, State}; + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + orber:dbg("[~p] PullerConsumer:forward();~n" + "Admin/Channel no longer exists; terminating and dropping: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] PullerConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL), + {noreply, State}; + R -> + orber:dbg("[~p] PullerConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, R, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, R}]), + {stop, normal, State} + end. + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/PullerSupplier_impl.erl b/lib/cosNotification/src/PullerSupplier_impl.erl new file mode 100644 index 0000000000..9f12f9c742 --- /dev/null +++ b/lib/cosNotification/src/PullerSupplier_impl.erl @@ -0,0 +1,914 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : PullerSupplier_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('PullerSupplier_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% cosEvent files. +-include_lib("cosEvent/include/CosEventChannelAdmin.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). + +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%%----- CosNotifyChannelAdmin::ProxyPullSupplier ------------- +-export([connect_any_pull_consumer/4]). + +%%----- CosNotifyChannelAdmin::SequenceProxyPullSupplier ----- +-export([connect_sequence_pull_consumer/4]). + +%%----- CosNotifyChannelAdmin::StructuredProxyPullSupplier --- +-export([connect_structured_pull_consumer/4]). + +%%----- Inherit from CosNotifyChannelAdmin::ProxySupplier ---- +-export([obtain_offered_types/4, + validate_event_qos/4]). + +%%----- Inherit from CosNotification::QoSAdmin --------------- +-export([get_qos/3, + set_qos/4, + validate_qos/4]). + +%%----- Inherit from CosNotifyComm::NotifySubscribe ---------- +-export([subscription_change/5]). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ------------ +-export([add_filter/4, + remove_filter/4, + get_filter/4, + get_all_filters/3, + remove_all_filters/3]). + +%%----- Inherit from CosEventComm::PullSupplier ------------- +-export([pull/3, + try_pull/3, + disconnect_pull_supplier/3]). + +%%----- Inherit from CosNotifyComm::SequencePullSupplier -- +-export([pull_structured_events/4, + try_pull_structured_events/4, + disconnect_sequence_pull_supplier/3]). + +%%----- Inherit from CosNotifyComm::StructuredPullSupplier -- +-export([pull_structured_event/3, + try_pull_structured_event/3, + disconnect_structured_pull_supplier/3]). + +%%----- Inherit from CosEventChannelAdmin::ProxyPullSupplier +-export([connect_pull_consumer/4]). + +%% Attributes (external) CosNotifyChannelAdmin::ProxySupplier +-export(['_get_MyType'/3, + '_get_MyAdmin'/3, + '_get_priority_filter'/3, + '_set_priority_filter'/4, + '_get_lifetime_filter'/3, + '_set_lifetime_filter'/4]). + +%%--------------- Internal ----------------------------------- +%%----- Inherit from cosNotificationComm -------------------- +-export([callAny/5, + callSeq/5]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {myType, + myAdmin, + myAdminPid, + myChannel, + myFilters = [], + myOperator, + idCounter = 0, + prioFil, + lifetFil, + client, + qosGlobal, + qosLocal, + pacingTimer, + respondTo, + subscribeType = false, + subscribeData = true, + etsR, + eventDB}). + +%% Data structures constructors +-define(get_InitState(_MyT, _MyA, _MyAP, _QS, _LQS, _Ch, _MyOp, _GT, _GL, _TR), + #state{myType = _MyT, + myAdmin = _MyA, + myAdminPid= _MyAP, + myChannel = _Ch, + myOperator= _MyOp, + qosGlobal = _QS, + qosLocal = _LQS, + etsR = ets:new(oe_ets, [set, protected]), + eventDB = cosNotification_eventDB:create_db(_LQS, _GT, _GL, _TR)}). + + +%% Data structures selectors +%% Attributes +-define(get_MyType(S), S#state.myType). +-define(get_MyAdmin(S), S#state.myAdmin). +-define(get_MyAdminPid(S), S#state.myAdmin). +-define(get_MyChannel(S), S#state.myChannel). +-define(get_MyOperator(S), S#state.myOperator). +-define(get_PrioFil(S), S#state.prioFil). +-define(get_LifeTFil(S), S#state.lifetFil). +%% Client Object +-define(get_Client(S), S#state.client). +%% QoS +-define(get_GlobalQoS(S), S#state.qosGlobal). +-define(get_LocalQoS(S), S#state.qosLocal). +-define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}). +%% Filters +-define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters))). +-define(get_AllFilter(S), S#state.myFilters). +-define(get_AllFilterID(S), find_ids(S#state.myFilters)). +%% Event +-define(get_Event(S), cosNotification_eventDB:get_event(S#state.eventDB)). +-define(get_Events(S,M), cosNotification_eventDB:get_events(S#state.eventDB, M)). +-define(get_RespondTo(S), S#state.respondTo). +%% Amin +-define(get_PacingTimer(S), S#state.pacingTimer). +-define(get_PacingInterval(S), round(?not_GetPacingInterval((S#state.qosLocal))/10000000)). +-define(get_BatchLimit(S), ?not_GetMaximumBatchSize((S#state.qosLocal))). +%% Subscribe +-define(get_AllSubscribe(S), lists:flatten(ets:match(S#state.etsR, + {'$1',subscribe}))). +-define(get_SubscribeType(S), S#state.subscribeType). +-define(get_SubscribeData(S), S#state.subscribeData). +%% ID +-define(get_IdCounter(S), S#state.idCounter). +-define(get_SubscribeDB(S), S#state.etsR). + +%% Data structures modifiers +%% Attributes +-define(set_PrioFil(S,D), S#state{prioFil=D}). +-define(set_LifeTFil(S,D), S#state{lifetFil=D}). +%% Client Object +-define(set_Client(S,D), S#state{client=D}). +-define(del_Client(S), S#state{client=undefined}). +%% QoS +-define(set_LocalQoS(S,D), S#state{qosLocal=D}). +-define(set_GlobalQoS(S,D), S#state{qosGlobal=D}). +-define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}). +-define(update_EventDB(S,Q), S#state{eventDB= + cosNotification_eventDB:update(S#state.eventDB, Q)}). +%% Filters +-define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}). +-define(del_Filter(S,I), S#state{myFilters= + delete_obj(lists:keydelete(I, 1, S#state.myFilters), + S#state.myFilters)}). +-define(del_AllFilter(S), S#state{myFilters=[]}). +-define(set_Unconnected(S), S#state{client=undefined}). +-define(reset_RespondTo(S), S#state{respondTo=undefined}). +-define(set_RespondTo(S,F), S#state{respondTo=F}). +%% Event +-define(add_Event(S,E), catch cosNotification_eventDB: + add_event(S#state.eventDB, E, S#state.lifetFil, S#state.prioFil)). +-define(addAndGet_Event(S,E), catch cosNotification_eventDB: + add_and_get_event(S#state.eventDB, E, S#state.lifetFil, S#state.prioFil)). +%% Admin +-define(set_PacingTimer(S,T), S#state{pacingTimer=T}). +%% Subscribe +-define(add_Subscribe(S,E), ets:insert(S#state.etsR, {E, subscribe})). +-define(del_Subscribe(S,E), ets:delete(S#state.etsR, E)). +-define(set_SubscribeType(S,T), S#state{subscribeType=T}). +-define(set_SubscribeData(S,D), S#state{subscribeData=D}). +%% ID +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). + +%% MISC +-define(is_ANY(S), S#state.myType == 'PULL_ANY'). +-define(is_STRUCTURED(S), S#state.myType == 'PULL_STRUCTURED'). +-define(is_SEQUENCE(S), S#state.myType == 'PULL_SEQUENCE'). +-define(is_ANDOP(S), S#state.myOperator == 'AND_OP'). +-define(is_UnConnected(S), S#state.client == undefined). +-define(is_Connected(S), S#state.client =/= undefined). +-define(is_Waiting(S), S#state.respondTo =/= undefined). +-define(is_SubscribedFor(S,K), ets:lookup(S#state.etsR, K) =/= []). +-define(is_BatchLimitReached(S,M), cosNotification_eventDB: + status(S#state.eventDB, {batchLimit, + ?not_GetMaximumBatchSize((S#state.qosLocal)), M})). + +%%----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%----------------------------------------------------------- + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + ?DBG("INFO: ~p~n", [Info]), + case Info of + {'EXIT', Pid, Reason} when ?get_MyAdminPid(State)==Pid-> + ?DBG("PARENT ADMIN: ~p TERMINATED.~n",[Reason]), + {stop, Reason, State}; + {'EXIT', _Pid, _Reason} -> + ?DBG("PROXYPUSHSUPPLIER: ~p TERMINATED.~n",[_Reason]), + {noreply, State}; + {pacing, TS} when ?is_Waiting(State) -> + case ?get_PacingTimer(State) of + {_, TS} -> + ?DBG("PULL SUPPLIER PACING LIMIT REACHED~n",[]), + {RespondTo, Max} = ?get_RespondTo(State), + {EventSeq, _} = ?get_Events(State, Max), + corba:reply(RespondTo, EventSeq), + {noreply, ?reset_RespondTo(State)}; + _ -> + %% Must have been an old timer event, i.e., we reached the + %% Batch Limit before Pace limit and we were not able + %% to stop the timer before it triggered an event. + ?DBG("PULL SUPPLIER OLD PACING LIMIT REACHED~n",[]), + {noreply, State} + end; + {pacing, _} -> + ?DBG("PULL SUPPLIER PACING LIMIT REACHED BUT NO CLIENT; IMPOSSIBLE!!!~n",[]), + {noreply, State}; + _ -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, Options, Operator]) -> + process_flag(trap_exit, true), + GCTime = 'CosNotification_Common':get_option(gcTime, Options, + ?not_DEFAULT_SETTINGS), + GCLimit = 'CosNotification_Common':get_option(gcLimit, Options, + ?not_DEFAULT_SETTINGS), + TimeRef = 'CosNotification_Common':get_option(timeService, Options, + ?not_DEFAULT_SETTINGS), + {ok, ?get_InitState(MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, + Operator, GCTime, GCLimit, TimeRef)}. + +terminate(_Reason, State) when ?is_UnConnected(State) -> + ok; +terminate(_Reason, State) -> + Client = ?get_Client(State), + case catch corba_object:is_nil(Client) of + false when ?is_ANY(State) -> + 'CosNotification_Common':disconnect('CosEventComm_PullConsumer', + disconnect_pull_consumer, + Client); + false when ?is_SEQUENCE(State) -> + 'CosNotification_Common':disconnect('CosNotifyComm_SequencePullConsumer', + disconnect_sequence_pull_consumer, + Client); + false when ?is_STRUCTURED(State) -> + 'CosNotification_Common':disconnect('CosNotifyComm_StructuredPullConsumer', + disconnect_structured_pull_consumer, + Client); + _ -> + ok + end. + +%%----------------------------------------------------------- +%%----- CosNotifyChannelAdmin_ProxySupplier attributes ------ +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_MyType' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyType'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyType(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyAdmin' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyAdmin'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyAdmin(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_*et_priority_filter' +%% Type : read/write +%% Returns : +%%----------------------------------------------------------- +'_get_priority_filter'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_PrioFil(State), State}. +'_set_priority_filter'(_OE_THIS, _OE_FROM, State, PrioF) -> + {reply, ok, ?set_PrioFil(State, PrioF)}. + + +%%----------------------------------------------------------% +%% Attribute: '_*et_lifetime_filter' +%% Type : read/write +%% Returns : +%%----------------------------------------------------------- +'_get_lifetime_filter'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_LifeTFil(State), State}. +'_set_lifetime_filter'(_OE_THIS, _OE_FROM, State, LifeTF) -> + {reply, ok, ?set_LifeTFil(State, LifeTF)}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----- CosEventChannelAdmin::ProxyPullSupplier ------------- +%%----------------------------------------------------------% +%% function : connect_pull_consumer +%% Arguments: Client - CosEventComm::PullConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%% Both exceptions from CosEventChannelAdmin!!! +%%----------------------------------------------------------- +connect_pull_consumer(OE_THIS, OE_FROM, State, Client) -> + connect_any_pull_consumer(OE_THIS, OE_FROM, State, Client). + +%%----- CosNotifyChannelAdmin::ProxyPullSupplier ------------ +%%----------------------------------------------------------% +%% function : connect_any_pull_consumer +%% Arguments: Client - CosEventComm::PullConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%% Both exceptions from CosEventChannelAdmin!!! +%%----------------------------------------------------------- +connect_any_pull_consumer(_OE_THIS, _OE_FROM, State, Client) when ?is_ANY(State) -> + ?not_TypeCheck(Client, 'CosEventComm_PullConsumer'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, ?set_Client(State, Client)} + end; +connect_any_pull_consumer(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::SequenceProxyPullSupplier ---- +%%----------------------------------------------------------% +%% function : connect_sequence_pull_consumer +%% Arguments: Client - CosNotifyComm::SequencePullConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%%----------------------------------------------------------- +connect_sequence_pull_consumer(_OE_THIS, _OE_FROM, State, Client) when ?is_SEQUENCE(State) -> + ?not_TypeCheck(Client, 'CosNotifyComm_SequencePullConsumer'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, ?set_Client(State, Client)} + end; +connect_sequence_pull_consumer(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::StructuredProxyPullSupplier -- +%%----------------------------------------------------------% +%% function : connect_structured_pull_consumer +%% Arguments: Client - CosNotifyComm::StructuredPullConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%%----------------------------------------------------------- +connect_structured_pull_consumer(_OE_THIS, _OE_FROM, State, Client) when ?is_STRUCTURED(State) -> + ?not_TypeCheck(Client, 'CosNotifyComm_StructuredPullConsumer'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, ?set_Client(State, Client)} + end; +connect_structured_pull_consumer(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- Inherit from CosNotifyChannelAdmin::ProxySupplier --- +%%----------------------------------------------------------% +%% function : obtain_offered_types +%% Arguments: Mode - enum 'ObtainInfoMode' (CosNotifyChannelAdmin) +%% Returns : CosNotification::EventTypeSeq +%%----------------------------------------------------------- +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_OFF') -> + {reply, ?get_AllSubscribe(State), ?set_SubscribeType(State, false)}; +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_ON') -> + {reply, ?get_AllSubscribe(State), ?set_SubscribeType(State, true)}; +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_OFF') -> + {reply, [], ?set_SubscribeType(State, false)}; +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_ON') -> + {reply, [], ?set_SubscribeType(State, true)}; +obtain_offered_types(_,_,_,What) -> + orber:dbg("[~p] PullerSupplier:obtain_offered_types(~p);~n" + "Incorrect enumerant", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : validate_event_qos +%% Arguments: RequiredQoS - CosNotification::QoSProperties +%% Returns : ok | {'EXCEPTION', #'UnsupportedQoS'{}} +%% AvilableQoS - CosNotification::NamedPropertyRangeSeq (out) +%%----------------------------------------------------------- +validate_event_qos(_OE_THIS, _OE_FROM, State, RequiredQoS) -> + AvilableQoS = 'CosNotification_Common':validate_event_qos(RequiredQoS, + ?get_LocalQoS(State)), + {reply, {ok, AvilableQoS}, State}. + +%%----- Inherit from CosNotification::QoSAdmin -------------- +%%----------------------------------------------------------% +%% function : get_qos +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +get_qos(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalQoS(State), State}. + +%%----------------------------------------------------------% +%% function : set_qos +%% Arguments: QoS - CosNotification::QoSProperties, i.e., +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +set_qos(_OE_THIS, _OE_FROM, State, QoS) -> + {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + NewState = ?update_EventDB(State, LQS), + {reply, ok, ?set_BothQoS(NewState, NewQoS, LQS)}. + +%%----------------------------------------------------------% +%% function : validate_qos +%% Arguments: Required_qos - CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS} +%% {ok, CosNotification::NamedPropertyRangeSeq} +%%----------------------------------------------------------- +validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) -> + QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + {reply, {ok, QoS}, State}. + +%%----- Inherit from CosNotifyComm::NotifySubscribe --------- +%%----------------------------------------------------------% +%% function : subscription_change +%% Arguments: Added - Removed - CosNotification::EventTypeSeq +%% Returns : ok +%%----------------------------------------------------------- +subscription_change(_OE_THIS, _OE_FROM, State, Added, Removed) -> + cosNotification_Filter:validate_types(Added), + cosNotification_Filter:validate_types(Removed), + %% On this "side", we care about which type of events the client + %% will require, since the client (or an agent) clearly stated + %% that it's only interested in these types of events. + %% Also see PusherConsumer- and PullerConsumer-'offer_change'. + update_subscribe(remove, State, Removed), + CurrentSub = ?get_AllSubscribe(State), + NewState = + case cosNotification_Filter:check_types(Added++CurrentSub) of + true -> + %% Types supplied does in some way cause all events to be valid. + %% Smart? Would have been better to not supply any at all. + ?set_SubscribeData(State, true); + {ok, Which, WC} -> + ?set_SubscribeData(State, {Which, WC}) + end, + update_subscribe(add, NewState, Added), + case ?get_SubscribeType(NewState) of + true -> + %% Perhaps we should handle exception here?! + %% Probably not. Better to stay "on-line". + catch 'CosNotifyComm_NotifyPublish': + offer_change(?get_Client(NewState), Added, Removed), + ok; + _-> + ok + end, + {reply, ok, NewState}. + +update_subscribe(_, _, [])-> + ok; +update_subscribe(add, State, [H|T]) -> + ?add_Subscribe(State, H), + update_subscribe(add, State, T); +update_subscribe(remove, State, [H|T]) -> + ?del_Subscribe(State, H), + update_subscribe(remove, State, T). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ----------- +%%----------------------------------------------------------% +%% function : add_filter +%% Arguments: Filter - CosNotifyFilter::Filter +%% Returns : FilterID - long +%%----------------------------------------------------------- +add_filter(_OE_THIS, _OE_FROM, State, Filter) -> + 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'), + FilterID = ?new_Id(State), + NewState = ?set_IdCounter(State, FilterID), + {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}. + +%%----------------------------------------------------------% +%% function : remove_filter +%% Arguments: FilterID - long +%% Returns : ok +%%----------------------------------------------------------- +remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ok, ?del_Filter(State, FilterID)}; +remove_filter(_,_,_,What) -> + orber:dbg("[~p] PullerSupplier:remove_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_filter +%% Arguments: FilterID - long +%% Returns : Filter - CosNotifyFilter::Filter | +%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}} +%%----------------------------------------------------------- +get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ?get_Filter(State, FilterID), State}; +get_filter(_,_,_,What) -> + orber:dbg("[~p] PullerSupplier:get_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_all_filters +%% Arguments: - +%% Returns : Filter - CosNotifyFilter::FilterIDSeq +%%----------------------------------------------------------- +get_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_AllFilterID(State), State}. + +%%----------------------------------------------------------% +%% function : remove_all_filters +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ok, ?del_AllFilter(State)}. + +%%----- Inherit from CosEventComm::PullSupplier ------------- +%%----------------------------------------------------------% +%% function : disconnect_pull_supplier +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_pull_supplier(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----------------------------------------------------------% +%% function : pull +%% Arguments: - +%% Returns : any - CORBA::ANY +%%----------------------------------------------------------- +pull(_OE_THIS, OE_FROM, State) when ?is_ANY(State) -> + case ?get_Event(State) of + {[], _} -> + {noreply, ?set_RespondTo(State, OE_FROM)}; + {Event,_} -> + {reply, Event, State} + end; +pull(_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : try_pull +%% Arguments: - +%% Returns : any - CORBA::ANY +%% HasEvent - boolean (out-type) +%%----------------------------------------------------------- +try_pull(_OE_THIS, _OE_FROM, State) when ?is_ANY(State) -> + case ?get_Event(State) of + {[], _} -> + {reply, {any:create(orber_tc:null(), null), false}, State}; + {Event, Bool} -> + {reply, {Event, Bool}, State} + end; +try_pull(_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- Inherit from CosNotifyComm::SequencePullSupplier ---- +%%----------------------------------------------------------% +%% function : disconnect_sequence_pull_supplier +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_sequence_pull_supplier(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----------------------------------------------------------% +%% function : pull_structured_events +%% Arguments: Max - long() +%% Returns : [StructuredEvent, ..] +%%----------------------------------------------------------- +pull_structured_events(_OE_THIS, OE_FROM, State, Max) when ?is_SEQUENCE(State) -> + case ?is_BatchLimitReached(State, Max) of + true -> + %% This test is not fool-proof; if Events have been stored + %% using StartTime they will still be there but we cannot + %% deliver them anyway. To solve this "problem" would cost! + %% Hence, since it works fine otherwise it will do. + case ?get_Events(State, Max) of + {[], false} -> + NewState = start_timer(State), + {noreply, ?set_RespondTo(NewState, {OE_FROM, Max})}; + {Event,_} -> + {reply, Event, State} + end; + _-> + NewState = start_timer(State), + {noreply, ?set_RespondTo(NewState, {OE_FROM, Max})} + end; +pull_structured_events(_,_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : try_pull_structured_events +%% Arguments: Max - long() +%% Returns : [StructuredEvent, ..] +%% HasEvent - Boolean() +%%----------------------------------------------------------- +try_pull_structured_events(_OE_THIS, _OE_FROM, State, Max) when ?is_SEQUENCE(State) -> + {reply, ?get_Events(State, Max), State}; +try_pull_structured_events(_,_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- Inherit from CosNotifyComm::StructuredPullSupplier -- +%%----------------------------------------------------------% +%% function : disconnect_structured_pull_supplier +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_structured_pull_supplier(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----------------------------------------------------------% +%% function : pull_structured_event +%% Arguments: - +%% Returns : +%%----------------------------------------------------------- +pull_structured_event(_OE_THIS, OE_FROM, State) when ?is_STRUCTURED(State) -> + case ?get_Event(State) of + {[], _} -> + {noreply, ?set_RespondTo(State, OE_FROM)}; + {Event,_} -> + {reply, Event, State} + end; +pull_structured_event(_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : try_pull_structured_event +%% Arguments: - +%% Returns : +%%----------------------------------------------------------- +try_pull_structured_event(_OE_THIS, _OE_FROM, State) when ?is_STRUCTURED(State) -> + case ?get_Event(State) of + {[], _} -> + {reply, + {?not_CreateSE("","","",[],[],any:create(orber_tc:null(), null)), false}, + State}; + {Event, Bool} -> + {reply, {Event, Bool}, State} + end; +try_pull_structured_event(_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + + +%%--------------- LOCAL FUNCTIONS ---------------------------- +find_obj({value, {_, Obj}}) -> Obj; +find_obj(_) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}. + +find_ids(List) -> find_ids(List, []). +find_ids([], Acc) -> Acc; +find_ids([{I,_}|T], Acc) -> find_ids(T, [I|Acc]); +find_ids(_, _) -> corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +%% Delete a single object. +%% The list do not differ, i.e., no filter removed, raise exception. +delete_obj(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{}); +delete_obj(List,_) -> List. + + +%%----------------------------------------------------------- +%% function : callSeq +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callSeq(_OE_THIS, OE_FROM, State, EventsIn, Status) -> + %% We should do something here, i.e., see what QoS this Object offers and + %% act accordingly. + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:validate_event(?get_SubscribeData(State), EventsIn, + ?get_AllFilter(State), + ?get_SubscribeDB(State), + Status) of + {[], _} -> + ?DBG("PROXY NOSUBSCRIPTION SEQUENCE/STRUCTURED: ~p~n",[EventsIn]), + {noreply, State}; + %% Just one event and we got a client waiting => there is no need to store + %% the event, just transform it and pass it on. + {[Event], _} when ?is_ANY(State), ?is_Waiting(State) -> + ?DBG("PROXY RECEIVED SEQUENCE[1]==>ANY: ~p~n",[Event]), + AnyEvent = any:create('CosNotification_StructuredEvent':tc(),Event), + case ?addAndGet_Event(State, AnyEvent) of + {[], _} -> + ?DBG("PROXY RECEIVED UNDELIVERABLE SEQUENCE[1]: ~p~n", + [Event]), + %% Cannot deliver the event at the moment; perhaps Starttime + %% set or Deadline passed. + {noreply, State}; + {PossiblyOtherEvent, _} -> + ?DBG("PROXY RECEIVED SEQUENCE[1] ~p; DELIVER: ~p~n", + [Event, PossiblyOtherEvent]), + corba:reply(?get_RespondTo(State), PossiblyOtherEvent), + {noreply, ?reset_RespondTo(State)} + end; + {[Event],_} when ?is_STRUCTURED(State), ?is_Waiting(State) -> + case ?addAndGet_Event(State, Event) of + {[], _} -> + ?DBG("PROXY RECEIVED UNDELIVERABLE SEQUENCE[1]: ~p~n", + [Event]), + %% Cannot deliver the event at the moment; perhaps Starttime + %% set or Deadline passed. + {noreply, State}; + {PossiblyOtherEvent, _} -> + ?DBG("PROXY RECEIVED SEQUENCE[1] ~p; DELIVER: ~p~n", + [Event, PossiblyOtherEvent]), + corba:reply(?get_RespondTo(State), PossiblyOtherEvent), + {noreply, ?reset_RespondTo(State)} + end; + %% A sequence of events => store them and extract the first (according to QoS) + %% event and forward it. + {Events,_} when ?is_ANY(State), ?is_Waiting(State) -> + ?DBG("PROXY RECEIVED SEQUENCE==>ANY: ~p~n",[Events]), + store_events(State, Events), + case ?get_Event(State) of + {[], _} -> + {noreply, State}; + {AnyEvent, _} -> + corba:reply(?get_RespondTo(State), AnyEvent), + {noreply, ?reset_RespondTo(State)} + end; + {Events, _} when ?is_STRUCTURED(State), ?is_Waiting(State) -> + ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Events]), + store_events(State, Events), + case ?get_Event(State) of + {[], _} -> + {noreply, State}; + {_StrEvent, _} -> + corba:reply(?get_RespondTo(State), Events), + {noreply, ?reset_RespondTo(State)} + end; + {Events, _} when ?is_SEQUENCE(State), ?is_Waiting(State) -> + ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Events]), + %% Store them first and extract Max events in QoS order. + store_events(State, Events), + {RespondTo, Max} = ?get_RespondTo(State), + case ?is_BatchLimitReached(State, Max) of + true -> + {EventSeq, _} = ?get_Events(State, Max), + corba:reply(RespondTo, EventSeq), + stop_timer(State), + {noreply, ?reset_RespondTo(State)}; + _-> + {noreply, State} + end; + %% No client waiting. Store the event(s). + {Events, _} -> + ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Events]), + store_events(State, Events), + {noreply, State} + end. + +store_events(_State, []) -> + ok; +store_events(State, [Event|Rest]) when ?is_ANY(State) -> + AnyEvent = any:create('CosNotification_StructuredEvent':tc(),Event), + ?add_Event(State,AnyEvent), + store_events(State, Rest); +store_events(State, [Event|Rest]) -> + ?add_Event(State,Event), + store_events(State, Rest). + +%%----------------------------------------------------------- +%% function : callAny +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callAny(_OE_THIS, OE_FROM, State, EventIn, Status) -> + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:validate_event(?get_SubscribeData(State), EventIn, + ?get_AllFilter(State), + ?get_SubscribeDB(State), + Status) of + {[],_} -> + ?DBG("PROXY NOSUBSCRIPTION ANY: ~p~n",[EventIn]), + {noreply, State}; + {Event,_} when ?is_ANY(State), ?is_Waiting(State) -> + ?DBG("PROXY RECEIVED ANY: ~p~n",[Event]), + case ?addAndGet_Event(State, Event) of + {[],_} -> + %% Unable to deliver the event (Starttime, Deadline etc). + {noreply, State}; + {MaybeOtherEvent , _} -> + corba:reply(?get_RespondTo(State), MaybeOtherEvent), + {noreply, ?reset_RespondTo(State)} + end; + {Event,_} when ?is_ANY(State) -> + ?DBG("PROXY RECEIVED ANY: ~p~n",[Event]), + ?add_Event(State,Event), + {noreply, State}; + {Event,_} when ?is_STRUCTURED(State), ?is_Waiting(State) -> + ?DBG("PROXY RECEIVED ANY==>STRUCTURED: ~p~n",[Event]), + case ?addAndGet_Event(State, ?not_CreateSE("","%ANY","",[],[],Event)) of + {[],_} -> + %% Unable to deliver the event (Starttime, Deadline etc). + {noreply, State}; + {MaybeOtherEvent , _} -> + corba:reply(?get_RespondTo(State), MaybeOtherEvent), + {noreply, ?reset_RespondTo(State)} + end; + {Event,_} when ?is_SEQUENCE(State), ?is_Waiting(State) -> + ?DBG("PROXY RECEIVED ANY==>SEQUENCE[1]: ~p~n",[Event]), + ?add_Event(State,?not_CreateSE("","%ANY","",[],[],Event)), + {RespondTo, Max} = ?get_RespondTo(State), + case ?is_BatchLimitReached(State, Max) of + true -> + {EventSeq, _} = ?get_Events(State, Max), + corba:reply(RespondTo, EventSeq), + stop_timer(State), + {noreply, ?reset_RespondTo(State)}; + _ -> + {noreply, State} + end; + {Event,_} -> + ?DBG("PROXY RECEIVED ANY==>STRUCTURED/SEQUENCE: ~p~n",[Event]), + ?add_Event(State,?not_CreateSE("","%ANY","",[],[],Event)), + {noreply, State} + end. + + + +%% Start timers which send a message each time we should push events. Only used +%% when this objects is defined to supply sequences. +start_timer(State) -> + TS = now(), + case catch timer:send_after(timer:seconds(?get_PacingInterval(State)), + {pacing, TS}) of + {ok,PacTRef} -> + ?DBG("PULL SUPPLIER STARTED TIMER, BATCH LIMIT: ~p~n", + [?get_BatchLimit(State)]), + ?set_PacingTimer(State, {PacTRef, TS}); + What -> + orber:dbg("[~p] PullerSupplier:start_timer();~n" + "Unable to invoke timer:send_interval/2: ~p", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +stop_timer(State) -> + case ?get_PacingTimer(State) of + undefined -> + ok; + {Timer, _} -> + ?DBG("PULL SUPPLIER STOPPED TIMER~n",[]), + timer:cancel(Timer) + end. + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/PusherConsumer_impl.erl b/lib/cosNotification/src/PusherConsumer_impl.erl new file mode 100644 index 0000000000..195e81ec58 --- /dev/null +++ b/lib/cosNotification/src/PusherConsumer_impl.erl @@ -0,0 +1,729 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : PusherConsumer_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('PusherConsumer_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% cosEvent files. +-include_lib("cosEvent/include/CosEventChannelAdmin.hrl"). +-include_lib("cosEvent/include/CosEventComm.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). + +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%%----- CosNotifyChannelAdmin::ProxyPushConsumer ------------- +-export([connect_any_push_supplier/4]). + +%%----- CosNotifyChannelAdmin::SequenceProxyPushConsumer ----- +-export([connect_sequence_push_supplier/4]). + +%%----- CosNotifyChannelAdmin::StructuredProxyPushConsumer --- +-export([connect_structured_push_supplier/4]). + +%%----- Inherit from CosNotifyChannelAdmin::ProxyConsumer ---- +-export([obtain_subscription_types/4, + validate_event_qos/4]). + +%%----- Inherit from CosNotification::QoSAdmin --------------- +-export([get_qos/3, + set_qos/4, + validate_qos/4]). + +%%----- Inherit from CosNotifyComm::NotifyPublish ------------ +-export([offer_change/5]). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ------------ +-export([add_filter/4, + remove_filter/4, + get_filter/4, + get_all_filters/3, + remove_all_filters/3]). + +%%----- Inherit from CosEventComm::PushConsumer ------------- +-export([push/4, + disconnect_push_consumer/3]). + +%%----- Inherit from CosNotifyComm::SequencePushConsumer ---- +-export([push_structured_events/4, + disconnect_sequence_push_consumer/3]). + +%%----- Inherit from CosNotifyComm::StructuredPushConsumer -- +-export([push_structured_event/4, + disconnect_structured_push_consumer/3]). + +%%----- Inherit from CosEventChannelAdmin::ProxyPushConsumer +-export([connect_push_supplier/4]). + +%% Attributes (external) CosNotifyChannelAdmin::ProxySupplier +-export(['_get_MyType'/3, + '_get_MyAdmin'/3]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {myType, + myAdmin, + myAdminPid, + myChannel, + myFilters = [], + myOperator, + idCounter = 0, + client, + qosGlobal, + qosLocal, + publishType = false, + etsR, + eventDB}). + +%% Data structures constructors +-define(get_InitState(_MyT, _MyA, _MyAP, _QS, _LQS, _Ch, _EDB, _MyOP), + #state{myType = _MyT, + myAdmin = _MyA, + myAdminPid= _MyAP, + myChannel = _Ch, + myOperator= _MyOP, + qosGlobal = _QS, + qosLocal = _LQS, + etsR = ets:new(oe_ets, [set, protected]), + eventDB = _EDB}). + +%%-------------- Data structures selectors ----------------- +%% Attributes +-define(get_MyType(S), S#state.myType). +-define(get_MyAdmin(S), S#state.myAdmin). +-define(get_MyAdminPid(S), S#state.myAdminPid). +-define(get_MyChannel(S), S#state.myChannel). +-define(get_MyOperator(S), S#state.myOperator). +%% Client Object +-define(get_Client(S), S#state.client). +%% QoS +-define(get_GlobalQoS(S), S#state.qosGlobal). +-define(get_LocalQoS(S), S#state.qosLocal). +-define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}). +%% Filters +-define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters))). +-define(get_AllFilter(S), S#state.myFilters). +-define(get_AllFilterID(S), find_ids(S#state.myFilters)). +%% Publish +-define(get_AllPublish(S), lists:flatten(ets:match(S#state.etsR, + {'$1',publish}))). +-define(get_PublishType(S), S#state.publishType). +%% ID +-define(get_IdCounter(S), S#state.idCounter). +%% Event +-define(get_Event(S), cosNotification_eventDB:get_event(S#state.eventDB)). +-define(get_Events(S,M), cosNotification_eventDB:get_events(S#state.eventDB, M)). + +-define(get_EventCounter(S), S#state.eventCounter). +%% Admin +-define(get_BatchLimit(S), ?not_GetMaximumBatchSize((S#state.qosLocal))). + +%%-------------- Data structures modifiers ----------------- +%% Client Object +-define(set_Client(S,D), S#state{client=D}). +-define(del_Client(S), S#state{client=undefined}). +-define(set_Unconnected(S), S#state{client=undefined}). +%% QoS +-define(set_LocalQoS(S,D), S#state{qosLocal=D}). +-define(set_GlobalQoS(S,D), S#state{qosGlobal=D}). +-define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}). +%% Filters +-define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}). +-define(del_Filter(S,I), S#state{myFilters= + delete_obj(lists:keydelete(I, 1, S#state.myFilters), + S#state.myFilters)}). +-define(del_AllFilter(S), S#state{myFilters=[]}). +%% Publish +-define(add_Publish(S,E), ets:insert(S#state.etsR, {E, publish})). +-define(del_Publish(S,E), ets:delete(S#state.etsR, E)). +-define(set_PublishType(S,T), S#state{publishType=T}). +%% ID +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). +%% Event +-define(add_Event(S,E), cosNotification_eventDB:add_event(S#state.eventDB, E)). +-define(update_EventDB(S,Q), S#state{eventDB= + cosNotification_eventDB:update(S#state.eventDB, Q)}). + +-define(set_EventCounter(S,V), S#state{eventCounter=V}). +-define(add_to_EventCounter(S,V),S#state{eventCounter=S#state.eventCounter+V}). +-define(reset_EventCounter(S), S#state{eventCounter=0}). +-define(increase_EventCounter(S),S#state{eventCounter=(S#state.eventCounter+1)}). +-define(decrease_EventCounter(S),S#state{eventCounter=S#state.eventCounter-1}). +-define(add_ToEventCounter(S,A), S#state{eventCounter=(S#state.eventCounter+A)}). +-define(sub_FromEventCounter(S,_A), S#state{eventCounter=(S#state.eventCounter-_A)}). +-define(set_EventCounterTo(S,V), S#state{eventCounter=V}). + +%% MISC +-define(is_ANY(S), S#state.myType == 'PUSH_ANY'). +-define(is_STRUCTURED(S), S#state.myType == 'PUSH_STRUCTURED'). +-define(is_SEQUENCE(S), S#state.myType == 'PUSH_SEQUENCE'). +-define(is_ANDOP(S), S#state.myOperator == 'AND_OP'). +-define(is_UnConnected(S), S#state.client == undefined). +-define(is_Connected(S), S#state.client =/= undefined). +-define(is_PersistentConnection(S), + ?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent). +-define(is_PersistentEvent(S), + ?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent). +-define(is_BatchLimitReached(S), S#state.eventCounter >= + ?not_GetMaximumBatchSize((S#state.qosLocal))). + + +%%----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%----------------------------------------------------------- + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + ?DBG("INFO: ~p~n", [Info]), + case Info of + {'EXIT', Pid, Reason} when ?get_MyAdminPid(State)==Pid-> + ?DBG("PARENT ADMIN: ~p TERMINATED.~n",[Reason]), + {stop, Reason, State}; + {'EXIT', _Pid, _Reason} -> + ?DBG("PROXYPUSHCONSUMER: ~p TERMINATED.~n",[_Reason]), + {noreply, State}; + _ -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init(['PUSH_SEQUENCE', MyAdmin, MyAdminPid, InitQoS, LQS, + MyChannel, Options, Operator]) -> + process_flag(trap_exit, true), + %% Only if MyType is 'PUSH_SEQUENCE' we need an ets to store events in. + %% Otherwise we'll forward them at once. Why? We don't know when the next event + %% is due. + GCTime = 'CosNotification_Common':get_option(gcTime, Options, + ?not_DEFAULT_SETTINGS), + GCLimit = 'CosNotification_Common':get_option(gcLimit, Options, + ?not_DEFAULT_SETTINGS), + TimeRef = 'CosNotification_Common':get_option(timeService, Options, + ?not_DEFAULT_SETTINGS), + {ok, ?get_InitState('PUSH_SEQUENCE', MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, + cosNotification_eventDB:create_db(LQS, GCTime, GCLimit, TimeRef), + Operator)}; +init([MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, _Options, Operator]) -> + process_flag(trap_exit, true), + {ok, ?get_InitState(MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, + undefined, Operator)}. + +terminate(_Reason, State) when ?is_UnConnected(State) -> + ok; +terminate(_Reason, State) -> + Client = ?get_Client(State), + case catch corba_object:is_nil(Client) of + false when ?is_ANY(State) -> + 'CosNotification_Common':disconnect('CosEventComm_PushSupplier', + disconnect_push_supplier, + Client); + false when ?is_SEQUENCE(State) -> + 'CosNotification_Common':disconnect('CosNotifyComm_SequencePushSupplier', + disconnect_sequence_push_supplier, + Client); + false when ?is_STRUCTURED(State) -> + 'CosNotification_Common':disconnect('CosNotifyComm_StructuredPushSupplier', + disconnect_structured_push_supplier, + Client); + _ -> + ok + end. + +%%----------------------------------------------------------- +%%----- CosNotifyChannelAdmin_ProxyConsumer attributes ------ +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_MyType' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyType'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyType(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyAdmin' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyAdmin'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyAdmin(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----- CosEventChannelAdmin::ProxyPushConsumer ------------- +%%----------------------------------------------------------% +%% function : connect_push_supplier +%% Arguments: Client - CosEventComm::PushSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%% Both exceptions from CosEventChannelAdmin!!! +%%----------------------------------------------------------- +connect_push_supplier(OE_THIS, OE_FROM, State, Client) -> + connect_any_push_supplier(OE_THIS, OE_FROM, State, Client). + +%%----- CosNotifyChannelAdmin::ProxyPushConsumer ------------ +%%----------------------------------------------------------% +%% function : connect_any_push_supplier +%% Arguments: Client - CosEventComm::PushSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%% Both exceptions from CosEventChannelAdmin!!! +%%----------------------------------------------------------- +connect_any_push_supplier(_OE_THIS, _OE_FROM, State, Client) when ?is_ANY(State) -> + ?not_TypeCheck(Client, 'CosEventComm_PushSupplier'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, ?set_Client(State, Client)} + end; +connect_any_push_supplier(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::SequenceProxyPushConsumer ---- +%%----------------------------------------------------------% +%% function : connect_sequence_push_supplier +%% Arguments: Client - CosNotifyComm::SequencePushSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%%----------------------------------------------------------- +connect_sequence_push_supplier(_OE_THIS, _OE_FROM, State, Client) when ?is_SEQUENCE(State) -> + ?not_TypeCheck(Client, 'CosNotifyComm_SequencePushSupplier'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, ?set_Client(State, Client)} + end; +connect_sequence_push_supplier(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::StructuredProxyPushConsumer -- +%%----------------------------------------------------------% +%% function : connect_structured_push_supplier +%% Arguments: Client - CosNotifyComm::StructuredPushSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%%----------------------------------------------------------- +connect_structured_push_supplier(_OE_THIS, _OE_FROM, State, Client) when ?is_STRUCTURED(State) -> + ?not_TypeCheck(Client, 'CosNotifyComm_StructuredPushSupplier'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, ?set_Client(State, Client)} + end; +connect_structured_push_supplier(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- Inherit from CosNotifyChannelAdmin::ProxyConsumer --- +%%----------------------------------------------------------% +%% function : obtain_subscription_types +%% Arguments: Mode - enum 'ObtainInfoMode' (CosNotifyChannelAdmin) +%% Returns : CosNotification::EventTypeSeq +%%----------------------------------------------------------- +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_OFF') -> + {reply, ?get_AllPublish(State), ?set_PublishType(State, false)}; +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_ON') -> + {reply, ?get_AllPublish(State), ?set_PublishType(State, true)}; +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_OFF') -> + {reply, [], ?set_PublishType(State, false)}; +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_ON') -> + {reply, [], ?set_PublishType(State, true)}; +obtain_subscription_types(_,_,_,What) -> + orber:dbg("[~p] PusherConsumer:obtain_subscription_types(~p);~n" + "Incorrect enumerant", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : validate_event_qos +%% Arguments: RequiredQoS - CosNotification::QoSProperties +%% Returns : ok | {'EXCEPTION', #'UnsupportedQoS'{}} +%% AvilableQoS - CosNotification::NamedPropertyRangeSeq (out) +%%----------------------------------------------------------- +validate_event_qos(_OE_THIS, _OE_FROM, State, RequiredQoS) -> + AvilableQoS = 'CosNotification_Common':validate_event_qos(RequiredQoS, + ?get_LocalQoS(State)), + {reply, {ok, AvilableQoS}, State}. + +%%----- Inherit from CosNotification::QoSAdmin -------------- +%%----------------------------------------------------------% +%% function : get_qos +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +get_qos(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalQoS(State), State}. + +%%----------------------------------------------------------% +%% function : set_qos +%% Arguments: QoS - CosNotification::QoSProperties, i.e., +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +set_qos(_OE_THIS, _OE_FROM, State, QoS) -> + {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + NewState = ?update_EventDB(State, LQS), + {reply, ok, ?set_BothQoS(NewState, NewQoS, LQS)}. + +%%----------------------------------------------------------% +%% function : validate_qos +%% Arguments: Required_qos - CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS} +%% {ok, CosNotification::NamedPropertyRangeSeq} +%%----------------------------------------------------------- +validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) -> + QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + {reply, {ok, QoS}, State}. + +%%----- Inherit from CosNotifyComm::NotifyPublish ----------- +%%----------------------------------------------------------% +%% function : offer_change +%% Arguments: Added - #'CosNotification_EventType'{} +%% Removed - #'CosNotification_EventType'{} +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyComm_InvalidEventType'{}} +%%----------------------------------------------------------- +offer_change(_OE_THIS, _OE_FROM, State, Added, Removed) -> + cosNotification_Filter:validate_types(Added), + cosNotification_Filter:validate_types(Removed), + %% On this "side" we don't really care about which + %% type of events the client will supply. + %% Perhaps, later on, if we want to check this against Filters + %% associated with this object we may change this approach, i.e., if + %% the filter will not allow passing certain event types. But the + %% user should see to that that situation never occurs. It would add + %% extra overhead. Also see PusherSupplier- and PullerSuppler- + %% 'subscription_change'. + update_publish(add, State, Added), + update_publish(remove, State, Removed), + case ?get_PublishType(State) of + true -> + %% Perhaps we should handle exception here?! + %% Probably not. Better to stay "on-line". + catch 'CosNotifyComm_NotifySubscribe': + subscription_change(?get_Client(State), Added, Removed), + ok; + _-> + ok + end, + {reply, ok, State}. + +update_publish(_, _, [])-> + ok; +update_publish(add, State, [H|T]) -> + ?add_Publish(State, H), + update_publish(add, State, T); +update_publish(remove, State, [H|T]) -> + ?del_Publish(State, H), + update_publish(remove, State, T). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ----------- +%%----------------------------------------------------------% +%% function : add_filter +%% Arguments: Filter - CosNotifyFilter::Filter +%% Returns : FilterID - long +%%----------------------------------------------------------- +add_filter(_OE_THIS, _OE_FROM, State, Filter) -> + 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'), + FilterID = ?new_Id(State), + NewState = ?set_IdCounter(State, FilterID), + {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}. + +%%----------------------------------------------------------% +%% function : remove_filter +%% Arguments: FilterID - long +%% Returns : ok +%%----------------------------------------------------------- +remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ok, ?del_Filter(State, FilterID)}; +remove_filter(_,_,_,What) -> + orber:dbg("[~p] PusherConsumer:remove_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_filter +%% Arguments: FilterID - long +%% Returns : Filter - CosNotifyFilter::Filter | +%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}} +%%----------------------------------------------------------- +get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ?get_Filter(State, FilterID), State}; +get_filter(_,_,_,What) -> + orber:dbg("[~p] PusherConsumer:get_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_all_filters +%% Arguments: - +%% Returns : Filter - CosNotifyFilter::FilterIDSeq +%%----------------------------------------------------------- +get_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_AllFilterID(State), State}. + +%%----------------------------------------------------------% +%% function : remove_all_filters +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ok, ?del_AllFilter(State)}. + +%%----- Inherit from CosEventComm::PushConsumer ------------- +%%----------------------------------------------------------% +%% function : disconnect_push_consumer +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_push_consumer(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----------------------------------------------------------% +%% function : push +%% Arguments: AnyEvent +%% Returns : ok | +%%----------------------------------------------------------- +push(OE_THIS, OE_FROM, State, Event) when ?is_ANY(State) -> + corba:reply(OE_FROM, ok), + case {?not_isConvertedStructured(Event), + cosNotification_eventDB:filter_events([Event], ?get_AllFilter(State))} of + {_, {[],_}} when ?is_ANDOP(State) -> + {noreply, State}; + {true, {[],[_]}} -> + %% Is OR and converted, change back and forward to Admin + forward(seq, ?get_MyAdmin(State), State, [any:get_value(Event)], + 'MATCH', OE_THIS); + {_, {[],[_]}} -> + %% Is OR and not converted, forward to Admin + forward(any, ?get_MyAdmin(State), State, Event, 'MATCH', OE_THIS); + {true, {[_],_}} when ?is_ANDOP(State) -> + %% Is AND and converted, change back and forward to Admin + forward(seq, ?get_MyAdmin(State), State, [any:get_value(Event)], + 'MATCH', OE_THIS); + {true, {[_],_}} -> + %% Is OR and converted, change back and forward to Channel + forward(seq, ?get_MyChannel(State), State, [any:get_value(Event)], + 'MATCHED', OE_THIS); + {_, {[_],_}} when ?is_ANDOP(State) -> + %% Is AND and not converted, forward to Admin + forward(any, ?get_MyAdmin(State), State, Event, 'MATCH', OE_THIS); + _ -> + %% Is OR and not converted, forward to Channel + forward(any, ?get_MyChannel(State), State, Event, 'MATCHED', OE_THIS) + end; +push(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- Inherit from CosNotifyComm::SequencePushConsumer ---- +%%----------------------------------------------------------% +%% function : disconnect_sequence_push_consumer +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_sequence_push_consumer(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----------------------------------------------------------% +%% function : push_structured_events +%% Arguments: CosNotification::EventBatch +%% Returns : ok | +%%----------------------------------------------------------- +push_structured_events(OE_THIS, OE_FROM, State, Events) when ?is_SEQUENCE(State) -> + corba:reply(OE_FROM, ok), + %% We cannot convert parts of the sequence to any, event though they + %% are converted from any to structured. Would be 'impossible' to send. + case cosNotification_eventDB:filter_events(Events, ?get_AllFilter(State)) of + {[],_} when ?is_ANDOP(State) -> + {noreply, State}; + {[],Failed} -> + forward(seq, ?get_MyAdmin(State), State, Failed, 'MATCH', OE_THIS); + {Passed, _} when ?is_ANDOP(State) -> + forward(seq, ?get_MyAdmin(State), State, Passed, 'MATCH', OE_THIS); + {Passed, []} -> + forward(seq, ?get_MyChannel(State), State, Passed, 'MATCHED', OE_THIS); + {Passed, Failed} -> + %% Is OR, send Passed to channel and Failed to Admin. + forward(seq, ?get_MyChannel(State), State, Passed, 'MATCHED', OE_THIS), + forward(seq, ?get_MyAdmin(State), State, Failed, 'MATCH', OE_THIS) + end; +push_structured_events(_,_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- Inherit from CosNotifyComm::StructuredPushConsumer -- +%%----------------------------------------------------------% +%% function : disconnect_structured_push_consumer +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_structured_push_consumer(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----------------------------------------------------------% +%% function : push_structured_event +%% Arguments: CosNotification::StructuredEvent +%% Returns : ok | +%%----------------------------------------------------------- +push_structured_event(OE_THIS, OE_FROM, State, Event) when ?is_STRUCTURED(State) -> + corba:reply(OE_FROM, ok), + case {?not_isConvertedAny(Event), + cosNotification_eventDB:filter_events([Event], ?get_AllFilter(State))} of + {_, {[],_}} when ?is_ANDOP(State) -> + {noreply, State}; + {true, {[],[_]}} -> + %% Is OR and converted, change back and forward to Admin + forward(any, ?get_MyAdmin(State), State, + Event#'CosNotification_StructuredEvent'.remainder_of_body, + 'MATCH', OE_THIS); + {_, {[],[_]}} -> + %% Is OR and not converted, forward to Admin + forward(seq, ?get_MyAdmin(State), State, [Event], 'MATCH', OE_THIS); + {true, {[_],_}} when ?is_ANDOP(State) -> + %% Is AND and converted, change back and forward to Admin + forward(any, ?get_MyAdmin(State), State, + Event#'CosNotification_StructuredEvent'.remainder_of_body, + 'MATCH', OE_THIS); + {true, {[_],_}} -> + %% Is OR and converted, change back and forward to Channel + forward(any, ?get_MyChannel(State), State, + Event#'CosNotification_StructuredEvent'.remainder_of_body, + 'MATCHED', OE_THIS); + {_, {[_],_}} when ?is_ANDOP(State) -> + %% Is AND and not converted, forward to Admin + forward(seq, ?get_MyAdmin(State), State, [Event], 'MATCH', OE_THIS); + _ -> + %% Is OR and not converted, forward to Channel + forward(seq, ?get_MyChannel(State), State, [Event], 'MATCHED', OE_THIS) + end; +push_structured_event(_,_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%--------------- LOCAL FUNCTIONS ---------------------------- +find_obj({value, {_, Obj}}) -> Obj; +find_obj(_) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}. + +find_ids(List) -> find_ids(List, []). +find_ids([], Acc) -> Acc; +find_ids([{I,_}|T], Acc) -> find_ids(T, [I|Acc]); +find_ids(What, _) -> + orber:dbg("[~p] PusherConsumer:find_ids();~n" + "Id corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +%% Delete a single object. +%% The list don not differ, i.e., no filter removed, raise exception. +delete_obj(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{}); +delete_obj(List,_) -> List. + +%% Forward events +forward(any, SendTo, State, Event, Status, OE_THIS) -> + case catch oe_CosNotificationComm_Event:callAny(SendTo, Event, Status) of + ok -> + ?DBG("PROXY FORWARD ANY: ~p~n",[Event]), + {noreply, State}; + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + orber:dbg("[~p] PusherConsumer:forward();~n" + "Admin/Channel no longer exists; terminating and dropping: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, OE_THIS}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] PusherConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL), + {noreply, State}; + R -> + orber:dbg("[~p] PusherConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, R, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, OE_THIS}, + {client, ?get_Client(State)}, + {reason, R}]), + {stop, normal, State} + end; +forward(seq, SendTo, State, Event, Status, OE_THIS) -> + case catch oe_CosNotificationComm_Event:callSeq(SendTo, Event, Status) of + ok -> + {noreply, State}; + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + ?DBG("ADMIN NO LONGER EXIST; DROPPING: ~p~n", [Event]), + 'CosNotification_Common':notify([{proxy, OE_THIS}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] PusherConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL), + {noreply, State}; + R -> + orber:dbg("[~p] PusherConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, R, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, OE_THIS}, + {client, ?get_Client(State)}, + {reason, R}]), + {stop, normal, State} + end. + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/PusherSupplier_impl.erl b/lib/cosNotification/src/PusherSupplier_impl.erl new file mode 100644 index 0000000000..51949b8c46 --- /dev/null +++ b/lib/cosNotification/src/PusherSupplier_impl.erl @@ -0,0 +1,1052 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : PusherSupplier_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('PusherSupplier_impl'). + + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% cosEvent files. +-include_lib("cosEvent/include/CosEventChannelAdmin.hrl"). +-include_lib("cosEvent/include/CosEventComm.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). + +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%%----- CosNotifyChannelAdmin::ProxyPushSupplier ------------- +-export([connect_any_push_consumer/4]). + +%%----- CosNotifyChannelAdmin::StructuredProxyPushSupplier --- +-export([connect_structured_push_consumer/4]). + +%%----- CosNotifyChannelAdmin::SequenceProxyPushSupplier ----- +-export([connect_sequence_push_consumer/4]). + +%%----- CosNotifyChannelAdmin::*ProxyPushSupplier ------------ +-export([suspend_connection/3, + resume_connection/3]). + +%%----- Inherit from CosNotifyChannelAdmin::ProxySupplier ---- +-export([obtain_offered_types/4, + validate_event_qos/4]). + +%%----- Inherit from CosNotification::QoSAdmin --------------- +-export([get_qos/3, + set_qos/4, + validate_qos/4]). + +%%----- Inherit from CosNotifyComm::NotifySubscribe ---------- +-export([subscription_change/5]). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ------------ +-export([add_filter/4, + remove_filter/4, + get_filter/4, + get_all_filters/3, + remove_all_filters/3]). + +%%----- Inherit from CosEventComm::PushSupplier ------------- +-export([disconnect_push_supplier/3]). + +%%----- Inherit from CosNotifyComm::StructuredPushSupplier -- +-export([disconnect_structured_push_supplier/3]). + +%%----- Inherit from CosNotifyComm::SequencePushSupplier ---- +-export([disconnect_sequence_push_supplier/3]). + +%%----- Inherit from CosEventChannelAdmin::ProxyPushSupplier +-export([connect_push_consumer/4]). + +%% Attributes (external) CosNotifyChannelAdmin::ProxySupplier +-export(['_get_MyType'/3, + '_get_MyAdmin'/3, + '_get_priority_filter'/3, + '_set_priority_filter'/4, + '_get_lifetime_filter'/3, + '_set_lifetime_filter'/4]). + +%%--------------- Internal ----------------------------------- +%%----- Inherit from cosNotificationComm --------------------- +-export([callAny/5, + callSeq/5]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {myType, + myAdmin, + myAdminPid, + myChannel, + myFilters = [], + myOperator, + idCounter = 0, + prioFil, + lifetFil, + client, + qosGlobal, + qosLocal, + suspended = false, + pacingTimer, + subscribeType = false, + subscribeData = true, + etsR, + eventDB, + this, + maxCache, + cacheTimeout, + cacheInterval}). + +%% Data structures constructors +-define(get_InitState(_MyT, _MyA, _MyAP, _QS, _LQS, _Ch, _MyOp, _GT, _GL, _TR), + #state{myType = _MyT, + myAdmin = _MyA, + myAdminPid= _MyAP, + qosGlobal = _QS, + qosLocal = _LQS, + myChannel = _Ch, + myOperator=_MyOp, + etsR = ets:new(oe_ets, [set, protected]), + eventDB = cosNotification_eventDB:create_db(_LQS, _GT, _GL, _TR), + maxCache = cosNotificationApp:max_events()}). + +%% Data structures selectors +%%-------------- Data structures selectors ----------------- +%% Attributes +-define(get_MyType(S), S#state.myType). +-define(get_MyAdmin(S), S#state.myAdmin). +-define(get_MyAdminPid(S), S#state.myAdminPid). +-define(get_MyChannel(S), S#state.myChannel). +-define(get_MyOperator(S), S#state.myOperator). +-define(get_PrioFil(S), S#state.prioFil). +-define(get_LifeTFil(S), S#state.lifetFil). +%% Client Object +-define(get_Client(S), S#state.client). +%% QoS +-define(get_GlobalQoS(S), S#state.qosGlobal). +-define(get_LocalQoS(S), S#state.qosLocal). +-define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}). +%% Filters +-define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters))). +-define(get_AllFilter(S), S#state.myFilters). +-define(get_AllFilterID(S), find_ids(S#state.myFilters)). +%% Amin +-define(get_PacingTimer(S), S#state.pacingTimer). +-define(get_PacingInterval(S), round(?not_GetPacingInterval((S#state.qosLocal))/10000000)). +-define(get_BatchLimit(S), ?not_GetMaximumBatchSize((S#state.qosLocal))). +%% Subscribe +-define(get_AllSubscribe(S), lists:flatten(ets:match(S#state.etsR, + {'$1',subscribe}))). +-define(get_SubscribeType(S), S#state.subscribeType). +-define(get_SubscribeData(S), S#state.subscribeData). +%% ID +-define(get_IdCounter(S), S#state.idCounter). +-define(get_SubscribeDB(S), S#state.etsR). +%% Event +-define(is_PersistentConnection(S), + (?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent)). +-define(is_PersistentEvent(S), + (?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent)). + +-define(get_Event(S), cosNotification_eventDB:get_event(S#state.eventDB, + false)). +% (not ?is_PersistentEvent(S)))). +-define(get_Events(S,M), cosNotification_eventDB:get_events(S#state.eventDB, M, false)). +% (not ?is_PersistentEvent(S)))). + +%%-------------- Data structures modifiers ----------------- +%% Attributes +-define(set_PrioFil(S,D), S#state{prioFil=D}). +-define(set_LifeTFil(S,D), S#state{lifetFil=D}). +%% Client Object +-define(set_Client(S,D), S#state{client=D}). +-define(del_Client(S), S#state{client=undefined}). +-define(set_Unconnected(S), S#state{client=undefined}). +-define(set_Suspended(S), S#state{suspended=true}). +-define(set_NotSuspended(S), S#state{suspended=false}). +%% QoS +-define(set_LocalQoS(S,D), S#state{qosLocal=D}). +-define(set_GlobalQoS(S,D), S#state{qosGlobal=D}). +-define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}). +%% Filters +-define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}). +-define(del_Filter(S,I), S#state{myFilters= + delete_obj(lists:keydelete(I, 1, S#state.myFilters), + S#state.myFilters)}). +-define(del_AllFilter(S), S#state{myFilters=[]}). +%% Admin +-define(set_PacingTimer(S,T), S#state{pacingTimer=T}). +%% Publish +%% Subscribe +-define(add_Subscribe(S,E), ets:insert(S#state.etsR, {E, subscribe})). +-define(del_Subscribe(S,E), ets:delete(S#state.etsR, E)). +-define(set_SubscribeType(S,T), S#state{subscribeType=T}). +-define(set_SubscribeData(S,D), S#state{subscribeData=D}). +%% ID +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). +%% Events +-define(add_Event(S,E), catch cosNotification_eventDB: + add_event(S#state.eventDB, E, S#state.lifetFil, S#state.prioFil)). +-define(addAndGet_Event(S,E), catch cosNotification_eventDB: + add_and_get_event(S#state.eventDB, E, S#state.lifetFil, S#state.prioFil, + false)). +% ?is_PersistentEvent(S))). +-define(update_EventDB(S,Q), S#state{eventDB= + cosNotification_eventDB:update(S#state.eventDB, Q)}). + + +%%-------------- MISC ---------------------------------------- +-define(is_ANY(S), S#state.myType == 'PUSH_ANY'). +-define(is_STRUCTURED(S), S#state.myType == 'PUSH_STRUCTURED'). +-define(is_SEQUENCE(S), S#state.myType == 'PUSH_SEQUENCE'). +-define(is_ANDOP(S), S#state.myOperator == 'AND_OP'). +-define(is_UnConnected(S), S#state.client == undefined). +-define(is_Connected(S), S#state.client =/= undefined). +-define(is_Suspended(S), S#state.suspended == true). +-define(is_NotSuspended(S), S#state.suspended == false). +-define(is_BatchLimitReached(S), cosNotification_eventDB:status(S#state.eventDB, + {batchLimit, + ?not_GetMaximumBatchSize((S#state.qosLocal))})). +-define(has_Filters(S), S#state.myFilters =/= []). + +%%----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%----------------------------------------------------------- + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, #state{cacheTimeout = Timeout, + cacheInterval = Interval} = State) -> + ?DBG("INFO: ~p~n", [Info]), + case Info of + {'EXIT', Pid, Reason} when ?get_MyAdminPid(State)==Pid -> + ?DBG("PARENT ADMIN: ~p TERMINATED.~n",[Reason]), + {stop, Reason, State}; + {'EXIT', _Pid, _Reason} -> + ?DBG("PROXYPUSHSUPPLIER: ~p TERMINATED.~n",[_Reason]), + {noreply, State}; + pacing -> + lookup_and_push(State, true); + cacheInterval -> + lookup_and_push(State, true); + cacheTimeout when Timeout == undefined, Interval == undefined -> + %% Late message, do not terminate + {noreply, State}; + cacheTimeout -> + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, State#state.client}, + {reason, + {timer, "Reached upper limit"}}]), + {stop, normal, State}; + _ -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, Options, Operator]) -> + process_flag(trap_exit, true), + GCTime = 'CosNotification_Common':get_option(gcTime, Options, + ?not_DEFAULT_SETTINGS), + GCLimit = 'CosNotification_Common':get_option(gcLimit, Options, + ?not_DEFAULT_SETTINGS), + TimeRef = 'CosNotification_Common':get_option(timeService, Options, + ?not_DEFAULT_SETTINGS), + timer:start(), + {ok, ?get_InitState(MyType, MyAdmin, MyAdminPid, + InitQoS, LQS, MyChannel, Operator, GCTime, GCLimit, TimeRef)}. + +terminate(_Reason, State) when ?is_UnConnected(State) -> + stop_timer(State#state.cacheTimeout), + stop_timer(State#state.cacheInterval), + stop_timer(State#state.pacingTimer), + %% We are not connected to a Client. Hence, no need to invoke disconnect. + ok; +terminate(_Reason, State) when ?is_ANY(State) -> + stop_timer(State#state.cacheTimeout), + stop_timer(State#state.cacheInterval), + stop_timer(State#state.pacingTimer), + 'CosNotification_Common':disconnect('CosEventComm_PushConsumer', + disconnect_push_consumer, + ?get_Client(State)); +terminate(_Reason, State) when ?is_SEQUENCE(State) -> + stop_timer(State#state.cacheTimeout), + stop_timer(State#state.cacheInterval), + stop_timer(State#state.pacingTimer), + 'CosNotification_Common':disconnect('CosNotifyComm_SequencePushConsumer', + disconnect_sequence_push_consumer, + ?get_Client(State)); +terminate(_Reason, State) when ?is_STRUCTURED(State) -> + stop_timer(State#state.cacheTimeout), + stop_timer(State#state.cacheInterval), + stop_timer(State#state.pacingTimer), + 'CosNotification_Common':disconnect('CosNotifyComm_StructuredPushConsumer', + disconnect_structured_push_consumer, + ?get_Client(State)). + +%%----------------------------------------------------------- +%%----- CosNotifyChannelAdmin_ProxySupplier attributes ------ +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_MyType' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyType'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyType(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyAdmin' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyAdmin'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyAdmin(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_*et_priority_filter' +%% Type : read/write +%% Returns : +%%----------------------------------------------------------- +'_get_priority_filter'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_PrioFil(State), State}. +'_set_priority_filter'(_OE_THIS, _OE_FROM, State, PrioF) -> + {reply, ok, ?set_PrioFil(State, PrioF)}. + +%%----------------------------------------------------------% +%% Attribute: '_*et_lifetime_filter' +%% Type : read/write +%% Returns : +%%----------------------------------------------------------- +'_get_lifetime_filter'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_LifeTFil(State), State}. +'_set_lifetime_filter'(_OE_THIS, _OE_FROM, State, LifeTF) -> + {reply, ok, ?set_LifeTFil(State, LifeTF)}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----- CosEventChannelAdmin::ProxyPushSupplier ------------- +%%----------------------------------------------------------% +%% function : connect_push_consumer +%% Arguments: Client - CosEventComm::PushConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%% Both exceptions from CosEventChannelAdmin!!!! +%%----------------------------------------------------------- +connect_push_consumer(OE_THIS, OE_FROM, State, Client) -> + connect_any_push_consumer(OE_THIS, OE_FROM, State, Client). + +%%----- CosNotifyChannelAdmin::ProxyPushSupplier ------------ +%%----------------------------------------------------------% +%% function : connect_any_push_consumer +%% Arguments: Client - CosEventComm::PushConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%% Both exceptions from CosEventChannelAdmin!!!! +%%----------------------------------------------------------- +connect_any_push_consumer(OE_THIS, _OE_FROM, State, Client) when ?is_ANY(State) -> + 'CosNotification_Common':type_check(Client, 'CosEventComm_PushConsumer'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, State#state{client = Client, this = OE_THIS}} + end; +connect_any_push_consumer(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::SequenceProxyPushSupplier ---- +%%----------------------------------------------------------% +%% function : connect_sequence_push_consumer +%% Arguments: Client - CosNotifyComm::SequencePushConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%%----------------------------------------------------------- +connect_sequence_push_consumer(OE_THIS, _OE_FROM, State, Client) when ?is_SEQUENCE(State) -> + 'CosNotification_Common':type_check(Client, + 'CosNotifyComm_SequencePushConsumer'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + NewState = start_timer(State), + {reply, ok, NewState#state{client = Client, this = OE_THIS}} + end; +connect_sequence_push_consumer(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::StructuredProxyPushSupplier --- +%%----------------------------------------------------------% +%% function : connect_structured_push_consumer +%% Arguments: Client - CosNotifyComm::StructuredPushConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%%----------------------------------------------------------- +connect_structured_push_consumer(OE_THIS, _OE_FROM, State, Client) when ?is_STRUCTURED(State) -> + 'CosNotification_Common':type_check(Client, + 'CosNotifyComm_StructuredPushConsumer'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, State#state{client = Client, this = OE_THIS}} + end; +connect_structured_push_consumer(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::*ProxyPushSupplier ----------- +%%----------------------------------------------------------% +%% function : suspend_connection +%% Arguments: +%% Returns : ok | {'EXCEPTION', #'ConnectionAlreadyInactive'{}} | +%% {'EXCEPTION', #'NotConneced'{}} +%%----------------------------------------------------------- +suspend_connection(_OE_THIS, _OE_FROM, State) when ?is_Connected(State) -> + if + ?is_Suspended(State) -> + corba:raise(#'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}); + true -> + stop_timer(State#state.pacingTimer), + {reply, ok, State#state{pacingTimer = undefined, + suspended=true}} + end; +suspend_connection(_,_,_)-> + corba:raise(#'CosNotifyChannelAdmin_NotConnected'{}). + +%%----------------------------------------------------------% +%% function : resume_connection +%% Arguments: +%% Returns : ok | {'EXCEPTION', #'ConnectionAlreadyActive'{}} | +%% {'EXCEPTION', #'NotConneced'{}} +%%----------------------------------------------------------- +resume_connection(_OE_THIS, OE_FROM, State) when ?is_Connected(State) -> + if + ?is_NotSuspended(State) -> + corba:raise(#'CosNotifyChannelAdmin_ConnectionAlreadyActive'{}); + true -> + corba:reply(OE_FROM, ok), + if + ?is_SEQUENCE(State) -> + start_timer(State); + true -> + ok + end, + lookup_and_push(?set_NotSuspended(State)) + end; +resume_connection(_,_,_) -> + corba:raise(#'CosNotifyChannelAdmin_NotConnected'{}). + +%%----- Inherit from CosNotifyChannelAdmin::ProxySupplier --- +%%----------------------------------------------------------% +%% function : obtain_offered_types +%% Arguments: Mode - enum 'ObtainInfoMode' (CosNotifyChannelAdmin) +%% Returns : CosNotification::EventTypeSeq +%%----------------------------------------------------------- +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_OFF') -> + {reply, ?get_AllSubscribe(State), ?set_SubscribeType(State, false)}; +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_ON') -> + {reply, ?get_AllSubscribe(State), ?set_SubscribeType(State, true)}; +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_OFF') -> + {reply, [], ?set_SubscribeType(State, false)}; +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_ON') -> + {reply, [], ?set_SubscribeType(State, true)}; +obtain_offered_types(_,_,_,What) -> + orber:dbg("[~p] PusherSupplier:obtain_offered_types(~p);~n" + "Bad enumerant", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : validate_event_qos +%% Arguments: RequiredQoS - CosNotification::QoSProperties +%% Returns : ok | {'EXCEPTION', #'UnsupportedQoS'{}} +%% AvilableQoS - CosNotification::NamedPropertyRangeSeq (out) +%%----------------------------------------------------------- +validate_event_qos(_OE_THIS, _OE_FROM, State, RequiredQoS) -> + AvilableQoS = 'CosNotification_Common':validate_event_qos(RequiredQoS, + ?get_LocalQoS(State)), + {reply, {ok, AvilableQoS}, State}. + +%%----- Inherit from CosNotification::QoSAdmin -------------- +%%----------------------------------------------------------% +%% function : get_qos +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +get_qos(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalQoS(State), State}. + +%%----------------------------------------------------------% +%% function : set_qos +%% Arguments: QoS - CosNotification::QoSProperties, i.e., +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +set_qos(_OE_THIS, _OE_FROM, State, QoS) -> + {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + NewState = ?update_EventDB(State, LQS), + {reply, ok, ?set_BothQoS(NewState, NewQoS, LQS)}. + +%%----------------------------------------------------------% +%% function : validate_qos +%% Arguments: Required_qos - CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS} +%% {ok, CosNotification::NamedPropertyRangeSeq} +%%----------------------------------------------------------- +validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) -> + QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + {reply, {ok, QoS}, State}. + +%%----- Inherit from CosNotifyComm::NotifySubscribe --------- +%%----------------------------------------------------------% +%% function : subscription_change +%% Arguments: Added - #'CosNotification_EventType'{} +%% Removed - #'CosNotification_EventType'{} +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyComm_InvalidEventType'{}} +%%----------------------------------------------------------- +subscription_change(_OE_THIS, _OE_FROM, State, Added, Removed) -> + cosNotification_Filter:validate_types(Added), + cosNotification_Filter:validate_types(Removed), + %% On this "side", we care about which type of events the client + %% will require, since the client (or an agent) clearly stated + %% that it's only interested in these types of events. + %% Also see PusherConsumer- and PullerConsumer-'offer_change'. + update_subscribe(remove, State, Removed), + CurrentSub = ?get_AllSubscribe(State), + NewState = + case cosNotification_Filter:check_types(Added++CurrentSub) of + true -> + %% Types supplied does in some way cause all events to be valid. + %% Smart? Would have been better to not supply any at all. + ?set_SubscribeData(State, true); + {ok, Which, WC} -> + ?set_SubscribeData(State, {Which, WC}) + end, + update_subscribe(add, NewState, Added), + case ?get_SubscribeType(NewState) of + true -> + %% Perhaps we should handle exception here?! + %% Probably not. Better to stay "on-line". + catch 'CosNotifyComm_NotifyPublish': + offer_change(?get_Client(NewState), Added, Removed), + ok; + _-> + ok + end, + {reply, ok, NewState}. + +update_subscribe(_, _, [])-> + ok; +update_subscribe(add, State, [H|T]) -> + ?add_Subscribe(State, H), + update_subscribe(add, State, T); +update_subscribe(remove, State, [H|T]) -> + ?del_Subscribe(State, H), + update_subscribe(remove, State, T). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ----------- +%%----------------------------------------------------------% +%% function : add_filter +%% Arguments: Filter - CosNotifyFilter::Filter +%% Returns : FilterID - long +%%----------------------------------------------------------- +add_filter(_OE_THIS, _OE_FROM, State, Filter) -> + 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'), + FilterID = ?new_Id(State), + NewState = ?set_IdCounter(State, FilterID), + {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}. + +%%----------------------------------------------------------% +%% function : remove_filter +%% Arguments: FilterID - long +%% Returns : ok +%%----------------------------------------------------------- +remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ok, ?del_Filter(State, FilterID)}; +remove_filter(_,_,_,What) -> + orber:dbg("[~p] PusherSupplier:remove_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_filter +%% Arguments: FilterID - long +%% Returns : Filter - CosNotifyFilter::Filter | +%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}} +%%----------------------------------------------------------- +get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ?get_Filter(State, FilterID), State}; +get_filter(_,_,_,What) -> + orber:dbg("[~p] PusherSupplier:get_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_all_filters +%% Arguments: - +%% Returns : Filter - CosNotifyFilter::FilterIDSeq +%%----------------------------------------------------------- +get_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_AllFilterID(State), State}. + +%%----------------------------------------------------------% +%% function : remove_all_filters +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ok, ?del_AllFilter(State)}. + + +%%----- Inherit from CosEventComm::PushSupplier ------------- +%%----------------------------------------------------------% +%% function : disconnect_push_supplier +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_push_supplier(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----- Inherit from CosNotifyComm::StructuredPushSupplier -- +%%----------------------------------------------------------% +%% function : disconnect_structured_push_supplier +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_structured_push_supplier(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----- Inherit from CosNotifyComm::SequencePushSupplier ---- +%%----------------------------------------------------------% +%% function : disconnect_sequence_push_supplier +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_sequence_push_supplier(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +find_obj({value, {_, Obj}}) -> Obj; +find_obj(_) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}. + +find_ids(List) -> find_ids(List, []). +find_ids([], Acc) -> Acc; +find_ids([{I,_}|T], Acc) -> find_ids(T, [I|Acc]); +find_ids(What, _) -> + orber:dbg("[~p] PusherSupplier:find_ids();~n" + "Id corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +%% Delete a single object. +%% The list do not differ, i.e., no filter removed, raise exception. +delete_obj(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{}); +delete_obj(List,_) -> List. + +%%----------------------------------------------------------- +%% function : callSeq +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callSeq(_OE_THIS, OE_FROM, State, EventsIn, Status) -> + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:validate_event(?get_SubscribeData(State), EventsIn, + ?get_AllFilter(State), + ?get_SubscribeDB(State), + Status) of + {[],_} -> + ?DBG("PROXY NOSUBSCRIPTION SEQUENCE/STRUCTURED: ~p~n",[EventsIn]), + {noreply, State}; + {Events,_} when ?is_Suspended(State) -> + store_events(State, Events), + {noreply, State}; + {Events,_} when ?is_UnConnected(State) -> + orber:dbg("[~p] PusherSupplier:callAny();~n" + "Not connected, dropping event(s): ~p", + [?LINE, Events], ?DEBUG_LEVEL), + {noreply, State}; + {[Event],_} when ?is_STRUCTURED(State) -> + ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Event]), + empty_db(State, ?addAndGet_Event(State, Event)); + {[Event],_} when ?is_ANY(State) -> + ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Event]), + AnyEvent = any:create('CosNotification_StructuredEvent':tc(),Event), + empty_db(State, ?addAndGet_Event(State, AnyEvent)); + {Events,_} -> + ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Events]), + store_events(State, Events), + lookup_and_push(State) + end. + +%%----------------------------------------------------------- +%% function : callAny +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callAny(_OE_THIS, OE_FROM, State, EventIn, Status) -> + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:validate_event(?get_SubscribeData(State), EventIn, + ?get_AllFilter(State), + ?get_SubscribeDB(State), + Status) of + {[],_} -> + ?DBG("PROXY NOSUBSCRIPTION ANY: ~p~n",[EventIn]), + %% To be on the safe side, test if there are any events that not + %% have been forwarded (should only be possible if StartTime is used). + lookup_and_push(State); + {Event,_} when ?is_Suspended(State), ?is_ANY(State) -> + ?add_Event(State, Event), + {noreply, State}; + {Event,_} when ?is_Suspended(State) -> + ?add_Event(State, ?not_CreateSE("","%ANY","",[],[],Event)), + {noreply, State}; + {Event,_} when ?is_UnConnected(State) -> + orber:dbg("[~p] PusherSupplier:callAny();~n" + "Not connected, dropping event: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + {noreply, State}; + {Event,_} when ?is_ANY(State) -> + ?DBG("PROXY RECEIVED ANY: ~p~n",[Event]), + %% We must store the event since there may be other events that should + %% be delivered first, e.g., higher priority. + empty_db(State, ?addAndGet_Event(State, Event)); + {Event,_} when ?is_SEQUENCE(State) -> + ?DBG("PROXY RECEIVED ANY==>SEQUENCE: ~p~n",[Event]), + StrEvent = ?not_CreateSE("","%ANY","",[],[],Event), + ?add_Event(State, StrEvent), + lookup_and_push(State); + {Event,_} -> + ?DBG("PROXY RECEIVED ANY==>STRUCTURED: ~p~n",[Event]), + StrEvent = ?not_CreateSE("","%ANY","",[],[],Event), + empty_db(State, ?addAndGet_Event(State, StrEvent)) + end. + +%% Lookup and push "the correct" amount of events. +lookup_and_push(State) -> + %% The boolean indicates, if false, that we will only push events if we have + %% passed the BatchLimit. If true we will ignore this limit and push events + %% anyway (typcially invoked when pacing limit passed). + lookup_and_push(State, false). +lookup_and_push(State, false) when ?is_SEQUENCE(State) -> + case ?is_BatchLimitReached(State) of + true -> + case ?get_Events(State, ?get_BatchLimit(State)) of + {[], _, _} -> + ?DBG("BATCHLIMIT (~p) REACHED BUT NO EVENTS FOUND~n", + [?get_BatchLimit(State)]), + {noreply, State}; + {Events, _, Keys} -> + ?DBG("BATCHLIMIT (~p) REACHED, EVENTS FOUND: ~p~n", + [?get_BatchLimit(State), Events]), + case catch 'CosNotifyComm_SequencePushConsumer': + push_structured_events(?get_Client(State), Events) of + ok -> + cosNotification_eventDB:delete_events(Keys), + lookup_and_push(reset_cache(State), false); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + ?DBG("PUSH SUPPLIER CLIENT NO LONGER EXIST~n", []), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + What when ?is_PersistentEvent(State), + ?is_PersistentConnection(State) -> + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p", + [?LINE, What], ?DEBUG_LEVEL), + check_cache(State); + What when ?is_PersistentConnection(State) -> + %% Here we should do something when we want to handle + %% Persistent EventReliability. + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p~n" + "Dropping events: ~p", + [?LINE, What, Events], ?DEBUG_LEVEL), + cosNotification_eventDB:delete_events(Keys), + {noreply, State}; + WhatII -> + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p~n" + "Terminating and dropping events: ~p", + [?LINE, WhatII, Events], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, WhatII}]), + {stop, normal, State} + end + end; + _ -> + ?DBG("BATCHLIMIT (~p) NOT REACHED~n",[?get_BatchLimit(State)]), + {noreply, State} + end; +lookup_and_push(State, true) when ?is_SEQUENCE(State) -> + case ?get_Events(State, ?get_BatchLimit(State)) of + {[], _, _} -> + ?DBG("PACELIMIT REACHED BUT NO EVENTS FOUND~n", []), + {noreply, State}; + {Events, _, Keys} -> + ?DBG("PACELIMIT REACHED, EVENTS FOUND: ~p~n", [Events]), + case catch 'CosNotifyComm_SequencePushConsumer': + push_structured_events(?get_Client(State), Events) of + ok -> + cosNotification_eventDB:delete_events(Keys), + lookup_and_push(reset_cache(State), false); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client no longer exists; terminating and dropping events: ~p", + [?LINE, Events], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + What when ?is_PersistentEvent(State), + ?is_PersistentConnection(State) -> + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p", + [?LINE, What], ?DEBUG_LEVEL), + check_cache(State); + What when ?is_PersistentConnection(State) -> + %% Here we should do something when we want to handle + %% Persistent EventReliability. + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p~n" + "Dropping events: ~p", + [?LINE, What, Events], ?DEBUG_LEVEL), + cosNotification_eventDB:delete_events(Keys), + {noreply, State}; + WhatII -> + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p~n" + "Terminating and dropping events: ~p", + [?LINE, WhatII, Events], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, WhatII}]), + {stop, normal, State} + end + end; +lookup_and_push(State, _) -> + empty_db(State, ?get_Event(State)). + + +%% Push all events stored while not connected or received in sequence. +empty_db(State, {[], _, _}) -> + {noreply, State}; +empty_db(State, {Event, _, Keys}) when ?is_STRUCTURED(State) -> + case catch 'CosNotifyComm_StructuredPushConsumer': + push_structured_event(?get_Client(State), Event) of + ok -> + cosNotification_eventDB:delete_events(Keys), + NewState = reset_cache(State), + empty_db(NewState, ?get_Event(NewState)); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + orber:dbg("[~p] PusherSupplier:empty_db();~n" + "Client no longer exists; terminating and dropping: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + What when ?is_PersistentEvent(State), + ?is_PersistentConnection(State) -> + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p", + [?LINE, What], ?DEBUG_LEVEL), + check_cache(State); + What when ?is_PersistentConnection(State) -> + %% Here we should do something when we want to handle + %% Persistent EventReliability. + orber:dbg("[~p] PusherSupplier:empty_db();~n" + "Client respond incorrect: ~p~n" + "Dropping event: ~p", + [?LINE, What, Event], ?DEBUG_LEVEL), + cosNotification_eventDB:delete_events(Keys), + {noreply, State}; + WhatII -> + orber:dbg("[~p] PusherSupplier:empty_db();~n" + "Client respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, WhatII, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, WhatII}]), + {stop, normal, State} + end; +empty_db(State, {Event, _, Keys}) when ?is_ANY(State) -> + case catch 'CosEventComm_PushConsumer':push(?get_Client(State), Event) of + ok -> + cosNotification_eventDB:delete_events(Keys), + NewState = reset_cache(State), + empty_db(NewState, ?get_Event(NewState)); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + orber:dbg("[~p] PusherSupplier:empty_db();~n" + "Client no longer exists; terminating and dropping: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + What when ?is_PersistentEvent(State), + ?is_PersistentConnection(State) -> + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p", + [?LINE, What], ?DEBUG_LEVEL), + check_cache(State); + What when ?is_PersistentConnection(State) -> + %% Here we should do something when we want to handle + %% Persistent EventReliability. + orber:dbg("[~p] PusherSupplier:empty_db();~n" + "Client respond incorrect: ~p~n" + "Dropping Event: ~p", + [?LINE, What, Event], ?DEBUG_LEVEL), + cosNotification_eventDB:delete_events(Keys), + {noreply, State}; + WhatII -> + orber:dbg("[~p] PusherSupplier:empty_db();~n" + "Client respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, WhatII, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, WhatII}]), + {stop, normal, State} + end. + +reset_cache(#state{cacheTimeout = undefined, + cacheInterval = undefined} = State) -> + State; +reset_cache(State) -> + stop_timer(State#state.cacheTimeout), + stop_timer(State#state.cacheInterval), + State#state{cacheTimeout = undefined, + cacheInterval = undefined}. + +check_cache(#state{maxCache = Max, cacheTimeout = Timeout, + cacheInterval = Interval} = State) -> + case cosNotification_eventDB:status(State#state.eventDB, eventCounter) of + Count when Count > Max -> + %% Reached the upper limit, terminate. + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, State#state.client}, + {reason, {max_events, Max}}]), + {stop, normal, State}; + _ when Timeout == undefined, Interval == undefined -> + case {timer:send_interval(cosNotificationApp:interval_events(), + cacheInterval), + timer:send_after(cosNotificationApp:timeout_events(), + cacheTimeout)} of + {{ok, IntervalRef}, {ok, TimeoutRef}} -> + {noreply, State#state{cacheTimeout = TimeoutRef, + cacheInterval = IntervalRef}}; + Error -> + orber:dbg("[~p] PusherSupplier:check_cache();~n" + "Unable to start timers: ~p", + [?LINE, Error], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, State#state.client}, + {reason, {timer, Error}}]), + {stop, normal, State} + end; + _ -> + %% Timers already started. + {noreply, State} + end. + +store_events(_State, []) -> + ok; +store_events(State, [Event|Rest]) when ?is_ANY(State) -> + AnyEvent = any:create('CosNotification_StructuredEvent':tc(),Event), + ?add_Event(State, AnyEvent), + store_events(State, Rest); +store_events(State, [Event|Rest]) -> + ?add_Event(State, Event), + store_events(State, Rest). + +%% Start timers which send a message each time we should push events. Only used +%% when this objects is defined to supply sequences. +start_timer(State) -> + case ?get_PacingInterval(State) of + 0 -> + ?DBG("PUSH SUPPLIER STARTED NO TIMER (0), BATCH LIMIT: ~p~n", + [?get_BatchLimit(State)]), + + State; + PacInt -> + case catch timer:send_interval(timer:seconds(PacInt), pacing) of + {ok,PacTRef} -> + ?DBG("PUSH SUPPLIER STARTED TIMER, BATCH LIMIT: ~p~n", + [?get_BatchLimit(State)]), + ?set_PacingTimer(State, PacTRef); + What -> + orber:dbg("[~p] PusherSupplier:start_timer();~n" + "Unable to invoke timer:send_interval/2: ~p", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end + end. + +stop_timer(undefined) -> + ?DBG("PUSH SUPPLIER HAVE NO TIMER TO STOP~n",[]), + ok; +stop_timer(Timer) -> + ?DBG("PUSH SUPPLIER STOPPED TIMER~n",[]), + timer:cancel(Timer), + ok. + + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/cosNotification.app.src b/lib/cosNotification/src/cosNotification.app.src new file mode 100644 index 0000000000..04beac36e8 --- /dev/null +++ b/lib/cosNotification/src/cosNotification.app.src @@ -0,0 +1,120 @@ +{application, cosNotification, + [{description, "The Erlang CosNotification application"}, + {vsn, "%VSN%"}, + {modules, + [ + 'CosNotification_Common', + 'CosNotifyChannelAdmin_ConsumerAdmin_impl', + 'CosNotifyChannelAdmin_EventChannelFactory_impl', + 'CosNotifyChannelAdmin_EventChannel_impl', + 'CosNotifyChannelAdmin_SupplierAdmin_impl', + 'PullerConsumer_impl', + 'PullerSupplier_impl', + 'PusherConsumer_impl', + 'PusherSupplier_impl', + 'cosNotificationApp', + 'CosNotifyFilter_Filter_impl', + 'CosNotifyFilter_MappingFilter_impl', + 'CosNotifyFilter_FilterFactory_impl', + 'cosNotification_Scanner', + 'cosNotification_Grammar', + 'cosNotification_Filter', + 'cosNotification_eventDB', + 'oe_CosNotification', + 'oe_cosNotificationAppComm', + 'oe_CosNotificationComm_Event', + 'CosNotification', + 'CosNotification_AdminPropertiesAdmin', + 'CosNotification_EventHeader', + 'CosNotification_EventType', + 'CosNotification_FixedEventHeader', + 'CosNotification_NamedPropertyRange', + 'CosNotification_Property', + 'CosNotification_PropertyError', + 'CosNotification_PropertyRange', + 'CosNotification_QoSAdmin', + 'CosNotification_StructuredEvent', + 'CosNotification_UnsupportedAdmin', + 'CosNotification_UnsupportedQoS', + 'CosNotification_EventBatch', + 'CosNotification_EventTypeSeq', + 'CosNotification_NamedPropertyRangeSeq', + 'CosNotification_PropertyErrorSeq', + 'CosNotification_PropertySeq', + 'oe_CosNotifyChannelAdmin', + 'CosNotifyChannelAdmin_AdminLimit', + 'CosNotifyChannelAdmin_AdminLimitExceeded', + 'CosNotifyChannelAdmin_AdminNotFound', + 'CosNotifyChannelAdmin_ChannelNotFound', + 'CosNotifyChannelAdmin_ConnectionAlreadyActive', + 'CosNotifyChannelAdmin_ConnectionAlreadyInactive', + 'CosNotifyChannelAdmin_ConsumerAdmin', + 'CosNotifyChannelAdmin_EventChannel', + 'CosNotifyChannelAdmin_EventChannelFactory', + 'CosNotifyChannelAdmin_NotConnected', + 'CosNotifyChannelAdmin_ProxyConsumer', + 'CosNotifyChannelAdmin_ProxyNotFound', + 'CosNotifyChannelAdmin_ProxyPullConsumer', + 'CosNotifyChannelAdmin_ProxyPullSupplier', + 'CosNotifyChannelAdmin_ProxyPushConsumer', + 'CosNotifyChannelAdmin_ProxyPushSupplier', + 'CosNotifyChannelAdmin_ProxySupplier', + 'CosNotifyChannelAdmin_SequenceProxyPullConsumer', + 'CosNotifyChannelAdmin_SequenceProxyPullSupplier', + 'CosNotifyChannelAdmin_SequenceProxyPushConsumer', + 'CosNotifyChannelAdmin_SequenceProxyPushSupplier', + 'CosNotifyChannelAdmin_StructuredProxyPullConsumer', + 'CosNotifyChannelAdmin_StructuredProxyPullSupplier', + 'CosNotifyChannelAdmin_StructuredProxyPushConsumer', + 'CosNotifyChannelAdmin_StructuredProxyPushSupplier', + 'CosNotifyChannelAdmin_SupplierAdmin', + 'CosNotifyChannelAdmin_AdminIDSeq', + 'CosNotifyChannelAdmin_ChannelIDSeq', + 'CosNotifyChannelAdmin_ProxyIDSeq', + 'oe_CosNotifyComm', + 'CosNotifyComm_InvalidEventType', + 'CosNotifyComm_NotifyPublish', + 'CosNotifyComm_NotifySubscribe', + 'CosNotifyComm_PullConsumer', + 'CosNotifyComm_PullSupplier', + 'CosNotifyComm_PushConsumer', + 'CosNotifyComm_PushSupplier', + 'CosNotifyComm_SequencePullConsumer', + 'CosNotifyComm_SequencePullSupplier', + 'CosNotifyComm_SequencePushConsumer', + 'CosNotifyComm_SequencePushSupplier', + 'CosNotifyComm_StructuredPullConsumer', + 'CosNotifyComm_StructuredPullSupplier', + 'CosNotifyComm_StructuredPushConsumer', + 'CosNotifyComm_StructuredPushSupplier', + 'oe_CosNotifyFilter', + 'CosNotifyFilter_CallbackNotFound', + 'CosNotifyFilter_ConstraintExp', + 'CosNotifyFilter_ConstraintInfo', + 'CosNotifyFilter_ConstraintNotFound', + 'CosNotifyFilter_DuplicateConstraintID', + 'CosNotifyFilter_Filter', + 'CosNotifyFilter_FilterAdmin', + 'CosNotifyFilter_FilterFactory', + 'CosNotifyFilter_FilterNotFound', + 'CosNotifyFilter_InvalidConstraint', + 'CosNotifyFilter_InvalidGrammar', + 'CosNotifyFilter_InvalidValue', + 'CosNotifyFilter_MappingConstraintInfo', + 'CosNotifyFilter_MappingConstraintPair', + 'CosNotifyFilter_MappingFilter', + 'CosNotifyFilter_UnsupportedFilterableData', + 'CosNotifyFilter_CallbackIDSeq', + 'CosNotifyFilter_ConstraintExpSeq', + 'CosNotifyFilter_ConstraintIDSeq', + 'CosNotifyFilter_ConstraintInfoSeq', + 'CosNotifyFilter_FilterIDSeq', + 'CosNotifyFilter_MappingConstraintInfoSeq', + 'CosNotifyFilter_MappingConstraintPairSeq' + ] + }, + {registered, [cosNotificationSup, oe_cosNotificationFactory]}, + {applications, [orber, stdlib, kernel]}, + {env, []}, + {mod, {cosNotificationApp, []}} +]}. diff --git a/lib/cosNotification/src/cosNotification.appup.src b/lib/cosNotification/src/cosNotification.appup.src new file mode 100644 index 0000000000..6c3b2833b7 --- /dev/null +++ b/lib/cosNotification/src/cosNotification.appup.src @@ -0,0 +1,7 @@ +{"%VSN%", + [ + ], + [ + ] +}. + diff --git a/lib/cosNotification/src/cosNotificationApp.erl b/lib/cosNotification/src/cosNotificationApp.erl new file mode 100644 index 0000000000..ba44163272 --- /dev/null +++ b/lib/cosNotification/src/cosNotificationApp.erl @@ -0,0 +1,447 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosNotificationApp.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module(cosNotificationApp). + +%%--------------- INCLUDES ----------------------------------- +%% Local +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). + +-include("CosNotification_Definitions.hrl"). +%%--------------- EXPORTS------------------------------------- +%% cosNotification API external +-export([start/0, stop/0, + start_factory/1, start_factory/0, stop_factory/1, + start_global_factory/0, start_global_factory/1, + start_filter_factory/1, start_filter_factory/0, stop_filter_factory/1, + install/0, install/1, uninstall/0, uninstall/1, + install_event/0, install_event/1, uninstall_event/0, uninstall_event/1, + install_typed/0, install_typed/1, uninstall_typed/0, uninstall_typed/1, + create_structured_event/6, type_check/0, notify/0, max_events/0, + timeout_events/0, interval_events/0]). + +%% Application callbacks +-export([start/2, init/1, stop/1]). + +%%--------------- DEFINES ------------------------------------ +-define(IDL_MODULES, ['oe_CosNotification', + 'oe_cosNotificationAppComm', + 'oe_CosNotifyComm', + 'oe_CosNotifyFilter', + 'oe_CosNotifyChannelAdmin']). +-define(EVENT_IDL_MODULES, ['oe_CosEventComm', + 'oe_CosEventChannelAdmin']). +-define(TYPED_IDL_MODULES, ['oe_CosTypedEvent', + 'oe_CosTypedNotification']). + +-define(FACTORY_NAME, oe_cosNotificationFactory). +-define(SUPERVISOR_NAME, cosNotificationSup). + + +%%------------------------------------------------------------ +%% function : install/X +%% Arguments: - | Time (seconds) +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Install necessary data in the IFR DB +%%------------------------------------------------------------ + +install() -> + install(0). + +install(Time) when is_integer(Time) -> + install_loop(?IDL_MODULES, timer:seconds(Time)); +install(_Time) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%------------------------------------------------------------ +%% function : install_event/X +%% Arguments: - | Time (seconds) +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Install necessary data in the IFR DB +%%------------------------------------------------------------ + +install_event() -> + install_event(0). + +install_event(Time) when is_integer(Time) -> + install_loop(?EVENT_IDL_MODULES, timer:seconds(Time)); +install_event(_Time) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%------------------------------------------------------------ +%% function : install_typed/X +%% Arguments: - | Time (seconds) +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Install necessary data in the IFR DB +%%------------------------------------------------------------ + +install_typed() -> + install_typed(0). + +install_typed(Time) when is_integer(Time) -> + install_loop(?TYPED_IDL_MODULES, timer:seconds(Time)); +install_typed(_Time) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +install_loop([], _) -> + ok; +install_loop([H|T], Time) -> + H:'oe_register'(), + timer:sleep(Time), + install_loop(T, Time). + +%%------------------------------------------------------------ +%% function : uninstall/X +%% Arguments: - | Time (seconds) +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Remove data related to cosNotificationin from the IFR DB +%%------------------------------------------------------------ + +uninstall() -> + uninstall(0). + +uninstall(Time) when is_integer(Time) -> + uninstall_loop(lists:reverse(?IDL_MODULES), timer:seconds(Time)); +uninstall(_Time) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%------------------------------------------------------------ +%% function : uninstall_event/X +%% Arguments: - | Time (seconds) +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Remove data related to cosNotificationin from the IFR DB +%%------------------------------------------------------------ + +uninstall_event() -> + uninstall_event(0). + +uninstall_event(Time) when is_integer(Time) -> + uninstall_loop(lists:reverse(?EVENT_IDL_MODULES), timer:seconds(Time)); +uninstall_event(_Time) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%------------------------------------------------------------ +%% function : uninstall_typed/X +%% Arguments: - | Time (seconds) +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Remove data related to cosNotificationin from the IFR DB +%%------------------------------------------------------------ + +uninstall_typed() -> + uninstall_typed(0). + +uninstall_typed(Time) when is_integer(Time) -> + uninstall_loop(lists:reverse(?TYPED_IDL_MODULES), timer:seconds(Time)); +uninstall_typed(_Time) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +uninstall_loop([], _) -> + ok; +uninstall_loop([H|T], Time) -> + H:'oe_unregister'(), + timer:sleep(Time), + uninstall_loop(T, Time). + + +%%------------------------------------------------------------ +%% function : start/stop +%% Arguments: +%% Returns : +%% Effect : Starts or stops the cosTRansaction application. +%%------------------------------------------------------------ + +start() -> + application:start(cosNotification). +stop() -> + application:stop(cosNotification). + +%%------------------------------------------------------------ +%% function : start_factory +%% Arguments: none or an argumentlist whith default values. +%% Returns : ObjectRef | {'EXCEPTION', _} | {'EXIT', Reason} +%% Effect : Starts a CosNotifyChannelAdmin_EventChannelFactory +%%------------------------------------------------------------ +start_factory() -> + start_factory(?not_DEFAULT_SETTINGS). + +start_factory(Args) when is_list(Args) -> + SO = 'CosNotification_Common':get_option(server_options, Args, ?not_DEFAULT_SETTINGS), + SPEC = ['CosNotifyChannelAdmin_EventChannelFactory',Args, + [{sup_child, true}, + {regname, {local, oe_cosNotificationFactory}}|SO]], + case supervisor:start_child(?SUPERVISOR_NAME, SPEC) of + {ok, Pid, Obj} when is_pid(Pid) -> + Obj; + Other-> + orber:dbg("[~p] cosNotificationApp:start_factory( ~p ).~n" + "Reason: ~p~n", [?LINE, Args, Other], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; +start_factory(Args) -> + orber:dbg("[~p] cosNotificationApp:start_factory( ~p ).~n" + "Bad parameters~n", [?LINE, Args], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%------------------------------------------------------------ +%% function : start_global_factory +%% Arguments: none or an argumentlist whith default values. +%% Returns : ObjectRef | {'EXCEPTION', _} | {'EXIT', Reason} +%% Effect : Starts a CosNotifyChannelAdmin_EventChannelFactory +%%------------------------------------------------------------ +start_global_factory() -> + start_global_factory(?not_DEFAULT_SETTINGS). + +start_global_factory(Args) when is_list(Args) -> + SO = 'CosNotification_Common':get_option(server_options, Args, ?not_DEFAULT_SETTINGS), + Name = create_name(), + SPEC = ['CosNotifyChannelAdmin_EventChannelFactory',Args, + [{sup_child, true}, + {regname, {global, Name}}|SO]], + case supervisor:start_child(?SUPERVISOR_NAME, SPEC) of + {ok, Pid, Obj} when is_pid(Pid) -> + Obj; + Other-> + orber:dbg("[~p] cosNotificationApp:start_global_factory( ~p ).~n" + "Reason: ~p~n", [?LINE, Args, Other], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; +start_global_factory(Args) -> + orber:dbg("[~p] cosNotificationApp:start_global_factory( ~p ).~n" + "Bad parameters~n", [?LINE, Args], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + + +%%------------------------------------------------------------ +%% function : stop_factory +%% Arguments: Factory Object Reference +%% Returns : ok | {'EXCEPTION', _} +%% Effect : +%%------------------------------------------------------------ + +stop_factory(Fac)-> + corba:dispose(Fac). + +%%------------------------------------------------------------ +%% function : start_filter_factory +%% Arguments: none or an argumentlist which by default is defined +%% in CosNotification_Definitions.hrl, i.e., '?not_FILTERFAC_DEF' +%% Returns : ObjectRef | {'EXCEPTION', _} | {'EXIT', Reason} +%% Effect : Starts a CosNotifyChannelAdmin_EventChannelFactory +%%------------------------------------------------------------ +start_filter_factory() -> + start_filter_factory([{typecheck, true}, + {tty, false}, + {logfile, false}, + {server_options, []}]). +start_filter_factory(Args) when is_list(Args) -> + SO = 'CosNotification_Common':get_option(server_options, Args, + ?not_DEFAULT_SETTINGS), + SPEC = ['CosNotifyFilter_FilterFactory',Args, [{sup_child, true}|SO]], + case supervisor:start_child(?SUPERVISOR_NAME, SPEC) of + {ok, Pid, Obj} when is_pid(Pid) -> + Obj; + Other-> + orber:dbg("[~p] cosNotificationApp:start_filter_factory( ~p ).~n" + "Reason: ~p~n", [?LINE, Args, Other], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; +start_filter_factory(Args) -> + orber:dbg("[~p] cosNotificationApp:start_filter_factory( ~p ).~n" + "Bad parameters~n", [?LINE, Args], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + + +%%------------------------------------------------------------ +%% function : stop_filter_factory +%% Arguments: FilterFactory Object Reference +%% Returns : ok | {'EXCEPTION', _} +%% Effect : +%%------------------------------------------------------------ + +stop_filter_factory(Fac)-> + corba:dispose(Fac). + + +%%------------------------------------------------------------ +%% function : create_structured_event +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ +create_structured_event(StrD,StrT,StrE,PSeqV,PSeqF,AnyR) + when is_list(StrD) andalso is_list(StrT) andalso is_list(StrE) + andalso is_list(PSeqV) andalso is_list(PSeqF) andalso + is_record(AnyR, any) -> +#'CosNotification_StructuredEvent'{header = + #'CosNotification_EventHeader'{fixed_header = + #'CosNotification_FixedEventHeader'{event_type = + #'CosNotification_EventType'{domain_name=StrD, + type_name=StrT}, + event_name = StrE}, + variable_header = PSeqV}, + filterable_data = PSeqF, + remainder_of_body = AnyR}; +create_structured_event(_StrD,_StrT,_StrE,_PSeqV,_PSeqF,_AnyR) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + + +%%------------------------------------------------------------ +%% function : type_check +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ +type_check() -> + case application:get_env(cosNotification, type_check) of + {ok, Boolean} when is_atom(Boolean) -> + Boolean; + _ -> + true + end. + +%%------------------------------------------------------------ +%% function : notify +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ +notify() -> + case application:get_env(cosNotification, notify) of + {ok, Module} when is_atom(Module) -> + Module; + _ -> + false + end. + +%%------------------------------------------------------------ +%% function : max_events +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ +max_events() -> + case application:get_env(cosNotification, max_events) of + {ok, Max} when is_integer(Max) -> + Max; + _ -> + 50 + end. + +%%------------------------------------------------------------ +%% function : timeout_events +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ +timeout_events() -> + case application:get_env(cosNotification, timeout_events) of + {ok, Max} when is_integer(Max) -> + Max; + _ -> + 3000000 %% 5 minutes + end. + + +%%------------------------------------------------------------ +%% function : interval_events +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ +interval_events() -> + case application:get_env(cosNotification, interval_events) of + {ok, Max} when is_integer(Max) -> + Max; + _ -> + 10000 %% 10 seconds + end. + + +%%------------------------------------------------------------ +%% function : start +%% Arguments: Type - see module application +%% Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ + +start(_, _) -> + supervisor:start_link({local, ?SUPERVISOR_NAME}, cosNotificationApp, app_init). + + +%%------------------------------------------------------------ +%% function : stop +%% Arguments: Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ + +stop(_) -> + ok. + +%%------------------------------------------------------------ +%% function : init +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +%% Starting using create_factory/X +init(own_init) -> + {ok,{{simple_one_for_one,50,10}, + [{"oe_NotChild", + {'CosNotification_Common',create_link, []}, + transient,100000,worker, + ['CosNotifyChannelAdmin_EventChannel', + 'CosNotifyChannelAdmin_EventChannel_impl']}]}}; +%% When starting as an application. +init(app_init) -> + {ok,{{simple_one_for_one,50,10}, + [{"oe_NotChild", + {'CosNotification_Common',create_link, []}, + transient,100000,worker, + ['CosNotifyChannelAdmin_EventChannel', + 'CosNotifyChannelAdmin_EventChannel_impl']}]}}. + + + +%%------------------------------------------------------------ +%% function : create_name +%% Arguments: +%% Returns : +%% Effect : Create a unique name to use when, for eaxmple, starting +%% a new server. +%%------------------------------------------------------------ +create_name() -> + {MSec, Sec, USec} = erlang:now(), + lists:concat(['oe_',node(),'_',MSec, '_', Sec, '_', USec]). + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/cosNotificationAppComm.idl b/lib/cosNotification/src/cosNotificationAppComm.idl new file mode 100644 index 0000000000..09e0af2568 --- /dev/null +++ b/lib/cosNotification/src/cosNotificationAppComm.idl @@ -0,0 +1,17 @@ +#ifndef _OE_COSNOTIFICATIONCOMM_IDL_ +#define _OE_COSNOTIFICATIONCOMM_IDL_ + +#include<CosNotification.idl> + +module oe_CosNotificationComm { + + interface Event { + + enum status {MATCH, MATCHED}; + void callSeq(in CosNotification::EventBatch events, in status stat); + void callAny(in any event, in status stat); + }; + +}; +#endif /* ifndef _OE_COSNOTIFICATIONCOMM_IDL_ */ + diff --git a/lib/cosNotification/src/cosNotificationComm.cfg b/lib/cosNotification/src/cosNotificationComm.cfg new file mode 100644 index 0000000000..89d207528d --- /dev/null +++ b/lib/cosNotification/src/cosNotificationComm.cfg @@ -0,0 +1,3 @@ +{this, "oe_CosNotificationComm::Event"}. +{from, "oe_CosNotificationComm::Event"}. +{{handle_info, "oe_CosNotificationComm::Event"}, true}. diff --git a/lib/cosNotification/src/cosNotification_Filter.erl b/lib/cosNotification/src/cosNotification_Filter.erl new file mode 100644 index 0000000000..dd3b5beb93 --- /dev/null +++ b/lib/cosNotification/src/cosNotification_Filter.erl @@ -0,0 +1,964 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosNotification_Filter.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module(cosNotification_Filter). + + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). + +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%% Internal Filter Functions +-export([eval/1, + eval/2, + create_filter/1, + check_types/1, + match_types/3, + validate_types/1]). + +%%--------------- DEFINES ------------------------------------ +-define(EVENT_PATH, [{dotid,"header"}, {dotid,"fixed_header"}, + {dotid,"event_name"}]). +-define(DOMAIN_PATH, [{dotid,"header"}, {dotid,"fixed_header"}, + {dotid,"event_type"}, {dotid,"domain_name"}]). +-define(TYPE_PATH, [{dotid,"header"}, {dotid,"fixed_header"}, + {dotid,"event_type"}, {dotid,"type_name"}]). +-define(VARIABLE_PATH(I), [{dotid,"header"}, {dotid,"variable_header"}, {dotid,I}]). +-define(FILTERABLE_PATH(I), [{dotid,"filterable_data"}, {dotid,I}]). + + +%%------------------------------------------------------------ +%%--------------- FILTER FUNCTIONS --------------------------- +%%------------------------------------------------------------ +%%------------------------------------------------------------ +%% function : create_filter/1 +%% Arguments: String - Filter grammar +%% Returns : +%% Effect : +%%------------------------------------------------------------ +create_filter(Str) -> + {ok, Tokens} = cosNotification_Scanner:scan(Str), + case cosNotification_Grammar:parse(Tokens) of + {ok, Filter} -> + {ok, Filter}; + _-> + corba:raise(#'CosNotifyFilter_InvalidConstraint'{constr = Str}) + end. + +%%------------------------------------------------------------ +%% function : eval +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +eval('$empty') -> true; +eval(Tree) -> eval(Tree, []). + + +%% Leaf expressions (literals and idents). +eval('$empty', _) -> true; +eval(Lit, _Env) when is_number(Lit) -> Lit; +eval(Lit, _Env) when is_list(Lit) -> Lit; %list == string +eval(Lit, _Env) when is_atom(Lit) -> Lit; %atom == bool +eval({component, V}, []) -> + %% Cannot evaluate variables at this stage. + throw({error, {unbound_variable, V}}); +eval({component, V}, Env) -> + case catch lookup(V, Env, undefined) of + {ok, Val} -> + Val; + _X -> + {error, {unbound_variable, V}} + end; + +%% CORBA2.3-15/26 states: +%% "The name parameters in tk_objref, tk_struct, tk_union, tk_enum, tk_alias, +%% tk_value, tk_value_box, tk_abstract_interface, tk_native and tk_except TypeCodes +%% and the member name parameters in tk_struct, tk_union, tk_enum, tk_value and +%% tk_except TypeCodes are not specified by (or significant in) GIOP. Agents should +%% not make assumptions about type equivalence based on these name values; only the +%% structural information (including RepositoryId values, if provided) is +%% significant. If provided, the strings should be the simple, unscoped names +%% supplied in the OMG IDL definition text. If omitted, they are encoded as empty +%% strings." +%% Makes it rather hard to follow the grammar 100 %. +eval({default_component, V}, Env) -> + case catch lookup(V, Env, default_component) of + {ok, false} -> + false; + {ok, true} -> + true; + _X -> + {error, {unbound_variable, V}} + end; +eval({exist_component, V}, Env) -> + case catch lookup(V, Env, exist_component) of + {ok, false} -> + false; + {ok, _} -> + true; + {error, _} -> + false; + _X -> + {error, {unbound_variable, V}} + end; +%% Arithmetic expressions. +eval({'*', X, Y}, Env) -> + eval_arith({fun(_X, _Y) -> _X*_Y end, X, Y}, Env); +eval({'/', X, Y}, Env) -> + eval_arith({fun(_X, _Y) -> _X/_Y end, X, Y}, Env); +eval({'+', X, Y}, Env) -> + eval_arith({fun(_X, _Y) -> _X+_Y end, X, Y}, Env); +eval({'-', X, Y}, Env) -> + eval_arith({fun(_X, _Y) -> _X-_Y end, X, Y}, Env); +eval({'u-', X}, Env) -> + eval_arith({fun(_X) -> -_X end, X}, Env); +%% Relational expressions. +eval({'==', X, Y}, Env) -> + eval_rel({fun(_X, _Y) -> _X == _Y end, X, Y}, Env); +eval({'!=', X, Y}, Env) -> + eval_rel({fun(_X, _Y) -> _X /= _Y end, X, Y}, Env); +eval({'<', X, Y}, Env) -> + eval_rel({fun(_X, _Y) -> _X < _Y end, X, Y}, Env); +eval({'<=', X, Y}, Env) -> + eval_rel({fun(_X, _Y) -> _X =< _Y end, X, Y}, Env); +eval({'>', X, Y}, Env) -> + eval_rel({fun(_X, _Y) -> _X > _Y end, X, Y}, Env); +eval({'>=', X, Y}, Env) -> + eval_rel({fun(_X, _Y) -> _X >= _Y end, X, Y}, Env); +eval({'~', Needle, Haystack}, Env) -> %substring match + N = eval(Needle, Env), + H = eval(Haystack, Env), + if + is_list(N) andalso is_list(H) -> + string:str(H, N) /= 0; + true -> + throw({error, {bad_type, Needle, Haystack}}) + end; +eval({'in', Needle, Haystack}, Env) -> %set membership + N = eval(Needle, Env), + H = eval(Haystack, Env), + if + is_list(H) -> + lists:member(N, H); + true -> + throw({error, {bad_type, Needle, Haystack}}) + end; +%% Boolean expressions. +eval({'and', false, _Y}, _Env) -> + false; +eval({'and', _X, false}, _Env) -> + false; +eval({'and', X, Y}, Env) -> + eval_and_bool({fun(_X, _Y) -> _X and _Y end, X, Y}, Env); + +eval({'or', true, _Y}, _Env) -> + true; +eval({'or', _X, true}, _Env) -> + true; +eval({'or', X, Y}, Env) -> + eval_or_bool({fun(_X, _Y) -> _X or _Y end, X, Y}, Env); +eval({'not', X}, Env) -> + eval_bool({fun(_X) -> not _X end, X}, Env); +%% Catch-all +eval(_T, _Env) -> + throw({error, internal}). + +eval_bool({Fun, X}, Env) -> + Xe = eval(X, Env), + if + is_atom(Xe) -> + Fun(Xe); + true -> + throw({error, {bad_type, X}}) + end. +eval_and_bool({Fun, X, Y}, Env) -> + case eval(X, Env) of + false -> + %% No need for evaluating the other expression. + false; + Xe -> + Ye = eval(Y, Env), + if + is_atom(Xe) andalso is_atom(Ye) -> + Fun(Xe, Ye); + true -> + throw({error, {bad_type, X, Y}}) + end + end. +eval_or_bool({Fun, X, Y}, Env) -> + case eval(X, Env) of + true -> + %% No need for evaluating the other expression. + true; + Xe -> + Ye = eval(Y, Env), + if + is_atom(Xe) andalso is_atom(Ye) -> + Fun(Xe, Ye); + true -> + throw({error, {bad_type, X, Y}}) + end + end. + + +%% According to issue 2203, OMG stated that arithmetic operations involving booleans +%% is allowed. TRUE equals 1 and FALSE 0. They refer to: + +%% "We at NEC like this feature, and feel it is both required and +%% standard with the way CORBA treats boolean values. We feel it's +%% required because it allows the constraint grammar to handle +%% expressions that combine the results of boolean comparisons, +%% which we feel is typically expected of a constraint grammar +%% (e.g., ($.fruit == apples) + ($.color == red) + ($.kind == macintosh) > 2) +%% Furthermore, while we have no fundamental opposition to explicitly +%% stating that TRUE=1 and FALSE=0, we don't necessarily feel it's +%% necessary because section 12.3.1 of CORBA alread states that +%% "Boolean values are encoded as single octets, where TRUE is the +%% value 1, and FALSE is 0." Essentially, we feel CORBA already +%% defines TRUE to be 1 and FALSE to be 0, however we are not +%% opposed to adding such a statement into Notification if folks +%% feel it's necessary." +%% If still valid, see: ftp://ftp.omg.org/pub/docs/telecom/99-07-06.txt + +%% The section they refer to (CORBA-2.0) merely states that TRUE and FALSE are +%% encoded as 1 and 0 in GIOP. Does not imply that booleans may be used as numeric. +%% But, they have stated that this should be the case so..... + +remap_bool(Num) when is_number(Num) -> Num; +remap_bool(true) -> 1; +remap_bool(false) -> 0; +remap_bool(X) -> throw({error, {bad_type, X}}). + +eval_arith({Fun, X}, Env) -> + Xe = remap_bool(eval(X, Env)), + Fun(Xe); +eval_arith({Fun, X, Y}, Env) -> + Xe = remap_bool(eval(X, Env)), + Ye = remap_bool(eval(Y, Env)), + Fun(Xe, Ye). + +eval_rel({Fun, X, Y}, Env) -> + Xe = eval(X, Env), + Ye = eval(Y, Env), + if + is_number(Xe) andalso is_number(Ye) -> + Fun(Xe, Ye); + is_list(Xe) andalso is_list(Ye) -> + Fun(Xe, Ye); + is_atom(Xe) andalso is_atom(Ye) -> + Fun(Xe, Ye); + true -> + throw({error, {bad_type, X, Y}}) + end. + +%%------------------------------------------------------------ +%% function : get_variable +%% Arguments: A sequence of CosNotification::Property{}, i.e., +%% name-value pairs. +%% ID - name in the Property +%% Any - remainder of body +%% Returns : Value in the Property | false +%% Comment : When searching for a variable we must start with +%% 'variable_header' followed by 'filterable_body'. +%% If not found we will then look in the 'remainder_of_body' +%%------------------------------------------------------------ + +get_variable([], ID, Any) when is_record(Any, any) -> + case {any:get_value(Any), any:get_typecode(Any)} of + {#'CosNotification_Property'{name=ID, value=A}, _} -> + any:get_value(A); + {_, TC} when is_atom(TC) -> + %% Since TC atom it must be a simple type, which don't have members. + throw({error, {bad_id, ID}}); + {Value, {tk_alias,_,ID,_}} when is_record(Value, any) -> + %% {tk_alias, IFRId, ID, TypeCode} + any:get_value(Value); + {Value, {tk_alias,_,ID,_}} -> + %% {tk_alias, IFRId, ID, TypeCode} + Value; + {Value, _TC} -> + get_variable([],ID, Value) + end; +get_variable([], ID, #'CosNotification_Property'{name=ID, value=Any}) -> + any:get_value(Any); +get_variable([], ID, [#'CosNotification_Property'{name=ID, value=Any}|_]) -> + any:get_value(Any); +get_variable([], ID, [H|T]) when is_record(H, 'CosNotification_Property') -> + get_variable([], ID, T); +get_variable([], ID, false) -> + throw({error, {bad_id, ID}}); +get_variable([], ID, Value) -> + M = element(1, Value), + case catch M:tc() of + {tk_struct,_,_,SList} -> + %% {tk_struct, Id, Name, ElementList}. + Field = get_field(ID, SList), + element(Field, Value); + {tk_union,_,_,_, DefNo, UList} -> + %% {tk_union, Id, Name, DiscrTC, Default, ElementList} + case id2switch(UList, ID) of + [default] when DefNo >= 0 -> + element(3, Value); + [default] -> + throw({error, {bad_id, "Bad Union ID supplied"}}); + Found -> + case catch lists:member(element(2, Value), Found) of + true -> + element(3, Value); + _ -> + throw({error, {bad_id, "Bad Union ID supplied"}}) + end + end; + _-> + throw({error, {bad_id, ID}}) + end; +get_variable([#'CosNotification_Property'{name=ID, value=A}|_], ID, _) -> + any:get_value(A); +get_variable([_|T], ID, Any) -> + get_variable(T, ID, Any). + +%%------------------------------------------------------------ +%% function : lookup +%% Arguments: T - A parse tree representing the grammar. +%% S - The event we want to extract data from +%% Op - which type of lookup should be done on this +%% component, e.g., 'default' or 'exist'. +%% Returns : {ok, boolean()} | +%% {error, _} +%% Comment : WARNING!!!! +%% This function uses some Orber core information to +%% extract data, e.g., TypeCode representation. Why? +%% We don't want to see the performance take a plunge +%% due to that users write constraints which they +%% can/may not know is slow. The alternative would be +%% to use the IFR. However, these shortcuts aren't +%% that frequent and we can easily update the code. +%% To update, investigate: +%% * lookup/3 cases related to '_type_id' +%% * lookup/3 cases related to unions +%% * get_variable/3 +%% * id2switch/2 +%% * switch2alias/2 +%%------------------------------------------------------------ +%% Done parsing, return the result. +lookup([],S,_) -> {ok, S}; +lookup('$empty', #'CosNotification_StructuredEvent'{remainder_of_body = Any},_) -> + {ok, any:get_value(Any)}; +lookup('$empty',S,_) when is_record(S, any) -> + {ok, any:get_value(S)}; + +%%------- varid -------- +%% CosNotification-revision-98-11-01/46 states: +%% "The following rules govern translation of a run-time variable, $variable , +%% into a specific event field. If the run-time variable is reserved +%% (e.g., $curtime) this translation takes precedence. Next, the first matching +%% translation is chosen respectively from: +%% * a simple-typed member of $.header.fixed_header, +%% * properties in $.header.variable_header, +%% and properties in $.header.filterable_data. +%% If no match is found, the translation defaults to $.variable. +%% Given these rules, an unstructured event with a $.priority member and a +%% structured event using $.header.variable_header(priority) can be specified +%% in a generic constraint using the run-time variable $priority . +%% Alternatively, a constraint can be written specifically for a structured or +%% unstructured event by avoiding the use of run-time variables." + +%% The above contains one error; $.header.filterable_data is not a part of the +%% header, but contained in the event body. + +%% For any events we must first verify that a path exist, e.g., +%% "header"->"fixed_header"->"event_type"->"domain_name", otherwise we will +%% use {dotid, "xxx"}. +lookup([{varid, "type_name"}|T], + #'CosNotification_StructuredEvent' + {header = #'CosNotification_EventHeader' + {fixed_header = #'CosNotification_FixedEventHeader' + {event_type = #'CosNotification_EventType'{type_name=TN}}}}, Op) -> + lookup(T, TN, Op); +lookup([{varid, "type_name"}|T], Any, Op) when is_record(Any, any) -> + case locate_var([?TYPE_PATH, ?VARIABLE_PATH("type_name"), + ?FILTERABLE_PATH("type_name")], Any, Op) of + {ok, Val} -> + lookup(T, Val, Op); + _ -> + lookup(T, get_variable([], "type_name", Any), Op) + end; +lookup([{varid, "domain_name"}|T], + #'CosNotification_StructuredEvent' + {header = #'CosNotification_EventHeader' + {fixed_header = #'CosNotification_FixedEventHeader' + {event_type = #'CosNotification_EventType'{domain_name=DN}}}}, Op) -> + lookup(T, DN, Op); +lookup([{varid, "domain_name"}|T], Any, Op) when is_record(Any, any) -> + case locate_var([?DOMAIN_PATH, ?VARIABLE_PATH("domain_name"), + ?FILTERABLE_PATH("domain_name")], Any, Op) of + {ok, Val} -> + lookup(T, Val, Op); + _ -> + lookup(T, get_variable([], "domain_name", Any), Op) + end; +lookup([{varid, "event_name"}|T], + #'CosNotification_StructuredEvent' + {header = #'CosNotification_EventHeader' + {fixed_header = #'CosNotification_FixedEventHeader' + {event_name = EN}}}, Op) -> + lookup(T, EN, Op); +lookup([{varid, "event_name"}|T], Any, Op) when is_record(Any, any) -> + case locate_var([?EVENT_PATH, ?VARIABLE_PATH("event_name"), + ?FILTERABLE_PATH("event_name")], Any, Op) of + {ok, Val} -> + lookup(T, Val, Op); + _ -> + lookup(T, get_variable([], "event_name", Any), Op) + end; + +lookup([{varid, ID}|T], + #'CosNotification_StructuredEvent'{header = + #'CosNotification_EventHeader'{variable_header = VS}, + filterable_data = FS, + remainder_of_body = Any}, Op) -> + lookup(T, get_variable(VS++FS, ID, Any), Op); +lookup([{varid, ID}|T], Any, Op) -> + case locate_var([?VARIABLE_PATH(ID), ?FILTERABLE_PATH(ID)], Any, Op) of + {ok, Val} -> + lookup(T, Val, Op); + _ -> + lookup(T, get_variable([], ID, Any), Op) + end; + +%%------- dotid -------- +%% First level +lookup([{dotid, "header"}|T], + #'CosNotification_StructuredEvent'{header = S}, Op) -> + lookup(T, S, Op); +lookup([{dotid, "filterable_data"}|T], + #'CosNotification_StructuredEvent'{filterable_data = S}, Op) -> + lookup(T, S, Op); + +lookup([{dotid, remainder_of_body}|T], + #'CosNotification_StructuredEvent'{remainder_of_body = S}, Op) -> + lookup(T, S, Op); +%% Second level. Previous token must have been header +lookup([{dotid, "fixed_header"}|T], + #'CosNotification_EventHeader'{fixed_header = S}, Op) -> + lookup(T, S, Op); +lookup([{dotid, "variable_header"}|T], + #'CosNotification_EventHeader'{variable_header = S}, Op) -> + lookup(T, S, Op); +%% Third level. Previous token must have been fixed_header. +lookup([{dotid, "event_type"}|T], + #'CosNotification_FixedEventHeader'{event_type = S}, Op) -> + lookup(T, S, Op); +lookup([{dotid, "event_name"}|T], + #'CosNotification_FixedEventHeader'{event_name = S}, Op) -> + lookup(T, S, Op); +%% Fourth level. Previous token must have been event_type +lookup([{dotid, "domain_name"}|T], #'CosNotification_EventType'{domain_name = S}, Op) -> + lookup(T, S, Op); +lookup([{dotid, "type_name"}|T], #'CosNotification_EventType'{type_name = S}, Op) -> + lookup(T, S, Op); + +%% Leaf expressions +lookup([{dotid, "name"}|T], #'CosNotification_Property'{name=S}, Op) -> + lookup(T, S, Op); +lookup([{dotid, "value"}|T], #'CosNotification_Property'{value=S}, Op) -> + lookup(T, S, Op); + +lookup([{dotid, ID}|T], + #'CosNotification_StructuredEvent'{remainder_of_body = Any}, Op) -> + lookup(T, get_variable([], ID, Any), Op); +lookup([{dotid, ID}|T], Any, Op) -> + lookup(T, get_variable([], ID, Any), Op); + +lookup([{associd, ID}|T], S, Op) when is_list(S) -> + %% Refers to an associative array, i.e., a list of + %% #'CosNotification_Property'{name=ID, value=A} + lookup(T, get_variable(S, ID, false), Op); + +lookup([{dotint, Position}|T], S, Op) when is_record(S, any) -> + lookup(T, element(Position+2, any:get_value(S)), Op); +lookup([{dotint, Position}|T], S, Op) -> + lookup(T, element(Position+2, S), Op); + +lookup([{uint, ID}|T], S, Op) when is_record(S, any) -> + lookup([{uint, ID}|T], any:get_value(S), Op); +lookup([{uint, ID} |T], S, Op) when is_tuple(S) -> + case catch element(2, S) of + ID -> + %% The supplied union do contain the requested discriminator. + lookup(T, element(3, S), Op); + _Other when Op == exist_component -> + throw({error, {bad_id, "Bad Union ID"}}); + Other -> + %% Check if default is allowed. + M = element(1, S), + case catch M:tc() of + {tk_union,_,_,_,DefNo, UList} -> + %% {tk_union, Id, Name, DiscrTC, Default, ElementList} + case switch2alias(UList, ID) of + {ok, [], _} -> + throw({error, {bad_id, "Bad Union ID"}}); + {ok, default, _} when DefNo >= 0 -> + lookup(T, element(3, S), Op); + {ok, List, _} -> + case lists:member(Other, List) of + true -> + lookup(T, element(3, S), Op); + _-> + throw({error, {bad_id, "Bad Union ID"}}) + end + end + end + end; +lookup([{ustr, ID}|T], S, Op) when is_record(S, any) -> + lookup([{ustr, ID}|T], any:get_value(S), Op); +lookup([{ustr, ID}|T], S, Op) when is_tuple(S) -> + M = element(1, S), + case catch M:tc() of + {tk_union,_,_,_,DefNo, UList} -> + case id2switch(UList, ID) of + [default] when DefNo >= 0 -> + lookup(T, element(3, S), Op); + [default] -> + throw({error, {bad_id, "Bad Union ID supplied"}}); + Found -> + case catch lists:member(element(2, S), Found) of + true -> + lookup(T, element(3, S), Op); + _ -> + throw({error, {bad_id, "Bad Union ID supplied"}}) + end + end + end; +lookup([default|T], S, Op) when is_record(S, any) -> + lookup([default|T], any:get_value(S), Op); +lookup([default|T], S, Op) when is_tuple(S) -> + M = element(1, S), + case catch M:tc() of + {tk_union,_,_,_,DefNo, _UList} when DefNo < 0 -> + %% {tk_union, Id, Name, DiscrTC, Default, ElementList} + throw({error, {bad_id, "No default discriminator"}}); + {tk_union,_,_,_,_DefNo, UList} -> + %% {tk_union, Id, Name, DiscrTC, Default, ElementList} + %% Check if the label really is default. + case lists:keymember(element(2, S), 1, UList) of + false -> + lookup(T, element(3, S), Op); + _-> + throw({error, {bad_id, "Bad Union"}}) + end; + _-> + throw({error, {bad_id, "Bad Union"}}) + end; + +lookup([{arrindex, Index}|T], S, Op) when is_tuple(S) -> + %% The OMG uses c/c++ index. We must add one. + lookup(T, element(Index+1,S), Op); + +%%%%%%%%%%%%%%%%%%%%%%% LEAF EXPRESSIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% got '$._length', which maps to the 'remainder_of_body' +lookup(['_length'], + #'CosNotification_StructuredEvent'{remainder_of_body = Any}, _Op) -> + {ok, length(any:get_value(Any))}; +lookup(['_length'], S, _Op) when is_record(S, any) -> + {ok, length(any:get_value(S))}; +lookup(['_length'], S, _Op) when is_list(S) -> + {ok, length(S)}; +lookup(['_length'], S, _Op) when is_tuple(S) -> + {ok, length(tuple_to_list(S))}; + +%% got '$._d', which maps to the 'remainder_of_body' +%% The discriminator may, accordiong to the CORBA specification, be (2.3/p3-37): +%% * integer_type +%% * char_type +%% * boolean_type +%% * enum_type +%% * scoped_name +lookup(['_d'], + #'CosNotification_StructuredEvent'{remainder_of_body = Any}, + default_component) -> + lookup(['_d'], any:get_value(Any), default_component); +lookup(['_d'], S, default_component) when is_record(S, any) -> + lookup(['_d'], any:get_value(S), default_component); +lookup(['_d'], S, default_component) -> + M = element(1, S), + case catch M:tc() of + {tk_union,_,_,_,DefNo,_} when DefNo < 0 -> + %% '-1' indicates that no default value may exist. + {ok, false}; + {tk_union,_,_,_,_,UList} -> + %% May be using the default setting; check if the Value is in the list. + {ok, not lists:keymember(element(2, S), 1, UList)}; + _ -> + {ok, false} + end; +lookup(['_d'], + #'CosNotification_StructuredEvent'{remainder_of_body = Any}, _Op) -> + {ok, element(2, any:get_value(Any))}; +lookup(['_d'], S, _Op) when is_record(S, any) -> + {ok, element(2, any:get_value(S))}; +lookup(['_d'], S, _Op) -> + {ok, element(2, S)}; + + +lookup(['_type_id'], S, _Op) when is_record(S,'CosNotification_StructuredEvent') -> + {ok, "StructuredEvent"}; +lookup(['_type_id'], S, _Op) when is_record(S,'CosNotification_EventHeader') -> + {ok, "EventHeader"}; +lookup(['_type_id'], S, _Op) when is_record(S,'CosNotification_FixedEventHeader') -> + {ok, "FixedEventHeader"}; +lookup(['_type_id'], S, _Op) when is_record(S,'CosNotification_EventType') -> + {ok, "EventType"}; +lookup(['_type_id'], S, _Op) when is_record(S,'CosNotification_Property') -> + {ok, "Property"}; +lookup(['_type_id'], S, _Op) when is_tuple(S) -> + M=element(1, S), + Name = case catch M:tc() of + {tk_union,_,ID,_,_,_} -> + ID; + {tk_enum, _, ID, _} -> + ID; + {tk_exception, _, ID, _} -> + ID; + {tk_alias, _, ID, _} -> + ID; + {tk_struct,_,ID,_} -> + ID + end, + {ok, Name}; + +lookup(['_repos_id'], S, _Op) when is_record(S,'CosNotification_StructuredEvent') -> + {ok, 'CosNotification_StructuredEvent':id()}; +lookup(['_repos_id'], S, _Op) when is_record(S,'CosNotification_EventHeader') -> + {ok, 'CosNotification_EventHeader':id()}; +lookup(['_repos_id'], S, _Op) when is_record(S,'CosNotification_FixedEventHeader') -> + {ok, 'CosNotification_FixedEventHeader':id()}; +lookup(['_repos_id'], S, _Op) when is_record(S,'CosNotification_EventType') -> + {ok, 'CosNotification_EventType':id()}; +lookup(['_repos_id'], S, _Op) when is_record(S,'CosNotification_Property') -> + {ok, 'CosNotification_Property':id()}; +lookup(['_repos_id'], S, _Op) when is_tuple(S) -> + M = element(1, S), + {ok, M:id()}; + +lookup(_, _, _) -> + error. + + +%%------------------------------------------------------------ +%% function : locate_var +%% Arguments: Paths - A list of path-lists which tells us where +%% to search for runtime variables and in which +%% order. +%% S - Data +%% Op - se lookup/3 +%% Returns : {error, _} | +%% {ok, Val} +%%------------------------------------------------------------ +locate_var([], _S, _) -> + {error, "not found"}; +locate_var([H|T], S, Op) -> + case catch lookup(H, S, Op) of + {ok, Val} -> + {ok,Val}; + _ -> + locate_var(T, S, Op) + end. + +%%------------------------------------------------------------ +%% function : id2switch +%% Arguments: UList - The list of elements contained in the +%% Union TypeCode. +%% ID - string() eq name of element. +%% Returns : Acc - A list of switches related to given ID. +%%------------------------------------------------------------ +id2switch(UList, ID) -> + id2switch(UList, ID, [], false). +id2switch([], _, Acc, _) -> + Acc; +id2switch([{Sw, ID, _}|T], ID, Acc, _) -> + id2switch(T, ID, [Sw|Acc], true); +id2switch([_|_T], _ID, Acc, true) -> + Acc; +id2switch([_|T], ID, Acc, Found) -> + id2switch(T, ID, Acc, Found). + +%%------------------------------------------------------------ +%% function : switch2alias +%% Arguments: UList - The list of elements contained in the +%% Union TypeCode. +%% Switch - the union discriminator. +%% Returns : Acc - A list of switches that are defined with the same +%% ID - The switches common ID. +%% Comment : A union IDL code can look like: +%% union Union switch(long) { +%% case 1: +%% case 2: long ID; }; +%% In this case supplying Switch == 1 (or) the result +%% should be {ok, [1,2], "ID"} +%%------------------------------------------------------------ +switch2alias([], _Switch) -> + %% Is it really possible to define an empty union?? + {ok, [], undefined}; +switch2alias([{Sw, ID, TC}|UList], Switch) -> + switch2alias([{Sw, ID, TC}|UList], Switch, [], ID, false). + + +switch2alias([{default, ID, _}], _, _, _, false) -> + {ok, default, ID}; +switch2alias([], _, _Acc, _, false) -> + {ok, [], undefined}; +switch2alias([], _, Acc, PreviousID, _) -> + {ok, Acc, PreviousID}; + +%% Seen the ID before but just found the correct switch, e.g., +%% [... {0,"K",{tk_string,0}}, {2,"K",{tk_string,0}}...] and switch eq '2' +switch2alias([{Switch, PreviousID, _}|T], Switch, Acc, PreviousID, _Found) -> + switch2alias(T, Switch, [Switch|Acc], PreviousID, true); + +%% First time for this ID and found the correct switch +switch2alias([{Switch, ID, _}|T], Switch, _Acc, _PreviousID, false) -> + switch2alias(T, Switch, [Switch], ID, true); + +%% Seen this ID and found the correct switch before. +switch2alias([{Sw, PreviousID, _}|T], Switch, Acc, PreviousID, true) -> + switch2alias(T, Switch, [Sw|Acc], PreviousID, true); + +%% Seen this ID but not found the correct switch. +switch2alias([{Sw, PreviousID, _}|T], Switch, Acc, PreviousID, false) -> + switch2alias(T, Switch, [Sw|Acc], PreviousID, false); + +%% No more of the correct ID/Switch. Done. +switch2alias([{_, _ID, _}|_], _, Acc, PreviousID, true) -> + {ok, Acc, PreviousID}; +%% Not found correct switch and ID is updated. +switch2alias([{Sw, ID, _}|T], Switch, _Acc, _PreviousID, Found) -> + switch2alias(T, Switch, [Sw], ID, Found). + + +%%------------------------------------------------------------ +%% function : get_field +%% Arguments: ID - element name +%% List - The list of elements contained in the +%% TypeCode. +%% Returns : false | +%% offset +%%------------------------------------------------------------ +get_field(ID, List) -> + get_field(ID, List, 2). +get_field(_ID, [], _) -> + false; +get_field(ID, [ID|_], I) -> + %% Memberlists in enum. + I; +get_field(ID, [{ID,_}|_], I) -> + %% Memberlists in structs. + I; +get_field(ID, [_|T], I) -> + get_field(ID, T, I+1). + +%%------------------------------------------------------------ +%% function : check_types +%% Arguments: A sequence of CosNotification::EventType{}, i.e., +%% name-value pairs. +%% Returns : {ok, WhichType, WC} +%% WhichType - type/domain/both +%% WC - [Types using wildcard] +%%------------------------------------------------------------ +%% With check_types we try to determin if one or more EventTypes force us to check +%% all events against this constraint. For example: +%% EventType A1 has domain_name="car",type_name = "*" +%% EventType A2 has domain_name="*",type_name = "DodgeViper" +%% Since A1 says that we must test against any type_name and A2 +%% against any domain_name, we must test all events using these permutations. +%% It's better to do these test now instead of when we are up and running. But +%% if a client change the constraints VERY often it's up to them and they have +%% to accept the delay. +%%------------------------------------------------------------ + +%% If types is an empty list it means that this constraint must be used +%% for all events. +check_types([]) -> true; +check_types(Types) -> check_types(Types, both, []). +check_types([], Which, WildCard) -> {ok, Which, WildCard}; +%% The following cases means that all events matches. +check_types([#'CosNotification_EventType'{domain_name="",type_name = ""}|_T],_,_) -> + true; +check_types([#'CosNotification_EventType'{domain_name="",type_name = "*"}|_T],_,_) -> + true; +check_types([#'CosNotification_EventType'{domain_name="*",type_name = ""}|_T],_,_) -> + true; +check_types([#'CosNotification_EventType'{domain_name="*",type_name = "*"}|_T],_,_) -> + true; +%% The following cases means that all events must be tested using this constraint. +check_types([#'CosNotification_EventType'{domain_name="",type_name = Ty}|T], domain,WC) when is_list(Ty) -> + check_wildcard(T, all, WC, "", Ty); +check_types([#'CosNotification_EventType'{domain_name="*",type_name = Ty}|T], domain, WC) when is_list(Ty) -> + check_wildcard(T, all, WC, "", Ty); +check_types([#'CosNotification_EventType'{domain_name=Do,type_name = ""}|T], type,WC) when is_list(Do) -> + check_wildcard(T, all, WC, Do, ""); +check_types([#'CosNotification_EventType'{domain_name=Do,type_name = "*"}|T], type,WC) when is_list(Do) -> + check_wildcard(T, all, WC, Do, ""); +%% The following cases is used to prevent other cases from converting, +%% for example, all->type. +check_types([#'CosNotification_EventType'{domain_name="",type_name = Ty}|T], all,WC) when is_list(Ty) -> + check_wildcard(T, all, WC, "", Ty); +check_types([#'CosNotification_EventType'{domain_name="*",type_name = Ty}|T], all,WC) when is_list(Ty) -> + check_wildcard(T, all, WC, "", Ty); +check_types([#'CosNotification_EventType'{domain_name=Do,type_name = ""}|T], all,WC) when is_list(Do) -> + check_wildcard(T, all, WC, Do, ""); +check_types([#'CosNotification_EventType'{domain_name=Do,type_name = "*"}|T], all,WC) when is_list(Do) -> + check_wildcard(T, all, WC, Do, ""); +%% The following cases means that all events with matching Type must be +%% tested using this constraint. +check_types([#'CosNotification_EventType'{domain_name="",type_name = Ty}|T], _W,WC) when is_list(Ty) -> + check_wildcard(T, type, WC, "", Ty); +check_types([#'CosNotification_EventType'{domain_name="*",type_name = Ty}|T], _W,WC) when is_list(Ty) -> + check_wildcard(T, type, WC, "", Ty); +%% The following cases means that all events with matching Domain must be +%% tested using this constraint. +check_types([#'CosNotification_EventType'{domain_name=Do,type_name = ""}|T], _W,WC) when is_list(Do) -> + check_wildcard(T, domain, WC, Do, ""); +check_types([#'CosNotification_EventType'{domain_name=Do,type_name = "*"}|T], _W,WC) when is_list(Do) -> + check_wildcard(T, domain, WC, Do, ""); +%% Sorry, no shortcuts. +check_types([#'CosNotification_EventType'{domain_name=Do,type_name=Ty}|T], W,WC) when is_list(Do) andalso is_list(Ty) -> + check_wildcard(T, W, WC, Do, Ty); +check_types([H|_], _,_) when is_record(H, 'CosNotification_EventType') -> + %% Not valid. + corba:raise(#'CosNotifyComm_InvalidEventType'{type=H}); +check_types(_,_,_) -> + %% Wasn't even a correct input. + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +check_wildcard(Types, Which, WC, Domain, Type) -> + NewWC = + case {string:chr(Domain, $*), string:chr(Type, $*)} of + {0, 0} -> + WC; + {0, _}-> + [{type, Domain, convert_wildcard(Type, [])}|WC]; + {_, 0}-> + [{domain, convert_wildcard(Domain, []), Type}|WC]; + _-> + [{both, convert_wildcard(Domain, []), convert_wildcard(Type, [])}|WC] + end, + check_types(Types, Which, NewWC). + +%% Change '*' to '.*', see regexp:parse/2 documentation. +convert_wildcard([], Acc) -> + case regexp:parse(lists:reverse(Acc)) of + {ok, Expr} -> + Expr; + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; +convert_wildcard([$*|T], Acc) -> + convert_wildcard(T, [$*, $.|Acc]); +convert_wildcard([H|T], Acc) -> + convert_wildcard(T, [H|Acc]). + +%%------------------------------------------------------------ +%% function : match_types +%% Arguments: A sequence of {Which, Domain, Type}, i.e., the same as +%% returned from cosNotification_Filter:check_types/3 +%% Returns : bolean() +%%------------------------------------------------------------ +match_types(_, _, []) -> + false; +match_types(Domain, Type, [{domain, WCDomain, Type}|T]) -> + L=length(Domain), + case catch regexp:matches(Domain, WCDomain) of + {match, []} -> + match_types(Domain, Type, T); + {match, [{1, L}]} -> + true; + _-> + match_types(Domain, Type, T) + end; +match_types(Domain, Type, [{type, Domain, WCType}|T]) -> + L=length(Type), + case catch regexp:matches(Type, WCType) of + {match, []} -> + match_types(Domain, Type, T); + {match, [{1, L}]} -> + true; + _-> + match_types(Domain, Type, T) + end; +match_types(Domain, Type, [{both, WCDomain, WCType}|T]) -> + L1=length(Domain), + case catch regexp:matches(Domain, WCDomain) of + {match, []} -> + match_types(Domain, Type, T); + {match, [{1, L1}]} -> + L2=length(Type), + case catch regexp:matches(Type, WCType) of + {match, []} -> + match_types(Domain, Type, T); + {match, [{1, L2}]} -> + true; + _-> + match_types(Domain, Type, T) + end; + _-> + match_types(Domain, Type, T) + end; +match_types(Domain, Type, [_|T]) -> + match_types(Domain, Type, T). + +%%------------------------------------------------------------ +%% function : validate_types +%% Arguments: A sequence of CosNotification::EventType{}, i.e., +%% name-value pairs. +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyComm_InvalidEventType'{}} +%%------------------------------------------------------------ + +validate_types([]) -> + ok; +validate_types([#'CosNotification_EventType'{domain_name=Do,type_name=Ty}|T]) + when is_list(Do) andalso is_list(Ty) -> + validate_types(T); +validate_types([H|_]) + when is_record(H, 'CosNotification_EventType') -> + %% Not valid. + corba:raise(#'CosNotifyComm_InvalidEventType'{type=H}); +validate_types(_) -> + %% Wasn't even a correct input. + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/cosNotification_Grammar.yrl b/lib/cosNotification/src/cosNotification_Grammar.yrl new file mode 100644 index 0000000000..98233bf92d --- /dev/null +++ b/lib/cosNotification/src/cosNotification_Grammar.yrl @@ -0,0 +1,166 @@ +%%-------------------------------------------------------------------- +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%%-------------------------------------------------------------------- +%% File : cosNotification_Grammar.yrl +%% Purpose : Implement the constraint grammar for CosNotification filters. +%%-------------------------------------------------------------------- + +Nonterminals + '<toplevel>' '<constraint>' '<expr>' '<bool>' '<bool_or>' '<Ident>' + '<bool_and>' '<bool_compare>' '<expr_in>' '<expr_twiddle>' '<term>' + '<factor_not>' '<factor>' '<Component>' '<CompExt>' '<CompDot>' '<UnionVal>'. + +Terminals +% 'dbslsh' 'bslshd' + 'bslsh' 'ident' 'string' + '_length' '_d''_type_id' '_repos_id' + 'not' 'or' 'and' 'num' + 'in' '~' '.' 'dollar' + 'ADDOP' 'RELOP' 'MULOP' 'default' 'exist' + 'TRUE' 'FALSE' + '(' ')' '[' ']' 'int'. + +Left 100 'or'. +Left 200 'and'. +%Nonassoc 300 'RELOP'. % '==', '!=', '<', '>', '<=', '=>' +Left 300 'RELOP'. +%Nonassoc 400 'in'. +Left 400 'in'. +%Nonassoc 500 '~'. +Left 500 '~'. +Left 600 'ADDOP'. % '+', '-' +Left 700 'MULOP'. % '*', '/' +Unary 800 'not'. +Unary 900 'exist'. +Unary 900 'default'. +%Unary 900 'u-'. % unary minus + +Rootsymbol '<toplevel>'. +Endsymbol '$end'. + +'<toplevel>' -> '$empty' : '$empty'. +'<toplevel>' -> '<constraint>' : '$1'. + +'<constraint>' -> '<bool>' : '$1'. + +'<bool>' -> '<bool_or>' : '$1'. + +'<bool_or>' -> '<bool_or>' 'or' '<bool_and>' : {'or', '$1', '$3'}. +'<bool_or>' -> '<bool_and>' : '$1'. + +'<bool_and>' -> '<bool_and>' 'and' '<bool_compare>' : {'and', '$1', '$3'}. +'<bool_and>' -> '<bool_compare>' : '$1'. + +'<bool_compare>' -> '<expr_in>' 'RELOP' '<expr_in>' : {element(2, '$2'), '$1', '$3'}. +'<bool_compare>' -> '<expr_in>' : '$1'. + +'<expr_in>' -> '<expr_twiddle>' : '$1'. +'<expr_in>' -> '<expr_twiddle>' 'in' '<Ident>' : {'in', '$1', '$3'}. +'<expr_in>' -> '<expr_twiddle>' 'in' 'dollar' '<Component>' : {'in', '$1', examin_comp({'component', '$4'})}. + +'<expr_twiddle>' -> '<expr>' : '$1'. +'<expr_twiddle>' -> '<expr>' '~' '<expr>' : {'~', '$1', '$3'}. + +'<expr>' -> '<term>' : '$1'. +'<expr>' -> '<expr>' 'ADDOP' '<term>' : {element(2, '$2'), '$1', '$3'}. + +'<term>' -> '<factor_not>' : '$1'. +'<term>' -> '<term>' 'MULOP' '<factor_not>' : {element(2, '$2'), '$1', '$3'}. + +'<factor_not>' -> '<factor>' : '$1'. +'<factor_not>' -> 'not' '<factor>' : {'not', '$2'}. + +'<factor>' -> '(' '<bool_or>' ')' : '$2'. +'<factor>' -> 'num' : element(2, '$1'). +'<factor>' -> 'int' : element(2, '$1'). +'<factor>' -> 'string' : element(2, '$1'). +'<factor>' -> 'TRUE' : 'true'. +'<factor>' -> 'FALSE' : 'false'. +'<factor>' -> 'ADDOP' 'num' : create_unary(element(2, '$1'), element(2, '$2')). +'<factor>' -> 'ADDOP' 'int' : create_unary(element(2, '$1'), element(2, '$2')). +'<factor>' -> '<Ident>' : list_to_atom('$1'). +'<factor>' -> 'dollar' '<Component>' : examin_comp({component, '$2'}). +'<factor>' -> 'default' 'dollar' '<Component>' : examin_comp({'default_component', '$3'}). +'<factor>' -> 'exist' 'dollar' '<Component>' : examin_comp({'exist_component', '$3'}). + +%% The following rules are used to create Components. The format used is: +%% [...] +'<Component>' -> '.' '<CompDot>' : '$2'. +'<Component>' -> '[' 'int' ']' '<CompExt>' : [{'arrindex', element(2, '$2')} | '$4']. %% CompArray +'<Component>' -> '(' '<Ident>' ')' '<CompExt>' : [{'associd', '$2'} | '$4']. %%CompAssoc +'<Component>' -> '<Ident>' '<CompExt>' : [{'varid', '$1'} | '$2']. %% run-time variable +'<Component>' -> '$empty' : []. + +'<CompExt>' -> '.' '<CompDot>' : '$2'. +'<CompExt>' -> '[' 'int' ']' '<CompExt>' : [{'arrindex', element(2, '$2')} | '$4']. %% CompArray +'<CompExt>' -> '(' '<Ident>' ')' '<CompExt>' : [{'associd', '$2'} | '$4']. %%CompAssoc +'<CompExt>' -> '$empty' : []. + +'<CompDot>' -> '<Ident>' '<CompExt>' : [{'dotid', '$1'} | '$2']. +'<CompDot>' -> 'int' '<CompExt>' : [{'dotint', element(2, '$1')} | '$2']. %% ComPos +'<CompDot>' -> '(' '<UnionVal>' ')' '<CompExt>' : ['$2' | '$4']. %% UnionPos +'<CompDot>' -> '_length' : ['_length']. %% arrays or sequences ONLY +'<CompDot>' -> '_d' : ['_d']. %% discriminated unions ONLY +'<CompDot>' -> '_type_id' : ['_type_id']. %% ok if info can be obtained +'<CompDot>' -> '_repos_id' : ['_repos_id']. %% ok if info can be obtained + +'<Ident>' -> 'ident' : element(2, '$1'). +'<Ident>' -> 'bslsh' 'ident' : element(2, '$2'). + +'<UnionVal>' -> 'int' : {'uint', element(2, '$1')}. +'<UnionVal>' -> 'ADDOP' 'int' : {'uint', create_unary(element(2, '$1'), element(2, '$2'))}. +'<UnionVal>' -> 'string' : {'ustr', element(2, '$1')}. +'<UnionVal>' -> '$empty': 'default'. + +Erlang code. +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%%---------------------------------------------------------------------- +%% File : cosNotification_Grammar.erl +%% Purpose : THIS FILE HAS BEEN GENERATED. DO NOT EDIT!!!! +%%---------------------------------------------------------------------- + +-include("CosNotification_Definitions.hrl"). + +create_unary('+', Val) when is_number(Val) -> Val; +create_unary('-', Val) when is_number(Val) -> -Val; +create_unary(_, _) -> return_error(0, "syntax error"). + +examin_comp({T, []}) -> + {T, '$empty'}; +examin_comp(V) -> + V. + diff --git a/lib/cosNotification/src/cosNotification_Scanner.erl b/lib/cosNotification/src/cosNotification_Scanner.erl new file mode 100644 index 0000000000..e9c54319f0 --- /dev/null +++ b/lib/cosNotification/src/cosNotification_Scanner.erl @@ -0,0 +1,268 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosNotification_Scanner.erl +%% Purpose : Scan and pre-process a grammar. +%%---------------------------------------------------------------------- + +-module('cosNotification_Scanner'). + +-export([scan/1]). + +scan(Str) -> + RSL = scan(Str, 1, [], any), + {ok, lists:reverse(RSL)}. + + +%% Guard macros used at top scan functions only +-define(is_number(X), X >= $0, X =< $9). +-define(is_upper(X), X >= $A, X =< $Z). +-define(is_lower(X), X >= $a, X =< $z). + +%%---------------------------------------------------------------------- +%% scan +%% +%% A-Z +scan([X|Str], Line, Out, Type) when ?is_upper(X) -> + scan_name(Str, [X], Line, Out, Type); +%% a-z +scan([X|Str], Line, Out, Type) when ?is_lower(X) -> + scan_name(Str, [X], Line, Out, Type); +%% 0-9 +scan([X|Str], Line, Out, Type) when ?is_number(X) -> + scan_number(Str, [X], Line, Out, Type); + +%% RELOP:s == != <= >= > < +scan([$=,$= | Str], Line, Out, _Type) -> + scan(Str, Line, [{'RELOP', '=='} | Out], any); +scan([$!,$= | Str], Line, Out, _Type) -> + scan(Str, Line, [{'RELOP', '!='} | Out], any); +scan([$<,$= | Str], Line, Out, _Type) -> + scan(Str, Line, [{'RELOP', '<='} | Out], any); +scan([$>,$= | Str], Line, Out, _Type) -> + scan(Str, Line, [{'RELOP', '>='} | Out], any); +scan([$> | Str], Line, Out, _Type) -> + scan(Str, Line, [{'RELOP', '>'} | Out], any); +scan([$< | Str], Line, Out, _Type) -> + scan(Str, Line, [{'RELOP', '<'} | Out], any); + +%% ADDOP:s + - +scan([$+ | Str], Line, Out, Type) -> + scan(Str, Line, [{'ADDOP', '+'} | Out], Type); +scan([$- | Str], Line, Out, Type) -> + scan(Str, Line, [{'ADDOP', '-'} | Out], Type); + +%% MULOP:s * / +scan([$* | Str], Line, Out, _Type) -> + scan(Str, Line, [{'MULOP', '*'} | Out], any); +scan([$/ | Str], Line, Out, _Type) -> + scan(Str, Line, [{'MULOP', '/'} | Out], any); + +%% TAB +scan([9| T], Line, Out, Type) -> scan(T, Line, Out, Type); +%% SP +scan([32| T], Line, Out, Type) -> scan(T, Line, Out, Type); +%% CR +scan([$\r|Str], Line, Out, Type) -> + scan(Str, Line, Out, Type); +%% LF +scan([$\n|Str], Line, Out, Type) -> + scan(Str, Line+1, Out, Type); +%% \\ +scan([92, 92 | Str], Line, Out, Type) -> + scan(Str, Line, [{'dbslsh', Line} | Out], Type); +%% \' +scan([92, 39 | Str], Line, Out, Type) -> + scan(Str, Line, [{'bslshd', Line} | Out], Type); +%% '\' +scan([92 | Str], Line, Out, Type) -> + scan(Str, Line, [{'bslsh', Line} | Out], Type); +%% '_' +scan([$_ | Str], Line, Out, dollar) -> + scan_name(Str, [$_], Line, Out, dollar); +%% '$' +scan([$$, 92 | Str], Line, Out, _Type) -> + scan(Str, Line, [{'bslsh', Line}, {'dollar', Line} | Out], dollar); +scan([$$ | Str], Line, Out, _Type) -> + scan(Str, Line, [{'dollar', Line} | Out], dollar); +scan([$"|Str], Line, Out, Type) -> + scan_const(char, Str, [], Line, Out, Type); +scan([$'|Str], Line, Out, Type) -> + scan_const(string, Str, [], Line, Out, Type); + +%% Writing '+.<CompDot>' is not allowed ('+' or '-' are only allowed +%% as unary for <UnionVal> (within a component) which must be en integer). +scan([$. | Str], Line, [{'ADDOP', Op}|Out], _) -> + scan_frac(Str, [$.], Line, [{'ADDOP', Op}|Out], any); +%% Must be a <CompDot> +scan([$. | Str], Line, Out, dollar) -> + scan(Str, Line, [{'.',Line} | Out], dollar); +%% Number +scan([$. | Str], Line, Out, Type) -> + scan_frac(Str, [$.], Line, Out, Type); +scan([C|Str], Line, Out, Type) -> + scan(Str, Line, [{list_to_atom([C]), Line} | Out], Type); + +scan([], _Line, Out, _Type) -> + Out. + +%%---------------------------------------------------------------------- +%% scan_name +%% + +scan_number([X|Str], Accum, Line, Out, Type) when ?is_number(X) -> + scan_number(Str, [X|Accum], Line, Out, Type); +scan_number([X|Str], Accum, Line, Out, dollar) when X==$. -> + scan(Str, Line, [{'.', Line}, + {'int', list_to_integer(lists:reverse(Accum))} | Out], dollar); +scan_number([X|Str], Accum, Line, Out, Type) when X==$. -> + scan_frac(Str, [X|Accum], Line, Out, Type); +scan_number([X|Str], Accum, Line, Out, Type) when X==$e -> + scan_exp(Str, [X|Accum], Line, Out, Type); +scan_number([X|Str], Accum, Line, Out, Type) when X==$E -> + scan_exp(Str, [X|Accum], Line, Out, Type); +scan_number(Str, Accum, Line, Out, Type) -> + scan(Str, Line, [{'int', list_to_integer(lists:reverse(Accum))} | Out], Type). + + +%% Floating point number scan. +%% +%% Non trivial scan. A float consists of an integral part, a +%% decimal point, a fraction part, an e or E and a signed integer +%% exponent. Either the integer part or the fraction part but not +%% both may be missing, and either the decimal point or the +%% exponent part but not both may be missing. The exponent part +%% must consist of an e or E and a possibly signed exponent. +%% +%% Analysis shows that "1." ".7" "1e2" ".5e-3" "1.7e2" "1.7e-2" +%% is allowed and "1" ".e9" is not. The sign is only allowed just +%% after an e or E. The scanner reads a number as an integer +%% until it encounters a "." so the integer part only error case +%% will not be caught in the scanner (but rather in expression +%% evaluation) + +scan_frac([$e | _Str], [$.], _Line, _Out, _Type) -> + {error, "illegal_float"}; +scan_frac([$E | _Str], [$.], _Line, _Out, _Type) -> + {error, "illegal_float"}; +scan_frac(Str, Accum, Line, Out, Type) -> + scan_frac2(Str, Accum, Line, Out, Type). + +scan_frac2([X|Str], Accum, Line, Out, Type) when ?is_number(X) -> + scan_frac2(Str, [X|Accum], Line, Out, Type); +scan_frac2([X|Str], Accum, Line, Out, Type) when X==$e -> + scan_exp(Str, [X|Accum], Line, Out, Type); +scan_frac2([X|Str], Accum, Line, Out, Type) when X==$E -> + scan_exp(Str, [X|Accum], Line, Out, Type); +%% Since '.2' is allowed, we add '0' in front to be sure (erlang do not allow +%% list_to_float(".2") and list_to_float("0.2") eq. list_to_float("00.2")). +scan_frac2(Str, Accum, Line, Out, Type) -> + scan(Str, Line, [{'num', list_to_float([$0|lists:reverse(Accum)])} | Out], Type). + +scan_exp([X|Str], Accum, Line, Out, Type) when X==$- -> + scan_exp2(Str, [X|Accum], Line, Out, Type); +scan_exp(Str, Accum, Line, Out, Type) -> + scan_exp2(Str, Accum, Line, Out, Type). + +scan_exp2([X|Str], Accum, Line, Out, Type) when ?is_number(X) -> + scan_exp2(Str, [X|Accum], Line, Out, Type); +%% Since '.2' is allowed, we add '0' in front to be sure (erlang do not allow +%% list_to_float(".2")). +scan_exp2(Str, Accum, Line, Out, Type) -> + scan(Str, Line, [{'num', list_to_float([$0|lists:reverse(Accum)])} | Out], Type). + + +scan_name([X|Str], Accum, Line, Out, Type) when ?is_upper(X) -> + scan_name(Str, [X|Accum], Line, Out, Type); +scan_name([X|Str], Accum, Line, Out, Type) when ?is_lower(X) -> + scan_name(Str, [X|Accum], Line, Out, Type); +scan_name([X|Str], Accum, Line, Out, Type) when ?is_number(X) -> + scan_name(Str, [X|Accum], Line, Out, Type); +scan_name([$_|Str], Accum, Line, Out, dollar) -> + scan_name(Str, [$_|Accum], Line, Out, dollar); +scan_name(S, Accum, Line, [{bslsh,LL} | Out], Type) -> + %% An escaped identifier. + L = lists:reverse(Accum), + scan(S, Line, [{'ident', L}, {bslsh,LL} | Out], Type); +scan_name(S, Accum, Line, Out, Type) -> + L = lists:reverse(Accum), + {X, NewType} = case check_name(L) of + false -> + {{'ident', L}, Type}; + _ -> + {{list_to_atom(L), Line}, any} + end, + scan(S, Line, [X | Out], NewType). + +%% Shall scan a constant +scan_const(char, [$" | Rest], Accum, Line, Out, Type) -> + scan(Rest, Line, + [{'ident', list_to_atom(lists:reverse(Accum))} | Out], Type); +scan_const(char, [], _Accum, _Line, Out, _Type) -> %% Bad string +% {error, "bad_string"}; + Out; +scan_const(string, [$' | Rest], Accum, Line, Out, Type) -> + scan(Rest, Line, + [{'string', lists:reverse(Accum)} | Out], Type); +scan_const(Mode, [$\\, C | Rest], Accum, Line, Out, Type) -> + case escaped_char(C) of + error -> + %% Bad escape character + %% {error, "bad_escape_character"}; + scan_const(Mode, Rest, [C | Accum], Line, Out, Type); + EC -> + scan_const(Mode, Rest, [EC | Accum], Line, Out, Type) + end; +scan_const(Mode, [C | Rest], Accum, Line, Out, Type) -> + scan_const(Mode, Rest, [C | Accum], Line, Out, Type). + +%% Escaped character. Escaped chars are repr as two characters in the +%% input list of letters and this is translated into one char. +escaped_char($n) -> $\n; +escaped_char($t) -> $\t; +escaped_char($v) -> $\v; +escaped_char($b) -> $\b; +escaped_char($r) -> $ ; +escaped_char($f) -> $\f; +escaped_char($a) -> $\a; +escaped_char($\\) -> $\\; +escaped_char($?) -> $?; +escaped_char($') -> $'; +escaped_char($") -> $"; +%% Error +escaped_char(_Other) -> error. + + +check_name("exist") -> true; +check_name("default") -> true; +check_name("_length") -> true; +check_name("_d") -> true; +check_name("_type_id") -> true; +check_name("_repos_id") -> true; +check_name("not") -> true; +check_name("or") -> true; +check_name("and") -> true; +check_name("FALSE") -> true; +check_name("TRUE") -> true; +check_name("in") -> true; +check_name(_) -> false. + + diff --git a/lib/cosNotification/src/cosNotification_eventDB.erl b/lib/cosNotification/src/cosNotification_eventDB.erl new file mode 100644 index 0000000000..89332d53f2 --- /dev/null +++ b/lib/cosNotification/src/cosNotification_eventDB.erl @@ -0,0 +1,1350 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosNotification_eventDB.erl +%% Purpose : +%% Purpose : This module is supposed to centralize Event storage. +%% Comments: +%% * Setting Order Policy to AnyOrder eq. Priority order +%% +%% * Setting Discard Policy to AnyOrder eq. RejectNewEvents. +%% +%% * DB ordering: Since the deliver- and discard-order may differ we need +%% two ets-tables, both of type 'ordered_set'. They contain: +%% - table 1 (T1): deliver order key and the associated event. +%% - table 2 (T2): discard order key. +%% +%% When adding a new event we add, if necessary, related keys in T2. +%% For example, if we should discard events in FIFO order, the delivery +%% order may be set to Priority order. If the Max Event limit is reached +%% we first look in T2 to find out which event to discard by using and +%% reorder the key elements. T2 gives {TimeStamp, Priority}, which is used +%% to lookup in T1 as {Priority, TimeStamp}. +%% A TimeStamp is always included in the DB keys, even if FIFO or LIFO +%% is used, since lots of events probably will have the same prioity and +%% with a little bit of bad luck some events will never be delivered. +%% +%% Note: deliver order AnyOrder and PriorityOrder is equal since the later +%% is defined as default. +%% discard order AnyOrder and RejectNewEvents is equal since the later +%% is defined as default. +%% The keys used is ('-' indicates T2 is not needed and, thus, not instantiated): +%% +%% T1 policy T1 Key T2 Policy T2 Key +%% ------------------------------------------------------------------ +%% DeadlineOrder {DL, Key, Prio} PriorityOrder {Prio, Key, DL} +%% DeadlineOrder {DL, Key} FifoOrder {Key, DL} +%% DeadlineOrder {DL, Key} LifoOrder {Key, DL} +%% DeadlineOrder {DL, Key} RejectNewEvents - +%% DeadlineOrder {DL, Key} DeadlineOrder - +%% FifoOrder {Key, DL} DeadlineOrder {DL, Key} +%% FifoOrder {Key, Prio} PriorityOrder {Prio, Key} +%% FifoOrder Key RejectNewEvents - +%% FifoOrder Key Fifo - +%% FifoOrder Key Lifo - +%% PriorityOrder {Prio, Key, DL} DeadlineOrder {DL, Key, Prio} +%% PriorityOrder {Prio, Key} Fifo {Key, Prio} +%% PriorityOrder {Prio, Key} Lifo {Key, Prio} +%% PriorityOrder {Prio, Key} RejectNewEvents - +%% ------------------------------------------------------------------ +%% DL == Deadline, Key == TimeStamp, Prio == Priority +%% +%% NOTE: If defined, the Discard DB Keys are the same as in Event DB, except +%% that the first and last Key change place. {K1,K2}<->{K2,K1} and +%% {K1,K2,K3}<->{K3,K2,K1}. +%%---------------------------------------------------------------------- + +-module(cosNotification_eventDB). + + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +-include_lib("cosTime/include/TimeBase.hrl"). + +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). + +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%% Internal Filter Functions +-export([validate_event/5, + create_db/4, + destroy_db/1, + get_event/1, + get_event/2, + get_events/2, + get_events/3, + delete_events/1, + update/2, + update/4, + add_event/2, + add_event/4, + add_and_get_event/2, + add_and_get_event/3, + add_and_get_event/4, + add_and_get_event/5, + gc_events/2, + gc_events_local/4, + gc_start/2, + filter_events/2, + filter_events/3, + status/2]). + +%%--------------- DATA STRUCTURES ---------------------------- +-record(dbRef, {orderRef, discardRef, orderPolicy, discardPolicy, + defPriority, maxEvents, defStopT, startTsupport, + stopTsupport, gcTime, gcLimit, timeRef}). + + + +%%--------------- DEFINES ------------------------------------ + +-define(CreateRef(OR, DR, O, D, DP, ME, DS, StaT, StoT, GT, GL, TR), + #dbRef{orderRef=OR, discardRef=DR, orderPolicy=O, discardPolicy=D, + defPriority=DP, maxEvents=ME, defStopT=DS, startTsupport=StaT, + stopTsupport=StoT, gcTime=GT, gcLimit=round(ME*GL/100), + timeRef=TR}). + + +-define(get_OrderP(DR), DR#dbRef.orderPolicy). +-define(get_DiscardP(DR), DR#dbRef.discardPolicy). +-define(get_OrderRef(DR), DR#dbRef.orderRef). +-define(get_DiscardRef(DR), DR#dbRef.orderRef). +-define(get_DefPriority(DR), DR#dbRef.defPriority). +-define(get_MaxEvents(DR), DR#dbRef.maxEvents). +-define(get_DefStopT(DR), DR#dbRef.defStopT). +-define(get_StartTsupport(DR), DR#dbRef.startTsupport). +-define(get_StopTsupport(DR), DR#dbRef.stopTsupport). +-define(get_GCTime(DR), DR#dbRef.gcTime). +-define(get_GCLimit(DR), DR#dbRef.gcLimit). +-define(get_TimeRef(DR), DR#dbRef.timeRef). + +-define(set_OrderP(DR, O), DR#dbRef{orderPolicy = O}). +-define(set_DiscardP(DR, D), DR#dbRef{discardPolicy = D}). +-define(set_OrderRef(DR, E), DR#dbRef{orderRef = E}). +-define(set_DiscardRef(DR, E), DR#dbRef{orderRef = E}). +-define(set_DefPriority(DR, DP), DR#dbRef{defPriority = DP}). +-define(set_MaxEvents(DR, ME), DR#dbRef{maxEvents = ME}). +-define(set_DefStopT(DR, DS), DR#dbRef{defStopT = DS}). +-define(set_StartTsupport(DR, B), DR#dbRef{startTsupport = B}). +-define(set_StopTsupport(DR, B), DR#dbRef{stopTsupport = B}). + +-define(is_StartTNotSupported(DR), DR#dbRef.startTsupport == false). +-define(is_StopTNotSupported(DR), DR#dbRef.stopTsupport == false). +-define(is_TimeoutNotUsed(DR), DR#dbRef.defStopT == 0). + + +%%------------------------------------------------------------ +%% function : status +%% Arguments: DBRef +%% Key - which information we want. +%% Returns : Data related to the Key. +%%------------------------------------------------------------ +status(DBRef, eventCounter) -> + ets:info(?get_OrderRef(DBRef), size); +status(DBRef, {batchLimit, Limit}) -> + case ets:info(?get_OrderRef(DBRef), size) of + Current when is_integer(Current) andalso Current >= Limit -> + ?debug_print("BATCH LIMIT (~p) REACHED, CONTAINS: ~p~n", [Limit, Current]), + true; + _Other -> + ?debug_print("BATCH LIMIT (~p) NOT REACHED, CONTAINS: ~p~n", + [Limit, _Other]), + false + end; +status(DBRef, {batchLimit, Limit, TemporaryMax}) -> + case ets:info(?get_OrderRef(DBRef), size) of + Current when is_integer(Current) andalso Current >= TemporaryMax -> + ?debug_print("MAX LIMIT (~p) REACHED, CONTAINS: ~p~n", + [TemporaryMax, Current]), + true; + Current when is_integer(Current) andalso Current >= Limit -> + ?debug_print("BATCH LIMIT (~p) REACHED, CONTAINS: ~p~n", [Limit, Current]), + true; + _Other -> + ?debug_print("BATCH LIMIT (~p) NOT REACHED, CONTAINS: ~p~n", + [Limit, _Other]), + false + end; +status(_, _) -> + error. + + +%%------------------------------------------------------------ +%% function : gc_events_local +%% Arguments: DBRef +%% Returns : +%% Comment : This function is intended for "emergency" GC, i.e., +%% when the DB must discard events we should first try +%% to remove events with expired deadlines. +%%------------------------------------------------------------ +gc_events_local(_, _, false, _) -> + ok; +gc_events_local(_, _, _, 0) -> + ok; +gc_events_local(ORef, DRef, _, _) -> + gc_loop(ets:first(ORef), ORef, DRef). + +%%------------------------------------------------------------ +%% function : gc_events +%% Arguments: DBRef +%% Priority - 'low', 'medium' or 'high'; will determine +%% how important a fast gc is. +%% Returns : +%% Comment : This function is intended for background GC. +%%------------------------------------------------------------ +gc_events(DBRef, _Priority) when ?is_TimeoutNotUsed(DBRef) -> + ok; +gc_events(DBRef, _Priority) when ?is_StopTNotSupported(DBRef) -> + ok; +gc_events(DBRef, Priority) -> + {M,S,U} = now(), + case get(oe_GC_timestamp) of + Num when {M,S,U} > Num -> + put(oe_GC_timestamp, {M,S+?get_GCTime(DBRef),U}), + spawn_link(?MODULE, gc_start, [DBRef, Priority]); + _-> + ok + end. + + +%%------------------------------------------------------------ +%% function : gc_start +%% Arguments: +%% Returns : +%%------------------------------------------------------------ +gc_start(#dbRef{orderRef = ORef, discardRef = DRef}, Priority) -> + process_flag(priority, Priority), + gc_loop(ets:first(ORef), ORef, DRef). + +gc_loop('$end_of_table', _, _) -> + ok; +gc_loop(Key, ORef, DRef) -> + [{Keys,DL,_,_,_}]=ets:lookup(ORef, Key), + case check_deadline(DL) of + true when DRef == undefined -> + ets:delete(ORef, Key); + true -> + ets:delete(ORef, Key), + gc_discard_DB(Keys, DRef); + _ -> + ok + end, + gc_loop(ets:next(ORef, Key), ORef, DRef). + +gc_discard_DB({Key1, Key2}, DRef) -> + ets:delete(DRef, {Key2, Key1}); +gc_discard_DB({Key1, Key2, Key3}, DRef) -> + ets:delete(DRef, {Key3, Key2, Key1}). + +%%------------------------------------------------------------ +%% function : create_FIFO_Key +%% Arguments: +%% Returns : +%%------------------------------------------------------------ +create_FIFO_Key() -> + {M, S, U} = erlang:now(), + -M*1000000000000 - S*1000000 - U. + +%%------------------------------------------------------------ +%% function : convert_FIFO_Key +%% Arguments: +%% Returns : A now tuple +%% Comment : Used when we must reuse a timestamp, i.e., only +%% when we must reorder the DB. +%%------------------------------------------------------------ +convert_FIFO_Key(Key) -> + K = abs(Key), + Secs = trunc(K/1000000), + M = trunc(K/1000000000000), + S = Secs-M*1000000, + U = K - S*1000000-M*1000000000000, + {M, S, U}. + +%%------------------------------------------------------------ +%% function : extract_priority +%% Arguments: Event +%% Defalt Value +%% Mapping Filter Value +%% - false value not needed (depends on QoS type) +%% - undefined value needed but no filter associated. +%% Returns : +%%------------------------------------------------------------ +extract_priority(_, _, false) -> + false; +extract_priority(#'CosNotification_StructuredEvent' + {header = #'CosNotification_EventHeader' + {variable_header = VH}}, DefPriority, undefined) -> + extract_value(VH, ?not_Priority, DefPriority); +%% Maybe a unstructured event. +extract_priority(_, DefPriority, undefined) -> + DefPriority; +extract_priority(_, _, PriorityOverride) -> + %% Must have an associated MappingFilter for Priority. + PriorityOverride. + +%%------------------------------------------------------------ +%% function : extract_start_time +%% Arguments: +%% Returns : +%%------------------------------------------------------------ +extract_start_time(_, false, _) -> + false; +extract_start_time(#'CosNotification_StructuredEvent' + {header = #'CosNotification_EventHeader' + {variable_header = VH}}, _, TRef) -> + ST = case extract_value(VH, ?not_StartTime, undefined) of + UTC when is_record(UTC, 'TimeBase_UtcT') -> + UTC; + _ -> + false + end, + convert_time(ST, TRef, now()); +extract_start_time(_, _, _) -> + false. + +%%------------------------------------------------------------ +%% function : extract_deadline +%% Arguments: Structured Event +%% Default Timeout Value - TimeT or UtcT (see cosTime). +%% StopTSupported - boolean(). +%% TRef - reference to TimeService +%% Mapping Filter Value +%% - false eq. value not needed (depends on QoS type) +%% - undefined eq. value needed but no filter associated. +%% Now - used when we want to reuse old TimeStamp which +%% must be done when changing QoS. +%% Returns : A modified return from now(). +%%------------------------------------------------------------ +extract_deadline(_, _, _, _, false) -> + false; +extract_deadline(Event, DefaultT, StopTSupported, TRef, MappingVal) -> + extract_deadline(Event, DefaultT, StopTSupported, TRef, MappingVal, now()). + +extract_deadline(_, _, _, _, false, _) -> + false; +extract_deadline(#'CosNotification_StructuredEvent' + {header = #'CosNotification_EventHeader' + {variable_header = VH}}, DefaultT, StopTSupported, + TRef, undefined, Now) -> + DL = case extract_value(VH, ?not_Timeout, undefined) of + undefined when StopTSupported == true, TRef =/= undefined -> + case extract_value(VH, ?not_StopTime, undefined) of + undefined -> + DefaultT; + DefinedTime -> + DefinedTime + end; + undefined -> + DefaultT; + DefinedTime -> + DefinedTime + end, + convert_time(DL, TRef, Now); +%% Maybe a unstructured event. +extract_deadline(_, Time, _, TRef, undefined, Now) -> + convert_time(Time, TRef, Now); +extract_deadline(_, _, _, TRef, DOverride, Now) -> + %% Must have an associated MappingFilter defining a Deadline. + convert_time(DOverride, TRef, Now). + +convert_time(0, _, _) -> + false; +convert_time(UTC, TRef, {M,S,U}) when is_record(UTC, 'TimeBase_UtcT') -> + case catch get_time_diff(UTC, TRef) of + {'EXCEPTION', _} -> + false; + {'EXIT', _} -> + false; + DL -> + MicroSecs = round(DL/10), + Secs = round(MicroSecs/1000000), + MegaSecs = round(Secs/1000000), + {-M-MegaSecs, -S-Secs+MegaSecs, -U-MicroSecs+Secs} + end; +convert_time(DL, _, {M,S,U}) when is_integer(DL) -> + MicroSecs = round(DL/10), + Secs = round(MicroSecs/1000000), + MegaSecs = round(Secs/1000000), + {-M-MegaSecs, -S-Secs+MegaSecs, -U-MicroSecs+Secs}; +convert_time(_, _, _) -> + false. + + +get_time_diff(UTC, TRef) -> + UTO = 'CosTime_TimeService':universal_time(TRef), + UTO2 = 'CosTime_TimeService':uto_from_utc(TRef, UTC), + TIO = 'CosTime_UTO':time_to_interval(UTO, UTO2), + #'TimeBase_IntervalT'{lower_bound=LB, upper_bound = UB} = + 'CosTime_TIO':'_get_time_interval'(TIO), + UB-LB. + +check_deadline(DL) when is_tuple(DL) -> + {M,S,U} = now(), + DL >= {-M,-S,-U}; +check_deadline(_DL) -> + %% This case will cover if no timeout is set. + false. + +check_start_time(ST) when is_tuple(ST) -> + {M,S,U} = now(), + ST >= {-M,-S,-U}; +check_start_time(_ST) -> + %% This case will cover if no earliest delivery time is set. + true. + +%%------------------------------------------------------------ +%% function : extract_value +%% Arguments: A Property Sequence +%% ID - wanted property string() +%% Other - default-value. +%% Returns : Value associated with given ID or default value. +%%------------------------------------------------------------ +extract_value([], _, Other) -> + Other; +extract_value([#'CosNotification_Property'{name=ID, value=V}|_], ID, _) -> + any:get_value(V); +extract_value([_H|T], ID, Other) -> + extract_value(T, ID, Other). + +%%------------------------------------------------------------ +%% function : get_event +%% Arguments: +%% Returns : +%%------------------------------------------------------------ +get_event(DBRef) -> + get_event(DBRef, true). +get_event(DBRef, Delete) -> + case get_events(DBRef, 1, Delete) of + {[], false} -> + {[], false}; + {[], false, Keys} -> + {[], false, Keys}; + {[Event], Bool} -> + {Event, Bool}; + {[Event], Bool, Keys} -> + {Event, Bool, Keys} + end. + +%%------------------------------------------------------------ +%% function : get_events +%% Arguments: +%% Returns : A list of events (possibly empty) and a boolean +%% indicating if event found. +%% Comments : Try to extract Max events from the database. +%%------------------------------------------------------------ +get_events(#dbRef{orderRef = ORef, discardRef = DRef}, Max) -> + event_loop(ets:last(ORef), ORef, DRef, Max, [], [], true). + +get_events(#dbRef{orderRef = ORef, discardRef = DRef}, Max, Delete) -> + event_loop(ets:last(ORef), ORef, DRef, Max, [], [], Delete). + +event_loop('$end_of_table', _, _, _, [], _, true) -> + {[], false}; +event_loop('$end_of_table', _, _, _, [], [], _) -> + {[], false, []}; +event_loop('$end_of_table', _ORef, _, _, Accum, _Keys, true) -> + {lists:reverse(Accum), true}; +event_loop('$end_of_table', _ORef, _, _, Accum, Keys, _) -> + {lists:reverse(Accum), true, Keys}; +event_loop(_, _ORef, _, 0, [], _Keys, true) -> + %% Only possible if some tries to pull a sequence of 0 events. + %% Should we really test for this case? + {[], false}; +event_loop(_, _ORef, _, 0, [], Keys, _) -> + {[], false, Keys}; +event_loop(_, _ORef, _, 0, Accum, _Keys, true) -> + {lists:reverse(Accum), true}; +event_loop(_, _ORef, _, 0, Accum, Keys, _) -> + {lists:reverse(Accum), true, Keys}; +event_loop(Key, ORef, undefined, Left, Accum, Keys, Delete) -> + [{_,DL,ST,_PO,Event}]=ets:lookup(ORef, Key), + case check_deadline(DL) of + true -> + ets:delete(ORef, Key), + event_loop(ets:prev(ORef, Key), ORef, undefined, + Left, Accum, Keys, Delete); + false -> + case check_start_time(ST) of + true when Delete == true -> + ets:delete(ORef, Key), + event_loop(ets:prev(ORef, Key), ORef, undefined, + Left-1, [Event|Accum], Keys, Delete); + true -> + event_loop(ets:prev(ORef, Key), ORef, undefined, + Left-1, [Event|Accum], [{ORef, Key}|Keys], Delete); + false -> + event_loop(ets:prev(ORef, Key), ORef, undefined, + Left, Accum, Keys, Delete) + end + end; +event_loop({Key1, Key2}, ORef, DRef, Left, Accum, Keys, Delete) -> + [{_,DL,ST,_PO,Event}]=ets:lookup(ORef, {Key1, Key2}), + case check_deadline(DL) of + true -> + ets:delete(ORef, {Key1, Key2}), + ets:delete(DRef, {Key2, Key1}), + event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef, + Left, Accum, Keys, Delete); + false -> + case check_start_time(ST) of + true when Delete == true -> + ets:delete(ORef, {Key1, Key2}), + ets:delete(DRef, {Key2, Key1}), + event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef, + Left-1, [Event|Accum], Keys, Delete); + true -> + event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef, + Left-1, [Event|Accum], + [{ORef, {Key1, Key2}}, {DRef, {Key2, Key1}}|Keys], + Delete); + false -> + event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef, + Left, Accum, Keys, Delete) + end + end; +event_loop({Key1, Key2, Key3}, ORef, DRef, Left, Accum, Keys, Delete) -> + [{_,DL,ST,_PO,Event}]=ets:lookup(ORef, {Key1, Key2, Key3}), + case check_deadline(DL) of + true -> + ets:delete(ORef, {Key1, Key2, Key3}), + ets:delete(DRef, {Key3, Key2, Key1}), + event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef, + Left, Accum, Keys, Delete); + false -> + case check_start_time(ST) of + true when Delete == true -> + ets:delete(ORef, {Key1, Key2, Key3}), + ets:delete(DRef, {Key3, Key2, Key1}), + event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef, + Left-1, [Event|Accum], Keys, Delete); + true -> + event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef, + Left-1, [Event|Accum], + [{ORef, {Key1, Key2, Key3}}, + {DRef, {Key3, Key2, Key1}}|Keys], Delete); + false -> + event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef, + Left, Accum, Keys, Delete) + end + end. + +%%------------------------------------------------------------ +%% function : delete_events +%% Arguments: EventList - what's returned by get_event, get_events +%% and add_and_get_event. +%% Returns : +%% Comment : Shall be invoked when it's safe to premanently remove +%% the events found in the EventList. +%% +%%------------------------------------------------------------ +delete_events([]) -> + ok; +delete_events([{DB, Key}|T]) -> + ets:delete(DB, Key), + delete_events(T). + +%%------------------------------------------------------------ +%% function : update +%% Arguments: +%% Returns : +%% Comment : As default we shall deliver Events in Priority order. +%% Hence, if AnyOrder set we will still deliver in +%% Priority order. +%%------------------------------------------------------------ +update(undefined, _QoS) -> + ok; +update(DBRef, QoS) -> + update(DBRef, QoS, undefined, undefined). + +update(DBRef, QoS, LifeFilter, PrioFilter) -> + case updated_order(DBRef, ?not_GetOrderPolicy(QoS)) of + false -> + case updated_discard(DBRef, ?not_GetDiscardPolicy(QoS)) of + false -> + DBR2 = ?set_DefPriority(DBRef, ?not_GetPriority(QoS)), + DBR3 = ?set_MaxEvents(DBR2, ?not_GetMaxEventsPerConsumer(QoS)), + DBR4 = ?set_DefStopT(DBR3, ?not_GetTimeout(QoS)), + DBR5 = ?set_StartTsupport(DBR4, ?not_GetStartTimeSupported(QoS)), + DBR6 = ?set_StopTsupport(DBR5, ?not_GetStopTimeSupported(QoS)), + case ets:info(?get_OrderRef(DBR6), size) of + N when N =< ?get_MaxEvents(DBR6) -> + %% Even if the QoS MaxEvents have been changed + %% we don't reach the limit. + DBR6; + N -> + %% The QoS MaxEvents must have been decreased. + discard_events(DBR6, N-?get_MaxEvents(DBR6)), + DBR6 + end; + true -> + destroy_discard_db(DBRef), + NewDBRef = create_db(QoS, ?get_GCTime(DBRef), ?get_GCLimit(DBRef), + ?get_TimeRef(DBRef)), + move_events(DBRef, NewDBRef, ets:first(?get_OrderRef(DBRef)), + LifeFilter, PrioFilter) + end; + true -> + destroy_discard_db(DBRef), + NewDBRef = create_db(QoS, ?get_GCTime(DBRef), ?get_GCLimit(DBRef), + ?get_TimeRef(DBRef)), + move_events(DBRef, NewDBRef, ets:first(?get_OrderRef(DBRef)), + LifeFilter, PrioFilter) + end. + +updated_order(#dbRef{orderPolicy = Equal}, Equal) -> false; +updated_order(#dbRef{orderPolicy = ?not_PriorityOrder}, ?not_AnyOrder) -> false; +updated_order(#dbRef{orderPolicy = ?not_AnyOrder}, ?not_PriorityOrder) -> false; +updated_order(_, _) -> true. + +updated_discard(#dbRef{discardPolicy = Equal}, Equal) -> false; +updated_discard(#dbRef{discardPolicy = ?not_RejectNewEvents}, ?not_AnyOrder) -> false; +updated_discard(#dbRef{discardPolicy = ?not_AnyOrder}, ?not_RejectNewEvents) -> false; +updated_discard(_, _) -> true. + +move_events(DBRef, NewDBRef, '$end_of_table', _, _) -> + destroy_order_db(DBRef), + case ets:info(?get_OrderRef(NewDBRef), size) of + N when N =< ?get_MaxEvents(NewDBRef) -> + %% Even if the QoS MaxEvents have been changed + %% we don't reach the limit. + NewDBRef; + N -> + %% The QoS MaxEvents must have been decreased. + discard_events(DBRef, N-?get_MaxEvents(NewDBRef)), + NewDBRef + end; +move_events(DBRef, NewDBRef, Key, LifeFilter, PrioFilter) -> + [{Keys, DeadLine, StartTime, PriorityOverride, Event}] = + ets:lookup(?get_OrderRef(DBRef), Key), + case check_deadline(DeadLine) of + true -> + ok; + _-> + write_event(?get_OrderP(DBRef), + {Keys, DeadLine, StartTime, PriorityOverride, Event}, + DBRef, NewDBRef, Key, LifeFilter, PrioFilter) + end, + ets:delete(?get_OrderRef(DBRef), Key), + move_events(DBRef, NewDBRef, ets:next(?get_OrderRef(DBRef), Key), + LifeFilter, PrioFilter). + +%% We cannot use do_add_event directly since we MUST lookup the timestamp (TS). +write_event(?not_DeadlineOrder, {{_, TS, _Prio}, DL, ST, PO, Event}, _DBRef, NewDBRef, + _Key, _LifeFilter, _PrioFilter) -> + StartT = update_starttime(NewDBRef, Event, ST), + %% Deadline and Priority previously extracted. + do_add_event(NewDBRef, Event, TS, DL, StartT, PO); +write_event(?not_DeadlineOrder, {{_, TS}, DL, _ST, PO, Event}, _DBRef, NewDBRef, + _Key, _LifeFilter, PrioFilter) -> + %% Priority not previously extracted. + POverride = update_priority(NewDBRef, PrioFilter, Event, PO), + StartT = extract_start_time(Event, ?get_StartTsupport(NewDBRef), + ?get_TimeRef(NewDBRef)), + do_add_event(NewDBRef, Event, TS, DL, StartT, POverride); +write_event(?not_FifoOrder, {{TS, _PorD}, DL, ST, PO, Event}, _DBRef, NewDBRef, + _Key, LifeFilter, PrioFilter) -> + %% Priority or Deadline have been extracted before but we cannot tell which. + POverride = update_priority(NewDBRef, PrioFilter, Event, PO), + DeadL = update_deadline(NewDBRef, LifeFilter, Event, TS, DL), + StartT = update_starttime(NewDBRef, Event, ST), + do_add_event(NewDBRef, Event, TS, DeadL, StartT, POverride); +write_event(?not_FifoOrder, {TS, DL, ST, PO, Event}, _DBRef, NewDBRef, + _Key, LifeFilter, PrioFilter) -> + %% Priority and Deadline not extracetd before. Do it now. + POverride = update_priority(NewDBRef, PrioFilter, Event, PO), + DeadL = update_deadline(NewDBRef, LifeFilter, Event, TS, DL), + StartT = update_starttime(NewDBRef, Event, ST), + do_add_event(NewDBRef, Event, TS, DeadL, StartT, POverride); +%% Order Policy must be AnyOrder or PriorityOrder. +write_event(_, {{_Prio, TS}, DL, ST, PO, Event}, _DBRef, NewDBRef, + _Key, LifeFilter, _PrioFilter) -> + DeadL = update_deadline(NewDBRef, LifeFilter, Event, TS, DL), + StartT = update_starttime(NewDBRef, Event, ST), + do_add_event(NewDBRef, Event, TS, DeadL, StartT, PO); +write_event(_, {{_Prio, TS, DL}, DL, ST, PO, Event}, _DBRef, NewDBRef, _Key, _, _) -> + %% Both Deadline and Priority have been extracetd before. + StartT = update_starttime(NewDBRef, Event, ST), + do_add_event(NewDBRef, Event, TS, DL, StartT, PO). + + +%%------------------------------------------------------------ +%% function : update_priority +%% Arguments: +%% Returns : +%% Comment : The purpose with this function is to avoid +%% calling MappingFilter priority again, especially +%% deadline again (we especially want to avoid calling +%% since it may require intra-ORB communication. +%% Use only when doing an update. +%%------------------------------------------------------------ +update_priority(DBRef, PrioFilter, Event, OldPrio) when is_atom(OldPrio) -> + get_prio_mapping_value(DBRef, PrioFilter, Event); +update_priority(_DBRef, _PrioFilter, _Event, OldPrio) -> + OldPrio. + +%%------------------------------------------------------------ +%% function : update_deadline +%% Arguments: +%% Returns : +%% Comment : The purpose with this function is to avoid +%% calling MappingFilter or parsing the events for +%% deadline again (we especially want to avoid calling +%% the MappingFilter since it may require intra-ORB +%% communication. Use only when doing an update. +%%------------------------------------------------------------ +update_deadline(DBRef, _LifeFilter, _Event, _TS, _OldDeadL) when + ?get_DiscardP(DBRef) =/= ?not_DeadlineOrder, + ?get_OrderP(DBRef) =/= ?not_DeadlineOrder, + ?is_StopTNotSupported(DBRef) -> + %% We do not need to extract the Deadline since it will not be used. + false; +update_deadline(DBRef, LifeFilter, Event, TS, OldDeadL) when is_atom(OldDeadL) -> + %% We need the Deadline and it have not been extracetd before. + DOverride = get_life_mapping_value(DBRef, LifeFilter, Event), + %% We must find out when the event was delivered; setting a deadline using + %% a new timestamp would not be accurate since we cannot tell for how long + %% the event have been waiting. + OldNow = convert_FIFO_Key(TS), + extract_deadline(Event, ?get_DefStopT(DBRef), ?get_StopTsupport(DBRef), + ?get_TimeRef(DBRef), DOverride, OldNow); +update_deadline(_DBRef, _LifeFilter, _Event, _TS, OldDeadL) -> + %% We need the Deadline and it have been extracetd before. + OldDeadL. + +%%------------------------------------------------------------ +%% function : update_starttime +%% Arguments: +%% Returns : +%% Comment : The purpose with this function is to avoid +%% parsing the events for starttime again. +%% Use only when doing an update. +%%------------------------------------------------------------ +update_starttime(DBRef, Event, OldStartT) when is_atom(OldStartT) -> + %% Probably not previously extracted; try to get it. + extract_start_time(Event, ?get_StartTsupport(DBRef), ?get_TimeRef(DBRef)); +update_starttime(_DBRef, _Event, OldStartT) -> + %% Previously extracted. + OldStartT. + +%%------------------------------------------------------------ +%% function : discard_events +%% Arguments: DBRef +%% N - number of events we must discard. +%% Returns : +%% Comment : As default we shall Reject New Events when the limit +%% is reached. Any discard order will do the same. +%% +%% This function can only be used for the discard policies +%% Fifo, Priority and Deadline. Any or RejectNewEvents +%% will not allow events to be stored at all, i.e., no events +%% to discard. Lifo will not be stored either since when +%% trying to add an event it is definitely the last event in. +%%------------------------------------------------------------ +%% Since no Discard DB must the same Order policy. +discard_events(#dbRef{orderRef = ORef, discardRef = undefined, + discardPolicy = ?not_DeadlineOrder}, N) -> + ?debug_print("Discarding ~p events Deadline Order.",[N]), + index_loop_backward(ets:last(ORef), undefined, ORef, N); +discard_events(#dbRef{orderRef = ORef, discardRef = DRef, + discardPolicy = ?not_DeadlineOrder}, N) -> + ?debug_print("Discarding ~p events Deadline Order.",[N]), + index_loop_backward(ets:last(DRef), DRef, ORef, N); +%% Fifo. +discard_events(#dbRef{orderRef = ORef, discardRef = undefined, + discardPolicy = ?not_FifoOrder}, N) -> + ?debug_print("Discarding ~p events Fifo Order.",[N]), + index_loop_backward(ets:last(ORef), undefined, ORef, N); +discard_events(#dbRef{orderRef = ORef, discardRef = DRef, + discardPolicy = ?not_FifoOrder}, N) -> + ?debug_print("Discarding ~p events Fifo Order.",[N]), + index_loop_backward(ets:last(DRef), DRef, ORef, N); +%% Lifo- or Priority-Order +discard_events(#dbRef{orderRef = ORef, discardRef = undefined}, N) -> + ?debug_print("Discarding ~p events Lifo- or Priority-Order.",[N]), + index_loop_forward(ets:first(ORef), undefined, ORef, N); +discard_events(#dbRef{orderRef = ORef, discardRef = DRef}, N) -> + ?debug_print("Discarding ~p events Lifo- or Priority-Order.",[N]), + index_loop_forward(ets:first(DRef), DRef, ORef, N). + + +index_loop_forward('$end_of_table', _, _, _Left) -> + ok; +index_loop_forward(_, _, _, 0) -> + ok; +index_loop_forward(Key, undefined, ORef, Left) -> + ets:delete(ORef, Key), + NewKey=ets:next(ORef, Key), + index_loop_forward(NewKey, undefined, ORef, Left-1); + +index_loop_forward({Key1, Key2, Key3}, DRef, ORef, Left) -> + ets:delete(DRef, {Key1, Key2, Key3}), + ets:delete(ORef, {Key3, Key2, Key1}), + NewKey=ets:next(DRef, {Key1, Key2, Key3}), + index_loop_forward(NewKey, DRef, ORef, Left-1); + +index_loop_forward({Key1, Key2}, DRef, ORef, Left) -> + ets:delete(DRef, {Key1, Key2}), + ets:delete(ORef, {Key2, Key1}), + NewKey=ets:next(DRef, {Key1, Key2}), + index_loop_forward(NewKey, DRef, ORef, Left-1). + +index_loop_backward('$end_of_table', _, _, _) -> + ok; +index_loop_backward(_, _, _, 0) -> + ok; +index_loop_backward(Key, undefined, ORef, Left) -> + ets:delete(ORef, Key), + NewKey=ets:prev(ORef, Key), + index_loop_backward(NewKey, undefined, ORef, Left-1); +index_loop_backward({Key1, Key2}, DRef, ORef, Left) -> + ets:delete(DRef, {Key1, Key2}), + ets:delete(ORef, {Key2, Key1}), + NewKey=ets:prev(DRef, {Key1, Key2}), + index_loop_backward(NewKey, DRef, ORef, Left-1); +index_loop_backward({Key1, Key2, Key3}, DRef, ORef, Left) -> + ets:delete(DRef, {Key1, Key2, Key3}), + ets:delete(ORef, {Key3, Key2, Key1}), + NewKey=ets:prev(DRef, {Key1, Key2, Key3}), + index_loop_backward(NewKey, DRef, ORef, Left-1). + +%%------------------------------------------------------------ +%% function : add_and_get_event +%% Arguments: DBRef and Event +%% Returns : {[], bool()} | {Event, bool()} +%% Comment : This function is a mixture of ad anf get events. +%% The intended use to avoid storing an event when +%% not necessary. +%%------------------------------------------------------------ +add_and_get_event(DBRef, Event) -> + add_and_get_event(DBRef, Event, undefined, undefined, true). + +add_and_get_event(DBRef, Event, Delete) -> + add_and_get_event(DBRef, Event, undefined, undefined, Delete). + +add_and_get_event(DBRef, Event, LifeFilter, PrioFilter) -> + add_and_get_event(DBRef, Event, LifeFilter, PrioFilter, true). + +add_and_get_event(DBRef, Event, LifeFilter, PrioFilter, Delete) -> + case ets:info(?get_OrderRef(DBRef), size) of + 0 when ?is_StartTNotSupported(DBRef), ?is_StopTNotSupported(DBRef), + Delete == true -> + %% No stored events and no timeouts used; just return the event. + {Event, false}; + 0 when ?is_StartTNotSupported(DBRef), ?is_StopTNotSupported(DBRef) -> + %% No stored events and no timeouts used; just return the event. + {Event, false, []}; + 0 when ?is_StartTNotSupported(DBRef) -> + %% Only deadline supported, lookup values and cehck if ok. + DOverride = get_life_mapping_value(DBRef, LifeFilter, Event), + DL = extract_deadline(Event, ?get_DefStopT(DBRef), + ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef), + DOverride), + case check_deadline(DL) of + true when Delete == true -> + %% Expired, just discard the event. + {[], false}; + true -> + {[], false, []}; + _ when Delete == true -> + %% Not expired, we can safely return the event. + {Event, false}; + _ -> + %% Not expired, we can safely return the event. + {Event, false, []} + end; + 0 when ?is_StopTNotSupported(DBRef) -> + %% Only starttime allowed, test if we can deliver the event now. + ST = extract_start_time(Event, ?get_StartTsupport(DBRef), + ?get_TimeRef(DBRef)), + case check_start_time(ST) of + false when Delete == true -> + DOverride = get_life_mapping_value(DBRef, LifeFilter, Event), + POverride = get_prio_mapping_value(DBRef, PrioFilter, Event), + DL = extract_deadline(Event, ?get_DefStopT(DBRef), + ?get_StopTsupport(DBRef), + ?get_TimeRef(DBRef), DOverride), + do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride), + {[], true}; + false -> + DOverride = get_life_mapping_value(DBRef, LifeFilter, Event), + POverride = get_prio_mapping_value(DBRef, PrioFilter, Event), + DL = extract_deadline(Event, ?get_DefStopT(DBRef), + ?get_StopTsupport(DBRef), + ?get_TimeRef(DBRef), DOverride), + do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride), + {[], true, []}; + _ when Delete == true -> + %% Starttime ok, just return the event. + {Event, false}; + _ -> + %% Starttime ok, just return the event. + {Event, false, []} + end; + _-> + %% Event already stored, just have to accept the overhead. + ST = extract_start_time(Event, ?get_StartTsupport(DBRef), + ?get_TimeRef(DBRef)), + DOverride = get_life_mapping_value(DBRef, LifeFilter, Event), + POverride = get_prio_mapping_value(DBRef, PrioFilter, Event), + DL = extract_deadline(Event, ?get_DefStopT(DBRef), + ?get_StopTsupport(DBRef), + ?get_TimeRef(DBRef), DOverride), + do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride), + get_event(DBRef, Delete) + end. + +%%------------------------------------------------------------ +%% function : add_event +%% Arguments: DBRef and Event +%% Returns : true (or whatever 'ets:insert' returns) | +%% {'EXCEPTION', #'IMP_LIMIT'{}} +%% Comment : As default we shall deliver Events in Priority order. +%% Hence, if AnyOrder set we will still deliver in +%% Priority order. But we cannot use only the Priority +%% value since if "all" events have the same priority +%% there is a risk that some never will be delivered if +%% the EventDB always contain events. +%% +%% When discard and order policy is equal we only use one +%% DB since all we have to do is to "read from the other +%% end" to discard the correct event(s). +%% +%% In the discard DB we must also store keys necessary to +%% lookup the event in the order DB. +%% +%% If event limit reached 'IMPL_LIMIT' is raised if +%% the discard policy is RejectNewEvents or AnyOrder. +%% Theses two policies we currently define to be equal. +%%------------------------------------------------------------ + +add_event(DBRef, Event) -> + %% Save overhead by first checking if we really need to extract + %% Deadline and/or Priority. + Deadline = get_life_mapping_value(DBRef, undefined, Event), + Priority = get_prio_mapping_value(DBRef, undefined, Event), + add_event_helper(DBRef, Event, Deadline, Priority). + +add_event(DBRef, Event, LifeFilter, PrioFilter) -> + %% Save overhead by first checking if we really need to extract + %% Deadline and/or Priority. + Deadline = get_life_mapping_value(DBRef, LifeFilter, Event), + Priority = get_prio_mapping_value(DBRef, PrioFilter, Event), + add_event_helper(DBRef, Event, Deadline, Priority). + +add_event_helper(DBRef, Event, DOverride, POverride) -> + case ets:info(?get_OrderRef(DBRef), size) of + N when N < ?get_MaxEvents(DBRef), N > ?get_GCLimit(DBRef) -> + gc_events(DBRef, low), + DL = extract_deadline(Event, ?get_DefStopT(DBRef), + ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef), + DOverride), + case check_deadline(DL) of + true -> + true; + _ -> + ST = extract_start_time(Event, ?get_StartTsupport(DBRef), + ?get_TimeRef(DBRef)), + do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride) + end; + N when N < ?get_MaxEvents(DBRef) -> + DL = extract_deadline(Event, ?get_DefStopT(DBRef), + ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef), + DOverride), + case check_deadline(DL) of + true -> + true; + _ -> + ST = extract_start_time(Event, ?get_StartTsupport(DBRef), + ?get_TimeRef(DBRef)), + do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride) + end; + _N when ?get_DiscardP(DBRef) == ?not_RejectNewEvents -> + gc_events(DBRef, low), + corba:raise(#'IMP_LIMIT'{completion_status=?COMPLETED_NO}); + _N when ?get_DiscardP(DBRef) == ?not_AnyOrder -> + gc_events(DBRef, low), + corba:raise(#'IMP_LIMIT'{completion_status=?COMPLETED_NO}); + _N when ?get_DiscardP(DBRef) == ?not_LifoOrder -> + gc_events(DBRef, low), + corba:raise(#'IMP_LIMIT'{completion_status=?COMPLETED_NO}); + _N -> + gc_events(DBRef, low), + %% Other discard policy; we must first store the event + %% and the look up in the Discard DB which event we + %% should remove. + DL = extract_deadline(Event, ?get_DefStopT(DBRef), + ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef), + DOverride), + case check_deadline(DL) of + true -> + true; + _ -> + ST = extract_start_time(Event, ?get_StartTsupport(DBRef), + ?get_TimeRef(DBRef)), + do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride), + discard_events(DBRef, 1) + end + end. + + +do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder, + discardRef = DRef, discardPolicy = ?not_PriorityOrder, + defPriority = DefPrio, defStopT = _DefStopT}, Event, Key, DL, ST, PO) -> + Prio = extract_priority(Event, DefPrio, PO), + ets:insert(ORef, {{DL, Key, Prio}, DL, ST, PO, Event}), + ets:insert(DRef, {{Prio, Key, DL}}); +do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder, + discardRef = DRef, discardPolicy = ?not_FifoOrder, + defStopT = _DefStopT}, Event, Key, DL, ST, PO) -> + ets:insert(ORef, {{DL, Key}, DL, ST, PO, Event}), + ets:insert(DRef, {{Key, DL}}); +do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder, + discardRef = DRef, discardPolicy = ?not_LifoOrder, + defStopT = _DefStopT}, Event, Key, DL, ST, PO) -> + ets:insert(ORef, {{DL, Key}, DL, ST, PO, Event}), + ets:insert(DRef, {{Key, DL}}); +%% Either the same (DeadlineOrder), RejectNewEvents or AnyOrder. No need +%% to store anything in the discard policy, i.e., if the same we'll just +%% read "from the other end" and AnyOrder and RejectNewEvents is equal. +do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder, + defStopT = _DefStopT}, Event, Key, DL, ST, PO) -> + ets:insert(ORef, {{DL, Key}, DL, ST, PO, Event}); + + +do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_FifoOrder, + discardRef = DRef, discardPolicy = ?not_DeadlineOrder, + defStopT = _DefStopT}, Event, Key, DL, ST, PO) -> + ets:insert(ORef, {{Key, DL}, DL, ST, PO, Event}), + ets:insert(DRef, {{DL, Key}}); +do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_FifoOrder, + discardRef = DRef, discardPolicy = ?not_PriorityOrder, + defPriority = DefPrio}, Event, Key, DL, ST, PO) -> + Prio = extract_priority(Event, DefPrio, PO), + ets:insert(ORef, {{Key, Prio}, DL, ST, PO, Event}), + ets:insert(DRef, {{Prio, Key}}); +%% The discard policy must RejectNewEvents, AnyOrder, Fifo or Lifo order. +do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_FifoOrder, + discardRef = _DRef}, Event, Key, DL, ST, PO) -> + ets:insert(ORef, {Key, DL, ST, PO, Event}); + +%% Order Policy must be AnyOrder or PriorityOrder. +do_add_event(#dbRef{orderRef = ORef, + discardRef = DRef, discardPolicy = ?not_DeadlineOrder, + defPriority = DefPrio, defStopT = _DefStopT}, Event, Key, DL, ST, PO) -> + Prio = extract_priority(Event, DefPrio, PO), + ets:insert(ORef, {{Prio, Key, DL}, DL, ST, PO, Event}), + ets:insert(DRef, {{DL, Key, Prio}}); +do_add_event(#dbRef{orderRef = ORef, + discardRef = DRef, discardPolicy = ?not_FifoOrder, + defPriority = DefPrio}, Event, Key, DL, ST, PO) -> + Prio = extract_priority(Event, DefPrio, PO), + ets:insert(ORef, {{Prio, Key}, DL, ST, PO, Event}), + ets:insert(DRef, {{Key, Prio}}); + +do_add_event(#dbRef{orderRef = ORef, + discardRef = DRef, discardPolicy = ?not_LifoOrder, + defPriority = DefPrio}, Event, Key, DL, ST, PO) -> + Prio = extract_priority(Event, DefPrio, PO), + ets:insert(ORef, {{Prio, Key}, DL, ST, PO, Event}), + ets:insert(DRef, {{Key, Prio}}); + +%% Order Policy must be AnyOrder or PriorityOrder and Discard Policy must be +%% AnyOrder or RejectNewEvents +do_add_event(#dbRef{orderRef = ORef, defPriority = DefPrio}, Event, Key, DL, ST, PO) -> + Prio = extract_priority(Event, DefPrio, PO), + ets:insert(ORef, {{Prio, Key}, DL, ST, PO, Event}). + +%%------------------------------------------------------------ +%% function : destroy_db +%% Arguments: A DB reference +%% Returns : +%%------------------------------------------------------------ +destroy_db(#dbRef{orderRef = ORef, discardRef = undefined}) -> + ets:delete(ORef); +destroy_db(#dbRef{orderRef = ORef, discardRef = DRef}) -> + ets:delete(ORef), + ets:delete(DRef). + +%%------------------------------------------------------------ +%% function : destroy_discard_db +%% Arguments: A DB reference +%% Returns : +%%------------------------------------------------------------ +destroy_discard_db(#dbRef{discardRef = undefined}) -> + ok; +destroy_discard_db(#dbRef{discardRef = DRef}) -> + ets:delete(DRef). + +%%------------------------------------------------------------ +%% function : destroy_order_db +%% Arguments: A DB reference +%% Returns : +%%------------------------------------------------------------ +destroy_order_db(#dbRef{orderRef = ORef}) -> + ets:delete(ORef). + +%%------------------------------------------------------------ +%% function : create_db +%% Arguments: QoS (local representation). +%% Returns : A DB reference +%%------------------------------------------------------------ +create_db(QoS, GCTime, GCLimit, TimeRef) -> + DiscardRef = + case {?not_GetDiscardPolicy(QoS), ?not_GetOrderPolicy(QoS)} of + {Equal, Equal} -> + undefined; + {?not_PriorityOrder, ?not_AnyOrder} -> + %% NOTE: Any- and Priority-Order delivery policy is equal. + undefined; + {?not_RejectNewEvents, _} -> + undefined; + {?not_AnyOrder, _} -> + undefined; + {?not_LifoOrder, ?not_FifoOrder} -> + undefined; + _ -> + ets:new(oe_ets, [set, public, ordered_set]) + end, + DBRef = ?CreateRef(ets:new(oe_ets, [set, public, ordered_set]), + DiscardRef, + ?not_GetOrderPolicy(QoS), ?not_GetDiscardPolicy(QoS), + ?not_GetPriority(QoS), ?not_GetMaxEventsPerConsumer(QoS), + ?not_GetTimeout(QoS), ?not_GetStartTimeSupported(QoS), + ?not_GetStopTimeSupported(QoS), GCTime, GCLimit, TimeRef), + if + ?is_TimeoutNotUsed(DBRef), ?is_StopTNotSupported(DBRef) -> + ok; + true -> + {M,S,U} = now(), + put(oe_GC_timestamp, {M,S+GCTime,U}) + end, + DBRef. + +%%------------------------------------------------------------ +%% function : get_prio_mapping_value +%% Arguments: A MappingFilter reference | undefined +%% Event (Any or Structured) +%% Returns : undefined | Data +%%------------------------------------------------------------ +get_prio_mapping_value(DBRef, _, _) when ?get_DiscardP(DBRef) =/= ?not_PriorityOrder, + ?get_OrderP(DBRef) =/= ?not_AnyOrder, + ?get_OrderP(DBRef) =/= ?not_PriorityOrder -> + false; +get_prio_mapping_value(_, undefined, _) -> + undefined; +get_prio_mapping_value(_, MFilter, Event) when is_record(Event, 'any') -> + case catch 'CosNotifyFilter_MappingFilter':match(MFilter, Event) of + {false, DefVal} when is_record(DefVal, 'any') -> + any:get_value(DefVal); + {true, Matched} when is_record(Matched, 'any') -> + any:get_value(Matched); + _ -> + undefined + end; +get_prio_mapping_value(_, MFilter, Event) -> + case catch 'CosNotifyFilter_MappingFilter':match_structured(MFilter, Event) of + {false, DefVal} when is_record(DefVal, 'any') -> + any:get_value(DefVal); + {true, Matched} when is_record(Matched, 'any') -> + any:get_value(Matched); + _ -> + undefined + end. + +%%------------------------------------------------------------ +%% function : get_life_mapping_value +%% Arguments: A MappingFilter reference | undefined +%% Event (Any or Structured) +%% Returns : undefined | Data +%%------------------------------------------------------------ +get_life_mapping_value(DBRef, _, _) when ?get_DiscardP(DBRef) =/= ?not_DeadlineOrder, + ?get_OrderP(DBRef) =/= ?not_DeadlineOrder, + ?is_StopTNotSupported(DBRef) -> + false; +get_life_mapping_value(_, undefined, _) -> + undefined; +get_life_mapping_value(_, MFilter, Event) when is_record(Event, 'any') -> + case catch 'CosNotifyFilter_MappingFilter':match(MFilter, Event) of + {false, DefVal} when is_record(DefVal, 'any') -> + any:get_value(DefVal); + {true, Matched} when is_record(Matched, 'any') -> + any:get_value(Matched); + _ -> + undefined + end; +get_life_mapping_value(_, MFilter, Event) -> + case catch 'CosNotifyFilter_MappingFilter':match_structured(MFilter, Event) of + {false, DefVal} when is_record(DefVal, 'any') -> + any:get_value(DefVal); + {true, Matched} when is_record(Matched, 'any') -> + any:get_value(Matched); + _ -> + undefined + end. + +%%------------------------------------------------------------ +%% function : validate_event +%% Arguments: Subscribe data +%% A sequence of Events, 'structured' or an 'any' record +%% A list of filter references +%% Status, i.e., do we have to filter the events or just check subscr. +%% Returns : A tuple of two lists; list1 the events that passed +%% and list2 the events that didn't pass. +%%------------------------------------------------------------ +validate_event(true, Events, Filters, _, 'MATCH') -> + filter_events(Events, Filters, false); +validate_event(true, Events, _Filters, _, _) -> + {Events, []}; +validate_event({_Which, _WC}, Event, Filters, _, 'MATCH') when is_record(Event, any) -> + filter_events(Event, Filters, false); +validate_event({_Which, _WC}, Event, _Filters, _, _) when is_record(Event, any) -> + {Event, []}; +validate_event({Which, WC}, Events, Filters, DBRef, 'MATCH') -> + Passed=validate_event2(DBRef, Events, Which, WC, []), + filter_events(Passed, Filters, true); +validate_event({Which, WC}, Events, _Filters, DBRef, _) -> + Passed=validate_event2(DBRef, Events, Which, WC, []), + {lists:reverse(Passed), []}. + +validate_event2(_, [], _, _, []) -> + []; +validate_event2(_, [], _, _, Acc) -> + Acc; +validate_event2(DBRef, [Event|T], Which, WC, Acc) -> + ET = ((Event#'CosNotification_StructuredEvent'.header) + #'CosNotification_EventHeader'.fixed_header) + #'CosNotification_FixedEventHeader'.event_type, + CheckList = + case Which of + both -> + [ET]; + domain -> + [ET, + ET#'CosNotification_EventType'{type_name=""}, + ET#'CosNotification_EventType'{type_name="*"}]; + type -> + [ET, + ET#'CosNotification_EventType'{domain_name=""}, + ET#'CosNotification_EventType'{domain_name="*"}]; + _ -> + [ET, + ET#'CosNotification_EventType'{type_name=""}, + ET#'CosNotification_EventType'{type_name="*"}, + ET#'CosNotification_EventType'{domain_name=""}, + ET#'CosNotification_EventType'{domain_name="*"}] + end, + case check_subscription(DBRef, CheckList) of + true -> + validate_event2(DBRef, T, Which, WC, [Event|Acc]); + _-> + case catch cosNotification_Filter:match_types( + ET#'CosNotification_EventType'.domain_name, + ET#'CosNotification_EventType'.type_name, + WC) of + true -> + validate_event2(DBRef, T, Which, WC, [Event|Acc]); + _-> + validate_event2(DBRef, T, Which, WC, Acc) + end + end. + +check_subscription(_, []) -> + false; +check_subscription(DBRef, [H|T]) -> + case ets:lookup(DBRef, H) of + [] -> + check_subscription(DBRef, T); + _ -> + true + end. + + +%%------------------------------------------------------------ +%% function : filter_events +%% Arguments: A sequence of structured Events or #any +%% Returns : A tuple of two lists; list1 the events that passed +%% and list2 the events that didn't pass. +%%------------------------------------------------------------ + +filter_events(Events, []) -> + {Events, []}; +filter_events(Events, Filters) -> + filter_events(Events, Filters, [], [], false). + +filter_events(Events, [], false) -> + {Events, []}; +filter_events(Events, [], _) -> + {lists:reverse(Events), []}; +filter_events(Events, Filters, Reversed) -> + filter_events(Events, Filters, [], [], Reversed). + +filter_events([], _, AccPassed, AccFailed, false) -> + {lists:reverse(AccPassed), lists:reverse(AccFailed)}; +filter_events([], _, AccPassed, AccFailed, _) -> + {AccPassed, AccFailed}; +filter_events([H|T], Filters, AccPassed, AccFailed, Reversed) -> + case call_filters(Filters, H) of + true -> + filter_events(T, Filters, [H|AccPassed], AccFailed, Reversed); + _ -> + filter_events(T, Filters, AccPassed, [H|AccFailed], Reversed) + end; +filter_events(Any, Filters, _AccPassed, _AccFailed, _Reversed) -> + case call_filters(Filters, Any) of + true -> + {Any, []}; + _ -> + {[], Any} + end. + +call_filters([], _) -> + false; +call_filters([{_,H}|T], Event) when is_record(Event, any) -> + case catch 'CosNotifyFilter_Filter':match(H, Event) of + true -> + true; + _-> + call_filters(T, Event) + end; +call_filters([{_,H}|T], Event) when ?not_isConvertedAny(Event) -> + case catch 'CosNotifyFilter_Filter':match(H, + Event#'CosNotification_StructuredEvent'.remainder_of_body) of + true -> + true; + _-> + call_filters(T, Event) + end; +call_filters([{_,H}|T], Event) -> + case catch 'CosNotifyFilter_Filter':match_structured(H, Event) of + true -> + true; + _-> + call_filters(T, Event) + end. + + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/vsn.mk b/lib/cosNotification/vsn.mk new file mode 100644 index 0000000000..65f9812f31 --- /dev/null +++ b/lib/cosNotification/vsn.mk @@ -0,0 +1,11 @@ +COSNOTIFICATION_VSN = 1.1.12 + +TICKETS = OTP-8201 + +TICKETS_1.1.11 = OTP-7987 + +TICKETS_1.1.10 = OTP-7837 + +TICKETS_1.1.9 = OTP-7595 + +TICKETS_1.1.8 = OTP-7553 |