How to use TCppWebBrowser on RAD 10.4 - c++builder-10.4-sydney

The code below used to be perfect to C++Builder 6.0, but it is not compiling on RAD 10.4 Sydney.
I am not familiar with OLE controls and its classes and methods.
Can someone help me to make it work?
PogBrowser is a TCppWebBrowser.
void __fastcall TRelatPOG::ShowStream( TStream *stm )
{
try
{
if( !PogBrowser->Document )
{
PogBrowser->Navigate(L"about:blank");
while( PogBrowser->ReadyState != 4 )
Application->ProcessMessages();
}
IPersistStreamInit *psi;
TStreamAdapter *sa = new TStreamAdapter(stm,soReference);
if( sa )
{
if (SUCCEEDED(PogBrowser->Document->QueryInterface(IID_IPersistStreamInit,(void **)&psi)))
{
psi->InitNew();
psi->Load(*sa);// Compile error
psi->Release();
}
delete sa;
}
}
catch(Exception *E)
{
MessageDlg(String(E->ClassName()) + " ( " + E->Message + " )", mtError, TMsgDlgButtons() << mbOK, 0);
}
}

Once upon a time, TStreamAdapter used to implicitly convert to IStream*, but now it implicitly converts to _di_IStream instead (ie DelphiInterface<IStream>).
IPersistStreamInit::Save() requires IStream*, thus requires 2 conversions (TStreamAdapter -> _di_IStream -> IStream*), but C++ only allows 1 implicit conversion at a time.
So, you need to cast the TStreamAdapter to _di_IStream explicitly, which can then convert to IStream* implicitly, eg:
psi->Load(static_cast<_di_IStream>(*sa));
However, a better solution would be to let _di_IStream handle the lifetime of the TStreamAdapter to begin with, eg:
_di_IPersistStreamInit psi;
if (SUCCEEDED(PogBrowser->Document->QueryInterface(IID_IPersistStreamInit, reinterpret_cast<void**>(&psi))))
{
_di_IStream sa(*(new TStreamAdapter(stm, soReference)));
psi->InitNew();
psi->Load(sa);
}

Related

Issue logging within an embedded C function

I'd like to generate logging messages from within a C function embedded in a DML method. Take the example code below where the fib() function is called from the write() method of the regs bank. The log methods available to C all require a pointer to the current device.
Is there a way to get the device that calls the embedded function? Do I need to pass the device pointer into fib()?
dml 1.2;
device simple_embedded;
parameter documentation = "Embedding C code example for"
+ " Model Builder User's Guide";
parameter desc = "example of C code";
extern int fib(int x);
bank regs {
register r0 size 4 #0x0000 {
parameter allocate = false;
parameter configuration = "none";
method write(val) {
log "info": "Fibonacci(%d) = %d.", val, fib(val);
}
method read() -> (value) {
// Must be implemented to compile
}
}
}
header %{
int fib(int x);
%}
footer %{
int fib(int x) {
SIM_LOG_INFO(1, mydev, 0, "Generating Fibonacci for %d", x);
if (x < 2) return 1;
else return fib(x-1) + fib(x-2);
}
%}
I want to log from an embedded C function.
I solved this by passing the Simics conf_object_t pointer along to C. Just like implied in the question.
So you would use:
int fib(conf_object_t *mydev, int x) {
SIM_LOG_INFO(1, mydev, 0, "Generating Fibonacci for %d", x);
}
And
method write(val) {
log "info": "Fibonacci(%d) = %d.", val, fib(dev.obj,val);
}
Jakob's answer is the right one if your purpose is to offload some computations to C code (which makes sense in many situations, like when functionality is implemented by a lib).
However, if you just want a way to pass a callback to an API that asks for a function pointer, then it is easier to keep the implementation within DML and use a method reference, like:
method init() {
SIM_add_notifier(obj, trigger_fib_notifier_type, obj, &trigger_fib,
&dev.regs.r0.val);
}
method trigger_fib(conf_object_t *_, lang_void *aux) {
value = *cast(aux, uint64 *);
local int result = fib(value);
log info: "result: %d", result;
}
method fib(int x) -> (int) {
log info: "Generating Fibonacci for %d", x;
if (x < 2) return 1;
else return fib(x-1) + fib(x-2);
}

How to use doOnNext, doOnSubscribe and doOnComplete?

New to RxJava2/RxAndroid and Android development, but am pretty familiar with Java.
However, I've ran into quite a roadblock when trying to "optimize" and be able to update the UI between a bunch of calls to the same resource.
My code is as follows:
private int batch = 0;
private int totalBatches = 0;
private List<ItemInfo> apiRetItems = new ArrayList<>();
private Observable<ItemInfo[]> apiGetItems(int[] ids) {
int batchSize = 100;
return Observable.create(emitter -> {
int[] idpart = new int[0];
for(int i = 0; i < ids.length; i += batchSize) {
batch++;
idpart = Arrays.copyOfRange(ids, i, Math.min(ids.length, i+batchSize));
ItemInfo[] items = client.items().get(idpart);
emitter.onNext(items);
}
emitter.onComplete();
}).doOnSubscribe( __ -> {
Log.d("GW2DB", "apiGetItems subscribed to with " + ids.length + " ids.");
totalBatches = (int)Math.ceil(ids.length / batchSize);
progressbarUpdate(0, totalBatches);
}).doOnNext(items -> {
Log.d("GW2DB", batch + " batches of " + totalBatches + " batches completed.");
progressbarUpdate(batch, totalBatches);
}).doOnComplete( () -> {
Log.d("GW2DB", "Fetching items completed!");
progressbarReset();
});
}
If I remove the doOnSubscribe, doOnNext and doOnComplete I get no errors in Android Studio, but if I use any of them I get Incompatible types. Required: Observable<[...].ItemInfo[]>. Found: Observable<java.lang.Object>
I'm using RxAndroid 2.1.1 and RxJava 2.2.16.
Any ideas?
Since you are adding a chain of method calls, the compiler is just unable to correctly guess the type for the generic parameter in Observable.create. You can set it explicitly using Observable.<ItemInfo[]>create(...).

Manipulate Date/Time in RDF4J for Debugging

I'm using RDF4J 2.2.1 on Windows 10 Professional 64-bit. I will have some SPIN constructor rules which are sensitive to date/time. For example, I may want to compare a triple containing an xsd:dateTime datatype property to the output of SPARQL's built-in now() function. To debug this functionality, it would be convenient to manipulate RDF4J's perception of date/time somehow rather than manipulating the system clock. I'm aware that there is general commercial software (e.g. Solution Soft's "Time Machine") that can generally manipulate the perception of time for any Windows process. However, this software appears to be far too expensive for our little proof-of-concept project.
What I'd like to be able to do:
Set RDF4J's date/time to some arbitrary date/time value.
Have RDF4J's date/time proceed at real time speed or at some programmable faster speed during debugging.
Does anyone have suggestions for how to manipulate in this manner date/time for RDF4J? It would make my debugging of time-sensitive SPIN rules much more efficient. I'd prefer not to fight my PC's system clock since many other things depend on it. I suppose that running an entire virtual PC and debugging on the virtual PC is another option, but it seems there should be a simpler way.
Thanks.
You could accomplish this by implementing a custom SPARQL function and using that instead of the actual now() function. Call it mock_now() for example. Since you implement it, you have full control over its behavior.
I'm posting my solution to my question in hopes it might help others as a further example of a custom SPARQL function under RDF4J. I don't hold this out as en elegant solution (due to how I set test conditions), but it does work and meets my requirements. This solution extends the answer from #jeen_broekstra based on http://docs.rdf4j.org/custom-sparql-functions/...
I now have a custom implemented in the namespace defined by PREFIX soo: <http://www.disa.mil/dso/a2i/ontologies/PBSM/Sharing/SpectrumOperationsOntology#>as a function called soo:spectrumOpsDateTime() which can take either three or no arguments. The three arguments case allows setting the scaled date time as follows.
First argument: xsd:boolean... use system clock if true or use scaled clock if false
Second argument: xsd:dateTime (ignored if first argument is true)... the starting date/time for scaled clock operation
Third argument: xsd:double (ignored if first argument is true)... the scaled clock rate (e.g. 2.0 means the scaled clock runs faster, at twice real time)
If there are no arguments, soo:spectrumOpsDateTime() returns the scaled date/time or the system date/time depending on what the initial values in the Java code specify or what the last three-argument call specified. The SPARQL and SPIN code under test will use only the no-argument version. Test setup queries will set up the time conditions for particular tests.
Here's an example SPARQL setup query to set up a 2x speed starting this morning:
PREFIX soo: <http://www.disa.mil/dso/a2i/ontologies/PBSM/Sharing/SpectrumOperationsOntology#>
SELECT DISTINCT *
WHERE {
BIND(soo:spectrumOpsDateTime("false"^^xsd:boolean, "2017-08-22T10:49:21.019-05:00"^^xsd:dateTime, "2.0"^^xsd:double) AS ?testDateTime) .
}
Here's an example SPARQL query to get the scaled date/time:
PREFIX soo: <http://www.disa.mil/dso/a2i/ontologies/PBSM/Sharing/SpectrumOperationsOntology#>
SELECT DISTINCT *
WHERE {
BIND(soo:spectrumOpsDateTime() AS ?testDateTime) .
}
The single class used to implement this custom function is:
/**
*
*/
package mil.disa.dso.spo.a2i.nsc.sharing2025.scaledDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
import org.eclipse.rdf4j.query.algebra.evaluation.ValueExprEvaluationException;
import org.eclipse.rdf4j.query.algebra.evaluation.function.Function;
/**
* Class for generating a configurable date/time clock that can either be a pass-through of the
* system clock or a scaled clock starting at a specified date/time running at a specified
* rate from that specified time (first call).
* #author Greg Cox of Roberson and Associates &copy Copyright 2017 Roberson and Associates, All Right Reserved
*
*/
public class DateTimeGenerator implements Function {
private static final String thisClassName = "RDF4JCustomSPARQLFunction." + DateTimeGenerator.class.getSimpleName();
private static final String thisClassFullName = DateTimeGenerator.class.getName();
private static final boolean errorMessages = true;
private static final boolean verboseMessages = true;
private double clockPace = 2.0; // the speed of the clock, 1.0 is real time, 2.0 is 2x real time (double speed)
private boolean useSystemClock = false; // flag to indicate whether to use scaled clock or pass through the system clock
private ZonedDateTime startingRealDateTime = null; // the real time stamp at the first call to the evaluate function
private ZonedDateTime startingScaledDateTime = // the scaled time stamp (starting scaled time) at the first call to the evaluate function
ZonedDateTime.parse("2016-08-21T17:29:37.568-05:00");
// define a constant for the namespace of custom function
private static String NAMESPACE = "http://www.disa.mil/dso/a2i/ontologies/PBSM/Sharing/SpectrumOperationsOntology#"; // defined as soo: elsewhere
// this is the evaluate function needed to implement the RDF4J Function interface
// it can take 0 or 3 arguments
// 0 - get the current scaled time (starting by first call)
// 3 - useSystemClock flag (true/false), starting date/time (xsd:dateTime), clock pace (non-negative real w/ 1.0 meaning 1sec = 1sec)
#SuppressWarnings("unused")
#Override
public Value evaluate(ValueFactory valueFactory, Value... args) throws ValueExprEvaluationException {
String thisMethodMessagePrefix = "";
if (errorMessages || verboseMessages ) {
String thisMethodName = ".evaluate: ";
thisMethodMessagePrefix = thisClassName + thisMethodName;
}
if (args.length == 3) {
// Three arguments --> attempting to set mode/parameters, so attempt to parse/check them
if (verboseMessages) System.out.println(thisMethodMessagePrefix + "attempting to set scaled clock mode/parameters");
boolean argErrFlag = false;
boolean newUseSystemClock = false;
String argErrMessage = "";
// first argument should be true/false on whether to use system clock (true) or scaled clock (false)
if (!(args[0] instanceof Literal)) {
argErrFlag = true;
argErrMessage += "first argument must be a literal true/false value... ";
} else {
String useSystemClockString = args[0].stringValue();
if (useSystemClockString.equalsIgnoreCase("true")) {
if (verboseMessages) System.out.println(thisMethodMessagePrefix + "use system clock specified");
newUseSystemClock = true;
} else if (useSystemClockString.equalsIgnoreCase("false")) {
if (verboseMessages) System.out.println(thisMethodMessagePrefix + "use scaled clock specified");
newUseSystemClock = false;
}
else {
argErrFlag = true;
argErrMessage += "first argument must be a literal true/false value... ";
}
}
// second argument should be starting date/time for scaled clock (ignore if using system clock)
ZonedDateTime startTime = null;
if (!newUseSystemClock) {
if (!(args[1] instanceof Literal)) {
argErrFlag = true;
argErrMessage += "second argument must be literal xsd:dateTime value for start of scaled date/time... ";
} else {
String startDateTimeString = args[1].stringValue();
try {
startTime = ZonedDateTime.parse(startDateTimeString);
} catch (Exception e) {
argErrFlag = true;
argErrMessage += "could not parse starting date/time... " + e.getMessage() + "... ";
}
}
}
// third argument should be clock pace for scaled clock (ignore if using system clock)
Double newClockPace = null;
if (!newUseSystemClock) {
if (!(args[2] instanceof Literal)) {
argErrFlag = true;
argErrMessage += "third argument must be literal xsd:double value for clock pace... ";
} else {
String clockPaceString = args[2].stringValue();
try {
newClockPace = Double.parseDouble(clockPaceString);
} catch (Exception e) {
argErrFlag = true;
argErrMessage += "could not parse clock pace which should be a positive xsd:double... ";
}
if ((newClockPace != null) && (newClockPace <= 0.0)) {
argErrFlag = true;
argErrMessage += "clock pace must be positive, got " + newClockPace + "... ";
}
}
}
// check for errors and set up the generator if no errors...
if (argErrFlag) {
if (errorMessages) System.err.println(thisMethodMessagePrefix + "ERROR - " + argErrMessage);
if (errorMessages) System.err.println(thisMethodMessagePrefix + "throwing exception...");
throw new ValueExprEvaluationException(
"spectrum operations time function soo:spectrumOpsDateTime() encountered errors in function arguments... " +
argErrMessage);
} else if (newUseSystemClock) {
if (verboseMessages) System.out.println(thisMethodMessagePrefix + "using unscaled system clock");
useSystemClock = newUseSystemClock;
} else if (!newUseSystemClock) {
if (verboseMessages) System.out.println(thisMethodMessagePrefix + "using scaled time");
useSystemClock = newUseSystemClock;
startingRealDateTime = ZonedDateTime.now();
if (verboseMessages) System.out.println(thisMethodMessagePrefix + "setting starting real time to " + startingRealDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
if (verboseMessages) System.out.println(thisMethodMessagePrefix + "setting start time to " + startTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
startingScaledDateTime = startTime;
if (verboseMessages) System.out.println(thisMethodMessagePrefix + "setting clock pace to " + String.format("%5.2f", newClockPace * 100.0) + "%");
clockPace = newClockPace;
}
} else if (args.length != 0) { // can only have no arguments or three arguments...
throw new ValueExprEvaluationException(
"spectrum operations time function soo:spectrumOpsDateTime() requires "
+ "zero arguments or three arguments, got "
+ args.length + " arguments");
}
// now run the generator and return the result...
IRI xsdDateTimeIRI = valueFactory.createIRI("http://www.w3.org/2001/XMLSchema#dateTime"); // long-form equivalent to xsd:dateTime
if (useSystemClock) {
String unscaledTimeString = millisTrailingZeroes(ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
return valueFactory.createLiteral(unscaledTimeString, xsdDateTimeIRI);
} else {
errString = null;
String scaledTimeString = millisTrailingZeroes(getScaledDateTime().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
if (scaledTimeString == null) {
if (errorMessages) System.err.println(thisMethodMessagePrefix + "ERROR - scaled time returned null");
if (errorMessages) System.err.println(thisMethodMessagePrefix + "thowing exception...");
throw new ValueExprEvaluationException("could not generate valid scaled time string" + ((errString == null) ? "" : "... " + errString));
}
return valueFactory.createLiteral(scaledTimeString, xsdDateTimeIRI);
}
}
private static String errString = null;
/**
* Utility method to make all the millisecond fields of an <tt>ISO_OFFSET_DATE_TIME</tt> three digits by
* adding trailing zeroes as needed. Why? Because of trouble with various implementations interpreting
* 1 and 2 digit milliseconds differently. Should be standard decimal, but sometimes interpreted
* as number of milliseconds (e.g. .39T interpreted as 39 millieconds inststead of 390 milliseconds)
* #param <tt>ISO_OFFSET_DATE_TIME</tt> string to check for millisecond field length
* #return <tt>ISO_OFFSET_DATE_TIME</tt> strnig with trailing zeroes in milliseconds field
* as require to make the field three digits or <tt>null</tt> on error
*/
private static String millisTrailingZeroes(String isoDateTimeString) {
if (isoDateTimeString == null) {
errString = "DateTimeGenerator.millisTrailingZeroes: got null isoDateTimeString argument, returning null...";
return null;
}
String[] ss_l1 = isoDateTimeString.split("\\."); // Example: 2017-08-18T13:01:05.39-05:00 --> 2017-08-18T13:01:05 AND 39-05:00
if (ss_l1.length != 2) {
errString = "DateTImeGenerator.millisTrailingZeros: first parsing split of isoDateTimeString=" + isoDateTimeString + " by '.' got unexpected number of parts=" + ss_l1.length;
return null;
}
String[] ss_l2 = ss_l1[1].split("-"); // 39-05:00 --> 39 AND 05:00
if (ss_l2.length != 2) {
errString = "DateTImeGenerator.millisTrailingZeros: second parsing split of " + ss_l1[1] + " by '-' got unexpected number of parts=" + ss_l2.length;
return null;
}
if (ss_l2[0].length() == 1) {
ss_l2[0] = ss_l2[0] + "00";
} else if (ss_l2[0].length() == 2)
ss_l2[0] = ss_l2[0] + "0"; // 39 --> 390
return ss_l1[0] + "." + ss_l2[0] + "-" + ss_l2[1]; // 2017-08-18T13:01:05.390-05:00
}
/**
* Method to get the current scaled date time according to the state of this DateTimeGenerator.
* If <tt>useSystemClock</tt> is <tt>true</tt>, then time is not
* scaled and system time is returned instead of scaled time.
* #return scaled date time if <tt>useSystemClock</tt> is <tt>true</tt> or
* system date time if <tt>useSystemClock</tt> is <tt>false</tt>
*/
private ZonedDateTime getScaledDateTime() {
ZonedDateTime scaledDateTime = null;
if (useSystemClock) {
scaledDateTime = ZonedDateTime.now();
} else {
if (startingRealDateTime == null)
startingRealDateTime = ZonedDateTime.now();
long realMillisFromFirstCall = ChronoUnit.MILLIS.between(startingRealDateTime, ZonedDateTime.now());
long scaledMillisFromFirstCall = (long) ((double) realMillisFromFirstCall * clockPace);
scaledDateTime = ChronoUnit.MILLIS.addTo(startingScaledDateTime, scaledMillisFromFirstCall);
}
return scaledDateTime;
}
#Override
public String getURI() {
return NAMESPACE + "spectrumOpsDateTime";
}
/**
* Test main method
* #param args command line arguments (ignored)
*/
#SuppressWarnings("unused")
public static void main(String[] args) {
String thisMethodMessagePrefix = "";
if (errorMessages || verboseMessages ) {
String thisMethodName = ".main: ";
thisMethodMessagePrefix = thisClassName + thisMethodName;
}
DateTimeGenerator testGen = new DateTimeGenerator();
if (verboseMessages) System.out.println(thisMethodMessagePrefix + "custom SPARQL method URI: " + testGen.getURI());
if (verboseMessages) System.out.println(thisMethodMessagePrefix + "fully-qualified class name: " + thisClassFullName);
ValueFactory testVF = SimpleValueFactory.getInstance();
Value testValues[] = new Value[0];
while (true) {
if (verboseMessages) System.out.println(thisMethodMessagePrefix + "scaled: " + testGen.evaluate(testVF, testValues).stringValue() +
" current real: " + millisTrailingZeroes(ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
In my case, the jar file exported from Eclipse executes under my installation of Apache and resides at C:\Apache\apache-tomcat-8.5.15\webapps\rdf4j-server\WEB-INF\lib\ScaledDateTime.jar I restart the Apache server after replacing this jar file when I do mofifications.

pybind11 equivalent of boost::python::extract?

I am considering port of a complex code from boost::python to pybind11, but I am puzzled by the absence of something like boost::python::extract<...>().check(). I read pybind11::cast<T> can be used to extract c++ object from a py::object, but the only way to check if the cast is possible is by calling it and catching the exception when the cast fails. Is there something I am overlooking?
isinstance will do the job (doc) :
namespace py = pybind11;
py::object obj = ...
if (py::isinstance<py::array_t<double>>(obj))
{
....
}
else if (py::isinstance<py::str>(obj))
{
std::string val = obj.cast<std::string>();
std::cout << val << std::endl;
}
else if (py::isinstance<py::list>(obj))
{
...
}

iPhone Operators

Okay so I have defined my DSNavigationManager class and it has a property called DSNavigationManagerStyle managerStyle:
typedef enum {
DSNavigationManagerStyleNone = 0,
DSNavigationManagerStyleDefaultNavigationBar = 1 << 0,
DSNavigationManagerStyleDefaultToolBar = 1 << 1,
DSNavigationManagerStyleDefault =
DSNavigationManagerStyleDefaultNavigationBar +
DSNavigationManagerStyleDefaultToolBar,
DSNavigationManagerStyleInteractiveNavigationBar = 1 << 2,
DSNavigationManagerStyleInteractiveToolBar = 1 << 3,
DSNavigationManagerStyleInteractiveWithDarkPanel = 1 << 4,
DSNavigationManagerStyleInteractiveWithBackButton = 1 << 5,
DSNavigationManagerStyleInteractiveWithTitleBar = 1 << 6,
DSNavigationManagerStyleInteractiveDefault =
DSNavigationManagerStyleInteractiveNavigationBar +
DSNavigationManagerStyleInteractiveToolBar +
DSNavigationManagerStyleInteractiveWithDarkPanel +
DSNavigationManagerStyleInteractiveWithBackButton +
DSNavigationManagerStyleInteractiveWithTitleBar,
} DSNavigationManagerStyle;
I just learned how to use bit-wise shifting but I don't know how to receive this information. I want to do something a little like:
DSNavigationManagerStyle managerStyle = DSNavigationManagerStyleDefault;
if(managerStyle "Has The DefaultNavigationBar bit or the DefaultToolBarBit") {
// Implement
}
else {
if(managerStyle "Has the InteractiveNavigationBar bit") {
// Implement
}
if(managerStyle "Has the InteractiveToolBar bit") {
// Implement
}
//.... and so on so that technically the object can implement all
// styles, no styles, or any number of styles in between
}
if (managerStyle & DSNavigationManagerStyleDefaultNavigationBar || managerStyle & DSNavigationManagerStyleDefaultToolBarBit) {
// Implement
} else if (managerStyle & DSNavigationManagerStyleInteractiveNavigationBar) {
// Implement
} else if (managerStyle & DSNavigationManagerStyleInteractiveToolBar) {
// Implement
}
//.... and so on so that technically the object can implement all
// styles, no styles, or any number of styles in between
}
& is the bitwise AND operator. You should read the Wikipedia article on Bitwise operation.
To check for the presence of a particular bit, use the bitwise and, & (not to be confused with &&, the logical and). For example,
01101101
& 00001000
----------
00001000
If you use this value where it will be cast to boolean, any non-zero value is considered "true," which makes tests like this easy to read:
if (managerStyle & DSNavigationManagerStyleDefaultToolBar) {
...
}
But this test won't work well with your compound values - for example, anding a bitfield with DSNavigationManagerStyleDefault will return 'true' if any of its component bits are set.
If you really want to use bitfields, accustom yourself to all the bitwise operators: http://developer.apple.com/tools/mpw-tools/commandref/appc_logical.html