function PsychPaidSupportAndServices(mininag) % % If you require paid support regarding Psychtoolbox, or custom feature % development (or if you want to buy a Psychtoolbox themed coffee mug, bag or shirt) % go to the following website which provides such services: % % https://www.psychtoolbox.net % % For paid support on the user forum or GitHub issue tracker, buy a % "Psychtoolbox support membership" under the "become a member" section: % % https://www.psychtoolbox.net/#service % % 1. As part of your purchase, you will receive a document - an invoice - with a % printed "Order Id" or "Order no.", and a printed "License key". % % 2. Next you can run *this* function PsychPaidSupportAndServices in Octave or % Matlab. The function will ask you if you need paid support and do have % an active license key to prove your community membership. Answer "y" for yes. % % 3. Next the function will ask you about your "Order Id" and "License key". % Please enter that info that you got from step 1. % % 4. The function will print out an "authentication token", a string of letters and % numbers. Now you can post your question on the Psychtoolbox user forum at % https://psychtoolbox.discourse.group or open a new issue for bugs and feature % requests on our GitHub issue tracker at https://github.com/Psychtoolbox-3/Psychtoolbox-3/issues % % Please add the "authentication token" to your forum question or GitHub issue. % This will prove to us that you deserve paid support for your question or % issue. Please note that initial activation of your license key may take 5-10 % days after date of receipt of payment, so do not buy the paid support last % minute, when the "house is already burning", but ahead of time, like you % would do with a fire insurance. % % % For more detailed background information about Psychtoolbox's need for funding, read on: % % Continued development, improvement, maintenance and support of % Psychtoolbox itself, and also improvement of the various open-source % software components on which Psychtoolbox and other neuroscience toolkits % (e.g., PsychoPy) critically depend, including improvements to the Linux % operating system as the strongest and most high quality foundation for % demanding stimulation and data collection paradigms, requires a lot of % highly qualified and highly focused work. % % This work is currently (year 2006 - present) mostly carried out by Mario % Kleiner, who is now employed to do this work by the Medical Innovations % Incubator GmbH (MII) in Tuebingen, Germany ( https://www.mi-incubator.com ). % The MII belongs by 100% to the non-profit foundation for medical % innovations ( http://www.mi-foundation.org ) in Tuebingen. % % In order to fund Mario's work and provide him with the resources to do % this job, the MII offers different types of paid services around % Psychtoolbox and the use of Linux for neuroscience, among them a % "Psychtoolbox community membership with paid support". % % Your lab can now financially contribute to Psychtoolbox sustainability, % upkeep and continued improvement, by once a year buying such a community % membership for a modest fee. This membership entitles you to some % paid support for questions regarding efficient use of Psychtoolbox, % questions regarding the resolution of issues you may have with it, fixing % of bugs you may encounter, and feature requests. MII also offers paid % feature development and other commercial services. % % Please visit the following website, operated by MII, for our offering of % commercial development services, and for the community membership with % paid support: % % % https://www.psychtoolbox.net % % % The membership allows you to get your voice heard by the developers % regarding future feature development, as well as preferential treatment % on the public Psychtoolbox user forum and GitHub issue tracker. Spare % income generated by your membership fee, that does not have to be used % to process paid requests made individually by you, will be used to % fund general development and upkeep of Psychtoolbox and its ecosystem. In % other words, it contributes to / acts as an insurance that allows % Psychtoolbox to be around and in good shape years into the future. % % To clarify: Psychtoolbox itself will stay open-source software. Anybody % able and willing to contribute code and ideas of sufficiently high quality % is invited to contribute to the open-source code, the documentation on our % public community website and Wiki % http://psychtoolbox.org, and to participate and help each other on the % public community forum https://psychtoolbox.discourse.group. % % Support by our developers will be reserved to paying community members. % % Thanks for your participation and support! % % Mini advert requested by some caller, e.g., PsychtoolboxPostInstallRoutine? if exist('mininag', 'var') && (mininag > 0) fprintf('\n'); % mininag 2 if called from an error handler, mininag 1 if called from % general setup code: if mininag == 2 fprintf('NOTE: You may want to acquire paid support for future issues like this.\n'); else fprintf('IMPORTANT NEWS:\n\n'); fprintf('You can now financially contribute to Psychtoolbox sustainability, upkeep and continued\n'); fprintf('improvement by buying a paid support membership, which provides some paid support\n'); fprintf('for questions regarding its use, or issues you may have with it. We also offer paid\n'); fprintf('feature development and other useful commercial services.\n'); end fprintf('Please type ''PsychPaidSupportAndServices'' to learn more.\n'); fprintf('\n\n'); if mininag == 1 end return; end % Nope, full request by user for information: try fid = fopen([PsychtoolboxConfigDir 'welcomemsgdone'], 'w'); fclose(fid); catch end more on; help PsychPaidSupportAndServices; more off; % Check if user wants to file a support request: fprintf('\n\n'); answer = ''; while length(answer)~=1 || ~ismember(answer, ['y', 'n']) answer = strtrim(input('Do you need paid support now and have an active license key [y/n]? ', 's')); end if ~strcmpi(answer, 'y') fprintf('A paid support membership can be bought as described above. Bye.\n'); return; end % Ok, our valued community member wants support now. Guide them through the process: orderId = ''; while isempty(orderId) fprintf('\nThe Order Id is on the invoice you received, as "Order no." between the invoice\n'); fprintf('number and the customer number.\n\n'); orderId = strtrim(upper(input('Please enter the Order Id of your license, or just ENTER if you can not find it: ', 's'))); if length(orderId) ~= 8 || ~all(isstrprop(orderId, 'alphanum')) fprintf('\nOrder Id seems to be invalid: It must be 8 letters or numbers, e.g., XS92UVY3\n'); orderId = ''; end if isempty(orderId) fprintf('\nIf you can not find the Order Id, i can also just use the first 8 characters of\n'); fprintf('your license key. This poses a mildly higher risk of somebody guessing your key\n'); fprintf('and abusing your community membership to their advantage, or of other mixups.\n\n'); if lower(input('Do you want me to use the license key instead [y/n]? ', 's')) == 'y' break; end end end % Get the date and time string as 2nd component: requestTimeDate = sprintf('%i', round(clock)); licenseKey = ''; while isempty(licenseKey) licenseKey = strtrim(upper(input('Please enter the license key: ', 's'))); if length(licenseKey) ~= 35 || ~all(isstrprop(licenseKey([1:5, 7:11, 13:17, 19:23, 25:29, 31:35]), 'alphanum')) || ~strcmp(licenseKey([6, 12, 18, 24, 30]), '-----') fprintf('The license key seems to be invalid: It must be 30 letters or numbers in dash separated groups of five, e.g.,\n'); fprintf('2BQR7-R5ZQP-SA36G-RAVDJ-ABZBM-PKKFJ\n\n'); licenseKey = ''; end end % User wants us to use first eight chars of license key as orderId? if isempty(orderId) orderId = licenseKey(1:8); end % Assemble the to-be-hashed string: publicString = [orderId '-' requestTimeDate]; hashSrcString = [publicString '-' licenseKey]; % Hash it with SHA-256: % fprintf('\nThe following string will be SHA-256 hashed: %s\n\n', hashSrcString); hashString = computeSHA256(hashSrcString); % Assemble final token for public posting at user forum, issue tracker etc.: authToken = [publicString ':' hashString]; fprintf('\n\nPlease add the following string to your request when\n'); fprintf('asking for support on the Psychtoolbox user forum\n'); fprintf('[ https://psychtoolbox.discourse.group ]\n'); fprintf('or on the Psychtoolbox-3 GitHub issue tracker\n'); fprintf('[ https://github.com/Psychtoolbox-3/Psychtoolbox-3/issues ]\n'); fprintf('to prove that you are eligible for paid support:\n'); fprintf('========================================================================================\n\n'); fprintf('%s\n\n', authToken); fprintf('========================================================================================\n\n'); % Validation code for the above: if 0 % Disassemble into pieces: eOrderId = authToken(1:8) epublicStringHashSep = strfind(authToken, ':'); epublicString = authToken(1:epublicStringHashSep-1) ehashString = authToken(epublicStringHashSep+1:end) % Here we'd use eOrderId to lookup licenseKey in our DB. % Then reassemble source string for hashing: ehashSrcString = [epublicString '-' licenseKey] % Hash it, and compare our local hash against the one provided in public authToken: bingo = strcmp(ehashString, computeSHA256(ehashSrcString)) end return; % Embedded SHA-256 implementation. This is the same as PsychComputeSHA(msg, '256'), % but embedded here to make PsychPaidSupportAndServices() self-contained. function rethash = computeSHA256(msg) shaId = '256'; if exist('hash', 'builtin') % Octave builtin rethash = hash(['SHA' shaId], msg); else md = javaMethod('getInstance', 'java.security.MessageDigest', ['SHA-' shaId]); rethash = sprintf('%2.2x', typecast(md.digest(uint8(msg)), 'uint8')'); end return;