OST Wallet React Native SDK UI
Introduction
For quick and easy integration with SDK, developers can use built-in user interface components which are configurable and support content and theme customization.
All OstWalletSdkUI workflows return workflow-id
.
The application can subscribe to the events of the workflow using the workflow-id
.
Setup
OstWalletSdkUI
is packaged along with OstWalletSdk.
There are no additional steps for using OstWalletSdkUI
.
To setup OstWalletSdk, please refer to setup.
Before We Begin
-
App must initialize the sdk *before* initiating any UI workflows.
-
App must perform setupDevice workflow *before* initiating any UI workflows.
OstWalletSdkUI SDK APIs
To use OstWalletSdkUI
import {OstWalletSdkUI} from '@ostdotcom/ost-wallet-sdk-react-native';
Set Theme Config
Theme for OstWalletSdkUI can be initialized by calling setThemeConfig
API which setup OstWalletSdkUI theme config.
To define custom theme config, please refer to Theme Config Android/https://github.com/ostdotcom/ost-wallet-sdk-ios/blob/release-2.3/documentation/ThemeConfig.md[Theme Config iOS] documentation.
// Define the content config
const theme_config = {
"nav_bar_logo_image": {
"asset_name": "YOUR_LOGO_ASSET_NAME"
}
};
/**
* Set theme config for UI
* config: Config to use for UI
*/
OstWalletSdkUI.setThemeConfig(theme_config);
In the above example,
asset_name
is name of asset which is present in the respective assets folder for iOS/android.
Set Content Config
Content for OstWalletSdkUI can be initialized by calling setContentConfig
API which set-up OstWalletSdkUI content config.
To define custom content config, please refer to Content Config Android/https://github.com/ostdotcom/ost-wallet-sdk-ios/blob/release-2.3/documentation/ContentConfig.md[Content Config iOS] documentation.
// Please update terms_and_condition.url as per your needs.
const content_config = {
"activate_user": {
"create_pin": {
"placeholders": {
"terms_and_condition": {
"url": "https://YOUR-WEB-SITE.com/terms-page"
}
}
},
"confirm_pin": {
"placeholders": {
"terms_and_condition": {
"url": "https://YOUR-WEB-SITE.com/terms-page"
}
}
}
}
};
/**
* Set content config for UI
* config: Config to use for UI
*/
OstWalletSdkUI.setContentConfig(content_config);
Set Loader Manager
Application loader for OstWalletUI can be initialized by calling setLoaderManager
API.
This API is available in native SDK.
+ + Custom loader is supported from OstWalletSdk-native version Android v2.3.6
Or iOS v2.3.5
+ Please, verify OstWalletSdk version in Cartfile
.
+ + Custom loader needs to be written in native code (java, swift/Objective-C).
+ Sample code for custom loader is available in respective platform directory.
For iOS and Android
Setup your Passphrase Prefix Delegate
Passphrase Prefix
is a salt provided by your application that assists in generation of User’s recovery key using user’s PIN.
This salt should be unique for each user, is immutable and needs to be associated with the user.
The salt should not be stored in memory or on deivce unencrypted.
When the UI workflow need’s to ask for user’s PIN, delegate’s getPassphrase method is invoked.
The delegate must be derived from OstWalletUIWorkflowCallback
class.
Here is an example:
import { OstWalletUIWorkflowCallback } from '@ostdotcom/ost-wallet-sdk-react-native';
class UserPassphrasePrefixDelegate extends OstWalletUIWorkflowCallback {
constructor() {
super();
}
getPassphrase(userId, ostWorkflowContext, OstPassphrasePrefixAccept) {
let fetchPromise = new Promise((resolve,reject) => {
//Write code here to validate userId.
//If it is not the same as that of the logged-in user, reject the promise.
//Write code here to fetch the salt from your server.
//Read the passphrasePrefix from response and resolve the Promise.
});
fetchPromise
.then((passphrasePrefix) => {
OstPassphrasePrefixAccept.setPassphrase(passphrasePrefix, userId, (error) => {
console.warn(error);
});
})
.catch((err) => {
// Cancel the workflow.
OstPassphrasePrefixAccept.cancelFlow();
});
}
/**
* Optional Callback Implementation
* --------------------------------
*
* Application can also define and use following callback methods:
* - requestAcknowledged(ostWorkflowContext , ostContextEntity )
* - flowComplete(ostWorkflowContext , ostContextEntity )
* - flowInterrupt(ostWorkflowContext , ostError)
*
* Note:
* These methods can be helpful for debugging.
* Defining these methods does NOT impact ui workflow event subscription in any way.
* If application subscribes to events and also defines these callbacks, both shall be invoked.
*/
requestAcknowledged(ostWorkflowContext , ostContextEntity ) {
console.log("Received requestAcknowledged callback");
let contextWorkflowId = ostWorkflowContext.WORKFLOW_ID;
let workflowType = ostWorkflowContext.WORKFLOW_TYPE;
let entityType = ostContextEntity.entityType;
let entityData = ostContextEntity.entity;
console.log("- Workflow Id:", contextWorkflowId);
console.log("- Workflow Type:", workflowType);
console.log("- OstContextEntity type:", entityType)
console.log("- OstContextEntity entityData:", entityData);
}
flowComplete(ostWorkflowContext , ostContextEntity ) {
console.log("Received flowComplete callback");
let contextWorkflowId = ostWorkflowContext.WORKFLOW_ID;
let workflowType = ostWorkflowContext.WORKFLOW_TYPE;
let entityType = ostContextEntity.entityType;
let entityData = ostContextEntity.entity;
console.log("- Workflow Id:", contextWorkflowId);
console.log("- Workflow Type:", workflowType);
console.log("- OstContextEntity type:", entityType)
console.log("- OstContextEntity entityData:", entityData);
}
flowInterrupt(ostWorkflowContext , ostError) {
console.log("Received flowInterrupt callback");
let contextWorkflowId = ostWorkflowContext.WORKFLOW_ID;
let workflowType = ostWorkflowContext.WORKFLOW_TYPE;
let errorData = ostError.error;
let errorCode = ostError.getErrorCode();
// If you would like to reach out to Ost Devs for support,
// we request you to collect internalErrorCode
let internalErrorCode = ostError.getInternalErrorCode();
let isApiError = ostError.isApiError();
console.log("- Workflow Id:", contextWorkflowId);
console.log("- Workflow Type:", workflowType);
console.log("- Error");
console.log(" - Error Code:", errorCode);
console.log(" - Is Api Error:", isApiError);
console.log(" - Sdk Internal Error Code", internalErrorCode);
console.log(" - error data", errorData);
if ( isApiError && ostError.isApiSignerUnauthorized() ) {
console.log("- This device has either been revoked or not yet registered.");
} else if ("WORKFLOW_CANCELED" === errorCode.toUpperCase() ) {
console.log("- This error can be ignored. The workflow has been canceled by the user or application");
}
}
}
export default UserPassphrasePrefixDelegate;
Ost Wallet Settings
OstWallet Settings is a pre-built UI Component available exclusively available in ost-wallet-sdk-react-native
Sdk.
It is a wallet settings page that can be used by end-users to perfrom different wallet operations(Ost Wallet UI Workflows).
For details check here
Note +
OstWalletSettings
is available fromost-wallet-sdk-react-native
SKD version v2.3.12-beta.1
Ost Wallet UI Workflows
Activate User
User activation refers to the deployment of smart-contracts that form the user’s token wallet. An activated user can engage with a token.
let uiCallback = new UserPassphrasePrefixDelegate()
/**
* Activate user
* @param {String} userId - Ost User id
* @param {String} expiresAfterInSecs - session key expiry time.
* @param {String} spendingLimit - spending limit once in a transaction of session
* @param {OstWalletUIWorkflowCallback} uiCallback - callback implementation instances for application communication
* @public
*/
let workflowId = OstWalletSdkUI.activateUser(
userId,
expiresAfterInSecs,
spendingLimit,
uiCallback
);
// Subscribe to events
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.requestAcknowledged, () => {
// User is being activated. At this point, user can neither receive or send tokens.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowComplete, (ostWorkflowContext , ostContextEntity) => {
// Show success message to user.
// User has been activated. User can now start receiving tokens.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowInterrupt, (ostWorkflowContext , ostError) => {
// Show error to user.
// An error occoured during the workflow. The user has NOT been activated.
});
Add Session
A session is a period of time during which a sessionKey is authorized to sign transactions under a pre-set limit per transaction on behalf of the user. The device manager, which controls the tokens, authorizes sessions.
let uiCallback = new UserPassphrasePrefixDelegate()
/**
* Add user session
* @param {String} userId - Ost User id
* @param {String} expiresAfterInSecs - session key expiry time.
* @param {String} spendingLimit - spending limit once in a transaction of session
* @param {OstWalletUIWorkflowCallback} uiCallback - callback implementation instances for application communication
* @public
*/
let workflowId = OstWalletSdkUI.addSession(
userId,
expiresAfterInSecs,
spendingLimit,
uiCallback
)
// Subscribe to events
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.requestAcknowledged, () => {
// Session is being added.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowComplete, (ostWorkflowContext , ostContextEntity) => {
// Show success message to user.
// Session has been added.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowInterrupt, (ostWorkflowContext , ostError) => {
// Show error to user.
// An error occoured during the workflow. The Session has NOT been added.
});
Get Mnemonic Phrase
The mnemonic phrase represents a human-readable way to authorize a new device. This phrase is 12 words long.
let uiCallback = new UserPassphrasePrefixDelegate()
/**
* Get device mnemonics
* @param {String} userId - Ost User id
* @param {OstWalletUIWorkflowCallback} uiCallback - callback implementation instances for application communication
* @public
*/
let workflowId = OstWalletSdkUI.getDeviceMnemonics(
userId,
uiCallback
)
// Subscribe to events
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowComplete, (ostWorkflowContext , ostContextEntity) => {
// Show success message to user.
// User has seen the mnemonics
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowInterrupt, (ostWorkflowContext , ostError) => {
// Show error to user.
// An error occoured during the workflow.
});
Reset a User’s PIN
The user’s PIN is set when activating the user. This method supports re-setting a PIN and re-creating the recoveryOwner as part of that.
let uiCallback = new UserPassphrasePrefixDelegate()
/**
* Reset pin
*
* @param {String} userId - Ost User id
* @param {OstWalletUIWorkflowCallback} uiCallback - callback implementation instances for application communication
*/
let workflowId = OstWalletSdkUI.resetPin(
userId,
uiCallback
)
// Subscribe to events
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.requestAcknowledged, () => {
// Pin is being reset.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowComplete, (ostWorkflowContext , ostContextEntity) => {
// Show success message to user.
// Workflow completed successfully.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowInterrupt, (ostWorkflowContext , ostError) => {
// Show error to user.
// An error occoured during the workflow.
});
Initiate Recovery
A user can control their tokens using their authorized device(s). If the user loses their authorized device, she can recover access to their tokens by authorizing a new device via the recovery process.
If application set recoverDeviceAddress
then OstWalletUI ask for pin
to initiate device recovery.
Else it displays authorized device list for given userId
to select device from.
let uiCallback = new UserPassphrasePrefixDelegate();
/**
* Initiate device recovery
* @param {String} userId - Ost User id
* @param {String} recoverDeviceAddress - Device address which wants to recover
* @param {OstWalletUIWorkflowCallback} uiCallback - callback implementation instances for application communication
* @public
*/
let workflowId = OstWalletSdkUI.initiateDeviceRecovery(
userId,
recoverDeviceAddress,
uiCallback
)
// Subscribe to events
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.requestAcknowledged, () => {
// Device recovery has been initiated.
// The device will be recovered after 12 hours.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowComplete, (ostWorkflowContext , ostContextEntity) => {
// Show success message to user.
// Device recovery has been initiated.
// The device will be recovered after 12 hours.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowInterrupt, (ostWorkflowContext , ostError) => {
// Show error to user.
// An error occoured during the workflow.
});
recoverDeviceAddress
can benull
. + If you have your own UI to select the device to revoke, setrecoverDeviceAddress
to the selected device address. + Whennull
is passed, the Sdk will ask user to choose the device using built-in device list UI.+
Abort Device Recovery
To abort initiated device recovery.
let uiCallback = new UserPassphrasePrefixDelegate();
/**
* Abort device recovery
* @param {String} userId - Ost User id
* @param {OstWalletUIWorkflowCallback} uiCallback - callback implementation instances for application communication
* @public
*/
OstWalletSdkUI.abortDeviceRecovery(
userId,
uiCallback
)
// Subscribe to events
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.requestAcknowledged, () => {
// Request has been acknowledged by OST Platform.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowComplete, (ostWorkflowContext , ostContextEntity) => {
// Show success message to user.
// Device recovery has been aborted.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowInterrupt, (ostWorkflowContext , ostError) => {
// Show error to user.
// An error occoured during the workflow.
});
Revoke Device
To revoke device access.
let uiCallback = new UserPassphrasePrefixDelegate();
/**
* Revoke device
* @param {String} userId - Ost User id
* @param {String} deviceAddressToRevoke - Device address which wants to recover
* @param {OstWalletUIWorkflowCallback} uiCallback - callback implementation instances for application communication
* @public
*/
let workflowId = OstWalletSdkUI.revokeDevice(userId, deviceAddressToRevoke, uiCallback );
// Subscribe to events
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.requestAcknowledged, () => {
// Request has been acknowledged by OST Platform.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowComplete, (ostWorkflowContext , ostContextEntity) => {
// Show success message to user.
// Device has been revoked.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowInterrupt, (ostWorkflowContext , ostError) => {
// Show error to user.
// An error occoured during the workflow.
});
deviceAddressToRevoke
can benull
. + If you have your own UI to select the device to revoke, setdeviceAddressToRevoke
to the selected device address. + Whennull
is passed, the Sdk will ask user to choose the device using built-in device list UI.+
Update Biometric Preference
To enable or disable the biometric.
let uiCallback = new UserPassphrasePrefixDelegate();
let shouldEnable = true;
/**
* Update biometric preference
* @param {String} userId - Ost User id
* @param {boolean} shouldEnable - pass true to enable biometic preference, false to disable.
* @param {OstWalletUIWorkflowCallback} uiCallback - callback implementation instances for application communication
* @public
*/
let workflowId = OstWalletSdkUI.updateBiometricPreference( userId, shouldEnable, uiCallback );
// Subscribe to events
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowComplete, (ostWorkflowContext , ostContextEntity) => {
// Show success message to user.
// Preference has been updated.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowInterrupt, (ostWorkflowContext , ostError) => {
// Show error to user.
// An error occoured during the workflow.
});
Authorize Current Device With Mnemonics
To add a new device using 12 words recovery phrase.
let uiCallback = new UserPassphrasePrefixDelegate();
/**
* Authorize user device with mnemonics
* @param {String} userId - Ost User id
* @param {OstWalletWorkFlowCallback} workflow - callback implementation instances for application communication
* @public
*/
let workflowId = OstWalletSdkUI.authorizeCurrentDeviceWithMnemonics(userId, uiCallback);
// Subscribe to events
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.requestAcknowledged, () => {
// Request has been acknowledged by OST Platform.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowComplete, (ostWorkflowContext , ostContextEntity) => {
// Show success message to user.
// Device has been authorized.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowInterrupt, (ostWorkflowContext , ostError) => {
// Show error to user.
// An error occoured during the workflow.
});
Get Add Device QR-Code
To show QR-Code to scan from another authorized device
let uiCallback = new UserPassphrasePrefixDelegate();
/**
* Get add device QR code
*
* @param {String} userId - Ost User id
* @param {OstWalletUIWorkflowCallback} uiCallback - callback implementation instances for application communication
* @public
*/
let workflowId = OstWalletSdkUI.getAddDeviceQRCode(userId, uiCallback);
// Subscribe to events
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.requestAcknowledged, () => {
// Current Device is being authorized.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowComplete, (ostWorkflowContext , ostContextEntity) => {
// Show success message to user.
// Current Device has been authorized.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowInterrupt, (ostWorkflowContext , ostError) => {
// Show error to user.
// An error occoured during the workflow.
});
Scan QR-Code to Authorize Device
To authorize device by scanning device QR-Code.
QR-Code Sample:
{
"dd":"AD",
"ddv":"1.1.0",
"d":{
"da": "0x7701af46018fc57c443b63e839eb24872755a2f8"
}
}
let uiCallback = new UserPassphrasePrefixDelegate();
/**
* Scan QR-Code to authorize device
* @param {String} userId - Ost User id
* @param {OstWalletUIWorkflowCallback} uiCallback - callback implementation instances for application communication
* @public
*/
let workflowId = OstWalletSdkUI.scanQRCodeToAuthorizeDevice(userId, uiCallback);
// Subscribe to events
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.requestAcknowledged, () => {
// Device is being authorized.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowComplete, (ostWorkflowContext , ostContextEntity) => {
// Show success message to user.
// Device has been authorized.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowInterrupt, (ostWorkflowContext , ostError) => {
// Show error to user.
// An error occoured during the workflow.
});
Execute Transaction
-
By Scanning QR-Code + To execute transaction via device by scanning device QR-Code.
QR-Code Sample:
{
"dd":"TX",
"ddv":"1.1.0",
"d":{
"rn":"direct transfer",
"ads":[
"0x7701af46018fc57c443b63e839eb24872755a2f8",
"0xed09dc167a72d939ecf3d3854ad0978fb13a8fe9"
],
"ams":[
"1000000000000000000",
"1000000000000000000"
],
"tid": 1140,
"o":{
"cs":"USD",
"s": "$"
}
},
"m":{
"tn":"comment",
"tt":"user_to_user",
"td":"Thanks for comment"
}
}
let uiCallback = new UserPassphrasePrefixDelegate();
/**
* Scan QR-Code to execute transaction
*
* @param {String} userId - Ost User id
* @param {OstWalletUIWorkflowCallback} uiCallback - callback implementation instances for application communication
* @public
*/
let workflowId = OstWalletSdkUI.scanQRCodeToExecuteTransaction(userId, uiCallback);
// Subscribe to events
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.requestAcknowledged, () => {
// Transaction is being executed.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowComplete, (ostWorkflowContext , ostContextEntity) => {
// Show success message to user.
// Transaction has been executed successfully.
});
OstWalletSdkUI.subscribe(workflowId, OstWalletSdkUI.EVENTS.flowInterrupt, (ostWorkflowContext , ostError) => {
// Show error to user.
// An error occoured during the workflow.
});
-
By Calling function + Helper method creates session if active sessoin for transction amount is not available. To execute transaction via helper method, ref here
Ost Wallet UI Events and Listeners
Subscribe
Subscribe to specified event of UI Workflow
Supported EventName
are:
-
requestAcknowledged
-
flowComplete
-
flowInterrupt
You can retrive event names from Sdk:
OstWalletSdkUI.EVENTS.requestAcknowledged
OstWalletSdkUI.EVENTS.flowComplete
OstWalletSdkUI.EVENTS.flowInterrupt
/**
* Subscribes to specified event of UI Workflow.
* @param {String} workflowId - Id of the workflow as returned by methods of OstWalletSdkUI
* @param {String} eventName - Name of the event to subscribe to.
* @param {Function} listener - The listener function.
* @param {*} context - The context to invoke the listener with.
* @returns {Boolean} - false if failed to subscribe.
* @public
*/
OstWalletSdkUI.subscribe(
workflowId,
eventName,
listener,
context
)
/**
* Subscribes once to specified event of UI Workflow.
* @param {String} workflowId - Id of the workflow as returned by methods of OstWalletSdkUI
* @param {String} eventName - Name of the event to subscribe to.
* @param {Function} listener - The listener function.
* @param {*} context - The context to invoke the listener with.
* @returns {Boolean} - false if failed to subscribe.
* @public
*/
OstWalletSdkUI.subscribeOnce(
workflowId,
eventName,
listener,
context
)
Unsubscribe
Unsubscribes the listener from the specified event of UI Workflow.
/**
* Unsubscribes the listener from the specified event of UI Workflow.
* @param {String} workflowId - Id of the workflow as returned by methods of OstWalletSdkUI
* @param {String} eventName - Name of the event to subscribe to.
* @param {Function} listener - The listener function.
* @param {*} context - The context to invoke the listener with.
* @returns {Boolean} - false if failed to subscribe.
* @public
*/
OstWalletSdkUI.unsubscribe(
workflowId,
eventName,
listener,
context
)
Event Listeners
Request Acknowledged Listener
Acknowledge application about the request which is going to made by SDK.
/**
* Request acknowledged
* @param {Object} ostWorkflowContext - info about workflow type
* @param ostContextEntity - info about entity
* @override
*/
requestAcknowledged(ostWorkflowContext, ostContextEntity ) => {
//ostWorkflowContext.WORKFLOW_ID gives the id of the workflow.
//ostWorkflowContext.WORKFLOW_TYPE gives the type of the workflow.
}
Flow Complete Listener
/**
* Flow complete
* @param ostWorkflowContext - workflow type
* @param ostContextEntity - status of the flow
* @override
*/
flowComplete(ostWorkflowContext, ostContextEntity ) => {
//ostWorkflowContext.WORKFLOW_ID gives the id of the workflow.
//ostWorkflowContext.WORKFLOW_TYPE gives the type of the workflow.
}
Flow Interrupt Listener
/**
* Flow interrupt
* @param ostWorkflowContext workflow type
* @param ostError reason of interruption
* @override
*/
flowInterrupt(ostWorkflowContext, ostError) => {
//ostWorkflowContext.WORKFLOW_ID gives the id of the workflow.
//ostWorkflowContext.WORKFLOW_TYPE gives the type of the workflow.
}


Image Size
Here we use the style attribute to specify the dimensions, that is, width and height of an image:


Aldi shoppers FURIOUS at missing out on Kevin the Carrot toys due to high demand
Some hopeful customers queued online for hours overnight!
by Robert LeighAldi shoppers were left frustrated earlier today as they tried for hours to get their hands on Kevin the Carrot toys.
Kevin fans queued online overnight to bag the plush dolls of the characters starring in the supermarket's Christmas TV advert, with huge demand thought to have crashed Aldi's website.
The online frenzy meant the range sold out within hours, reportedly leaving thousands disappointed - including many who either stayed up all night on Saturday night or woke up very early on Sunday morning to stake their claim for the £3.99 collectibles.
According to the Mirror's website, an incredible 20,000 hopeful punters were in the online queue at one point.
Read more: Sprouts may have to be imported this Christmas as British shoppers 'face shortage'
One person is quoted as telling the news outlet that they remained in front of a screen to try and buy from midnight until 6am this morning.
And dozens of other would-be purchasers also complained in real time on social media about their lack of success in securing their very own Kevin.
"Kevin the carrot has sold out 😤😤😤," tweeted one unsatisfied customer.
"Just waited 20 mins to get on Aldi website for Kevin the Carrot and they are completely sold out #scandalous," said another.
Read more: Kevin the Carrot is back and he's got a new nemesis in the Aldi Christmas ad
Another shopper seethed: "I would of had better luck getting Glastonbury tickets than bloody Kevin the Carrot! Log back in at 7am and they are all sold out!"
"You should be sorry for not stocking enough Kevin the Carrots online," someone else tweeted at the supermarket's account.
And another particularly furious person raged: "If you stayed up all night to buy these toys just to put on ebay for inflated prices then you're a [bleep] and I hope every time you leave the house you get [bleep] on by seagulls with explosive diarrhoea 😊 #KevinTheCarrot."
Aldi told customers on social media: "Due to popular demand, Kevin and the rest of the range do tend to sell out quickly.
"But please don't worry! These characters will also be available to purchase individually in store on Thursday 28th November."
And a representative for Aldi told ED: "We're sorry that some shoppers were unable to get their hands on these toys online this morning, however, demand has been extremely high.
"The range will be stocked in-store from 28th November but, as with all of our Specialbuy products, these will also only be available while stocks last."
Leave us a comment on our Facebook page @EntertainmentDailyFix and let us know what you think of this story.


| Table 1 |
Parameters used for SWAT model calibration. |
| Table 2 |
ET simulation results at two typical sub-basins (numbers 3 a ... |
| Table 3 |
Correlation coefficients (r) between ET per unit area, total ... |
| Table 4 |
Rotated component matrix in factor analysis of ET per unit a ... |
| Table 5 |
Total variance explained in factor analysis for ET per unit ... |
| Table 6 |
Rotated component matrix in factor analysis of total ET. |


Fast Shipping
Free Shipping over 48 state*
Stark.Winterfell
| Orders | Date | Total | Products | Statue |
|---|---|---|---|---|
| #204 | 15/2/2018 | 58$ | Nike t shirts | Done |
| #258 | 15/7/2018 | 58$ | Polo t shirts | Progress |
| #784 | 1/2/2018 | 180$ | Nike Air one | Done |
| #432 | 1/7/2016 | 180$ | Nike Air one | Cancelled |
| #438 | 1/7/2016 | 32$ | Nike hooddie | Waiting... |


My promise to you is unwavering passion and support for total health transformation
In my approach to ultra-wellness, I consider every aspect of your lifestyle – food, breath, stress, knowledge – and help you create balance. This is called an integrative functioning approach. When each of these pieces are in equilibrium, the outcome is energy, healing, and vibrance.
The key to a total health transformation is reducing inflammation in the body which is the precursor to many chronic diseases and illnesses and creating a body that is balanced.
I know that something magical happens when you start feeling good. You sparkle a little more. Your hair shines. A new light within begins to glow. You sleep better. You have more clarity. Your skin is smoother. Your mind is sharper. You see new possibilities. You have more energy. Your immune system thrives. You awaken. You feel… vibrant.
My mission is to provide and curate the resources, information, guidance, support and goods that will produce the greatest impact for each individual person.
TigerNut Producers
TigerNuts are rich in prebiotic fiber.
Prebiotics act as food for your body's natural organisms.
They help your gut's natural probiotics thrive. A single ounce of TigerNuts has 40% of our daily recommended fiber!
We are the producers of fresh tigernut juice and smoothies.
We trend by offering you fresh drink from the far,
We donot add sugar nor preservatives to our drink<>.
TigerNuts are not nuts, they are small root vegetables.
This ancient superfood originates from Africa.
It is currently cultivated in West Africa & Spain.


Mid Term Average
Final Average
{{course_mid_term_average}}
{{course_final_average}}
{{mid_term_grade}}
{{final_grade}}
{{i.name}}
{{i.score}}


Cluster
Node
Server
dispycos: Cluster Status
Tasks Submitted :
0
Tasks Running :
0
Tasks Done :
0
Nodes
IP Address
Name
Servers
Available
Tasks
Last Update
CPU
Memory
Swap
Disk
Submitted
Running
Done
Update Interval Seconds :
Show Task Aguments :
Sort Nodes by :
IP Address
Name
Tasks Done
Last Update
Update
Selected Nodes :
Select
Suspend Node
Resume Node
Execute


The McMaster Mars Rover Team brings together students with interest in space and technologies to gain real world experience while solving technical problems. It allows students to participate in the design and construction of a functional Mars Rover, which will compete in international competitions. Many networking opportunities are available for members of the team.
Learn More!Want to join the team or sponsor us? Hit us up here!


Is it possible to have a normal right click AND your radar? I and others would greatly appreciate it if it's possible. I am in particular looking for the ability to "open in a new tab".
Love your work!!
Thanks for your time.
Nano
Global Moderator
You can use a Delayed Context Menu to open BBLog menu only when you
hold
right button.
Or just click in a link with control pressed or middle mouse click to open in a new tab.


iReporter enables any/every citizen to bring any form of corruption to the notice of appropriate authorities and the general public. You can also report on things that need government intervention.
From poor healthcare services to low quality of education, corruption affects us all! Why not do something about it now?
Corruption is a monster that grows daily and threatens to consume us all. The more you delay to act, the bigger corruption becomes.
Does it seem easier to keep quiet and just let that bribe pass? Think of our future, no pain now, no gain tomorrow.


NAME OF THE PROJECT
{{title}}
AUTHOR
{{author.name}}
{{author.email}}, +91 {{author.phone}}
CO-AUTHOR
{{coauthor.name}}
{{coauthor.email}}, +91 {{coauthor.phone}}
ADDRESS FOR CORRESPONDENCE
{{address}}
COLLEGE
{{author.college}}
CATEGORY
{{category}}
{% if round == '2' %}
{% endif %}


--- author: display_name: Rick Kelson email<EMAIL_ADDRESS>tags: - 100k - 24k - 250k - 500k - drg - geotiff - overview - quads - topo - usgs categories: [] date: 2011-08-15 18:16:39 -0600 24K: downloads: - url: https://raster.utah.gov/?catGroup=24K%20DRG,100K%20DRG,250K%20DRG&title=USGS%20Topo%20Maps label: USGS Topographic Maps via Interactive Map updates: - March 5, 2008 500K: downloads: - url: https://storage.googleapis.com/state-of-utah-sgid-downloads/drgs/500k/Collared/state_DRG500K_NAD27.zip label: Statewide 500K Topographic Map (NAD27) Vintage: downloads: - url: https://raster.utah.gov/?catGroup=Vintage%20Topographic%20Map&title=USGS%20Vintage%20Topo%20Maps label: USGS Vintage Topographic Maps via Interactive Map --- {% include abstract.html name="USGS Scanned Topographic Maps" type="Imagery" webapp="https://raster.utah.gov/?catGroup=24K%20DRG,100K%20DRG,250K%20DRG&title=USGS%20Topo%20Maps" abstract="The SGID contains complete statewide coverage of scanned standard series USGS topographic maps, also known as digital raster graphics (DRGs). UGRC has modified these DRGs so that they are collarless and are georeferenced to the surface of the earth using the UTM Zone 12 North, NAD83 projected coordinate system (except where noted). Every product on this page should be downloadable from raster.utah.gov. For all available USGS Topographic Maps visit The National Map TNM Download page or topoView." %}
1:24K Resolution products from the USGS modified by UGRC.
1:100K Resolution products from the USGS modified by UGRC.
1:250K Resolution products from the USGS modified by UGRC.
1:500K Resolution products from the USGS modified by UGRC.
The Utah Geological Survey created digital 7.5, 15 and 30-minute vintage U.S. Geological Survey topographic quadrangle maps (1900-1966) by scanning original paper maps at a resolution of 500 dots per inch (dpi). These digital scans were enhanced in Adobe Photoshop as needed. Subsequent 16 point spline georeferencing was done in ArcMap. There is not a statewide collection of these vintage topographic maps and they have a NAD27 Datum.


Summary
Aaron Althauser
Creative Project Manager with 2+ years of managing web & mobile application projects from estimation through completion, networking at international tech conferences, and building meaningful relationships with partners and clients.
- (+90)<PHONE_NUMBER>
-<EMAIL_ADDRESS>Education
Master of Science in Data Science
2021 - Present
IU University of Applied Sciences, Berlin, GR
Currently attending Master's studies courses in Data Science.
Bachelor of Arts in Psychology
2014 - 2016
University of Washington, Seattle, WA
Undergraduate studies in research at a top-25 ranked global university. Specialized in cognitive psychology, perception and human cognition.
Associate in Arts
2008 - 2010
Green River College, Auburn, WA
Transfer degree to undergraduate studies. Attended Running Start program to earn college credit while completing secondary school.
Professional Experience
Freelance: Available
Contact me anytime to inquire about freelance project management, software
development, art commissions, or just to be social.
Project Manager
2019 - Present
Mango Byte, Phnom Penh, KH (remote)
- Backend & frontend web app development using PHP/Laravel, React.js/Vue.js/Node.js, HTML5/SASS;
- Coordinate agile sprint meetings and tasks for developers, perform code reviews;
- Negotiate budget, scope and schedule of clients’ projects and app ideas;
- Network at international conferences, design and implement marketing campaigns;
Market Research & Development
2018 - 2019
BRN Technology, Izmir, TR
- Analyzed global markets through data collection, analysis, and research of procurement contracts;
- Provided business development insights based on market demand in the medical devices sector;
- Designed marketing materials and edited technical documents;
- Recruited, interviewed and trained international candidates;
- Established contact with new clients for medical supplies distribution;
Certificates
Professional Scrum Master (PSM1)
scrum.org, 09.2020
[Link] verification email<EMAIL_ADDRESS>Advanced Algorithmics and Graph Theory with Python
edX: IMTx, 06.2020
[Link]
Mathematical Thinking in Computer Science
Coursera: UC San Diego, 06.2020
[Link]
Java Data Structures and Software Design
edX: UPenn, 03.2020
[Link]
Computing in Python - Professional certificate program
edX: GTx, 12.2018 - 12.2019
CS1301xI: Fundamentals and Procedural Programming; CS1301xII: Control Structures;
CS1301xIII: Data Structures; CS1301xIV: Objects & Algorithms;
[Link]
Protecting Human Research Participants
National Institutes of Health, 04.2016
[Link]


The UDF system within ABPro allows you to add any number of additional data entry fields to you booking screen. You can add textboxes, checkboxes or radio buttons to you screen. The values entered by the user will be displayed in the appointment detail screen.
Cancel: Abort changes and return to the previous screen.
Save: Save changes and return to the previous screen.
Help: Opens this help screen.
Screen Label: The label for the UDF on the booking screen.
Type: Textbox, Checkbox or Radio Button. Textarea.
Size: You can set the size that textboxes will be shown on the booking screen. The size of the textbox does not limit the amount of text that can be entered, just the on-screen size of the box. The max text allowed is 255 characters.
Rows: This will set the number of rows if the 'Type' is textarea. The size of the textbox does not limit the amount of text that can be entered. The max text allowed is 255 characters.
Columns: This will set the number of columns if the 'Type' is textarea. The size of the textbox does not limit the amount of text that can be entered. The max text allowed is 255 characters.
Radio Buttons: Enter a comma separated list of words or phrases that are to be used as the radio button labels. You can specify one radio button to be initially selected by adding a "(d)" (to indicate default selection).
Example: "Apples, (d)Oranges, Bananas", will open the booking screen with the Oranges radio button selected.
Required Field: You can set any Textbox, or Textarea, UDFs to be a required field. This setting is ignored for non-Textbox/Textarea UDFs.
Help Text: You can define help text that will appear below the UDF on the booking screen. This is intended to assist the user in filling in the box.
Tooltip Text: You can define tooltip text that will appear when the user puts the mouse over the UDF on the booking screen.
Resources: You can assign this UDF to one or more resources. If NOT assigned, it will be shown for ALL. Select one or more resources that this UDF applies to. If you wish this UDF to be available for ALL resources, do not select any.
Order: The order in which the UDFs are presented on the booking screen.
Published: Only Published UDFs will appear in the booking screen.


 Like Jun Wu, I found studying this domain to be self-actualizing --- anxiety and clinical depression had not been anomalies, but intrinsic parts of my childhood.
I'm now somewhere around 20 years old and persistence of least the latter is ubiquitous in my daily life.
My experiences with mental health have been the result of many influences. One
of the most important influences has been the notion of smart
ness. I'll
discuss my interpretation of smart
, then explain why I think it's not a good
word.I use the
word "definitely" frequently in this post, not as an emphasis but as a synonym for "confidently".
u: School Rules
I grew up in an extremely competitive school district. Exemplifications of this include
- some of my friends began competing their SAT scores in the 7th grade;
- having a 4.0 GPA would not guarantee that you were in the academic top 10% of the student body;
- student leadership positions were often explicitly granted on a combined prestige and quid pro quo basis.
The problem is not always that such an environment exists. The problem is that for a student that has spent all of their primary education experience in such an environment, it is very likely the only environment they know exists. I still sometimes feel that it is the only environment that matters.
Viewerse.g. parents, teachers would compliment many
in this environment for their intelligence, and of course, for being smart
.
Maybe it is already obvious that smart
is not a good word for this - 80 hour
academic work weeks, at any age, is not necessarily an indication of
intelligence. It can only definitely be an indication of hard work.
But also, smart
ness doesn't have anything to do with intelligence.
s: DJ Benzi
What does being smart
even mean? In my experience, people use smart
to
simultaneously describe to someone's prowess in a certain skill and their
overall intelligence.
The problem with this is that knowledge of a particular domain and general
intelligence have almost nothing to do with each other. The reality is that you
and I are probably very knowledgeable in respective (but different!) knowledge
areas, and also probably have nearly-equal intelligences. Lumping the two
together means that a a listener who hears something about an individual's
smart
s has to either
- treat
smart
ness as a score of both domains, or - ask more questions.
Deference to the latter is least-ambiguous, but the presence of ambiguity at all
means this usage of smart
is already not a good pattern.
DJ Benzi is one of the most clever and knowledgeable individuals in their fieldFrom my perspective. There are many other clever and knowledgeable individuals in this domain as well. I just wrote this listening to Benzi.. From Benzi's perspective, I imagine there is one domain that he would consider me clever and knowledgeable in. I also believe that both of us have equalor at least definitely highly-similar intelligences.
Maybe someone could say DJ Benzi and I are both smart. What does that tell you?
t: Computational Equivalence
The thing is, I'm pretty sure all entities in the environments around us are computationally equivalentDerived from the theory of computation, itself an idea popularized by Stephen Wolfram., which is the idea that structures are identical in their design complexity though their functionality may be radically differentMy interpretation of computational equivalence is a very optimistic one. It may be the case that this model can be absolutely refuted, but it is the most generic appeal to logic I currently have..
Treating all entities as computationally equivalent generalizes influences on
functionality. In this model, intelligence
is as not good of a word as smart
is. It becomes easy to show that the only
differentiatorsas related to this discussion
between any two entities are the knowledge domains they operate in.
This means the cumulative domain signature an entity operates in must be globally unique. Perception of something as "difficult" or "interesting" is an artifact of contrasting domain signatures, though in fact every domain is equally complex. This is the model I employ for reasoning why different people find problems to be "difficult" or "interesting"This can be thought of as generalizing a context of ethnocentrism..
"Passion" is also solved by this model. A
's "passion" is an artifact of A
's
perception of contrasting structural distribution. Structures may be more or
less rare, but they are still all equivalent in complexity. It's even possible
to generalize that A
's passion is A
's computational signature.
Anyway, that's an unbound idea. The point is smart
is not a good word. Maybe
it's even a bad word.
ThoughtThoughts
I would like to hear your thoughts about my thoughts. The best way to contact me is via email.


Testing PI:ref and footnotes
What?
Running short of meaningfull text, I turn to some latin quotes copied from [1] . It may not be correct to use footnotes for translation, it may be "Ad absurdum"1 To the point of absurdity, but it looks fine. Like for instance "Extra ecclesiam nulla salus" 2 Outside the Church [there is] No Salvation. (A phrase of much disputed significance in Roman Catholic theology) could be used in many situations outside the church.
Or if ypu are a teacher you could of course tell your students "Aut disce aut discede"3 Either learn or leave, as you have always wanted.
Content file for this page
content/page1_xml.html
- To the point of absurdity
- Outside the Church [there is] No Salvation. (A phrase of much disputed significance in Roman Catholic theology)
- Either learn or leave
- Latin Quotes and Latin Phrases Yuni Words of Wisdom www.yuni.com/library/latin.html 11-12-2010


---
layout: post
title: 2nd Lifehack for 2008
tags:
- Mac
- Work Practices
status: publish
type: post
published: true
meta: {}
---
Now dropping Emacs in favour of TextWrangler in the belief that it's simpler and easier to use for my limited needs.
So export SVN_EDITOR=/usr/bin/edit
if using subversion as well, after installing the TextWrangler command line tools


Model fitting of flexible behavioural recapture models based on conditional probability reparameterization and meaningful partial capture history quantification also referred to as meaningful behavioural covariate
| Version: | 0.1 |
| Depends: | R (≥ 3.0.2), HI, locfit, lme4, secr |
| Published: | 2013-12-19 |
| Author: | Luca Tardella and Danilo Alunni Fegatelli |
| Maintainer: | Danilo Alunni Fegatelli <danilo.alunnifegatelli at uniroma1.it> |
| License: | GPL-2 |
| NeedsCompilation: | no |
| CRAN checks: | BBRecapture results |
| Reference manual: | BBRecapture.pdf |
| Package source: | BBRecapture_0.1.tar.gz |
| Windows binaries: | r-devel: BBRecapture_0.1.zip, r-release: BBRecapture_0.1.zip, r-oldrel: BBRecapture_0.1.zip |
| OS X binaries: | r-release: BBRecapture_0.1.tgz, r-oldrel: BBRecapture_0.1.tgz |
Please use the canonical form https://CRAN.R-project.org/package=BBRecapture to link to this page.


If you wanna play our game go to the homepage and click on the button start new game!
If you wanna see the user info go to homepage and click on the button current user!
If you wanna update your email or password go to Profile and then settings.There you can choose between changing your email or your password.
If you like chess this is the app for you.Have lots of fun!


Convert text into speech (voice file in 'wav' format) with API offered by ITRI TTS (Text-To-Speech service, Industrial Technology Research Institute, Taiwan. http://tts.itri.org.tw/). One main function is given, tts_ITRI(). English and Chinese (both traditional and simplified) are supported, and user can specify the speaker accent, speed and volume. Using this package requires internet connection.
| Version: | 0.3.3 |
| Depends: | RCurl |
| Published: | 2015-11-07 |
| Author: | Xiaodong Deng |
| Maintainer: | Xiaodong Deng <xd_deng at hotmail.com> |
| License: | GPL-3 |
| URL: | http://me.seekingqed.com/ |
| NeedsCompilation: | no |
| Materials: | NEWS |
| CRAN checks: | Rtts results |
| Reference manual: | Rtts.pdf |
| Package source: | Rtts_0.3.3.tar.gz |
| Windows binaries: | r-devel: Rtts_0.3.3.zip, r-release: Rtts_0.3.3.zip, r-oldrel: Rtts_0.3.3.zip |
| OS X binaries: | r-release: Rtts_0.3.3.tgz, r-oldrel: Rtts_0.3.3.tgz |
| Old sources: | Rtts archive |
Please use the canonical form https://CRAN.R-project.org/package=Rtts to link to this page.


public class SerialPortEvent
extends java.lang.Object
| Modifier and Type | Field and Description |
|---|---|
static int |
BREAK |
static int |
CTS |
static int |
DSR |
static int |
ERR |
private int |
eventType |
private int |
eventValue |
private java.lang.String |
portName |
static int |
RING |
static int |
RLSD |
static int |
RXCHAR |
static int |
RXFLAG |
static int |
TXEMPTY |
| Constructor and Description |
|---|
SerialPortEvent(java.lang.String portName,
int eventType,
int eventValue) |
| Modifier and Type | Method and Description |
|---|---|
int |
getEventType()
Getting event type
|
int |
getEventValue()
Getting event value
Event values depending on their types: RXCHAR - bytes count in input buffer RXFLAG - bytes count in input buffer (Not supported in Linux) TXEMPTY - bytes count in output buffer CTS - state of CTS line (0 - OFF, 1 - ON) DSR - state of DSR line (0 - OFF, 1 - ON) RLSD - state of RLSD line (0 - OFF, 1 - ON) BREAK - 0 RING - state of RING line (0 - OFF, 1 - ON) ERR - mask of errors |
java.lang.String |
getPortName()
Getting port name which sent the event
|
boolean |
isBREAK()
Method returns true if event of type "BREAK" is received and otherwise false
|
boolean |
isCTS()
Method returns true if event of type "CTS" is received and otherwise false
|
boolean |
isDSR()
Method returns true if event of type "DSR" is received and otherwise false
|
boolean |
isERR()
Method returns true if event of type "ERR" is received and otherwise false
|
boolean |
isRING()
Method returns true if event of type "RING" is received and otherwise false
|
boolean |
isRLSD()
Method returns true if event of type "RLSD" is received and otherwise false
|
boolean |
isRXCHAR()
Method returns true if event of type "RXCHAR" is received and otherwise false
|
boolean |
isRXFLAG()
Method returns true if event of type "RXFLAG" is received and otherwise false
|
boolean |
isTXEMPTY()
Method returns true if event of type "TXEMPTY" is received and otherwise false
|
private java.lang.String portName
private int eventType
private int eventValue
public static final int RXCHAR
public static final int RXFLAG
public static final int TXEMPTY
public static final int CTS
public static final int DSR
public static final int RLSD
public static final int BREAK
public static final int ERR
public static final int RING
public SerialPortEvent(java.lang.String portName, int eventType, int eventValue)
public java.lang.String getPortName()
public int getEventType()
public int getEventValue()
public boolean isRXCHAR()
public boolean isRXFLAG()
public boolean isTXEMPTY()
public boolean isCTS()
public boolean isDSR()
public boolean isRLSD()
public boolean isBREAK()
public boolean isERR()
public boolean isRING()


Recipe 11.9. Combining GUIs and Asynchronous I/Owith ThreadsCredit: Jacob Hallén, Laura Creighton, Boudewijn Rempt ProblemYou need to access sockets, serial ports, or other asynchronous (but blocking) I/O sources, while running a GUI. SolutionThe solution is to handle a GUI interface on one thread and communicate to it (via Queue instances) the events on I/O channels handled by other threads. Here's the code for the standard Tkinter GUI toolkit that comes with Python: import Tkinter, time, threading, random, Queue
class GuiPart(object):
def _ _init_ _(self, master, queue, endCommand):
self.queue = queue
# Set up the GUI
Tkinter.Button(master, text='Done', command=endCommand).pack( )
# Add more GUI stuff here depending on your specific needs
def processIncoming(self):
""" Handle all messages currently in the queue, if any. """
while self.queue.qsize( ):
try:
msg = self.queue.get(0)
# Check contents of message and do whatever is needed. As a
# simple example, let's print it (in real life, you would
# suitably update the GUI's display in a richer fashion).
print msg
except Queue.Empty:
# just on general principles, although we don't expect this
# branch to be taken in this case, ignore this exception!
pass
class ThreadedClient(object):
"""
Launch the "main" part of the GUI and the worker thread. periodicCall and
endApplication could reside in the GUI part, but putting them here
means that you have all the thread controls in a single place.
"""
def _ _init_ _(self, master):
"""
Start the GUI and the asynchronous threads. We are in the "main"
(original) thread of the application, which will later be used by
the GUI as well. We spawn a new thread for the worker (I/O).
"""
self.master = master
# Create the queue
self.queue = Queue.Queue( )
# Set up the GUI part
self.gui = GuiPart(master, self.queue, self.endApplication)
# Set up the thread to do asynchronous I/O
# More threads can also be created and used, if necessary
self.running = True
self.thread1 = threading.Thread(target=self.workerThread1)
self.thread1.start( )
# Start the periodic call in the GUI to check the queue
self.periodicCall( )
def periodicCall(self):
""" Check every 200 ms if there is something new in the queue. """
self.master.after(200, self.periodicCall)
self.gui.processIncoming( )
if not self.running:
# This is the brutal stop of the system. You may want to do
# some cleanup before actually shutting it down.
import sys
sys.exit(1)
def workerThread1(self):
"""
This is where we handle the asynchronous I/O. For example, it may be
a 'select( )'. One important thing to remember is that the thread has
to yield control pretty regularly, be it by select or otherwise.
"""
while self.running:
# To simulate asynchronous I/O, create a random number at random
# intervals. Replace the following two lines with the real thing.
time.sleep(rand.random( ) * 1.5)
msg = rand.random( )
self.queue.put(msg)
def endApplication(self):
self.running = False
rand = random.Random( )
root = Tkinter.Tk( )
client = ThreadedClient(root)
root.mainloop( ) DiscussionThis recipe demonstrates the easiest way of handling access to sockets, serial ports, and other asynchronous I/O ports while running a Tkinter-based GUI. The recipe's principles generalize to other GUI toolkits, since most toolkits make it preferable to access the GUI itself from a single thread, and all offer a toolkit-dependent way to set up periodic polling as this recipe does. Tkinter, like most other GUIs, is best used with all graphic commands in a single thread. On the other hand, it's far more efficient to make I/O channels block, then wait for something to happen, rather than using nonblocking I/O and having to poll at regular intervals. The latter approach may not even be available in some cases, since not all data sources support nonblocking I/O. Therefore, for generality as well as for efficiency, we should handle I/O with a separate thread, or more than one. The I/O threads can communicate in a safe way with the "main", GUI-handling thread through one or more Queues. In this recipe, the GUI thread still has to do some polling (on the Queues), to check whether something in the Queue needs to be processed. Other architectures are possible, but they are much more complex than the one in this recipe. My advice is to start with this recipe, which will handle your needs over 90% of the time, and explore the much more complex alternatives only if it turns out that this approach cannot meet your performance requirements. This recipe lets a worker thread block in a select (simulated by random sleeps in the recipe's example worker thread). Whenever something arrives, it is received and inserted in a Queue instance. The main (GUI) thread polls the Queue five times per second and processes all messages that have arrived since it last checked. (Polling 5 times per second is frequent enough that the end user will not notice any significant delay but infrequent enough that the computational load on the computer will be negligible.) You may want to fine-tune this feature, depending on your needs. This recipe solves a common problem that is frequently asked about on Python mailing lists and newsgroups. Other solutions, involving synchronization between threads, help you solve such problems without polling (the self.master.after call in the recipe). Unfortunately, such solutions are generally complicated and messy, since you tend to raise and wait for semaphores throughout your code. In any case, a GUI already has several polling mechanisms built into it (the "main" event loop), so adding one more won't make much difference, especially since it seldom runs. The code has been tested in depth only under Linux, but it should work on any platform with working threads, including Windows. Here is a PyQt equivalent, with very minor variations: import sys, time, threading, random, Queue, qt class GuiPart(qt.QMainWindow): def _ _init_ _(self, queue, endcommand, *args): qt.QMainWindow._ _init_ _(self, *args) self.queue = queue # We show the result of the thread in the gui, instead of the console self.editor = qt.QMultiLineEdit(self) self.setCentralWidget(self.editor) self.endcommand = endcommand def closeEvent(self, ev): """ We just call the endcommand when the window is closed, instead of presenting a button for that purpose. """ self.endcommand( ) def processIncoming(self): """ Handle all the messages currently in the queue (if any). """ while self.queue.qsize( ): try: msg = self.queue.get(0) self.editor.insertLine(str(msg)) except Queue.Empty: pass class ThreadedClient(object): """ Launch the "main" part of the GUI and the worker thread. periodicCall and endApplication could reside in the GUI part, but putting them here means that you have all the thread controls in a single place. """ def _ _init_ _(self): # Create the queue self.queue = Queue.Queue( ) # Set up the GUI part self.gui = GuiPart(self.queue, self.endApplication) self.gui.show( ) # A timer to periodically call periodicCall self.timer = qt.QTimer( ) qt.QObject.connect(self.timer, qt.SIGNAL("timeout( )"), self.periodicCall) # Start the timer -- this replaces the initial call to periodicCall self.timer.start(200) # Set up the thread to do asynchronous I/O # More can be made if necessary self.running = True self.thread1 = threading.Thread(target=self.workerThread1) self.thread1.start( ) def periodicCall(self): """ Check every 200 ms if there is something new in the queue. """ self.gui.processIncoming( ) if not self.running: root.quit( ) def endApplication(self): self.running = False def workerThread1(self): """ This is where we handle the asynchronous I/O. For example, it may be a 'select( )'. An important thing to remember is that the thread has to yield control once in a while. """ while self.running: # To simulate asynchronous I/O, we create a random number at # random intervals. Replace the following 2 lines with the real # thing. time.sleep(rand.random( ) * 0.3) msg = rand.random( ) self.queue.put(msg) rand = random.Random( ) root = qt.QApplication(sys.argv) client = ThreadedClient( ) root.exec_loop( ) As you can see, this PyQt variation has a structure that's uncannily similar to the Tkinter version, with just a few variations (and a few enhancements, such as using QApplication.quit instead of the more brutal sys.exit, and displaying the thread's result in the GUI itself rather than on the console). See AlsoDocumentation of the standard library modules threading and Queue in the Library Reference and Python in a Nutshell; information about Tkinter can be obtained from a variety of sources, such as Fredrik Lundh, An Introduction to Tkinter (Pythonware: http://www.pythonware.com/library), New Mexico Tech's Tkinter Reference (http://www.nmt.edu/tcc/help/lang/python/docs.html), Python in a Nutshell, and various other books; information about PyQt can be found at PyQt's own web site, http://www.riverbankcomputing.co.uk/pyqt/index.php. |


| 931 | (A) | and sayde semliche the knyghode of Rome |
| 938 | (C) | They seyde comely kynge . þe knyȝthode of rome |
| 924 | (D) | And seyn Comely kyng þe knygħthood of rome |
| 901 | (E) | ¶ & seyden comlich kyng . þe knyȝthod of rome |
| (Ex) | ---- no text ---- | |
| 956 | (L) | sayn comelich kyng þe knyȝthod of rome |
| 874 | (P) | Sayde comly kynge þe knyghthede of Rome |
| 911 | (U) | ¶ Seying comely kyng / the knyghthode of Rome |
| (V) | ---- no text ---- |


review_requested
by Francis Kayiwa at 2023-05-09 18:52:52.referenced
by Vickie Karasic at 2023-05-10 00:54:46.merged
by Vickie Karasic at 2023-05-10 00:54:46.closed
by Vickie Karasic at 2023-05-10 00:54:46.HM needs to provide a stable IP for Francis to put on the allow list
closed
by None at 2023-05-09 18:51:30.closed
by None at 2023-05-09 18:51:35.labeled
by Kevin Reiss at 2023-05-09 20:50:02.labeled
by Kevin Reiss at 2023-05-09 21:53:26.referenced
by esmé cowles at 2023-05-09 12:32:01.merged
by esmé cowles at 2023-05-09 12:32:01.closed
by esmé cowles at 2023-05-09 12:32:01.head_ref_deleted
by esmé cowles at 2023-05-09 12:32:04.Closed with #55
closed
by esmé cowles at 2023-05-09 12:33:31.review_requested
by Francis Kayiwa at 2023-05-09 14:04:21.mentioned
by Bess Sadler at 2023-05-09 08:36:55.subscribed
by Bess Sadler at 2023-05-09 08:36:55.referenced
by Jane Sandberg at 2023-05-09 12:47:05.merged
by Jane Sandberg at 2023-05-09 12:47:05.closed
by Jane Sandberg at 2023-05-09 12:47:05.head_ref_deleted
by Jane Sandberg at 2023-05-09 12:47:06.closed
by James R. Griffin III at 2023-05-09 13:26:52.https://github.com/pulibrary/princeton_ansible/pull/3873/files did not resolve this issue, I am still struggling to diagnose this, and shall proceed with this as an urgent priority.
I have been able to isolate the bitstreams for this Item with the following:
dataspace_prod_db=> select bit.bitstream_id,bit.internal_id from bitstream as bit inner join bundle2bitstream as b2b on bit.bitstream_id=b2b.bitstream_id inner join bundle as bun on bun.bundle_id=b2b.bundle_id inner join item2bundle as i2b on bun.bundle_id=i2b.bundle_id where i2b.item_id=28854;
bitstream_id | internal_id
--------------+-----------------------------------------
39149 |<PHONE_NUMBER>29412055520366204091862923761
137193 |<PHONE_NUMBER>3505381792192318745048114491
(2 rows)
This is the affected file, I am not quite certain why this is proving to be problematic:
dspace@gcp-dataspace-prod1:~$ file /mnt/disks/dataspaceproddatastore/prod-copy/assetstore_production/29/17/65/29176517213505381792192318745048114491
/mnt/disks/dataspaceproddatastore/prod-copy/assetstore_production/29/17/65/29176517213505381792192318745048114491: PDF document, version 1.4
dspace@gcp-dataspace-prod1:~$ stat /mnt/disks/dataspaceproddatastore/prod-copy/assetstore_production/29/17/65/29176517213505381792192318745048114491
File: /mnt/disks/dataspaceproddatastore/prod-copy/assetstore_production/29/17/65/29176517213505381792192318745048114491
Size: 61220117 Blocks: 119576 IO Block: 4096 regular file
Device: 810h/2064d Inode: 51511900 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 1005/ dspace) Gid: ( 1005/ dspace)
Access: 2023-05-09 09:40:33.332799458 -0400
Modify: 2019-08-27 08:46:55.665441000 -0400
Change: 2021-09-20 15:43:28.020223109 -0400
Birth: -
Observing the URL structure, it may be the case that this is actually related to some inconsistency in resolving bitstream file names to bitstream binaries during requests for downloads. Please note that, during download attempts, %2c_
is encoded into ,_
:
Joe no longer needs an account at this time. Should we need to create a new user, we will need to open a support ticket with the vendor.
assigned
by Kate Lynch at 2023-05-09 15:25:21.labeled
by Kate Lynch at 2023-05-09 15:25:27.closed
by Kate Lynch at 2023-05-09 15:31:55.closed
by Bess Sadler at 2023-05-09 16:44:06.It looks like this was already completed per a request from Lynn about 6 months ago (https://github.com/pulibrary/etd_transformer/pull/141/files)? The metadata for the older ones would still be in DataSpace but it looks like we're not adding that message in anymore (see a more recently-imported dissertation example here - https://dataspace.princeton.edu/handle/88435/dsp01vm40xv82h?mode=full).
assigned
by Kate Lynch at 2023-05-09 20:39:00.closed
by Bess Sadler at 2023-05-09 21:14:33.Images are added after, at the very least, the MVP metadata. Do we have variations of preservation for specific things? ex: we would have local fixity on in process stuff and do the full preservation once complete? i.e. keep it from the cloud until completion? Is that silly?
review_dismissed
by Eliot Jordan at 2023-05-09 15:34:50.head_ref_force_pushed
by Eliot Jordan at 2023-05-09 15:35:10.deployed
by None at 2023-05-09 15:37:46.deployed
by None at 2023-05-09 17:14:25.head_ref_force_pushed
by Eliot Jordan at 2023-05-09 17:43:57.deployed
by None at 2023-05-09 19:18:33.deployed
by None at 2023-05-09 20:26:01.renamed
by Kevin Reiss at 2023-05-09 21:41:05.referenced
by None at 2023-05-09 16:25:27.merged
by None at 2023-05-09 16:25:27.closed
by None at 2023-05-09 16:25:27.head_ref_deleted
by None at 2023-05-09 16:25:28.Coverage: 95.215% (-0.03%) from 95.249% when pulling 993e2228587ffc7753d9845a96c0742a272be30f on dry-openurl-behavior into 5862a638b8245c811271ddab58c7158473ab9115 on main.
head_ref_force_pushed
by Jane Sandberg at 2023-05-09 22:19:38.deployed
by None at 2023-05-09 13:02:20.referenced
by Hector Correa at 2023-05-09 13:04:55.merged
by Hector Correa at 2023-05-09 13:04:56.closed
by Hector Correa at 2023-05-09 13:04:56.head_ref_deleted
by Hector Correa at 2023-05-09 13:04:57.@hectorcorrea my open PR already addresses this issue Could we just merge that and close the issue? https://github.com/pulibrary/pdc_describe/pull/1125
Addressed in https://github.com/pulibrary/pdc_describe/pull/1125
mentioned
by Hector Correa at 2023-05-09 12:23:38.subscribed
by Hector Correa at 2023-05-09 12:23:38.mentioned
by Hector Correa at 2023-05-09 12:48:32.subscribed
by Hector Correa at 2023-05-09 12:48:32.closed
by Hector Correa at 2023-05-09 13:05:33.Fixed with https://github.com/pulibrary/pdc_describe/pull/1125
closed
by Hector Correa at 2023-05-09 13:06:12.review_requested
by Hector Correa at 2023-05-09 13:03:37.referenced
by None at 2023-05-09 13:17:17.merged
by None at 2023-05-09 13:17:17.closed
by None at 2023-05-09 13:17:17.head_ref_deleted
by None at 2023-05-09 13:17:18.convert_to_draft
by James R. Griffin III at 2023-05-09 14:20:17.Closing in favor of https://github.com/pulibrary/pdc_describe/issues/1135
closed
by Kate Lynch at 2023-05-09 15:02:39.labeled
by Kate Lynch at 2023-05-09 15:02:48.@jrgriffiniii Looks good to me, but it's failing CI at the moment. :(
head_ref_force_pushed
by James R. Griffin III at 2023-05-09 13:28:44.mentioned
by James R. Griffin III at 2023-05-09 16:23:46.subscribed
by James R. Griffin III at 2023-05-09 16:23:46.referenced
by Bess Sadler at 2023-05-09 18:28:15.merged
by Bess Sadler at 2023-05-09 18:28:15.closed
by Bess Sadler at 2023-05-09 18:28:15.head_ref_deleted
by Bess Sadler at 2023-05-09 18:28:16.closed
by Bess Sadler at 2023-05-09 18:28:16.review_dismissed
by Bess Sadler at 2023-05-09 18:45:42.referenced
by Bess Sadler at 2023-05-09 18:52:08.merged
by Bess Sadler at 2023-05-09 18:52:09.closed
by Bess Sadler at 2023-05-09 18:52:09.head_ref_deleted
by Bess Sadler at 2023-05-09 18:52:10.assigned
by Kate Lynch at 2023-05-09 14:30:26.labeled
by Kate Lynch at 2023-05-09 14:30:34.closed
by Bess Sadler at 2023-05-09 18:52:10.assigned
by James R. Griffin III at 2023-05-09 20:37:28.assigned
by Bess Sadler at 2023-05-09 21:15:21.referenced
by Francis Kayiwa at 2023-05-09 13:01:26.merged
by Francis Kayiwa at 2023-05-09 13:01:26.closed
by Francis Kayiwa at 2023-05-09 13:01:26.head_ref_deleted
by Francis Kayiwa at 2023-05-09 13:01:27.closed
by Francis Kayiwa at 2023-05-09 13:01:55.review_requested
by Francis Kayiwa at 2023-05-09 13:07:52.review_requested
by Francis Kayiwa at 2023-05-09 13:20:23.the modules will not allow some of the IAM commands to run successfully.
closed
by Francis Kayiwa at 2023-05-09 13:28:30.added CPU monitoring on sensu
referenced
by Jane Sandberg at 2023-05-09 14:26:06.merged
by Jane Sandberg at 2023-05-09 14:26:06.closed
by Jane Sandberg at 2023-05-09 14:26:06.head_ref_deleted
by Jane Sandberg at 2023-05-09 14:26:07.closed
by Jane Sandberg at 2023-05-09 14:26:08.referenced
by Jane Sandberg at 2023-05-09 14:26:08.referenced
by Francis Kayiwa at 2023-05-09 14:32:47.review_requested
by Francis Kayiwa at 2023-05-09 14:33:04.Follow this permalink to see the old vsphere_init
role in the infra
repo.
referenced
by Alicia Cozine at 2023-05-09 15:47:05.merged
by Alicia Cozine at 2023-05-09 15:47:05.closed
by Alicia Cozine at 2023-05-09 15:47:05.head_ref_deleted
by Alicia Cozine at 2023-05-09 15:47:06.ready_for_review
by Alicia Cozine at 2023-05-09 14:10:34.review_requested
by Francis Kayiwa at 2023-05-09 13:26:59.referenced
by Jane Sandberg at 2023-05-09 18:15:53.merged
by Jane Sandberg at 2023-05-09 18:15:53.closed
by Jane Sandberg at 2023-05-09 18:15:53.head_ref_deleted
by Jane Sandberg at 2023-05-09 18:15:54.referenced
by Francis Kayiwa at 2023-05-09 13:26:35.closed
by Jane Sandberg at 2023-05-09 18:15:54.referenced
by Jane Sandberg at 2023-05-09 18:15:55.As a first step, today we powered the appdeploy1
VM down. We are waiting to see if this causes problems. We also archived the heaven
and pulbot
repos today.
Our plan is to do the final cleanup and delete the VM at all-hands.
renamed
by Kevin Reiss at 2023-05-09 21:37:50.labeled
by Kevin Reiss at 2023-05-09 21:53:25.referenced
by None at 2023-05-09 16:22:17.merged
by None at 2023-05-09 16:22:17.closed
by None at 2023-05-09 16:22:17.head_ref_deleted
by None at 2023-05-09 16:22:18.closed
by James R. Griffin III at 2023-05-09 14:05:24.renamed
by Kevin Reiss at 2023-05-09 21:41:24.closed
by Kevin Reiss at 2023-05-09 21:40:42.renamed
by Kevin Reiss at 2023-05-09 21:41:42.renamed
by Kevin Reiss at 2023-05-09 21:42:25.labeled
by Kevin Reiss at 2023-05-09 21:53:26.


---
layout: post
title: Just to keep in mind...
date: '2009-09-21T16:26:00.000-04:00'
author: RyGuy
tags:
modified_time: '2010-06-16T12:58:11.083-04:00'
blogger_id: tag:blogger.com,1999:blog-2767138550438691941.post-7578184778331675306
blogger_orig_url: https://muchtoilingant.blogspot.com/2009/09/just-to-keep-in-mind.html
---
When he was in his twenties, [Miguel Mihura] wrote his best known comedy, Tres sombreros de copa, but its humour was not appreciated by the conservative pre-war Spanish society. Tres sombreros de copa was not staged until 1952, achieving a great success.
cf. Stravinsky's Rite of Spring, others, and Ray's instructive query into the criteria of truth with respect to one's artistic decisions, and his response that the audience has a major role.
also think of poems of canonical poets not yet canonical. It's a precarious situation...


Jim Fulton, Digital Creations, Inc<EMAIL_ADDRESS>Copyright (C) 1996-1998, Digital Creations.
A lightweight mechanism has been developed for making Python extension types more class-like. Classes can be developed in an extension language, such as C or C++, and these classes can be treated like other python classes:
They can be sub-classed in python,
They provide access to method documentation strings, and
They can be used to directly create new instances.
An example class shows how extension classes are implemented and how they differ from extension types.
Extension classes provide additional extensions to class and instance semantics, including:
A protocol for accessing subobjects "in the context of" their containers. This is used to implement custom method types and environmental acquisition.
A protocol for overriding method call semantics. This is used to implement "synchonized" classes and could be used to implement argument type checking.
A protocol for class initialization that supports execution of a
special __class_init__
method after a class has been
initialized.
Extension classes illustrate how the Python class mechanism can be extended and may provide a basis for improved or specialized class models.
To find out what's changed in this release, see the release notes.
Currently, Python provides two ways of defining new kinds of objects:
Python classes
Extension types
Each approach has it's strengths. Extension types provide much greater control to the programmer and, generally, better performance. Because extension types are written in C, the programmer has greater access to external resources. (Note that Python's use of the term type has little to do with the notion of type as a formal specification.)
Classes provide a higher level of abstraction and are generally much easier to develop. Classes provide full inheritance support, while support for inheritance when developing extension types is very limited. Classes provide run-time meta-data, such as method documentation strings, that are useful for documentation and discovery. Classes act as factories for creating instances, while separate functions must be provided to create instances of types.
It would be useful to combine the features of the two approaches. It would be useful to be able to have better support for inheritance for types, or to be able to subclass from types in Python. It would be useful to be able to have class-like meta-data support for types and the ability to construct instances directly from types.
Our software is developed in Python. When necessary, we convert debugged Python routines and classes to C for improved performance. In most cases, a small number of methods in a class is responsible for most of the computation. It should be possible to convert only these methods to C, while leaving the other method in Python. A natural way to approach this is to create a base class in C that contains only the performance-critical aspects of a class' implementation and mix this base class into a Python class.
We have need, in a number of projects, for semantics that are
slightly different than the usual class and instance semantics,
yet we don't want to do most of our development in C. For
example, we have developed a persistence mechanism [1] that
redefines __getattr__
and __setattr__
to take storage-related
actions when object state is accessed or modified. We want to be
able to take certain actions on every attribute reference, but
for python class instances, __getattr__
is only called when
attribute lookup fails by normal means.
As another example, we would like to have greater control over how methods are bound. Currently, when accessing a class instance attribute, the attribute value is bound together with the instance in a method object if and only if the attribute value is a python function. For some applications, we might also want to be able to bind extension functions, or other types of callable objects, such as HTML document templates [2]. Furthermore, we might want to have greater control over how objects are bound. For example, we might want to bind instances and callable objects with special method objects that assure that no more than one thread accesses the object or method at one time.
We can provide these special semantics in extension types, but we wish to provide them for classes developed in Python.
At the first Python Workshop, Don Beaudry presented work [3] done at V.I. Corp to integrate Python with C++ frameworks. This system provided a number of important features, including:
Definition of extension types that provide class-like meta-data and that can be called to create instances.
Ability to subclass in python from C types.
Ability to define classes in python who's data are stored as C structures rather than in dictionaries to better interface to C and C++ libraries, and for better performance.
Less dynamic data structures. In particular, the data structure for a class is declared during class definition.
Support for enumeration types.
This work was not released, initially.
Shortly after the workshop, changes were made to Python to support the sub-classing features described in [3]. These changes were not documented until the fourth Python Workshop [4].
At the third Python workshop, I presented some work I had done on generating module documentation for extension types. Based on the discussion at this workshop, I developed a meta-type proposal [5]. This meta-type proposal was for an object that simply stored meta-information for a type, for the purpose of generating module documentation.
In the summer of 1996, Don Beaudry released the system described in [3] under the name MESS [6]. MESS addresses a number of needs but has a few drawbacks:
Only single inheritance is supported.
The mechanisms for defining MESS extension types is very different from and more complicated than the standard Python type creation mechanism.
Defining MESS types requires the use of an extensive C applications programming interface. This presents problems for configuring dynamically-loaded extension modules unless the MESS library is linked into the Python interpreter.
Because the system tries to do a number of different things, it is fairly large, about 15,000 lines.
There is very little documentation, especially for the C programming interface.
The system is a work in progress, with a number of outstanding bugs.
As MESS matures, we expect most of these problems to be addressed.
To meet short term needs for a C-based persistence mechanism [1], an extension class module was developed using the mechanism described in [4] and building on ideas from MESS [6]. The extension class module recasts extension types as "extension classes" by seeking to eliminate, or at least reduce semantic differences between types and classes. The module was designed to meet the following goal:
Provide class-like behavior for extension types, including interfaces for meta information and for constructing instances.
Support sub-classing in Python from extension classes, with support for multiple inheritance.
Provide a small hardened implementation that can be used for current products.
Provide a mechanism that requires minimal modification to existing extension types.
Provide a basis for research on alternative semantics for classes and inheritance.
Note: I use non-standard terminology here. By standard python terminology, only standard python classes can be called classes. ExtensionClass "classes" are technically just "types" that happen to swim, walk and quack like python classes.
Base extension classes are implemented in C. Extension subclasses are implemented in Python and inherit, directly or indirectly from one or more base extension classes. An extension subclass may inherit from base extension classes, extension subclasses, and ordinary python classes. The usual inheritance order rules apply. Currently, extension subclasses must conform to the following two rules:
The first super class listed in the class statement defining an extension subclass must be either a base extension class or an extension subclass. This restriction will be removed in Python-1.5.
At most one base extension direct or indirect super class may define C data members. If an extension subclass inherits from multiple base extension classes, then all but one must be mix-in classes that provide extension methods but no data.
Like standard python classes, extension classes have the following attributes containing meta-data:
__doc__
a documentation string for the class,
__name__
the class name,
__bases__
a sequence of base classes,
__dict__
a class dictionary, and
__module__
the name of the module in which the class was defined.
The class dictionary provides access to unbound methods and their documentation strings, including extension methods and special methods, such as methods that implement sequence and numeric protocols. Unbound methods can be called with instance first arguments.
Extension subclass instances have instance dictionaries, just like Python class instances do. When fetching attribute values, extension class instances will first try to obtain data from the base extension class data structure, then from the instance dictionary, then from the class dictionary, and finally from base classes. When setting attributes, extension classes first attempt to use extension base class attribute setting operations, and if these fail, then data are placed in the instance dictionary.
A base extension class is implemented in much the same way that an extension type is implemented, except:
The include file, ExtensionClass.h
, must be included.
The type structure is declared to be of type PyExtensionClass
, rather
than of type PyTypeObject
.
The type structure has an additional member that must be defined
after the documentation string. This extra member is a method chain
(PyMethodChain
) containing a linked list of method definition
(PyMethodDef
) lists. Method chains can be used to implement
method inheritance in C. Most extensions don't use method chains,
but simply define method lists, which are null-terminated arrays
of method definitions. A macro, METHOD_CHAIN
is defined in
ExtensionClass.h
that converts a method list to a method chain.
(See the example below.)
Module functions that create new instances must be replaced by
__init__
methods that initialize, but does not create storage for
instances.
The extension class must be initialized and exported to the module with::
PyExtensionClass_Export(d,"name",type); where 'name' is the module name and 'type' is the extension class type object.
Attribute lookup is performed by calling the base extension class
getattr
operation for the base extension class that includes C
data, or for the first base extension class, if none of the base
extension classes include C data. ExtensionClass.h
defines a
macro Py_FindAttrString
that can be used to find an object's
attributes that are stored in the object's instance dictionary or
in the object's class or base classes:
v = Py_FindAttrString(self,name);
where name
is a C string containing the attribute name.
In addition, a macro is provided that replaces Py_FindMethod
calls with logic to perform the same sort of lookup that is
provided by Py_FindAttrString
.
If an attribute name is contained in a Python string object,
rather than a C string object, then the macro Py_FindAttr
should
be used to look up an attribute value.
The extension class mechanism was designed to be useful with
dynamically linked extension modules. Modules that implement
extension classes do not have to be linked against an extension
class library. The macro PyExtensionClass_Export
imports the
ExtensionClass
module and uses objects imported from this module
to initialize an extension class with necessary behavior.
An example is provided that illustrates the changes needed to convert an existing type to an ExtensionClass.
Some care should be taken when implementing or overriding base
class constructors. When a Python class overrides a base class
constructor and fails to call the base class constructor, a
program using the class may fail, but it will not crash the
interpreter. On the other hand, an extension subclass that
overrides a constructor in an extension base class must call the
extension base class constructor or risk crashing the interpreter.
This is because the base class constructor may set C pointers that,
if not set properly, will cause the interpreter to crash when
accessed. This is the case with the MultiMapping
extension base
class shown in the example above.
If no base class constructor is provided, extension class instance memory will be initialized to 0. It is a good idea to design extension base classes so that instance methods check for uninitialized memory and perform initialialization if necessary. This was not done above to simplify the example.
A problem occurs when trying to overide methods inherited from Python base classes. Consider the following example:
from ExtensionClass import Base class Spam: def __init__(self, name): self.name=name class ECSpam(Base, Spam): def __init__(self, name, favorite_color): Spam.__init__(self,name) self.favorite_color=favorite_color
This implementation will fail when an ECSpam
object is
instantiated. The problem is that ECSpam.__init__
calls
Spam.__init__
, and Spam.__init__
can only be called with a
Python instance (an object of type "instance"
) as the first
argument. The first argument passed to Spam.__init__
will be an
ECSpam
instance (an object of type ECSPam
).
To overcome this problem, extension classes provide a class method
inheritedAttribute
that can be used to obtain an inherited
attribute that is suitable for calling with an extension class
instance. Using the inheritedAttribute
method, the above
example can be rewritten as:
from ExtensionClass import Base class Spam: def __init__(self, name): self.name=name class ECSpam(Base, Spam): def __init__(self, name, favorite_color): ECSpam.inheritedAttribute('__init__')(self,name) self.favorite_color=favorite_color
This isn't as pretty but does provide the desired result.
It is sometimes useful to be able to wrap up an object together with a containing object. I call this "context wrapping" because an object is accessed in the context of the object it is accessed through.
We have found many applications for this, including:
User-defined method objects,
Acquisition and
Computed attributes
Python classes wrap Python function attributes into methods. When a class has a function attribute that is accessed as an instance attribute, a method object is created and returned that contains references to the original function and instance. When the method is called, the original function is called with the instance as the first argument followed by any arguments passed to the method.
Extension classes provide a similar mechanism for attributes that
are Python functions or inherited extension functions. In
addition, if an extension class attribute is an instance of an
extension class that defines an __of__
method, then when the
attribute is accessed through an instance, it's __of__
method
will be called to create a bound method.
Consider the following example:
import ExtensionClass class CustomMethod(ExtensionClass.Base): def __call__(self,ob): print 'a %s was called' % ob.__class__.__name__ class wrapper: def __init__(self,m,o): self.meth, self.ob=m,o def __call__(self): self.meth(self.ob) def __of__(self,o): return self.wrapper(self,o) class bar(ExtensionClass.Base): hi=CustomMethod() x=bar() hi=x.hi()
Note that ExtensionClass.Base
is a base extension class that
provides very basic ExtensionClass behavior.
When run, this program outputs: a bar was called
.
It is not uncommon to wish to expose information via the
attribute interface without affecting implementation data
structures. One can use a custom __getattr__
method to
implement computed attributes, however, this can be a bit
cumbersome and can interfere with other uses of __getattr__
,
such as for persistence.
The __of__
protocol provides a convenient way to implement
computed attributes. First, we define a ComputedAttribute
class. a ComputedAttribute is constructed with a function to
be used to compute an attribute, and calls the function when
it's __of__
method is called:
import ExtensionClass
class ComputedAttribute(ExtensionClass.Base):
def __init__(self, func): self.func=func
def __of__(self, parent): return self.func(parent)
Then we can use this class to create computed attributes. In the
example below, we create a computed attribute, radius
:
from math import sqrt
class Point(ExtensionClass.Base):
def __init__(self, x, y): self.x, self.y = x, y
radius=ComputedAttribute(lambda self: sqrt(self.x**2+self.y**2))
which we can use just like an ordinary attribute:
p=Point(2,2) print p.radius
Normally, when a method is called, the function wrapped by the
method is called directly by the method. In some cases, it is
useful for user-defined logic to participate in the actual
function call. Extension classes introduce a new protocol that
provides extension classes greater control over how their
methods are called. If an extension class defines a special
method, __call_method__
, then this method will be called to
call the functions (or other callable object) wrapped by the
method. The method. __call_method__
should provide the same
interface as provided by the Python builtin apply
function.
For example, consider the expression: x.meth(arg1, arg2)
. The
expression is evaluated by first computing a method object that
wraps x
and the attribute of x
stored under the name meth
.
Assuming that x
has a __call_method__
method defined, then
the __call_method__
method of x
will be called with two
arguments, the attribute of x
stored under the name meth
,
and a tuple containing x
, arg1
, and arg2
.
To see how this feature may be used, see the Python module,
Syn.py
, which is included in the ExtensionClass distribution.
This module provides a mix-in class that provides Java-like
"synchonized" classes that limit access to their methods to one
thread at a time.
An interesting application of this mechanism would be to implement interface checking on method calls.
Methods of ExtensionClass instances can have user-defined attributes, which are stored in their associated instances.
For example:
class C(ExtensionClass.Base): def f(self): "Get a secret" .... c=C() c.f.__roles__=['Trusted People'] print c.f.__roles__ # outputs ['Trusted People'] print c.f__roles__ # outputs ['Trusted People'] print C.f.__roles__ # fails, unbound method
A bound method attribute is set by setting an attribute in it's
instance with a name consisting of the concatination of the
method's __name__
attribute and the attribute name.
Attributes cannot be set on unbound methods.
Normal Python class initialization is similar to but subtley
different from instance initialization. An instance __init__
function is called on an instance immediately after it is
created. An instance __init__
function can use instance
information, like it's class and can pass the instance to other
functions. On the other hand, the code in class statements is
executed immediately before the class is created. This means
that the code in a class statement cannot use class attributes,
like __bases__
, or pass the class to functions.
Extension classes provide a mechanism for specifying code to be
run after a class has been created. If a class or one of it's
base classes defines a __class_init__
method, then this method
will be called just after a class has been created. The one
argument passed to the method will be the class, not an
instance of the class.
A number of useful macros are defined in ExtensionClass.h.
These are documented in ExtensionClass.h
.
Classes created with ExtensionClass, including extension base
classes are automatically pickleable. The usual gymnastics
necessary to pickle non-standard
types are not necessray for
types that have been modified to be extension base classes.
The current release of the extension class module is 1.1. The core implementation has less than four thousand lines of code, including comments. This release requires Python 1.4 or higher.
To find out what's changed in this release, see the release notes.
Installation instructions are provided.
There are a number of issues that came up in the course of this work and that deserve mention.
In Python 1.4, the class extension mechanism described in [4] required
that the first superclass in a list of super-classes must be of the
extended class type. This may not be convenient if mix-in
behavior is desired. If a list of base classes starts with a
standard python class, but includes an extension class, then an
error was raised. It would be more useful if, when a list of base
classes contains one or more objects that are not python classes,
the first such object was used to control the extended class
definition. To get around this, the ExtensionClass
module exports
a base extension class, Base
, that can be used as the first base
class in a list of base classes to assure that an extension
subclass is created.
Python 1.5 allows the class extension even if the first non-class object in the list of base classes is not the first object in the list. This issue appears to go away in Python 1.5, however, the restriction that the first non-class object in a list of base classes must be the first in the list may reappear in later versions of Python.
Currently, only one base extension class can define any data in C. The data layout of subclasses-instances is the same as for the base class that defines data in C, except that the data structure is extended to hold an instance dictionary. The data structure begins with a standard python header, and extension methods expect the C instance data to occur immediately after the object header. If two or more base classes defined C data, the methods for the different base classes would expect their data to be in the same location. A solution might be to allocate base class instances and store pointers to these instances in the subclass data structure. The method binding mechanism would have to be a more complicated to make sure that methods were bound to the correct base data structure. Alternatively, the signature of C methods could be expanded to allow pointers to expected class data to be passed in addition to object pointers.
There is currently no support for sub-classing in C, beyond that provided by method chains.
Rules for mixed-type arithmetic are different for python class instances than they are for extension type instances. Python classes can define right and left versions of numeric binary operators, or they can define a coercion operator for converting binary operator operands to a common type. For extension types, only the latter, coercion-based, approach is supported. The coercion-based approach does not work well for many data types for which coercion rules depend on the operator. Because extension classes are based on extension types, they are currently limited to the coercion-based approach. It should be possible to extend the extension class implementation to allow both types of mixed-type arithmetic control.
I considered making extension classes immutable, meaning that class attributes could not be set after class creation. I also considered making extension subclasses cache inherited attributes. Both of these are related and attractive for some applications, however, I decided that it would be better to retain standard class instance semantics and provide these features as options at a later time.
The extension class module defines new method types to bind C and python methods to extension class instances. It would be useful for these method objects to provide access to function call information, such as the number and names of arguments and the number of defaults, by parsing extension function documentation strings.
Aside from test and demonstration applications, the extension class mechanism has been used to provide an extension-based implementation of the persistence mechanism described in [1]. We have developed this further to provide features such as automatic deactivation of objects not used after some period of time and to provide more efficient persistent-object cache management.
Acquisition has been heavily used in our recent products. Synchonized classes have also been used in recent products.
The extension-class mechanism described here provides a way to add class services to extension types. It allows:
Sub-classing extension classes in Python,
Construction of extension class instances by calling extension classes,
Extension classes to provide meta-data, such as unbound methods and their documentation string.
In addition, the extension class module provides a relatively concise example of the use of mechanisms that were added to Python to support MESS [6], and that were described at the fourth Python Workshop [4]. It is hoped that this will spur research in improved and specialized models for class implementation in Python.
References
[1] Fulton, J., Providing Persistence for World-Wide-Web Applications Proceedings of the 5th Python Workshop.
[2] Page, R. and Cropper, S., Document Template Proceedings of the 5th Python Workshop.
[3] Beaudry, D., Deriving Built-In Classes in Python Proceedings of the First International Python Workshop.
[4] Van Rossum, G., Don Beaudry Hack - MESS presented in the Developer's Future Enhancements session of the 4th Python Workshop.
[5] Fulton, J., Meta-Type Object This is a small proposal, the text of which is contained in a sample implementation source file,
[6] Beaudry, D., and Ascher, D., The Meta-Extension Set.


Admin Prototype
Administrator Tasks
-
New Homepage Design
Mafe Ponce
06/26/2020
3:30pm
-
User Tasks Design
Leonard Zhang
06/26/2020
3:30pm
-
Admin Console Design
Denzil Ekow Bilson
06/26/2020
3:30pm
-
User Authentication
Mafe Ponce
06/30/2020
4:00pm
-
404 Page Design
Denzil Bilson
06/30/2020
4:00pm
-
Upload Tasks
Leonard Zhang
06/30/2020
4:00pm


Private Over Public
Description: Most of the participants from the focus group expressed their preference to go to private clinics over free clinics, however costs were a major obstacle. The free clinics were perceived as lower quality.
Comments: - 'We receive the services from the Emirati hospital and other places.'
- 'They suffer from long waiting times because of the pressure on the Emirati Hospital.'
- 'The group agreed that the Emirati Hospital provides good service.'
- 'They prefer going to a private doctor and bearing the costs of treatment, thus saving time, effort, and travel costs.'
- 'After the pain persisted for 3 months, she decided to visit the Emirati Hospital.'
- 'They did an ECHO scan at the Emirati Hospital.'
- 'While comparing services in the private and the public sector, it was clear that the services of the private sector are the best.'
- 'One woman cited a popular proverb, which translates to 'If it’s free, it’s worthless!'
- 'Another said: “If you have money, then you are a Pasha ‘Sir’”.'
- 'Informal care, private clinic, pharmacies.'
- 'If we have difficulty dealing with the health situation, we have to go to private and expensive clinics.'
- 'They said that they seek treatment at a private clinic where they can run all necessary tests. However, they have to pay for all that despite the fact that they do not always have the funds to do so.'
- 'Some people have experienced the feeling of comfort and justice, while others discovered that going to an organization or center that provide free care is a bad idea, so they decided to resort to centers or clinics and defray the services themselves.'
- 'We talked about how to access and obtain health care services and how each of them decided to go to the doctor. They responded by stating that after a great deal of pain, disease, and developing symptoms, they finally decided to seek treatment at private centers or clinics.'
- 'They all regret going to organizations and government centers, because they do not receive services there.'
- 'After the session, I noticed that most people have a very negative impression formed around the treatment provided at the free health service centers. They believe these services are useless and hard to access.'
- 'They prefer to go to a private doctor and pay for the service although it constitutes a burden. They simply do this because they are convinced of the inefficiency of free service centers.'
Full Data link


You need to have the "Manage webhooks" permission (or be an admin) to create a webhook. Go to
your server's settings > Webhooks > Create webhook > Set the name, channel and avatar. > Copy
the URL > Save the webhook > Done.
You can later rename and delete it through this program or in the server's settings.