From c514805c7d8a8da459dd17b7f0cda2f272da9f8f Mon Sep 17 00:00:00 2001 From: Alexandre Lision <alexandre.lision@savoirfairelinux.com> Date: Wed, 4 Mar 2015 15:10:35 -0500 Subject: [PATCH] ui: add call screen interface - in/out animation - switch calls in conversation tree - basic controls over call: accept/hangup/hold - video Refs #67611 Change-Id: I1d302d2539cb473e27ea469781b72f44963eb0a0 --- CMakeLists.txt | 3 + ConversationsViewController.h | 7 +- ConversationsViewController.mm | 63 ++-- CurrentCall.xib | 650 +++++++++++++++++++++++++++++++++ CurrentCallVC.h | 45 +++ CurrentCallVC.mm | 450 +++++++++++++++++++++++ HistoryViewController.h | 7 +- HistoryViewController.mm | 95 ++--- PreferencesViewController.mm | 3 - RingWindow.xib | 300 ++++++++------- RingWindowController.h | 2 +- RingWindowController.mm | 110 +++++- 12 files changed, 1505 insertions(+), 230 deletions(-) create mode 100644 CurrentCall.xib create mode 100644 CurrentCallVC.h create mode 100644 CurrentCallVC.mm diff --git a/CMakeLists.txt b/CMakeLists.txt index 58fd995e..d838c7fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,7 @@ SET(ringclient_SRCS AccAdvancedVC.mm AccSecurityVC.mm AccountsVC.mm + CurrentCallVC.mm AudioPrefsVC.mm VideoPrefsVC.mm GeneralPrefsVC.mm @@ -47,6 +48,7 @@ SET(ringclient_SRCS SET(ringclient_FORMS MainMenu.xib RingWindow.xib + CurrentCall.xib GeneralPrefs.xib Accounts.xib AccGeneral.xib @@ -62,6 +64,7 @@ SET(ringclient_FORMS SET(ringclient_HDRS AppDelegate.h RingWindowController.h + CurrentCallVC.h ConversationsViewController.h PreferencesViewController.h AccGeneralVC.h diff --git a/ConversationsViewController.h b/ConversationsViewController.h index 2d62f7a5..09d4e3bc 100644 --- a/ConversationsViewController.h +++ b/ConversationsViewController.h @@ -34,12 +34,9 @@ #import "QNSTreeController.h" @interface ConversationsViewController : NSViewController <NSOutlineViewDelegate> { - NSOutlineView *conversationsView; -} -@property QNSTreeController *treeController; -@property (assign) IBOutlet NSOutlineView *conversationsView; +} @end -#endif // CONVERSATIONSVC_H \ No newline at end of file +#endif // CONVERSATIONSVC_H diff --git a/ConversationsViewController.mm b/ConversationsViewController.mm index 456d4f4b..c545ee3a 100644 --- a/ConversationsViewController.mm +++ b/ConversationsViewController.mm @@ -30,29 +30,30 @@ #import "ConversationsViewController.h" #import <callmodel.h> +#import <QtCore/qitemselectionmodel.h> + +#import "CurrentCallVC.h" #define COLUMNID_CONVERSATIONS @"ConversationsColumn" // the single column name in our outline view @interface ConversationsViewController () +@property CurrentCallVC* currentVC; +@property (assign) IBOutlet NSView *currentCallView; +@property QNSTreeController *treeController; +@property (assign) IBOutlet NSOutlineView *conversationsView; + @end @implementation ConversationsViewController @synthesize conversationsView; @synthesize treeController; - -- (id)initWithCoder:(NSCoder *)aDecoder -{ - if (self = [super initWithCoder:aDecoder]) { - NSLog(@"INIT Conversations VC"); - } - return self; -} - +@synthesize currentVC; +@synthesize currentCallView; - (void)awakeFromNib { - NSLog(@"awakeFromNib"); + NSLog(@"INIT Conversations VC"); treeController = [[QNSTreeController alloc] initWithQModel:CallModel::instance()]; @@ -65,6 +66,24 @@ NSInteger idx = [conversationsView columnWithIdentifier:COLUMNID_CONVERSATIONS]; [[[[self.conversationsView tableColumns] objectAtIndex:idx] headerCell] setStringValue:@"Conversations"]; + + QObject::connect(CallModel::instance(), + &QAbstractItemModel::dataChanged, + [=](const QModelIndex &topLeft, const QModelIndex &bottomRight) { + NSLog(@"data changed for call tree %d, %d", topLeft.row(), bottomRight.row()); + + [conversationsView reloadDataForRowIndexes: + [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(topLeft.row(), bottomRight.row() + 1)] + columnIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, conversationsView.tableColumns.count)]]; + + }); + + currentVC = [[CurrentCallVC alloc] initWithNibName:@"CurrentCall" bundle:nil]; + [currentCallView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [[currentVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + + [currentCallView addSubview:[self.currentVC view]]; + [currentVC initFrame]; } #pragma mark - NSOutlineViewDelegate methods @@ -83,24 +102,8 @@ - (NSCell *)outlineView:(NSOutlineView *)outlineView dataCellForTableColumn:(NSTableColumn *)tableColumn item:(id)item { NSCell *returnCell = [tableColumn dataCell]; - - if(item == nil) return returnCell; - if ([[tableColumn identifier] isEqualToString:COLUMNID_CONVERSATIONS]) - { - - NSIndexPath* idx = ((NSTreeNode*)item).indexPath; - NSUInteger myArray[[idx length]]; - [idx getIndexes:myArray]; - - NSLog(@"dataCellForTableColumn, indexPath: %lu", (unsigned long)myArray[0]); - - QModelIndex qIdx = CallModel::instance()->index(myArray[0], 0); - - QVariant test = CallModel::instance()->data(qIdx, Qt::DisplayRole); - } - return returnCell; } @@ -160,7 +163,13 @@ - (void)outlineViewSelectionDidChange:(NSNotification *)notification { // ask the tree controller for the current selection - NSLog(@"outlineViewSelectionDidChange!!"); + if([[treeController selectedNodes] count] > 0) { + QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]]; + //Update details view by changing selection + CallModel::instance()->selectionModel()->setCurrentIndex(qIdx, QItemSelectionModel::ClearAndSelect); + } else { + CallModel::instance()->selectionModel()->clearCurrentIndex(); + } } diff --git a/CurrentCall.xib b/CurrentCall.xib new file mode 100644 index 00000000..70b804d0 --- /dev/null +++ b/CurrentCall.xib @@ -0,0 +1,650 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6751" systemVersion="14C1510" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES"> + <dependencies> + <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6751"/> + </dependencies> + <objects> + <customObject id="-2" userLabel="File's Owner" customClass="CurrentCallVC"> + <connections> + <outlet property="controlsPanel" destination="Eoi-B8-iL6" id="4xn-3b-SNn"/> + <outlet property="coucou" destination="bg3-hB-nE8" id="BU2-jT-bfz"/> + <outlet property="hangUpButton" destination="Kjq-iM-NBL" id="Puz-4L-Okl"/> + <outlet property="holdOnOffButton" destination="anb-Y8-JQi" id="HSl-pE-Kwg"/> + <outlet property="personLabel" destination="bg3-hB-nE8" id="t6l-1B-JxI"/> + <outlet property="pickUpButton" destination="qgD-3D-nD5" id="mkD-IT-22E"/> + <outlet property="previewView" destination="6y6-RH-qOp" id="1PY-sd-mh4"/> + <outlet property="recordOnOffButton" destination="oRa-pS-HN2" id="N7C-wn-0le"/> + <outlet property="stateLabel" destination="kFD-FB-vig" id="SSO-14-q2t"/> + <outlet property="timeSpentLabel" destination="cIU-M7-xpN" id="9Rl-t3-gjY"/> + <outlet property="videoView" destination="2wf-Py-l6B" id="dEF-Gx-w6x"/> + <outlet property="view" destination="Hz6-mo-xeY" id="VKn-lN-ijP"/> + </connections> + </customObject> + <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> + <customObject id="-3" userLabel="Application" customClass="NSObject"/> + <customView id="Hz6-mo-xeY"> + <rect key="frame" x="0.0" y="0.0" width="608" height="493"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <subviews> + <customView translatesAutoresizingMaskIntoConstraints="NO" id="2wf-Py-l6B"> + <rect key="frame" x="0.0" y="0.0" width="608" height="493"/> + <subviews> + <customView translatesAutoresizingMaskIntoConstraints="NO" id="6y6-RH-qOp" userLabel="Preview"> + <rect key="frame" x="413" y="20" width="175" height="120"/> + <constraints> + <constraint firstAttribute="height" constant="120" id="BvU-kV-0uD"/> + <constraint firstAttribute="width" constant="175" id="aEv-Tt-tSD"/> + </constraints> + </customView> + <customView translatesAutoresizingMaskIntoConstraints="NO" id="Eoi-B8-iL6" userLabel="Controls"> + <rect key="frame" x="20" y="20" width="385" height="77"/> + <subviews> + <button horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oRa-pS-HN2"> + <rect key="frame" x="18" y="8" width="80" height="60"/> + <constraints> + <constraint firstAttribute="width" constant="76" id="Afw-2T-aY9"/> + <constraint firstAttribute="height" constant="55" id="t21-HC-Wvs"/> + </constraints> + <buttonCell key="cell" type="bevel" title="Record" bezelStyle="regularSquare" imagePosition="overlaps" alignment="center" borderStyle="border" imageScaling="proportionallyDown" id="rhz-4Z-avV"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="toggleRecording:" target="-2" id="gAc-ZJ-9PN"/> + </connections> + </button> + <button horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Kjq-iM-NBL"> + <rect key="frame" x="187" y="8" width="80" height="60"/> + <constraints> + <constraint firstAttribute="width" constant="76" id="7Ja-wI-kLL"/> + <constraint firstAttribute="height" constant="55" id="E2W-LK-NfM"/> + </constraints> + <buttonCell key="cell" type="bevel" bezelStyle="regularSquare" image="4EC7ADC2-5838-4238-8BD9-981133E3FC46" imagePosition="overlaps" alignment="left" borderStyle="border" imageScaling="proportionallyDown" id="kR5-bV-2KY"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="hangUp:" target="-2" id="1Fj-b8-nfh"/> + </connections> + </button> + <button horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qgD-3D-nD5"> + <rect key="frame" x="103" y="8" width="80" height="60"/> + <constraints> + <constraint firstAttribute="width" constant="76" id="9Aq-GM-wT2"/> + <constraint firstAttribute="height" constant="55" id="mnN-fs-Rr6"/> + </constraints> + <buttonCell key="cell" type="bevel" bezelStyle="regularSquare" image="372C8682-ADE9-483C-BC2A-7B5CCDBA78E1" imagePosition="overlaps" alignment="left" borderStyle="border" imageScaling="proportionallyDown" id="CoO-HS-nEB"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="accept:" target="-2" id="maS-G8-eY7"/> + </connections> + </button> + <button horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="anb-Y8-JQi"> + <rect key="frame" x="271" y="8" width="80" height="60"/> + <constraints> + <constraint firstAttribute="width" constant="76" id="QBx-uC-sub"/> + <constraint firstAttribute="height" constant="55" id="nPV-iA-aaw"/> + </constraints> + <buttonCell key="cell" type="bevel" title="Hold" bezelStyle="regularSquare" imagePosition="overlaps" alignment="center" borderStyle="border" imageScaling="proportionallyDown" id="7w5-d1-mNe"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="toggleHold:" target="-2" id="O18-nN-hHE"/> + </connections> + </button> + </subviews> + <constraints> + <constraint firstItem="qgD-3D-nD5" firstAttribute="top" secondItem="Eoi-B8-iL6" secondAttribute="top" constant="11" id="1lr-kB-A5h"/> + <constraint firstItem="anb-Y8-JQi" firstAttribute="top" secondItem="Eoi-B8-iL6" secondAttribute="top" constant="11" id="4C3-og-43v"/> + <constraint firstAttribute="bottom" secondItem="Kjq-iM-NBL" secondAttribute="bottom" constant="11" id="IPS-1V-PVm"/> + <constraint firstAttribute="bottom" secondItem="qgD-3D-nD5" secondAttribute="bottom" constant="11" id="KYy-za-dDq"/> + <constraint firstAttribute="bottom" secondItem="anb-Y8-JQi" secondAttribute="bottom" constant="11" id="MwL-3I-lJv"/> + <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="385" id="TSJ-9A-brf"/> + <constraint firstItem="Kjq-iM-NBL" firstAttribute="top" secondItem="Eoi-B8-iL6" secondAttribute="top" constant="11" id="a1R-g8-5gl"/> + <constraint firstAttribute="bottom" secondItem="oRa-pS-HN2" secondAttribute="bottom" constant="11" id="aOv-xQ-1pk"/> + <constraint firstItem="oRa-pS-HN2" firstAttribute="top" secondItem="Eoi-B8-iL6" secondAttribute="top" constant="11" id="faC-l8-iCU"/> + </constraints> + </customView> + <customView translatesAutoresizingMaskIntoConstraints="NO" id="d0X-cW-Xgz"> + <rect key="frame" x="20" y="422" width="568" height="71"/> + <subviews> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bg3-hB-nE8"> + <rect key="frame" x="107" y="40" width="139" height="17"/> + <constraints> + <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="81" id="gT7-Wu-XtU"/> + </constraints> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="Person name" id="osk-LS-0Qg"> + <font key="font" metaFont="system"/> + <color key="textColor" name="highlightColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kFD-FB-vig"> + <rect key="frame" x="107" y="20" width="37" height="17"/> + <constraints> + <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="29" id="pft-oc-ZNh"/> + </constraints> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="State" id="ugy-uK-901"> + <font key="font" metaFont="system"/> + <color key="textColor" name="highlightColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="highlightColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + <imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="kCB-7W-VSv"> + <rect key="frame" x="41" y="17" width="60" height="40"/> + <constraints> + <constraint firstAttribute="width" constant="60" id="bx8-uw-fxQ"/> + <constraint firstAttribute="height" constant="40" id="eda-WT-Fkh"/> + </constraints> + <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSUser" id="glW-s4-kXA"/> + </imageView> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="cIU-M7-xpN"> + <rect key="frame" x="448" y="23" width="100" height="24"/> + <constraints> + <constraint firstAttribute="width" constant="100" id="9vz-kb-6L6"/> + </constraints> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Time" drawsBackground="YES" id="zsO-T7-9yi"> + <font key="font" size="20" name="HelveticaNeue"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="highlightColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="string" keyPath="layer.cornerRadius" value="15"/> + </userDefinedRuntimeAttributes> + </textField> + </subviews> + <constraints> + <constraint firstItem="kCB-7W-VSv" firstAttribute="leading" secondItem="d0X-cW-Xgz" secondAttribute="leading" constant="41" id="Ada-lv-NZv"/> + <constraint firstItem="bg3-hB-nE8" firstAttribute="leading" secondItem="kCB-7W-VSv" secondAttribute="trailing" constant="8" id="KMt-AK-JAd"/> + <constraint firstItem="kFD-FB-vig" firstAttribute="leading" secondItem="kCB-7W-VSv" secondAttribute="trailing" constant="8" id="OrP-dD-OOc"/> + <constraint firstAttribute="trailing" secondItem="cIU-M7-xpN" secondAttribute="trailing" constant="20" id="RXf-xZ-4f9"/> + <constraint firstItem="kCB-7W-VSv" firstAttribute="top" secondItem="d0X-cW-Xgz" secondAttribute="top" constant="14" id="SVQ-yS-XhQ"/> + <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="568" id="Xeq-Aa-f1W"/> + <constraint firstItem="kFD-FB-vig" firstAttribute="top" secondItem="bg3-hB-nE8" secondAttribute="bottom" constant="3" id="Z06-5v-81Q"/> + <constraint firstAttribute="bottom" secondItem="kCB-7W-VSv" secondAttribute="bottom" constant="17" id="b6S-BG-osE"/> + <constraint firstItem="bg3-hB-nE8" firstAttribute="leading" secondItem="kFD-FB-vig" secondAttribute="leading" id="cgq-pa-Y57"/> + <constraint firstItem="kFD-FB-vig" firstAttribute="top" secondItem="bg3-hB-nE8" secondAttribute="bottom" constant="3" id="gRn-E6-o6O"/> + <constraint firstAttribute="bottom" secondItem="kFD-FB-vig" secondAttribute="bottom" constant="20" id="l71-7V-oLx"/> + <constraint firstAttribute="centerY" secondItem="cIU-M7-xpN" secondAttribute="centerY" id="yvc-8B-cEu"/> + </constraints> + </customView> + </subviews> + <constraints> + <constraint firstItem="6y6-RH-qOp" firstAttribute="leading" secondItem="Eoi-B8-iL6" secondAttribute="trailing" constant="8" id="7wV-uh-Xb7"/> + <constraint firstAttribute="trailing" secondItem="d0X-cW-Xgz" secondAttribute="trailing" constant="20" id="G79-Jv-EYw"/> + <constraint firstAttribute="bottom" secondItem="6y6-RH-qOp" secondAttribute="bottom" constant="20" id="HOt-7O-FU2"/> + <constraint firstAttribute="trailing" secondItem="6y6-RH-qOp" secondAttribute="trailing" constant="20" id="KTx-SN-RUg"/> + <constraint firstItem="d0X-cW-Xgz" firstAttribute="top" secondItem="2wf-Py-l6B" secondAttribute="top" id="MKB-zm-C75"/> + <constraint firstItem="d0X-cW-Xgz" firstAttribute="leading" secondItem="2wf-Py-l6B" secondAttribute="leading" constant="20" id="efy-70-qsJ"/> + <constraint firstAttribute="bottom" secondItem="Eoi-B8-iL6" secondAttribute="bottom" constant="20" id="glQ-Is-Pk6"/> + <constraint firstItem="Eoi-B8-iL6" firstAttribute="leading" secondItem="2wf-Py-l6B" secondAttribute="leading" constant="20" id="sHw-xg-QAo"/> + </constraints> + </customView> + </subviews> + <constraints> + <constraint firstAttribute="trailing" secondItem="2wf-Py-l6B" secondAttribute="trailing" id="55Z-0g-5TN"/> + <constraint firstItem="2wf-Py-l6B" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" id="X7p-et-pnn"/> + <constraint firstAttribute="trailing" secondItem="2wf-Py-l6B" secondAttribute="trailing" id="YzN-ww-GnM"/> + <constraint firstAttribute="bottom" secondItem="2wf-Py-l6B" secondAttribute="bottom" id="a7w-Ws-Gv9"/> + <constraint firstItem="2wf-Py-l6B" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" id="fQz-Y7-SMk"/> + <constraint firstAttribute="bottom" secondItem="2wf-Py-l6B" secondAttribute="bottom" id="iMg-yV-adv"/> + <constraint firstItem="2wf-Py-l6B" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" id="mf8-S2-fcv"/> + </constraints> + <point key="canvasLocation" x="1225" y="13.5"/> + </customView> + </objects> + <resources> + <image name="372C8682-ADE9-483C-BC2A-7B5CCDBA78E1" width="48" height="48"> + <mutableData key="keyedArchiveRepresentation"> +YnBsaXN0MDDUAQIDBAUGOzxYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoK0HCBEW +GxwgISksLzU4VSRudWxs1AkKCwwNDg8QViRjbGFzc1xOU0ltYWdlRmxhZ3NWTlNSZXBzV05TQ29sb3KA +DBIAwAAAgAKACtISCRMVWk5TLm9iamVjdHOhFIADgAnSEgkXGqIYGYAEgAWACBAA0h0JHh9fEBROU1RJ +RkZSZXByZXNlbnRhdGlvboAGgAdPETEOTU0AKgAAJAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwozMzNDMzMzTTMzM00zMzNN +MzMzTTMzM00zMzNNMzMzTTMzM00zMzMdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzM2kzMzOZ +MzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAADMzM3MzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAADMzM3MzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZ +MzMzEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzM3MzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZ +MzMzmTMzM5kzMzOZMzMzMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzM00zMzOZMzMzmTMzM5kzMzOZ +MzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzTQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMzkzMzOZ +MzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzfAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAADMzMxMzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzMxMAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAzMzOGMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZ +MzMzmTMzM0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMzNgMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZ +MzMzmTMzM5kzMzOZMzMzmTMzMzkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMwMzMzmTMzM5kzMzOZ +MzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +MzMzjzMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzN8MzMzCgAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAMzMzVjMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM3wzMzMKAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzMzEzMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzjzMzMwoAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzM2AzMzOZMzMzmTMzM5kzMzOZ +MzMzmTMzM0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMxMzMzOZ +MzMzmTMzM5kzMzOZMzMzmTMzM48zMzMTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAzMzNNMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzN8MzMzCgAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMKMzMzhjMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzaQAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzMzJjMzM5kzMzOZMzMzmTMzM5kzMzOZ +MzMzmTMzM2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzM00zMzOZ +MzMzmTMzM5kzMzOZMzMzmTMzM5kzMzNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMK +MzMzJjMzMwoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAzMzNgMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzaTMzMwoAAAAAAAAAAAAAAAAAAAAA +AAAAADMzMwozMzN8MzMzmTMzM5kzMzNpMzMzQzMzMyYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMKMzMzfDMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM3wzMzMd +AAAAAAAAAAAAAAAAMzMzCjMzM3wzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzjzMzM3MzMzMm +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzMzCjMzM3wzMzOZMzMzmTMzM5kzMzOZ +MzMzmTMzM5kzMzOPMzMzQwAAAAAzMzMTMzMzfDMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZ +MzMzmTMzM5kzMzOGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwozMzN8 +MzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM3wzMzOPMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZ +MzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAMzMzYDMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZ +MzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMzkzMzOPMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZ +MzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMTMzMzczMzM5kzMzOZ +MzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZ +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAADMzMzkzMzOPMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZ +MzMzmTMzM5kzMzOZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMKMzMzTTMzM48zMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZ +MzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMzM5MzMzczMzM5kzMzOZ +MzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzOGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAADMzMxMzMzM5MzMzYDMzM4YzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzNWAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMTMzMzJjMzM00zMzNNMzMzTTMzM0MzMzMK +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAADgEAAAMAAAABADAAAAEBAAMAAAABADAAAAECAAMAAAAEAAAktgEDAAMAAAABAAEAAAEG +AAMAAAABAAIAAAERAAQAAAABAAAACAESAAMAAAABAAEAAAEVAAMAAAABAAQAAAEWAAMAAAABADAAAAEX +AAQAAAABAAAkAAEcAAMAAAABAAEAAAFSAAMAAAABAAIAAAFTAAMAAAAEAAAkvodzAAcAAAxIAAAkxgAA +AAAACAAIAAgACAABAAEAAQABAAAMSExpbm8CEAAAbW50clJHQiBYWVogB84AAgAJAAYAMQAAYWNzcE1T +RlQAAAAASUVDIHNSR0IAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1IUCAgAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARY3BydAAAAVAAAAAzZGVzYwAAAYQAAABsd3RwdAAA +AfAAAAAUYmtwdAAAAgQAAAAUclhZWgAAAhgAAAAUZ1hZWgAAAiwAAAAUYlhZWgAAAkAAAAAUZG1uZAAA +AlQAAABwZG1kZAAAAsQAAACIdnVlZAAAA0wAAACGdmlldwAAA9QAAAAkbHVtaQAAA/gAAAAUbWVhcwAA +BAwAAAAkdGVjaAAABDAAAAAMclRSQwAABDwAAAgMZ1RSQwAABDwAAAgMYlRSQwAABDwAAAgMdGV4dAAA +AABDb3B5cmlnaHQgKGMpIDE5OTggSGV3bGV0dC1QYWNrYXJkIENvbXBhbnkAAGRlc2MAAAAAAAAAEnNS +R0IgSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAASc1JHQiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAADzUQABAAAAARbMWFlaIAAA +AAAAAAAAAAAAAAAAAABYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAA +AAAAACSgAAAPhAAAts9kZXNjAAAAAAAAABZJRUMgaHR0cDovL3d3dy5pZWMuY2gAAAAAAAAAAAAAABZJ +RUMgaHR0cDovL3d3dy5pZWMuY2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAZGVzYwAAAAAAAAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3BhY2UgLSBz +UkdCAAAAAAAAAAAAAAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3BhY2UgLSBzUkdC +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRlc2MAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlv +biBpbiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAACxSZWZlcmVuY2UgVmlld2luZyBDb25kaXRpb24gaW4g +SUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2aWV3AAAAAAATpP4AFF8uABDPFAAD +7cwABBMLAANcngAAAAFYWVogAAAAAABMCVYAUAAAAFcf521lYXMAAAAAAAAAAQAAAAAAAAAAAAAAAAAA +AAAAAAKPAAAAAnNpZyAAAAAAQ1JUIGN1cnYAAAAAAAAEAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7 +AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwAgQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQ +ANUA2wDgAOUA6wDwAPYA+wEBAQcBDQETARkBHwElASsBMgE4AT4BRQFMAVIBWQFgAWcBbgF1AXwBgwGL +AZIBmgGhAakBsQG5AcEByQHRAdkB4QHpAfIB+gIDAgwCFAIdAiYCLwI4AkECSwJUAl0CZwJxAnoChAKO +ApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNPA1oDZgNyA34DigOWA6IDrgO6A8cD0wPg +A+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwEmgSoBLYExATTBOEE8AT+BQ0FHAUrBToFSQVYBWcFdwWG +BZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7BowGnQavBsAG0QbjBvUHBwcZBysHPQdPB2EHdAeG +B5kHrAe/B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjnCPsJEAklCToJTwlkCXkJjwmkCboJzwnl +CfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5C1ELaQuAC5gLsAvIC+EL+QwSDCoMQwxcDHUMjgyn +DMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgOEw4uDkkOZA5/DpsOtg7SDu4PCQ8lD0EPXg96D5YPsw/P +D+wQCRAmEEMQYRB+EJsQuRDXEPURExExEU8RbRGMEaoRyRHoEgcSJhJFEmQShBKjEsMS4xMDEyMTQxNj +E4MTpBPFE+UUBhQnFEkUahSLFK0UzhTwFRIVNBVWFXgVmxW9FeAWAxYmFkkWbBaPFrIW1hb6Fx0XQRdl +F4kXrhfSF/cYGxhAGGUYihivGNUY+hkgGUUZaxmRGbcZ3RoEGioaURp3Gp4axRrsGxQbOxtjG4obshva +HAIcKhxSHHscoxzMHPUdHh1HHXAdmR3DHeweFh5AHmoelB6+HukfEx8+H2kflB+/H+ogFSBBIGwgmCDE +IPAhHCFIIXUhoSHOIfsiJyJVIoIiryLdIwojOCNmI5QjwiPwJB8kTSR8JKsk2iUJJTglaCWXJccl9yYn +Jlcmhya3JugnGCdJJ3onqyfcKA0oPyhxKKIo1CkGKTgpaymdKdAqAio1KmgqmyrPKwIrNitpK50r0SwF +LDksbiyiLNctDC1BLXYtqy3hLhYuTC6CLrcu7i8kL1ovkS/HL/4wNTBsMKQw2zESMUoxgjG6MfIyKjJj +Mpsy1DMNM0YzfzO4M/E0KzRlNJ402DUTNU01hzXCNf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlC +OX85vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8pDzjPSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/iQCNAZECm +QOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fASAVIS0iR +SNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6TQJNSk2TTdxOJU5uTrdPAE9JT5NP3VAnUHFQu1EG +UVBRm1HmUjFSfFLHUxNTX1OqU/ZUQlSPVNtVKFV1VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoH +WlZaplr1W0VblVvlXDVchlzWXSddeF3JXhpebF69Xw9fYV+zYAVgV2CqYPxhT2GiYfViSWKcYvBjQ2OX +Y+tkQGSUZOllPWWSZedmPWaSZuhnPWeTZ+loP2iWaOxpQ2maafFqSGqfavdrT2una/9sV2yvbQhtYG25 +bhJua27Ebx5veG/RcCtwhnDgcTpxlXHwcktypnMBc11zuHQUdHB0zHUodYV14XY+dpt2+HdWd7N4EXhu +eMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9oX4BfmJ+wn8jf4R/5YBHgKiBCoFrgc2CMIKSgvSDV4O6 +hB2EgITjhUeFq4YOhnKG14c7h5+IBIhpiM6JM4mZif6KZIrKizCLlov8jGOMyo0xjZiN/45mjs6PNo+e +kAaQbpDWkT+RqJIRknqS45NNk7aUIJSKlPSVX5XJljSWn5cKl3WX4JhMmLiZJJmQmfyaaJrVm0Kbr5wc +nImc951kndKeQJ6unx2fi5/6oGmg2KFHobaiJqKWowajdqPmpFakx6U4pammGqaLpv2nbqfgqFKoxKk3 +qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxavi7AAsHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbw +t2i34LhZuNG5SrnCuju6tbsuu6e8IbybvRW9j74KvoS+/796v/XAcMDswWfB48JfwtvDWMPUxFHEzsVL +xcjGRsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ +1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp22vvbgNwF3IrdEN2W3hzeot8p36/gNuC94UThzOJT4tvjY+Pr +5HPk/OWE5g3mlucf56noMui86Ubp0Opb6uXrcOv77IbtEe2c7ijutO9A78zwWPDl8XLx//KM8xnzp/Q0 +9ML1UPXe9m32+/eK+Bn4qPk4+cf6V/rn+3f8B/yY/Sn9uv5L/tz/bf//0iIjJCVaJGNsYXNzbmFtZVgk +Y2xhc3Nlc18QEE5TQml0bWFwSW1hZ2VSZXCjJicoXxAQTlNCaXRtYXBJbWFnZVJlcFpOU0ltYWdlUmVw +WE5TT2JqZWN00iIjKitXTlNBcnJheaIqKNIiIy0uXk5TTXV0YWJsZUFycmF5oy0qKNMwMQkyMzRXTlNX +aGl0ZVxOU0NvbG9yU3BhY2VEMCAwABADgAvSIiM2N1dOU0NvbG9yojYo0iIjOTpXTlNJbWFnZaI5KF8Q +D05TS2V5ZWRBcmNoaXZlctE9PlRyb290gAEACAARABoAIwAtADIANwBFAEsAVABbAGgAbwB3AHkAfgCA +AIIAhwCSAJQAlgCYAJ0AoACiAKQApgCoAK0AxADGAMgx2jHfMeox8zIGMgoyHTIoMjEyNjI+MkEyRjJV +MlkyYDJoMnUyejJ8Mn4ygzKLMo4ykzKbMp4ysDKzMrgAAAAAAAACAQAAAAAAAAA/AAAAAAAAAAAAAAAA +AAAyug +</mutableData> + </image> + <image name="4EC7ADC2-5838-4238-8BD9-981133E3FC46" width="48" height="48"> + <mutableData key="keyedArchiveRepresentation"> +YnBsaXN0MDDUAQIDBAUGOzxYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoK0HCBEW +GxwgISksLzU4VSRudWxs1AkKCwwNDg8QViRjbGFzc1xOU0ltYWdlRmxhZ3NWTlNSZXBzV05TQ29sb3KA +DBIAwAAAgAKACtISCRMVWk5TLm9iamVjdHOhFIADgAnSEgkXGqIYGYAEgAWACBAA0h0JHh9fEBROU1RJ +RkZSZXByZXNlbnRhdGlvboAGgAdPETEOTU0AKgAAJAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAzMzNDMzMzCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzMzCjMzM0MAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzM2AzMzOZMzMzfDMzMwoAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMK +MzMzfDMzM5kzMzNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzMzQzMzM5kzMzOZMzMzmTMzM3wzMzMK +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAADMzMwozMzN8MzMzmTMzM5kzMzOZMzMzQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzMzCjMzM3wzMzOZ +MzMzmTMzM5kzMzN8MzMzCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAMzMzCjMzM3wzMzOZMzMzmTMzM5kzMzN8MzMzCgAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAADMzMwozMzN8MzMzmTMzM5kzMzOZMzMzfDMzMwoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMKMzMzfDMzM5kzMzOZMzMzmTMzM3wzMzMKAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMKMzMzfDMzM5kzMzOZMzMzmTMzM3wzMzMKAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwozMzN8MzMzmTMzM5kzMzOZMzMzfDMzMwoAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzMzCjMzM3wzMzOZMzMzmTMzM5kzMzN8 +MzMzCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzMzCjMzM3wzMzOZMzMzmTMzM5kzMzN8 +MzMzCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwozMzN8 +MzMzmTMzM5kzMzOZMzMzfDMzMwoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMKMzMzfDMzM5kzMzOZ +MzMzmTMzM3wzMzMKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAzMzMKMzMzfDMzM5kzMzOZMzMzmTMzM3wzMzMKAAAAAAAAAAAAAAAAAAAAADMzMwozMzN8 +MzMzmTMzM5kzMzOZMzMzfDMzMwoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzMzCjMzM3wzMzOZMzMzmTMzM5kzMzN8MzMzCgAAAAAAAAAA +MzMzCjMzM3wzMzOZMzMzmTMzM5kzMzN8MzMzCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwozMzN8MzMzmTMzM5kzMzOZ +MzMzfDMzMwozMzMKMzMzfDMzM5kzMzOZMzMzmTMzM3wzMzMKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMK +MzMzfDMzM5kzMzOZMzMzmTMzM3wzMzN8MzMzmTMzM5kzMzOZMzMzfDMzMwoAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAMzMzCjMzM3wzMzOZMzMzmTMzM5kzMzOZMzMzmTMzM5kzMzN8MzMzCgAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwozMzN8MzMzmTMzM5kzMzOZMzMzmTMzM3wzMzMK +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwozMzN8MzMzmTMzM5kzMzOZ +MzMzmTMzM3wzMzMKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzMzCjMzM3wzMzOZ +MzMzmTMzM5kzMzOZMzMzmTMzM5kzMzN8MzMzCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMK +MzMzfDMzM5kzMzOZMzMzmTMzM3wzMzN8MzMzmTMzM5kzMzOZMzMzfDMzMwoAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAADMzMwozMzN8MzMzmTMzM5kzMzOZMzMzfDMzMwozMzMKMzMzfDMzM5kzMzOZMzMzmTMzM3wzMzMK +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAMzMzCjMzM3wzMzOZMzMzmTMzM5kzMzN8MzMzCgAAAAAAAAAAMzMzCjMzM3wzMzOZ +MzMzmTMzM5kzMzN8MzMzCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMKMzMzfDMzM5kzMzOZMzMzmTMzM3wzMzMKAAAAAAAAAAAAAAAA +AAAAADMzMwozMzN8MzMzmTMzM5kzMzOZMzMzfDMzMwoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwozMzN8MzMzmTMzM5kzMzOZMzMzfDMzMwoAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMKMzMzfDMzM5kzMzOZMzMzmTMzM3wzMzMKAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzMzCjMzM3wzMzOZMzMzmTMzM5kzMzN8 +MzMzCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzMzCjMzM3wzMzOZMzMzmTMzM5kzMzN8 +MzMzCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMKMzMzfDMzM5kzMzOZ +MzMzmTMzM3wzMzMKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwozMzN8 +MzMzmTMzM5kzMzOZMzMzfDMzMwoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwozMzN8 +MzMzmTMzM5kzMzOZMzMzfDMzMwoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAzMzMKMzMzfDMzM5kzMzOZMzMzmTMzM3wzMzMKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +MzMzCjMzM3wzMzOZMzMzmTMzM5kzMzN8MzMzCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzMzCjMzM3wzMzOZMzMzmTMzM5kzMzN8MzMzCgAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAMzMzQzMzM5kzMzOZMzMzmTMzM3wzMzMKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwozMzN8MzMzmTMzM5kzMzOZ +MzMzQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzM2AzMzOZMzMzfDMzMwoAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMK +MzMzfDMzM5kzMzNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMzNDMzMzCgAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAMzMzCjMzM0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAADgEAAAMAAAABADAAAAEBAAMAAAABADAAAAECAAMAAAAEAAAktgEDAAMAAAABAAEAAAEG +AAMAAAABAAIAAAERAAQAAAABAAAACAESAAMAAAABAAEAAAEVAAMAAAABAAQAAAEWAAMAAAABADAAAAEX +AAQAAAABAAAkAAEcAAMAAAABAAEAAAFSAAMAAAABAAIAAAFTAAMAAAAEAAAkvodzAAcAAAxIAAAkxgAA +AAAACAAIAAgACAABAAEAAQABAAAMSExpbm8CEAAAbW50clJHQiBYWVogB84AAgAJAAYAMQAAYWNzcE1T +RlQAAAAASUVDIHNSR0IAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1IUCAgAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARY3BydAAAAVAAAAAzZGVzYwAAAYQAAABsd3RwdAAA +AfAAAAAUYmtwdAAAAgQAAAAUclhZWgAAAhgAAAAUZ1hZWgAAAiwAAAAUYlhZWgAAAkAAAAAUZG1uZAAA +AlQAAABwZG1kZAAAAsQAAACIdnVlZAAAA0wAAACGdmlldwAAA9QAAAAkbHVtaQAAA/gAAAAUbWVhcwAA +BAwAAAAkdGVjaAAABDAAAAAMclRSQwAABDwAAAgMZ1RSQwAABDwAAAgMYlRSQwAABDwAAAgMdGV4dAAA +AABDb3B5cmlnaHQgKGMpIDE5OTggSGV3bGV0dC1QYWNrYXJkIENvbXBhbnkAAGRlc2MAAAAAAAAAEnNS +R0IgSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAASc1JHQiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAADzUQABAAAAARbMWFlaIAAA +AAAAAAAAAAAAAAAAAABYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAA +AAAAACSgAAAPhAAAts9kZXNjAAAAAAAAABZJRUMgaHR0cDovL3d3dy5pZWMuY2gAAAAAAAAAAAAAABZJ +RUMgaHR0cDovL3d3dy5pZWMuY2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAZGVzYwAAAAAAAAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3BhY2UgLSBz +UkdCAAAAAAAAAAAAAAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3BhY2UgLSBzUkdC +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRlc2MAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlv +biBpbiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAACxSZWZlcmVuY2UgVmlld2luZyBDb25kaXRpb24gaW4g +SUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2aWV3AAAAAAATpP4AFF8uABDPFAAD +7cwABBMLAANcngAAAAFYWVogAAAAAABMCVYAUAAAAFcf521lYXMAAAAAAAAAAQAAAAAAAAAAAAAAAAAA +AAAAAAKPAAAAAnNpZyAAAAAAQ1JUIGN1cnYAAAAAAAAEAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7 +AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwAgQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQ +ANUA2wDgAOUA6wDwAPYA+wEBAQcBDQETARkBHwElASsBMgE4AT4BRQFMAVIBWQFgAWcBbgF1AXwBgwGL +AZIBmgGhAakBsQG5AcEByQHRAdkB4QHpAfIB+gIDAgwCFAIdAiYCLwI4AkECSwJUAl0CZwJxAnoChAKO +ApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNPA1oDZgNyA34DigOWA6IDrgO6A8cD0wPg +A+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwEmgSoBLYExATTBOEE8AT+BQ0FHAUrBToFSQVYBWcFdwWG +BZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7BowGnQavBsAG0QbjBvUHBwcZBysHPQdPB2EHdAeG +B5kHrAe/B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjnCPsJEAklCToJTwlkCXkJjwmkCboJzwnl +CfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5C1ELaQuAC5gLsAvIC+EL+QwSDCoMQwxcDHUMjgyn +DMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgOEw4uDkkOZA5/DpsOtg7SDu4PCQ8lD0EPXg96D5YPsw/P +D+wQCRAmEEMQYRB+EJsQuRDXEPURExExEU8RbRGMEaoRyRHoEgcSJhJFEmQShBKjEsMS4xMDEyMTQxNj +E4MTpBPFE+UUBhQnFEkUahSLFK0UzhTwFRIVNBVWFXgVmxW9FeAWAxYmFkkWbBaPFrIW1hb6Fx0XQRdl +F4kXrhfSF/cYGxhAGGUYihivGNUY+hkgGUUZaxmRGbcZ3RoEGioaURp3Gp4axRrsGxQbOxtjG4obshva +HAIcKhxSHHscoxzMHPUdHh1HHXAdmR3DHeweFh5AHmoelB6+HukfEx8+H2kflB+/H+ogFSBBIGwgmCDE +IPAhHCFIIXUhoSHOIfsiJyJVIoIiryLdIwojOCNmI5QjwiPwJB8kTSR8JKsk2iUJJTglaCWXJccl9yYn +Jlcmhya3JugnGCdJJ3onqyfcKA0oPyhxKKIo1CkGKTgpaymdKdAqAio1KmgqmyrPKwIrNitpK50r0SwF +LDksbiyiLNctDC1BLXYtqy3hLhYuTC6CLrcu7i8kL1ovkS/HL/4wNTBsMKQw2zESMUoxgjG6MfIyKjJj +Mpsy1DMNM0YzfzO4M/E0KzRlNJ402DUTNU01hzXCNf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlC +OX85vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8pDzjPSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/iQCNAZECm +QOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fASAVIS0iR +SNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6TQJNSk2TTdxOJU5uTrdPAE9JT5NP3VAnUHFQu1EG +UVBRm1HmUjFSfFLHUxNTX1OqU/ZUQlSPVNtVKFV1VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoH +WlZaplr1W0VblVvlXDVchlzWXSddeF3JXhpebF69Xw9fYV+zYAVgV2CqYPxhT2GiYfViSWKcYvBjQ2OX +Y+tkQGSUZOllPWWSZedmPWaSZuhnPWeTZ+loP2iWaOxpQ2maafFqSGqfavdrT2una/9sV2yvbQhtYG25 +bhJua27Ebx5veG/RcCtwhnDgcTpxlXHwcktypnMBc11zuHQUdHB0zHUodYV14XY+dpt2+HdWd7N4EXhu +eMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9oX4BfmJ+wn8jf4R/5YBHgKiBCoFrgc2CMIKSgvSDV4O6 +hB2EgITjhUeFq4YOhnKG14c7h5+IBIhpiM6JM4mZif6KZIrKizCLlov8jGOMyo0xjZiN/45mjs6PNo+e +kAaQbpDWkT+RqJIRknqS45NNk7aUIJSKlPSVX5XJljSWn5cKl3WX4JhMmLiZJJmQmfyaaJrVm0Kbr5wc +nImc951kndKeQJ6unx2fi5/6oGmg2KFHobaiJqKWowajdqPmpFakx6U4pammGqaLpv2nbqfgqFKoxKk3 +qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxavi7AAsHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbw +t2i34LhZuNG5SrnCuju6tbsuu6e8IbybvRW9j74KvoS+/796v/XAcMDswWfB48JfwtvDWMPUxFHEzsVL +xcjGRsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ +1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp22vvbgNwF3IrdEN2W3hzeot8p36/gNuC94UThzOJT4tvjY+Pr +5HPk/OWE5g3mlucf56noMui86Ubp0Opb6uXrcOv77IbtEe2c7ijutO9A78zwWPDl8XLx//KM8xnzp/Q0 +9ML1UPXe9m32+/eK+Bn4qPk4+cf6V/rn+3f8B/yY/Sn9uv5L/tz/bf//0iIjJCVaJGNsYXNzbmFtZVgk +Y2xhc3Nlc18QEE5TQml0bWFwSW1hZ2VSZXCjJicoXxAQTlNCaXRtYXBJbWFnZVJlcFpOU0ltYWdlUmVw +WE5TT2JqZWN00iIjKitXTlNBcnJheaIqKNIiIy0uXk5TTXV0YWJsZUFycmF5oy0qKNMwMQkyMzRXTlNX +aGl0ZVxOU0NvbG9yU3BhY2VEMCAwABADgAvSIiM2N1dOU0NvbG9yojYo0iIjOTpXTlNJbWFnZaI5KF8Q +D05TS2V5ZWRBcmNoaXZlctE9PlRyb290gAEACAARABoAIwAtADIANwBFAEsAVABbAGgAbwB3AHkAfgCA +AIIAhwCSAJQAlgCYAJ0AoACiAKQApgCoAK0AxADGAMgx2jHfMeox8zIGMgoyHTIoMjEyNjI+MkEyRjJV +MlkyYDJoMnUyejJ8Mn4ygzKLMo4ykzKbMp4ysDKzMrgAAAAAAAACAQAAAAAAAAA/AAAAAAAAAAAAAAAA +AAAyug +</mutableData> + </image> + <image name="NSUser" width="32" height="32"/> + </resources> +</document> diff --git a/CurrentCallVC.h b/CurrentCallVC.h new file mode 100644 index 00000000..e24cf012 --- /dev/null +++ b/CurrentCallVC.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2004-2015 Savoir-Faire Linux Inc. + * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ +#ifndef CURRENTCALLVC_H +#define CURRENTCALLVC_H + +#import <Cocoa/Cocoa.h> + +class Call; + +@interface CurrentCallVC : NSViewController { + +} + +- (void) initFrame; + +@end + +#endif // CURRENTCALLVC_H \ No newline at end of file diff --git a/CurrentCallVC.mm b/CurrentCallVC.mm new file mode 100644 index 00000000..404e75a8 --- /dev/null +++ b/CurrentCallVC.mm @@ -0,0 +1,450 @@ +/* + * Copyright (C) 2004-2015 Savoir-Faire Linux Inc. + * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ +#import "CurrentCallVC.h" + +#import <QuartzCore/QuartzCore.h> + +#import <call.h> +#import <callmodel.h> +#import <useractionmodel.h> +#import <contactmethod.h> +#import <qabstractitemmodel.h> +#import <QItemSelectionModel> +#import <QItemSelection> + +#import <video/previewmanager.h> +#import <video/renderer.h> + +/** FrameReceiver class - delegate for AVCaptureSession + */ +@interface RendererConnectionsHolder : NSObject + +@property QMetaObject::Connection frameUpdated; +@property QMetaObject::Connection started; +@property QMetaObject::Connection stopped; + +@end + +@implementation RendererConnectionsHolder + +@end + +@interface CurrentCallVC () + +@property (assign) IBOutlet NSTextField *personLabel; +@property (assign) IBOutlet NSTextField *stateLabel; +@property (assign) IBOutlet NSButton *holdOnOffButton; +@property (assign) IBOutlet NSButton *hangUpButton; +@property (assign) IBOutlet NSButton *recordOnOffButton; +@property (assign) IBOutlet NSButton *pickUpButton; +@property (assign) IBOutlet NSTextField *timeSpentLabel; +@property (assign) IBOutlet NSView *controlsPanel; + +@property QHash<int, NSButton*> actionHash; + +// Video +@property (assign) IBOutlet NSView *videoView; +@property CALayer* videoLayer; +@property (assign) IBOutlet NSView *previewView; +@property CALayer* previewLayer; + +@property RendererConnectionsHolder* previewHolder; +@property RendererConnectionsHolder* videoHolder; + +@end + +@implementation CurrentCallVC +@synthesize personLabel; +@synthesize actionHash; +@synthesize stateLabel; +@synthesize holdOnOffButton; +@synthesize hangUpButton; +@synthesize recordOnOffButton; +@synthesize pickUpButton; +@synthesize timeSpentLabel; +@synthesize controlsPanel; +@synthesize videoView; +@synthesize videoLayer; +@synthesize previewLayer; +@synthesize previewView; + +@synthesize previewHolder; +@synthesize videoHolder; + + + + +- (void) updateActions +{ + for(int i = 0 ; i <= CallModel::instance()->userActionModel()->rowCount() ; i++) { + const QModelIndex& idx = CallModel::instance()->userActionModel()->index(i,0); + NSButton* a = actionHash[(int)qvariant_cast<UserActionModel::Action>(idx.data(UserActionModel::Role::ACTION))]; + if (a != nil) { + [a setEnabled:(idx.flags() & Qt::ItemIsEnabled)]; + [a setState:(idx.data(Qt::CheckStateRole) == Qt::Checked) ? NSOnState : NSOffState]; + } + } +} + +-(void) updateCall +{ + QModelIndex callIdx = CallModel::instance()->selectionModel()->currentIndex(); + [personLabel setStringValue:CallModel::instance()->data(callIdx, Qt::DisplayRole).toString().toNSString()]; + [timeSpentLabel setStringValue:CallModel::instance()->data(callIdx, (int)Call::Role::Length).toString().toNSString()]; + + Call::State state = CallModel::instance()->data(callIdx, (int)Call::Role::State).value<Call::State>(); + + switch (state) { + case Call::State::INITIALIZATION: + [stateLabel setStringValue:@"Initializing"]; + break; + case Call::State::RINGING: + [stateLabel setStringValue:@"Ringing"]; + break; + case Call::State::CURRENT: + [stateLabel setStringValue:@"Current"]; + break; + case Call::State::HOLD: + [stateLabel setStringValue:@"On Hold"]; + break; + case Call::State::BUSY: + [stateLabel setStringValue:@"Busy"]; + break; + case Call::State::OVER: + [stateLabel setStringValue:@"Finished"]; + break; + case Call::State::FAILURE: + [stateLabel setStringValue:@"Failure"]; + break; + default: + break; + } + +} + +- (void)awakeFromNib +{ + NSLog(@"INIT CurrentCall VC"); + [self.view setWantsLayer:YES]; // view's backing store is using a Core Animation Layer + [self.view setLayer:[CALayer layer]]; + //self.view.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay; + + + [controlsPanel setWantsLayer:YES]; + [controlsPanel setLayer:[CALayer layer]]; + [controlsPanel.layer setZPosition:2.0]; + [controlsPanel.layer setBackgroundColor:[NSColor whiteColor].CGColor]; + + actionHash[ (int)UserActionModel::Action::ACCEPT ] = pickUpButton; + actionHash[ (int)UserActionModel::Action::HOLD ] = holdOnOffButton; + actionHash[ (int)UserActionModel::Action::RECORD ] = recordOnOffButton; + actionHash[ (int)UserActionModel::Action::HANGUP ] = hangUpButton; + //actionHash[ (int)UserActionModel::Action::MUTE_AUDIO ] = action_mute_capture; + //actionHash[ (int)UserActionModel::Action::SERVER_TRANSFER ] = action_transfer; + + + + videoLayer = [CALayer layer]; + [videoView setWantsLayer:YES]; + [videoView setLayer:videoLayer]; + [videoView.layer setBackgroundColor:[NSColor blackColor].CGColor]; + [videoView.layer setFrame:videoView.frame]; + [videoView.layer setContentsGravity:kCAGravityResizeAspect]; + //[videoView.layer setBounds:CGRectMake(0, 0, videoView.frame.size.width, videoView.frame.size.height)]; + + previewLayer = [CALayer layer]; + [previewView setWantsLayer:YES]; + [previewView setLayer:previewLayer]; + [previewLayer setBackgroundColor:[NSColor blackColor].CGColor]; + [previewLayer setContentsGravity:kCAGravityResizeAspect]; + [previewLayer setFrame:previewView.frame]; + + [controlsPanel setWantsLayer:YES]; + [controlsPanel setLayer:[CALayer layer]]; + [controlsPanel.layer setBackgroundColor:[NSColor clearColor].CGColor]; + [controlsPanel.layer setFrame:controlsPanel.frame]; + + [self connect]; +} + +- (void) connect +{ + QObject::connect(CallModel::instance()->selectionModel(), + &QItemSelectionModel::currentChanged, + [=](const QModelIndex ¤t, const QModelIndex &previous) { + NSLog(@"selection changed!"); + if(!current.isValid()) { + [self animateOut]; + return; + } + [self updateCall]; + [self updateActions]; + [self animateOut]; + }); + + QObject::connect(CallModel::instance(), + &QAbstractItemModel::dataChanged, + [=](const QModelIndex &topLeft, const QModelIndex &bottomRight) { + NSLog(@"data changed!"); + [self updateCall]; + }); + + QObject::connect(CallModel::instance()->userActionModel(), + &QAbstractItemModel::dataChanged, + [=](const QModelIndex &topLeft, const QModelIndex &bottomRight) { + NSLog(@"useraction changed"); + const int first(topLeft.row()),last(bottomRight.row()); + for(int i = first; i <= last;i++) { + const QModelIndex& idx = CallModel::instance()->userActionModel()->index(i,0); + NSButton* a = actionHash[(int)qvariant_cast<UserActionModel::Action>(idx.data(UserActionModel::Role::ACTION))]; + if (a) { + [a setEnabled:(idx.flags() & Qt::ItemIsEnabled)]; + [a setState:(idx.data(Qt::CheckStateRole) == Qt::Checked) ? NSOnState : NSOffState]; + } + } + }); + + QObject::connect(CallModel::instance(), + &CallModel::callStateChanged, + [self](Call* c, Call::State state) { + NSLog(@"callStateChanged"); + [self updateCall]; + }); +} + +-(void) connectVideoSignals +{ + QModelIndex idx = CallModel::instance()->selectionModel()->currentIndex(); + Call* call = CallModel::instance()->getCall(idx); + + QObject::connect(call, + &Call::videoStarted, + [=](Video::Renderer* renderer) { + NSLog(@"Video started!"); + [self connectVideoRenderer:renderer]; + }); + + if(call->videoRenderer()) + { + NSLog(@"GONNA CONNECT TO FRAMES"); + [self connectVideoRenderer:call->videoRenderer()]; + } + + [self connectPreviewRenderer]; + +} + +-(void) connectPreviewRenderer +{ + previewHolder.started = QObject::connect(Video::PreviewManager::instance(), + &Video::PreviewManager::previewStarted, + [=](Video::Renderer* renderer) { + NSLog(@"Preview started"); + QObject::disconnect(previewHolder.frameUpdated); + previewHolder.frameUpdated = QObject::connect(renderer, + &Video::Renderer::frameUpdated, + [=]() { + [self renderer:Video::PreviewManager::instance()->previewRenderer() + renderFrameForView:previewView]; + }); + }); + + previewHolder.stopped = QObject::connect(Video::PreviewManager::instance(), + &Video::PreviewManager::previewStopped, + [=](Video::Renderer* renderer) { + NSLog(@"Preview stopped"); + QObject::disconnect(previewHolder.frameUpdated); + [previewView.layer setContents:nil]; + }); + + previewHolder.frameUpdated = QObject::connect(Video::PreviewManager::instance()->previewRenderer(), + &Video::Renderer::frameUpdated, + [=]() { + [self renderer:Video::PreviewManager::instance()->previewRenderer() + renderFrameForView:previewView]; + }); +} + +-(void) connectVideoRenderer: (Video::Renderer*)renderer +{ + videoHolder.frameUpdated = QObject::connect(renderer, + &Video::Renderer::frameUpdated, + [=]() { + [self renderer:renderer renderFrameForView:videoView]; + }); + + videoHolder.started = QObject::connect(renderer, + &Video::Renderer::started, + [=]() { + NSLog(@"Renderer started"); + QObject::disconnect(videoHolder.frameUpdated); + videoHolder.frameUpdated = QObject::connect(renderer, + &Video::Renderer::frameUpdated, + [=]() { + [self renderer:renderer renderFrameForView:videoView]; + }); + }); + + videoHolder.stopped = QObject::connect(renderer, + &Video::Renderer::stopped, + [=]() { + NSLog(@"Renderer stopped"); + QObject::disconnect(videoHolder.frameUpdated); + [videoView.layer setContents:nil]; + }); +} + +-(void) renderer: (Video::Renderer*)renderer renderFrameForView:(NSView*) view +{ + const QByteArray& data = renderer->currentFrame(); + QSize res = renderer->size(); + + auto buf = reinterpret_cast<const unsigned char*>(data.data()); + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef newContext = CGBitmapContextCreate((void *)buf, + res.width(), + res.height(), + 8, + 4*res.width(), + colorSpace, + kCGImageAlphaPremultipliedLast); + + + CGImageRef newImage = CGBitmapContextCreateImage(newContext); + + /*We release some components*/ + CGContextRelease(newContext); + CGColorSpaceRelease(colorSpace); + + [CATransaction begin]; + view.layer.contents = (__bridge id)newImage; + [CATransaction commit]; + + CFRelease(newImage); +} + +- (void) initFrame +{ + [self.view setFrame:self.view.superview.bounds]; + [self.view setHidden:YES]; + self.view.layer.position = self.view.frame.origin; +} + +# pragma private IN/OUT animations + +-(void) animateIn +{ + NSLog(@"animateIn"); + CGRect frame = CGRectOffset(self.view.superview.bounds, -self.view.superview.bounds.size.width, 0); + [self.view setHidden:NO]; + + [CATransaction begin]; + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"]; + [animation setFromValue:[NSValue valueWithPoint:frame.origin]]; + [animation setToValue:[NSValue valueWithPoint:self.view.superview.bounds.origin]]; + [animation setDuration:0.2f]; + [animation setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:.7 :0.9 :1 :1]]; + [CATransaction setCompletionBlock:^{ + NSLog(@"COMPLETION IN"); + + [self connectVideoSignals]; + + }]; + [self.view.layer addAnimation:animation forKey:animation.keyPath]; + + [CATransaction commit]; +} + +-(void) cleanUp +{ + [videoView.layer setContents:nil]; + [previewView.layer setContents:nil]; +} + +-(void) animateOut +{ + NSLog(@"animateOut"); + if(self.view.frame.origin.x < 0) { + NSLog(@"Already hidden"); + if (CallModel::instance()->selectionModel()->currentIndex().isValid()) { + [self animateIn]; + } + return; + } + + CGRect frame = CGRectOffset(self.view.frame, -self.view.frame.size.width, 0); + [CATransaction begin]; + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"]; + [animation setFromValue:[NSValue valueWithPoint:self.view.frame.origin]]; + [animation setToValue:[NSValue valueWithPoint:frame.origin]]; + [animation setDuration:0.2f]; + [animation setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:.7 :0.9 :1 :1]]; + + [CATransaction setCompletionBlock:^{ + [self.view setHidden:YES]; + + [self cleanUp]; + + if (CallModel::instance()->selectionModel()->currentIndex().isValid()) { + [self animateIn]; + } + }]; + [self.view.layer addAnimation:animation forKey:animation.keyPath]; + [CATransaction commit]; +} + +/** + * Debug purpose + */ +-(void) dumpFrame:(CGRect) frame WithName:(NSString*) name +{ + NSLog(@"frame %@ : %f %f %f %f \n\n",name ,frame.origin.x, frame.origin.y, frame.size.width, frame.size.height); +} + + +#pragma button methods +- (IBAction)hangUp:(id)sender { + CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::REFUSE; +} + +- (IBAction)accept:(id)sender { + CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::ACCEPT; +} + +- (IBAction)toggleRecording:(id)sender { + CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::RECORD; +} + +- (IBAction)toggleHold:(id)sender { + CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::HOLD; +} + +@end diff --git a/HistoryViewController.h b/HistoryViewController.h index c532c728..4c4dbeac 100644 --- a/HistoryViewController.h +++ b/HistoryViewController.h @@ -31,16 +31,11 @@ #define HISTORYVIEWCONTROLLER_H #import <Cocoa/Cocoa.h> -#import "QNSTreeController.h" @interface HistoryViewController : NSViewController <NSOutlineViewDelegate> { - NSOutlineView *historyView; } -@property NSTreeController *treeController; -@property (assign) IBOutlet NSOutlineView *historyView; - @end -#endif // HISTORYVIEWCONTROLLER_H \ No newline at end of file +#endif // HISTORYVIEWCONTROLLER_H diff --git a/HistoryViewController.mm b/HistoryViewController.mm index bf821f9b..4f6cc888 100644 --- a/HistoryViewController.mm +++ b/HistoryViewController.mm @@ -30,21 +30,31 @@ #import "HistoryViewController.h" #import <historymodel.h> +#import <callmodel.h> +#import <call.h> +#import <contactmethod.h> -#define COLUMNID_HISTORY @"HistoryColumn" // the single column name in our outline view +#import "MinimalHistoryBackend.h" +#import "QNSTreeController.h" +#define COLUMNID_DAY @"DayColumn" // the single column name in our outline view +#define COLUMNID_CONTACTMETHOD @"ContactMethodColumn" // the single column name in our outline view +#define COLUMNID_DATE @"DateColumn" // the single column name in our outline view -@implementation HistoryViewController +@interface HistoryViewController() -@synthesize treeController; +@property NSTreeController *treeController; +@property (assign) IBOutlet NSOutlineView *historyView; +@end +@implementation HistoryViewController +@synthesize treeController; +@synthesize historyView; - (id)initWithCoder:(NSCoder *)aDecoder { - - if (self = [super initWithCoder:aDecoder]) { NSLog(@"INIT HVC"); @@ -52,29 +62,41 @@ return self; } - - - (void)awakeFromNib { - NSLog(@"awakeFromNib"); - treeController = [[QNSTreeController alloc] initWithQModel:HistoryModel::instance()]; [treeController setAvoidsEmptySelection:NO]; [treeController setChildrenKeyPath:@"children"]; - [self.historyView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil]; - [self.historyView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil]; - [self.historyView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil]; + [historyView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil]; + [historyView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil]; + [historyView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil]; + [historyView setTarget:self]; + [historyView setDoubleAction:@selector(placeCall:)]; - NSInteger idx = [historyView columnWithIdentifier:COLUMNID_HISTORY]; + NSInteger idx = [historyView columnWithIdentifier:COLUMNID_DAY]; [[[[self.historyView tableColumns] objectAtIndex:idx] headerCell] setStringValue:@"Name"]; - //HistoryModel::instance()->addBackend(new MinimalHistoryBackend(nil), - // LoadOptions::FORCE_ENABLED); + HistoryModel::instance()->addCollection<MinimalHistoryBackend>(LoadOptions::FORCE_ENABLED); } +- (void)placeCall:(id)sender +{ + if([[treeController selectedNodes] count] > 0) { + Call* c = CallModel::instance()->dialingCall(); + QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]]; + QVariant var = HistoryModel::instance()->data(qIdx, (int)Call::Role::ContactMethod); + ContactMethod* m = qvariant_cast<ContactMethod*>(var); + if(m){ + Call* c = CallModel::instance()->dialingCall(); + c->setDialNumber(m); + c << Call::Action::ACCEPT; + } + } +} + #pragma mark - NSOutlineViewDelegate methods // ------------------------------------------------------------------------------- @@ -91,24 +113,8 @@ - (NSCell *)outlineView:(NSOutlineView *)outlineView dataCellForTableColumn:(NSTableColumn *)tableColumn item:(id)item { NSCell *returnCell = [tableColumn dataCell]; - - if(item == nil) return returnCell; - if ([[tableColumn identifier] isEqualToString:COLUMNID_HISTORY]) - { - - NSIndexPath* idx = ((NSTreeNode*)item).indexPath; - NSUInteger myArray[[idx length]]; - [idx getIndexes:myArray]; - - //NSLog(@"dataCellForTableColumn, indexPath: %d", myArray[0]); - - QModelIndex qIdx = HistoryModel::instance()->index(myArray[0], 0); - - QVariant test = HistoryModel::instance()->data(qIdx, Qt::DisplayRole); - } - return returnCell; } @@ -143,22 +149,19 @@ // ------------------------------------------------------------------------------- - (void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item { - if ([[tableColumn identifier] isEqualToString:COLUMNID_HISTORY]) - { - NSIndexPath* idx = ((NSTreeNode*)item).indexPath; - NSUInteger myArray[[idx length]]; - [idx getIndexes:myArray]; - //NSLog(@"array:%@", idx); - - QModelIndex qIdx; - if(idx.length == 2) - qIdx = HistoryModel::instance()->index(myArray[1], 0, HistoryModel::instance()->index(myArray[0], 0)); - else - qIdx = HistoryModel::instance()->index(myArray[0], 0); - + QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)]; + if(!qIdx.isValid()) + return; - if(qIdx.isValid()) - cell.title = HistoryModel::instance()->data(qIdx, Qt::DisplayRole).toString().toNSString(); + if ([[tableColumn identifier] isEqualToString:COLUMNID_DAY]) + { + cell.title = HistoryModel::instance()->data(qIdx, Qt::DisplayRole).toString().toNSString(); + } else if ([[tableColumn identifier] isEqualToString:COLUMNID_CONTACTMETHOD]) + { + cell.title = HistoryModel::instance()->data(qIdx, (int)Call::Role::Number).toString().toNSString(); + } else if ([[tableColumn identifier] isEqualToString:COLUMNID_DATE]) + { + cell.title = HistoryModel::instance()->data(qIdx, (int)Call::Role::FormattedDate).toString().toNSString(); } } diff --git a/PreferencesViewController.mm b/PreferencesViewController.mm index 103baa49..adba6481 100644 --- a/PreferencesViewController.mm +++ b/PreferencesViewController.mm @@ -73,10 +73,7 @@ static NSString* const kDonePrefsIdentifer = @"DonePrefsIdentifer"; animation.toValue = [NSValue valueWithPoint:self.view.frame.origin]; animation.duration = 0.3f; [animation setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:.7 :0.9 :1 :1]]; - - [self.view.layer addAnimation:animation forKey:animation.keyPath]; - self.view.layer.position = frame.origin; } - (void) close diff --git a/RingWindow.xib b/RingWindow.xib index 26e4b3dc..384dad70 100644 --- a/RingWindow.xib +++ b/RingWindow.xib @@ -16,35 +16,88 @@ <customObject id="-3" userLabel="Application" customClass="NSObject"/> <window title="Ring" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" animationBehavior="default" id="F0z-JX-Cv5"> <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> + <windowCollectionBehavior key="collectionBehavior" fullScreenPrimary="YES"/> <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> - <rect key="contentRect" x="196" y="240" width="1065" height="626"/> + <rect key="contentRect" x="196" y="240" width="1053" height="626"/> <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1050"/> <view key="contentView" autoresizesSubviews="NO" id="se5-gp-TjO"> - <rect key="frame" x="0.0" y="0.0" width="1065" height="626"/> + <rect key="frame" x="0.0" y="0.0" width="1053" height="626"/> <autoresizingMask key="autoresizingMask"/> <subviews> - <tabView focusRingType="none" fixedFrame="YES" type="bottomTabsBezelBorder" translatesAutoresizingMaskIntoConstraints="NO" id="xXW-iq-GcP"> - <rect key="frame" x="13" y="14" width="384" height="427"/> + <scrollView focusRingType="none" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bqQ-DB-Z0g"> + <rect key="frame" x="20" y="461" width="300" height="145"/> + <clipView key="contentView" focusRingType="none" id="1so-Pz-QB2"> + <rect key="frame" x="1" y="17" width="238" height="117"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <outlineView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" autosaveColumns="NO" headerView="nuM-bu-a6l" indentationPerLevel="16" outlineTableColumn="VDO-Cu-h8f" id="zcl-pp-rGb"> + <rect key="frame" x="0.0" y="0.0" width="298" height="19"/> + <autoresizingMask key="autoresizingMask"/> + <size key="intercellSpacing" width="3" height="2"/> + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/> + <tableColumns> + <tableColumn identifier="ConversationsColumn" width="295" minWidth="40" maxWidth="1000" id="VDO-Cu-h8f"> + <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Conversations"> + <font key="font" metaFont="smallSystem"/> + <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/> + </tableHeaderCell> + <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="fca-40-NK1"> + <font key="font" metaFont="system"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/> + </tableColumn> + </tableColumns> + <connections> + <outlet property="delegate" destination="txt-J3-pzW" id="6In-PG-OW4"/> + </connections> + </outlineView> + </subviews> + <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> + </clipView> + <constraints> + <constraint firstAttribute="width" constant="300" id="eCz-d8-35b"/> + <constraint firstAttribute="height" constant="145" id="lWc-BG-yhJ"/> + </constraints> + <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="Fze-JQ-8rU"> + <rect key="frame" x="1" y="119" width="223" height="15"/> + <autoresizingMask key="autoresizingMask"/> + </scroller> + <scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="e1E-df-1Rw"> + <rect key="frame" x="224" y="17" width="15" height="102"/> + <autoresizingMask key="autoresizingMask"/> + </scroller> + <tableHeaderView key="headerView" id="nuM-bu-a6l"> + <rect key="frame" x="0.0" y="0.0" width="238" height="17"/> + <autoresizingMask key="autoresizingMask"/> + </tableHeaderView> + </scrollView> + <tabView focusRingType="none" ambiguous="YES" misplaced="YES" type="bottomTabsBezelBorder" translatesAutoresizingMaskIntoConstraints="NO" id="xXW-iq-GcP"> + <rect key="frame" x="13" y="14" width="309" height="443"/> <font key="font" metaFont="system"/> <tabViewItems> <tabViewItem label="History" identifier="1" id="Wi9-Zd-O1N"> - <view key="view" id="h2E-qI-upQ"> + <view key="view" ambiguous="YES" id="h2E-qI-upQ"> + <rect key="frame" x="10" y="7" width="138" height="405"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> - <scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9uI-D5-KRt"> - <rect key="frame" x="-3" y="-395" width="370" height="398"/> - <clipView key="contentView" misplaced="YES" id="eME-fQ-3QX"> + <scrollView ambiguous="YES" misplaced="YES" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9uI-D5-KRt"> + <rect key="frame" x="-3" y="0.0" width="295" height="408"/> + <clipView key="contentView" ambiguous="YES" misplaced="YES" id="eME-fQ-3QX"> <rect key="frame" x="1" y="17" width="238" height="117"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> - <outlineView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" autosaveColumns="NO" headerView="3Mm-vF-0m3" indentationPerLevel="16" autoresizesOutlineColumn="YES" outlineTableColumn="pTT-gU-NVa" id="rr8-UC-gGF"> - <rect key="frame" x="0.0" y="0.0" width="368" height="19"/> + <outlineView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" autosaveColumns="NO" headerView="u2H-dj-Z3N" indentationPerLevel="16" autoresizesOutlineColumn="YES" outlineTableColumn="pTT-gU-NVa" id="rr8-UC-gGF"> + <rect key="frame" x="0.0" y="0.0" width="226" height="19"/> <autoresizingMask key="autoresizingMask"/> <size key="intercellSpacing" width="3" height="2"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/> <tableColumns> - <tableColumn identifier="HistoryColumn" width="365" minWidth="40" maxWidth="1000" id="pTT-gU-NVa"> + <tableColumn identifier="DayColumn" width="87.5703125" minWidth="40" maxWidth="1000" id="pTT-gU-NVa"> <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left"> <font key="font" metaFont="smallSystem"/> <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/> @@ -57,6 +110,32 @@ </textFieldCell> <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/> </tableColumn> + <tableColumn identifier="ContactMethodColumn" width="64" minWidth="10" maxWidth="3.4028234663852886e+38" id="uZK-ej-3oe"> + <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left"> + <font key="font" metaFont="smallSystem"/> + <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/> + </tableHeaderCell> + <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="hsi-nD-XUY"> + <font key="font" metaFont="system"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/> + </tableColumn> + <tableColumn identifier="DateColumn" width="65.5" minWidth="10" maxWidth="3.4028234663852886e+38" id="HlW-br-V4K"> + <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left"> + <font key="font" metaFont="smallSystem"/> + <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/> + </tableHeaderCell> + <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="TeI-6b-R8a"> + <font key="font" metaFont="system"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/> + </tableColumn> </tableColumns> <connections> <outlet property="delegate" destination="jzj-dD-ryc" id="UpR-Pm-j0w"/> @@ -73,168 +152,134 @@ <rect key="frame" x="224" y="17" width="15" height="102"/> <autoresizingMask key="autoresizingMask"/> </scroller> - <tableHeaderView key="headerView" id="3Mm-vF-0m3"> - <rect key="frame" x="0.0" y="0.0" width="238" height="17"/> + <tableHeaderView key="headerView" id="u2H-dj-Z3N"> + <rect key="frame" x="0.0" y="0.0" width="10000" height="17"/> <autoresizingMask key="autoresizingMask"/> </tableHeaderView> </scrollView> </subviews> + <constraints> + <constraint firstAttribute="trailing" secondItem="9uI-D5-KRt" secondAttribute="trailing" constant="3" id="7Oo-Z3-JeE"/> + <constraint firstItem="9uI-D5-KRt" firstAttribute="top" secondItem="h2E-qI-upQ" secondAttribute="top" constant="3" id="Fu4-zc-WvO"/> + <constraint firstItem="9uI-D5-KRt" firstAttribute="leading" secondItem="h2E-qI-upQ" secondAttribute="leading" constant="3" id="mO1-Tn-dFB"/> + <constraint firstAttribute="bottom" secondItem="9uI-D5-KRt" secondAttribute="bottom" id="mRP-eB-8tk"/> + </constraints> </view> </tabViewItem> <tabViewItem label="Contacts" identifier="2" id="K8Y-fi-aYs"> <view key="view" id="pkc-Vr-KaR"> - <rect key="frame" x="10" y="7" width="364" height="389"/> + <rect key="frame" x="10" y="7" width="289" height="405"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> - <scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uSW-wV-jgA"> - <rect key="frame" x="-3" y="5" width="370" height="386"/> - <clipView key="contentView" misplaced="YES" id="teg-nj-5g1"> - <rect key="frame" x="1" y="17" width="238" height="117"/> + <scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="26" horizontalPageScroll="10" verticalLineScroll="26" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="97U-Gt-cyM"> + <rect key="frame" x="-3" y="5" width="262" height="403"/> + <clipView key="contentView" misplaced="YES" drawsBackground="NO" id="hWX-Nx-pQp"> + <rect key="frame" x="1" y="1" width="148" height="398"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> - <outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" autosaveColumns="NO" headerView="1R3-0U-i5y" indentationPerLevel="16" outlineTableColumn="vsd-Kj-tgi" id="net-CU-6Pr"> - <rect key="frame" x="0.0" y="0.0" width="119" height="19"/> + <outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="sourceList" multipleSelection="NO" autosaveColumns="NO" rowHeight="24" rowSizeStyle="systemDefault" viewBased="YES" indentationPerLevel="16" outlineTableColumn="hAb-Pb-oGc" id="QWJ-19-vdG"> <autoresizingMask key="autoresizingMask"/> <size key="intercellSpacing" width="3" height="2"/> - <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + <color key="backgroundColor" name="_sourceListBackgroundColor" catalog="System" colorSpace="catalog"/> <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/> <tableColumns> - <tableColumn width="116" minWidth="40" maxWidth="1000" id="vsd-Kj-tgi"> + <tableColumn width="257" minWidth="16" maxWidth="1000" id="hAb-Pb-oGc"> <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left"> <font key="font" metaFont="smallSystem"/> <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/> </tableHeaderCell> - <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="F1l-ce-gHn"> + <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="uZb-xz-gWA"> <font key="font" metaFont="system"/> <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> </textFieldCell> <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/> + <prototypeCellViews> + <tableCellView identifier="HeaderCell" id="PzH-z0-VD7"> + <rect key="frame" x="1" y="0.0" width="257" height="17"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Oys-k4-9rU"> + <rect key="frame" x="0.0" y="1" width="145" height="14"/> + <textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="HEADER CELL" id="R5Z-ka-3n9"> + <font key="font" metaFont="smallSystemBold"/> + <color key="textColor" name="headerColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + </subviews> + <connections> + <outlet property="textField" destination="Oys-k4-9rU" id="8y1-pg-oNp"/> + </connections> + </tableCellView> + <tableCellView identifier="DataCell" id="5Ha-Xw-dV2"> + <rect key="frame" x="1" y="17" width="257" height="17"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <imageView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="TRY-iI-50K"> + <rect key="frame" x="3" y="0.0" width="17" height="17"/> + <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSActionTemplate" id="VCC-yq-OnA"/> + </imageView> + <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xGF-1J-9zK"> + <rect key="frame" x="25" y="0.0" width="120" height="17"/> + <textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="hUW-SW-o2M"> + <font key="font" metaFont="system"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + </subviews> + <connections> + <outlet property="imageView" destination="TRY-iI-50K" id="oxM-HW-Q2y"/> + <outlet property="textField" destination="xGF-1J-9zK" id="ECl-Xz-gHc"/> + </connections> + </tableCellView> + </prototypeCellViews> </tableColumn> </tableColumns> </outlineView> </subviews> - <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> + <nil key="backgroundColor"/> </clipView> - <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="743-H8-ZNq"> - <rect key="frame" x="1" y="119" width="223" height="15"/> + <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="M74-sb-E0H"> + <rect key="frame" x="1" y="119" width="238" height="15"/> <autoresizingMask key="autoresizingMask"/> </scroller> - <scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="cdr-l3-THF"> + <scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="ESd-xt-czc"> <rect key="frame" x="224" y="17" width="15" height="102"/> <autoresizingMask key="autoresizingMask"/> </scroller> - <tableHeaderView key="headerView" id="1R3-0U-i5y"> - <rect key="frame" x="0.0" y="0.0" width="238" height="17"/> - <autoresizingMask key="autoresizingMask"/> - </tableHeaderView> </scrollView> </subviews> </view> </tabViewItem> </tabViewItems> </tabView> - <customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tSW-YT-asL"> - <rect key="frame" x="427" y="69" width="309" height="447"/> - <subviews> - <scrollView focusRingType="none" fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bqQ-DB-Z0g"> - <rect key="frame" x="20" y="11" width="275" height="322"/> - <clipView key="contentView" focusRingType="none" misplaced="YES" id="1so-Pz-QB2"> - <rect key="frame" x="1" y="17" width="238" height="117"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> - <subviews> - <outlineView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" autosaveColumns="NO" headerView="nuM-bu-a6l" indentationPerLevel="16" outlineTableColumn="VDO-Cu-h8f" id="zcl-pp-rGb"> - <rect key="frame" x="0.0" y="0.0" width="273" height="19"/> - <autoresizingMask key="autoresizingMask"/> - <size key="intercellSpacing" width="3" height="2"/> - <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> - <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/> - <tableColumns> - <tableColumn identifier="ConversationsColumn" width="270" minWidth="40" maxWidth="1000" id="VDO-Cu-h8f"> - <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left"> - <font key="font" metaFont="smallSystem"/> - <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/> - </tableHeaderCell> - <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="fca-40-NK1"> - <font key="font" metaFont="system"/> - <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> - </textFieldCell> - <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/> - </tableColumn> - </tableColumns> - <connections> - <outlet property="delegate" destination="txt-J3-pzW" id="6In-PG-OW4"/> - </connections> - </outlineView> - </subviews> - <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> - </clipView> - <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="Fze-JQ-8rU"> - <rect key="frame" x="1" y="119" width="223" height="15"/> - <autoresizingMask key="autoresizingMask"/> - </scroller> - <scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="e1E-df-1Rw"> - <rect key="frame" x="224" y="17" width="15" height="102"/> - <autoresizingMask key="autoresizingMask"/> - </scroller> - <tableHeaderView key="headerView" id="nuM-bu-a6l"> - <rect key="frame" x="0.0" y="0.0" width="238" height="17"/> - <autoresizingMask key="autoresizingMask"/> - </tableHeaderView> - </scrollView> - <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="SIv-wg-z9p"> - <rect key="frame" x="14" y="379" width="64" height="32"/> - <buttonCell key="cell" type="push" title="Call" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="0gt-3R-vVa"> - <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> - <font key="font" metaFont="system"/> - </buttonCell> - <connections> - <action selector="placeCall:" target="txt-J3-pzW" id="Kqn-M7-Zqx"/> - </connections> - </button> - <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="TLn-7x-ekk"> - <rect key="frame" x="91" y="379" width="70" height="32"/> - <buttonCell key="cell" type="push" title="Hold" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="uAm-ag-EFO"> - <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> - <font key="font" metaFont="system"/> - </buttonCell> - </button> - <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="gU5-lZ-BvR"> - <rect key="frame" x="168" y="379" width="90" height="32"/> - <buttonCell key="cell" type="push" title="Hangup" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="xpJ-nm-Bg6"> - <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> - <font key="font" metaFont="system"/> - </buttonCell> - </button> - <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uL1-rr-hj0"> - <rect key="frame" x="20" y="415" width="250" height="22"/> - <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="sil-2N-5Wz"> - <font key="font" metaFont="system"/> - <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> - </textFieldCell> - </textField> - <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Iny-6e-BBx"> - <rect key="frame" x="91" y="338" width="89" height="32"/> - <buttonCell key="cell" type="push" title="preview" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="rwC-ls-8XK"> - <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> - <font key="font" metaFont="system"/> - </buttonCell> - <connections> - <action selector="startPreview:" target="txt-J3-pzW" id="yds-UF-819"/> - </connections> - </button> - </subviews> + <customView misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tSW-YT-asL"> + <rect key="frame" x="323" y="0.0" width="725" height="626"/> + <constraints> + <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="626" id="5yo-rb-X1O"/> + <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="725" id="ccX-uq-zuj"/> + </constraints> </customView> </subviews> + <constraints> + <constraint firstItem="xXW-iq-GcP" firstAttribute="leading" secondItem="se5-gp-TjO" secondAttribute="leading" constant="20" id="6mJ-d2-JIf"/> + <constraint firstItem="bqQ-DB-Z0g" firstAttribute="top" secondItem="se5-gp-TjO" secondAttribute="top" constant="20" id="FeC-4y-ScK"/> + <constraint firstItem="xXW-iq-GcP" firstAttribute="top" secondItem="bqQ-DB-Z0g" secondAttribute="bottom" constant="8" id="KXj-CP-Fmh"/> + <constraint firstAttribute="bottom" secondItem="tSW-YT-asL" secondAttribute="bottom" id="Xa4-hd-K1t"/> + <constraint firstItem="tSW-YT-asL" firstAttribute="leading" secondItem="bqQ-DB-Z0g" secondAttribute="trailing" constant="8" id="cW1-si-AGR"/> + <constraint firstAttribute="trailing" secondItem="tSW-YT-asL" secondAttribute="trailing" id="g0F-Wt-YT6"/> + <constraint firstAttribute="bottom" secondItem="xXW-iq-GcP" secondAttribute="bottom" constant="20" id="hQL-rc-Qaw"/> + <constraint firstItem="bqQ-DB-Z0g" firstAttribute="leading" secondItem="se5-gp-TjO" secondAttribute="leading" constant="20" id="jQg-C7-rD0"/> + <constraint firstItem="tSW-YT-asL" firstAttribute="top" secondItem="se5-gp-TjO" secondAttribute="top" id="w5j-cX-qS9"/> + </constraints> </view> <connections> <outlet property="delegate" destination="-2" id="0bl-1N-AYu"/> </connections> - <point key="canvasLocation" x="204.5" y="343"/> + <point key="canvasLocation" x="530" y="361"/> </window> <viewController id="jzj-dD-ryc" customClass="HistoryViewController"> <connections> @@ -244,10 +289,13 @@ </viewController> <viewController id="txt-J3-pzW" customClass="ConversationsViewController"> <connections> - <outlet property="callUriTextField" destination="uL1-rr-hj0" id="YbK-vC-zee"/> <outlet property="conversationsView" destination="zcl-pp-rGb" id="YXp-WN-UmC"/> + <outlet property="currentCallView" destination="tSW-YT-asL" id="r2r-Q3-clc"/> <outlet property="view" destination="tSW-YT-asL" id="fv5-ly-rk8"/> </connections> </viewController> </objects> + <resources> + <image name="NSActionTemplate" width="14" height="14"/> + </resources> </document> diff --git a/RingWindowController.h b/RingWindowController.h index c65513af..cfca2e70 100644 --- a/RingWindowController.h +++ b/RingWindowController.h @@ -34,7 +34,7 @@ #import "HistoryViewController.h" #import "PreferencesViewController.h" -@interface RingWindowController : NSWindowController { +@interface RingWindowController : NSWindowController <NSToolbarDelegate>{ IBOutlet NSView *currentView; } @property (nonatomic, assign) NSViewController *myCurrentViewController; diff --git a/RingWindowController.mm b/RingWindowController.mm index e48ad6fa..4ad23cf2 100644 --- a/RingWindowController.mm +++ b/RingWindowController.mm @@ -37,28 +37,20 @@ @interface RingWindowController () +@property NSSearchField* callField; @end @implementation RingWindowController +@synthesize callField; +static NSString* const kSearchViewIdentifier = @"SearchViewIdentifier"; +static NSString* const kPreferencesIdentifier = @"PreferencesIdentifier"; +static NSString* const kCallButtonIdentifer = @"CallButtonIdentifier"; + - (void)windowDidLoad { [super windowDidLoad]; - [self connectSlots]; -} - - -- (void) connectSlots -{ - CallModel* callModel_ = CallModel::instance(); - QObject::connect(callModel_, &CallModel::callStateChanged, [](Call*, Call::State) { - NSLog(@"callStateChanged"); - }); - - QObject::connect(callModel_, &CallModel::incomingCall, [] (Call*) { - NSLog(@"incomingCall"); - }); - + [self displayMainToolBar]; } - (IBAction)openPreferences:(id)sender @@ -122,11 +114,19 @@ if(self.myCurrentViewController != nil) { [self.preferencesViewController close]; - [self.window setToolbar:nil]; + [self displayMainToolBar]; self.preferencesViewController = nil; } } +-(void) displayMainToolBar +{ + NSToolbar* tb = [[NSToolbar alloc] initWithIdentifier: @"MainToolbar"]; + [tb setDisplayMode:NSToolbarDisplayModeIconAndLabel]; + [tb setDelegate: self]; + [self.window setToolbar: tb]; +} + // FIXME: This is sick, NSWindowController is catching my selectors - (void)displayGeneral:(NSToolbarItem *)sender { [self.preferencesViewController displayGeneral:sender]; @@ -149,4 +149,82 @@ } +#pragma NSToolbar Delegate + +-(NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag +{ + NSToolbarItem* item = nil; + + if ([itemIdentifier isEqualToString: kSearchViewIdentifier]) { + item = [[NSToolbarItem alloc] initWithItemIdentifier: kSearchViewIdentifier]; + callField = [[NSSearchField alloc] initWithFrame:NSMakeRect(0,0,400,21)]; + [[callField cell] setSearchButtonCell:nil]; + [callField setToolTip:@"Call"]; + //[callField setAlignment:NSCenterTextAlignment]; + + [item setView:callField]; + } + + if ([itemIdentifier isEqualToString: kCallButtonIdentifer]) { + item = [[NSToolbarItem alloc] initWithItemIdentifier: kCallButtonIdentifer]; + + NSButton *callButton = [[NSButton alloc] initWithFrame:NSMakeRect(0,0,80,30)]; + + [callButton setButtonType:NSMomentaryLightButton]; //Set what type button You want + [callButton setBezelStyle:NSRoundedBezelStyle]; //Set what style You want] + [callButton setBordered:YES]; + [callButton setTitle:@"Call"]; + [item setView:callButton]; + [item setAction:@selector(placeCall:)]; + } + + if ([itemIdentifier isEqualToString: kPreferencesIdentifier]) { + item = [[NSToolbarItem alloc] initWithItemIdentifier: kPreferencesIdentifier]; + [item setImage: [NSImage imageNamed: @"NSAdvanced"]]; + [item setLabel: @"Settings"]; + [item setAction:@selector(openPreferences:)]; + } + + return item; + +} + + +- (IBAction)placeCall:(id)sender +{ + Call* c = CallModel::instance()->dialingCall(); + c->setDialNumber(QString::fromNSString([callField stringValue])); + c << Call::Action::ACCEPT; +} + +-(NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar +{ + return [NSArray arrayWithObjects: + NSToolbarSpaceItemIdentifier, + NSToolbarFlexibleSpaceItemIdentifier, + NSToolbarSpaceItemIdentifier, + NSToolbarSpaceItemIdentifier, + kSearchViewIdentifier, + kCallButtonIdentifer, + NSToolbarFlexibleSpaceItemIdentifier, + kPreferencesIdentifier, + nil]; +} + +-(NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar +{ + return [NSArray arrayWithObjects: + kSearchViewIdentifier, + kCallButtonIdentifer, + kPreferencesIdentifier, + nil]; +} + +-(NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar +{ + return nil; +} + + + @end -- GitLab