function submit(partId, webSubmit) %SUBMIT Submit your code and output to the ml-class servers % SUBMIT() will connect to the ml-class server and submit your solution fprintf('==\n== [ml-class] Submitting Solutions | Programming Exercise %s\n==\n', ... homework_id()); if ~exist('partId', 'var') || isempty(partId) partId = promptPart(); end if ~exist('webSubmit', 'var') || isempty(webSubmit) webSubmit = 0; % submit directly by default end % Check valid partId partNames = validParts(); if ~isValidPartId(partId) fprintf('!! Invalid homework part selected.\n'); fprintf('!! Expected an integer from 1 to %d.\n', numel(partNames) + 1); fprintf('!! Submission Cancelled\n'); return end if ~exist('ml_login_data.mat','file') [login password] = loginPrompt(); save('ml_login_data.mat','login','password'); else load('ml_login_data.mat'); [login password] = quickLogin(login, password); save('ml_login_data.mat','login','password'); end if isempty(login) fprintf('!! Submission Cancelled\n'); return end fprintf('\n== Connecting to ml-class ... '); if exist('OCTAVE_VERSION') fflush(stdout); end % Setup submit list if partId == numel(partNames) + 1 submitParts = 1:numel(partNames); else submitParts = [partId]; end for s = 1:numel(submitParts) thisPartId = submitParts(s); if (~webSubmit) % submit directly to server [login, ch, signature, auxstring] = getChallenge(login, thisPartId); if isempty(login) || isempty(ch) || isempty(signature) % Some error occured, error string in first return element. fprintf('\n!! Error: %s\n\n', login); return end % Attempt Submission with Challenge ch_resp = challengeResponse(login, password, ch); [result, str] = submitSolution(login, ch_resp, thisPartId, ... output(thisPartId, auxstring), source(thisPartId), signature); partName = partNames{thisPartId}; fprintf('\n== [ml-class] Submitted Assignment %s - Part %d - %s\n', ... homework_id(), thisPartId, partName); fprintf('== %s\n', strtrim(str)); if exist('OCTAVE_VERSION') fflush(stdout); end else [result] = submitSolutionWeb(login, thisPartId, output(thisPartId), ... source(thisPartId)); result = base64encode(result); fprintf('\nSave as submission file [submit_ex%s_part%d.txt (enter to accept default)]:', ... homework_id(), thisPartId); saveAsFile = input('', 's'); if (isempty(saveAsFile)) saveAsFile = sprintf('submit_ex%s_part%d.txt', homework_id(), thisPartId); end fid = fopen(saveAsFile, 'w'); if (fid) fwrite(fid, result); fclose(fid); fprintf('\nSaved your solutions to %s.\n\n', saveAsFile); fprintf(['You can now submit your solutions through the web \n' ... 'form in the programming exercises. Select the corresponding \n' ... 'programming exercise to access the form.\n']); else fprintf('Unable to save to %s\n\n', saveAsFile); fprintf(['You can create a submission file by saving the \n' ... 'following text in a file: (press enter to continue)\n\n']); pause; fprintf(result); end end end end % ================== CONFIGURABLES FOR EACH HOMEWORK ================== function id = homework_id() id = '1'; end function [partNames] = validParts() partNames = { 'Warm up exercise ', ... 'Computing Cost (for one variable)', ... 'Gradient Descent (for one variable)', ... 'Feature Normalization', ... 'Computing Cost (for multiple variables)', ... 'Gradient Descent (for multiple variables)', ... 'Normal Equations'}; end function srcs = sources() % Separated by part srcs = { { 'warmUpExercise.m' }, ... { 'computeCost.m' }, ... { 'gradientDescent.m' }, ... { 'featureNormalize.m' }, ... { 'computeCostMulti.m' }, ... { 'gradientDescentMulti.m' }, ... { 'normalEqn.m' }, ... }; end function out = output(partId, auxstring) % Random Test Cases X1 = [ones(20,1) (exp(1) + exp(2) * (0.1:0.1:2))']; Y1 = X1(:,2) + sin(X1(:,1)) + cos(X1(:,2)); X2 = [X1 X1(:,2).^0.5 X1(:,2).^0.25]; Y2 = Y1.^0.5 + Y1; if partId == 1 out = sprintf('%0.5f ', warmUpExercise()); elseif partId == 2 out = sprintf('%0.5f ', computeCost(X1, Y1, [0.5 -0.5]')); elseif partId == 3 out = sprintf('%0.5f ', gradientDescent(X1, Y1, [0.5 -0.5]', 0.01, 10)); elseif partId == 4 out = sprintf('%0.5f ', featureNormalize(X2(:,2:4))); elseif partId == 5 out = sprintf('%0.5f ', computeCostMulti(X2, Y2, [0.1 0.2 0.3 0.4]')); elseif partId == 6 out = sprintf('%0.5f ', gradientDescentMulti(X2, Y2, [-0.1 -0.2 -0.3 -0.4]', 0.01, 10)); elseif partId == 7 out = sprintf('%0.5f ', normalEqn(X2, Y2)); end end % ====================== SERVER CONFIGURATION =========================== % ***************** REMOVE -staging WHEN YOU DEPLOY ********************* function url = site_url() url = 'http://class.coursera.org/ml-007'; end function url = challenge_url() url = [site_url() '/assignment/challenge']; end function url = submit_url() url = [site_url() '/assignment/submit']; end % ========================= CHALLENGE HELPERS ========================= function src = source(partId) src = ''; src_files = sources(); if partId <= numel(src_files) flist = src_files{partId}; for i = 1:numel(flist) fid = fopen(flist{i}); if (fid == -1) error('Error opening %s (is it missing?)', flist{i}); end line = fgets(fid); while ischar(line) src = [src line]; line = fgets(fid); end fclose(fid); src = [src '||||||||']; end end end function ret = isValidPartId(partId) partNames = validParts(); ret = (~isempty(partId)) && (partId >= 1) && (partId <= numel(partNames) + 1); end function partId = promptPart() fprintf('== Select which part(s) to submit:\n'); partNames = validParts(); srcFiles = sources(); for i = 1:numel(partNames) fprintf('== %d) %s [', i, partNames{i}); fprintf(' %s ', srcFiles{i}{:}); fprintf(']\n'); end fprintf('== %d) All of the above \n==\nEnter your choice [1-%d]: ', ... numel(partNames) + 1, numel(partNames) + 1); selPart = input('', 's'); partId = str2num(selPart); if ~isValidPartId(partId) partId = -1; end end function [email,ch,signature,auxstring] = getChallenge(email, part) str = urlread(challenge_url(), 'post', {'email_address', email, 'assignment_part_sid', [homework_id() '-' num2str(part)], 'response_encoding', 'delim'}); str = strtrim(str); r = struct; while(numel(str) > 0) [f, str] = strtok (str, '|'); [v, str] = strtok (str, '|'); r = setfield(r, f, v); end email = getfield(r, 'email_address'); ch = getfield(r, 'challenge_key'); signature = getfield(r, 'state'); auxstring = getfield(r, 'challenge_aux_data'); end function [result, str] = submitSolutionWeb(email, part, output, source) result = ['{"assignment_part_sid":"' base64encode([homework_id() '-' num2str(part)], '') '",' ... '"email_address":"' base64encode(email, '') '",' ... '"submission":"' base64encode(output, '') '",' ... '"submission_aux":"' base64encode(source, '') '"' ... '}']; str = 'Web-submission'; end function [result, str] = submitSolution(email, ch_resp, part, output, ... source, signature) params = {'assignment_part_sid', [homework_id() '-' num2str(part)], ... 'email_address', email, ... 'submission', base64encode(output, ''), ... 'submission_aux', base64encode(source, ''), ... 'challenge_response', ch_resp, ... 'state', signature}; str = urlread(submit_url(), 'post', params); % Parse str to read for success / failure result = 0; end % =========================== LOGIN HELPERS =========================== function [login password] = loginPrompt() % Prompt for password [login password] = basicPrompt(); if isempty(login) || isempty(password) login = []; password = []; end end function [login password] = basicPrompt() login = input('Login (Email address): ', 's'); password = input('Password: ', 's'); end function [login password] = quickLogin(login,password) disp(['You are currently logged in as ' login '.']); cont_token = input('Is this you? (y/n - type n to reenter password)','s'); if(isempty(cont_token) || cont_token(1)=='Y'||cont_token(1)=='y') return; else [login password] = loginPrompt(); end end function [str] = challengeResponse(email, passwd, challenge) str = sha1([challenge passwd]); end % =============================== SHA-1 ================================ function hash = sha1(str) % Initialize variables h0 = uint32(1732584193); h1 = uint32(4023233417); h2 = uint32(2562383102); h3 = uint32(271733878); h4 = uint32(3285377520); % Convert to word array strlen = numel(str); % Break string into chars and append the bit 1 to the message mC = [double(str) 128]; mC = [mC zeros(1, 4-mod(numel(mC), 4), 'uint8')]; numB = strlen * 8; if exist('idivide') numC = idivide(uint32(numB + 65), 512, 'ceil'); else numC = ceil(double(numB + 65)/512); end numW = numC * 16; mW = zeros(numW, 1, 'uint32'); idx = 1; for i = 1:4:strlen + 1 mW(idx) = bitor(bitor(bitor( ... bitshift(uint32(mC(i)), 24), ... bitshift(uint32(mC(i+1)), 16)), ... bitshift(uint32(mC(i+2)), 8)), ... uint32(mC(i+3))); idx = idx + 1; end % Append length of message mW(numW - 1) = uint32(bitshift(uint64(numB), -32)); mW(numW) = uint32(bitshift(bitshift(uint64(numB), 32), -32)); % Process the message in successive 512-bit chs for cId = 1 : double(numC) cSt = (cId - 1) * 16 + 1; cEnd = cId * 16; ch = mW(cSt : cEnd); % Extend the sixteen 32-bit words into eighty 32-bit words for j = 17 : 80 ch(j) = ch(j - 3); ch(j) = bitxor(ch(j), ch(j - 8)); ch(j) = bitxor(ch(j), ch(j - 14)); ch(j) = bitxor(ch(j), ch(j - 16)); ch(j) = bitrotate(ch(j), 1); end % Initialize hash value for this ch a = h0; b = h1; c = h2; d = h3; e = h4; % Main loop for i = 1 : 80 if(i >= 1 && i <= 20) f = bitor(bitand(b, c), bitand(bitcmp(b), d)); k = uint32(1518500249); elseif(i >= 21 && i <= 40) f = bitxor(bitxor(b, c), d); k = uint32(1859775393); elseif(i >= 41 && i <= 60) f = bitor(bitor(bitand(b, c), bitand(b, d)), bitand(c, d)); k = uint32(2400959708); elseif(i >= 61 && i <= 80) f = bitxor(bitxor(b, c), d); k = uint32(3395469782); end t = bitrotate(a, 5); t = bitadd(t, f); t = bitadd(t, e); t = bitadd(t, k); t = bitadd(t, ch(i)); e = d; d = c; c = bitrotate(b, 30); b = a; a = t; end h0 = bitadd(h0, a); h1 = bitadd(h1, b); h2 = bitadd(h2, c); h3 = bitadd(h3, d); h4 = bitadd(h4, e); end hash = reshape(dec2hex(double([h0 h1 h2 h3 h4]), 8)', [1 40]); hash = lower(hash); end function ret = bitadd(iA, iB) ret = double(iA) + double(iB); ret = bitset(ret, 33, 0); ret = uint32(ret); end function ret = bitrotate(iA, places) t = bitshift(iA, places - 32); ret = bitshift(iA, places); ret = bitor(ret, t); end % =========================== Base64 Encoder ============================ % Thanks to Peter John Acklam % function y = base64encode(x, eol) %BASE64ENCODE Perform base64 encoding on a string. % % BASE64ENCODE(STR, EOL) encode the given string STR. EOL is the line ending % sequence to use; it is optional and defaults to '\n' (ASCII decimal 10). % The returned encoded string is broken into lines of no more than 76 % characters each, and each line will end with EOL unless it is empty. Let % EOL be empty if you do not want the encoded string broken into lines. % % STR and EOL don't have to be strings (i.e., char arrays). The only % requirement is that they are vectors containing values in the range 0-255. % % This function may be used to encode strings into the Base64 encoding % specified in RFC 2045 - MIME (Multipurpose Internet Mail Extensions). The % Base64 encoding is designed to represent arbitrary sequences of octets in a % form that need not be humanly readable. A 65-character subset % ([A-Za-z0-9+/=]) of US-ASCII is used, enabling 6 bits to be represented per % printable character. % % Examples % -------- % % If you want to encode a large file, you should encode it in chunks that are % a multiple of 57 bytes. This ensures that the base64 lines line up and % that you do not end up with padding in the middle. 57 bytes of data fills % one complete base64 line (76 == 57*4/3): % % If ifid and ofid are two file identifiers opened for reading and writing, % respectively, then you can base64 encode the data with % % while ~feof(ifid) % fwrite(ofid, base64encode(fread(ifid, 60*57))); % end % % or, if you have enough memory, % % fwrite(ofid, base64encode(fread(ifid))); % % See also BASE64DECODE. % Author: Peter John Acklam % Time-stamp: 2004-02-03 21:36:56 +0100 % E-mail: pjacklam@online.no % URL: http://home.online.no/~pjacklam if isnumeric(x) x = num2str(x); end % make sure we have the EOL value if nargin < 2 eol = sprintf('\n'); else if sum(size(eol) > 1) > 1 error('EOL must be a vector.'); end if any(eol(:) > 255) error('EOL can not contain values larger than 255.'); end end if sum(size(x) > 1) > 1 error('STR must be a vector.'); end x = uint8(x); eol = uint8(eol); ndbytes = length(x); % number of decoded bytes nchunks = ceil(ndbytes / 3); % number of chunks/groups nebytes = 4 * nchunks; % number of encoded bytes % add padding if necessary, to make the length of x a multiple of 3 if rem(ndbytes, 3) x(end+1 : 3*nchunks) = 0; end x = reshape(x, [3, nchunks]); % reshape the data y = repmat(uint8(0), 4, nchunks); % for the encoded data %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Split up every 3 bytes into 4 pieces % % aaaaaabb bbbbcccc ccdddddd % % to form % % 00aaaaaa 00bbbbbb 00cccccc 00dddddd % y(1,:) = bitshift(x(1,:), -2); % 6 highest bits of x(1,:) y(2,:) = bitshift(bitand(x(1,:), 3), 4); % 2 lowest bits of x(1,:) y(2,:) = bitor(y(2,:), bitshift(x(2,:), -4)); % 4 highest bits of x(2,:) y(3,:) = bitshift(bitand(x(2,:), 15), 2); % 4 lowest bits of x(2,:) y(3,:) = bitor(y(3,:), bitshift(x(3,:), -6)); % 2 highest bits of x(3,:) y(4,:) = bitand(x(3,:), 63); % 6 lowest bits of x(3,:) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Now perform the following mapping % % 0 - 25 -> A-Z % 26 - 51 -> a-z % 52 - 61 -> 0-9 % 62 -> + % 63 -> / % % We could use a mapping vector like % % ['A':'Z', 'a':'z', '0':'9', '+/'] % % but that would require an index vector of class double. % z = repmat(uint8(0), size(y)); i = y <= 25; z(i) = 'A' + double(y(i)); i = 26 <= y & y <= 51; z(i) = 'a' - 26 + double(y(i)); i = 52 <= y & y <= 61; z(i) = '0' - 52 + double(y(i)); i = y == 62; z(i) = '+'; i = y == 63; z(i) = '/'; y = z; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Add padding if necessary. % npbytes = 3 * nchunks - ndbytes; % number of padding bytes if npbytes y(end-npbytes+1 : end) = '='; % '=' is used for padding end if isempty(eol) % reshape to a row vector y = reshape(y, [1, nebytes]); else nlines = ceil(nebytes / 76); % number of lines neolbytes = length(eol); % number of bytes in eol string % pad data so it becomes a multiple of 76 elements y = [y(:) ; zeros(76 * nlines - numel(y), 1)]; y(nebytes + 1 : 76 * nlines) = 0; y = reshape(y, 76, nlines); % insert eol strings eol = eol(:); y(end + 1 : end + neolbytes, :) = eol(:, ones(1, nlines)); % remove padding, but keep the last eol string m = nebytes + neolbytes * (nlines - 1); n = (76+neolbytes)*nlines - neolbytes; y(m+1 : n) = ''; % extract and reshape to row vector y = reshape(y, 1, m+neolbytes); end % output is a character array y = char(y); end