Browse Source

first commit

CHEN Yihui 5 years ago
commit
428f69c72f
100 changed files with 14270 additions and 0 deletions
  1. 2 0
      .gitignore
  2. 17 0
      README.md
  3. 27 0
      ex1/computeCost.m
  4. 25 0
      ex1/computeCostMulti.m
  5. 135 0
      ex1/ex1.m
  6. 159 0
      ex1/ex1_multi.m
  7. 97 0
      ex1/ex1data1.txt
  8. 47 0
      ex1/ex1data2.txt
  9. 39 0
      ex1/featureNormalize.m
  10. 29 0
      ex1/gradientDescent.m
  11. 34 0
      ex1/gradientDescentMulti.m
  12. 41 0
      ex1/lib/jsonlab/AUTHORS.txt
  13. 74 0
      ex1/lib/jsonlab/ChangeLog.txt
  14. 25 0
      ex1/lib/jsonlab/LICENSE_BSD.txt
  15. 394 0
      ex1/lib/jsonlab/README.txt
  16. 32 0
      ex1/lib/jsonlab/jsonopt.m
  17. 566 0
      ex1/lib/jsonlab/loadjson.m
  18. 528 0
      ex1/lib/jsonlab/loadubjson.m
  19. 33 0
      ex1/lib/jsonlab/mergestruct.m
  20. 475 0
      ex1/lib/jsonlab/savejson.m
  21. 504 0
      ex1/lib/jsonlab/saveubjson.m
  22. 40 0
      ex1/lib/jsonlab/varargin2struct.m
  23. 30 0
      ex1/lib/makeValidFieldName.m
  24. 179 0
      ex1/lib/submitWithConfiguration.m
  25. 23 0
      ex1/normalEqn.m
  26. 28 0
      ex1/plotData.m
  27. 69 0
      ex1/submit.m
  28. 21 0
      ex1/warmUpExercise.m
  29. 33 0
      ex2/costFunction.m
  30. 30 0
      ex2/costFunctionReg.m
  31. 151 0
      ex2/ex2.m
  32. 136 0
      ex2/ex2_reg.m
  33. 100 0
      ex2/ex2data1.txt
  34. 118 0
      ex2/ex2data2.txt
  35. 8 0
      ex2/hypothesis.m
  36. 41 0
      ex2/lib/jsonlab/AUTHORS.txt
  37. 74 0
      ex2/lib/jsonlab/ChangeLog.txt
  38. 25 0
      ex2/lib/jsonlab/LICENSE_BSD.txt
  39. 394 0
      ex2/lib/jsonlab/README.txt
  40. 32 0
      ex2/lib/jsonlab/jsonopt.m
  41. 566 0
      ex2/lib/jsonlab/loadjson.m
  42. 528 0
      ex2/lib/jsonlab/loadubjson.m
  43. 33 0
      ex2/lib/jsonlab/mergestruct.m
  44. 475 0
      ex2/lib/jsonlab/savejson.m
  45. 504 0
      ex2/lib/jsonlab/saveubjson.m
  46. 40 0
      ex2/lib/jsonlab/varargin2struct.m
  47. 30 0
      ex2/lib/makeValidFieldName.m
  48. 179 0
      ex2/lib/submitWithConfiguration.m
  49. 21 0
      ex2/mapFeature.m
  50. 32 0
      ex2/plotData.m
  51. 48 0
      ex2/plotDecisionBoundary.m
  52. 27 0
      ex2/predict.m
  53. 18 0
      ex2/sigmoid.m
  54. 62 0
      ex2/submit.m
  55. 59 0
      ex3/displayData.m
  56. 88 0
      ex3/ex3.m
  57. 91 0
      ex3/ex3_nn.m
  58. BIN
      ex3/ex3data1.mat
  59. BIN
      ex3/ex3weights.mat
  60. 175 0
      ex3/fmincg.m
  61. 6 0
      ex3/hypothesis.m
  62. 41 0
      ex3/lib/jsonlab/AUTHORS.txt
  63. 74 0
      ex3/lib/jsonlab/ChangeLog.txt
  64. 25 0
      ex3/lib/jsonlab/LICENSE_BSD.txt
  65. 394 0
      ex3/lib/jsonlab/README.txt
  66. 32 0
      ex3/lib/jsonlab/jsonopt.m
  67. 566 0
      ex3/lib/jsonlab/loadjson.m
  68. 528 0
      ex3/lib/jsonlab/loadubjson.m
  69. 33 0
      ex3/lib/jsonlab/mergestruct.m
  70. 475 0
      ex3/lib/jsonlab/savejson.m
  71. 504 0
      ex3/lib/jsonlab/saveubjson.m
  72. 40 0
      ex3/lib/jsonlab/varargin2struct.m
  73. 30 0
      ex3/lib/makeValidFieldName.m
  74. 179 0
      ex3/lib/submitWithConfiguration.m
  75. 56 0
      ex3/lrCostFunction.m
  76. 73 0
      ex3/oneVsAll.m
  77. 44 0
      ex3/predict.m
  78. 42 0
      ex3/predictOneVsAll.m
  79. 6 0
      ex3/sigmoid.m
  80. 56 0
      ex3/submit.m
  81. 52 0
      ex4/checkNNGradients.m
  82. 29 0
      ex4/computeNumericalGradient.m
  83. 26 0
      ex4/cost.m
  84. 22 0
      ex4/debugInitializeWeights.m
  85. 59 0
      ex4/displayData.m
  86. 234 0
      ex4/ex4.m
  87. BIN
      ex4/ex4data1.mat
  88. BIN
      ex4/ex4weights.mat
  89. 175 0
      ex4/fmincg.m
  90. 6 0
      ex4/hypothesis.m
  91. 41 0
      ex4/lib/jsonlab/AUTHORS.txt
  92. 74 0
      ex4/lib/jsonlab/ChangeLog.txt
  93. 25 0
      ex4/lib/jsonlab/LICENSE_BSD.txt
  94. 394 0
      ex4/lib/jsonlab/README.txt
  95. 32 0
      ex4/lib/jsonlab/jsonopt.m
  96. 566 0
      ex4/lib/jsonlab/loadjson.m
  97. 528 0
      ex4/lib/jsonlab/loadubjson.m
  98. 33 0
      ex4/lib/jsonlab/mergestruct.m
  99. 475 0
      ex4/lib/jsonlab/savejson.m
  100. 504 0
      ex4/lib/jsonlab/saveubjson.m

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+# tokens
+token.mat

+ 17 - 0
README.md

@@ -0,0 +1,17 @@
+## coursera machine learning exercise solutions
+
+### course infomation:
+
+https://www.coursera.org/learn/machine-learning/
+
+### content
+
+* [**Linear Regression**]
+
+* [**Logistic Regression**]
+* [**Multi-class Classification and Neural Networks**]
+* [**Neural Network Learning**]
+* [**Regularized Linear Regression and Bias/Variance**]
+* [**Support Vector Machines**]
+* [**K-Means Clustering and PCA**]
+* [**Anomaly Detection and Recommender Systems**]

+ 27 - 0
ex1/computeCost.m

@@ -0,0 +1,27 @@
+function J = computeCost(X, y, theta)
+%COMPUTECOST Compute cost for linear regression
+%   J = COMPUTECOST(X, y, theta) computes the cost of using theta as the
+%   parameter for linear regression to fit the data points in X and y
+
+% Initialize some useful values
+m = length(y); % number of training examples
+
+% You need to return the following variables correctly 
+% J = 0;
+% for i = 1:m
+	% J = J + (theta' * X(i,:)' - y(i)) ^ 2
+% end
+% J = J / m / 2	
+z = (X*theta-y);
+J = z' * z / 2 / m;
+% ====================== YOUR CODE HERE ======================
+% Instructions: Compute the cost of a particular choice of theta
+%               You should set J to the cost.
+
+
+
+
+
+% =========================================================================
+
+end

+ 25 - 0
ex1/computeCostMulti.m

@@ -0,0 +1,25 @@
+function J = computeCostMulti(X, y, theta)
+%COMPUTECOSTMULTI Compute cost for linear regression with multiple variables
+%   J = COMPUTECOSTMULTI(X, y, theta) computes the cost of using theta as the
+%   parameter for linear regression to fit the data points in X and y
+
+% Initialize some useful values
+m = length(y); % number of training examples
+
+% You need to return the following variables correctly 
+J = 0;
+
+z = (X*theta-y);
+J = z' * z / 2 / m;
+
+% ====================== YOUR CODE HERE ======================
+% Instructions: Compute the cost of a particular choice of theta
+%               You should set J to the cost.
+
+
+
+
+
+% =========================================================================
+
+end

+ 135 - 0
ex1/ex1.m

@@ -0,0 +1,135 @@
+%% Machine Learning Online Class - Exercise 1: Linear Regression
+
+%  Instructions
+%  ------------
+%
+%  This file contains code that helps you get started on the
+%  linear exercise. You will need to complete the following functions
+%  in this exericse:
+%
+%     warmUpExercise.m
+%     plotData.m
+%     gradientDescent.m
+%     computeCost.m
+%     gradientDescentMulti.m
+%     computeCostMulti.m
+%     featureNormalize.m
+%     normalEqn.m
+%
+%  For this exercise, you will not need to change any code in this file,
+%  or any other files other than those mentioned above.
+%
+% x refers to the population size in 10,000s
+% y refers to the profit in $10,000s
+%
+
+%% Initialization
+clear ; close all; clc
+
+%% ==================== Part 1: Basic Function ====================
+% Complete warmUpExercise.m
+fprintf('Running warmUpExercise ... \n');
+fprintf('5x5 Identity Matrix: \n');
+warmUpExercise()
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+
+
+%% ======================= Part 2: Plotting =======================
+fprintf('Plotting Data ...\n')
+data = load('ex1data1.txt');
+X = data(:, 1); y = data(:, 2);
+m = length(y); % number of training examples
+
+% Plot Data
+% Note: You have to complete the code in plotData.m
+plotData(X, y);
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+
+%% =================== Part 3: Cost and Gradient descent ===================
+
+X = [ones(m, 1), data(:,1)]; % Add a column of ones to x
+theta = zeros(2, 1); % initialize fitting parameters
+
+% Some gradient descent settings
+iterations = 1500;
+alpha = 0.01;
+
+fprintf('\nTesting the cost function ...\n')
+% compute and display initial cost
+J = computeCost(X, y, theta);
+fprintf('With theta = [0 ; 0]\nCost computed = %f\n', J);
+fprintf('Expected cost value (approx) 32.07\n');
+
+% further testing of the cost function
+J = computeCost(X, y, [-1 ; 2]);
+fprintf('\nWith theta = [-1 ; 2]\nCost computed = %f\n', J);
+fprintf('Expected cost value (approx) 54.24\n');
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+
+fprintf('\nRunning Gradient Descent ...\n')
+% run gradient descent
+theta = gradientDescent(X, y, theta, alpha, iterations);
+
+% print theta to screen
+fprintf('Theta found by gradient descent:\n');
+fprintf('%f\n', theta);
+fprintf('Expected theta values (approx)\n');
+fprintf(' -3.6303\n  1.1664\n\n');
+
+% Plot the linear fit
+hold on; % keep previous plot visible
+plot(X(:,2), X*theta, '-')
+legend('Training data', 'Linear regression')
+hold off % don't overlay any more plots on this figure
+
+% Predict values for population sizes of 35,000 and 70,000
+predict1 = [1, 3.5] *theta;
+fprintf('For population = 35,000, we predict a profit of %f\n',...
+    predict1*10000);
+predict2 = [1, 7] * theta;
+fprintf('For population = 70,000, we predict a profit of %f\n',...
+    predict2*10000);
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+
+%% ============= Part 4: Visualizing J(theta_0, theta_1) =============
+fprintf('Visualizing J(theta_0, theta_1) ...\n')
+
+% Grid over which we will calculate J
+theta0_vals = linspace(-10, 10, 100);
+theta1_vals = linspace(-1, 4, 100);
+
+% initialize J_vals to a matrix of 0's
+J_vals = zeros(length(theta0_vals), length(theta1_vals));
+
+% Fill out J_vals
+for i = 1:length(theta0_vals)
+    for j = 1:length(theta1_vals)
+	  t = [theta0_vals(i); theta1_vals(j)];
+	  J_vals(i,j) = computeCost(X, y, t);
+    end
+end
+
+
+% Because of the way meshgrids work in the surf command, we need to
+% transpose J_vals before calling surf, or else the axes will be flipped
+J_vals = J_vals';
+% Surface plot
+figure;
+surf(theta0_vals, theta1_vals, J_vals)
+xlabel('\theta_0'); ylabel('\theta_1');
+
+% Contour plot
+figure;
+% Plot J_vals as 15 contours spaced logarithmically between 0.01 and 100
+contour(theta0_vals, theta1_vals, J_vals, logspace(-2, 3, 20))
+xlabel('\theta_0'); ylabel('\theta_1');
+hold on;
+plot(theta(1), theta(2), 'rx', 'MarkerSize', 10, 'LineWidth', 2);

+ 159 - 0
ex1/ex1_multi.m

@@ -0,0 +1,159 @@
+%% Machine Learning Online Class
+%  Exercise 1: Linear regression with multiple variables
+%
+%  Instructions
+%  ------------
+% 
+%  This file contains code that helps you get started on the
+%  linear regression exercise. 
+%
+%  You will need to complete the following functions in this 
+%  exericse:
+%
+%     warmUpExercise.m
+%     plotData.m
+%     gradientDescent.m
+%     computeCost.m
+%     gradientDescentMulti.m
+%     computeCostMulti.m
+%     featureNormalize.m
+%     normalEqn.m
+%
+%  For this part of the exercise, you will need to change some
+%  parts of the code below for various experiments (e.g., changing
+%  learning rates).
+%
+
+%% Initialization
+
+%% ================ Part 1: Feature Normalization ================
+
+%% Clear and Close Figures
+clear ; close all; clc
+
+fprintf('Loading data ...\n');
+
+%% Load Data
+data = load('ex1data2.txt');
+X = data(:, 1:2);
+y = data(:, 3);
+m = length(y);
+
+% Print out some data points
+fprintf('First 10 examples from the dataset: \n');
+fprintf(' x = [%.0f %.0f], y = %.0f \n', [X(1:10,:) y(1:10,:)]');
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+
+% Scale features and set them to zero mean
+fprintf('Normalizing Features ...\n');
+
+[X mu sigma] = featureNormalize(X);
+
+% Add intercept term to X
+X = [ones(m, 1) X];
+
+
+%% ================ Part 2: Gradient Descent ================
+
+% ====================== YOUR CODE HERE ======================
+% Instructions: We have provided you with the following starter
+%               code that runs gradient descent with a particular
+%               learning rate (alpha). 
+%
+%               Your task is to first make sure that your functions - 
+%               computeCost and gradientDescent already work with 
+%               this starter code and support multiple variables.
+%
+%               After that, try running gradient descent with 
+%               different values of alpha and see which one gives
+%               you the best result.
+%
+%               Finally, you should complete the code at the end
+%               to predict the price of a 1650 sq-ft, 3 br house.
+%
+% Hint: By using the 'hold on' command, you can plot multiple
+%       graphs on the same figure.
+%
+% Hint: At prediction, make sure you do the same feature normalization.
+%
+
+fprintf('Running gradient descent ...\n');
+
+% Choose some alpha value
+alpha = 0.01;
+num_iters = 400;
+
+% Init Theta and Run Gradient Descent 
+theta = zeros(3, 1);
+[theta, J_history] = gradientDescentMulti(X, y, theta, alpha, num_iters);
+
+% Plot the convergence graph
+figure;
+plot(1:numel(J_history), J_history, '-b', 'LineWidth', 2);
+xlabel('Number of iterations');
+ylabel('Cost J');
+
+% Display gradient descent's result
+fprintf('Theta computed from gradient descent: \n');
+fprintf(' %f \n', theta);
+fprintf('\n');
+
+% Estimate the price of a 1650 sq-ft, 3 br house
+% ====================== YOUR CODE HERE ======================
+% Recall that the first column of X is all-ones. Thus, it does
+% not need to be normalized.
+price = 0; % You should change this
+
+
+% ============================================================
+
+fprintf(['Predicted price of a 1650 sq-ft, 3 br house ' ...
+         '(using gradient descent):\n $%f\n'], price);
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+
+%% ================ Part 3: Normal Equations ================
+
+fprintf('Solving with normal equations...\n');
+
+% ====================== YOUR CODE HERE ======================
+% Instructions: The following code computes the closed form 
+%               solution for linear regression using the normal
+%               equations. You should complete the code in 
+%               normalEqn.m
+%
+%               After doing so, you should complete this code 
+%               to predict the price of a 1650 sq-ft, 3 br house.
+%
+
+%% Load Data
+data = csvread('ex1data2.txt');
+X = data(:, 1:2);
+y = data(:, 3);
+m = length(y);
+
+% Add intercept term to X
+X = [ones(m, 1) X];
+
+% Calculate the parameters from the normal equation
+theta = normalEqn(X, y);
+
+% Display normal equation's result
+fprintf('Theta computed from the normal equations: \n');
+fprintf(' %f \n', theta);
+fprintf('\n');
+
+
+% Estimate the price of a 1650 sq-ft, 3 br house
+% ====================== YOUR CODE HERE ======================
+price = 0; % You should change this
+
+
+% ============================================================
+
+fprintf(['Predicted price of a 1650 sq-ft, 3 br house ' ...
+         '(using normal equations):\n $%f\n'], price);
+

+ 97 - 0
ex1/ex1data1.txt

@@ -0,0 +1,97 @@
+6.1101,17.592
+5.5277,9.1302
+8.5186,13.662
+7.0032,11.854
+5.8598,6.8233
+8.3829,11.886
+7.4764,4.3483
+8.5781,12
+6.4862,6.5987
+5.0546,3.8166
+5.7107,3.2522
+14.164,15.505
+5.734,3.1551
+8.4084,7.2258
+5.6407,0.71618
+5.3794,3.5129
+6.3654,5.3048
+5.1301,0.56077
+6.4296,3.6518
+7.0708,5.3893
+6.1891,3.1386
+20.27,21.767
+5.4901,4.263
+6.3261,5.1875
+5.5649,3.0825
+18.945,22.638
+12.828,13.501
+10.957,7.0467
+13.176,14.692
+22.203,24.147
+5.2524,-1.22
+6.5894,5.9966
+9.2482,12.134
+5.8918,1.8495
+8.2111,6.5426
+7.9334,4.5623
+8.0959,4.1164
+5.6063,3.3928
+12.836,10.117
+6.3534,5.4974
+5.4069,0.55657
+6.8825,3.9115
+11.708,5.3854
+5.7737,2.4406
+7.8247,6.7318
+7.0931,1.0463
+5.0702,5.1337
+5.8014,1.844
+11.7,8.0043
+5.5416,1.0179
+7.5402,6.7504
+5.3077,1.8396
+7.4239,4.2885
+7.6031,4.9981
+6.3328,1.4233
+6.3589,-1.4211
+6.2742,2.4756
+5.6397,4.6042
+9.3102,3.9624
+9.4536,5.4141
+8.8254,5.1694
+5.1793,-0.74279
+21.279,17.929
+14.908,12.054
+18.959,17.054
+7.2182,4.8852
+8.2951,5.7442
+10.236,7.7754
+5.4994,1.0173
+20.341,20.992
+10.136,6.6799
+7.3345,4.0259
+6.0062,1.2784
+7.2259,3.3411
+5.0269,-2.6807
+6.5479,0.29678
+7.5386,3.8845
+5.0365,5.7014
+10.274,6.7526
+5.1077,2.0576
+5.7292,0.47953
+5.1884,0.20421
+6.3557,0.67861
+9.7687,7.5435
+6.5159,5.3436
+8.5172,4.2415
+9.1802,6.7981
+6.002,0.92695
+5.5204,0.152
+5.0594,2.8214
+5.7077,1.8451
+7.6366,4.2959
+5.8707,7.2029
+5.3054,1.9869
+8.2934,0.14454
+13.394,9.0551
+5.4369,0.61705

+ 47 - 0
ex1/ex1data2.txt

@@ -0,0 +1,47 @@
+2104,3,399900
+1600,3,329900
+2400,3,369000
+1416,2,232000
+3000,4,539900
+1985,4,299900
+1534,3,314900
+1427,3,198999
+1380,3,212000
+1494,3,242500
+1940,4,239999
+2000,3,347000
+1890,3,329999
+4478,5,699900
+1268,3,259900
+2300,4,449900
+1320,2,299900
+1236,3,199900
+2609,4,499998
+3031,4,599000
+1767,3,252900
+1888,2,255000
+1604,3,242900
+1962,4,259900
+3890,3,573900
+1100,3,249900
+1458,3,464500
+2526,3,469000
+2200,3,475000
+2637,3,299900
+1839,2,349900
+1000,1,169900
+2040,4,314900
+3137,3,579900
+1811,4,285900
+1437,3,249900
+1239,3,229900
+2132,4,345000
+4215,4,549000
+2162,4,287000
+1664,2,368500
+2238,3,329900
+2567,4,314000
+1200,3,299000
+852,2,179900
+1852,4,299900
+1203,3,239500

+ 39 - 0
ex1/featureNormalize.m

@@ -0,0 +1,39 @@
+function [X_norm, mu, sigma] = featureNormalize(X)
+%FEATURENORMALIZE Normalizes the features in X 
+%   FEATURENORMALIZE(X) returns a normalized version of X where
+%   the mean value of each feature is 0 and the standard deviation
+%   is 1. This is often a good preprocessing step to do when
+%   working with learning algorithms.
+
+% You need to set these values correctly
+
+mu = mean(X);
+sigma = std(X);
+X_norm = (X - ones(length(X),1)*mu ) ./ (ones(length(X),1)*sigma);
+% ====================== YOUR CODE HERE ======================
+% Instructions: First, for each feature dimension, compute the mean
+%               of the feature and subtract it from the dataset,
+%               storing the mean value in mu. Next, compute the 
+%               standard deviation of each feature and divide
+%               each feature by it's standard deviation, storing
+%               the standard deviation in sigma. 
+%
+%               Note that X is a matrix where each column is a 
+%               feature and each row is an example. You need 
+%               to perform the normalization separately for 
+%               each feature. 
+%
+% Hint: You might find the 'mean' and 'std' functions useful.
+%       
+
+
+
+
+
+
+
+
+
+% ============================================================
+
+end

+ 29 - 0
ex1/gradientDescent.m

@@ -0,0 +1,29 @@
+function [theta, J_history] = gradientDescent(X, y, theta, alpha, num_iters)
+%GRADIENTDESCENT Performs gradient descent to learn theta
+%   theta = GRADIENTDESCENT(X, y, theta, alpha, num_iters) updates theta by 
+%   taking num_iters gradient steps with learning rate alpha
+
+% Initialize some useful values
+m = length(y); % number of training examples
+J_history = zeros(num_iters, 1);
+
+for iter = 1:num_iters
+    J_history(iter) = computeCost(X, y, theta);
+
+	
+	theta = theta - alpha / m * (X' * (X * theta - y));
+	
+	
+	
+end
+
+end
+    % ====================== YOUR CODE HERE ======================
+    % Instructions: Perform a single gradient step on the parameter vector
+    %               theta. 
+    %
+    % Hint: While debugging, it can be useful to print out the values
+    %       of the cost function (computeCost) and gradient here.
+    %
+    % ============================================================
+    % Save the cost J in every iteration    

+ 34 - 0
ex1/gradientDescentMulti.m

@@ -0,0 +1,34 @@
+function [theta, J_history] = gradientDescentMulti(X, y, theta, alpha, num_iters)
+%GRADIENTDESCENTMULTI Performs gradient descent to learn theta
+%   theta = GRADIENTDESCENTMULTI(x, y, theta, alpha, num_iters) updates theta by
+%   taking num_iters gradient steps with learning rate alpha
+
+% Initialize some useful values
+m = length(y); % number of training examples
+J_history = zeros(num_iters, 1);
+
+for iter = 1:num_iters
+
+    % ====================== YOUR CODE HERE ======================
+    % Instructions: Perform a single gradient step on the parameter vector
+    %               theta. 
+    %
+    % Hint: While debugging, it can be useful to print out the values
+    %       of the cost function (computeCostMulti) and gradient here.
+    %
+
+	
+	theta = theta - alpha / m * (X' * (X * theta - y));
+
+
+
+
+
+    % ============================================================
+
+    % Save the cost J in every iteration    
+    J_history(iter) = computeCostMulti(X, y, theta);
+
+end
+
+end

+ 41 - 0
ex1/lib/jsonlab/AUTHORS.txt

@@ -0,0 +1,41 @@
+The author of "jsonlab" toolbox is Qianqian Fang. Qianqian
+is currently an Assistant Professor at Massachusetts General Hospital, 
+Harvard Medical School.
+
+Address: Martinos Center for Biomedical Imaging, 
+         Massachusetts General Hospital, 
+         Harvard Medical School
+         Bldg 149, 13th St, Charlestown, MA 02129, USA
+URL: http://nmr.mgh.harvard.edu/~fangq/
+Email: <fangq at nmr.mgh.harvard.edu> or <fangqq at gmail.com>
+
+
+The script loadjson.m was built upon previous works by
+
+- Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
+       date: 2009/11/02
+- François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
+       date: 2009/03/22
+- Joel Feenstra: http://www.mathworks.com/matlabcentral/fileexchange/20565
+       date: 2008/07/03
+
+
+This toolbox contains patches submitted by the following contributors:
+
+- Blake Johnson <bjohnso at bbn.com>
+  part of revision 341
+
+- Niclas Borlin <Niclas.Borlin at cs.umu.se>
+  various fixes in revision 394, including
+  - loadjson crashes for all-zero sparse matrix.
+  - loadjson crashes for empty sparse matrix.
+  - Non-zero size of 0-by-N and N-by-0 empty matrices is lost after savejson/loadjson.
+  - loadjson crashes for sparse real column vector.
+  - loadjson crashes for sparse complex column vector.
+  - Data is corrupted by savejson for sparse real row vector.
+  - savejson crashes for sparse complex row vector. 
+
+- Yul Kang <yul.kang.on at gmail.com>
+  patches for svn revision 415.
+  - savejson saves an empty cell array as [] instead of null
+  - loadjson differentiates an empty struct from an empty array

+ 74 - 0
ex1/lib/jsonlab/ChangeLog.txt

@@ -0,0 +1,74 @@
+============================================================================
+
+   JSONlab - a toolbox to encode/decode JSON/UBJSON files in MATLAB/Octave
+
+----------------------------------------------------------------------------
+
+JSONlab ChangeLog (key features marked by *):
+
+== JSONlab 1.0 (codename: Optimus - Final), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2015/01/02 polish help info for all major functions, update examples, finalize 1.0
+ 2014/12/19 fix a bug to strictly respect NoRowBracket in savejson
+
+== JSONlab 1.0.0-RC2 (codename: Optimus - RC2), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2014/11/22 show progress bar in loadjson ('ShowProgress') 
+ 2014/11/17 add Compact option in savejson to output compact JSON format ('Compact')
+ 2014/11/17 add FastArrayParser in loadjson to specify fast parser applicable levels
+ 2014/09/18 start official github mirror: https://github.com/fangq/jsonlab
+
+== JSONlab 1.0.0-RC1 (codename: Optimus - RC1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2014/09/17  fix several compatibility issues when running on octave versions 3.2-3.8
+ 2014/09/17  support 2D cell and struct arrays in both savejson and saveubjson
+ 2014/08/04  escape special characters in a JSON string
+ 2014/02/16  fix a bug when saving ubjson files
+
+== JSONlab 0.9.9 (codename: Optimus - beta), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2014/01/22  use binary read and write in saveubjson and loadubjson
+
+== JSONlab 0.9.8-1 (codename: Optimus - alpha update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2013/10/07 better round-trip conservation for empty arrays and structs (patch submitted by Yul Kang)
+
+== JSONlab 0.9.8 (codename: Optimus - alpha), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+ 2013/08/23 *universal Binary JSON (UBJSON) support, including both saveubjson and loadubjson
+
+== JSONlab 0.9.1 (codename: Rodimus, update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+ 2012/12/18 *handling of various empty and sparse matrices (fixes submitted by Niclas Borlin)
+
+== JSONlab 0.9.0 (codename: Rodimus), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2012/06/17 *new format for an invalid leading char, unpacking hex code in savejson
+ 2012/06/01  support JSONP in savejson
+ 2012/05/25  fix the empty cell bug (reported by Cyril Davin)
+ 2012/04/05  savejson can save to a file (suggested by Patrick Rapin)
+
+== JSONlab 0.8.1 (codename: Sentiel, Update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2012/02/28  loadjson quotation mark escape bug, see http://bit.ly/yyk1nS
+ 2012/01/25  patch to handle root-less objects, contributed by Blake Johnson
+
+== JSONlab 0.8.0 (codename: Sentiel), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2012/01/13 *speed up loadjson by 20 fold when parsing large data arrays in matlab
+ 2012/01/11  remove row bracket if an array has 1 element, suggested by Mykel Kochenderfer
+ 2011/12/22 *accept sequence of 'param',value input in savejson and loadjson
+ 2011/11/18  fix struct array bug reported by Mykel Kochenderfer
+
+== JSONlab 0.5.1 (codename: Nexus Update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2011/10/21  fix a bug in loadjson, previous code does not use any of the acceleration
+ 2011/10/20  loadjson supports JSON collections - concatenated JSON objects
+
+== JSONlab 0.5.0 (codename: Nexus), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2011/10/16  package and release jsonlab 0.5.0
+ 2011/10/15 *add json demo and regression test, support cpx numbers, fix double quote bug
+ 2011/10/11 *speed up readjson dramatically, interpret _Array* tags, show data in root level
+ 2011/10/10  create jsonlab project, start jsonlab website, add online documentation
+ 2011/10/07 *speed up savejson by 25x using sprintf instead of mat2str, add options support
+ 2011/10/06 *savejson works for structs, cells and arrays
+ 2011/09/09  derive loadjson from JSON parser from MATLAB Central, draft savejson.m

+ 25 - 0
ex1/lib/jsonlab/LICENSE_BSD.txt

@@ -0,0 +1,25 @@
+Copyright 2011-2015 Qianqian Fang <fangq at nmr.mgh.harvard.edu>. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice, this list of
+      conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright notice, this list
+      of conditions and the following disclaimer in the documentation and/or other materials
+      provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those of the
+authors and should not be interpreted as representing official policies, either expressed
+or implied, of the copyright holders.

+ 394 - 0
ex1/lib/jsonlab/README.txt

@@ -0,0 +1,394 @@
+===============================================================================
+=                                 JSONLab                                     =
+=           An open-source MATLAB/Octave JSON encoder and decoder             =
+===============================================================================
+
+*Copyright (C) 2011-2015  Qianqian Fang <fangq at nmr.mgh.harvard.edu>
+*License: BSD License, see License_BSD.txt for details
+*Version: 1.0 (Optimus - Final)
+
+-------------------------------------------------------------------------------
+
+Table of Content:
+
+I.  Introduction
+II. Installation
+III.Using JSONLab
+IV. Known Issues and TODOs
+V.  Contribution and feedback
+
+-------------------------------------------------------------------------------
+
+I.  Introduction
+
+JSON ([http://www.json.org/ JavaScript Object Notation]) is a highly portable, 
+human-readable and "[http://en.wikipedia.org/wiki/JSON fat-free]" text format 
+to represent complex and hierarchical data. It is as powerful as 
+[http://en.wikipedia.org/wiki/XML XML], but less verbose. JSON format is widely 
+used for data-exchange in applications, and is essential for the wild success 
+of [http://en.wikipedia.org/wiki/Ajax_(programming) Ajax] and 
+[http://en.wikipedia.org/wiki/Web_2.0 Web2.0]. 
+
+UBJSON (Universal Binary JSON) is a binary JSON format, specifically 
+optimized for compact file size and better performance while keeping
+the semantics as simple as the text-based JSON format. Using the UBJSON
+format allows to wrap complex binary data in a flexible and extensible
+structure, making it possible to process complex and large dataset 
+without accuracy loss due to text conversions.
+
+We envision that both JSON and its binary version will serve as part of 
+the mainstream data-exchange formats for scientific research in the future. 
+It will provide the flexibility and generality achieved by other popular 
+general-purpose file specifications, such as
+[http://www.hdfgroup.org/HDF5/whatishdf5.html HDF5], with significantly 
+reduced complexity and enhanced performance.
+
+JSONLab is a free and open-source implementation of a JSON/UBJSON encoder 
+and a decoder in the native MATLAB language. It can be used to convert a MATLAB 
+data structure (array, struct, cell, struct array and cell array) into 
+JSON/UBJSON formatted strings, or to decode a JSON/UBJSON file into MATLAB 
+data structure. JSONLab supports both MATLAB and  
+[http://www.gnu.org/software/octave/ GNU Octave] (a free MATLAB clone).
+
+-------------------------------------------------------------------------------
+
+II. Installation
+
+The installation of JSONLab is no different than any other simple
+MATLAB toolbox. You only need to download/unzip the JSONLab package
+to a folder, and add the folder's path to MATLAB/Octave's path list
+by using the following command:
+
+    addpath('/path/to/jsonlab');
+
+If you want to add this path permanently, you need to type "pathtool", 
+browse to the jsonlab root folder and add to the list, then click "Save".
+Then, run "rehash" in MATLAB, and type "which loadjson", if you see an 
+output, that means JSONLab is installed for MATLAB/Octave.
+
+-------------------------------------------------------------------------------
+
+III.Using JSONLab
+
+JSONLab provides two functions, loadjson.m -- a MATLAB->JSON decoder, 
+and savejson.m -- a MATLAB->JSON encoder, for the text-based JSON, and 
+two equivallent functions -- loadubjson and saveubjson for the binary 
+JSON. The detailed help info for the four functions can be found below:
+
+=== loadjson.m ===
+<pre>
+  data=loadjson(fname,opt)
+     or
+  data=loadjson(fname,'param1',value1,'param2',value2,...)
+ 
+  parse a JSON (JavaScript Object Notation) file or string
+ 
+  authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2011/09/09, including previous works from 
+ 
+          Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
+             created on 2009/11/02
+          François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
+             created on  2009/03/22
+          Joel Feenstra:
+          http://www.mathworks.com/matlabcentral/fileexchange/20565
+             created on 2008/07/03
+ 
+  $Id: loadjson.m 452 2014-11-22 16:43:33Z fangq $
+ 
+  input:
+       fname: input file name, if fname contains "{}" or "[]", fname
+              will be interpreted as a JSON string
+       opt: a struct to store parsing options, opt can be replaced by 
+            a list of ('param',value) pairs - the param string is equivallent
+            to a field in opt. opt can have the following 
+            fields (first in [.|.] is the default)
+ 
+            opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat
+                          for each element of the JSON data, and group 
+                          arrays based on the cell2mat rules.
+            opt.FastArrayParser [1|0 or integer]: if set to 1, use a
+                          speed-optimized array parser when loading an 
+                          array object. The fast array parser may 
+                          collapse block arrays into a single large
+                          array similar to rules defined in cell2mat; 0 to 
+                          use a legacy parser; if set to a larger-than-1
+                          value, this option will specify the minimum
+                          dimension to enable the fast array parser. For
+                          example, if the input is a 3D array, setting
+                          FastArrayParser to 1 will return a 3D array;
+                          setting to 2 will return a cell array of 2D
+                          arrays; setting to 3 will return to a 2D cell
+                          array of 1D vectors; setting to 4 will return a
+                          3D cell array.
+            opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar.
+ 
+  output:
+       dat: a cell array, where {...} blocks are converted into cell arrays,
+            and [...] are converted to arrays
+ 
+  examples:
+       dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}')
+       dat=loadjson(['examples' filesep 'example1.json'])
+       dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1)
+</pre>
+
+=== savejson.m ===
+
+<pre>
+  json=savejson(rootname,obj,filename)
+     or
+  json=savejson(rootname,obj,opt)
+  json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
+ 
+  convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
+  Object Notation) string
+ 
+  author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2011/09/09
+ 
+  $Id: savejson.m 458 2014-12-19 22:17:17Z fangq $
+ 
+  input:
+       rootname: the name of the root-object, when set to '', the root name
+         is ignored, however, when opt.ForceRootName is set to 1 (see below),
+         the MATLAB variable name will be used as the root name.
+       obj: a MATLAB object (array, cell, cell array, struct, struct array).
+       filename: a string for the file name to save the output JSON data.
+       opt: a struct for additional options, ignore to use default values.
+         opt can have the following fields (first in [.|.] is the default)
+ 
+         opt.FileName [''|string]: a file name to save the output JSON data
+         opt.FloatFormat ['%.10g'|string]: format to show each numeric element
+                          of a 1D/2D array;
+         opt.ArrayIndent [1|0]: if 1, output explicit data array with
+                          precedent indentation; if 0, no indentation
+         opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
+                          array in JSON array format; if sets to 1, an
+                          array will be shown as a struct with fields
+                          "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+                          sparse arrays, the non-zero elements will be
+                          saved to _ArrayData_ field in triplet-format i.e.
+                          (ix,iy,val) and "_ArrayIsSparse_" will be added
+                          with a value of 1; for a complex array, the 
+                          _ArrayData_ array will include two columns 
+                          (4 for sparse) to record the real and imaginary 
+                          parts, and also "_ArrayIsComplex_":1 is added. 
+         opt.ParseLogical [0|1]: if this is set to 1, logical array elem
+                          will use true/false rather than 1/0.
+         opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+                          numerical element will be shown without a square
+                          bracket, unless it is the root object; if 0, square
+                          brackets are forced for any numerical arrays.
+         opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
+                          will use the name of the passed obj variable as the 
+                          root object name; if obj is an expression and 
+                          does not have a name, 'root' will be used; if this 
+                          is set to 0 and rootname is empty, the root level 
+                          will be merged down to the lower level.
+         opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
+                          to represent +/-Inf. The matched pattern is '([-+]*)Inf'
+                          and $1 represents the sign. For those who want to use
+                          1e999 to represent Inf, they can set opt.Inf to '$11e999'
+         opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
+                          to represent NaN
+         opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+                          for example, if opt.JSONP='foo', the JSON data is
+                          wrapped inside a function call as 'foo(...);'
+         opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+                          back to the string form
+         opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
+         opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs)
+ 
+         opt can be replaced by a list of ('param',value) pairs. The param 
+         string is equivallent to a field in opt and is case sensitive.
+  output:
+       json: a string in the JSON format (see http://json.org)
+ 
+  examples:
+       jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+                'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+                'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+                           2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+                'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+                'SpecialData',[nan, inf, -inf]);
+       savejson('jmesh',jsonmesh)
+       savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g')
+ </pre>
+
+=== loadubjson.m ===
+
+<pre>
+  data=loadubjson(fname,opt)
+     or
+  data=loadubjson(fname,'param1',value1,'param2',value2,...)
+ 
+  parse a JSON (JavaScript Object Notation) file or string
+ 
+  authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2013/08/01
+ 
+  $Id: loadubjson.m 436 2014-08-05 20:51:40Z fangq $
+ 
+  input:
+       fname: input file name, if fname contains "{}" or "[]", fname
+              will be interpreted as a UBJSON string
+       opt: a struct to store parsing options, opt can be replaced by 
+            a list of ('param',value) pairs - the param string is equivallent
+            to a field in opt. opt can have the following 
+            fields (first in [.|.] is the default)
+ 
+            opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
+                          for each element of the JSON data, and group 
+                          arrays based on the cell2mat rules.
+            opt.IntEndian [B|L]: specify the endianness of the integer fields
+                          in the UBJSON input data. B - Big-Endian format for 
+                          integers (as required in the UBJSON specification); 
+                          L - input integer fields are in Little-Endian order.
+ 
+  output:
+       dat: a cell array, where {...} blocks are converted into cell arrays,
+            and [...] are converted to arrays
+ 
+  examples:
+       obj=struct('string','value','array',[1 2 3]);
+       ubjdata=saveubjson('obj',obj);
+       dat=loadubjson(ubjdata)
+       dat=loadubjson(['examples' filesep 'example1.ubj'])
+       dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)
+</pre>
+
+=== saveubjson.m ===
+
+<pre>
+  json=saveubjson(rootname,obj,filename)
+     or
+  json=saveubjson(rootname,obj,opt)
+  json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
+ 
+  convert a MATLAB object (cell, struct or array) into a Universal 
+  Binary JSON (UBJSON) binary string
+ 
+  author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2013/08/17
+ 
+  $Id: saveubjson.m 440 2014-09-17 19:59:45Z fangq $
+ 
+  input:
+       rootname: the name of the root-object, when set to '', the root name
+         is ignored, however, when opt.ForceRootName is set to 1 (see below),
+         the MATLAB variable name will be used as the root name.
+       obj: a MATLAB object (array, cell, cell array, struct, struct array)
+       filename: a string for the file name to save the output UBJSON data
+       opt: a struct for additional options, ignore to use default values.
+         opt can have the following fields (first in [.|.] is the default)
+ 
+         opt.FileName [''|string]: a file name to save the output JSON data
+         opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
+                          array in JSON array format; if sets to 1, an
+                          array will be shown as a struct with fields
+                          "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+                          sparse arrays, the non-zero elements will be
+                          saved to _ArrayData_ field in triplet-format i.e.
+                          (ix,iy,val) and "_ArrayIsSparse_" will be added
+                          with a value of 1; for a complex array, the 
+                          _ArrayData_ array will include two columns 
+                          (4 for sparse) to record the real and imaginary 
+                          parts, and also "_ArrayIsComplex_":1 is added. 
+         opt.ParseLogical [1|0]: if this is set to 1, logical array elem
+                          will use true/false rather than 1/0.
+         opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+                          numerical element will be shown without a square
+                          bracket, unless it is the root object; if 0, square
+                          brackets are forced for any numerical arrays.
+         opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
+                          will use the name of the passed obj variable as the 
+                          root object name; if obj is an expression and 
+                          does not have a name, 'root' will be used; if this 
+                          is set to 0 and rootname is empty, the root level 
+                          will be merged down to the lower level.
+         opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+                          for example, if opt.JSON='foo', the JSON data is
+                          wrapped inside a function call as 'foo(...);'
+         opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+                          back to the string form
+ 
+         opt can be replaced by a list of ('param',value) pairs. The param 
+         string is equivallent to a field in opt and is case sensitive.
+  output:
+       json: a binary string in the UBJSON format (see http://ubjson.org)
+ 
+  examples:
+       jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+                'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+                'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+                           2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+                'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+                'SpecialData',[nan, inf, -inf]);
+       saveubjson('jsonmesh',jsonmesh)
+       saveubjson('jsonmesh',jsonmesh,'meshdata.ubj')
+</pre>
+
+
+=== examples ===
+
+Under the "examples" folder, you can find several scripts to demonstrate the
+basic utilities of JSONLab. Running the "demo_jsonlab_basic.m" script, you 
+will see the conversions from MATLAB data structure to JSON text and backward.
+In "jsonlab_selftest.m", we load complex JSON files downloaded from the Internet
+and validate the loadjson/savejson functions for regression testing purposes.
+Similarly, a "demo_ubjson_basic.m" script is provided to test the saveubjson
+and loadubjson pairs for various matlab data structures.
+
+Please run these examples and understand how JSONLab works before you use
+it to process your data.
+
+-------------------------------------------------------------------------------
+
+IV. Known Issues and TODOs
+
+JSONLab has several known limitations. We are striving to make it more general
+and robust. Hopefully in a few future releases, the limitations become less.
+
+Here are the known issues:
+
+# 3D or higher dimensional cell/struct-arrays will be converted to 2D arrays;
+# When processing names containing multi-byte characters, Octave and MATLAB \
+can give different field-names; you can use feature('DefaultCharacterSet','latin1') \
+in MATLAB to get consistant results
+# savejson can not handle class and dataset.
+# saveubjson converts a logical array into a uint8 ([U]) array
+# an unofficial N-D array count syntax is implemented in saveubjson. We are \
+actively communicating with the UBJSON spec maintainer to investigate the \
+possibility of making it upstream
+# loadubjson can not parse all UBJSON Specification (Draft 9) compliant \
+files, however, it can parse all UBJSON files produced by saveubjson.
+
+-------------------------------------------------------------------------------
+
+V. Contribution and feedback
+
+JSONLab is an open-source project. This means you can not only use it and modify
+it as you wish, but also you can contribute your changes back to JSONLab so
+that everyone else can enjoy the improvement. For anyone who want to contribute,
+please download JSONLab source code from it's subversion repository by using the
+following command:
+
+ svn checkout svn://svn.code.sf.net/p/iso2mesh/code/trunk/jsonlab jsonlab
+
+You can make changes to the files as needed. Once you are satisfied with your
+changes, and ready to share it with others, please cd the root directory of 
+JSONLab, and type
+
+ svn diff > yourname_featurename.patch
+
+You then email the .patch file to JSONLab's maintainer, Qianqian Fang, at
+the email address shown in the beginning of this file. Qianqian will review 
+the changes and commit it to the subversion if they are satisfactory.
+
+We appreciate any suggestions and feedbacks from you. Please use iso2mesh's
+mailing list to report any questions you may have with JSONLab:
+
+http://groups.google.com/group/iso2mesh-users?hl=en&pli=1
+
+(Subscription to the mailing list is needed in order to post messages).

+ 32 - 0
ex1/lib/jsonlab/jsonopt.m

@@ -0,0 +1,32 @@
+function val=jsonopt(key,default,varargin)
+%
+% val=jsonopt(key,default,optstruct)
+%
+% setting options based on a struct. The struct can be produced
+% by varargin2struct from a list of 'param','value' pairs
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+%
+% $Id: loadjson.m 371 2012-06-20 12:43:06Z fangq $
+%
+% input:
+%      key: a string with which one look up a value from a struct
+%      default: if the key does not exist, return default
+%      optstruct: a struct where each sub-field is a key 
+%
+% output:
+%      val: if key exists, val=optstruct.key; otherwise val=default
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details
+%
+% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+% 
+
+val=default;
+if(nargin<=2) return; end
+opt=varargin{1};
+if(isstruct(opt) && isfield(opt,key))
+    val=getfield(opt,key);
+end
+

+ 566 - 0
ex1/lib/jsonlab/loadjson.m

@@ -0,0 +1,566 @@
+function data = loadjson(fname,varargin)
+%
+% data=loadjson(fname,opt)
+%    or
+% data=loadjson(fname,'param1',value1,'param2',value2,...)
+%
+% parse a JSON (JavaScript Object Notation) file or string
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2011/09/09, including previous works from 
+%
+%         Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
+%            created on 2009/11/02
+%         François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
+%            created on  2009/03/22
+%         Joel Feenstra:
+%         http://www.mathworks.com/matlabcentral/fileexchange/20565
+%            created on 2008/07/03
+%
+% $Id: loadjson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      fname: input file name, if fname contains "{}" or "[]", fname
+%             will be interpreted as a JSON string
+%      opt: a struct to store parsing options, opt can be replaced by 
+%           a list of ('param',value) pairs - the param string is equivallent
+%           to a field in opt. opt can have the following 
+%           fields (first in [.|.] is the default)
+%
+%           opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat
+%                         for each element of the JSON data, and group 
+%                         arrays based on the cell2mat rules.
+%           opt.FastArrayParser [1|0 or integer]: if set to 1, use a
+%                         speed-optimized array parser when loading an 
+%                         array object. The fast array parser may 
+%                         collapse block arrays into a single large
+%                         array similar to rules defined in cell2mat; 0 to 
+%                         use a legacy parser; if set to a larger-than-1
+%                         value, this option will specify the minimum
+%                         dimension to enable the fast array parser. For
+%                         example, if the input is a 3D array, setting
+%                         FastArrayParser to 1 will return a 3D array;
+%                         setting to 2 will return a cell array of 2D
+%                         arrays; setting to 3 will return to a 2D cell
+%                         array of 1D vectors; setting to 4 will return a
+%                         3D cell array.
+%           opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar.
+%
+% output:
+%      dat: a cell array, where {...} blocks are converted into cell arrays,
+%           and [...] are converted to arrays
+%
+% examples:
+%      dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}')
+%      dat=loadjson(['examples' filesep 'example1.json'])
+%      dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1)
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details 
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+global pos inStr len  esc index_esc len_esc isoct arraytoken
+
+if(regexp(fname,'[\{\}\]\[]','once'))
+   string=fname;
+elseif(exist(fname,'file'))
+   fid = fopen(fname,'rb');
+   string = fread(fid,inf,'uint8=>char')';
+   fclose(fid);
+else
+   error('input file does not exist');
+end
+
+pos = 1; len = length(string); inStr = string;
+isoct=exist('OCTAVE_VERSION','builtin');
+arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
+jstr=regexprep(inStr,'\\\\','  ');
+escquote=regexp(jstr,'\\"');
+arraytoken=sort([arraytoken escquote]);
+
+% String delimiters and escape chars identified to improve speed:
+esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
+index_esc = 1; len_esc = length(esc);
+
+opt=varargin2struct(varargin{:});
+
+if(jsonopt('ShowProgress',0,opt)==1)
+    opt.progressbar_=waitbar(0,'loading ...');
+end
+jsoncount=1;
+while pos <= len
+    switch(next_char)
+        case '{'
+            data{jsoncount} = parse_object(opt);
+        case '['
+            data{jsoncount} = parse_array(opt);
+        otherwise
+            error_pos('Outer level structure must be an object or an array');
+    end
+    jsoncount=jsoncount+1;
+end % while
+
+jsoncount=length(data);
+if(jsoncount==1 && iscell(data))
+    data=data{1};
+end
+
+if(~isempty(data))
+      if(isstruct(data)) % data can be a struct array
+          data=jstruct2array(data);
+      elseif(iscell(data))
+          data=jcell2array(data);
+      end
+end
+if(isfield(opt,'progressbar_'))
+    close(opt.progressbar_);
+end
+
+%%
+function newdata=jcell2array(data)
+len=length(data);
+newdata=data;
+for i=1:len
+      if(isstruct(data{i}))
+          newdata{i}=jstruct2array(data{i});
+      elseif(iscell(data{i}))
+          newdata{i}=jcell2array(data{i});
+      end
+end
+
+%%-------------------------------------------------------------------------
+function newdata=jstruct2array(data)
+fn=fieldnames(data);
+newdata=data;
+len=length(data);
+for i=1:length(fn) % depth-first
+    for j=1:len
+        if(isstruct(getfield(data(j),fn{i})))
+            newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
+        end
+    end
+end
+if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
+  newdata=cell(len,1);
+  for j=1:len
+    ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
+    iscpx=0;
+    if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
+        if(data(j).x0x5F_ArrayIsComplex_)
+           iscpx=1;
+        end
+    end
+    if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
+        if(data(j).x0x5F_ArrayIsSparse_)
+            if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+                dim=data(j).x0x5F_ArraySize_;
+                if(iscpx && size(ndata,2)==4-any(dim==1))
+                    ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
+                end
+                if isempty(ndata)
+                    % All-zeros sparse
+                    ndata=sparse(dim(1),prod(dim(2:end)));
+                elseif dim(1)==1
+                    % Sparse row vector
+                    ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
+                elseif dim(2)==1
+                    % Sparse column vector
+                    ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
+                else
+                    % Generic sparse array.
+                    ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
+                end
+            else
+                if(iscpx && size(ndata,2)==4)
+                    ndata(:,3)=complex(ndata(:,3),ndata(:,4));
+                end
+                ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
+            end
+        end
+    elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+        if(iscpx && size(ndata,2)==2)
+             ndata=complex(ndata(:,1),ndata(:,2));
+        end
+        ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
+    end
+    newdata{j}=ndata;
+  end
+  if(len==1)
+      newdata=newdata{1};
+  end
+end
+
+%%-------------------------------------------------------------------------
+function object = parse_object(varargin)
+    parse_char('{');
+    object = [];
+    if next_char ~= '}'
+        while 1
+            str = parseStr(varargin{:});
+            if isempty(str)
+                error_pos('Name of value at position %d cannot be empty');
+            end
+            parse_char(':');
+            val = parse_value(varargin{:});
+            eval( sprintf( 'object.%s  = val;', valid_field(str) ) );
+            if next_char == '}'
+                break;
+            end
+            parse_char(',');
+        end
+    end
+    parse_char('}');
+
+%%-------------------------------------------------------------------------
+
+function object = parse_array(varargin) % JSON array is written in row-major order
+global pos inStr isoct
+    parse_char('[');
+    object = cell(0, 1);
+    dim2=[];
+    arraydepth=jsonopt('JSONLAB_ArrayDepth_',1,varargin{:});
+    pbar=jsonopt('progressbar_',-1,varargin{:});
+
+    if next_char ~= ']'
+	if(jsonopt('FastArrayParser',1,varargin{:})>=1 && arraydepth>=jsonopt('FastArrayParser',1,varargin{:}))
+            [endpos, e1l, e1r, maxlevel]=matching_bracket(inStr,pos);
+            arraystr=['[' inStr(pos:endpos)];
+            arraystr=regexprep(arraystr,'"_NaN_"','NaN');
+            arraystr=regexprep(arraystr,'"([-+]*)_Inf_"','$1Inf');
+            arraystr(arraystr==sprintf('\n'))=[];
+            arraystr(arraystr==sprintf('\r'))=[];
+            %arraystr=regexprep(arraystr,'\s*,',','); % this is slow,sometimes needed
+            if(~isempty(e1l) && ~isempty(e1r)) % the array is in 2D or higher D
+        	astr=inStr((e1l+1):(e1r-1));
+        	astr=regexprep(astr,'"_NaN_"','NaN');
+        	astr=regexprep(astr,'"([-+]*)_Inf_"','$1Inf');
+        	astr(astr==sprintf('\n'))=[];
+        	astr(astr==sprintf('\r'))=[];
+        	astr(astr==' ')='';
+        	if(isempty(find(astr=='[', 1))) % array is 2D
+                    dim2=length(sscanf(astr,'%f,',[1 inf]));
+        	end
+            else % array is 1D
+        	astr=arraystr(2:end-1);
+        	astr(astr==' ')='';
+        	[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',[1,inf]);
+        	if(nextidx>=length(astr)-1)
+                    object=obj;
+                    pos=endpos;
+                    parse_char(']');
+                    return;
+        	end
+            end
+            if(~isempty(dim2))
+        	astr=arraystr;
+        	astr(astr=='[')='';
+        	astr(astr==']')='';
+        	astr(astr==' ')='';
+        	[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',inf);
+        	if(nextidx>=length(astr)-1)
+                    object=reshape(obj,dim2,numel(obj)/dim2)';
+                    pos=endpos;
+                    parse_char(']');
+                    if(pbar>0)
+                        waitbar(pos/length(inStr),pbar,'loading ...');
+                    end
+                    return;
+        	end
+            end
+            arraystr=regexprep(arraystr,'\]\s*,','];');
+	else
+            arraystr='[';
+	end
+        try
+           if(isoct && regexp(arraystr,'"','once'))
+                error('Octave eval can produce empty cells for JSON-like input');
+           end
+           object=eval(arraystr);
+           pos=endpos;
+        catch
+         while 1
+            newopt=varargin2struct(varargin{:},'JSONLAB_ArrayDepth_',arraydepth+1);
+            val = parse_value(newopt);
+            object{end+1} = val;
+            if next_char == ']'
+                break;
+            end
+            parse_char(',');
+         end
+        end
+    end
+    if(jsonopt('SimplifyCell',0,varargin{:})==1)
+      try
+        oldobj=object;
+        object=cell2mat(object')';
+        if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
+            object=oldobj;
+        elseif(size(object,1)>1 && ndims(object)==2)
+            object=object';
+        end
+      catch
+      end
+    end
+    parse_char(']');
+    
+    if(pbar>0)
+        waitbar(pos/length(inStr),pbar,'loading ...');
+    end
+%%-------------------------------------------------------------------------
+
+function parse_char(c)
+    global pos inStr len
+    skip_whitespace;
+    if pos > len || inStr(pos) ~= c
+        error_pos(sprintf('Expected %c at position %%d', c));
+    else
+        pos = pos + 1;
+        skip_whitespace;
+    end
+
+%%-------------------------------------------------------------------------
+
+function c = next_char
+    global pos inStr len
+    skip_whitespace;
+    if pos > len
+        c = [];
+    else
+        c = inStr(pos);
+    end
+
+%%-------------------------------------------------------------------------
+
+function skip_whitespace
+    global pos inStr len
+    while pos <= len && isspace(inStr(pos))
+        pos = pos + 1;
+    end
+
+%%-------------------------------------------------------------------------
+function str = parseStr(varargin)
+    global pos inStr len  esc index_esc len_esc
+ % len, ns = length(inStr), keyboard
+    if inStr(pos) ~= '"'
+        error_pos('String starting with " expected at position %d');
+    else
+        pos = pos + 1;
+    end
+    str = '';
+    while pos <= len
+        while index_esc <= len_esc && esc(index_esc) < pos
+            index_esc = index_esc + 1;
+        end
+        if index_esc > len_esc
+            str = [str inStr(pos:len)];
+            pos = len + 1;
+            break;
+        else
+            str = [str inStr(pos:esc(index_esc)-1)];
+            pos = esc(index_esc);
+        end
+        nstr = length(str); switch inStr(pos)
+            case '"'
+                pos = pos + 1;
+                if(~isempty(str))
+                    if(strcmp(str,'_Inf_'))
+                        str=Inf;
+                    elseif(strcmp(str,'-_Inf_'))
+                        str=-Inf;
+                    elseif(strcmp(str,'_NaN_'))
+                        str=NaN;
+                    end
+                end
+                return;
+            case '\'
+                if pos+1 > len
+                    error_pos('End of file reached right after escape character');
+                end
+                pos = pos + 1;
+                switch inStr(pos)
+                    case {'"' '\' '/'}
+                        str(nstr+1) = inStr(pos);
+                        pos = pos + 1;
+                    case {'b' 'f' 'n' 'r' 't'}
+                        str(nstr+1) = sprintf(['\' inStr(pos)]);
+                        pos = pos + 1;
+                    case 'u'
+                        if pos+4 > len
+                            error_pos('End of file reached in escaped unicode character');
+                        end
+                        str(nstr+(1:6)) = inStr(pos-1:pos+4);
+                        pos = pos + 5;
+                end
+            otherwise % should never happen
+                str(nstr+1) = inStr(pos), keyboard
+                pos = pos + 1;
+        end
+    end
+    error_pos('End of file while expecting end of inStr');
+
+%%-------------------------------------------------------------------------
+
+function num = parse_number(varargin)
+    global pos inStr len isoct
+    currstr=inStr(pos:end);
+    numstr=0;
+    if(isoct~=0)
+        numstr=regexp(currstr,'^\s*-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?','end');
+        [num, one] = sscanf(currstr, '%f', 1);
+        delta=numstr+1;
+    else
+        [num, one, err, delta] = sscanf(currstr, '%f', 1);
+        if ~isempty(err)
+            error_pos('Error reading number at position %d');
+        end
+    end
+    pos = pos + delta-1;
+
+%%-------------------------------------------------------------------------
+
+function val = parse_value(varargin)
+    global pos inStr len
+    true = 1; false = 0;
+    
+    pbar=jsonopt('progressbar_',-1,varargin{:});
+    if(pbar>0)
+        waitbar(pos/len,pbar,'loading ...');
+    end
+    
+    switch(inStr(pos))
+        case '"'
+            val = parseStr(varargin{:});
+            return;
+        case '['
+            val = parse_array(varargin{:});
+            return;
+        case '{'
+            val = parse_object(varargin{:});
+            if isstruct(val)
+                if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
+                    val=jstruct2array(val);
+                end
+            elseif isempty(val)
+                val = struct;
+            end
+            return;
+        case {'-','0','1','2','3','4','5','6','7','8','9'}
+            val = parse_number(varargin{:});
+            return;
+        case 't'
+            if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'true')
+                val = true;
+                pos = pos + 4;
+                return;
+            end
+        case 'f'
+            if pos+4 <= len && strcmpi(inStr(pos:pos+4), 'false')
+                val = false;
+                pos = pos + 5;
+                return;
+            end
+        case 'n'
+            if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'null')
+                val = [];
+                pos = pos + 4;
+                return;
+            end
+    end
+    error_pos('Value expected at position %d');
+%%-------------------------------------------------------------------------
+
+function error_pos(msg)
+    global pos inStr len
+    poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
+    if poShow(3) == poShow(2)
+        poShow(3:4) = poShow(2)+[0 -1];  % display nothing after
+    end
+    msg = [sprintf(msg, pos) ': ' ...
+    inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
+    error( ['JSONparser:invalidFormat: ' msg] );
+
+%%-------------------------------------------------------------------------
+
+function str = valid_field(str)
+global isoct
+% From MATLAB doc: field names must begin with a letter, which may be
+% followed by any combination of letters, digits, and underscores.
+% Invalid characters will be converted to underscores, and the prefix
+% "x0x[Hex code]_" will be added if the first character is not a letter.
+    pos=regexp(str,'^[^A-Za-z]','once');
+    if(~isempty(pos))
+        if(~isoct)
+            str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
+        else
+            str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
+        end
+    end
+    if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return;  end
+    if(~isoct)
+        str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
+    else
+        pos=regexp(str,'[^0-9A-Za-z_]');
+        if(isempty(pos)) return; end
+        str0=str;
+        pos0=[0 pos(:)' length(str)];
+        str='';
+        for i=1:length(pos)
+            str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
+        end
+        if(pos(end)~=length(str))
+            str=[str str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+    %str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
+
+%%-------------------------------------------------------------------------
+function endpos = matching_quote(str,pos)
+len=length(str);
+while(pos<len)
+    if(str(pos)=='"')
+        if(~(pos>1 && str(pos-1)=='\'))
+            endpos=pos;
+            return;
+        end        
+    end
+    pos=pos+1;
+end
+error('unmatched quotation mark');
+%%-------------------------------------------------------------------------
+function [endpos, e1l, e1r, maxlevel] = matching_bracket(str,pos)
+global arraytoken
+level=1;
+maxlevel=level;
+endpos=0;
+bpos=arraytoken(arraytoken>=pos);
+tokens=str(bpos);
+len=length(tokens);
+pos=1;
+e1l=[];
+e1r=[];
+while(pos<=len)
+    c=tokens(pos);
+    if(c==']')
+        level=level-1;
+        if(isempty(e1r)) e1r=bpos(pos); end
+        if(level==0)
+            endpos=bpos(pos);
+            return
+        end
+    end
+    if(c=='[')
+        if(isempty(e1l)) e1l=bpos(pos); end
+        level=level+1;
+        maxlevel=max(maxlevel,level);
+    end
+    if(c=='"')
+        pos=matching_quote(tokens,pos+1);
+    end
+    pos=pos+1;
+end
+if(endpos==0) 
+    error('unmatched "]"');
+end
+

+ 528 - 0
ex1/lib/jsonlab/loadubjson.m

@@ -0,0 +1,528 @@
+function data = loadubjson(fname,varargin)
+%
+% data=loadubjson(fname,opt)
+%    or
+% data=loadubjson(fname,'param1',value1,'param2',value2,...)
+%
+% parse a JSON (JavaScript Object Notation) file or string
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2013/08/01
+%
+% $Id: loadubjson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      fname: input file name, if fname contains "{}" or "[]", fname
+%             will be interpreted as a UBJSON string
+%      opt: a struct to store parsing options, opt can be replaced by 
+%           a list of ('param',value) pairs - the param string is equivallent
+%           to a field in opt. opt can have the following 
+%           fields (first in [.|.] is the default)
+%
+%           opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
+%                         for each element of the JSON data, and group 
+%                         arrays based on the cell2mat rules.
+%           opt.IntEndian [B|L]: specify the endianness of the integer fields
+%                         in the UBJSON input data. B - Big-Endian format for 
+%                         integers (as required in the UBJSON specification); 
+%                         L - input integer fields are in Little-Endian order.
+%
+% output:
+%      dat: a cell array, where {...} blocks are converted into cell arrays,
+%           and [...] are converted to arrays
+%
+% examples:
+%      obj=struct('string','value','array',[1 2 3]);
+%      ubjdata=saveubjson('obj',obj);
+%      dat=loadubjson(ubjdata)
+%      dat=loadubjson(['examples' filesep 'example1.ubj'])
+%      dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details 
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+global pos inStr len  esc index_esc len_esc isoct arraytoken fileendian systemendian
+
+if(regexp(fname,'[\{\}\]\[]','once'))
+   string=fname;
+elseif(exist(fname,'file'))
+   fid = fopen(fname,'rb');
+   string = fread(fid,inf,'uint8=>char')';
+   fclose(fid);
+else
+   error('input file does not exist');
+end
+
+pos = 1; len = length(string); inStr = string;
+isoct=exist('OCTAVE_VERSION','builtin');
+arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
+jstr=regexprep(inStr,'\\\\','  ');
+escquote=regexp(jstr,'\\"');
+arraytoken=sort([arraytoken escquote]);
+
+% String delimiters and escape chars identified to improve speed:
+esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
+index_esc = 1; len_esc = length(esc);
+
+opt=varargin2struct(varargin{:});
+fileendian=upper(jsonopt('IntEndian','B',opt));
+[os,maxelem,systemendian]=computer;
+
+jsoncount=1;
+while pos <= len
+    switch(next_char)
+        case '{'
+            data{jsoncount} = parse_object(opt);
+        case '['
+            data{jsoncount} = parse_array(opt);
+        otherwise
+            error_pos('Outer level structure must be an object or an array');
+    end
+    jsoncount=jsoncount+1;
+end % while
+
+jsoncount=length(data);
+if(jsoncount==1 && iscell(data))
+    data=data{1};
+end
+
+if(~isempty(data))
+      if(isstruct(data)) % data can be a struct array
+          data=jstruct2array(data);
+      elseif(iscell(data))
+          data=jcell2array(data);
+      end
+end
+
+
+%%
+function newdata=parse_collection(id,data,obj)
+
+if(jsoncount>0 && exist('data','var')) 
+    if(~iscell(data))
+       newdata=cell(1);
+       newdata{1}=data;
+       data=newdata;
+    end
+end
+
+%%
+function newdata=jcell2array(data)
+len=length(data);
+newdata=data;
+for i=1:len
+      if(isstruct(data{i}))
+          newdata{i}=jstruct2array(data{i});
+      elseif(iscell(data{i}))
+          newdata{i}=jcell2array(data{i});
+      end
+end
+
+%%-------------------------------------------------------------------------
+function newdata=jstruct2array(data)
+fn=fieldnames(data);
+newdata=data;
+len=length(data);
+for i=1:length(fn) % depth-first
+    for j=1:len
+        if(isstruct(getfield(data(j),fn{i})))
+            newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
+        end
+    end
+end
+if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
+  newdata=cell(len,1);
+  for j=1:len
+    ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
+    iscpx=0;
+    if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
+        if(data(j).x0x5F_ArrayIsComplex_)
+           iscpx=1;
+        end
+    end
+    if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
+        if(data(j).x0x5F_ArrayIsSparse_)
+            if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+                dim=double(data(j).x0x5F_ArraySize_);
+                if(iscpx && size(ndata,2)==4-any(dim==1))
+                    ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
+                end
+                if isempty(ndata)
+                    % All-zeros sparse
+                    ndata=sparse(dim(1),prod(dim(2:end)));
+                elseif dim(1)==1
+                    % Sparse row vector
+                    ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
+                elseif dim(2)==1
+                    % Sparse column vector
+                    ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
+                else
+                    % Generic sparse array.
+                    ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
+                end
+            else
+                if(iscpx && size(ndata,2)==4)
+                    ndata(:,3)=complex(ndata(:,3),ndata(:,4));
+                end
+                ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
+            end
+        end
+    elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+        if(iscpx && size(ndata,2)==2)
+             ndata=complex(ndata(:,1),ndata(:,2));
+        end
+        ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
+    end
+    newdata{j}=ndata;
+  end
+  if(len==1)
+      newdata=newdata{1};
+  end
+end
+
+%%-------------------------------------------------------------------------
+function object = parse_object(varargin)
+    parse_char('{');
+    object = [];
+    type='';
+    count=-1;
+    if(next_char == '$')
+        type=inStr(pos+1); % TODO
+        pos=pos+2;
+    end
+    if(next_char == '#')
+        pos=pos+1;
+        count=double(parse_number());
+    end
+    if next_char ~= '}'
+        num=0;
+        while 1
+            str = parseStr(varargin{:});
+            if isempty(str)
+                error_pos('Name of value at position %d cannot be empty');
+            end
+            %parse_char(':');
+            val = parse_value(varargin{:});
+            num=num+1;
+            eval( sprintf( 'object.%s  = val;', valid_field(str) ) );
+            if next_char == '}' || (count>=0 && num>=count)
+                break;
+            end
+            %parse_char(',');
+        end
+    end
+    if(count==-1)
+        parse_char('}');
+    end
+
+%%-------------------------------------------------------------------------
+function [cid,len]=elem_info(type)
+id=strfind('iUIlLdD',type);
+dataclass={'int8','uint8','int16','int32','int64','single','double'};
+bytelen=[1,1,2,4,8,4,8];
+if(id>0)
+    cid=dataclass{id};
+    len=bytelen(id);
+else
+    error_pos('unsupported type at position %d');
+end
+%%-------------------------------------------------------------------------
+
+
+function [data adv]=parse_block(type,count,varargin)
+global pos inStr isoct fileendian systemendian
+[cid,len]=elem_info(type);
+datastr=inStr(pos:pos+len*count-1);
+if(isoct)
+    newdata=int8(datastr);
+else
+    newdata=uint8(datastr);
+end
+id=strfind('iUIlLdD',type);
+if(id<=5 && fileendian~=systemendian)
+    newdata=swapbytes(typecast(newdata,cid));
+end
+data=typecast(newdata,cid);
+adv=double(len*count);
+
+%%-------------------------------------------------------------------------
+
+
+function object = parse_array(varargin) % JSON array is written in row-major order
+global pos inStr isoct
+    parse_char('[');
+    object = cell(0, 1);
+    dim=[];
+    type='';
+    count=-1;
+    if(next_char == '$')
+        type=inStr(pos+1);
+        pos=pos+2;
+    end
+    if(next_char == '#')
+        pos=pos+1;
+        if(next_char=='[')
+            dim=parse_array(varargin{:});
+            count=prod(double(dim));
+        else
+            count=double(parse_number());
+        end
+    end
+    if(~isempty(type))
+        if(count>=0)
+            [object adv]=parse_block(type,count,varargin{:});
+            if(~isempty(dim))
+                object=reshape(object,dim);
+            end
+            pos=pos+adv;
+            return;
+        else
+            endpos=matching_bracket(inStr,pos);
+            [cid,len]=elem_info(type);
+            count=(endpos-pos)/len;
+            [object adv]=parse_block(type,count,varargin{:});
+            pos=pos+adv;
+            parse_char(']');
+            return;
+        end
+    end
+    if next_char ~= ']'
+         while 1
+            val = parse_value(varargin{:});
+            object{end+1} = val;
+            if next_char == ']'
+                break;
+            end
+            %parse_char(',');
+         end
+    end
+    if(jsonopt('SimplifyCell',0,varargin{:})==1)
+      try
+        oldobj=object;
+        object=cell2mat(object')';
+        if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
+            object=oldobj;
+        elseif(size(object,1)>1 && ndims(object)==2)
+            object=object';
+        end
+      catch
+      end
+    end
+    if(count==-1)
+        parse_char(']');
+    end
+
+%%-------------------------------------------------------------------------
+
+function parse_char(c)
+    global pos inStr len
+    skip_whitespace;
+    if pos > len || inStr(pos) ~= c
+        error_pos(sprintf('Expected %c at position %%d', c));
+    else
+        pos = pos + 1;
+        skip_whitespace;
+    end
+
+%%-------------------------------------------------------------------------
+
+function c = next_char
+    global pos inStr len
+    skip_whitespace;
+    if pos > len
+        c = [];
+    else
+        c = inStr(pos);
+    end
+
+%%-------------------------------------------------------------------------
+
+function skip_whitespace
+    global pos inStr len
+    while pos <= len && isspace(inStr(pos))
+        pos = pos + 1;
+    end
+
+%%-------------------------------------------------------------------------
+function str = parseStr(varargin)
+    global pos inStr esc index_esc len_esc
+ % len, ns = length(inStr), keyboard
+    type=inStr(pos);
+    if type ~= 'S' && type ~= 'C' && type ~= 'H'
+        error_pos('String starting with S expected at position %d');
+    else
+        pos = pos + 1;
+    end
+    if(type == 'C')
+        str=inStr(pos);
+        pos=pos+1;
+        return;
+    end
+    bytelen=double(parse_number());
+    if(length(inStr)>=pos+bytelen-1)
+        str=inStr(pos:pos+bytelen-1);
+        pos=pos+bytelen;
+    else
+        error_pos('End of file while expecting end of inStr');
+    end
+
+%%-------------------------------------------------------------------------
+
+function num = parse_number(varargin)
+    global pos inStr len isoct fileendian systemendian
+    id=strfind('iUIlLdD',inStr(pos));
+    if(isempty(id))
+        error_pos('expecting a number at position %d');
+    end
+    type={'int8','uint8','int16','int32','int64','single','double'};
+    bytelen=[1,1,2,4,8,4,8];
+    datastr=inStr(pos+1:pos+bytelen(id));
+    if(isoct)
+        newdata=int8(datastr);
+    else
+        newdata=uint8(datastr);
+    end
+    if(id<=5 && fileendian~=systemendian)
+        newdata=swapbytes(typecast(newdata,type{id}));
+    end
+    num=typecast(newdata,type{id});
+    pos = pos + bytelen(id)+1;
+
+%%-------------------------------------------------------------------------
+
+function val = parse_value(varargin)
+    global pos inStr len
+    true = 1; false = 0;
+
+    switch(inStr(pos))
+        case {'S','C','H'}
+            val = parseStr(varargin{:});
+            return;
+        case '['
+            val = parse_array(varargin{:});
+            return;
+        case '{'
+            val = parse_object(varargin{:});
+            if isstruct(val)
+                if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
+                    val=jstruct2array(val);
+                end
+            elseif isempty(val)
+                val = struct;
+            end
+            return;
+        case {'i','U','I','l','L','d','D'}
+            val = parse_number(varargin{:});
+            return;
+        case 'T'
+            val = true;
+            pos = pos + 1;
+            return;
+        case 'F'
+            val = false;
+            pos = pos + 1;
+            return;
+        case {'Z','N'}
+            val = [];
+            pos = pos + 1;
+            return;
+    end
+    error_pos('Value expected at position %d');
+%%-------------------------------------------------------------------------
+
+function error_pos(msg)
+    global pos inStr len
+    poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
+    if poShow(3) == poShow(2)
+        poShow(3:4) = poShow(2)+[0 -1];  % display nothing after
+    end
+    msg = [sprintf(msg, pos) ': ' ...
+    inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
+    error( ['JSONparser:invalidFormat: ' msg] );
+
+%%-------------------------------------------------------------------------
+
+function str = valid_field(str)
+global isoct
+% From MATLAB doc: field names must begin with a letter, which may be
+% followed by any combination of letters, digits, and underscores.
+% Invalid characters will be converted to underscores, and the prefix
+% "x0x[Hex code]_" will be added if the first character is not a letter.
+    pos=regexp(str,'^[^A-Za-z]','once');
+    if(~isempty(pos))
+        if(~isoct)
+            str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
+        else
+            str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
+        end
+    end
+    if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return;  end
+    if(~isoct)
+        str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
+    else
+        pos=regexp(str,'[^0-9A-Za-z_]');
+        if(isempty(pos)) return; end
+        str0=str;
+        pos0=[0 pos(:)' length(str)];
+        str='';
+        for i=1:length(pos)
+            str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
+        end
+        if(pos(end)~=length(str))
+            str=[str str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+    %str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
+
+%%-------------------------------------------------------------------------
+function endpos = matching_quote(str,pos)
+len=length(str);
+while(pos<len)
+    if(str(pos)=='"')
+        if(~(pos>1 && str(pos-1)=='\'))
+            endpos=pos;
+            return;
+        end        
+    end
+    pos=pos+1;
+end
+error('unmatched quotation mark');
+%%-------------------------------------------------------------------------
+function [endpos e1l e1r maxlevel] = matching_bracket(str,pos)
+global arraytoken
+level=1;
+maxlevel=level;
+endpos=0;
+bpos=arraytoken(arraytoken>=pos);
+tokens=str(bpos);
+len=length(tokens);
+pos=1;
+e1l=[];
+e1r=[];
+while(pos<=len)
+    c=tokens(pos);
+    if(c==']')
+        level=level-1;
+        if(isempty(e1r)) e1r=bpos(pos); end
+        if(level==0)
+            endpos=bpos(pos);
+            return
+        end
+    end
+    if(c=='[')
+        if(isempty(e1l)) e1l=bpos(pos); end
+        level=level+1;
+        maxlevel=max(maxlevel,level);
+    end
+    if(c=='"')
+        pos=matching_quote(tokens,pos+1);
+    end
+    pos=pos+1;
+end
+if(endpos==0) 
+    error('unmatched "]"');
+end
+

+ 33 - 0
ex1/lib/jsonlab/mergestruct.m

@@ -0,0 +1,33 @@
+function s=mergestruct(s1,s2)
+%
+% s=mergestruct(s1,s2)
+%
+% merge two struct objects into one
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% date: 2012/12/22
+%
+% input:
+%      s1,s2: a struct object, s1 and s2 can not be arrays
+%
+% output:
+%      s: the merged struct object. fields in s1 and s2 will be combined in s.
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details 
+%
+% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+if(~isstruct(s1) || ~isstruct(s2))
+    error('input parameters contain non-struct');
+end
+if(length(s1)>1 || length(s2)>1)
+    error('can not merge struct arrays');
+end
+fn=fieldnames(s2);
+s=s1;
+for i=1:length(fn)              
+    s=setfield(s,fn{i},getfield(s2,fn{i}));
+end
+

+ 475 - 0
ex1/lib/jsonlab/savejson.m

@@ -0,0 +1,475 @@
+function json=savejson(rootname,obj,varargin)
+%
+% json=savejson(rootname,obj,filename)
+%    or
+% json=savejson(rootname,obj,opt)
+% json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
+%
+% convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
+% Object Notation) string
+%
+% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2011/09/09
+%
+% $Id: savejson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      rootname: the name of the root-object, when set to '', the root name
+%        is ignored, however, when opt.ForceRootName is set to 1 (see below),
+%        the MATLAB variable name will be used as the root name.
+%      obj: a MATLAB object (array, cell, cell array, struct, struct array).
+%      filename: a string for the file name to save the output JSON data.
+%      opt: a struct for additional options, ignore to use default values.
+%        opt can have the following fields (first in [.|.] is the default)
+%
+%        opt.FileName [''|string]: a file name to save the output JSON data
+%        opt.FloatFormat ['%.10g'|string]: format to show each numeric element
+%                         of a 1D/2D array;
+%        opt.ArrayIndent [1|0]: if 1, output explicit data array with
+%                         precedent indentation; if 0, no indentation
+%        opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
+%                         array in JSON array format; if sets to 1, an
+%                         array will be shown as a struct with fields
+%                         "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+%                         sparse arrays, the non-zero elements will be
+%                         saved to _ArrayData_ field in triplet-format i.e.
+%                         (ix,iy,val) and "_ArrayIsSparse_" will be added
+%                         with a value of 1; for a complex array, the 
+%                         _ArrayData_ array will include two columns 
+%                         (4 for sparse) to record the real and imaginary 
+%                         parts, and also "_ArrayIsComplex_":1 is added. 
+%        opt.ParseLogical [0|1]: if this is set to 1, logical array elem
+%                         will use true/false rather than 1/0.
+%        opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+%                         numerical element will be shown without a square
+%                         bracket, unless it is the root object; if 0, square
+%                         brackets are forced for any numerical arrays.
+%        opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
+%                         will use the name of the passed obj variable as the 
+%                         root object name; if obj is an expression and 
+%                         does not have a name, 'root' will be used; if this 
+%                         is set to 0 and rootname is empty, the root level 
+%                         will be merged down to the lower level.
+%        opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
+%                         to represent +/-Inf. The matched pattern is '([-+]*)Inf'
+%                         and $1 represents the sign. For those who want to use
+%                         1e999 to represent Inf, they can set opt.Inf to '$11e999'
+%        opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
+%                         to represent NaN
+%        opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+%                         for example, if opt.JSONP='foo', the JSON data is
+%                         wrapped inside a function call as 'foo(...);'
+%        opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+%                         back to the string form
+%        opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
+%        opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs)
+%
+%        opt can be replaced by a list of ('param',value) pairs. The param 
+%        string is equivallent to a field in opt and is case sensitive.
+% output:
+%      json: a string in the JSON format (see http://json.org)
+%
+% examples:
+%      jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+%               'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+%               'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+%                          2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+%               'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+%               'SpecialData',[nan, inf, -inf]);
+%      savejson('jmesh',jsonmesh)
+%      savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g')
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+if(nargin==1)
+   varname=inputname(1);
+   obj=rootname;
+   if(isempty(varname)) 
+      varname='root';
+   end
+   rootname=varname;
+else
+   varname=inputname(2);
+end
+if(length(varargin)==1 && ischar(varargin{1}))
+   opt=struct('FileName',varargin{1});
+else
+   opt=varargin2struct(varargin{:});
+end
+opt.IsOctave=exist('OCTAVE_VERSION','builtin');
+rootisarray=0;
+rootlevel=1;
+forceroot=jsonopt('ForceRootName',0,opt);
+if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)
+    rootisarray=1;
+    rootlevel=0;
+else
+    if(isempty(rootname))
+        rootname=varname;
+    end
+end
+if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
+    rootname='root';
+end
+
+whitespaces=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+if(jsonopt('Compact',0,opt)==1)
+    whitespaces=struct('tab','','newline','','sep',',');
+end
+if(~isfield(opt,'whitespaces_'))
+    opt.whitespaces_=whitespaces;
+end
+
+nl=whitespaces.newline;
+
+json=obj2json(rootname,obj,rootlevel,opt);
+if(rootisarray)
+    json=sprintf('%s%s',json,nl);
+else
+    json=sprintf('{%s%s%s}\n',nl,json,nl);
+end
+
+jsonp=jsonopt('JSONP','',opt);
+if(~isempty(jsonp))
+    json=sprintf('%s(%s);%s',jsonp,json,nl);
+end
+
+% save to a file if FileName is set, suggested by Patrick Rapin
+if(~isempty(jsonopt('FileName','',opt)))
+    if(jsonopt('SaveBinary',0,opt)==1)
+	    fid = fopen(opt.FileName, 'wb');
+	    fwrite(fid,json);
+    else
+	    fid = fopen(opt.FileName, 'wt');
+	    fwrite(fid,json,'char');
+    end
+    fclose(fid);
+end
+
+%%-------------------------------------------------------------------------
+function txt=obj2json(name,item,level,varargin)
+
+if(iscell(item))
+    txt=cell2json(name,item,level,varargin{:});
+elseif(isstruct(item))
+    txt=struct2json(name,item,level,varargin{:});
+elseif(ischar(item))
+    txt=str2json(name,item,level,varargin{:});
+else
+    txt=mat2json(name,item,level,varargin{:});
+end
+
+%%-------------------------------------------------------------------------
+function txt=cell2json(name,item,level,varargin)
+txt='';
+if(~iscell(item))
+        error('input is not a cell');
+end
+
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item);
+ws=jsonopt('whitespaces_',struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n')),varargin{:});
+padding0=repmat(ws.tab,1,level);
+padding2=repmat(ws.tab,1,level+1);
+nl=ws.newline;
+if(len>1)
+    if(~isempty(name))
+        txt=sprintf('%s"%s": [%s',padding0, checkname(name,varargin{:}),nl); name=''; 
+    else
+        txt=sprintf('%s[%s',padding0,nl); 
+    end
+elseif(len==0)
+    if(~isempty(name))
+        txt=sprintf('%s"%s": []',padding0, checkname(name,varargin{:})); name=''; 
+    else
+        txt=sprintf('%s[]',padding0); 
+    end
+end
+for j=1:dim(2)
+    if(dim(1)>1) txt=sprintf('%s%s[%s',txt,padding2,nl); end
+    for i=1:dim(1)
+       txt=sprintf('%s%s',txt,obj2json(name,item{i,j},level+(dim(1)>1)+1,varargin{:}));
+       if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+    end
+    if(dim(1)>1) txt=sprintf('%s%s%s]',txt,nl,padding2); end
+    if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+    %if(j==dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+end
+if(len>1) txt=sprintf('%s%s%s]',txt,nl,padding0); end
+
+%%-------------------------------------------------------------------------
+function txt=struct2json(name,item,level,varargin)
+txt='';
+if(~isstruct(item))
+	error('input is not a struct');
+end
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item);
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+padding0=repmat(ws.tab,1,level);
+padding2=repmat(ws.tab,1,level+1);
+padding1=repmat(ws.tab,1,level+(dim(1)>1)+(len>1));
+nl=ws.newline;
+
+if(~isempty(name)) 
+    if(len>1) txt=sprintf('%s"%s": [%s',padding0,checkname(name,varargin{:}),nl); end
+else
+    if(len>1) txt=sprintf('%s[%s',padding0,nl); end
+end
+for j=1:dim(2)
+  if(dim(1)>1) txt=sprintf('%s%s[%s',txt,padding2,nl); end
+  for i=1:dim(1)
+    names = fieldnames(item(i,j));
+    if(~isempty(name) && len==1)
+        txt=sprintf('%s%s"%s": {%s',txt,padding1, checkname(name,varargin{:}),nl); 
+    else
+        txt=sprintf('%s%s{%s',txt,padding1,nl); 
+    end
+    if(~isempty(names))
+      for e=1:length(names)
+	    txt=sprintf('%s%s',txt,obj2json(names{e},getfield(item(i,j),...
+             names{e}),level+(dim(1)>1)+1+(len>1),varargin{:}));
+        if(e<length(names)) txt=sprintf('%s%s',txt,','); end
+        txt=sprintf('%s%s',txt,nl);
+      end
+    end
+    txt=sprintf('%s%s}',txt,padding1);
+    if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+  end
+  if(dim(1)>1) txt=sprintf('%s%s%s]',txt,nl,padding2); end
+  if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+end
+if(len>1) txt=sprintf('%s%s%s]',txt,nl,padding0); end
+
+%%-------------------------------------------------------------------------
+function txt=str2json(name,item,level,varargin)
+txt='';
+if(~ischar(item))
+        error('input is not a string');
+end
+item=reshape(item, max(size(item),[1 0]));
+len=size(item,1);
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+padding1=repmat(ws.tab,1,level);
+padding0=repmat(ws.tab,1,level+1);
+nl=ws.newline;
+sep=ws.sep;
+
+if(~isempty(name)) 
+    if(len>1) txt=sprintf('%s"%s": [%s',padding1,checkname(name,varargin{:}),nl); end
+else
+    if(len>1) txt=sprintf('%s[%s',padding1,nl); end
+end
+isoct=jsonopt('IsOctave',0,varargin{:});
+for e=1:len
+    if(isoct)
+        val=regexprep(item(e,:),'\\','\\');
+        val=regexprep(val,'"','\"');
+        val=regexprep(val,'^"','\"');
+    else
+        val=regexprep(item(e,:),'\\','\\\\');
+        val=regexprep(val,'"','\\"');
+        val=regexprep(val,'^"','\\"');
+    end
+    val=escapejsonstring(val);
+    if(len==1)
+        obj=['"' checkname(name,varargin{:}) '": ' '"',val,'"'];
+	if(isempty(name)) obj=['"',val,'"']; end
+        txt=sprintf('%s%s%s%s',txt,padding1,obj);
+    else
+        txt=sprintf('%s%s%s%s',txt,padding0,['"',val,'"']);
+    end
+    if(e==len) sep=''; end
+    txt=sprintf('%s%s',txt,sep);
+end
+if(len>1) txt=sprintf('%s%s%s%s',txt,nl,padding1,']'); end
+
+%%-------------------------------------------------------------------------
+function txt=mat2json(name,item,level,varargin)
+if(~isnumeric(item) && ~islogical(item))
+        error('input is not an array');
+end
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+padding1=repmat(ws.tab,1,level);
+padding0=repmat(ws.tab,1,level+1);
+nl=ws.newline;
+sep=ws.sep;
+
+if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
+   isempty(item) ||jsonopt('ArrayToStruct',0,varargin{:}))
+    if(isempty(name))
+    	txt=sprintf('%s{%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',...
+              padding1,nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl);
+    else
+    	txt=sprintf('%s"%s": {%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',...
+              padding1,checkname(name,varargin{:}),nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl);
+    end
+else
+    if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1 && level>0)
+        numtxt=regexprep(regexprep(matdata2json(item,level+1,varargin{:}),'^\[',''),']','');
+    else
+        numtxt=matdata2json(item,level+1,varargin{:});
+    end
+    if(isempty(name))
+    	txt=sprintf('%s%s',padding1,numtxt);
+    else
+        if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
+           	txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);
+        else
+    	    txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);
+        end
+    end
+    return;
+end
+dataformat='%s%s%s%s%s';
+
+if(issparse(item))
+    [ix,iy]=find(item);
+    data=full(item(find(item)));
+    if(~isreal(item))
+       data=[real(data(:)),imag(data(:))];
+       if(size(item,1)==1)
+           % Kludge to have data's 'transposedness' match item's.
+           % (Necessary for complex row vector handling below.)
+           data=data';
+       end
+       txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep);
+    end
+    txt=sprintf(dataformat,txt,padding0,'"_ArrayIsSparse_": ','1', sep);
+    if(size(item,1)==1)
+        % Row vector, store only column indices.
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+           matdata2json([iy(:),data'],level+2,varargin{:}), nl);
+    elseif(size(item,2)==1)
+        % Column vector, store only row indices.
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+           matdata2json([ix,data],level+2,varargin{:}), nl);
+    else
+        % General case, store row and column indices.
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+           matdata2json([ix,iy,data],level+2,varargin{:}), nl);
+    end
+else
+    if(isreal(item))
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+            matdata2json(item(:)',level+2,varargin{:}), nl);
+    else
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep);
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+            matdata2json([real(item(:)) imag(item(:))],level+2,varargin{:}), nl);
+    end
+end
+txt=sprintf('%s%s%s',txt,padding1,'}');
+
+%%-------------------------------------------------------------------------
+function txt=matdata2json(mat,level,varargin)
+
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+tab=ws.tab;
+nl=ws.newline;
+
+if(size(mat,1)==1)
+    pre='';
+    post='';
+    level=level-1;
+else
+    pre=sprintf('[%s',nl);
+    post=sprintf('%s%s]',nl,repmat(tab,1,level-1));
+end
+
+if(isempty(mat))
+    txt='null';
+    return;
+end
+floatformat=jsonopt('FloatFormat','%.10g',varargin{:});
+%if(numel(mat)>1)
+    formatstr=['[' repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf('],%s',nl)]];
+%else
+%    formatstr=[repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf(',\n')]];
+%end
+
+if(nargin>=2 && size(mat,1)>1 && jsonopt('ArrayIndent',1,varargin{:})==1)
+    formatstr=[repmat(tab,1,level) formatstr];
+end
+
+txt=sprintf(formatstr,mat');
+txt(end-length(nl):end)=[];
+if(islogical(mat) && jsonopt('ParseLogical',0,varargin{:})==1)
+   txt=regexprep(txt,'1','true');
+   txt=regexprep(txt,'0','false');
+end
+%txt=regexprep(mat2str(mat),'\s+',',');
+%txt=regexprep(txt,';',sprintf('],\n['));
+% if(nargin>=2 && size(mat,1)>1)
+%     txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
+% end
+txt=[pre txt post];
+if(any(isinf(mat(:))))
+    txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
+end
+if(any(isnan(mat(:))))
+    txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
+end
+
+%%-------------------------------------------------------------------------
+function newname=checkname(name,varargin)
+isunpack=jsonopt('UnpackHex',1,varargin{:});
+newname=name;
+if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
+    return
+end
+if(isunpack)
+    isoct=jsonopt('IsOctave',0,varargin{:});
+    if(~isoct)
+        newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
+    else
+        pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
+        pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
+        if(isempty(pos)) return; end
+        str0=name;
+        pos0=[0 pend(:)' length(name)];
+        newname='';
+        for i=1:length(pos)
+            newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
+        end
+        if(pos(end)~=length(name))
+            newname=[newname str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+end
+
+%%-------------------------------------------------------------------------
+function newstr=escapejsonstring(str)
+newstr=str;
+isoct=exist('OCTAVE_VERSION','builtin');
+if(isoct)
+   vv=sscanf(OCTAVE_VERSION,'%f');
+   if(vv(1)>=3.8) isoct=0; end
+end
+if(isoct)
+  escapechars={'\a','\f','\n','\r','\t','\v'};
+  for i=1:length(escapechars);
+    newstr=regexprep(newstr,escapechars{i},escapechars{i});
+  end
+else
+  escapechars={'\a','\b','\f','\n','\r','\t','\v'};
+  for i=1:length(escapechars);
+    newstr=regexprep(newstr,escapechars{i},regexprep(escapechars{i},'\\','\\\\'));
+  end
+end

+ 504 - 0
ex1/lib/jsonlab/saveubjson.m

@@ -0,0 +1,504 @@
+function json=saveubjson(rootname,obj,varargin)
+%
+% json=saveubjson(rootname,obj,filename)
+%    or
+% json=saveubjson(rootname,obj,opt)
+% json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
+%
+% convert a MATLAB object (cell, struct or array) into a Universal 
+% Binary JSON (UBJSON) binary string
+%
+% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2013/08/17
+%
+% $Id: saveubjson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      rootname: the name of the root-object, when set to '', the root name
+%        is ignored, however, when opt.ForceRootName is set to 1 (see below),
+%        the MATLAB variable name will be used as the root name.
+%      obj: a MATLAB object (array, cell, cell array, struct, struct array)
+%      filename: a string for the file name to save the output UBJSON data
+%      opt: a struct for additional options, ignore to use default values.
+%        opt can have the following fields (first in [.|.] is the default)
+%
+%        opt.FileName [''|string]: a file name to save the output JSON data
+%        opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
+%                         array in JSON array format; if sets to 1, an
+%                         array will be shown as a struct with fields
+%                         "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+%                         sparse arrays, the non-zero elements will be
+%                         saved to _ArrayData_ field in triplet-format i.e.
+%                         (ix,iy,val) and "_ArrayIsSparse_" will be added
+%                         with a value of 1; for a complex array, the 
+%                         _ArrayData_ array will include two columns 
+%                         (4 for sparse) to record the real and imaginary 
+%                         parts, and also "_ArrayIsComplex_":1 is added. 
+%        opt.ParseLogical [1|0]: if this is set to 1, logical array elem
+%                         will use true/false rather than 1/0.
+%        opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+%                         numerical element will be shown without a square
+%                         bracket, unless it is the root object; if 0, square
+%                         brackets are forced for any numerical arrays.
+%        opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
+%                         will use the name of the passed obj variable as the 
+%                         root object name; if obj is an expression and 
+%                         does not have a name, 'root' will be used; if this 
+%                         is set to 0 and rootname is empty, the root level 
+%                         will be merged down to the lower level.
+%        opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+%                         for example, if opt.JSON='foo', the JSON data is
+%                         wrapped inside a function call as 'foo(...);'
+%        opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+%                         back to the string form
+%
+%        opt can be replaced by a list of ('param',value) pairs. The param 
+%        string is equivallent to a field in opt and is case sensitive.
+% output:
+%      json: a binary string in the UBJSON format (see http://ubjson.org)
+%
+% examples:
+%      jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+%               'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+%               'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+%                          2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+%               'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+%               'SpecialData',[nan, inf, -inf]);
+%      saveubjson('jsonmesh',jsonmesh)
+%      saveubjson('jsonmesh',jsonmesh,'meshdata.ubj')
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+if(nargin==1)
+   varname=inputname(1);
+   obj=rootname;
+   if(isempty(varname)) 
+      varname='root';
+   end
+   rootname=varname;
+else
+   varname=inputname(2);
+end
+if(length(varargin)==1 && ischar(varargin{1}))
+   opt=struct('FileName',varargin{1});
+else
+   opt=varargin2struct(varargin{:});
+end
+opt.IsOctave=exist('OCTAVE_VERSION','builtin');
+rootisarray=0;
+rootlevel=1;
+forceroot=jsonopt('ForceRootName',0,opt);
+if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)
+    rootisarray=1;
+    rootlevel=0;
+else
+    if(isempty(rootname))
+        rootname=varname;
+    end
+end
+if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
+    rootname='root';
+end
+json=obj2ubjson(rootname,obj,rootlevel,opt);
+if(~rootisarray)
+    json=['{' json '}'];
+end
+
+jsonp=jsonopt('JSONP','',opt);
+if(~isempty(jsonp))
+    json=[jsonp '(' json ')'];
+end
+
+% save to a file if FileName is set, suggested by Patrick Rapin
+if(~isempty(jsonopt('FileName','',opt)))
+    fid = fopen(opt.FileName, 'wb');
+    fwrite(fid,json);
+    fclose(fid);
+end
+
+%%-------------------------------------------------------------------------
+function txt=obj2ubjson(name,item,level,varargin)
+
+if(iscell(item))
+    txt=cell2ubjson(name,item,level,varargin{:});
+elseif(isstruct(item))
+    txt=struct2ubjson(name,item,level,varargin{:});
+elseif(ischar(item))
+    txt=str2ubjson(name,item,level,varargin{:});
+else
+    txt=mat2ubjson(name,item,level,varargin{:});
+end
+
+%%-------------------------------------------------------------------------
+function txt=cell2ubjson(name,item,level,varargin)
+txt='';
+if(~iscell(item))
+        error('input is not a cell');
+end
+
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item); % let's handle 1D cell first
+if(len>1) 
+    if(~isempty(name))
+        txt=[S_(checkname(name,varargin{:})) '[']; name=''; 
+    else
+        txt='['; 
+    end
+elseif(len==0)
+    if(~isempty(name))
+        txt=[S_(checkname(name,varargin{:})) 'Z']; name=''; 
+    else
+        txt='Z'; 
+    end
+end
+for j=1:dim(2)
+    if(dim(1)>1) txt=[txt '[']; end
+    for i=1:dim(1)
+       txt=[txt obj2ubjson(name,item{i,j},level+(len>1),varargin{:})];
+    end
+    if(dim(1)>1) txt=[txt ']']; end
+end
+if(len>1) txt=[txt ']']; end
+
+%%-------------------------------------------------------------------------
+function txt=struct2ubjson(name,item,level,varargin)
+txt='';
+if(~isstruct(item))
+	error('input is not a struct');
+end
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item);
+
+if(~isempty(name)) 
+    if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
+else
+    if(len>1) txt='['; end
+end
+for j=1:dim(2)
+  if(dim(1)>1) txt=[txt '[']; end
+  for i=1:dim(1)
+     names = fieldnames(item(i,j));
+     if(~isempty(name) && len==1)
+        txt=[txt S_(checkname(name,varargin{:})) '{']; 
+     else
+        txt=[txt '{']; 
+     end
+     if(~isempty(names))
+       for e=1:length(names)
+	     txt=[txt obj2ubjson(names{e},getfield(item(i,j),...
+             names{e}),level+(dim(1)>1)+1+(len>1),varargin{:})];
+       end
+     end
+     txt=[txt '}'];
+  end
+  if(dim(1)>1) txt=[txt ']']; end
+end
+if(len>1) txt=[txt ']']; end
+
+%%-------------------------------------------------------------------------
+function txt=str2ubjson(name,item,level,varargin)
+txt='';
+if(~ischar(item))
+        error('input is not a string');
+end
+item=reshape(item, max(size(item),[1 0]));
+len=size(item,1);
+
+if(~isempty(name)) 
+    if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
+else
+    if(len>1) txt='['; end
+end
+isoct=jsonopt('IsOctave',0,varargin{:});
+for e=1:len
+    val=item(e,:);
+    if(len==1)
+        obj=['' S_(checkname(name,varargin{:})) '' '',S_(val),''];
+	if(isempty(name)) obj=['',S_(val),'']; end
+        txt=[txt,'',obj];
+    else
+        txt=[txt,'',['',S_(val),'']];
+    end
+end
+if(len>1) txt=[txt ']']; end
+
+%%-------------------------------------------------------------------------
+function txt=mat2ubjson(name,item,level,varargin)
+if(~isnumeric(item) && ~islogical(item))
+        error('input is not an array');
+end
+
+if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
+   isempty(item) || jsonopt('ArrayToStruct',0,varargin{:}))
+      cid=I_(uint32(max(size(item))));
+      if(isempty(name))
+    	txt=['{' S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1)) ];
+      else
+          if(isempty(item))
+              txt=[S_(checkname(name,varargin{:})),'Z'];
+              return;
+          else
+    	      txt=[S_(checkname(name,varargin{:})),'{',S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1))];
+          end
+      end
+else
+    if(isempty(name))
+    	txt=matdata2ubjson(item,level+1,varargin{:});
+    else
+        if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
+            numtxt=regexprep(regexprep(matdata2ubjson(item,level+1,varargin{:}),'^\[',''),']','');
+           	txt=[S_(checkname(name,varargin{:})) numtxt];
+        else
+    	    txt=[S_(checkname(name,varargin{:})),matdata2ubjson(item,level+1,varargin{:})];
+        end
+    end
+    return;
+end
+if(issparse(item))
+    [ix,iy]=find(item);
+    data=full(item(find(item)));
+    if(~isreal(item))
+       data=[real(data(:)),imag(data(:))];
+       if(size(item,1)==1)
+           % Kludge to have data's 'transposedness' match item's.
+           % (Necessary for complex row vector handling below.)
+           data=data';
+       end
+       txt=[txt,S_('_ArrayIsComplex_'),'T'];
+    end
+    txt=[txt,S_('_ArrayIsSparse_'),'T'];
+    if(size(item,1)==1)
+        % Row vector, store only column indices.
+        txt=[txt,S_('_ArrayData_'),...
+           matdata2ubjson([iy(:),data'],level+2,varargin{:})];
+    elseif(size(item,2)==1)
+        % Column vector, store only row indices.
+        txt=[txt,S_('_ArrayData_'),...
+           matdata2ubjson([ix,data],level+2,varargin{:})];
+    else
+        % General case, store row and column indices.
+        txt=[txt,S_('_ArrayData_'),...
+           matdata2ubjson([ix,iy,data],level+2,varargin{:})];
+    end
+else
+    if(isreal(item))
+        txt=[txt,S_('_ArrayData_'),...
+            matdata2ubjson(item(:)',level+2,varargin{:})];
+    else
+        txt=[txt,S_('_ArrayIsComplex_'),'T'];
+        txt=[txt,S_('_ArrayData_'),...
+            matdata2ubjson([real(item(:)) imag(item(:))],level+2,varargin{:})];
+    end
+end
+txt=[txt,'}'];
+
+%%-------------------------------------------------------------------------
+function txt=matdata2ubjson(mat,level,varargin)
+if(isempty(mat))
+    txt='Z';
+    return;
+end
+if(size(mat,1)==1)
+    level=level-1;
+end
+type='';
+hasnegtive=(mat<0);
+if(isa(mat,'integer') || isinteger(mat) || (isfloat(mat) && all(mod(mat(:),1) == 0)))
+    if(isempty(hasnegtive))
+       if(max(mat(:))<=2^8)
+           type='U';
+       end
+    end
+    if(isempty(type))
+        % todo - need to consider negative ones separately
+        id= histc(abs(max(mat(:))),[0 2^7 2^15 2^31 2^63]);
+        if(isempty(find(id)))
+            error('high-precision data is not yet supported');
+        end
+        key='iIlL';
+	type=key(find(id));
+    end
+    txt=[I_a(mat(:),type,size(mat))];
+elseif(islogical(mat))
+    logicalval='FT';
+    if(numel(mat)==1)
+        txt=logicalval(mat+1);
+    else
+        txt=['[$U#' I_a(size(mat),'l') typecast(swapbytes(uint8(mat(:)')),'uint8')];
+    end
+else
+    if(numel(mat)==1)
+        txt=['[' D_(mat) ']'];
+    else
+        txt=D_a(mat(:),'D',size(mat));
+    end
+end
+
+%txt=regexprep(mat2str(mat),'\s+',',');
+%txt=regexprep(txt,';',sprintf('],['));
+% if(nargin>=2 && size(mat,1)>1)
+%     txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
+% end
+if(any(isinf(mat(:))))
+    txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
+end
+if(any(isnan(mat(:))))
+    txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
+end
+
+%%-------------------------------------------------------------------------
+function newname=checkname(name,varargin)
+isunpack=jsonopt('UnpackHex',1,varargin{:});
+newname=name;
+if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
+    return
+end
+if(isunpack)
+    isoct=jsonopt('IsOctave',0,varargin{:});
+    if(~isoct)
+        newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
+    else
+        pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
+        pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
+        if(isempty(pos)) return; end
+        str0=name;
+        pos0=[0 pend(:)' length(name)];
+        newname='';
+        for i=1:length(pos)
+            newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
+        end
+        if(pos(end)~=length(name))
+            newname=[newname str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+end
+%%-------------------------------------------------------------------------
+function val=S_(str)
+if(length(str)==1)
+  val=['C' str];
+else
+  val=['S' I_(int32(length(str))) str];
+end
+%%-------------------------------------------------------------------------
+function val=I_(num)
+if(~isinteger(num))
+    error('input is not an integer');
+end
+if(num>=0 && num<255)
+   val=['U' data2byte(swapbytes(cast(num,'uint8')),'uint8')];
+   return;
+end
+key='iIlL';
+cid={'int8','int16','int32','int64'};
+for i=1:4
+  if((num>0 && num<2^(i*8-1)) || (num<0 && num>=-2^(i*8-1)))
+    val=[key(i) data2byte(swapbytes(cast(num,cid{i})),'uint8')];
+    return;
+  end
+end
+error('unsupported integer');
+
+%%-------------------------------------------------------------------------
+function val=D_(num)
+if(~isfloat(num))
+    error('input is not a float');
+end
+
+if(isa(num,'single'))
+  val=['d' data2byte(num,'uint8')];
+else
+  val=['D' data2byte(num,'uint8')];
+end
+%%-------------------------------------------------------------------------
+function data=I_a(num,type,dim,format)
+id=find(ismember('iUIlL',type));
+
+if(id==0)
+  error('unsupported integer array');
+end
+
+% based on UBJSON specs, all integer types are stored in big endian format
+
+if(id==1)
+  data=data2byte(swapbytes(int8(num)),'uint8');
+  blen=1;
+elseif(id==2)
+  data=data2byte(swapbytes(uint8(num)),'uint8');
+  blen=1;
+elseif(id==3)
+  data=data2byte(swapbytes(int16(num)),'uint8');
+  blen=2;
+elseif(id==4)
+  data=data2byte(swapbytes(int32(num)),'uint8');
+  blen=4;
+elseif(id==5)
+  data=data2byte(swapbytes(int64(num)),'uint8');
+  blen=8;
+end
+
+if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
+  format='opt';
+end
+if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
+  if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
+      cid=I_(uint32(max(dim)));
+      data=['$' type '#' I_a(dim,cid(1)) data(:)'];
+  else
+      data=['$' type '#' I_(int32(numel(data)/blen)) data(:)'];
+  end
+  data=['[' data(:)'];
+else
+  data=reshape(data,blen,numel(data)/blen);
+  data(2:blen+1,:)=data;
+  data(1,:)=type;
+  data=data(:)';
+  data=['[' data(:)' ']'];
+end
+%%-------------------------------------------------------------------------
+function data=D_a(num,type,dim,format)
+id=find(ismember('dD',type));
+
+if(id==0)
+  error('unsupported float array');
+end
+
+if(id==1)
+  data=data2byte(single(num),'uint8');
+elseif(id==2)
+  data=data2byte(double(num),'uint8');
+end
+
+if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
+  format='opt';
+end
+if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
+  if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
+      cid=I_(uint32(max(dim)));
+      data=['$' type '#' I_a(dim,cid(1)) data(:)'];
+  else
+      data=['$' type '#' I_(int32(numel(data)/(id*4))) data(:)'];
+  end
+  data=['[' data];
+else
+  data=reshape(data,(id*4),length(data)/(id*4));
+  data(2:(id*4+1),:)=data;
+  data(1,:)=type;
+  data=data(:)';
+  data=['[' data(:)' ']'];
+end
+%%-------------------------------------------------------------------------
+function bytes=data2byte(varargin)
+bytes=typecast(varargin{:});
+bytes=bytes(:)';

+ 40 - 0
ex1/lib/jsonlab/varargin2struct.m

@@ -0,0 +1,40 @@
+function opt=varargin2struct(varargin)
+%
+% opt=varargin2struct('param1',value1,'param2',value2,...)
+%   or
+% opt=varargin2struct(...,optstruct,...)
+%
+% convert a series of input parameters into a structure
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% date: 2012/12/22
+%
+% input:
+%      'param', value: the input parameters should be pairs of a string and a value
+%       optstruct: if a parameter is a struct, the fields will be merged to the output struct
+%
+% output:
+%      opt: a struct where opt.param1=value1, opt.param2=value2 ...
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details 
+%
+% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+len=length(varargin);
+opt=struct;
+if(len==0) return; end
+i=1;
+while(i<=len)
+    if(isstruct(varargin{i}))
+        opt=mergestruct(opt,varargin{i});
+    elseif(ischar(varargin{i}) && i<len)
+        opt=setfield(opt,varargin{i},varargin{i+1});
+        i=i+1;
+    else
+        error('input must be in the form of ...,''name'',value,... pairs or structs');
+    end
+    i=i+1;
+end
+

+ 30 - 0
ex1/lib/makeValidFieldName.m

@@ -0,0 +1,30 @@
+function str = makeValidFieldName(str)
+% From MATLAB doc: field names must begin with a letter, which may be
+% followed by any combination of letters, digits, and underscores.
+% Invalid characters will be converted to underscores, and the prefix
+% "x0x[Hex code]_" will be added if the first character is not a letter.
+    isoct=exist('OCTAVE_VERSION','builtin');
+    pos=regexp(str,'^[^A-Za-z]','once');
+    if(~isempty(pos))
+        if(~isoct)
+            str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
+        else
+            str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
+        end
+    end
+    if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return;  end
+    if(~isoct)
+        str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
+    else
+        pos=regexp(str,'[^0-9A-Za-z_]');
+        if(isempty(pos)) return; end
+        str0=str;
+        pos0=[0 pos(:)' length(str)];
+        str='';
+        for i=1:length(pos)
+            str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
+        end
+        if(pos(end)~=length(str))
+            str=[str str0(pos0(end-1)+1:pos0(end))];
+        end
+    end

+ 179 - 0
ex1/lib/submitWithConfiguration.m

@@ -0,0 +1,179 @@
+function submitWithConfiguration(conf)
+  addpath('./lib/jsonlab');
+
+  parts = parts(conf);
+
+  fprintf('== Submitting solutions | %s...\n', conf.itemName);
+
+  tokenFile = 'token.mat';
+  if exist(tokenFile, 'file')
+    load(tokenFile);
+    [email token] = promptToken(email, token, tokenFile);
+  else
+    [email token] = promptToken('', '', tokenFile);
+  end
+
+  if isempty(token)
+    fprintf('!! Submission Cancelled\n');
+    return
+  end
+
+  try
+    response = submitParts(conf, email, token, parts);
+  catch
+    e = lasterror();
+    fprintf('\n!! Submission failed: %s\n', e.message);
+    fprintf('\n\nFunction: %s\nFileName: %s\nLineNumber: %d\n', ...
+      e.stack(1,1).name, e.stack(1,1).file, e.stack(1,1).line);
+    fprintf('\nPlease correct your code and resubmit.\n');
+    return
+  end
+
+  if isfield(response, 'errorMessage')
+    fprintf('!! Submission failed: %s\n', response.errorMessage);
+  elseif isfield(response, 'errorCode')
+    fprintf('!! Submission failed: %s\n', response.message);
+  else
+    showFeedback(parts, response);
+    save(tokenFile, 'email', 'token');
+  end
+end
+
+function [email token] = promptToken(email, existingToken, tokenFile)
+  if (~isempty(email) && ~isempty(existingToken))
+    prompt = sprintf( ...
+      'Use token from last successful submission (%s)? (Y/n): ', ...
+      email);
+    reenter = input(prompt, 's');
+
+    if (isempty(reenter) || reenter(1) == 'Y' || reenter(1) == 'y')
+      token = existingToken;
+      return;
+    else
+      delete(tokenFile);
+    end
+  end
+  email = input('Login (email address): ', 's');
+  token = input('Token: ', 's');
+end
+
+function isValid = isValidPartOptionIndex(partOptions, i)
+  isValid = (~isempty(i)) && (1 <= i) && (i <= numel(partOptions));
+end
+
+function response = submitParts(conf, email, token, parts)
+  body = makePostBody(conf, email, token, parts);
+  submissionUrl = submissionUrl();
+
+  responseBody = getResponse(submissionUrl, body);
+  jsonResponse = validateResponse(responseBody);
+  response = loadjson(jsonResponse);
+end
+
+function body = makePostBody(conf, email, token, parts)
+  bodyStruct.assignmentSlug = conf.assignmentSlug;
+  bodyStruct.submitterEmail = email;
+  bodyStruct.secret = token;
+  bodyStruct.parts = makePartsStruct(conf, parts);
+
+  opt.Compact = 1;
+  body = savejson('', bodyStruct, opt);
+end
+
+function partsStruct = makePartsStruct(conf, parts)
+  for part = parts
+    partId = part{:}.id;
+    fieldName = makeValidFieldName(partId);
+    outputStruct.output = conf.output(partId);
+    partsStruct.(fieldName) = outputStruct;
+  end
+end
+
+function [parts] = parts(conf)
+  parts = {};
+  for partArray = conf.partArrays
+    part.id = partArray{:}{1};
+    part.sourceFiles = partArray{:}{2};
+    part.name = partArray{:}{3};
+    parts{end + 1} = part;
+  end
+end
+
+function showFeedback(parts, response)
+  fprintf('== \n');
+  fprintf('== %43s | %9s | %-s\n', 'Part Name', 'Score', 'Feedback');
+  fprintf('== %43s | %9s | %-s\n', '---------', '-----', '--------');
+  for part = parts
+    score = '';
+    partFeedback = '';
+    partFeedback = response.partFeedbacks.(makeValidFieldName(part{:}.id));
+    partEvaluation = response.partEvaluations.(makeValidFieldName(part{:}.id));
+    score = sprintf('%d / %3d', partEvaluation.score, partEvaluation.maxScore);
+    fprintf('== %43s | %9s | %-s\n', part{:}.name, score, partFeedback);
+  end
+  evaluation = response.evaluation;
+  totalScore = sprintf('%d / %d', evaluation.score, evaluation.maxScore);
+  fprintf('==                                   --------------------------------\n');
+  fprintf('== %43s | %9s | %-s\n', '', totalScore, '');
+  fprintf('== \n');
+end
+
+% use urlread or curl to send submit results to the grader and get a response
+function response = getResponse(url, body)
+% try using urlread() and a secure connection
+  params = {'jsonBody', body};
+  [response, success] = urlread(url, 'post', params);
+
+  if (success == 0)
+    % urlread didn't work, try curl & the peer certificate patch
+    if ispc
+      % testing note: use 'jsonBody =' for a test case
+      json_command = sprintf('echo jsonBody=%s | curl -k -X POST -d @- %s', body, url);
+    else
+      % it's linux/OS X, so use the other form
+      json_command = sprintf('echo ''jsonBody=%s'' | curl -k -X POST -d @- %s', body, url);
+    end
+    % get the response body for the peer certificate patch method
+    [code, response] = system(json_command);
+    % test the success code
+    if (code ~= 0)
+      fprintf('[error] submission with curl() was not successful\n');
+    end
+  end
+end
+
+% validate the grader's response
+function response = validateResponse(resp)
+  % test if the response is json or an HTML page
+  isJson = length(resp) > 0 && resp(1) == '{';
+  isHtml = findstr(lower(resp), '<html');
+
+  if (isJson)
+    response = resp;
+  elseif (isHtml)
+    % the response is html, so it's probably an error message
+    printHTMLContents(resp);
+    error('Grader response is an HTML message');
+  else
+    error('Grader sent no response');
+  end
+end
+
+% parse a HTML response and print it's contents
+function printHTMLContents(response)
+  strippedResponse = regexprep(response, '<[^>]+>', ' ');
+  strippedResponse = regexprep(strippedResponse, '[\t ]+', ' ');
+  fprintf(strippedResponse);
+end
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Service configuration
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function submissionUrl = submissionUrl()
+  submissionUrl = 'https://www-origin.coursera.org/api/onDemandProgrammingImmediateFormSubmissions.v1';
+end

+ 23 - 0
ex1/normalEqn.m

@@ -0,0 +1,23 @@
+function [theta] = normalEqn(X, y)
+%NORMALEQN Computes the closed-form solution to linear regression 
+%   NORMALEQN(X,y) computes the closed-form solution to linear 
+%   regression using the normal equations.
+
+theta = (X'*X)\X'*y;
+
+% ====================== YOUR CODE HERE ======================
+% Instructions: Complete the code to compute the closed form solution
+%               to linear regression and put the result in theta.
+%
+
+% ---------------------- Sample Solution ----------------------
+
+
+
+
+% -------------------------------------------------------------
+
+
+% ============================================================
+
+end

+ 28 - 0
ex1/plotData.m

@@ -0,0 +1,28 @@
+function plotData(x, y)
+%PLOTDATA Plots the data points x and y into a new figure 
+%   PLOTDATA(x,y) plots the data points and gives the figure axes labels of
+%   population and profit.
+
+figure; % open a new figure window
+plot(x, y, 'rx', 'MarkerSize', 10); % Plot the data
+ylabel('Profit in $10,000s'); % Set the y􀀀axis label
+xlabel('Population of City in 10,000s'); % Set the x􀀀axis label
+
+% ====================== YOUR CODE HERE ======================
+% Instructions: Plot the training data into a figure using the 
+%               "figure" and "plot" commands. Set the axes labels using
+%               the "xlabel" and "ylabel" commands. Assume the 
+%               population and revenue data have been passed in
+%               as the x and y arguments of this function.
+%
+% Hint: You can use the 'rx' option with plot to have the markers
+%       appear as red crosses. Furthermore, you can make the
+%       markers larger by using plot(..., 'rx', 'MarkerSize', 10);
+
+
+
+
+
+% ============================================================
+
+end

+ 69 - 0
ex1/submit.m

@@ -0,0 +1,69 @@
+function submit()
+  addpath('./lib');
+
+  conf.assignmentSlug = 'linear-regression';
+  conf.itemName = 'Linear Regression with Multiple Variables';
+  conf.partArrays = { ...
+    { ...
+      '1', ...
+      { 'warmUpExercise.m' }, ...
+      'Warm-up Exercise', ...
+    }, ...
+    { ...
+      '2', ...
+      { 'computeCost.m' }, ...
+      'Computing Cost (for One Variable)', ...
+    }, ...
+    { ...
+      '3', ...
+      { 'gradientDescent.m' }, ...
+      'Gradient Descent (for One Variable)', ...
+    }, ...
+    { ...
+      '4', ...
+      { 'featureNormalize.m' }, ...
+      'Feature Normalization', ...
+    }, ...
+    { ...
+      '5', ...
+      { 'computeCostMulti.m' }, ...
+      'Computing Cost (for Multiple Variables)', ...
+    }, ...
+    { ...
+      '6', ...
+      { 'gradientDescentMulti.m' }, ...
+      'Gradient Descent (for Multiple Variables)', ...
+    }, ...
+    { ...
+      '7', ...
+      { 'normalEqn.m' }, ...
+      'Normal Equations', ...
+    }, ...
+  };
+  conf.output = @output;
+
+  submitWithConfiguration(conf);
+end
+
+function out = output(partId)
+  % 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

+ 21 - 0
ex1/warmUpExercise.m

@@ -0,0 +1,21 @@
+function A = warmUpExercise()
+%WARMUPEXERCISE Example function in octave
+%   A = WARMUPEXERCISE() is an example function that returns the 5x5 identity matrix
+
+A = eye(5);
+% ============= YOUR CODE HERE ==============
+% Instructions: Return the 5x5 identity matrix 
+%               In octave, we return values by defining which variables
+%               represent the return values (at the top of the file)
+%               and then set them accordingly. 
+
+
+
+
+
+
+
+% ===========================================
+
+
+end

+ 33 - 0
ex2/costFunction.m

@@ -0,0 +1,33 @@
+function [J, grad] = costFunction(theta, X, y)
+%COSTFUNCTION Compute cost and gradient for logistic regression
+%   J = COSTFUNCTION(theta, X, y) computes the cost of using theta as the
+%   parameter for logistic regression and the gradient of the cost
+%   w.r.t. to the parameters.
+
+% Initialize some useful values
+%m = length(y); % number of training examples
+
+% You need to return the following variables correctly 
+z = hypothesis(theta, X);
+J = mean(- y .* log(z) + (y - 1) .* log(1 - z));
+grad = mean((z - y) .* X);
+
+% ====================== YOUR CODE HERE ======================
+% Instructions: Compute the cost of a particular choice of theta.
+%               You should set J to the cost.
+%               Compute the partial derivatives and set grad to the partial
+%               derivatives of the cost w.r.t. each parameter in theta
+%
+% Note: grad should have the same dimensions as theta
+%
+
+
+
+
+
+
+
+
+% =============================================================
+
+end

+ 30 - 0
ex2/costFunctionReg.m

@@ -0,0 +1,30 @@
+function [J, grad] = costFunctionReg(theta, X, y, lambda)
+%COSTFUNCTIONREG Compute cost and gradient for logistic regression with regularization
+%   J = COSTFUNCTIONREG(theta, X, y, lambda) computes the cost of using
+%   theta as the parameter for regularized logistic regression and the
+%   gradient of the cost w.r.t. to the parameters. 
+
+% Initialize some useful values
+m = length(y); % number of training examples
+
+% You need to return the following variables correctly 
+z = hypothesis(theta, X);
+t = lambda*(sum(theta .^ 2)-theta(1)^2)/2/m;
+J = mean(- y .* log(z) + (y - 1) .* log(1 - z)) + t;
+
+grad = mean((z - y) .* X)' + lambda /m * theta;
+grad(1) = grad(1) - lambda /m * theta(1);
+% ====================== YOUR CODE HERE ======================
+% Instructions: Compute the cost of a particular choice of theta.
+%               You should set J to the cost.
+%               Compute the partial derivatives and set grad to the partial
+%               derivatives of the cost w.r.t. each parameter in theta
+
+
+
+
+
+
+% =============================================================
+
+end

+ 151 - 0
ex2/ex2.m

@@ -0,0 +1,151 @@
+%% Machine Learning Online Class - Exercise 2: Logistic Regression
+%
+%  Instructions
+%  ------------
+% 
+%  This file contains code that helps you get started on the logistic
+%  regression exercise. You will need to complete the following functions 
+%  in this exericse:
+%
+%     sigmoid.m
+%     costFunction.m
+%     predict.m
+%     costFunctionReg.m
+%
+%  For this exercise, you will not need to change any code in this file,
+%  or any other files other than those mentioned above.
+%
+
+%% Initialization
+clear ; close all; clc
+
+%% Load Data
+%  The first two columns contains the exam scores and the third column
+%  contains the label.
+
+data = load('ex2data1.txt');
+X = data(:, [1, 2]); y = data(:, 3);
+
+%% ==================== Part 1: Plotting ====================
+%  We start the exercise by first plotting the data to understand the 
+%  the problem we are working with.
+
+fprintf(['Plotting data with + indicating (y = 1) examples and o ' ...
+         'indicating (y = 0) examples.\n']);
+
+plotData(X, y);
+
+% Put some labels 
+hold on;
+% Labels and Legend
+xlabel('Exam 1 score')
+ylabel('Exam 2 score')
+
+% Specified in plot order
+legend('Admitted', 'Not admitted')
+hold off;
+
+fprintf('\nProgram paused. Press enter to continue.\n');
+pause;
+
+
+%% ============ Part 2: Compute Cost and Gradient ============
+%  In this part of the exercise, you will implement the cost and gradient
+%  for logistic regression. You neeed to complete the code in 
+%  costFunction.m
+
+%  Setup the data matrix appropriately, and add ones for the intercept term
+[m, n] = size(X);
+
+% Add intercept term to x and X_test
+X = [ones(m, 1) X];
+
+% Initialize fitting parameters
+initial_theta = zeros(n + 1, 1);
+
+% Compute and display initial cost and gradient
+[cost, grad] = costFunction(initial_theta, X, y);
+
+fprintf('Cost at initial theta (zeros): %f\n', cost);
+fprintf('Expected cost (approx): 0.693\n');
+fprintf('Gradient at initial theta (zeros): \n');
+fprintf(' %f \n', grad);
+fprintf('Expected gradients (approx):\n -0.1000\n -12.0092\n -11.2628\n');
+
+% Compute and display cost and gradient with non-zero theta
+test_theta = [-24; 0.2; 0.2];
+[cost, grad] = costFunction(test_theta, X, y);
+
+fprintf('\nCost at test theta: %f\n', cost);
+fprintf('Expected cost (approx): 0.218\n');
+fprintf('Gradient at test theta: \n');
+fprintf(' %f \n', grad);
+fprintf('Expected gradients (approx):\n 0.043\n 2.566\n 2.647\n');
+
+fprintf('\nProgram paused. Press enter to continue.\n');
+pause;
+
+
+%% ============= Part 3: Optimizing using fminunc  =============
+%  In this exercise, you will use a built-in function (fminunc) to find the
+%  optimal parameters theta.
+
+%  Set options for fminunc
+options = optimset('GradObj', 'on', 'MaxIter', 400);
+
+%  Run fminunc to obtain the optimal theta
+%  This function will return theta and the cost 
+[theta, cost] = ...
+	fminunc(@(t)(costFunction(t, X, y)), initial_theta, options);
+
+% Print theta to screen
+fprintf('Cost at theta found by fminunc: %f\n', cost);
+fprintf('Expected cost (approx): 0.203\n');
+fprintf('theta: \n');
+fprintf(' %f \n', theta);
+fprintf('Expected theta (approx):\n');
+fprintf(' -25.161\n 0.206\n 0.201\n');
+
+% Plot Boundary
+plotDecisionBoundary(theta, X, y);
+
+% Put some labels 
+hold on;
+% Labels and Legend
+xlabel('Exam 1 score')
+ylabel('Exam 2 score')
+
+% Specified in plot order
+legend('Admitted', 'Not admitted')
+hold off;
+
+fprintf('\nProgram paused. Press enter to continue.\n');
+pause;
+
+%% ============== Part 4: Predict and Accuracies ==============
+%  After learning the parameters, you'll like to use it to predict the outcomes
+%  on unseen data. In this part, you will use the logistic regression model
+%  to predict the probability that a student with score 45 on exam 1 and 
+%  score 85 on exam 2 will be admitted.
+%
+%  Furthermore, you will compute the training and test set accuracies of 
+%  our model.
+%
+%  Your task is to complete the code in predict.m
+
+%  Predict probability for a student with score 45 on exam 1 
+%  and score 85 on exam 2 
+
+prob = sigmoid([1 45 85] * theta);
+fprintf(['For a student with scores 45 and 85, we predict an admission ' ...
+         'probability of %f\n'], prob);
+fprintf('Expected value: 0.775 +/- 0.002\n\n');
+
+% Compute accuracy on our training set
+p = predict(theta, X);
+
+fprintf('Train Accuracy: %f\n', mean(double(p == y)) * 100);
+fprintf('Expected accuracy (approx): 89.0\n');
+fprintf('\n');
+
+

+ 136 - 0
ex2/ex2_reg.m

@@ -0,0 +1,136 @@
+%% Machine Learning Online Class - Exercise 2: Logistic Regression
+%
+%  Instructions
+%  ------------
+%
+%  This file contains code that helps you get started on the second part
+%  of the exercise which covers regularization with logistic regression.
+%
+%  You will need to complete the following functions in this exericse:
+%
+%     sigmoid.m
+%     costFunction.m
+%     predict.m
+%     costFunctionReg.m
+%
+%  For this exercise, you will not need to change any code in this file,
+%  or any other files other than those mentioned above.
+%
+
+%% Initialization
+clear ; close all; clc
+
+%% Load Data
+%  The first two columns contains the X values and the third column
+%  contains the label (y).
+
+data = load('ex2data2.txt');
+X = data(:, [1, 2]); y = data(:, 3);
+
+plotData(X, y);
+
+% Put some labels
+hold on;
+
+% Labels and Legend
+xlabel('Microchip Test 1')
+ylabel('Microchip Test 2')
+
+% Specified in plot order
+legend('y = 1', 'y = 0')
+hold off;
+
+
+%% =========== Part 1: Regularized Logistic Regression ============
+%  In this part, you are given a dataset with data points that are not
+%  linearly separable. However, you would still like to use logistic
+%  regression to classify the data points.
+%
+%  To do so, you introduce more features to use -- in particular, you add
+%  polynomial features to our data matrix (similar to polynomial
+%  regression).
+%
+
+% Add Polynomial Features
+
+% Note that mapFeature also adds a column of ones for us, so the intercept
+% term is handled
+X = mapFeature(X(:,1), X(:,2));
+
+% Initialize fitting parameters
+initial_theta = zeros(size(X, 2), 1);
+
+% Set regularization parameter lambda to 1
+lambda = 1;
+
+% Compute and display initial cost and gradient for regularized logistic
+% regression
+[cost, grad] = costFunctionReg(initial_theta, X, y, lambda);
+
+fprintf('Cost at initial theta (zeros): %f\n', cost);
+fprintf('Expected cost (approx): 0.693\n');
+fprintf('Gradient at initial theta (zeros) - first five values only:\n');
+fprintf(' %f \n', grad(1:5));
+fprintf('Expected gradients (approx) - first five values only:\n');
+fprintf(' 0.0085\n 0.0188\n 0.0001\n 0.0503\n 0.0115\n');
+
+fprintf('\nProgram paused. Press enter to continue.\n');
+pause;
+
+% Compute and display cost and gradient
+% with all-ones theta and lambda = 10
+test_theta = ones(size(X,2),1);
+[cost, grad] = costFunctionReg(test_theta, X, y, 10);
+
+fprintf('\nCost at test theta (with lambda = 10): %f\n', cost);
+fprintf('Expected cost (approx): 3.16\n');
+fprintf('Gradient at test theta - first five values only:\n');
+fprintf(' %f \n', grad(1:5));
+fprintf('Expected gradients (approx) - first five values only:\n');
+fprintf(' 0.3460\n 0.1614\n 0.1948\n 0.2269\n 0.0922\n');
+
+fprintf('\nProgram paused. Press enter to continue.\n');
+pause;
+
+%% ============= Part 2: Regularization and Accuracies =============
+%  Optional Exercise:
+%  In this part, you will get to try different values of lambda and
+%  see how regularization affects the decision coundart
+%
+%  Try the following values of lambda (0, 1, 10, 100).
+%
+%  How does the decision boundary change when you vary lambda? How does
+%  the training set accuracy vary?
+%
+
+% Initialize fitting parameters
+initial_theta = zeros(size(X, 2), 1);
+
+% Set regularization parameter lambda to 1 (you should vary this)
+lambda = 1;
+
+% Set Options
+options = optimset('GradObj', 'on', 'MaxIter', 400);
+
+% Optimize
+[theta, J, exit_flag] = ...
+	fminunc(@(t)(costFunctionReg(t, X, y, lambda)), initial_theta, options);
+
+% Plot Boundary
+plotDecisionBoundary(theta, X, y);
+hold on;
+title(sprintf('lambda = %g', lambda))
+
+% Labels and Legend
+xlabel('Microchip Test 1')
+ylabel('Microchip Test 2')
+
+legend('y = 1', 'y = 0', 'Decision boundary')
+hold off;
+
+% Compute accuracy on our training set
+p = predict(theta, X);
+
+fprintf('Train Accuracy: %f\n', mean(double(p == y)) * 100);
+fprintf('Expected accuracy (with lambda = 1): 83.1 (approx)\n');
+

+ 100 - 0
ex2/ex2data1.txt

@@ -0,0 +1,100 @@
+34.62365962451697,78.0246928153624,0
+30.28671076822607,43.89499752400101,0
+35.84740876993872,72.90219802708364,0
+60.18259938620976,86.30855209546826,1
+79.0327360507101,75.3443764369103,1
+45.08327747668339,56.3163717815305,0
+61.10666453684766,96.51142588489624,1
+75.02474556738889,46.55401354116538,1
+76.09878670226257,87.42056971926803,1
+84.43281996120035,43.53339331072109,1
+95.86155507093572,38.22527805795094,0
+75.01365838958247,30.60326323428011,0
+82.30705337399482,76.48196330235604,1
+69.36458875970939,97.71869196188608,1
+39.53833914367223,76.03681085115882,0
+53.9710521485623,89.20735013750205,1
+69.07014406283025,52.74046973016765,1
+67.94685547711617,46.67857410673128,0
+70.66150955499435,92.92713789364831,1
+76.97878372747498,47.57596364975532,1
+67.37202754570876,42.83843832029179,0
+89.67677575072079,65.79936592745237,1
+50.534788289883,48.85581152764205,0
+34.21206097786789,44.20952859866288,0
+77.9240914545704,68.9723599933059,1
+62.27101367004632,69.95445795447587,1
+80.1901807509566,44.82162893218353,1
+93.114388797442,38.80067033713209,0
+61.83020602312595,50.25610789244621,0
+38.78580379679423,64.99568095539578,0
+61.379289447425,72.80788731317097,1
+85.40451939411645,57.05198397627122,1
+52.10797973193984,63.12762376881715,0
+52.04540476831827,69.43286012045222,1
+40.23689373545111,71.16774802184875,0
+54.63510555424817,52.21388588061123,0
+33.91550010906887,98.86943574220611,0
+64.17698887494485,80.90806058670817,1
+74.78925295941542,41.57341522824434,0
+34.1836400264419,75.2377203360134,0
+83.90239366249155,56.30804621605327,1
+51.54772026906181,46.85629026349976,0
+94.44336776917852,65.56892160559052,1
+82.36875375713919,40.61825515970618,0
+51.04775177128865,45.82270145776001,0
+62.22267576120188,52.06099194836679,0
+77.19303492601364,70.45820000180959,1
+97.77159928000232,86.7278223300282,1
+62.07306379667647,96.76882412413983,1
+91.56497449807442,88.69629254546599,1
+79.94481794066932,74.16311935043758,1
+99.2725269292572,60.99903099844988,1
+90.54671411399852,43.39060180650027,1
+34.52451385320009,60.39634245837173,0
+50.2864961189907,49.80453881323059,0
+49.58667721632031,59.80895099453265,0
+97.64563396007767,68.86157272420604,1
+32.57720016809309,95.59854761387875,0
+74.24869136721598,69.82457122657193,1
+71.79646205863379,78.45356224515052,1
+75.3956114656803,85.75993667331619,1
+35.28611281526193,47.02051394723416,0
+56.25381749711624,39.26147251058019,0
+30.05882244669796,49.59297386723685,0
+44.66826172480893,66.45008614558913,0
+66.56089447242954,41.09209807936973,0
+40.45755098375164,97.53518548909936,1
+49.07256321908844,51.88321182073966,0
+80.27957401466998,92.11606081344084,1
+66.74671856944039,60.99139402740988,1
+32.72283304060323,43.30717306430063,0
+64.0393204150601,78.03168802018232,1
+72.34649422579923,96.22759296761404,1
+60.45788573918959,73.09499809758037,1
+58.84095621726802,75.85844831279042,1
+99.82785779692128,72.36925193383885,1
+47.26426910848174,88.47586499559782,1
+50.45815980285988,75.80985952982456,1
+60.45555629271532,42.50840943572217,0
+82.22666157785568,42.71987853716458,0
+88.9138964166533,69.80378889835472,1
+94.83450672430196,45.69430680250754,1
+67.31925746917527,66.58935317747915,1
+57.23870631569862,59.51428198012956,1
+80.36675600171273,90.96014789746954,1
+68.46852178591112,85.59430710452014,1
+42.0754545384731,78.84478600148043,0
+75.47770200533905,90.42453899753964,1
+78.63542434898018,96.64742716885644,1
+52.34800398794107,60.76950525602592,0
+94.09433112516793,77.15910509073893,1
+90.44855097096364,87.50879176484702,1
+55.48216114069585,35.57070347228866,0
+74.49269241843041,84.84513684930135,1
+89.84580670720979,45.35828361091658,1
+83.48916274498238,48.38028579728175,1
+42.2617008099817,87.10385094025457,1
+99.31500880510394,68.77540947206617,1
+55.34001756003703,64.9319380069486,1
+74.77589300092767,89.52981289513276,1

+ 118 - 0
ex2/ex2data2.txt

@@ -0,0 +1,118 @@
+0.051267,0.69956,1
+-0.092742,0.68494,1
+-0.21371,0.69225,1
+-0.375,0.50219,1
+-0.51325,0.46564,1
+-0.52477,0.2098,1
+-0.39804,0.034357,1
+-0.30588,-0.19225,1
+0.016705,-0.40424,1
+0.13191,-0.51389,1
+0.38537,-0.56506,1
+0.52938,-0.5212,1
+0.63882,-0.24342,1
+0.73675,-0.18494,1
+0.54666,0.48757,1
+0.322,0.5826,1
+0.16647,0.53874,1
+-0.046659,0.81652,1
+-0.17339,0.69956,1
+-0.47869,0.63377,1
+-0.60541,0.59722,1
+-0.62846,0.33406,1
+-0.59389,0.005117,1
+-0.42108,-0.27266,1
+-0.11578,-0.39693,1
+0.20104,-0.60161,1
+0.46601,-0.53582,1
+0.67339,-0.53582,1
+-0.13882,0.54605,1
+-0.29435,0.77997,1
+-0.26555,0.96272,1
+-0.16187,0.8019,1
+-0.17339,0.64839,1
+-0.28283,0.47295,1
+-0.36348,0.31213,1
+-0.30012,0.027047,1
+-0.23675,-0.21418,1
+-0.06394,-0.18494,1
+0.062788,-0.16301,1
+0.22984,-0.41155,1
+0.2932,-0.2288,1
+0.48329,-0.18494,1
+0.64459,-0.14108,1
+0.46025,0.012427,1
+0.6273,0.15863,1
+0.57546,0.26827,1
+0.72523,0.44371,1
+0.22408,0.52412,1
+0.44297,0.67032,1
+0.322,0.69225,1
+0.13767,0.57529,1
+-0.0063364,0.39985,1
+-0.092742,0.55336,1
+-0.20795,0.35599,1
+-0.20795,0.17325,1
+-0.43836,0.21711,1
+-0.21947,-0.016813,1
+-0.13882,-0.27266,1
+0.18376,0.93348,0
+0.22408,0.77997,0
+0.29896,0.61915,0
+0.50634,0.75804,0
+0.61578,0.7288,0
+0.60426,0.59722,0
+0.76555,0.50219,0
+0.92684,0.3633,0
+0.82316,0.27558,0
+0.96141,0.085526,0
+0.93836,0.012427,0
+0.86348,-0.082602,0
+0.89804,-0.20687,0
+0.85196,-0.36769,0
+0.82892,-0.5212,0
+0.79435,-0.55775,0
+0.59274,-0.7405,0
+0.51786,-0.5943,0
+0.46601,-0.41886,0
+0.35081,-0.57968,0
+0.28744,-0.76974,0
+0.085829,-0.75512,0
+0.14919,-0.57968,0
+-0.13306,-0.4481,0
+-0.40956,-0.41155,0
+-0.39228,-0.25804,0
+-0.74366,-0.25804,0
+-0.69758,0.041667,0
+-0.75518,0.2902,0
+-0.69758,0.68494,0
+-0.4038,0.70687,0
+-0.38076,0.91886,0
+-0.50749,0.90424,0
+-0.54781,0.70687,0
+0.10311,0.77997,0
+0.057028,0.91886,0
+-0.10426,0.99196,0
+-0.081221,1.1089,0
+0.28744,1.087,0
+0.39689,0.82383,0
+0.63882,0.88962,0
+0.82316,0.66301,0
+0.67339,0.64108,0
+1.0709,0.10015,0
+-0.046659,-0.57968,0
+-0.23675,-0.63816,0
+-0.15035,-0.36769,0
+-0.49021,-0.3019,0
+-0.46717,-0.13377,0
+-0.28859,-0.060673,0
+-0.61118,-0.067982,0
+-0.66302,-0.21418,0
+-0.59965,-0.41886,0
+-0.72638,-0.082602,0
+-0.83007,0.31213,0
+-0.72062,0.53874,0
+-0.59389,0.49488,0
+-0.48445,0.99927,0
+-0.0063364,0.99927,0
+0.63265,-0.030612,0

+ 8 - 0
ex2/hypothesis.m

@@ -0,0 +1,8 @@
+function  h  = hypothesis( theta, X )
+%HYPOTHESIS 此处显示有关此函数的摘要
+%   此处显示详细说明
+
+h = sigmoid(X * theta);
+
+end
+

+ 41 - 0
ex2/lib/jsonlab/AUTHORS.txt

@@ -0,0 +1,41 @@
+The author of "jsonlab" toolbox is Qianqian Fang. Qianqian
+is currently an Assistant Professor at Massachusetts General Hospital, 
+Harvard Medical School.
+
+Address: Martinos Center for Biomedical Imaging, 
+         Massachusetts General Hospital, 
+         Harvard Medical School
+         Bldg 149, 13th St, Charlestown, MA 02129, USA
+URL: http://nmr.mgh.harvard.edu/~fangq/
+Email: <fangq at nmr.mgh.harvard.edu> or <fangqq at gmail.com>
+
+
+The script loadjson.m was built upon previous works by
+
+- Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
+       date: 2009/11/02
+- François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
+       date: 2009/03/22
+- Joel Feenstra: http://www.mathworks.com/matlabcentral/fileexchange/20565
+       date: 2008/07/03
+
+
+This toolbox contains patches submitted by the following contributors:
+
+- Blake Johnson <bjohnso at bbn.com>
+  part of revision 341
+
+- Niclas Borlin <Niclas.Borlin at cs.umu.se>
+  various fixes in revision 394, including
+  - loadjson crashes for all-zero sparse matrix.
+  - loadjson crashes for empty sparse matrix.
+  - Non-zero size of 0-by-N and N-by-0 empty matrices is lost after savejson/loadjson.
+  - loadjson crashes for sparse real column vector.
+  - loadjson crashes for sparse complex column vector.
+  - Data is corrupted by savejson for sparse real row vector.
+  - savejson crashes for sparse complex row vector. 
+
+- Yul Kang <yul.kang.on at gmail.com>
+  patches for svn revision 415.
+  - savejson saves an empty cell array as [] instead of null
+  - loadjson differentiates an empty struct from an empty array

+ 74 - 0
ex2/lib/jsonlab/ChangeLog.txt

@@ -0,0 +1,74 @@
+============================================================================
+
+   JSONlab - a toolbox to encode/decode JSON/UBJSON files in MATLAB/Octave
+
+----------------------------------------------------------------------------
+
+JSONlab ChangeLog (key features marked by *):
+
+== JSONlab 1.0 (codename: Optimus - Final), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2015/01/02 polish help info for all major functions, update examples, finalize 1.0
+ 2014/12/19 fix a bug to strictly respect NoRowBracket in savejson
+
+== JSONlab 1.0.0-RC2 (codename: Optimus - RC2), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2014/11/22 show progress bar in loadjson ('ShowProgress') 
+ 2014/11/17 add Compact option in savejson to output compact JSON format ('Compact')
+ 2014/11/17 add FastArrayParser in loadjson to specify fast parser applicable levels
+ 2014/09/18 start official github mirror: https://github.com/fangq/jsonlab
+
+== JSONlab 1.0.0-RC1 (codename: Optimus - RC1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2014/09/17  fix several compatibility issues when running on octave versions 3.2-3.8
+ 2014/09/17  support 2D cell and struct arrays in both savejson and saveubjson
+ 2014/08/04  escape special characters in a JSON string
+ 2014/02/16  fix a bug when saving ubjson files
+
+== JSONlab 0.9.9 (codename: Optimus - beta), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2014/01/22  use binary read and write in saveubjson and loadubjson
+
+== JSONlab 0.9.8-1 (codename: Optimus - alpha update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2013/10/07 better round-trip conservation for empty arrays and structs (patch submitted by Yul Kang)
+
+== JSONlab 0.9.8 (codename: Optimus - alpha), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+ 2013/08/23 *universal Binary JSON (UBJSON) support, including both saveubjson and loadubjson
+
+== JSONlab 0.9.1 (codename: Rodimus, update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+ 2012/12/18 *handling of various empty and sparse matrices (fixes submitted by Niclas Borlin)
+
+== JSONlab 0.9.0 (codename: Rodimus), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2012/06/17 *new format for an invalid leading char, unpacking hex code in savejson
+ 2012/06/01  support JSONP in savejson
+ 2012/05/25  fix the empty cell bug (reported by Cyril Davin)
+ 2012/04/05  savejson can save to a file (suggested by Patrick Rapin)
+
+== JSONlab 0.8.1 (codename: Sentiel, Update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2012/02/28  loadjson quotation mark escape bug, see http://bit.ly/yyk1nS
+ 2012/01/25  patch to handle root-less objects, contributed by Blake Johnson
+
+== JSONlab 0.8.0 (codename: Sentiel), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2012/01/13 *speed up loadjson by 20 fold when parsing large data arrays in matlab
+ 2012/01/11  remove row bracket if an array has 1 element, suggested by Mykel Kochenderfer
+ 2011/12/22 *accept sequence of 'param',value input in savejson and loadjson
+ 2011/11/18  fix struct array bug reported by Mykel Kochenderfer
+
+== JSONlab 0.5.1 (codename: Nexus Update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2011/10/21  fix a bug in loadjson, previous code does not use any of the acceleration
+ 2011/10/20  loadjson supports JSON collections - concatenated JSON objects
+
+== JSONlab 0.5.0 (codename: Nexus), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2011/10/16  package and release jsonlab 0.5.0
+ 2011/10/15 *add json demo and regression test, support cpx numbers, fix double quote bug
+ 2011/10/11 *speed up readjson dramatically, interpret _Array* tags, show data in root level
+ 2011/10/10  create jsonlab project, start jsonlab website, add online documentation
+ 2011/10/07 *speed up savejson by 25x using sprintf instead of mat2str, add options support
+ 2011/10/06 *savejson works for structs, cells and arrays
+ 2011/09/09  derive loadjson from JSON parser from MATLAB Central, draft savejson.m

+ 25 - 0
ex2/lib/jsonlab/LICENSE_BSD.txt

@@ -0,0 +1,25 @@
+Copyright 2011-2015 Qianqian Fang <fangq at nmr.mgh.harvard.edu>. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice, this list of
+      conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright notice, this list
+      of conditions and the following disclaimer in the documentation and/or other materials
+      provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those of the
+authors and should not be interpreted as representing official policies, either expressed
+or implied, of the copyright holders.

+ 394 - 0
ex2/lib/jsonlab/README.txt

@@ -0,0 +1,394 @@
+===============================================================================
+=                                 JSONLab                                     =
+=           An open-source MATLAB/Octave JSON encoder and decoder             =
+===============================================================================
+
+*Copyright (C) 2011-2015  Qianqian Fang <fangq at nmr.mgh.harvard.edu>
+*License: BSD License, see License_BSD.txt for details
+*Version: 1.0 (Optimus - Final)
+
+-------------------------------------------------------------------------------
+
+Table of Content:
+
+I.  Introduction
+II. Installation
+III.Using JSONLab
+IV. Known Issues and TODOs
+V.  Contribution and feedback
+
+-------------------------------------------------------------------------------
+
+I.  Introduction
+
+JSON ([http://www.json.org/ JavaScript Object Notation]) is a highly portable, 
+human-readable and "[http://en.wikipedia.org/wiki/JSON fat-free]" text format 
+to represent complex and hierarchical data. It is as powerful as 
+[http://en.wikipedia.org/wiki/XML XML], but less verbose. JSON format is widely 
+used for data-exchange in applications, and is essential for the wild success 
+of [http://en.wikipedia.org/wiki/Ajax_(programming) Ajax] and 
+[http://en.wikipedia.org/wiki/Web_2.0 Web2.0]. 
+
+UBJSON (Universal Binary JSON) is a binary JSON format, specifically 
+optimized for compact file size and better performance while keeping
+the semantics as simple as the text-based JSON format. Using the UBJSON
+format allows to wrap complex binary data in a flexible and extensible
+structure, making it possible to process complex and large dataset 
+without accuracy loss due to text conversions.
+
+We envision that both JSON and its binary version will serve as part of 
+the mainstream data-exchange formats for scientific research in the future. 
+It will provide the flexibility and generality achieved by other popular 
+general-purpose file specifications, such as
+[http://www.hdfgroup.org/HDF5/whatishdf5.html HDF5], with significantly 
+reduced complexity and enhanced performance.
+
+JSONLab is a free and open-source implementation of a JSON/UBJSON encoder 
+and a decoder in the native MATLAB language. It can be used to convert a MATLAB 
+data structure (array, struct, cell, struct array and cell array) into 
+JSON/UBJSON formatted strings, or to decode a JSON/UBJSON file into MATLAB 
+data structure. JSONLab supports both MATLAB and  
+[http://www.gnu.org/software/octave/ GNU Octave] (a free MATLAB clone).
+
+-------------------------------------------------------------------------------
+
+II. Installation
+
+The installation of JSONLab is no different than any other simple
+MATLAB toolbox. You only need to download/unzip the JSONLab package
+to a folder, and add the folder's path to MATLAB/Octave's path list
+by using the following command:
+
+    addpath('/path/to/jsonlab');
+
+If you want to add this path permanently, you need to type "pathtool", 
+browse to the jsonlab root folder and add to the list, then click "Save".
+Then, run "rehash" in MATLAB, and type "which loadjson", if you see an 
+output, that means JSONLab is installed for MATLAB/Octave.
+
+-------------------------------------------------------------------------------
+
+III.Using JSONLab
+
+JSONLab provides two functions, loadjson.m -- a MATLAB->JSON decoder, 
+and savejson.m -- a MATLAB->JSON encoder, for the text-based JSON, and 
+two equivallent functions -- loadubjson and saveubjson for the binary 
+JSON. The detailed help info for the four functions can be found below:
+
+=== loadjson.m ===
+<pre>
+  data=loadjson(fname,opt)
+     or
+  data=loadjson(fname,'param1',value1,'param2',value2,...)
+ 
+  parse a JSON (JavaScript Object Notation) file or string
+ 
+  authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2011/09/09, including previous works from 
+ 
+          Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
+             created on 2009/11/02
+          François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
+             created on  2009/03/22
+          Joel Feenstra:
+          http://www.mathworks.com/matlabcentral/fileexchange/20565
+             created on 2008/07/03
+ 
+  $Id: loadjson.m 452 2014-11-22 16:43:33Z fangq $
+ 
+  input:
+       fname: input file name, if fname contains "{}" or "[]", fname
+              will be interpreted as a JSON string
+       opt: a struct to store parsing options, opt can be replaced by 
+            a list of ('param',value) pairs - the param string is equivallent
+            to a field in opt. opt can have the following 
+            fields (first in [.|.] is the default)
+ 
+            opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat
+                          for each element of the JSON data, and group 
+                          arrays based on the cell2mat rules.
+            opt.FastArrayParser [1|0 or integer]: if set to 1, use a
+                          speed-optimized array parser when loading an 
+                          array object. The fast array parser may 
+                          collapse block arrays into a single large
+                          array similar to rules defined in cell2mat; 0 to 
+                          use a legacy parser; if set to a larger-than-1
+                          value, this option will specify the minimum
+                          dimension to enable the fast array parser. For
+                          example, if the input is a 3D array, setting
+                          FastArrayParser to 1 will return a 3D array;
+                          setting to 2 will return a cell array of 2D
+                          arrays; setting to 3 will return to a 2D cell
+                          array of 1D vectors; setting to 4 will return a
+                          3D cell array.
+            opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar.
+ 
+  output:
+       dat: a cell array, where {...} blocks are converted into cell arrays,
+            and [...] are converted to arrays
+ 
+  examples:
+       dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}')
+       dat=loadjson(['examples' filesep 'example1.json'])
+       dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1)
+</pre>
+
+=== savejson.m ===
+
+<pre>
+  json=savejson(rootname,obj,filename)
+     or
+  json=savejson(rootname,obj,opt)
+  json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
+ 
+  convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
+  Object Notation) string
+ 
+  author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2011/09/09
+ 
+  $Id: savejson.m 458 2014-12-19 22:17:17Z fangq $
+ 
+  input:
+       rootname: the name of the root-object, when set to '', the root name
+         is ignored, however, when opt.ForceRootName is set to 1 (see below),
+         the MATLAB variable name will be used as the root name.
+       obj: a MATLAB object (array, cell, cell array, struct, struct array).
+       filename: a string for the file name to save the output JSON data.
+       opt: a struct for additional options, ignore to use default values.
+         opt can have the following fields (first in [.|.] is the default)
+ 
+         opt.FileName [''|string]: a file name to save the output JSON data
+         opt.FloatFormat ['%.10g'|string]: format to show each numeric element
+                          of a 1D/2D array;
+         opt.ArrayIndent [1|0]: if 1, output explicit data array with
+                          precedent indentation; if 0, no indentation
+         opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
+                          array in JSON array format; if sets to 1, an
+                          array will be shown as a struct with fields
+                          "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+                          sparse arrays, the non-zero elements will be
+                          saved to _ArrayData_ field in triplet-format i.e.
+                          (ix,iy,val) and "_ArrayIsSparse_" will be added
+                          with a value of 1; for a complex array, the 
+                          _ArrayData_ array will include two columns 
+                          (4 for sparse) to record the real and imaginary 
+                          parts, and also "_ArrayIsComplex_":1 is added. 
+         opt.ParseLogical [0|1]: if this is set to 1, logical array elem
+                          will use true/false rather than 1/0.
+         opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+                          numerical element will be shown without a square
+                          bracket, unless it is the root object; if 0, square
+                          brackets are forced for any numerical arrays.
+         opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
+                          will use the name of the passed obj variable as the 
+                          root object name; if obj is an expression and 
+                          does not have a name, 'root' will be used; if this 
+                          is set to 0 and rootname is empty, the root level 
+                          will be merged down to the lower level.
+         opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
+                          to represent +/-Inf. The matched pattern is '([-+]*)Inf'
+                          and $1 represents the sign. For those who want to use
+                          1e999 to represent Inf, they can set opt.Inf to '$11e999'
+         opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
+                          to represent NaN
+         opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+                          for example, if opt.JSONP='foo', the JSON data is
+                          wrapped inside a function call as 'foo(...);'
+         opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+                          back to the string form
+         opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
+         opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs)
+ 
+         opt can be replaced by a list of ('param',value) pairs. The param 
+         string is equivallent to a field in opt and is case sensitive.
+  output:
+       json: a string in the JSON format (see http://json.org)
+ 
+  examples:
+       jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+                'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+                'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+                           2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+                'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+                'SpecialData',[nan, inf, -inf]);
+       savejson('jmesh',jsonmesh)
+       savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g')
+ </pre>
+
+=== loadubjson.m ===
+
+<pre>
+  data=loadubjson(fname,opt)
+     or
+  data=loadubjson(fname,'param1',value1,'param2',value2,...)
+ 
+  parse a JSON (JavaScript Object Notation) file or string
+ 
+  authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2013/08/01
+ 
+  $Id: loadubjson.m 436 2014-08-05 20:51:40Z fangq $
+ 
+  input:
+       fname: input file name, if fname contains "{}" or "[]", fname
+              will be interpreted as a UBJSON string
+       opt: a struct to store parsing options, opt can be replaced by 
+            a list of ('param',value) pairs - the param string is equivallent
+            to a field in opt. opt can have the following 
+            fields (first in [.|.] is the default)
+ 
+            opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
+                          for each element of the JSON data, and group 
+                          arrays based on the cell2mat rules.
+            opt.IntEndian [B|L]: specify the endianness of the integer fields
+                          in the UBJSON input data. B - Big-Endian format for 
+                          integers (as required in the UBJSON specification); 
+                          L - input integer fields are in Little-Endian order.
+ 
+  output:
+       dat: a cell array, where {...} blocks are converted into cell arrays,
+            and [...] are converted to arrays
+ 
+  examples:
+       obj=struct('string','value','array',[1 2 3]);
+       ubjdata=saveubjson('obj',obj);
+       dat=loadubjson(ubjdata)
+       dat=loadubjson(['examples' filesep 'example1.ubj'])
+       dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)
+</pre>
+
+=== saveubjson.m ===
+
+<pre>
+  json=saveubjson(rootname,obj,filename)
+     or
+  json=saveubjson(rootname,obj,opt)
+  json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
+ 
+  convert a MATLAB object (cell, struct or array) into a Universal 
+  Binary JSON (UBJSON) binary string
+ 
+  author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2013/08/17
+ 
+  $Id: saveubjson.m 440 2014-09-17 19:59:45Z fangq $
+ 
+  input:
+       rootname: the name of the root-object, when set to '', the root name
+         is ignored, however, when opt.ForceRootName is set to 1 (see below),
+         the MATLAB variable name will be used as the root name.
+       obj: a MATLAB object (array, cell, cell array, struct, struct array)
+       filename: a string for the file name to save the output UBJSON data
+       opt: a struct for additional options, ignore to use default values.
+         opt can have the following fields (first in [.|.] is the default)
+ 
+         opt.FileName [''|string]: a file name to save the output JSON data
+         opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
+                          array in JSON array format; if sets to 1, an
+                          array will be shown as a struct with fields
+                          "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+                          sparse arrays, the non-zero elements will be
+                          saved to _ArrayData_ field in triplet-format i.e.
+                          (ix,iy,val) and "_ArrayIsSparse_" will be added
+                          with a value of 1; for a complex array, the 
+                          _ArrayData_ array will include two columns 
+                          (4 for sparse) to record the real and imaginary 
+                          parts, and also "_ArrayIsComplex_":1 is added. 
+         opt.ParseLogical [1|0]: if this is set to 1, logical array elem
+                          will use true/false rather than 1/0.
+         opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+                          numerical element will be shown without a square
+                          bracket, unless it is the root object; if 0, square
+                          brackets are forced for any numerical arrays.
+         opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
+                          will use the name of the passed obj variable as the 
+                          root object name; if obj is an expression and 
+                          does not have a name, 'root' will be used; if this 
+                          is set to 0 and rootname is empty, the root level 
+                          will be merged down to the lower level.
+         opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+                          for example, if opt.JSON='foo', the JSON data is
+                          wrapped inside a function call as 'foo(...);'
+         opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+                          back to the string form
+ 
+         opt can be replaced by a list of ('param',value) pairs. The param 
+         string is equivallent to a field in opt and is case sensitive.
+  output:
+       json: a binary string in the UBJSON format (see http://ubjson.org)
+ 
+  examples:
+       jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+                'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+                'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+                           2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+                'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+                'SpecialData',[nan, inf, -inf]);
+       saveubjson('jsonmesh',jsonmesh)
+       saveubjson('jsonmesh',jsonmesh,'meshdata.ubj')
+</pre>
+
+
+=== examples ===
+
+Under the "examples" folder, you can find several scripts to demonstrate the
+basic utilities of JSONLab. Running the "demo_jsonlab_basic.m" script, you 
+will see the conversions from MATLAB data structure to JSON text and backward.
+In "jsonlab_selftest.m", we load complex JSON files downloaded from the Internet
+and validate the loadjson/savejson functions for regression testing purposes.
+Similarly, a "demo_ubjson_basic.m" script is provided to test the saveubjson
+and loadubjson pairs for various matlab data structures.
+
+Please run these examples and understand how JSONLab works before you use
+it to process your data.
+
+-------------------------------------------------------------------------------
+
+IV. Known Issues and TODOs
+
+JSONLab has several known limitations. We are striving to make it more general
+and robust. Hopefully in a few future releases, the limitations become less.
+
+Here are the known issues:
+
+# 3D or higher dimensional cell/struct-arrays will be converted to 2D arrays;
+# When processing names containing multi-byte characters, Octave and MATLAB \
+can give different field-names; you can use feature('DefaultCharacterSet','latin1') \
+in MATLAB to get consistant results
+# savejson can not handle class and dataset.
+# saveubjson converts a logical array into a uint8 ([U]) array
+# an unofficial N-D array count syntax is implemented in saveubjson. We are \
+actively communicating with the UBJSON spec maintainer to investigate the \
+possibility of making it upstream
+# loadubjson can not parse all UBJSON Specification (Draft 9) compliant \
+files, however, it can parse all UBJSON files produced by saveubjson.
+
+-------------------------------------------------------------------------------
+
+V. Contribution and feedback
+
+JSONLab is an open-source project. This means you can not only use it and modify
+it as you wish, but also you can contribute your changes back to JSONLab so
+that everyone else can enjoy the improvement. For anyone who want to contribute,
+please download JSONLab source code from it's subversion repository by using the
+following command:
+
+ svn checkout svn://svn.code.sf.net/p/iso2mesh/code/trunk/jsonlab jsonlab
+
+You can make changes to the files as needed. Once you are satisfied with your
+changes, and ready to share it with others, please cd the root directory of 
+JSONLab, and type
+
+ svn diff > yourname_featurename.patch
+
+You then email the .patch file to JSONLab's maintainer, Qianqian Fang, at
+the email address shown in the beginning of this file. Qianqian will review 
+the changes and commit it to the subversion if they are satisfactory.
+
+We appreciate any suggestions and feedbacks from you. Please use iso2mesh's
+mailing list to report any questions you may have with JSONLab:
+
+http://groups.google.com/group/iso2mesh-users?hl=en&pli=1
+
+(Subscription to the mailing list is needed in order to post messages).

+ 32 - 0
ex2/lib/jsonlab/jsonopt.m

@@ -0,0 +1,32 @@
+function val=jsonopt(key,default,varargin)
+%
+% val=jsonopt(key,default,optstruct)
+%
+% setting options based on a struct. The struct can be produced
+% by varargin2struct from a list of 'param','value' pairs
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+%
+% $Id: loadjson.m 371 2012-06-20 12:43:06Z fangq $
+%
+% input:
+%      key: a string with which one look up a value from a struct
+%      default: if the key does not exist, return default
+%      optstruct: a struct where each sub-field is a key 
+%
+% output:
+%      val: if key exists, val=optstruct.key; otherwise val=default
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details
+%
+% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+% 
+
+val=default;
+if(nargin<=2) return; end
+opt=varargin{1};
+if(isstruct(opt) && isfield(opt,key))
+    val=getfield(opt,key);
+end
+

+ 566 - 0
ex2/lib/jsonlab/loadjson.m

@@ -0,0 +1,566 @@
+function data = loadjson(fname,varargin)
+%
+% data=loadjson(fname,opt)
+%    or
+% data=loadjson(fname,'param1',value1,'param2',value2,...)
+%
+% parse a JSON (JavaScript Object Notation) file or string
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2011/09/09, including previous works from 
+%
+%         Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
+%            created on 2009/11/02
+%         François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
+%            created on  2009/03/22
+%         Joel Feenstra:
+%         http://www.mathworks.com/matlabcentral/fileexchange/20565
+%            created on 2008/07/03
+%
+% $Id: loadjson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      fname: input file name, if fname contains "{}" or "[]", fname
+%             will be interpreted as a JSON string
+%      opt: a struct to store parsing options, opt can be replaced by 
+%           a list of ('param',value) pairs - the param string is equivallent
+%           to a field in opt. opt can have the following 
+%           fields (first in [.|.] is the default)
+%
+%           opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat
+%                         for each element of the JSON data, and group 
+%                         arrays based on the cell2mat rules.
+%           opt.FastArrayParser [1|0 or integer]: if set to 1, use a
+%                         speed-optimized array parser when loading an 
+%                         array object. The fast array parser may 
+%                         collapse block arrays into a single large
+%                         array similar to rules defined in cell2mat; 0 to 
+%                         use a legacy parser; if set to a larger-than-1
+%                         value, this option will specify the minimum
+%                         dimension to enable the fast array parser. For
+%                         example, if the input is a 3D array, setting
+%                         FastArrayParser to 1 will return a 3D array;
+%                         setting to 2 will return a cell array of 2D
+%                         arrays; setting to 3 will return to a 2D cell
+%                         array of 1D vectors; setting to 4 will return a
+%                         3D cell array.
+%           opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar.
+%
+% output:
+%      dat: a cell array, where {...} blocks are converted into cell arrays,
+%           and [...] are converted to arrays
+%
+% examples:
+%      dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}')
+%      dat=loadjson(['examples' filesep 'example1.json'])
+%      dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1)
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details 
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+global pos inStr len  esc index_esc len_esc isoct arraytoken
+
+if(regexp(fname,'[\{\}\]\[]','once'))
+   string=fname;
+elseif(exist(fname,'file'))
+   fid = fopen(fname,'rb');
+   string = fread(fid,inf,'uint8=>char')';
+   fclose(fid);
+else
+   error('input file does not exist');
+end
+
+pos = 1; len = length(string); inStr = string;
+isoct=exist('OCTAVE_VERSION','builtin');
+arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
+jstr=regexprep(inStr,'\\\\','  ');
+escquote=regexp(jstr,'\\"');
+arraytoken=sort([arraytoken escquote]);
+
+% String delimiters and escape chars identified to improve speed:
+esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
+index_esc = 1; len_esc = length(esc);
+
+opt=varargin2struct(varargin{:});
+
+if(jsonopt('ShowProgress',0,opt)==1)
+    opt.progressbar_=waitbar(0,'loading ...');
+end
+jsoncount=1;
+while pos <= len
+    switch(next_char)
+        case '{'
+            data{jsoncount} = parse_object(opt);
+        case '['
+            data{jsoncount} = parse_array(opt);
+        otherwise
+            error_pos('Outer level structure must be an object or an array');
+    end
+    jsoncount=jsoncount+1;
+end % while
+
+jsoncount=length(data);
+if(jsoncount==1 && iscell(data))
+    data=data{1};
+end
+
+if(~isempty(data))
+      if(isstruct(data)) % data can be a struct array
+          data=jstruct2array(data);
+      elseif(iscell(data))
+          data=jcell2array(data);
+      end
+end
+if(isfield(opt,'progressbar_'))
+    close(opt.progressbar_);
+end
+
+%%
+function newdata=jcell2array(data)
+len=length(data);
+newdata=data;
+for i=1:len
+      if(isstruct(data{i}))
+          newdata{i}=jstruct2array(data{i});
+      elseif(iscell(data{i}))
+          newdata{i}=jcell2array(data{i});
+      end
+end
+
+%%-------------------------------------------------------------------------
+function newdata=jstruct2array(data)
+fn=fieldnames(data);
+newdata=data;
+len=length(data);
+for i=1:length(fn) % depth-first
+    for j=1:len
+        if(isstruct(getfield(data(j),fn{i})))
+            newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
+        end
+    end
+end
+if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
+  newdata=cell(len,1);
+  for j=1:len
+    ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
+    iscpx=0;
+    if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
+        if(data(j).x0x5F_ArrayIsComplex_)
+           iscpx=1;
+        end
+    end
+    if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
+        if(data(j).x0x5F_ArrayIsSparse_)
+            if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+                dim=data(j).x0x5F_ArraySize_;
+                if(iscpx && size(ndata,2)==4-any(dim==1))
+                    ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
+                end
+                if isempty(ndata)
+                    % All-zeros sparse
+                    ndata=sparse(dim(1),prod(dim(2:end)));
+                elseif dim(1)==1
+                    % Sparse row vector
+                    ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
+                elseif dim(2)==1
+                    % Sparse column vector
+                    ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
+                else
+                    % Generic sparse array.
+                    ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
+                end
+            else
+                if(iscpx && size(ndata,2)==4)
+                    ndata(:,3)=complex(ndata(:,3),ndata(:,4));
+                end
+                ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
+            end
+        end
+    elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+        if(iscpx && size(ndata,2)==2)
+             ndata=complex(ndata(:,1),ndata(:,2));
+        end
+        ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
+    end
+    newdata{j}=ndata;
+  end
+  if(len==1)
+      newdata=newdata{1};
+  end
+end
+
+%%-------------------------------------------------------------------------
+function object = parse_object(varargin)
+    parse_char('{');
+    object = [];
+    if next_char ~= '}'
+        while 1
+            str = parseStr(varargin{:});
+            if isempty(str)
+                error_pos('Name of value at position %d cannot be empty');
+            end
+            parse_char(':');
+            val = parse_value(varargin{:});
+            eval( sprintf( 'object.%s  = val;', valid_field(str) ) );
+            if next_char == '}'
+                break;
+            end
+            parse_char(',');
+        end
+    end
+    parse_char('}');
+
+%%-------------------------------------------------------------------------
+
+function object = parse_array(varargin) % JSON array is written in row-major order
+global pos inStr isoct
+    parse_char('[');
+    object = cell(0, 1);
+    dim2=[];
+    arraydepth=jsonopt('JSONLAB_ArrayDepth_',1,varargin{:});
+    pbar=jsonopt('progressbar_',-1,varargin{:});
+
+    if next_char ~= ']'
+	if(jsonopt('FastArrayParser',1,varargin{:})>=1 && arraydepth>=jsonopt('FastArrayParser',1,varargin{:}))
+            [endpos, e1l, e1r, maxlevel]=matching_bracket(inStr,pos);
+            arraystr=['[' inStr(pos:endpos)];
+            arraystr=regexprep(arraystr,'"_NaN_"','NaN');
+            arraystr=regexprep(arraystr,'"([-+]*)_Inf_"','$1Inf');
+            arraystr(arraystr==sprintf('\n'))=[];
+            arraystr(arraystr==sprintf('\r'))=[];
+            %arraystr=regexprep(arraystr,'\s*,',','); % this is slow,sometimes needed
+            if(~isempty(e1l) && ~isempty(e1r)) % the array is in 2D or higher D
+        	astr=inStr((e1l+1):(e1r-1));
+        	astr=regexprep(astr,'"_NaN_"','NaN');
+        	astr=regexprep(astr,'"([-+]*)_Inf_"','$1Inf');
+        	astr(astr==sprintf('\n'))=[];
+        	astr(astr==sprintf('\r'))=[];
+        	astr(astr==' ')='';
+        	if(isempty(find(astr=='[', 1))) % array is 2D
+                    dim2=length(sscanf(astr,'%f,',[1 inf]));
+        	end
+            else % array is 1D
+        	astr=arraystr(2:end-1);
+        	astr(astr==' ')='';
+        	[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',[1,inf]);
+        	if(nextidx>=length(astr)-1)
+                    object=obj;
+                    pos=endpos;
+                    parse_char(']');
+                    return;
+        	end
+            end
+            if(~isempty(dim2))
+        	astr=arraystr;
+        	astr(astr=='[')='';
+        	astr(astr==']')='';
+        	astr(astr==' ')='';
+        	[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',inf);
+        	if(nextidx>=length(astr)-1)
+                    object=reshape(obj,dim2,numel(obj)/dim2)';
+                    pos=endpos;
+                    parse_char(']');
+                    if(pbar>0)
+                        waitbar(pos/length(inStr),pbar,'loading ...');
+                    end
+                    return;
+        	end
+            end
+            arraystr=regexprep(arraystr,'\]\s*,','];');
+	else
+            arraystr='[';
+	end
+        try
+           if(isoct && regexp(arraystr,'"','once'))
+                error('Octave eval can produce empty cells for JSON-like input');
+           end
+           object=eval(arraystr);
+           pos=endpos;
+        catch
+         while 1
+            newopt=varargin2struct(varargin{:},'JSONLAB_ArrayDepth_',arraydepth+1);
+            val = parse_value(newopt);
+            object{end+1} = val;
+            if next_char == ']'
+                break;
+            end
+            parse_char(',');
+         end
+        end
+    end
+    if(jsonopt('SimplifyCell',0,varargin{:})==1)
+      try
+        oldobj=object;
+        object=cell2mat(object')';
+        if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
+            object=oldobj;
+        elseif(size(object,1)>1 && ndims(object)==2)
+            object=object';
+        end
+      catch
+      end
+    end
+    parse_char(']');
+    
+    if(pbar>0)
+        waitbar(pos/length(inStr),pbar,'loading ...');
+    end
+%%-------------------------------------------------------------------------
+
+function parse_char(c)
+    global pos inStr len
+    skip_whitespace;
+    if pos > len || inStr(pos) ~= c
+        error_pos(sprintf('Expected %c at position %%d', c));
+    else
+        pos = pos + 1;
+        skip_whitespace;
+    end
+
+%%-------------------------------------------------------------------------
+
+function c = next_char
+    global pos inStr len
+    skip_whitespace;
+    if pos > len
+        c = [];
+    else
+        c = inStr(pos);
+    end
+
+%%-------------------------------------------------------------------------
+
+function skip_whitespace
+    global pos inStr len
+    while pos <= len && isspace(inStr(pos))
+        pos = pos + 1;
+    end
+
+%%-------------------------------------------------------------------------
+function str = parseStr(varargin)
+    global pos inStr len  esc index_esc len_esc
+ % len, ns = length(inStr), keyboard
+    if inStr(pos) ~= '"'
+        error_pos('String starting with " expected at position %d');
+    else
+        pos = pos + 1;
+    end
+    str = '';
+    while pos <= len
+        while index_esc <= len_esc && esc(index_esc) < pos
+            index_esc = index_esc + 1;
+        end
+        if index_esc > len_esc
+            str = [str inStr(pos:len)];
+            pos = len + 1;
+            break;
+        else
+            str = [str inStr(pos:esc(index_esc)-1)];
+            pos = esc(index_esc);
+        end
+        nstr = length(str); switch inStr(pos)
+            case '"'
+                pos = pos + 1;
+                if(~isempty(str))
+                    if(strcmp(str,'_Inf_'))
+                        str=Inf;
+                    elseif(strcmp(str,'-_Inf_'))
+                        str=-Inf;
+                    elseif(strcmp(str,'_NaN_'))
+                        str=NaN;
+                    end
+                end
+                return;
+            case '\'
+                if pos+1 > len
+                    error_pos('End of file reached right after escape character');
+                end
+                pos = pos + 1;
+                switch inStr(pos)
+                    case {'"' '\' '/'}
+                        str(nstr+1) = inStr(pos);
+                        pos = pos + 1;
+                    case {'b' 'f' 'n' 'r' 't'}
+                        str(nstr+1) = sprintf(['\' inStr(pos)]);
+                        pos = pos + 1;
+                    case 'u'
+                        if pos+4 > len
+                            error_pos('End of file reached in escaped unicode character');
+                        end
+                        str(nstr+(1:6)) = inStr(pos-1:pos+4);
+                        pos = pos + 5;
+                end
+            otherwise % should never happen
+                str(nstr+1) = inStr(pos), keyboard
+                pos = pos + 1;
+        end
+    end
+    error_pos('End of file while expecting end of inStr');
+
+%%-------------------------------------------------------------------------
+
+function num = parse_number(varargin)
+    global pos inStr len isoct
+    currstr=inStr(pos:end);
+    numstr=0;
+    if(isoct~=0)
+        numstr=regexp(currstr,'^\s*-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?','end');
+        [num, one] = sscanf(currstr, '%f', 1);
+        delta=numstr+1;
+    else
+        [num, one, err, delta] = sscanf(currstr, '%f', 1);
+        if ~isempty(err)
+            error_pos('Error reading number at position %d');
+        end
+    end
+    pos = pos + delta-1;
+
+%%-------------------------------------------------------------------------
+
+function val = parse_value(varargin)
+    global pos inStr len
+    true = 1; false = 0;
+    
+    pbar=jsonopt('progressbar_',-1,varargin{:});
+    if(pbar>0)
+        waitbar(pos/len,pbar,'loading ...');
+    end
+    
+    switch(inStr(pos))
+        case '"'
+            val = parseStr(varargin{:});
+            return;
+        case '['
+            val = parse_array(varargin{:});
+            return;
+        case '{'
+            val = parse_object(varargin{:});
+            if isstruct(val)
+                if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
+                    val=jstruct2array(val);
+                end
+            elseif isempty(val)
+                val = struct;
+            end
+            return;
+        case {'-','0','1','2','3','4','5','6','7','8','9'}
+            val = parse_number(varargin{:});
+            return;
+        case 't'
+            if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'true')
+                val = true;
+                pos = pos + 4;
+                return;
+            end
+        case 'f'
+            if pos+4 <= len && strcmpi(inStr(pos:pos+4), 'false')
+                val = false;
+                pos = pos + 5;
+                return;
+            end
+        case 'n'
+            if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'null')
+                val = [];
+                pos = pos + 4;
+                return;
+            end
+    end
+    error_pos('Value expected at position %d');
+%%-------------------------------------------------------------------------
+
+function error_pos(msg)
+    global pos inStr len
+    poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
+    if poShow(3) == poShow(2)
+        poShow(3:4) = poShow(2)+[0 -1];  % display nothing after
+    end
+    msg = [sprintf(msg, pos) ': ' ...
+    inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
+    error( ['JSONparser:invalidFormat: ' msg] );
+
+%%-------------------------------------------------------------------------
+
+function str = valid_field(str)
+global isoct
+% From MATLAB doc: field names must begin with a letter, which may be
+% followed by any combination of letters, digits, and underscores.
+% Invalid characters will be converted to underscores, and the prefix
+% "x0x[Hex code]_" will be added if the first character is not a letter.
+    pos=regexp(str,'^[^A-Za-z]','once');
+    if(~isempty(pos))
+        if(~isoct)
+            str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
+        else
+            str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
+        end
+    end
+    if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return;  end
+    if(~isoct)
+        str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
+    else
+        pos=regexp(str,'[^0-9A-Za-z_]');
+        if(isempty(pos)) return; end
+        str0=str;
+        pos0=[0 pos(:)' length(str)];
+        str='';
+        for i=1:length(pos)
+            str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
+        end
+        if(pos(end)~=length(str))
+            str=[str str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+    %str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
+
+%%-------------------------------------------------------------------------
+function endpos = matching_quote(str,pos)
+len=length(str);
+while(pos<len)
+    if(str(pos)=='"')
+        if(~(pos>1 && str(pos-1)=='\'))
+            endpos=pos;
+            return;
+        end        
+    end
+    pos=pos+1;
+end
+error('unmatched quotation mark');
+%%-------------------------------------------------------------------------
+function [endpos, e1l, e1r, maxlevel] = matching_bracket(str,pos)
+global arraytoken
+level=1;
+maxlevel=level;
+endpos=0;
+bpos=arraytoken(arraytoken>=pos);
+tokens=str(bpos);
+len=length(tokens);
+pos=1;
+e1l=[];
+e1r=[];
+while(pos<=len)
+    c=tokens(pos);
+    if(c==']')
+        level=level-1;
+        if(isempty(e1r)) e1r=bpos(pos); end
+        if(level==0)
+            endpos=bpos(pos);
+            return
+        end
+    end
+    if(c=='[')
+        if(isempty(e1l)) e1l=bpos(pos); end
+        level=level+1;
+        maxlevel=max(maxlevel,level);
+    end
+    if(c=='"')
+        pos=matching_quote(tokens,pos+1);
+    end
+    pos=pos+1;
+end
+if(endpos==0) 
+    error('unmatched "]"');
+end
+

+ 528 - 0
ex2/lib/jsonlab/loadubjson.m

@@ -0,0 +1,528 @@
+function data = loadubjson(fname,varargin)
+%
+% data=loadubjson(fname,opt)
+%    or
+% data=loadubjson(fname,'param1',value1,'param2',value2,...)
+%
+% parse a JSON (JavaScript Object Notation) file or string
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2013/08/01
+%
+% $Id: loadubjson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      fname: input file name, if fname contains "{}" or "[]", fname
+%             will be interpreted as a UBJSON string
+%      opt: a struct to store parsing options, opt can be replaced by 
+%           a list of ('param',value) pairs - the param string is equivallent
+%           to a field in opt. opt can have the following 
+%           fields (first in [.|.] is the default)
+%
+%           opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
+%                         for each element of the JSON data, and group 
+%                         arrays based on the cell2mat rules.
+%           opt.IntEndian [B|L]: specify the endianness of the integer fields
+%                         in the UBJSON input data. B - Big-Endian format for 
+%                         integers (as required in the UBJSON specification); 
+%                         L - input integer fields are in Little-Endian order.
+%
+% output:
+%      dat: a cell array, where {...} blocks are converted into cell arrays,
+%           and [...] are converted to arrays
+%
+% examples:
+%      obj=struct('string','value','array',[1 2 3]);
+%      ubjdata=saveubjson('obj',obj);
+%      dat=loadubjson(ubjdata)
+%      dat=loadubjson(['examples' filesep 'example1.ubj'])
+%      dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details 
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+global pos inStr len  esc index_esc len_esc isoct arraytoken fileendian systemendian
+
+if(regexp(fname,'[\{\}\]\[]','once'))
+   string=fname;
+elseif(exist(fname,'file'))
+   fid = fopen(fname,'rb');
+   string = fread(fid,inf,'uint8=>char')';
+   fclose(fid);
+else
+   error('input file does not exist');
+end
+
+pos = 1; len = length(string); inStr = string;
+isoct=exist('OCTAVE_VERSION','builtin');
+arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
+jstr=regexprep(inStr,'\\\\','  ');
+escquote=regexp(jstr,'\\"');
+arraytoken=sort([arraytoken escquote]);
+
+% String delimiters and escape chars identified to improve speed:
+esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
+index_esc = 1; len_esc = length(esc);
+
+opt=varargin2struct(varargin{:});
+fileendian=upper(jsonopt('IntEndian','B',opt));
+[os,maxelem,systemendian]=computer;
+
+jsoncount=1;
+while pos <= len
+    switch(next_char)
+        case '{'
+            data{jsoncount} = parse_object(opt);
+        case '['
+            data{jsoncount} = parse_array(opt);
+        otherwise
+            error_pos('Outer level structure must be an object or an array');
+    end
+    jsoncount=jsoncount+1;
+end % while
+
+jsoncount=length(data);
+if(jsoncount==1 && iscell(data))
+    data=data{1};
+end
+
+if(~isempty(data))
+      if(isstruct(data)) % data can be a struct array
+          data=jstruct2array(data);
+      elseif(iscell(data))
+          data=jcell2array(data);
+      end
+end
+
+
+%%
+function newdata=parse_collection(id,data,obj)
+
+if(jsoncount>0 && exist('data','var')) 
+    if(~iscell(data))
+       newdata=cell(1);
+       newdata{1}=data;
+       data=newdata;
+    end
+end
+
+%%
+function newdata=jcell2array(data)
+len=length(data);
+newdata=data;
+for i=1:len
+      if(isstruct(data{i}))
+          newdata{i}=jstruct2array(data{i});
+      elseif(iscell(data{i}))
+          newdata{i}=jcell2array(data{i});
+      end
+end
+
+%%-------------------------------------------------------------------------
+function newdata=jstruct2array(data)
+fn=fieldnames(data);
+newdata=data;
+len=length(data);
+for i=1:length(fn) % depth-first
+    for j=1:len
+        if(isstruct(getfield(data(j),fn{i})))
+            newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
+        end
+    end
+end
+if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
+  newdata=cell(len,1);
+  for j=1:len
+    ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
+    iscpx=0;
+    if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
+        if(data(j).x0x5F_ArrayIsComplex_)
+           iscpx=1;
+        end
+    end
+    if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
+        if(data(j).x0x5F_ArrayIsSparse_)
+            if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+                dim=double(data(j).x0x5F_ArraySize_);
+                if(iscpx && size(ndata,2)==4-any(dim==1))
+                    ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
+                end
+                if isempty(ndata)
+                    % All-zeros sparse
+                    ndata=sparse(dim(1),prod(dim(2:end)));
+                elseif dim(1)==1
+                    % Sparse row vector
+                    ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
+                elseif dim(2)==1
+                    % Sparse column vector
+                    ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
+                else
+                    % Generic sparse array.
+                    ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
+                end
+            else
+                if(iscpx && size(ndata,2)==4)
+                    ndata(:,3)=complex(ndata(:,3),ndata(:,4));
+                end
+                ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
+            end
+        end
+    elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+        if(iscpx && size(ndata,2)==2)
+             ndata=complex(ndata(:,1),ndata(:,2));
+        end
+        ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
+    end
+    newdata{j}=ndata;
+  end
+  if(len==1)
+      newdata=newdata{1};
+  end
+end
+
+%%-------------------------------------------------------------------------
+function object = parse_object(varargin)
+    parse_char('{');
+    object = [];
+    type='';
+    count=-1;
+    if(next_char == '$')
+        type=inStr(pos+1); % TODO
+        pos=pos+2;
+    end
+    if(next_char == '#')
+        pos=pos+1;
+        count=double(parse_number());
+    end
+    if next_char ~= '}'
+        num=0;
+        while 1
+            str = parseStr(varargin{:});
+            if isempty(str)
+                error_pos('Name of value at position %d cannot be empty');
+            end
+            %parse_char(':');
+            val = parse_value(varargin{:});
+            num=num+1;
+            eval( sprintf( 'object.%s  = val;', valid_field(str) ) );
+            if next_char == '}' || (count>=0 && num>=count)
+                break;
+            end
+            %parse_char(',');
+        end
+    end
+    if(count==-1)
+        parse_char('}');
+    end
+
+%%-------------------------------------------------------------------------
+function [cid,len]=elem_info(type)
+id=strfind('iUIlLdD',type);
+dataclass={'int8','uint8','int16','int32','int64','single','double'};
+bytelen=[1,1,2,4,8,4,8];
+if(id>0)
+    cid=dataclass{id};
+    len=bytelen(id);
+else
+    error_pos('unsupported type at position %d');
+end
+%%-------------------------------------------------------------------------
+
+
+function [data adv]=parse_block(type,count,varargin)
+global pos inStr isoct fileendian systemendian
+[cid,len]=elem_info(type);
+datastr=inStr(pos:pos+len*count-1);
+if(isoct)
+    newdata=int8(datastr);
+else
+    newdata=uint8(datastr);
+end
+id=strfind('iUIlLdD',type);
+if(id<=5 && fileendian~=systemendian)
+    newdata=swapbytes(typecast(newdata,cid));
+end
+data=typecast(newdata,cid);
+adv=double(len*count);
+
+%%-------------------------------------------------------------------------
+
+
+function object = parse_array(varargin) % JSON array is written in row-major order
+global pos inStr isoct
+    parse_char('[');
+    object = cell(0, 1);
+    dim=[];
+    type='';
+    count=-1;
+    if(next_char == '$')
+        type=inStr(pos+1);
+        pos=pos+2;
+    end
+    if(next_char == '#')
+        pos=pos+1;
+        if(next_char=='[')
+            dim=parse_array(varargin{:});
+            count=prod(double(dim));
+        else
+            count=double(parse_number());
+        end
+    end
+    if(~isempty(type))
+        if(count>=0)
+            [object adv]=parse_block(type,count,varargin{:});
+            if(~isempty(dim))
+                object=reshape(object,dim);
+            end
+            pos=pos+adv;
+            return;
+        else
+            endpos=matching_bracket(inStr,pos);
+            [cid,len]=elem_info(type);
+            count=(endpos-pos)/len;
+            [object adv]=parse_block(type,count,varargin{:});
+            pos=pos+adv;
+            parse_char(']');
+            return;
+        end
+    end
+    if next_char ~= ']'
+         while 1
+            val = parse_value(varargin{:});
+            object{end+1} = val;
+            if next_char == ']'
+                break;
+            end
+            %parse_char(',');
+         end
+    end
+    if(jsonopt('SimplifyCell',0,varargin{:})==1)
+      try
+        oldobj=object;
+        object=cell2mat(object')';
+        if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
+            object=oldobj;
+        elseif(size(object,1)>1 && ndims(object)==2)
+            object=object';
+        end
+      catch
+      end
+    end
+    if(count==-1)
+        parse_char(']');
+    end
+
+%%-------------------------------------------------------------------------
+
+function parse_char(c)
+    global pos inStr len
+    skip_whitespace;
+    if pos > len || inStr(pos) ~= c
+        error_pos(sprintf('Expected %c at position %%d', c));
+    else
+        pos = pos + 1;
+        skip_whitespace;
+    end
+
+%%-------------------------------------------------------------------------
+
+function c = next_char
+    global pos inStr len
+    skip_whitespace;
+    if pos > len
+        c = [];
+    else
+        c = inStr(pos);
+    end
+
+%%-------------------------------------------------------------------------
+
+function skip_whitespace
+    global pos inStr len
+    while pos <= len && isspace(inStr(pos))
+        pos = pos + 1;
+    end
+
+%%-------------------------------------------------------------------------
+function str = parseStr(varargin)
+    global pos inStr esc index_esc len_esc
+ % len, ns = length(inStr), keyboard
+    type=inStr(pos);
+    if type ~= 'S' && type ~= 'C' && type ~= 'H'
+        error_pos('String starting with S expected at position %d');
+    else
+        pos = pos + 1;
+    end
+    if(type == 'C')
+        str=inStr(pos);
+        pos=pos+1;
+        return;
+    end
+    bytelen=double(parse_number());
+    if(length(inStr)>=pos+bytelen-1)
+        str=inStr(pos:pos+bytelen-1);
+        pos=pos+bytelen;
+    else
+        error_pos('End of file while expecting end of inStr');
+    end
+
+%%-------------------------------------------------------------------------
+
+function num = parse_number(varargin)
+    global pos inStr len isoct fileendian systemendian
+    id=strfind('iUIlLdD',inStr(pos));
+    if(isempty(id))
+        error_pos('expecting a number at position %d');
+    end
+    type={'int8','uint8','int16','int32','int64','single','double'};
+    bytelen=[1,1,2,4,8,4,8];
+    datastr=inStr(pos+1:pos+bytelen(id));
+    if(isoct)
+        newdata=int8(datastr);
+    else
+        newdata=uint8(datastr);
+    end
+    if(id<=5 && fileendian~=systemendian)
+        newdata=swapbytes(typecast(newdata,type{id}));
+    end
+    num=typecast(newdata,type{id});
+    pos = pos + bytelen(id)+1;
+
+%%-------------------------------------------------------------------------
+
+function val = parse_value(varargin)
+    global pos inStr len
+    true = 1; false = 0;
+
+    switch(inStr(pos))
+        case {'S','C','H'}
+            val = parseStr(varargin{:});
+            return;
+        case '['
+            val = parse_array(varargin{:});
+            return;
+        case '{'
+            val = parse_object(varargin{:});
+            if isstruct(val)
+                if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
+                    val=jstruct2array(val);
+                end
+            elseif isempty(val)
+                val = struct;
+            end
+            return;
+        case {'i','U','I','l','L','d','D'}
+            val = parse_number(varargin{:});
+            return;
+        case 'T'
+            val = true;
+            pos = pos + 1;
+            return;
+        case 'F'
+            val = false;
+            pos = pos + 1;
+            return;
+        case {'Z','N'}
+            val = [];
+            pos = pos + 1;
+            return;
+    end
+    error_pos('Value expected at position %d');
+%%-------------------------------------------------------------------------
+
+function error_pos(msg)
+    global pos inStr len
+    poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
+    if poShow(3) == poShow(2)
+        poShow(3:4) = poShow(2)+[0 -1];  % display nothing after
+    end
+    msg = [sprintf(msg, pos) ': ' ...
+    inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
+    error( ['JSONparser:invalidFormat: ' msg] );
+
+%%-------------------------------------------------------------------------
+
+function str = valid_field(str)
+global isoct
+% From MATLAB doc: field names must begin with a letter, which may be
+% followed by any combination of letters, digits, and underscores.
+% Invalid characters will be converted to underscores, and the prefix
+% "x0x[Hex code]_" will be added if the first character is not a letter.
+    pos=regexp(str,'^[^A-Za-z]','once');
+    if(~isempty(pos))
+        if(~isoct)
+            str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
+        else
+            str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
+        end
+    end
+    if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return;  end
+    if(~isoct)
+        str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
+    else
+        pos=regexp(str,'[^0-9A-Za-z_]');
+        if(isempty(pos)) return; end
+        str0=str;
+        pos0=[0 pos(:)' length(str)];
+        str='';
+        for i=1:length(pos)
+            str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
+        end
+        if(pos(end)~=length(str))
+            str=[str str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+    %str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
+
+%%-------------------------------------------------------------------------
+function endpos = matching_quote(str,pos)
+len=length(str);
+while(pos<len)
+    if(str(pos)=='"')
+        if(~(pos>1 && str(pos-1)=='\'))
+            endpos=pos;
+            return;
+        end        
+    end
+    pos=pos+1;
+end
+error('unmatched quotation mark');
+%%-------------------------------------------------------------------------
+function [endpos e1l e1r maxlevel] = matching_bracket(str,pos)
+global arraytoken
+level=1;
+maxlevel=level;
+endpos=0;
+bpos=arraytoken(arraytoken>=pos);
+tokens=str(bpos);
+len=length(tokens);
+pos=1;
+e1l=[];
+e1r=[];
+while(pos<=len)
+    c=tokens(pos);
+    if(c==']')
+        level=level-1;
+        if(isempty(e1r)) e1r=bpos(pos); end
+        if(level==0)
+            endpos=bpos(pos);
+            return
+        end
+    end
+    if(c=='[')
+        if(isempty(e1l)) e1l=bpos(pos); end
+        level=level+1;
+        maxlevel=max(maxlevel,level);
+    end
+    if(c=='"')
+        pos=matching_quote(tokens,pos+1);
+    end
+    pos=pos+1;
+end
+if(endpos==0) 
+    error('unmatched "]"');
+end
+

+ 33 - 0
ex2/lib/jsonlab/mergestruct.m

@@ -0,0 +1,33 @@
+function s=mergestruct(s1,s2)
+%
+% s=mergestruct(s1,s2)
+%
+% merge two struct objects into one
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% date: 2012/12/22
+%
+% input:
+%      s1,s2: a struct object, s1 and s2 can not be arrays
+%
+% output:
+%      s: the merged struct object. fields in s1 and s2 will be combined in s.
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details 
+%
+% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+if(~isstruct(s1) || ~isstruct(s2))
+    error('input parameters contain non-struct');
+end
+if(length(s1)>1 || length(s2)>1)
+    error('can not merge struct arrays');
+end
+fn=fieldnames(s2);
+s=s1;
+for i=1:length(fn)              
+    s=setfield(s,fn{i},getfield(s2,fn{i}));
+end
+

+ 475 - 0
ex2/lib/jsonlab/savejson.m

@@ -0,0 +1,475 @@
+function json=savejson(rootname,obj,varargin)
+%
+% json=savejson(rootname,obj,filename)
+%    or
+% json=savejson(rootname,obj,opt)
+% json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
+%
+% convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
+% Object Notation) string
+%
+% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2011/09/09
+%
+% $Id: savejson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      rootname: the name of the root-object, when set to '', the root name
+%        is ignored, however, when opt.ForceRootName is set to 1 (see below),
+%        the MATLAB variable name will be used as the root name.
+%      obj: a MATLAB object (array, cell, cell array, struct, struct array).
+%      filename: a string for the file name to save the output JSON data.
+%      opt: a struct for additional options, ignore to use default values.
+%        opt can have the following fields (first in [.|.] is the default)
+%
+%        opt.FileName [''|string]: a file name to save the output JSON data
+%        opt.FloatFormat ['%.10g'|string]: format to show each numeric element
+%                         of a 1D/2D array;
+%        opt.ArrayIndent [1|0]: if 1, output explicit data array with
+%                         precedent indentation; if 0, no indentation
+%        opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
+%                         array in JSON array format; if sets to 1, an
+%                         array will be shown as a struct with fields
+%                         "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+%                         sparse arrays, the non-zero elements will be
+%                         saved to _ArrayData_ field in triplet-format i.e.
+%                         (ix,iy,val) and "_ArrayIsSparse_" will be added
+%                         with a value of 1; for a complex array, the 
+%                         _ArrayData_ array will include two columns 
+%                         (4 for sparse) to record the real and imaginary 
+%                         parts, and also "_ArrayIsComplex_":1 is added. 
+%        opt.ParseLogical [0|1]: if this is set to 1, logical array elem
+%                         will use true/false rather than 1/0.
+%        opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+%                         numerical element will be shown without a square
+%                         bracket, unless it is the root object; if 0, square
+%                         brackets are forced for any numerical arrays.
+%        opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
+%                         will use the name of the passed obj variable as the 
+%                         root object name; if obj is an expression and 
+%                         does not have a name, 'root' will be used; if this 
+%                         is set to 0 and rootname is empty, the root level 
+%                         will be merged down to the lower level.
+%        opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
+%                         to represent +/-Inf. The matched pattern is '([-+]*)Inf'
+%                         and $1 represents the sign. For those who want to use
+%                         1e999 to represent Inf, they can set opt.Inf to '$11e999'
+%        opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
+%                         to represent NaN
+%        opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+%                         for example, if opt.JSONP='foo', the JSON data is
+%                         wrapped inside a function call as 'foo(...);'
+%        opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+%                         back to the string form
+%        opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
+%        opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs)
+%
+%        opt can be replaced by a list of ('param',value) pairs. The param 
+%        string is equivallent to a field in opt and is case sensitive.
+% output:
+%      json: a string in the JSON format (see http://json.org)
+%
+% examples:
+%      jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+%               'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+%               'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+%                          2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+%               'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+%               'SpecialData',[nan, inf, -inf]);
+%      savejson('jmesh',jsonmesh)
+%      savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g')
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+if(nargin==1)
+   varname=inputname(1);
+   obj=rootname;
+   if(isempty(varname)) 
+      varname='root';
+   end
+   rootname=varname;
+else
+   varname=inputname(2);
+end
+if(length(varargin)==1 && ischar(varargin{1}))
+   opt=struct('FileName',varargin{1});
+else
+   opt=varargin2struct(varargin{:});
+end
+opt.IsOctave=exist('OCTAVE_VERSION','builtin');
+rootisarray=0;
+rootlevel=1;
+forceroot=jsonopt('ForceRootName',0,opt);
+if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)
+    rootisarray=1;
+    rootlevel=0;
+else
+    if(isempty(rootname))
+        rootname=varname;
+    end
+end
+if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
+    rootname='root';
+end
+
+whitespaces=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+if(jsonopt('Compact',0,opt)==1)
+    whitespaces=struct('tab','','newline','','sep',',');
+end
+if(~isfield(opt,'whitespaces_'))
+    opt.whitespaces_=whitespaces;
+end
+
+nl=whitespaces.newline;
+
+json=obj2json(rootname,obj,rootlevel,opt);
+if(rootisarray)
+    json=sprintf('%s%s',json,nl);
+else
+    json=sprintf('{%s%s%s}\n',nl,json,nl);
+end
+
+jsonp=jsonopt('JSONP','',opt);
+if(~isempty(jsonp))
+    json=sprintf('%s(%s);%s',jsonp,json,nl);
+end
+
+% save to a file if FileName is set, suggested by Patrick Rapin
+if(~isempty(jsonopt('FileName','',opt)))
+    if(jsonopt('SaveBinary',0,opt)==1)
+	    fid = fopen(opt.FileName, 'wb');
+	    fwrite(fid,json);
+    else
+	    fid = fopen(opt.FileName, 'wt');
+	    fwrite(fid,json,'char');
+    end
+    fclose(fid);
+end
+
+%%-------------------------------------------------------------------------
+function txt=obj2json(name,item,level,varargin)
+
+if(iscell(item))
+    txt=cell2json(name,item,level,varargin{:});
+elseif(isstruct(item))
+    txt=struct2json(name,item,level,varargin{:});
+elseif(ischar(item))
+    txt=str2json(name,item,level,varargin{:});
+else
+    txt=mat2json(name,item,level,varargin{:});
+end
+
+%%-------------------------------------------------------------------------
+function txt=cell2json(name,item,level,varargin)
+txt='';
+if(~iscell(item))
+        error('input is not a cell');
+end
+
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item);
+ws=jsonopt('whitespaces_',struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n')),varargin{:});
+padding0=repmat(ws.tab,1,level);
+padding2=repmat(ws.tab,1,level+1);
+nl=ws.newline;
+if(len>1)
+    if(~isempty(name))
+        txt=sprintf('%s"%s": [%s',padding0, checkname(name,varargin{:}),nl); name=''; 
+    else
+        txt=sprintf('%s[%s',padding0,nl); 
+    end
+elseif(len==0)
+    if(~isempty(name))
+        txt=sprintf('%s"%s": []',padding0, checkname(name,varargin{:})); name=''; 
+    else
+        txt=sprintf('%s[]',padding0); 
+    end
+end
+for j=1:dim(2)
+    if(dim(1)>1) txt=sprintf('%s%s[%s',txt,padding2,nl); end
+    for i=1:dim(1)
+       txt=sprintf('%s%s',txt,obj2json(name,item{i,j},level+(dim(1)>1)+1,varargin{:}));
+       if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+    end
+    if(dim(1)>1) txt=sprintf('%s%s%s]',txt,nl,padding2); end
+    if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+    %if(j==dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+end
+if(len>1) txt=sprintf('%s%s%s]',txt,nl,padding0); end
+
+%%-------------------------------------------------------------------------
+function txt=struct2json(name,item,level,varargin)
+txt='';
+if(~isstruct(item))
+	error('input is not a struct');
+end
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item);
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+padding0=repmat(ws.tab,1,level);
+padding2=repmat(ws.tab,1,level+1);
+padding1=repmat(ws.tab,1,level+(dim(1)>1)+(len>1));
+nl=ws.newline;
+
+if(~isempty(name)) 
+    if(len>1) txt=sprintf('%s"%s": [%s',padding0,checkname(name,varargin{:}),nl); end
+else
+    if(len>1) txt=sprintf('%s[%s',padding0,nl); end
+end
+for j=1:dim(2)
+  if(dim(1)>1) txt=sprintf('%s%s[%s',txt,padding2,nl); end
+  for i=1:dim(1)
+    names = fieldnames(item(i,j));
+    if(~isempty(name) && len==1)
+        txt=sprintf('%s%s"%s": {%s',txt,padding1, checkname(name,varargin{:}),nl); 
+    else
+        txt=sprintf('%s%s{%s',txt,padding1,nl); 
+    end
+    if(~isempty(names))
+      for e=1:length(names)
+	    txt=sprintf('%s%s',txt,obj2json(names{e},getfield(item(i,j),...
+             names{e}),level+(dim(1)>1)+1+(len>1),varargin{:}));
+        if(e<length(names)) txt=sprintf('%s%s',txt,','); end
+        txt=sprintf('%s%s',txt,nl);
+      end
+    end
+    txt=sprintf('%s%s}',txt,padding1);
+    if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+  end
+  if(dim(1)>1) txt=sprintf('%s%s%s]',txt,nl,padding2); end
+  if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+end
+if(len>1) txt=sprintf('%s%s%s]',txt,nl,padding0); end
+
+%%-------------------------------------------------------------------------
+function txt=str2json(name,item,level,varargin)
+txt='';
+if(~ischar(item))
+        error('input is not a string');
+end
+item=reshape(item, max(size(item),[1 0]));
+len=size(item,1);
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+padding1=repmat(ws.tab,1,level);
+padding0=repmat(ws.tab,1,level+1);
+nl=ws.newline;
+sep=ws.sep;
+
+if(~isempty(name)) 
+    if(len>1) txt=sprintf('%s"%s": [%s',padding1,checkname(name,varargin{:}),nl); end
+else
+    if(len>1) txt=sprintf('%s[%s',padding1,nl); end
+end
+isoct=jsonopt('IsOctave',0,varargin{:});
+for e=1:len
+    if(isoct)
+        val=regexprep(item(e,:),'\\','\\');
+        val=regexprep(val,'"','\"');
+        val=regexprep(val,'^"','\"');
+    else
+        val=regexprep(item(e,:),'\\','\\\\');
+        val=regexprep(val,'"','\\"');
+        val=regexprep(val,'^"','\\"');
+    end
+    val=escapejsonstring(val);
+    if(len==1)
+        obj=['"' checkname(name,varargin{:}) '": ' '"',val,'"'];
+	if(isempty(name)) obj=['"',val,'"']; end
+        txt=sprintf('%s%s%s%s',txt,padding1,obj);
+    else
+        txt=sprintf('%s%s%s%s',txt,padding0,['"',val,'"']);
+    end
+    if(e==len) sep=''; end
+    txt=sprintf('%s%s',txt,sep);
+end
+if(len>1) txt=sprintf('%s%s%s%s',txt,nl,padding1,']'); end
+
+%%-------------------------------------------------------------------------
+function txt=mat2json(name,item,level,varargin)
+if(~isnumeric(item) && ~islogical(item))
+        error('input is not an array');
+end
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+padding1=repmat(ws.tab,1,level);
+padding0=repmat(ws.tab,1,level+1);
+nl=ws.newline;
+sep=ws.sep;
+
+if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
+   isempty(item) ||jsonopt('ArrayToStruct',0,varargin{:}))
+    if(isempty(name))
+    	txt=sprintf('%s{%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',...
+              padding1,nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl);
+    else
+    	txt=sprintf('%s"%s": {%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',...
+              padding1,checkname(name,varargin{:}),nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl);
+    end
+else
+    if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1 && level>0)
+        numtxt=regexprep(regexprep(matdata2json(item,level+1,varargin{:}),'^\[',''),']','');
+    else
+        numtxt=matdata2json(item,level+1,varargin{:});
+    end
+    if(isempty(name))
+    	txt=sprintf('%s%s',padding1,numtxt);
+    else
+        if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
+           	txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);
+        else
+    	    txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);
+        end
+    end
+    return;
+end
+dataformat='%s%s%s%s%s';
+
+if(issparse(item))
+    [ix,iy]=find(item);
+    data=full(item(find(item)));
+    if(~isreal(item))
+       data=[real(data(:)),imag(data(:))];
+       if(size(item,1)==1)
+           % Kludge to have data's 'transposedness' match item's.
+           % (Necessary for complex row vector handling below.)
+           data=data';
+       end
+       txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep);
+    end
+    txt=sprintf(dataformat,txt,padding0,'"_ArrayIsSparse_": ','1', sep);
+    if(size(item,1)==1)
+        % Row vector, store only column indices.
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+           matdata2json([iy(:),data'],level+2,varargin{:}), nl);
+    elseif(size(item,2)==1)
+        % Column vector, store only row indices.
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+           matdata2json([ix,data],level+2,varargin{:}), nl);
+    else
+        % General case, store row and column indices.
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+           matdata2json([ix,iy,data],level+2,varargin{:}), nl);
+    end
+else
+    if(isreal(item))
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+            matdata2json(item(:)',level+2,varargin{:}), nl);
+    else
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep);
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+            matdata2json([real(item(:)) imag(item(:))],level+2,varargin{:}), nl);
+    end
+end
+txt=sprintf('%s%s%s',txt,padding1,'}');
+
+%%-------------------------------------------------------------------------
+function txt=matdata2json(mat,level,varargin)
+
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+tab=ws.tab;
+nl=ws.newline;
+
+if(size(mat,1)==1)
+    pre='';
+    post='';
+    level=level-1;
+else
+    pre=sprintf('[%s',nl);
+    post=sprintf('%s%s]',nl,repmat(tab,1,level-1));
+end
+
+if(isempty(mat))
+    txt='null';
+    return;
+end
+floatformat=jsonopt('FloatFormat','%.10g',varargin{:});
+%if(numel(mat)>1)
+    formatstr=['[' repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf('],%s',nl)]];
+%else
+%    formatstr=[repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf(',\n')]];
+%end
+
+if(nargin>=2 && size(mat,1)>1 && jsonopt('ArrayIndent',1,varargin{:})==1)
+    formatstr=[repmat(tab,1,level) formatstr];
+end
+
+txt=sprintf(formatstr,mat');
+txt(end-length(nl):end)=[];
+if(islogical(mat) && jsonopt('ParseLogical',0,varargin{:})==1)
+   txt=regexprep(txt,'1','true');
+   txt=regexprep(txt,'0','false');
+end
+%txt=regexprep(mat2str(mat),'\s+',',');
+%txt=regexprep(txt,';',sprintf('],\n['));
+% if(nargin>=2 && size(mat,1)>1)
+%     txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
+% end
+txt=[pre txt post];
+if(any(isinf(mat(:))))
+    txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
+end
+if(any(isnan(mat(:))))
+    txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
+end
+
+%%-------------------------------------------------------------------------
+function newname=checkname(name,varargin)
+isunpack=jsonopt('UnpackHex',1,varargin{:});
+newname=name;
+if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
+    return
+end
+if(isunpack)
+    isoct=jsonopt('IsOctave',0,varargin{:});
+    if(~isoct)
+        newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
+    else
+        pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
+        pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
+        if(isempty(pos)) return; end
+        str0=name;
+        pos0=[0 pend(:)' length(name)];
+        newname='';
+        for i=1:length(pos)
+            newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
+        end
+        if(pos(end)~=length(name))
+            newname=[newname str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+end
+
+%%-------------------------------------------------------------------------
+function newstr=escapejsonstring(str)
+newstr=str;
+isoct=exist('OCTAVE_VERSION','builtin');
+if(isoct)
+   vv=sscanf(OCTAVE_VERSION,'%f');
+   if(vv(1)>=3.8) isoct=0; end
+end
+if(isoct)
+  escapechars={'\a','\f','\n','\r','\t','\v'};
+  for i=1:length(escapechars);
+    newstr=regexprep(newstr,escapechars{i},escapechars{i});
+  end
+else
+  escapechars={'\a','\b','\f','\n','\r','\t','\v'};
+  for i=1:length(escapechars);
+    newstr=regexprep(newstr,escapechars{i},regexprep(escapechars{i},'\\','\\\\'));
+  end
+end

+ 504 - 0
ex2/lib/jsonlab/saveubjson.m

@@ -0,0 +1,504 @@
+function json=saveubjson(rootname,obj,varargin)
+%
+% json=saveubjson(rootname,obj,filename)
+%    or
+% json=saveubjson(rootname,obj,opt)
+% json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
+%
+% convert a MATLAB object (cell, struct or array) into a Universal 
+% Binary JSON (UBJSON) binary string
+%
+% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2013/08/17
+%
+% $Id: saveubjson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      rootname: the name of the root-object, when set to '', the root name
+%        is ignored, however, when opt.ForceRootName is set to 1 (see below),
+%        the MATLAB variable name will be used as the root name.
+%      obj: a MATLAB object (array, cell, cell array, struct, struct array)
+%      filename: a string for the file name to save the output UBJSON data
+%      opt: a struct for additional options, ignore to use default values.
+%        opt can have the following fields (first in [.|.] is the default)
+%
+%        opt.FileName [''|string]: a file name to save the output JSON data
+%        opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
+%                         array in JSON array format; if sets to 1, an
+%                         array will be shown as a struct with fields
+%                         "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+%                         sparse arrays, the non-zero elements will be
+%                         saved to _ArrayData_ field in triplet-format i.e.
+%                         (ix,iy,val) and "_ArrayIsSparse_" will be added
+%                         with a value of 1; for a complex array, the 
+%                         _ArrayData_ array will include two columns 
+%                         (4 for sparse) to record the real and imaginary 
+%                         parts, and also "_ArrayIsComplex_":1 is added. 
+%        opt.ParseLogical [1|0]: if this is set to 1, logical array elem
+%                         will use true/false rather than 1/0.
+%        opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+%                         numerical element will be shown without a square
+%                         bracket, unless it is the root object; if 0, square
+%                         brackets are forced for any numerical arrays.
+%        opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
+%                         will use the name of the passed obj variable as the 
+%                         root object name; if obj is an expression and 
+%                         does not have a name, 'root' will be used; if this 
+%                         is set to 0 and rootname is empty, the root level 
+%                         will be merged down to the lower level.
+%        opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+%                         for example, if opt.JSON='foo', the JSON data is
+%                         wrapped inside a function call as 'foo(...);'
+%        opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+%                         back to the string form
+%
+%        opt can be replaced by a list of ('param',value) pairs. The param 
+%        string is equivallent to a field in opt and is case sensitive.
+% output:
+%      json: a binary string in the UBJSON format (see http://ubjson.org)
+%
+% examples:
+%      jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+%               'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+%               'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+%                          2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+%               'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+%               'SpecialData',[nan, inf, -inf]);
+%      saveubjson('jsonmesh',jsonmesh)
+%      saveubjson('jsonmesh',jsonmesh,'meshdata.ubj')
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+if(nargin==1)
+   varname=inputname(1);
+   obj=rootname;
+   if(isempty(varname)) 
+      varname='root';
+   end
+   rootname=varname;
+else
+   varname=inputname(2);
+end
+if(length(varargin)==1 && ischar(varargin{1}))
+   opt=struct('FileName',varargin{1});
+else
+   opt=varargin2struct(varargin{:});
+end
+opt.IsOctave=exist('OCTAVE_VERSION','builtin');
+rootisarray=0;
+rootlevel=1;
+forceroot=jsonopt('ForceRootName',0,opt);
+if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)
+    rootisarray=1;
+    rootlevel=0;
+else
+    if(isempty(rootname))
+        rootname=varname;
+    end
+end
+if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
+    rootname='root';
+end
+json=obj2ubjson(rootname,obj,rootlevel,opt);
+if(~rootisarray)
+    json=['{' json '}'];
+end
+
+jsonp=jsonopt('JSONP','',opt);
+if(~isempty(jsonp))
+    json=[jsonp '(' json ')'];
+end
+
+% save to a file if FileName is set, suggested by Patrick Rapin
+if(~isempty(jsonopt('FileName','',opt)))
+    fid = fopen(opt.FileName, 'wb');
+    fwrite(fid,json);
+    fclose(fid);
+end
+
+%%-------------------------------------------------------------------------
+function txt=obj2ubjson(name,item,level,varargin)
+
+if(iscell(item))
+    txt=cell2ubjson(name,item,level,varargin{:});
+elseif(isstruct(item))
+    txt=struct2ubjson(name,item,level,varargin{:});
+elseif(ischar(item))
+    txt=str2ubjson(name,item,level,varargin{:});
+else
+    txt=mat2ubjson(name,item,level,varargin{:});
+end
+
+%%-------------------------------------------------------------------------
+function txt=cell2ubjson(name,item,level,varargin)
+txt='';
+if(~iscell(item))
+        error('input is not a cell');
+end
+
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item); % let's handle 1D cell first
+if(len>1) 
+    if(~isempty(name))
+        txt=[S_(checkname(name,varargin{:})) '[']; name=''; 
+    else
+        txt='['; 
+    end
+elseif(len==0)
+    if(~isempty(name))
+        txt=[S_(checkname(name,varargin{:})) 'Z']; name=''; 
+    else
+        txt='Z'; 
+    end
+end
+for j=1:dim(2)
+    if(dim(1)>1) txt=[txt '[']; end
+    for i=1:dim(1)
+       txt=[txt obj2ubjson(name,item{i,j},level+(len>1),varargin{:})];
+    end
+    if(dim(1)>1) txt=[txt ']']; end
+end
+if(len>1) txt=[txt ']']; end
+
+%%-------------------------------------------------------------------------
+function txt=struct2ubjson(name,item,level,varargin)
+txt='';
+if(~isstruct(item))
+	error('input is not a struct');
+end
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item);
+
+if(~isempty(name)) 
+    if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
+else
+    if(len>1) txt='['; end
+end
+for j=1:dim(2)
+  if(dim(1)>1) txt=[txt '[']; end
+  for i=1:dim(1)
+     names = fieldnames(item(i,j));
+     if(~isempty(name) && len==1)
+        txt=[txt S_(checkname(name,varargin{:})) '{']; 
+     else
+        txt=[txt '{']; 
+     end
+     if(~isempty(names))
+       for e=1:length(names)
+	     txt=[txt obj2ubjson(names{e},getfield(item(i,j),...
+             names{e}),level+(dim(1)>1)+1+(len>1),varargin{:})];
+       end
+     end
+     txt=[txt '}'];
+  end
+  if(dim(1)>1) txt=[txt ']']; end
+end
+if(len>1) txt=[txt ']']; end
+
+%%-------------------------------------------------------------------------
+function txt=str2ubjson(name,item,level,varargin)
+txt='';
+if(~ischar(item))
+        error('input is not a string');
+end
+item=reshape(item, max(size(item),[1 0]));
+len=size(item,1);
+
+if(~isempty(name)) 
+    if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
+else
+    if(len>1) txt='['; end
+end
+isoct=jsonopt('IsOctave',0,varargin{:});
+for e=1:len
+    val=item(e,:);
+    if(len==1)
+        obj=['' S_(checkname(name,varargin{:})) '' '',S_(val),''];
+	if(isempty(name)) obj=['',S_(val),'']; end
+        txt=[txt,'',obj];
+    else
+        txt=[txt,'',['',S_(val),'']];
+    end
+end
+if(len>1) txt=[txt ']']; end
+
+%%-------------------------------------------------------------------------
+function txt=mat2ubjson(name,item,level,varargin)
+if(~isnumeric(item) && ~islogical(item))
+        error('input is not an array');
+end
+
+if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
+   isempty(item) || jsonopt('ArrayToStruct',0,varargin{:}))
+      cid=I_(uint32(max(size(item))));
+      if(isempty(name))
+    	txt=['{' S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1)) ];
+      else
+          if(isempty(item))
+              txt=[S_(checkname(name,varargin{:})),'Z'];
+              return;
+          else
+    	      txt=[S_(checkname(name,varargin{:})),'{',S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1))];
+          end
+      end
+else
+    if(isempty(name))
+    	txt=matdata2ubjson(item,level+1,varargin{:});
+    else
+        if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
+            numtxt=regexprep(regexprep(matdata2ubjson(item,level+1,varargin{:}),'^\[',''),']','');
+           	txt=[S_(checkname(name,varargin{:})) numtxt];
+        else
+    	    txt=[S_(checkname(name,varargin{:})),matdata2ubjson(item,level+1,varargin{:})];
+        end
+    end
+    return;
+end
+if(issparse(item))
+    [ix,iy]=find(item);
+    data=full(item(find(item)));
+    if(~isreal(item))
+       data=[real(data(:)),imag(data(:))];
+       if(size(item,1)==1)
+           % Kludge to have data's 'transposedness' match item's.
+           % (Necessary for complex row vector handling below.)
+           data=data';
+       end
+       txt=[txt,S_('_ArrayIsComplex_'),'T'];
+    end
+    txt=[txt,S_('_ArrayIsSparse_'),'T'];
+    if(size(item,1)==1)
+        % Row vector, store only column indices.
+        txt=[txt,S_('_ArrayData_'),...
+           matdata2ubjson([iy(:),data'],level+2,varargin{:})];
+    elseif(size(item,2)==1)
+        % Column vector, store only row indices.
+        txt=[txt,S_('_ArrayData_'),...
+           matdata2ubjson([ix,data],level+2,varargin{:})];
+    else
+        % General case, store row and column indices.
+        txt=[txt,S_('_ArrayData_'),...
+           matdata2ubjson([ix,iy,data],level+2,varargin{:})];
+    end
+else
+    if(isreal(item))
+        txt=[txt,S_('_ArrayData_'),...
+            matdata2ubjson(item(:)',level+2,varargin{:})];
+    else
+        txt=[txt,S_('_ArrayIsComplex_'),'T'];
+        txt=[txt,S_('_ArrayData_'),...
+            matdata2ubjson([real(item(:)) imag(item(:))],level+2,varargin{:})];
+    end
+end
+txt=[txt,'}'];
+
+%%-------------------------------------------------------------------------
+function txt=matdata2ubjson(mat,level,varargin)
+if(isempty(mat))
+    txt='Z';
+    return;
+end
+if(size(mat,1)==1)
+    level=level-1;
+end
+type='';
+hasnegtive=(mat<0);
+if(isa(mat,'integer') || isinteger(mat) || (isfloat(mat) && all(mod(mat(:),1) == 0)))
+    if(isempty(hasnegtive))
+       if(max(mat(:))<=2^8)
+           type='U';
+       end
+    end
+    if(isempty(type))
+        % todo - need to consider negative ones separately
+        id= histc(abs(max(mat(:))),[0 2^7 2^15 2^31 2^63]);
+        if(isempty(find(id)))
+            error('high-precision data is not yet supported');
+        end
+        key='iIlL';
+	type=key(find(id));
+    end
+    txt=[I_a(mat(:),type,size(mat))];
+elseif(islogical(mat))
+    logicalval='FT';
+    if(numel(mat)==1)
+        txt=logicalval(mat+1);
+    else
+        txt=['[$U#' I_a(size(mat),'l') typecast(swapbytes(uint8(mat(:)')),'uint8')];
+    end
+else
+    if(numel(mat)==1)
+        txt=['[' D_(mat) ']'];
+    else
+        txt=D_a(mat(:),'D',size(mat));
+    end
+end
+
+%txt=regexprep(mat2str(mat),'\s+',',');
+%txt=regexprep(txt,';',sprintf('],['));
+% if(nargin>=2 && size(mat,1)>1)
+%     txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
+% end
+if(any(isinf(mat(:))))
+    txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
+end
+if(any(isnan(mat(:))))
+    txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
+end
+
+%%-------------------------------------------------------------------------
+function newname=checkname(name,varargin)
+isunpack=jsonopt('UnpackHex',1,varargin{:});
+newname=name;
+if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
+    return
+end
+if(isunpack)
+    isoct=jsonopt('IsOctave',0,varargin{:});
+    if(~isoct)
+        newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
+    else
+        pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
+        pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
+        if(isempty(pos)) return; end
+        str0=name;
+        pos0=[0 pend(:)' length(name)];
+        newname='';
+        for i=1:length(pos)
+            newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
+        end
+        if(pos(end)~=length(name))
+            newname=[newname str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+end
+%%-------------------------------------------------------------------------
+function val=S_(str)
+if(length(str)==1)
+  val=['C' str];
+else
+  val=['S' I_(int32(length(str))) str];
+end
+%%-------------------------------------------------------------------------
+function val=I_(num)
+if(~isinteger(num))
+    error('input is not an integer');
+end
+if(num>=0 && num<255)
+   val=['U' data2byte(swapbytes(cast(num,'uint8')),'uint8')];
+   return;
+end
+key='iIlL';
+cid={'int8','int16','int32','int64'};
+for i=1:4
+  if((num>0 && num<2^(i*8-1)) || (num<0 && num>=-2^(i*8-1)))
+    val=[key(i) data2byte(swapbytes(cast(num,cid{i})),'uint8')];
+    return;
+  end
+end
+error('unsupported integer');
+
+%%-------------------------------------------------------------------------
+function val=D_(num)
+if(~isfloat(num))
+    error('input is not a float');
+end
+
+if(isa(num,'single'))
+  val=['d' data2byte(num,'uint8')];
+else
+  val=['D' data2byte(num,'uint8')];
+end
+%%-------------------------------------------------------------------------
+function data=I_a(num,type,dim,format)
+id=find(ismember('iUIlL',type));
+
+if(id==0)
+  error('unsupported integer array');
+end
+
+% based on UBJSON specs, all integer types are stored in big endian format
+
+if(id==1)
+  data=data2byte(swapbytes(int8(num)),'uint8');
+  blen=1;
+elseif(id==2)
+  data=data2byte(swapbytes(uint8(num)),'uint8');
+  blen=1;
+elseif(id==3)
+  data=data2byte(swapbytes(int16(num)),'uint8');
+  blen=2;
+elseif(id==4)
+  data=data2byte(swapbytes(int32(num)),'uint8');
+  blen=4;
+elseif(id==5)
+  data=data2byte(swapbytes(int64(num)),'uint8');
+  blen=8;
+end
+
+if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
+  format='opt';
+end
+if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
+  if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
+      cid=I_(uint32(max(dim)));
+      data=['$' type '#' I_a(dim,cid(1)) data(:)'];
+  else
+      data=['$' type '#' I_(int32(numel(data)/blen)) data(:)'];
+  end
+  data=['[' data(:)'];
+else
+  data=reshape(data,blen,numel(data)/blen);
+  data(2:blen+1,:)=data;
+  data(1,:)=type;
+  data=data(:)';
+  data=['[' data(:)' ']'];
+end
+%%-------------------------------------------------------------------------
+function data=D_a(num,type,dim,format)
+id=find(ismember('dD',type));
+
+if(id==0)
+  error('unsupported float array');
+end
+
+if(id==1)
+  data=data2byte(single(num),'uint8');
+elseif(id==2)
+  data=data2byte(double(num),'uint8');
+end
+
+if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
+  format='opt';
+end
+if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
+  if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
+      cid=I_(uint32(max(dim)));
+      data=['$' type '#' I_a(dim,cid(1)) data(:)'];
+  else
+      data=['$' type '#' I_(int32(numel(data)/(id*4))) data(:)'];
+  end
+  data=['[' data];
+else
+  data=reshape(data,(id*4),length(data)/(id*4));
+  data(2:(id*4+1),:)=data;
+  data(1,:)=type;
+  data=data(:)';
+  data=['[' data(:)' ']'];
+end
+%%-------------------------------------------------------------------------
+function bytes=data2byte(varargin)
+bytes=typecast(varargin{:});
+bytes=bytes(:)';

+ 40 - 0
ex2/lib/jsonlab/varargin2struct.m

@@ -0,0 +1,40 @@
+function opt=varargin2struct(varargin)
+%
+% opt=varargin2struct('param1',value1,'param2',value2,...)
+%   or
+% opt=varargin2struct(...,optstruct,...)
+%
+% convert a series of input parameters into a structure
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% date: 2012/12/22
+%
+% input:
+%      'param', value: the input parameters should be pairs of a string and a value
+%       optstruct: if a parameter is a struct, the fields will be merged to the output struct
+%
+% output:
+%      opt: a struct where opt.param1=value1, opt.param2=value2 ...
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details 
+%
+% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+len=length(varargin);
+opt=struct;
+if(len==0) return; end
+i=1;
+while(i<=len)
+    if(isstruct(varargin{i}))
+        opt=mergestruct(opt,varargin{i});
+    elseif(ischar(varargin{i}) && i<len)
+        opt=setfield(opt,varargin{i},varargin{i+1});
+        i=i+1;
+    else
+        error('input must be in the form of ...,''name'',value,... pairs or structs');
+    end
+    i=i+1;
+end
+

+ 30 - 0
ex2/lib/makeValidFieldName.m

@@ -0,0 +1,30 @@
+function str = makeValidFieldName(str)
+% From MATLAB doc: field names must begin with a letter, which may be
+% followed by any combination of letters, digits, and underscores.
+% Invalid characters will be converted to underscores, and the prefix
+% "x0x[Hex code]_" will be added if the first character is not a letter.
+    isoct=exist('OCTAVE_VERSION','builtin');
+    pos=regexp(str,'^[^A-Za-z]','once');
+    if(~isempty(pos))
+        if(~isoct)
+            str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
+        else
+            str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
+        end
+    end
+    if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return;  end
+    if(~isoct)
+        str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
+    else
+        pos=regexp(str,'[^0-9A-Za-z_]');
+        if(isempty(pos)) return; end
+        str0=str;
+        pos0=[0 pos(:)' length(str)];
+        str='';
+        for i=1:length(pos)
+            str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
+        end
+        if(pos(end)~=length(str))
+            str=[str str0(pos0(end-1)+1:pos0(end))];
+        end
+    end

+ 179 - 0
ex2/lib/submitWithConfiguration.m

@@ -0,0 +1,179 @@
+function submitWithConfiguration(conf)
+  addpath('./lib/jsonlab');
+
+  parts = parts(conf);
+
+  fprintf('== Submitting solutions | %s...\n', conf.itemName);
+
+  tokenFile = 'token.mat';
+  if exist(tokenFile, 'file')
+    load(tokenFile);
+    [email token] = promptToken(email, token, tokenFile);
+  else
+    [email token] = promptToken('', '', tokenFile);
+  end
+
+  if isempty(token)
+    fprintf('!! Submission Cancelled\n');
+    return
+  end
+
+  try
+    response = submitParts(conf, email, token, parts);
+  catch
+    e = lasterror();
+    fprintf('\n!! Submission failed: %s\n', e.message);
+    fprintf('\n\nFunction: %s\nFileName: %s\nLineNumber: %d\n', ...
+      e.stack(1,1).name, e.stack(1,1).file, e.stack(1,1).line);
+    fprintf('\nPlease correct your code and resubmit.\n');
+    return
+  end
+
+  if isfield(response, 'errorMessage')
+    fprintf('!! Submission failed: %s\n', response.errorMessage);
+  elseif isfield(response, 'errorCode')
+    fprintf('!! Submission failed: %s\n', response.message);
+  else
+    showFeedback(parts, response);
+    save(tokenFile, 'email', 'token');
+  end
+end
+
+function [email token] = promptToken(email, existingToken, tokenFile)
+  if (~isempty(email) && ~isempty(existingToken))
+    prompt = sprintf( ...
+      'Use token from last successful submission (%s)? (Y/n): ', ...
+      email);
+    reenter = input(prompt, 's');
+
+    if (isempty(reenter) || reenter(1) == 'Y' || reenter(1) == 'y')
+      token = existingToken;
+      return;
+    else
+      delete(tokenFile);
+    end
+  end
+  email = input('Login (email address): ', 's');
+  token = input('Token: ', 's');
+end
+
+function isValid = isValidPartOptionIndex(partOptions, i)
+  isValid = (~isempty(i)) && (1 <= i) && (i <= numel(partOptions));
+end
+
+function response = submitParts(conf, email, token, parts)
+  body = makePostBody(conf, email, token, parts);
+  submissionUrl = submissionUrl();
+
+  responseBody = getResponse(submissionUrl, body);
+  jsonResponse = validateResponse(responseBody);
+  response = loadjson(jsonResponse);
+end
+
+function body = makePostBody(conf, email, token, parts)
+  bodyStruct.assignmentSlug = conf.assignmentSlug;
+  bodyStruct.submitterEmail = email;
+  bodyStruct.secret = token;
+  bodyStruct.parts = makePartsStruct(conf, parts);
+
+  opt.Compact = 1;
+  body = savejson('', bodyStruct, opt);
+end
+
+function partsStruct = makePartsStruct(conf, parts)
+  for part = parts
+    partId = part{:}.id;
+    fieldName = makeValidFieldName(partId);
+    outputStruct.output = conf.output(partId);
+    partsStruct.(fieldName) = outputStruct;
+  end
+end
+
+function [parts] = parts(conf)
+  parts = {};
+  for partArray = conf.partArrays
+    part.id = partArray{:}{1};
+    part.sourceFiles = partArray{:}{2};
+    part.name = partArray{:}{3};
+    parts{end + 1} = part;
+  end
+end
+
+function showFeedback(parts, response)
+  fprintf('== \n');
+  fprintf('== %43s | %9s | %-s\n', 'Part Name', 'Score', 'Feedback');
+  fprintf('== %43s | %9s | %-s\n', '---------', '-----', '--------');
+  for part = parts
+    score = '';
+    partFeedback = '';
+    partFeedback = response.partFeedbacks.(makeValidFieldName(part{:}.id));
+    partEvaluation = response.partEvaluations.(makeValidFieldName(part{:}.id));
+    score = sprintf('%d / %3d', partEvaluation.score, partEvaluation.maxScore);
+    fprintf('== %43s | %9s | %-s\n', part{:}.name, score, partFeedback);
+  end
+  evaluation = response.evaluation;
+  totalScore = sprintf('%d / %d', evaluation.score, evaluation.maxScore);
+  fprintf('==                                   --------------------------------\n');
+  fprintf('== %43s | %9s | %-s\n', '', totalScore, '');
+  fprintf('== \n');
+end
+
+% use urlread or curl to send submit results to the grader and get a response
+function response = getResponse(url, body)
+% try using urlread() and a secure connection
+  params = {'jsonBody', body};
+  [response, success] = urlread(url, 'post', params);
+
+  if (success == 0)
+    % urlread didn't work, try curl & the peer certificate patch
+    if ispc
+      % testing note: use 'jsonBody =' for a test case
+      json_command = sprintf('echo jsonBody=%s | curl -k -X POST -d @- %s', body, url);
+    else
+      % it's linux/OS X, so use the other form
+      json_command = sprintf('echo ''jsonBody=%s'' | curl -k -X POST -d @- %s', body, url);
+    end
+    % get the response body for the peer certificate patch method
+    [code, response] = system(json_command);
+    % test the success code
+    if (code ~= 0)
+      fprintf('[error] submission with curl() was not successful\n');
+    end
+  end
+end
+
+% validate the grader's response
+function response = validateResponse(resp)
+  % test if the response is json or an HTML page
+  isJson = length(resp) > 0 && resp(1) == '{';
+  isHtml = findstr(lower(resp), '<html');
+
+  if (isJson)
+    response = resp;
+  elseif (isHtml)
+    % the response is html, so it's probably an error message
+    printHTMLContents(resp);
+    error('Grader response is an HTML message');
+  else
+    error('Grader sent no response');
+  end
+end
+
+% parse a HTML response and print it's contents
+function printHTMLContents(response)
+  strippedResponse = regexprep(response, '<[^>]+>', ' ');
+  strippedResponse = regexprep(strippedResponse, '[\t ]+', ' ');
+  fprintf(strippedResponse);
+end
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Service configuration
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function submissionUrl = submissionUrl()
+  submissionUrl = 'https://www-origin.coursera.org/api/onDemandProgrammingImmediateFormSubmissions.v1';
+end

+ 21 - 0
ex2/mapFeature.m

@@ -0,0 +1,21 @@
+function out = mapFeature(X1, X2)
+% MAPFEATURE Feature mapping function to polynomial features
+%
+%   MAPFEATURE(X1, X2) maps the two input features
+%   to quadratic features used in the regularization exercise.
+%
+%   Returns a new feature array with more features, comprising of 
+%   X1, X2, X1.^2, X2.^2, X1*X2, X1*X2.^2, etc..
+%
+%   Inputs X1, X2 must be the same size
+%
+
+degree = 6;
+out = ones(size(X1(:,1)));
+for i = 1:degree
+    for j = 0:i
+        out(:, end+1) = (X1.^(i-j)).*(X2.^j);
+    end
+end
+
+end

+ 32 - 0
ex2/plotData.m

@@ -0,0 +1,32 @@
+function plotData(X, y)
+%PLOTDATA Plots the data points X and y into a new figure 
+%   PLOTDATA(x,y) plots the data points with + for the positive examples
+%   and o for the negative examples. X is assumed to be a Mx2 matrix.
+
+% Create New Figure
+figure; hold on;
+
+% ====================== YOUR CODE HERE ======================
+% Instructions: Plot the positive and negative examples on a
+%               2D plot, using the option 'k+' for the positive
+%               examples and 'ko' for the negative examples.
+%
+
+
+
+pos = find(y==1); neg = find(y == 0);
+% Plot Examples
+plot(X(pos, 1), X(pos, 2), 'k+','LineWidth', 2, 'MarkerSize', 7);
+plot(X(neg, 1), X(neg, 2), 'ko', 'MarkerFaceColor', 'y', 'MarkerSize', 7);
+
+
+
+
+
+% =========================================================================
+
+
+
+hold off;
+
+end

+ 48 - 0
ex2/plotDecisionBoundary.m

@@ -0,0 +1,48 @@
+function plotDecisionBoundary(theta, X, y)
+%PLOTDECISIONBOUNDARY Plots the data points X and y into a new figure with
+%the decision boundary defined by theta
+%   PLOTDECISIONBOUNDARY(theta, X,y) plots the data points with + for the 
+%   positive examples and o for the negative examples. X is assumed to be 
+%   a either 
+%   1) Mx3 matrix, where the first column is an all-ones column for the 
+%      intercept.
+%   2) MxN, N>3 matrix, where the first column is all-ones
+
+% Plot Data
+plotData(X(:,2:3), y);
+hold on
+
+if size(X, 2) <= 3
+    % Only need 2 points to define a line, so choose two endpoints
+    plot_x = [min(X(:,2))-2,  max(X(:,2))+2];
+
+    % Calculate the decision boundary line
+    plot_y = (-1./theta(3)).*(theta(2).*plot_x + theta(1));
+
+    % Plot, and adjust axes for better viewing
+    plot(plot_x, plot_y)
+    
+    % Legend, specific for the exercise
+    legend('Admitted', 'Not admitted', 'Decision Boundary')
+    axis([30, 100, 30, 100])
+else
+    % Here is the grid range
+    u = linspace(-1, 1.5, 50);
+    v = linspace(-1, 1.5, 50);
+
+    z = zeros(length(u), length(v));
+    % Evaluate z = theta*x over the grid
+    for i = 1:length(u)
+        for j = 1:length(v)
+            z(i,j) = mapFeature(u(i), v(j))*theta;
+        end
+    end
+    z = z'; % important to transpose z before calling contour
+
+    % Plot z = 0
+    % Notice you need to specify the range [0, 0]
+    contour(u, v, z, [0, 0], 'LineWidth', 2)
+end
+hold off
+
+end

+ 27 - 0
ex2/predict.m

@@ -0,0 +1,27 @@
+function p = predict(theta, X)
+%PREDICT Predict whether the label is 0 or 1 using learned logistic 
+%regression parameters theta
+%   p = PREDICT(theta, X) computes the predictions for X using a 
+%   threshold at 0.5 (i.e., if sigmoid(theta'*x) >= 0.5, predict 1)
+
+m = size(X, 1); % Number of training examples
+
+% You need to return the following variables correctly
+p = round(hypothesis(theta, X));
+
+% ====================== YOUR CODE HERE ======================
+% Instructions: Complete the following code to make predictions using
+%               your learned logistic regression parameters. 
+%               You should set p to a vector of 0's and 1's
+%
+
+
+
+
+
+
+
+% =========================================================================
+
+
+end

+ 18 - 0
ex2/sigmoid.m

@@ -0,0 +1,18 @@
+function g = sigmoid(z)
+%SIGMOID Compute sigmoid function
+%   g = SIGMOID(z) computes the sigmoid of z.
+
+% You need to return the following variables correctly 
+g = 1 ./ ( exp(-z) + 1 );
+
+% ====================== YOUR CODE HERE ======================
+% Instructions: Compute the sigmoid of each value of z (z can be a matrix,
+%               vector or scalar).
+
+
+
+
+
+% =============================================================
+
+end

+ 62 - 0
ex2/submit.m

@@ -0,0 +1,62 @@
+function submit()
+  addpath('./lib');
+
+  conf.assignmentSlug = 'logistic-regression';
+  conf.itemName = 'Logistic Regression';
+  conf.partArrays = { ...
+    { ...
+      '1', ...
+      { 'sigmoid.m' }, ...
+      'Sigmoid Function', ...
+    }, ...
+    { ...
+      '2', ...
+      { 'costFunction.m' }, ...
+      'Logistic Regression Cost', ...
+    }, ...
+    { ...
+      '3', ...
+      { 'costFunction.m' }, ...
+      'Logistic Regression Gradient', ...
+    }, ...
+    { ...
+      '4', ...
+      { 'predict.m' }, ...
+      'Predict', ...
+    }, ...
+    { ...
+      '5', ...
+      { 'costFunctionReg.m' }, ...
+      'Regularized Logistic Regression Cost', ...
+    }, ...
+    { ...
+      '6', ...
+      { 'costFunctionReg.m' }, ...
+      'Regularized Logistic Regression Gradient', ...
+    }, ...
+  };
+  conf.output = @output;
+
+  submitWithConfiguration(conf);
+end
+
+function out = output(partId, auxstring)
+  % Random Test Cases
+  X = [ones(20,1) (exp(1) * sin(1:1:20))' (exp(0.5) * cos(1:1:20))'];
+  y = sin(X(:,1) + X(:,2)) > 0;
+  if partId == '1'
+    out = sprintf('%0.5f ', sigmoid(X));
+  elseif partId == '2'
+    out = sprintf('%0.5f ', costFunction([0.25 0.5 -0.5]', X, y));
+  elseif partId == '3'
+    [cost, grad] = costFunction([0.25 0.5 -0.5]', X, y);
+    out = sprintf('%0.5f ', grad);
+  elseif partId == '4'
+    out = sprintf('%0.5f ', predict([0.25 0.5 -0.5]', X));
+  elseif partId == '5'
+    out = sprintf('%0.5f ', costFunctionReg([0.25 0.5 -0.5]', X, y, 0.1));
+  elseif partId == '6'
+    [cost, grad] = costFunctionReg([0.25 0.5 -0.5]', X, y, 0.1);
+    out = sprintf('%0.5f ', grad);
+  end 
+end

+ 59 - 0
ex3/displayData.m

@@ -0,0 +1,59 @@
+function [h, display_array] = displayData(X, example_width)
+%DISPLAYDATA Display 2D data in a nice grid
+%   [h, display_array] = DISPLAYDATA(X, example_width) displays 2D data
+%   stored in X in a nice grid. It returns the figure handle h and the 
+%   displayed array if requested.
+
+% Set example_width automatically if not passed in
+if ~exist('example_width', 'var') || isempty(example_width) 
+	example_width = round(sqrt(size(X, 2)));
+end
+
+% Gray Image
+colormap(gray);
+
+% Compute rows, cols
+[m n] = size(X);
+example_height = (n / example_width);
+
+% Compute number of items to display
+display_rows = floor(sqrt(m));
+display_cols = ceil(m / display_rows);
+
+% Between images padding
+pad = 1;
+
+% Setup blank display
+display_array = - ones(pad + display_rows * (example_height + pad), ...
+                       pad + display_cols * (example_width + pad));
+
+% Copy each example into a patch on the display array
+curr_ex = 1;
+for j = 1:display_rows
+	for i = 1:display_cols
+		if curr_ex > m, 
+			break; 
+		end
+		% Copy the patch
+		
+		% Get the max value of the patch
+		max_val = max(abs(X(curr_ex, :)));
+		display_array(pad + (j - 1) * (example_height + pad) + (1:example_height), ...
+		              pad + (i - 1) * (example_width + pad) + (1:example_width)) = ...
+						reshape(X(curr_ex, :), example_height, example_width) / max_val;
+		curr_ex = curr_ex + 1;
+	end
+	if curr_ex > m, 
+		break; 
+	end
+end
+
+% Display Image
+h = imagesc(display_array, [-1 1]);
+
+% Do not show axis
+axis image off
+
+drawnow;
+
+end

+ 88 - 0
ex3/ex3.m

@@ -0,0 +1,88 @@
+%% Machine Learning Online Class - Exercise 3 | Part 1: One-vs-all
+
+%  Instructions
+%  ------------
+%
+%  This file contains code that helps you get started on the
+%  linear exercise. You will need to complete the following functions
+%  in this exericse:
+%
+%     lrCostFunction.m (logistic regression cost function)
+%     oneVsAll.m
+%     predictOneVsAll.m
+%     predict.m
+%
+%  For this exercise, you will not need to change any code in this file,
+%  or any other files other than those mentioned above.
+%
+
+%% Initialization
+clear ; close all; clc
+
+%% Setup the parameters you will use for this part of the exercise
+input_layer_size  = 400;  % 20x20 Input Images of Digits
+num_labels = 10;          % 10 labels, from 1 to 10
+                          % (note that we have mapped "0" to label 10)
+
+%% =========== Part 1: Loading and Visualizing Data =============
+%  We start the exercise by first loading and visualizing the dataset.
+%  You will be working with a dataset that contains handwritten digits.
+%
+
+% Load Training Data
+fprintf('Loading and Visualizing Data ...\n')
+
+load('ex3data1.mat'); % training data stored in arrays X, y
+m = size(X, 1);
+
+% Randomly select 100 data points to display
+rand_indices = randperm(m);
+sel = X(rand_indices(1:100), :);
+
+displayData(sel);
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+
+%% ============ Part 2a: Vectorize Logistic Regression ============
+%  In this part of the exercise, you will reuse your logistic regression
+%  code from the last exercise. You task here is to make sure that your
+%  regularized logistic regression implementation is vectorized. After
+%  that, you will implement one-vs-all classification for the handwritten
+%  digit dataset.
+%
+
+% Test case for lrCostFunction
+fprintf('\nTesting lrCostFunction() with regularization');
+
+theta_t = [-2; -1; 1; 2];
+X_t = [ones(5,1) reshape(1:15,5,3)/10];
+y_t = ([1;0;1;0;1] >= 0.5);
+lambda_t = 3;
+[J grad] = lrCostFunction(theta_t, X_t, y_t, lambda_t);
+
+fprintf('\nCost: %f\n', J);
+fprintf('Expected cost: 2.534819\n');
+fprintf('Gradients:\n');
+fprintf(' %f \n', grad);
+fprintf('Expected gradients:\n');
+fprintf(' 0.146561\n -0.548558\n 0.724722\n 1.398003\n');
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+%% ============ Part 2b: One-vs-All Training ============
+fprintf('\nTraining One-vs-All Logistic Regression...\n')
+
+lambda = 0.1;
+[all_theta] = oneVsAll(X, y, num_labels, lambda);
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+
+
+%% ================ Part 3: Predict for One-Vs-All ================
+
+pred = predictOneVsAll(all_theta, X);
+
+fprintf('\nTraining Set Accuracy: %f\n', mean(double(pred == y)) * 100);
+

+ 91 - 0
ex3/ex3_nn.m

@@ -0,0 +1,91 @@
+%% Machine Learning Online Class - Exercise 3 | Part 2: Neural Networks
+
+%  Instructions
+%  ------------
+% 
+%  This file contains code that helps you get started on the
+%  linear exercise. You will need to complete the following functions 
+%  in this exericse:
+%
+%     lrCostFunction.m (logistic regression cost function)
+%     oneVsAll.m
+%     predictOneVsAll.m
+%     predict.m
+%
+%  For this exercise, you will not need to change any code in this file,
+%  or any other files other than those mentioned above.
+%
+
+%% Initialization
+clear ; close all; clc
+
+%% Setup the parameters you will use for this exercise
+input_layer_size  = 400;  % 20x20 Input Images of Digits
+hidden_layer_size = 25;   % 25 hidden units
+num_labels = 10;          % 10 labels, from 1 to 10   
+                          % (note that we have mapped "0" to label 10)
+
+%% =========== Part 1: Loading and Visualizing Data =============
+%  We start the exercise by first loading and visualizing the dataset. 
+%  You will be working with a dataset that contains handwritten digits.
+%
+
+% Load Training Data
+fprintf('Loading and Visualizing Data ...\n')
+
+load('ex3data1.mat');
+m = size(X, 1);
+
+% Randomly select 100 data points to display
+sel = randperm(size(X, 1));
+sel = sel(1:100);
+
+displayData(X(sel, :));
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+
+%% ================ Part 2: Loading Pameters ================
+% In this part of the exercise, we load some pre-initialized 
+% neural network parameters.
+
+fprintf('\nLoading Saved Neural Network Parameters ...\n')
+
+% Load the weights into variables Theta1 and Theta2
+load('ex3weights.mat');
+
+%% ================= Part 3: Implement Predict =================
+%  After training the neural network, we would like to use it to predict
+%  the labels. You will now implement the "predict" function to use the
+%  neural network to predict the labels of the training set. This lets
+%  you compute the training set accuracy.
+
+pred = predict(Theta1, Theta2, X);
+
+fprintf('\nTraining Set Accuracy: %f\n', mean(double(pred == y)) * 100);
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+
+%  To give you an idea of the network's output, you can also run
+%  through the examples one at the a time to see what it is predicting.
+
+%  Randomly permute examples
+rp = randperm(m);
+
+for i = 1:m
+    % Display 
+    fprintf('\nDisplaying Example Image\n');
+    displayData(X(rp(i), :));
+
+    pred = predict(Theta1, Theta2, X(rp(i),:));
+    
+    fprintf('\nNeural Network Prediction: %d (digit %d)\n', pred, mod(pred, 10));
+    
+    % Pause with quit option
+    s = input('Paused - press enter to continue, q to exit:','s');
+    if s == 'q'
+      break
+    end
+end
+

BIN
ex3/ex3data1.mat


BIN
ex3/ex3weights.mat


+ 175 - 0
ex3/fmincg.m

@@ -0,0 +1,175 @@
+function [X, fX, i] = fmincg(f, X, options, P1, P2, P3, P4, P5)
+% Minimize a continuous differentialble multivariate function. Starting point
+% is given by "X" (D by 1), and the function named in the string "f", must
+% return a function value and a vector of partial derivatives. The Polack-
+% Ribiere flavour of conjugate gradients is used to compute search directions,
+% and a line search using quadratic and cubic polynomial approximations and the
+% Wolfe-Powell stopping criteria is used together with the slope ratio method
+% for guessing initial step sizes. Additionally a bunch of checks are made to
+% make sure that exploration is taking place and that extrapolation will not
+% be unboundedly large. The "length" gives the length of the run: if it is
+% positive, it gives the maximum number of line searches, if negative its
+% absolute gives the maximum allowed number of function evaluations. You can
+% (optionally) give "length" a second component, which will indicate the
+% reduction in function value to be expected in the first line-search (defaults
+% to 1.0). The function returns when either its length is up, or if no further
+% progress can be made (ie, we are at a minimum, or so close that due to
+% numerical problems, we cannot get any closer). If the function terminates
+% within a few iterations, it could be an indication that the function value
+% and derivatives are not consistent (ie, there may be a bug in the
+% implementation of your "f" function). The function returns the found
+% solution "X", a vector of function values "fX" indicating the progress made
+% and "i" the number of iterations (line searches or function evaluations,
+% depending on the sign of "length") used.
+%
+% Usage: [X, fX, i] = fmincg(f, X, options, P1, P2, P3, P4, P5)
+%
+% See also: checkgrad 
+%
+% Copyright (C) 2001 and 2002 by Carl Edward Rasmussen. Date 2002-02-13
+%
+%
+% (C) Copyright 1999, 2000 & 2001, Carl Edward Rasmussen
+% 
+% Permission is granted for anyone to copy, use, or modify these
+% programs and accompanying documents for purposes of research or
+% education, provided this copyright notice is retained, and note is
+% made of any changes that have been made.
+% 
+% These programs and documents are distributed without any warranty,
+% express or implied.  As the programs were written for research
+% purposes only, they have not been tested to the degree that would be
+% advisable in any important application.  All use of these programs is
+% entirely at the user's own risk.
+%
+% [ml-class] Changes Made:
+% 1) Function name and argument specifications
+% 2) Output display
+%
+
+% Read options
+if exist('options', 'var') && ~isempty(options) && isfield(options, 'MaxIter')
+    length = options.MaxIter;
+else
+    length = 100;
+end
+
+
+RHO = 0.01;                            % a bunch of constants for line searches
+SIG = 0.5;       % RHO and SIG are the constants in the Wolfe-Powell conditions
+INT = 0.1;    % don't reevaluate within 0.1 of the limit of the current bracket
+EXT = 3.0;                    % extrapolate maximum 3 times the current bracket
+MAX = 20;                         % max 20 function evaluations per line search
+RATIO = 100;                                      % maximum allowed slope ratio
+
+argstr = ['feval(f, X'];                      % compose string used to call function
+for i = 1:(nargin - 3)
+  argstr = [argstr, ',P', int2str(i)];
+end
+argstr = [argstr, ')'];
+
+if max(size(length)) == 2, red=length(2); length=length(1); else red=1; end
+S=['Iteration '];
+
+i = 0;                                            % zero the run length counter
+ls_failed = 0;                             % no previous line search has failed
+fX = [];
+[f1 df1] = eval(argstr);                      % get function value and gradient
+i = i + (length<0);                                            % count epochs?!
+s = -df1;                                        % search direction is steepest
+d1 = -s'*s;                                                 % this is the slope
+z1 = red/(1-d1);                                  % initial step is red/(|s|+1)
+
+while i < abs(length)                                      % while not finished
+  i = i + (length>0);                                      % count iterations?!
+
+  X0 = X; f0 = f1; df0 = df1;                   % make a copy of current values
+  X = X + z1*s;                                             % begin line search
+  [f2 df2] = eval(argstr);
+  i = i + (length<0);                                          % count epochs?!
+  d2 = df2'*s;
+  f3 = f1; d3 = d1; z3 = -z1;             % initialize point 3 equal to point 1
+  if length>0, M = MAX; else M = min(MAX, -length-i); end
+  success = 0; limit = -1;                     % initialize quanteties
+  while 1
+    while ((f2 > f1+z1*RHO*d1) || (d2 > -SIG*d1)) && (M > 0) 
+      limit = z1;                                         % tighten the bracket
+      if f2 > f1
+        z2 = z3 - (0.5*d3*z3*z3)/(d3*z3+f2-f3);                 % quadratic fit
+      else
+        A = 6*(f2-f3)/z3+3*(d2+d3);                                 % cubic fit
+        B = 3*(f3-f2)-z3*(d3+2*d2);
+        z2 = (sqrt(B*B-A*d2*z3*z3)-B)/A;       % numerical error possible - ok!
+      end
+      if isnan(z2) || isinf(z2)
+        z2 = z3/2;                  % if we had a numerical problem then bisect
+      end
+      z2 = max(min(z2, INT*z3),(1-INT)*z3);  % don't accept too close to limits
+      z1 = z1 + z2;                                           % update the step
+      X = X + z2*s;
+      [f2 df2] = eval(argstr);
+      M = M - 1; i = i + (length<0);                           % count epochs?!
+      d2 = df2'*s;
+      z3 = z3-z2;                    % z3 is now relative to the location of z2
+    end
+    if f2 > f1+z1*RHO*d1 || d2 > -SIG*d1
+      break;                                                % this is a failure
+    elseif d2 > SIG*d1
+      success = 1; break;                                             % success
+    elseif M == 0
+      break;                                                          % failure
+    end
+    A = 6*(f2-f3)/z3+3*(d2+d3);                      % make cubic extrapolation
+    B = 3*(f3-f2)-z3*(d3+2*d2);
+    z2 = -d2*z3*z3/(B+sqrt(B*B-A*d2*z3*z3));        % num. error possible - ok!
+    if ~isreal(z2) || isnan(z2) || isinf(z2) || z2 < 0 % num prob or wrong sign?
+      if limit < -0.5                               % if we have no upper limit
+        z2 = z1 * (EXT-1);                 % the extrapolate the maximum amount
+      else
+        z2 = (limit-z1)/2;                                   % otherwise bisect
+      end
+    elseif (limit > -0.5) && (z2+z1 > limit)         % extraplation beyond max?
+      z2 = (limit-z1)/2;                                               % bisect
+    elseif (limit < -0.5) && (z2+z1 > z1*EXT)       % extrapolation beyond limit
+      z2 = z1*(EXT-1.0);                           % set to extrapolation limit
+    elseif z2 < -z3*INT
+      z2 = -z3*INT;
+    elseif (limit > -0.5) && (z2 < (limit-z1)*(1.0-INT))  % too close to limit?
+      z2 = (limit-z1)*(1.0-INT);
+    end
+    f3 = f2; d3 = d2; z3 = -z2;                  % set point 3 equal to point 2
+    z1 = z1 + z2; X = X + z2*s;                      % update current estimates
+    [f2 df2] = eval(argstr);
+    M = M - 1; i = i + (length<0);                             % count epochs?!
+    d2 = df2'*s;
+  end                                                      % end of line search
+
+  if success                                         % if line search succeeded
+    f1 = f2; fX = [fX' f1]';
+    fprintf('%s %4i | Cost: %4.6e\r', S, i, f1);
+    s = (df2'*df2-df1'*df2)/(df1'*df1)*s - df2;      % Polack-Ribiere direction
+    tmp = df1; df1 = df2; df2 = tmp;                         % swap derivatives
+    d2 = df1'*s;
+    if d2 > 0                                      % new slope must be negative
+      s = -df1;                              % otherwise use steepest direction
+      d2 = -s'*s;    
+    end
+    z1 = z1 * min(RATIO, d1/(d2-realmin));          % slope ratio but max RATIO
+    d1 = d2;
+    ls_failed = 0;                              % this line search did not fail
+  else
+    X = X0; f1 = f0; df1 = df0;  % restore point from before failed line search
+    if ls_failed || i > abs(length)          % line search failed twice in a row
+      break;                             % or we ran out of time, so we give up
+    end
+    tmp = df1; df1 = df2; df2 = tmp;                         % swap derivatives
+    s = -df1;                                                    % try steepest
+    d1 = -s'*s;
+    z1 = 1/(1-d1);                     
+    ls_failed = 1;                                    % this line search failed
+  end
+  if exist('OCTAVE_VERSION')
+    fflush(stdout);
+  end
+end
+fprintf('\n');

+ 6 - 0
ex3/hypothesis.m

@@ -0,0 +1,6 @@
+function  h  = hypothesis( theta, X )
+%HYPOTHESIS 此处显示有关此函数的摘要
+%   此处显示详细说明
+
+h = sigmoid(X * theta);
+end

+ 41 - 0
ex3/lib/jsonlab/AUTHORS.txt

@@ -0,0 +1,41 @@
+The author of "jsonlab" toolbox is Qianqian Fang. Qianqian
+is currently an Assistant Professor at Massachusetts General Hospital, 
+Harvard Medical School.
+
+Address: Martinos Center for Biomedical Imaging, 
+         Massachusetts General Hospital, 
+         Harvard Medical School
+         Bldg 149, 13th St, Charlestown, MA 02129, USA
+URL: http://nmr.mgh.harvard.edu/~fangq/
+Email: <fangq at nmr.mgh.harvard.edu> or <fangqq at gmail.com>
+
+
+The script loadjson.m was built upon previous works by
+
+- Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
+       date: 2009/11/02
+- François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
+       date: 2009/03/22
+- Joel Feenstra: http://www.mathworks.com/matlabcentral/fileexchange/20565
+       date: 2008/07/03
+
+
+This toolbox contains patches submitted by the following contributors:
+
+- Blake Johnson <bjohnso at bbn.com>
+  part of revision 341
+
+- Niclas Borlin <Niclas.Borlin at cs.umu.se>
+  various fixes in revision 394, including
+  - loadjson crashes for all-zero sparse matrix.
+  - loadjson crashes for empty sparse matrix.
+  - Non-zero size of 0-by-N and N-by-0 empty matrices is lost after savejson/loadjson.
+  - loadjson crashes for sparse real column vector.
+  - loadjson crashes for sparse complex column vector.
+  - Data is corrupted by savejson for sparse real row vector.
+  - savejson crashes for sparse complex row vector. 
+
+- Yul Kang <yul.kang.on at gmail.com>
+  patches for svn revision 415.
+  - savejson saves an empty cell array as [] instead of null
+  - loadjson differentiates an empty struct from an empty array

+ 74 - 0
ex3/lib/jsonlab/ChangeLog.txt

@@ -0,0 +1,74 @@
+============================================================================
+
+   JSONlab - a toolbox to encode/decode JSON/UBJSON files in MATLAB/Octave
+
+----------------------------------------------------------------------------
+
+JSONlab ChangeLog (key features marked by *):
+
+== JSONlab 1.0 (codename: Optimus - Final), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2015/01/02 polish help info for all major functions, update examples, finalize 1.0
+ 2014/12/19 fix a bug to strictly respect NoRowBracket in savejson
+
+== JSONlab 1.0.0-RC2 (codename: Optimus - RC2), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2014/11/22 show progress bar in loadjson ('ShowProgress') 
+ 2014/11/17 add Compact option in savejson to output compact JSON format ('Compact')
+ 2014/11/17 add FastArrayParser in loadjson to specify fast parser applicable levels
+ 2014/09/18 start official github mirror: https://github.com/fangq/jsonlab
+
+== JSONlab 1.0.0-RC1 (codename: Optimus - RC1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2014/09/17  fix several compatibility issues when running on octave versions 3.2-3.8
+ 2014/09/17  support 2D cell and struct arrays in both savejson and saveubjson
+ 2014/08/04  escape special characters in a JSON string
+ 2014/02/16  fix a bug when saving ubjson files
+
+== JSONlab 0.9.9 (codename: Optimus - beta), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2014/01/22  use binary read and write in saveubjson and loadubjson
+
+== JSONlab 0.9.8-1 (codename: Optimus - alpha update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2013/10/07 better round-trip conservation for empty arrays and structs (patch submitted by Yul Kang)
+
+== JSONlab 0.9.8 (codename: Optimus - alpha), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+ 2013/08/23 *universal Binary JSON (UBJSON) support, including both saveubjson and loadubjson
+
+== JSONlab 0.9.1 (codename: Rodimus, update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+ 2012/12/18 *handling of various empty and sparse matrices (fixes submitted by Niclas Borlin)
+
+== JSONlab 0.9.0 (codename: Rodimus), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2012/06/17 *new format for an invalid leading char, unpacking hex code in savejson
+ 2012/06/01  support JSONP in savejson
+ 2012/05/25  fix the empty cell bug (reported by Cyril Davin)
+ 2012/04/05  savejson can save to a file (suggested by Patrick Rapin)
+
+== JSONlab 0.8.1 (codename: Sentiel, Update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2012/02/28  loadjson quotation mark escape bug, see http://bit.ly/yyk1nS
+ 2012/01/25  patch to handle root-less objects, contributed by Blake Johnson
+
+== JSONlab 0.8.0 (codename: Sentiel), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2012/01/13 *speed up loadjson by 20 fold when parsing large data arrays in matlab
+ 2012/01/11  remove row bracket if an array has 1 element, suggested by Mykel Kochenderfer
+ 2011/12/22 *accept sequence of 'param',value input in savejson and loadjson
+ 2011/11/18  fix struct array bug reported by Mykel Kochenderfer
+
+== JSONlab 0.5.1 (codename: Nexus Update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2011/10/21  fix a bug in loadjson, previous code does not use any of the acceleration
+ 2011/10/20  loadjson supports JSON collections - concatenated JSON objects
+
+== JSONlab 0.5.0 (codename: Nexus), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2011/10/16  package and release jsonlab 0.5.0
+ 2011/10/15 *add json demo and regression test, support cpx numbers, fix double quote bug
+ 2011/10/11 *speed up readjson dramatically, interpret _Array* tags, show data in root level
+ 2011/10/10  create jsonlab project, start jsonlab website, add online documentation
+ 2011/10/07 *speed up savejson by 25x using sprintf instead of mat2str, add options support
+ 2011/10/06 *savejson works for structs, cells and arrays
+ 2011/09/09  derive loadjson from JSON parser from MATLAB Central, draft savejson.m

+ 25 - 0
ex3/lib/jsonlab/LICENSE_BSD.txt

@@ -0,0 +1,25 @@
+Copyright 2011-2015 Qianqian Fang <fangq at nmr.mgh.harvard.edu>. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice, this list of
+      conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright notice, this list
+      of conditions and the following disclaimer in the documentation and/or other materials
+      provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those of the
+authors and should not be interpreted as representing official policies, either expressed
+or implied, of the copyright holders.

+ 394 - 0
ex3/lib/jsonlab/README.txt

@@ -0,0 +1,394 @@
+===============================================================================
+=                                 JSONLab                                     =
+=           An open-source MATLAB/Octave JSON encoder and decoder             =
+===============================================================================
+
+*Copyright (C) 2011-2015  Qianqian Fang <fangq at nmr.mgh.harvard.edu>
+*License: BSD License, see License_BSD.txt for details
+*Version: 1.0 (Optimus - Final)
+
+-------------------------------------------------------------------------------
+
+Table of Content:
+
+I.  Introduction
+II. Installation
+III.Using JSONLab
+IV. Known Issues and TODOs
+V.  Contribution and feedback
+
+-------------------------------------------------------------------------------
+
+I.  Introduction
+
+JSON ([http://www.json.org/ JavaScript Object Notation]) is a highly portable, 
+human-readable and "[http://en.wikipedia.org/wiki/JSON fat-free]" text format 
+to represent complex and hierarchical data. It is as powerful as 
+[http://en.wikipedia.org/wiki/XML XML], but less verbose. JSON format is widely 
+used for data-exchange in applications, and is essential for the wild success 
+of [http://en.wikipedia.org/wiki/Ajax_(programming) Ajax] and 
+[http://en.wikipedia.org/wiki/Web_2.0 Web2.0]. 
+
+UBJSON (Universal Binary JSON) is a binary JSON format, specifically 
+optimized for compact file size and better performance while keeping
+the semantics as simple as the text-based JSON format. Using the UBJSON
+format allows to wrap complex binary data in a flexible and extensible
+structure, making it possible to process complex and large dataset 
+without accuracy loss due to text conversions.
+
+We envision that both JSON and its binary version will serve as part of 
+the mainstream data-exchange formats for scientific research in the future. 
+It will provide the flexibility and generality achieved by other popular 
+general-purpose file specifications, such as
+[http://www.hdfgroup.org/HDF5/whatishdf5.html HDF5], with significantly 
+reduced complexity and enhanced performance.
+
+JSONLab is a free and open-source implementation of a JSON/UBJSON encoder 
+and a decoder in the native MATLAB language. It can be used to convert a MATLAB 
+data structure (array, struct, cell, struct array and cell array) into 
+JSON/UBJSON formatted strings, or to decode a JSON/UBJSON file into MATLAB 
+data structure. JSONLab supports both MATLAB and  
+[http://www.gnu.org/software/octave/ GNU Octave] (a free MATLAB clone).
+
+-------------------------------------------------------------------------------
+
+II. Installation
+
+The installation of JSONLab is no different than any other simple
+MATLAB toolbox. You only need to download/unzip the JSONLab package
+to a folder, and add the folder's path to MATLAB/Octave's path list
+by using the following command:
+
+    addpath('/path/to/jsonlab');
+
+If you want to add this path permanently, you need to type "pathtool", 
+browse to the jsonlab root folder and add to the list, then click "Save".
+Then, run "rehash" in MATLAB, and type "which loadjson", if you see an 
+output, that means JSONLab is installed for MATLAB/Octave.
+
+-------------------------------------------------------------------------------
+
+III.Using JSONLab
+
+JSONLab provides two functions, loadjson.m -- a MATLAB->JSON decoder, 
+and savejson.m -- a MATLAB->JSON encoder, for the text-based JSON, and 
+two equivallent functions -- loadubjson and saveubjson for the binary 
+JSON. The detailed help info for the four functions can be found below:
+
+=== loadjson.m ===
+<pre>
+  data=loadjson(fname,opt)
+     or
+  data=loadjson(fname,'param1',value1,'param2',value2,...)
+ 
+  parse a JSON (JavaScript Object Notation) file or string
+ 
+  authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2011/09/09, including previous works from 
+ 
+          Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
+             created on 2009/11/02
+          François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
+             created on  2009/03/22
+          Joel Feenstra:
+          http://www.mathworks.com/matlabcentral/fileexchange/20565
+             created on 2008/07/03
+ 
+  $Id: loadjson.m 452 2014-11-22 16:43:33Z fangq $
+ 
+  input:
+       fname: input file name, if fname contains "{}" or "[]", fname
+              will be interpreted as a JSON string
+       opt: a struct to store parsing options, opt can be replaced by 
+            a list of ('param',value) pairs - the param string is equivallent
+            to a field in opt. opt can have the following 
+            fields (first in [.|.] is the default)
+ 
+            opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat
+                          for each element of the JSON data, and group 
+                          arrays based on the cell2mat rules.
+            opt.FastArrayParser [1|0 or integer]: if set to 1, use a
+                          speed-optimized array parser when loading an 
+                          array object. The fast array parser may 
+                          collapse block arrays into a single large
+                          array similar to rules defined in cell2mat; 0 to 
+                          use a legacy parser; if set to a larger-than-1
+                          value, this option will specify the minimum
+                          dimension to enable the fast array parser. For
+                          example, if the input is a 3D array, setting
+                          FastArrayParser to 1 will return a 3D array;
+                          setting to 2 will return a cell array of 2D
+                          arrays; setting to 3 will return to a 2D cell
+                          array of 1D vectors; setting to 4 will return a
+                          3D cell array.
+            opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar.
+ 
+  output:
+       dat: a cell array, where {...} blocks are converted into cell arrays,
+            and [...] are converted to arrays
+ 
+  examples:
+       dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}')
+       dat=loadjson(['examples' filesep 'example1.json'])
+       dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1)
+</pre>
+
+=== savejson.m ===
+
+<pre>
+  json=savejson(rootname,obj,filename)
+     or
+  json=savejson(rootname,obj,opt)
+  json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
+ 
+  convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
+  Object Notation) string
+ 
+  author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2011/09/09
+ 
+  $Id: savejson.m 458 2014-12-19 22:17:17Z fangq $
+ 
+  input:
+       rootname: the name of the root-object, when set to '', the root name
+         is ignored, however, when opt.ForceRootName is set to 1 (see below),
+         the MATLAB variable name will be used as the root name.
+       obj: a MATLAB object (array, cell, cell array, struct, struct array).
+       filename: a string for the file name to save the output JSON data.
+       opt: a struct for additional options, ignore to use default values.
+         opt can have the following fields (first in [.|.] is the default)
+ 
+         opt.FileName [''|string]: a file name to save the output JSON data
+         opt.FloatFormat ['%.10g'|string]: format to show each numeric element
+                          of a 1D/2D array;
+         opt.ArrayIndent [1|0]: if 1, output explicit data array with
+                          precedent indentation; if 0, no indentation
+         opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
+                          array in JSON array format; if sets to 1, an
+                          array will be shown as a struct with fields
+                          "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+                          sparse arrays, the non-zero elements will be
+                          saved to _ArrayData_ field in triplet-format i.e.
+                          (ix,iy,val) and "_ArrayIsSparse_" will be added
+                          with a value of 1; for a complex array, the 
+                          _ArrayData_ array will include two columns 
+                          (4 for sparse) to record the real and imaginary 
+                          parts, and also "_ArrayIsComplex_":1 is added. 
+         opt.ParseLogical [0|1]: if this is set to 1, logical array elem
+                          will use true/false rather than 1/0.
+         opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+                          numerical element will be shown without a square
+                          bracket, unless it is the root object; if 0, square
+                          brackets are forced for any numerical arrays.
+         opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
+                          will use the name of the passed obj variable as the 
+                          root object name; if obj is an expression and 
+                          does not have a name, 'root' will be used; if this 
+                          is set to 0 and rootname is empty, the root level 
+                          will be merged down to the lower level.
+         opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
+                          to represent +/-Inf. The matched pattern is '([-+]*)Inf'
+                          and $1 represents the sign. For those who want to use
+                          1e999 to represent Inf, they can set opt.Inf to '$11e999'
+         opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
+                          to represent NaN
+         opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+                          for example, if opt.JSONP='foo', the JSON data is
+                          wrapped inside a function call as 'foo(...);'
+         opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+                          back to the string form
+         opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
+         opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs)
+ 
+         opt can be replaced by a list of ('param',value) pairs. The param 
+         string is equivallent to a field in opt and is case sensitive.
+  output:
+       json: a string in the JSON format (see http://json.org)
+ 
+  examples:
+       jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+                'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+                'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+                           2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+                'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+                'SpecialData',[nan, inf, -inf]);
+       savejson('jmesh',jsonmesh)
+       savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g')
+ </pre>
+
+=== loadubjson.m ===
+
+<pre>
+  data=loadubjson(fname,opt)
+     or
+  data=loadubjson(fname,'param1',value1,'param2',value2,...)
+ 
+  parse a JSON (JavaScript Object Notation) file or string
+ 
+  authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2013/08/01
+ 
+  $Id: loadubjson.m 436 2014-08-05 20:51:40Z fangq $
+ 
+  input:
+       fname: input file name, if fname contains "{}" or "[]", fname
+              will be interpreted as a UBJSON string
+       opt: a struct to store parsing options, opt can be replaced by 
+            a list of ('param',value) pairs - the param string is equivallent
+            to a field in opt. opt can have the following 
+            fields (first in [.|.] is the default)
+ 
+            opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
+                          for each element of the JSON data, and group 
+                          arrays based on the cell2mat rules.
+            opt.IntEndian [B|L]: specify the endianness of the integer fields
+                          in the UBJSON input data. B - Big-Endian format for 
+                          integers (as required in the UBJSON specification); 
+                          L - input integer fields are in Little-Endian order.
+ 
+  output:
+       dat: a cell array, where {...} blocks are converted into cell arrays,
+            and [...] are converted to arrays
+ 
+  examples:
+       obj=struct('string','value','array',[1 2 3]);
+       ubjdata=saveubjson('obj',obj);
+       dat=loadubjson(ubjdata)
+       dat=loadubjson(['examples' filesep 'example1.ubj'])
+       dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)
+</pre>
+
+=== saveubjson.m ===
+
+<pre>
+  json=saveubjson(rootname,obj,filename)
+     or
+  json=saveubjson(rootname,obj,opt)
+  json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
+ 
+  convert a MATLAB object (cell, struct or array) into a Universal 
+  Binary JSON (UBJSON) binary string
+ 
+  author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2013/08/17
+ 
+  $Id: saveubjson.m 440 2014-09-17 19:59:45Z fangq $
+ 
+  input:
+       rootname: the name of the root-object, when set to '', the root name
+         is ignored, however, when opt.ForceRootName is set to 1 (see below),
+         the MATLAB variable name will be used as the root name.
+       obj: a MATLAB object (array, cell, cell array, struct, struct array)
+       filename: a string for the file name to save the output UBJSON data
+       opt: a struct for additional options, ignore to use default values.
+         opt can have the following fields (first in [.|.] is the default)
+ 
+         opt.FileName [''|string]: a file name to save the output JSON data
+         opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
+                          array in JSON array format; if sets to 1, an
+                          array will be shown as a struct with fields
+                          "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+                          sparse arrays, the non-zero elements will be
+                          saved to _ArrayData_ field in triplet-format i.e.
+                          (ix,iy,val) and "_ArrayIsSparse_" will be added
+                          with a value of 1; for a complex array, the 
+                          _ArrayData_ array will include two columns 
+                          (4 for sparse) to record the real and imaginary 
+                          parts, and also "_ArrayIsComplex_":1 is added. 
+         opt.ParseLogical [1|0]: if this is set to 1, logical array elem
+                          will use true/false rather than 1/0.
+         opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+                          numerical element will be shown without a square
+                          bracket, unless it is the root object; if 0, square
+                          brackets are forced for any numerical arrays.
+         opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
+                          will use the name of the passed obj variable as the 
+                          root object name; if obj is an expression and 
+                          does not have a name, 'root' will be used; if this 
+                          is set to 0 and rootname is empty, the root level 
+                          will be merged down to the lower level.
+         opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+                          for example, if opt.JSON='foo', the JSON data is
+                          wrapped inside a function call as 'foo(...);'
+         opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+                          back to the string form
+ 
+         opt can be replaced by a list of ('param',value) pairs. The param 
+         string is equivallent to a field in opt and is case sensitive.
+  output:
+       json: a binary string in the UBJSON format (see http://ubjson.org)
+ 
+  examples:
+       jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+                'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+                'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+                           2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+                'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+                'SpecialData',[nan, inf, -inf]);
+       saveubjson('jsonmesh',jsonmesh)
+       saveubjson('jsonmesh',jsonmesh,'meshdata.ubj')
+</pre>
+
+
+=== examples ===
+
+Under the "examples" folder, you can find several scripts to demonstrate the
+basic utilities of JSONLab. Running the "demo_jsonlab_basic.m" script, you 
+will see the conversions from MATLAB data structure to JSON text and backward.
+In "jsonlab_selftest.m", we load complex JSON files downloaded from the Internet
+and validate the loadjson/savejson functions for regression testing purposes.
+Similarly, a "demo_ubjson_basic.m" script is provided to test the saveubjson
+and loadubjson pairs for various matlab data structures.
+
+Please run these examples and understand how JSONLab works before you use
+it to process your data.
+
+-------------------------------------------------------------------------------
+
+IV. Known Issues and TODOs
+
+JSONLab has several known limitations. We are striving to make it more general
+and robust. Hopefully in a few future releases, the limitations become less.
+
+Here are the known issues:
+
+# 3D or higher dimensional cell/struct-arrays will be converted to 2D arrays;
+# When processing names containing multi-byte characters, Octave and MATLAB \
+can give different field-names; you can use feature('DefaultCharacterSet','latin1') \
+in MATLAB to get consistant results
+# savejson can not handle class and dataset.
+# saveubjson converts a logical array into a uint8 ([U]) array
+# an unofficial N-D array count syntax is implemented in saveubjson. We are \
+actively communicating with the UBJSON spec maintainer to investigate the \
+possibility of making it upstream
+# loadubjson can not parse all UBJSON Specification (Draft 9) compliant \
+files, however, it can parse all UBJSON files produced by saveubjson.
+
+-------------------------------------------------------------------------------
+
+V. Contribution and feedback
+
+JSONLab is an open-source project. This means you can not only use it and modify
+it as you wish, but also you can contribute your changes back to JSONLab so
+that everyone else can enjoy the improvement. For anyone who want to contribute,
+please download JSONLab source code from it's subversion repository by using the
+following command:
+
+ svn checkout svn://svn.code.sf.net/p/iso2mesh/code/trunk/jsonlab jsonlab
+
+You can make changes to the files as needed. Once you are satisfied with your
+changes, and ready to share it with others, please cd the root directory of 
+JSONLab, and type
+
+ svn diff > yourname_featurename.patch
+
+You then email the .patch file to JSONLab's maintainer, Qianqian Fang, at
+the email address shown in the beginning of this file. Qianqian will review 
+the changes and commit it to the subversion if they are satisfactory.
+
+We appreciate any suggestions and feedbacks from you. Please use iso2mesh's
+mailing list to report any questions you may have with JSONLab:
+
+http://groups.google.com/group/iso2mesh-users?hl=en&pli=1
+
+(Subscription to the mailing list is needed in order to post messages).

+ 32 - 0
ex3/lib/jsonlab/jsonopt.m

@@ -0,0 +1,32 @@
+function val=jsonopt(key,default,varargin)
+%
+% val=jsonopt(key,default,optstruct)
+%
+% setting options based on a struct. The struct can be produced
+% by varargin2struct from a list of 'param','value' pairs
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+%
+% $Id: loadjson.m 371 2012-06-20 12:43:06Z fangq $
+%
+% input:
+%      key: a string with which one look up a value from a struct
+%      default: if the key does not exist, return default
+%      optstruct: a struct where each sub-field is a key 
+%
+% output:
+%      val: if key exists, val=optstruct.key; otherwise val=default
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details
+%
+% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+% 
+
+val=default;
+if(nargin<=2) return; end
+opt=varargin{1};
+if(isstruct(opt) && isfield(opt,key))
+    val=getfield(opt,key);
+end
+

+ 566 - 0
ex3/lib/jsonlab/loadjson.m

@@ -0,0 +1,566 @@
+function data = loadjson(fname,varargin)
+%
+% data=loadjson(fname,opt)
+%    or
+% data=loadjson(fname,'param1',value1,'param2',value2,...)
+%
+% parse a JSON (JavaScript Object Notation) file or string
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2011/09/09, including previous works from 
+%
+%         Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
+%            created on 2009/11/02
+%         François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
+%            created on  2009/03/22
+%         Joel Feenstra:
+%         http://www.mathworks.com/matlabcentral/fileexchange/20565
+%            created on 2008/07/03
+%
+% $Id: loadjson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      fname: input file name, if fname contains "{}" or "[]", fname
+%             will be interpreted as a JSON string
+%      opt: a struct to store parsing options, opt can be replaced by 
+%           a list of ('param',value) pairs - the param string is equivallent
+%           to a field in opt. opt can have the following 
+%           fields (first in [.|.] is the default)
+%
+%           opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat
+%                         for each element of the JSON data, and group 
+%                         arrays based on the cell2mat rules.
+%           opt.FastArrayParser [1|0 or integer]: if set to 1, use a
+%                         speed-optimized array parser when loading an 
+%                         array object. The fast array parser may 
+%                         collapse block arrays into a single large
+%                         array similar to rules defined in cell2mat; 0 to 
+%                         use a legacy parser; if set to a larger-than-1
+%                         value, this option will specify the minimum
+%                         dimension to enable the fast array parser. For
+%                         example, if the input is a 3D array, setting
+%                         FastArrayParser to 1 will return a 3D array;
+%                         setting to 2 will return a cell array of 2D
+%                         arrays; setting to 3 will return to a 2D cell
+%                         array of 1D vectors; setting to 4 will return a
+%                         3D cell array.
+%           opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar.
+%
+% output:
+%      dat: a cell array, where {...} blocks are converted into cell arrays,
+%           and [...] are converted to arrays
+%
+% examples:
+%      dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}')
+%      dat=loadjson(['examples' filesep 'example1.json'])
+%      dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1)
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details 
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+global pos inStr len  esc index_esc len_esc isoct arraytoken
+
+if(regexp(fname,'[\{\}\]\[]','once'))
+   string=fname;
+elseif(exist(fname,'file'))
+   fid = fopen(fname,'rb');
+   string = fread(fid,inf,'uint8=>char')';
+   fclose(fid);
+else
+   error('input file does not exist');
+end
+
+pos = 1; len = length(string); inStr = string;
+isoct=exist('OCTAVE_VERSION','builtin');
+arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
+jstr=regexprep(inStr,'\\\\','  ');
+escquote=regexp(jstr,'\\"');
+arraytoken=sort([arraytoken escquote]);
+
+% String delimiters and escape chars identified to improve speed:
+esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
+index_esc = 1; len_esc = length(esc);
+
+opt=varargin2struct(varargin{:});
+
+if(jsonopt('ShowProgress',0,opt)==1)
+    opt.progressbar_=waitbar(0,'loading ...');
+end
+jsoncount=1;
+while pos <= len
+    switch(next_char)
+        case '{'
+            data{jsoncount} = parse_object(opt);
+        case '['
+            data{jsoncount} = parse_array(opt);
+        otherwise
+            error_pos('Outer level structure must be an object or an array');
+    end
+    jsoncount=jsoncount+1;
+end % while
+
+jsoncount=length(data);
+if(jsoncount==1 && iscell(data))
+    data=data{1};
+end
+
+if(~isempty(data))
+      if(isstruct(data)) % data can be a struct array
+          data=jstruct2array(data);
+      elseif(iscell(data))
+          data=jcell2array(data);
+      end
+end
+if(isfield(opt,'progressbar_'))
+    close(opt.progressbar_);
+end
+
+%%
+function newdata=jcell2array(data)
+len=length(data);
+newdata=data;
+for i=1:len
+      if(isstruct(data{i}))
+          newdata{i}=jstruct2array(data{i});
+      elseif(iscell(data{i}))
+          newdata{i}=jcell2array(data{i});
+      end
+end
+
+%%-------------------------------------------------------------------------
+function newdata=jstruct2array(data)
+fn=fieldnames(data);
+newdata=data;
+len=length(data);
+for i=1:length(fn) % depth-first
+    for j=1:len
+        if(isstruct(getfield(data(j),fn{i})))
+            newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
+        end
+    end
+end
+if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
+  newdata=cell(len,1);
+  for j=1:len
+    ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
+    iscpx=0;
+    if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
+        if(data(j).x0x5F_ArrayIsComplex_)
+           iscpx=1;
+        end
+    end
+    if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
+        if(data(j).x0x5F_ArrayIsSparse_)
+            if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+                dim=data(j).x0x5F_ArraySize_;
+                if(iscpx && size(ndata,2)==4-any(dim==1))
+                    ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
+                end
+                if isempty(ndata)
+                    % All-zeros sparse
+                    ndata=sparse(dim(1),prod(dim(2:end)));
+                elseif dim(1)==1
+                    % Sparse row vector
+                    ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
+                elseif dim(2)==1
+                    % Sparse column vector
+                    ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
+                else
+                    % Generic sparse array.
+                    ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
+                end
+            else
+                if(iscpx && size(ndata,2)==4)
+                    ndata(:,3)=complex(ndata(:,3),ndata(:,4));
+                end
+                ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
+            end
+        end
+    elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+        if(iscpx && size(ndata,2)==2)
+             ndata=complex(ndata(:,1),ndata(:,2));
+        end
+        ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
+    end
+    newdata{j}=ndata;
+  end
+  if(len==1)
+      newdata=newdata{1};
+  end
+end
+
+%%-------------------------------------------------------------------------
+function object = parse_object(varargin)
+    parse_char('{');
+    object = [];
+    if next_char ~= '}'
+        while 1
+            str = parseStr(varargin{:});
+            if isempty(str)
+                error_pos('Name of value at position %d cannot be empty');
+            end
+            parse_char(':');
+            val = parse_value(varargin{:});
+            eval( sprintf( 'object.%s  = val;', valid_field(str) ) );
+            if next_char == '}'
+                break;
+            end
+            parse_char(',');
+        end
+    end
+    parse_char('}');
+
+%%-------------------------------------------------------------------------
+
+function object = parse_array(varargin) % JSON array is written in row-major order
+global pos inStr isoct
+    parse_char('[');
+    object = cell(0, 1);
+    dim2=[];
+    arraydepth=jsonopt('JSONLAB_ArrayDepth_',1,varargin{:});
+    pbar=jsonopt('progressbar_',-1,varargin{:});
+
+    if next_char ~= ']'
+	if(jsonopt('FastArrayParser',1,varargin{:})>=1 && arraydepth>=jsonopt('FastArrayParser',1,varargin{:}))
+            [endpos, e1l, e1r, maxlevel]=matching_bracket(inStr,pos);
+            arraystr=['[' inStr(pos:endpos)];
+            arraystr=regexprep(arraystr,'"_NaN_"','NaN');
+            arraystr=regexprep(arraystr,'"([-+]*)_Inf_"','$1Inf');
+            arraystr(arraystr==sprintf('\n'))=[];
+            arraystr(arraystr==sprintf('\r'))=[];
+            %arraystr=regexprep(arraystr,'\s*,',','); % this is slow,sometimes needed
+            if(~isempty(e1l) && ~isempty(e1r)) % the array is in 2D or higher D
+        	astr=inStr((e1l+1):(e1r-1));
+        	astr=regexprep(astr,'"_NaN_"','NaN');
+        	astr=regexprep(astr,'"([-+]*)_Inf_"','$1Inf');
+        	astr(astr==sprintf('\n'))=[];
+        	astr(astr==sprintf('\r'))=[];
+        	astr(astr==' ')='';
+        	if(isempty(find(astr=='[', 1))) % array is 2D
+                    dim2=length(sscanf(astr,'%f,',[1 inf]));
+        	end
+            else % array is 1D
+        	astr=arraystr(2:end-1);
+        	astr(astr==' ')='';
+        	[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',[1,inf]);
+        	if(nextidx>=length(astr)-1)
+                    object=obj;
+                    pos=endpos;
+                    parse_char(']');
+                    return;
+        	end
+            end
+            if(~isempty(dim2))
+        	astr=arraystr;
+        	astr(astr=='[')='';
+        	astr(astr==']')='';
+        	astr(astr==' ')='';
+        	[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',inf);
+        	if(nextidx>=length(astr)-1)
+                    object=reshape(obj,dim2,numel(obj)/dim2)';
+                    pos=endpos;
+                    parse_char(']');
+                    if(pbar>0)
+                        waitbar(pos/length(inStr),pbar,'loading ...');
+                    end
+                    return;
+        	end
+            end
+            arraystr=regexprep(arraystr,'\]\s*,','];');
+	else
+            arraystr='[';
+	end
+        try
+           if(isoct && regexp(arraystr,'"','once'))
+                error('Octave eval can produce empty cells for JSON-like input');
+           end
+           object=eval(arraystr);
+           pos=endpos;
+        catch
+         while 1
+            newopt=varargin2struct(varargin{:},'JSONLAB_ArrayDepth_',arraydepth+1);
+            val = parse_value(newopt);
+            object{end+1} = val;
+            if next_char == ']'
+                break;
+            end
+            parse_char(',');
+         end
+        end
+    end
+    if(jsonopt('SimplifyCell',0,varargin{:})==1)
+      try
+        oldobj=object;
+        object=cell2mat(object')';
+        if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
+            object=oldobj;
+        elseif(size(object,1)>1 && ndims(object)==2)
+            object=object';
+        end
+      catch
+      end
+    end
+    parse_char(']');
+    
+    if(pbar>0)
+        waitbar(pos/length(inStr),pbar,'loading ...');
+    end
+%%-------------------------------------------------------------------------
+
+function parse_char(c)
+    global pos inStr len
+    skip_whitespace;
+    if pos > len || inStr(pos) ~= c
+        error_pos(sprintf('Expected %c at position %%d', c));
+    else
+        pos = pos + 1;
+        skip_whitespace;
+    end
+
+%%-------------------------------------------------------------------------
+
+function c = next_char
+    global pos inStr len
+    skip_whitespace;
+    if pos > len
+        c = [];
+    else
+        c = inStr(pos);
+    end
+
+%%-------------------------------------------------------------------------
+
+function skip_whitespace
+    global pos inStr len
+    while pos <= len && isspace(inStr(pos))
+        pos = pos + 1;
+    end
+
+%%-------------------------------------------------------------------------
+function str = parseStr(varargin)
+    global pos inStr len  esc index_esc len_esc
+ % len, ns = length(inStr), keyboard
+    if inStr(pos) ~= '"'
+        error_pos('String starting with " expected at position %d');
+    else
+        pos = pos + 1;
+    end
+    str = '';
+    while pos <= len
+        while index_esc <= len_esc && esc(index_esc) < pos
+            index_esc = index_esc + 1;
+        end
+        if index_esc > len_esc
+            str = [str inStr(pos:len)];
+            pos = len + 1;
+            break;
+        else
+            str = [str inStr(pos:esc(index_esc)-1)];
+            pos = esc(index_esc);
+        end
+        nstr = length(str); switch inStr(pos)
+            case '"'
+                pos = pos + 1;
+                if(~isempty(str))
+                    if(strcmp(str,'_Inf_'))
+                        str=Inf;
+                    elseif(strcmp(str,'-_Inf_'))
+                        str=-Inf;
+                    elseif(strcmp(str,'_NaN_'))
+                        str=NaN;
+                    end
+                end
+                return;
+            case '\'
+                if pos+1 > len
+                    error_pos('End of file reached right after escape character');
+                end
+                pos = pos + 1;
+                switch inStr(pos)
+                    case {'"' '\' '/'}
+                        str(nstr+1) = inStr(pos);
+                        pos = pos + 1;
+                    case {'b' 'f' 'n' 'r' 't'}
+                        str(nstr+1) = sprintf(['\' inStr(pos)]);
+                        pos = pos + 1;
+                    case 'u'
+                        if pos+4 > len
+                            error_pos('End of file reached in escaped unicode character');
+                        end
+                        str(nstr+(1:6)) = inStr(pos-1:pos+4);
+                        pos = pos + 5;
+                end
+            otherwise % should never happen
+                str(nstr+1) = inStr(pos), keyboard
+                pos = pos + 1;
+        end
+    end
+    error_pos('End of file while expecting end of inStr');
+
+%%-------------------------------------------------------------------------
+
+function num = parse_number(varargin)
+    global pos inStr len isoct
+    currstr=inStr(pos:end);
+    numstr=0;
+    if(isoct~=0)
+        numstr=regexp(currstr,'^\s*-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?','end');
+        [num, one] = sscanf(currstr, '%f', 1);
+        delta=numstr+1;
+    else
+        [num, one, err, delta] = sscanf(currstr, '%f', 1);
+        if ~isempty(err)
+            error_pos('Error reading number at position %d');
+        end
+    end
+    pos = pos + delta-1;
+
+%%-------------------------------------------------------------------------
+
+function val = parse_value(varargin)
+    global pos inStr len
+    true = 1; false = 0;
+    
+    pbar=jsonopt('progressbar_',-1,varargin{:});
+    if(pbar>0)
+        waitbar(pos/len,pbar,'loading ...');
+    end
+    
+    switch(inStr(pos))
+        case '"'
+            val = parseStr(varargin{:});
+            return;
+        case '['
+            val = parse_array(varargin{:});
+            return;
+        case '{'
+            val = parse_object(varargin{:});
+            if isstruct(val)
+                if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
+                    val=jstruct2array(val);
+                end
+            elseif isempty(val)
+                val = struct;
+            end
+            return;
+        case {'-','0','1','2','3','4','5','6','7','8','9'}
+            val = parse_number(varargin{:});
+            return;
+        case 't'
+            if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'true')
+                val = true;
+                pos = pos + 4;
+                return;
+            end
+        case 'f'
+            if pos+4 <= len && strcmpi(inStr(pos:pos+4), 'false')
+                val = false;
+                pos = pos + 5;
+                return;
+            end
+        case 'n'
+            if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'null')
+                val = [];
+                pos = pos + 4;
+                return;
+            end
+    end
+    error_pos('Value expected at position %d');
+%%-------------------------------------------------------------------------
+
+function error_pos(msg)
+    global pos inStr len
+    poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
+    if poShow(3) == poShow(2)
+        poShow(3:4) = poShow(2)+[0 -1];  % display nothing after
+    end
+    msg = [sprintf(msg, pos) ': ' ...
+    inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
+    error( ['JSONparser:invalidFormat: ' msg] );
+
+%%-------------------------------------------------------------------------
+
+function str = valid_field(str)
+global isoct
+% From MATLAB doc: field names must begin with a letter, which may be
+% followed by any combination of letters, digits, and underscores.
+% Invalid characters will be converted to underscores, and the prefix
+% "x0x[Hex code]_" will be added if the first character is not a letter.
+    pos=regexp(str,'^[^A-Za-z]','once');
+    if(~isempty(pos))
+        if(~isoct)
+            str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
+        else
+            str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
+        end
+    end
+    if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return;  end
+    if(~isoct)
+        str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
+    else
+        pos=regexp(str,'[^0-9A-Za-z_]');
+        if(isempty(pos)) return; end
+        str0=str;
+        pos0=[0 pos(:)' length(str)];
+        str='';
+        for i=1:length(pos)
+            str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
+        end
+        if(pos(end)~=length(str))
+            str=[str str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+    %str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
+
+%%-------------------------------------------------------------------------
+function endpos = matching_quote(str,pos)
+len=length(str);
+while(pos<len)
+    if(str(pos)=='"')
+        if(~(pos>1 && str(pos-1)=='\'))
+            endpos=pos;
+            return;
+        end        
+    end
+    pos=pos+1;
+end
+error('unmatched quotation mark');
+%%-------------------------------------------------------------------------
+function [endpos, e1l, e1r, maxlevel] = matching_bracket(str,pos)
+global arraytoken
+level=1;
+maxlevel=level;
+endpos=0;
+bpos=arraytoken(arraytoken>=pos);
+tokens=str(bpos);
+len=length(tokens);
+pos=1;
+e1l=[];
+e1r=[];
+while(pos<=len)
+    c=tokens(pos);
+    if(c==']')
+        level=level-1;
+        if(isempty(e1r)) e1r=bpos(pos); end
+        if(level==0)
+            endpos=bpos(pos);
+            return
+        end
+    end
+    if(c=='[')
+        if(isempty(e1l)) e1l=bpos(pos); end
+        level=level+1;
+        maxlevel=max(maxlevel,level);
+    end
+    if(c=='"')
+        pos=matching_quote(tokens,pos+1);
+    end
+    pos=pos+1;
+end
+if(endpos==0) 
+    error('unmatched "]"');
+end
+

+ 528 - 0
ex3/lib/jsonlab/loadubjson.m

@@ -0,0 +1,528 @@
+function data = loadubjson(fname,varargin)
+%
+% data=loadubjson(fname,opt)
+%    or
+% data=loadubjson(fname,'param1',value1,'param2',value2,...)
+%
+% parse a JSON (JavaScript Object Notation) file or string
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2013/08/01
+%
+% $Id: loadubjson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      fname: input file name, if fname contains "{}" or "[]", fname
+%             will be interpreted as a UBJSON string
+%      opt: a struct to store parsing options, opt can be replaced by 
+%           a list of ('param',value) pairs - the param string is equivallent
+%           to a field in opt. opt can have the following 
+%           fields (first in [.|.] is the default)
+%
+%           opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
+%                         for each element of the JSON data, and group 
+%                         arrays based on the cell2mat rules.
+%           opt.IntEndian [B|L]: specify the endianness of the integer fields
+%                         in the UBJSON input data. B - Big-Endian format for 
+%                         integers (as required in the UBJSON specification); 
+%                         L - input integer fields are in Little-Endian order.
+%
+% output:
+%      dat: a cell array, where {...} blocks are converted into cell arrays,
+%           and [...] are converted to arrays
+%
+% examples:
+%      obj=struct('string','value','array',[1 2 3]);
+%      ubjdata=saveubjson('obj',obj);
+%      dat=loadubjson(ubjdata)
+%      dat=loadubjson(['examples' filesep 'example1.ubj'])
+%      dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details 
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+global pos inStr len  esc index_esc len_esc isoct arraytoken fileendian systemendian
+
+if(regexp(fname,'[\{\}\]\[]','once'))
+   string=fname;
+elseif(exist(fname,'file'))
+   fid = fopen(fname,'rb');
+   string = fread(fid,inf,'uint8=>char')';
+   fclose(fid);
+else
+   error('input file does not exist');
+end
+
+pos = 1; len = length(string); inStr = string;
+isoct=exist('OCTAVE_VERSION','builtin');
+arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
+jstr=regexprep(inStr,'\\\\','  ');
+escquote=regexp(jstr,'\\"');
+arraytoken=sort([arraytoken escquote]);
+
+% String delimiters and escape chars identified to improve speed:
+esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
+index_esc = 1; len_esc = length(esc);
+
+opt=varargin2struct(varargin{:});
+fileendian=upper(jsonopt('IntEndian','B',opt));
+[os,maxelem,systemendian]=computer;
+
+jsoncount=1;
+while pos <= len
+    switch(next_char)
+        case '{'
+            data{jsoncount} = parse_object(opt);
+        case '['
+            data{jsoncount} = parse_array(opt);
+        otherwise
+            error_pos('Outer level structure must be an object or an array');
+    end
+    jsoncount=jsoncount+1;
+end % while
+
+jsoncount=length(data);
+if(jsoncount==1 && iscell(data))
+    data=data{1};
+end
+
+if(~isempty(data))
+      if(isstruct(data)) % data can be a struct array
+          data=jstruct2array(data);
+      elseif(iscell(data))
+          data=jcell2array(data);
+      end
+end
+
+
+%%
+function newdata=parse_collection(id,data,obj)
+
+if(jsoncount>0 && exist('data','var')) 
+    if(~iscell(data))
+       newdata=cell(1);
+       newdata{1}=data;
+       data=newdata;
+    end
+end
+
+%%
+function newdata=jcell2array(data)
+len=length(data);
+newdata=data;
+for i=1:len
+      if(isstruct(data{i}))
+          newdata{i}=jstruct2array(data{i});
+      elseif(iscell(data{i}))
+          newdata{i}=jcell2array(data{i});
+      end
+end
+
+%%-------------------------------------------------------------------------
+function newdata=jstruct2array(data)
+fn=fieldnames(data);
+newdata=data;
+len=length(data);
+for i=1:length(fn) % depth-first
+    for j=1:len
+        if(isstruct(getfield(data(j),fn{i})))
+            newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
+        end
+    end
+end
+if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
+  newdata=cell(len,1);
+  for j=1:len
+    ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
+    iscpx=0;
+    if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
+        if(data(j).x0x5F_ArrayIsComplex_)
+           iscpx=1;
+        end
+    end
+    if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
+        if(data(j).x0x5F_ArrayIsSparse_)
+            if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+                dim=double(data(j).x0x5F_ArraySize_);
+                if(iscpx && size(ndata,2)==4-any(dim==1))
+                    ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
+                end
+                if isempty(ndata)
+                    % All-zeros sparse
+                    ndata=sparse(dim(1),prod(dim(2:end)));
+                elseif dim(1)==1
+                    % Sparse row vector
+                    ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
+                elseif dim(2)==1
+                    % Sparse column vector
+                    ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
+                else
+                    % Generic sparse array.
+                    ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
+                end
+            else
+                if(iscpx && size(ndata,2)==4)
+                    ndata(:,3)=complex(ndata(:,3),ndata(:,4));
+                end
+                ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
+            end
+        end
+    elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+        if(iscpx && size(ndata,2)==2)
+             ndata=complex(ndata(:,1),ndata(:,2));
+        end
+        ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
+    end
+    newdata{j}=ndata;
+  end
+  if(len==1)
+      newdata=newdata{1};
+  end
+end
+
+%%-------------------------------------------------------------------------
+function object = parse_object(varargin)
+    parse_char('{');
+    object = [];
+    type='';
+    count=-1;
+    if(next_char == '$')
+        type=inStr(pos+1); % TODO
+        pos=pos+2;
+    end
+    if(next_char == '#')
+        pos=pos+1;
+        count=double(parse_number());
+    end
+    if next_char ~= '}'
+        num=0;
+        while 1
+            str = parseStr(varargin{:});
+            if isempty(str)
+                error_pos('Name of value at position %d cannot be empty');
+            end
+            %parse_char(':');
+            val = parse_value(varargin{:});
+            num=num+1;
+            eval( sprintf( 'object.%s  = val;', valid_field(str) ) );
+            if next_char == '}' || (count>=0 && num>=count)
+                break;
+            end
+            %parse_char(',');
+        end
+    end
+    if(count==-1)
+        parse_char('}');
+    end
+
+%%-------------------------------------------------------------------------
+function [cid,len]=elem_info(type)
+id=strfind('iUIlLdD',type);
+dataclass={'int8','uint8','int16','int32','int64','single','double'};
+bytelen=[1,1,2,4,8,4,8];
+if(id>0)
+    cid=dataclass{id};
+    len=bytelen(id);
+else
+    error_pos('unsupported type at position %d');
+end
+%%-------------------------------------------------------------------------
+
+
+function [data adv]=parse_block(type,count,varargin)
+global pos inStr isoct fileendian systemendian
+[cid,len]=elem_info(type);
+datastr=inStr(pos:pos+len*count-1);
+if(isoct)
+    newdata=int8(datastr);
+else
+    newdata=uint8(datastr);
+end
+id=strfind('iUIlLdD',type);
+if(id<=5 && fileendian~=systemendian)
+    newdata=swapbytes(typecast(newdata,cid));
+end
+data=typecast(newdata,cid);
+adv=double(len*count);
+
+%%-------------------------------------------------------------------------
+
+
+function object = parse_array(varargin) % JSON array is written in row-major order
+global pos inStr isoct
+    parse_char('[');
+    object = cell(0, 1);
+    dim=[];
+    type='';
+    count=-1;
+    if(next_char == '$')
+        type=inStr(pos+1);
+        pos=pos+2;
+    end
+    if(next_char == '#')
+        pos=pos+1;
+        if(next_char=='[')
+            dim=parse_array(varargin{:});
+            count=prod(double(dim));
+        else
+            count=double(parse_number());
+        end
+    end
+    if(~isempty(type))
+        if(count>=0)
+            [object adv]=parse_block(type,count,varargin{:});
+            if(~isempty(dim))
+                object=reshape(object,dim);
+            end
+            pos=pos+adv;
+            return;
+        else
+            endpos=matching_bracket(inStr,pos);
+            [cid,len]=elem_info(type);
+            count=(endpos-pos)/len;
+            [object adv]=parse_block(type,count,varargin{:});
+            pos=pos+adv;
+            parse_char(']');
+            return;
+        end
+    end
+    if next_char ~= ']'
+         while 1
+            val = parse_value(varargin{:});
+            object{end+1} = val;
+            if next_char == ']'
+                break;
+            end
+            %parse_char(',');
+         end
+    end
+    if(jsonopt('SimplifyCell',0,varargin{:})==1)
+      try
+        oldobj=object;
+        object=cell2mat(object')';
+        if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
+            object=oldobj;
+        elseif(size(object,1)>1 && ndims(object)==2)
+            object=object';
+        end
+      catch
+      end
+    end
+    if(count==-1)
+        parse_char(']');
+    end
+
+%%-------------------------------------------------------------------------
+
+function parse_char(c)
+    global pos inStr len
+    skip_whitespace;
+    if pos > len || inStr(pos) ~= c
+        error_pos(sprintf('Expected %c at position %%d', c));
+    else
+        pos = pos + 1;
+        skip_whitespace;
+    end
+
+%%-------------------------------------------------------------------------
+
+function c = next_char
+    global pos inStr len
+    skip_whitespace;
+    if pos > len
+        c = [];
+    else
+        c = inStr(pos);
+    end
+
+%%-------------------------------------------------------------------------
+
+function skip_whitespace
+    global pos inStr len
+    while pos <= len && isspace(inStr(pos))
+        pos = pos + 1;
+    end
+
+%%-------------------------------------------------------------------------
+function str = parseStr(varargin)
+    global pos inStr esc index_esc len_esc
+ % len, ns = length(inStr), keyboard
+    type=inStr(pos);
+    if type ~= 'S' && type ~= 'C' && type ~= 'H'
+        error_pos('String starting with S expected at position %d');
+    else
+        pos = pos + 1;
+    end
+    if(type == 'C')
+        str=inStr(pos);
+        pos=pos+1;
+        return;
+    end
+    bytelen=double(parse_number());
+    if(length(inStr)>=pos+bytelen-1)
+        str=inStr(pos:pos+bytelen-1);
+        pos=pos+bytelen;
+    else
+        error_pos('End of file while expecting end of inStr');
+    end
+
+%%-------------------------------------------------------------------------
+
+function num = parse_number(varargin)
+    global pos inStr len isoct fileendian systemendian
+    id=strfind('iUIlLdD',inStr(pos));
+    if(isempty(id))
+        error_pos('expecting a number at position %d');
+    end
+    type={'int8','uint8','int16','int32','int64','single','double'};
+    bytelen=[1,1,2,4,8,4,8];
+    datastr=inStr(pos+1:pos+bytelen(id));
+    if(isoct)
+        newdata=int8(datastr);
+    else
+        newdata=uint8(datastr);
+    end
+    if(id<=5 && fileendian~=systemendian)
+        newdata=swapbytes(typecast(newdata,type{id}));
+    end
+    num=typecast(newdata,type{id});
+    pos = pos + bytelen(id)+1;
+
+%%-------------------------------------------------------------------------
+
+function val = parse_value(varargin)
+    global pos inStr len
+    true = 1; false = 0;
+
+    switch(inStr(pos))
+        case {'S','C','H'}
+            val = parseStr(varargin{:});
+            return;
+        case '['
+            val = parse_array(varargin{:});
+            return;
+        case '{'
+            val = parse_object(varargin{:});
+            if isstruct(val)
+                if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
+                    val=jstruct2array(val);
+                end
+            elseif isempty(val)
+                val = struct;
+            end
+            return;
+        case {'i','U','I','l','L','d','D'}
+            val = parse_number(varargin{:});
+            return;
+        case 'T'
+            val = true;
+            pos = pos + 1;
+            return;
+        case 'F'
+            val = false;
+            pos = pos + 1;
+            return;
+        case {'Z','N'}
+            val = [];
+            pos = pos + 1;
+            return;
+    end
+    error_pos('Value expected at position %d');
+%%-------------------------------------------------------------------------
+
+function error_pos(msg)
+    global pos inStr len
+    poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
+    if poShow(3) == poShow(2)
+        poShow(3:4) = poShow(2)+[0 -1];  % display nothing after
+    end
+    msg = [sprintf(msg, pos) ': ' ...
+    inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
+    error( ['JSONparser:invalidFormat: ' msg] );
+
+%%-------------------------------------------------------------------------
+
+function str = valid_field(str)
+global isoct
+% From MATLAB doc: field names must begin with a letter, which may be
+% followed by any combination of letters, digits, and underscores.
+% Invalid characters will be converted to underscores, and the prefix
+% "x0x[Hex code]_" will be added if the first character is not a letter.
+    pos=regexp(str,'^[^A-Za-z]','once');
+    if(~isempty(pos))
+        if(~isoct)
+            str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
+        else
+            str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
+        end
+    end
+    if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return;  end
+    if(~isoct)
+        str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
+    else
+        pos=regexp(str,'[^0-9A-Za-z_]');
+        if(isempty(pos)) return; end
+        str0=str;
+        pos0=[0 pos(:)' length(str)];
+        str='';
+        for i=1:length(pos)
+            str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
+        end
+        if(pos(end)~=length(str))
+            str=[str str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+    %str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
+
+%%-------------------------------------------------------------------------
+function endpos = matching_quote(str,pos)
+len=length(str);
+while(pos<len)
+    if(str(pos)=='"')
+        if(~(pos>1 && str(pos-1)=='\'))
+            endpos=pos;
+            return;
+        end        
+    end
+    pos=pos+1;
+end
+error('unmatched quotation mark');
+%%-------------------------------------------------------------------------
+function [endpos e1l e1r maxlevel] = matching_bracket(str,pos)
+global arraytoken
+level=1;
+maxlevel=level;
+endpos=0;
+bpos=arraytoken(arraytoken>=pos);
+tokens=str(bpos);
+len=length(tokens);
+pos=1;
+e1l=[];
+e1r=[];
+while(pos<=len)
+    c=tokens(pos);
+    if(c==']')
+        level=level-1;
+        if(isempty(e1r)) e1r=bpos(pos); end
+        if(level==0)
+            endpos=bpos(pos);
+            return
+        end
+    end
+    if(c=='[')
+        if(isempty(e1l)) e1l=bpos(pos); end
+        level=level+1;
+        maxlevel=max(maxlevel,level);
+    end
+    if(c=='"')
+        pos=matching_quote(tokens,pos+1);
+    end
+    pos=pos+1;
+end
+if(endpos==0) 
+    error('unmatched "]"');
+end
+

+ 33 - 0
ex3/lib/jsonlab/mergestruct.m

@@ -0,0 +1,33 @@
+function s=mergestruct(s1,s2)
+%
+% s=mergestruct(s1,s2)
+%
+% merge two struct objects into one
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% date: 2012/12/22
+%
+% input:
+%      s1,s2: a struct object, s1 and s2 can not be arrays
+%
+% output:
+%      s: the merged struct object. fields in s1 and s2 will be combined in s.
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details 
+%
+% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+if(~isstruct(s1) || ~isstruct(s2))
+    error('input parameters contain non-struct');
+end
+if(length(s1)>1 || length(s2)>1)
+    error('can not merge struct arrays');
+end
+fn=fieldnames(s2);
+s=s1;
+for i=1:length(fn)              
+    s=setfield(s,fn{i},getfield(s2,fn{i}));
+end
+

+ 475 - 0
ex3/lib/jsonlab/savejson.m

@@ -0,0 +1,475 @@
+function json=savejson(rootname,obj,varargin)
+%
+% json=savejson(rootname,obj,filename)
+%    or
+% json=savejson(rootname,obj,opt)
+% json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
+%
+% convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
+% Object Notation) string
+%
+% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2011/09/09
+%
+% $Id: savejson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      rootname: the name of the root-object, when set to '', the root name
+%        is ignored, however, when opt.ForceRootName is set to 1 (see below),
+%        the MATLAB variable name will be used as the root name.
+%      obj: a MATLAB object (array, cell, cell array, struct, struct array).
+%      filename: a string for the file name to save the output JSON data.
+%      opt: a struct for additional options, ignore to use default values.
+%        opt can have the following fields (first in [.|.] is the default)
+%
+%        opt.FileName [''|string]: a file name to save the output JSON data
+%        opt.FloatFormat ['%.10g'|string]: format to show each numeric element
+%                         of a 1D/2D array;
+%        opt.ArrayIndent [1|0]: if 1, output explicit data array with
+%                         precedent indentation; if 0, no indentation
+%        opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
+%                         array in JSON array format; if sets to 1, an
+%                         array will be shown as a struct with fields
+%                         "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+%                         sparse arrays, the non-zero elements will be
+%                         saved to _ArrayData_ field in triplet-format i.e.
+%                         (ix,iy,val) and "_ArrayIsSparse_" will be added
+%                         with a value of 1; for a complex array, the 
+%                         _ArrayData_ array will include two columns 
+%                         (4 for sparse) to record the real and imaginary 
+%                         parts, and also "_ArrayIsComplex_":1 is added. 
+%        opt.ParseLogical [0|1]: if this is set to 1, logical array elem
+%                         will use true/false rather than 1/0.
+%        opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+%                         numerical element will be shown without a square
+%                         bracket, unless it is the root object; if 0, square
+%                         brackets are forced for any numerical arrays.
+%        opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
+%                         will use the name of the passed obj variable as the 
+%                         root object name; if obj is an expression and 
+%                         does not have a name, 'root' will be used; if this 
+%                         is set to 0 and rootname is empty, the root level 
+%                         will be merged down to the lower level.
+%        opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
+%                         to represent +/-Inf. The matched pattern is '([-+]*)Inf'
+%                         and $1 represents the sign. For those who want to use
+%                         1e999 to represent Inf, they can set opt.Inf to '$11e999'
+%        opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
+%                         to represent NaN
+%        opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+%                         for example, if opt.JSONP='foo', the JSON data is
+%                         wrapped inside a function call as 'foo(...);'
+%        opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+%                         back to the string form
+%        opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
+%        opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs)
+%
+%        opt can be replaced by a list of ('param',value) pairs. The param 
+%        string is equivallent to a field in opt and is case sensitive.
+% output:
+%      json: a string in the JSON format (see http://json.org)
+%
+% examples:
+%      jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+%               'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+%               'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+%                          2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+%               'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+%               'SpecialData',[nan, inf, -inf]);
+%      savejson('jmesh',jsonmesh)
+%      savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g')
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+if(nargin==1)
+   varname=inputname(1);
+   obj=rootname;
+   if(isempty(varname)) 
+      varname='root';
+   end
+   rootname=varname;
+else
+   varname=inputname(2);
+end
+if(length(varargin)==1 && ischar(varargin{1}))
+   opt=struct('FileName',varargin{1});
+else
+   opt=varargin2struct(varargin{:});
+end
+opt.IsOctave=exist('OCTAVE_VERSION','builtin');
+rootisarray=0;
+rootlevel=1;
+forceroot=jsonopt('ForceRootName',0,opt);
+if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)
+    rootisarray=1;
+    rootlevel=0;
+else
+    if(isempty(rootname))
+        rootname=varname;
+    end
+end
+if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
+    rootname='root';
+end
+
+whitespaces=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+if(jsonopt('Compact',0,opt)==1)
+    whitespaces=struct('tab','','newline','','sep',',');
+end
+if(~isfield(opt,'whitespaces_'))
+    opt.whitespaces_=whitespaces;
+end
+
+nl=whitespaces.newline;
+
+json=obj2json(rootname,obj,rootlevel,opt);
+if(rootisarray)
+    json=sprintf('%s%s',json,nl);
+else
+    json=sprintf('{%s%s%s}\n',nl,json,nl);
+end
+
+jsonp=jsonopt('JSONP','',opt);
+if(~isempty(jsonp))
+    json=sprintf('%s(%s);%s',jsonp,json,nl);
+end
+
+% save to a file if FileName is set, suggested by Patrick Rapin
+if(~isempty(jsonopt('FileName','',opt)))
+    if(jsonopt('SaveBinary',0,opt)==1)
+	    fid = fopen(opt.FileName, 'wb');
+	    fwrite(fid,json);
+    else
+	    fid = fopen(opt.FileName, 'wt');
+	    fwrite(fid,json,'char');
+    end
+    fclose(fid);
+end
+
+%%-------------------------------------------------------------------------
+function txt=obj2json(name,item,level,varargin)
+
+if(iscell(item))
+    txt=cell2json(name,item,level,varargin{:});
+elseif(isstruct(item))
+    txt=struct2json(name,item,level,varargin{:});
+elseif(ischar(item))
+    txt=str2json(name,item,level,varargin{:});
+else
+    txt=mat2json(name,item,level,varargin{:});
+end
+
+%%-------------------------------------------------------------------------
+function txt=cell2json(name,item,level,varargin)
+txt='';
+if(~iscell(item))
+        error('input is not a cell');
+end
+
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item);
+ws=jsonopt('whitespaces_',struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n')),varargin{:});
+padding0=repmat(ws.tab,1,level);
+padding2=repmat(ws.tab,1,level+1);
+nl=ws.newline;
+if(len>1)
+    if(~isempty(name))
+        txt=sprintf('%s"%s": [%s',padding0, checkname(name,varargin{:}),nl); name=''; 
+    else
+        txt=sprintf('%s[%s',padding0,nl); 
+    end
+elseif(len==0)
+    if(~isempty(name))
+        txt=sprintf('%s"%s": []',padding0, checkname(name,varargin{:})); name=''; 
+    else
+        txt=sprintf('%s[]',padding0); 
+    end
+end
+for j=1:dim(2)
+    if(dim(1)>1) txt=sprintf('%s%s[%s',txt,padding2,nl); end
+    for i=1:dim(1)
+       txt=sprintf('%s%s',txt,obj2json(name,item{i,j},level+(dim(1)>1)+1,varargin{:}));
+       if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+    end
+    if(dim(1)>1) txt=sprintf('%s%s%s]',txt,nl,padding2); end
+    if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+    %if(j==dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+end
+if(len>1) txt=sprintf('%s%s%s]',txt,nl,padding0); end
+
+%%-------------------------------------------------------------------------
+function txt=struct2json(name,item,level,varargin)
+txt='';
+if(~isstruct(item))
+	error('input is not a struct');
+end
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item);
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+padding0=repmat(ws.tab,1,level);
+padding2=repmat(ws.tab,1,level+1);
+padding1=repmat(ws.tab,1,level+(dim(1)>1)+(len>1));
+nl=ws.newline;
+
+if(~isempty(name)) 
+    if(len>1) txt=sprintf('%s"%s": [%s',padding0,checkname(name,varargin{:}),nl); end
+else
+    if(len>1) txt=sprintf('%s[%s',padding0,nl); end
+end
+for j=1:dim(2)
+  if(dim(1)>1) txt=sprintf('%s%s[%s',txt,padding2,nl); end
+  for i=1:dim(1)
+    names = fieldnames(item(i,j));
+    if(~isempty(name) && len==1)
+        txt=sprintf('%s%s"%s": {%s',txt,padding1, checkname(name,varargin{:}),nl); 
+    else
+        txt=sprintf('%s%s{%s',txt,padding1,nl); 
+    end
+    if(~isempty(names))
+      for e=1:length(names)
+	    txt=sprintf('%s%s',txt,obj2json(names{e},getfield(item(i,j),...
+             names{e}),level+(dim(1)>1)+1+(len>1),varargin{:}));
+        if(e<length(names)) txt=sprintf('%s%s',txt,','); end
+        txt=sprintf('%s%s',txt,nl);
+      end
+    end
+    txt=sprintf('%s%s}',txt,padding1);
+    if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+  end
+  if(dim(1)>1) txt=sprintf('%s%s%s]',txt,nl,padding2); end
+  if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+end
+if(len>1) txt=sprintf('%s%s%s]',txt,nl,padding0); end
+
+%%-------------------------------------------------------------------------
+function txt=str2json(name,item,level,varargin)
+txt='';
+if(~ischar(item))
+        error('input is not a string');
+end
+item=reshape(item, max(size(item),[1 0]));
+len=size(item,1);
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+padding1=repmat(ws.tab,1,level);
+padding0=repmat(ws.tab,1,level+1);
+nl=ws.newline;
+sep=ws.sep;
+
+if(~isempty(name)) 
+    if(len>1) txt=sprintf('%s"%s": [%s',padding1,checkname(name,varargin{:}),nl); end
+else
+    if(len>1) txt=sprintf('%s[%s',padding1,nl); end
+end
+isoct=jsonopt('IsOctave',0,varargin{:});
+for e=1:len
+    if(isoct)
+        val=regexprep(item(e,:),'\\','\\');
+        val=regexprep(val,'"','\"');
+        val=regexprep(val,'^"','\"');
+    else
+        val=regexprep(item(e,:),'\\','\\\\');
+        val=regexprep(val,'"','\\"');
+        val=regexprep(val,'^"','\\"');
+    end
+    val=escapejsonstring(val);
+    if(len==1)
+        obj=['"' checkname(name,varargin{:}) '": ' '"',val,'"'];
+	if(isempty(name)) obj=['"',val,'"']; end
+        txt=sprintf('%s%s%s%s',txt,padding1,obj);
+    else
+        txt=sprintf('%s%s%s%s',txt,padding0,['"',val,'"']);
+    end
+    if(e==len) sep=''; end
+    txt=sprintf('%s%s',txt,sep);
+end
+if(len>1) txt=sprintf('%s%s%s%s',txt,nl,padding1,']'); end
+
+%%-------------------------------------------------------------------------
+function txt=mat2json(name,item,level,varargin)
+if(~isnumeric(item) && ~islogical(item))
+        error('input is not an array');
+end
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+padding1=repmat(ws.tab,1,level);
+padding0=repmat(ws.tab,1,level+1);
+nl=ws.newline;
+sep=ws.sep;
+
+if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
+   isempty(item) ||jsonopt('ArrayToStruct',0,varargin{:}))
+    if(isempty(name))
+    	txt=sprintf('%s{%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',...
+              padding1,nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl);
+    else
+    	txt=sprintf('%s"%s": {%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',...
+              padding1,checkname(name,varargin{:}),nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl);
+    end
+else
+    if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1 && level>0)
+        numtxt=regexprep(regexprep(matdata2json(item,level+1,varargin{:}),'^\[',''),']','');
+    else
+        numtxt=matdata2json(item,level+1,varargin{:});
+    end
+    if(isempty(name))
+    	txt=sprintf('%s%s',padding1,numtxt);
+    else
+        if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
+           	txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);
+        else
+    	    txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);
+        end
+    end
+    return;
+end
+dataformat='%s%s%s%s%s';
+
+if(issparse(item))
+    [ix,iy]=find(item);
+    data=full(item(find(item)));
+    if(~isreal(item))
+       data=[real(data(:)),imag(data(:))];
+       if(size(item,1)==1)
+           % Kludge to have data's 'transposedness' match item's.
+           % (Necessary for complex row vector handling below.)
+           data=data';
+       end
+       txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep);
+    end
+    txt=sprintf(dataformat,txt,padding0,'"_ArrayIsSparse_": ','1', sep);
+    if(size(item,1)==1)
+        % Row vector, store only column indices.
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+           matdata2json([iy(:),data'],level+2,varargin{:}), nl);
+    elseif(size(item,2)==1)
+        % Column vector, store only row indices.
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+           matdata2json([ix,data],level+2,varargin{:}), nl);
+    else
+        % General case, store row and column indices.
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+           matdata2json([ix,iy,data],level+2,varargin{:}), nl);
+    end
+else
+    if(isreal(item))
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+            matdata2json(item(:)',level+2,varargin{:}), nl);
+    else
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep);
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+            matdata2json([real(item(:)) imag(item(:))],level+2,varargin{:}), nl);
+    end
+end
+txt=sprintf('%s%s%s',txt,padding1,'}');
+
+%%-------------------------------------------------------------------------
+function txt=matdata2json(mat,level,varargin)
+
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+tab=ws.tab;
+nl=ws.newline;
+
+if(size(mat,1)==1)
+    pre='';
+    post='';
+    level=level-1;
+else
+    pre=sprintf('[%s',nl);
+    post=sprintf('%s%s]',nl,repmat(tab,1,level-1));
+end
+
+if(isempty(mat))
+    txt='null';
+    return;
+end
+floatformat=jsonopt('FloatFormat','%.10g',varargin{:});
+%if(numel(mat)>1)
+    formatstr=['[' repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf('],%s',nl)]];
+%else
+%    formatstr=[repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf(',\n')]];
+%end
+
+if(nargin>=2 && size(mat,1)>1 && jsonopt('ArrayIndent',1,varargin{:})==1)
+    formatstr=[repmat(tab,1,level) formatstr];
+end
+
+txt=sprintf(formatstr,mat');
+txt(end-length(nl):end)=[];
+if(islogical(mat) && jsonopt('ParseLogical',0,varargin{:})==1)
+   txt=regexprep(txt,'1','true');
+   txt=regexprep(txt,'0','false');
+end
+%txt=regexprep(mat2str(mat),'\s+',',');
+%txt=regexprep(txt,';',sprintf('],\n['));
+% if(nargin>=2 && size(mat,1)>1)
+%     txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
+% end
+txt=[pre txt post];
+if(any(isinf(mat(:))))
+    txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
+end
+if(any(isnan(mat(:))))
+    txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
+end
+
+%%-------------------------------------------------------------------------
+function newname=checkname(name,varargin)
+isunpack=jsonopt('UnpackHex',1,varargin{:});
+newname=name;
+if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
+    return
+end
+if(isunpack)
+    isoct=jsonopt('IsOctave',0,varargin{:});
+    if(~isoct)
+        newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
+    else
+        pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
+        pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
+        if(isempty(pos)) return; end
+        str0=name;
+        pos0=[0 pend(:)' length(name)];
+        newname='';
+        for i=1:length(pos)
+            newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
+        end
+        if(pos(end)~=length(name))
+            newname=[newname str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+end
+
+%%-------------------------------------------------------------------------
+function newstr=escapejsonstring(str)
+newstr=str;
+isoct=exist('OCTAVE_VERSION','builtin');
+if(isoct)
+   vv=sscanf(OCTAVE_VERSION,'%f');
+   if(vv(1)>=3.8) isoct=0; end
+end
+if(isoct)
+  escapechars={'\a','\f','\n','\r','\t','\v'};
+  for i=1:length(escapechars);
+    newstr=regexprep(newstr,escapechars{i},escapechars{i});
+  end
+else
+  escapechars={'\a','\b','\f','\n','\r','\t','\v'};
+  for i=1:length(escapechars);
+    newstr=regexprep(newstr,escapechars{i},regexprep(escapechars{i},'\\','\\\\'));
+  end
+end

+ 504 - 0
ex3/lib/jsonlab/saveubjson.m

@@ -0,0 +1,504 @@
+function json=saveubjson(rootname,obj,varargin)
+%
+% json=saveubjson(rootname,obj,filename)
+%    or
+% json=saveubjson(rootname,obj,opt)
+% json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
+%
+% convert a MATLAB object (cell, struct or array) into a Universal 
+% Binary JSON (UBJSON) binary string
+%
+% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2013/08/17
+%
+% $Id: saveubjson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      rootname: the name of the root-object, when set to '', the root name
+%        is ignored, however, when opt.ForceRootName is set to 1 (see below),
+%        the MATLAB variable name will be used as the root name.
+%      obj: a MATLAB object (array, cell, cell array, struct, struct array)
+%      filename: a string for the file name to save the output UBJSON data
+%      opt: a struct for additional options, ignore to use default values.
+%        opt can have the following fields (first in [.|.] is the default)
+%
+%        opt.FileName [''|string]: a file name to save the output JSON data
+%        opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
+%                         array in JSON array format; if sets to 1, an
+%                         array will be shown as a struct with fields
+%                         "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+%                         sparse arrays, the non-zero elements will be
+%                         saved to _ArrayData_ field in triplet-format i.e.
+%                         (ix,iy,val) and "_ArrayIsSparse_" will be added
+%                         with a value of 1; for a complex array, the 
+%                         _ArrayData_ array will include two columns 
+%                         (4 for sparse) to record the real and imaginary 
+%                         parts, and also "_ArrayIsComplex_":1 is added. 
+%        opt.ParseLogical [1|0]: if this is set to 1, logical array elem
+%                         will use true/false rather than 1/0.
+%        opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+%                         numerical element will be shown without a square
+%                         bracket, unless it is the root object; if 0, square
+%                         brackets are forced for any numerical arrays.
+%        opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
+%                         will use the name of the passed obj variable as the 
+%                         root object name; if obj is an expression and 
+%                         does not have a name, 'root' will be used; if this 
+%                         is set to 0 and rootname is empty, the root level 
+%                         will be merged down to the lower level.
+%        opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+%                         for example, if opt.JSON='foo', the JSON data is
+%                         wrapped inside a function call as 'foo(...);'
+%        opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+%                         back to the string form
+%
+%        opt can be replaced by a list of ('param',value) pairs. The param 
+%        string is equivallent to a field in opt and is case sensitive.
+% output:
+%      json: a binary string in the UBJSON format (see http://ubjson.org)
+%
+% examples:
+%      jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+%               'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+%               'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+%                          2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+%               'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+%               'SpecialData',[nan, inf, -inf]);
+%      saveubjson('jsonmesh',jsonmesh)
+%      saveubjson('jsonmesh',jsonmesh,'meshdata.ubj')
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+if(nargin==1)
+   varname=inputname(1);
+   obj=rootname;
+   if(isempty(varname)) 
+      varname='root';
+   end
+   rootname=varname;
+else
+   varname=inputname(2);
+end
+if(length(varargin)==1 && ischar(varargin{1}))
+   opt=struct('FileName',varargin{1});
+else
+   opt=varargin2struct(varargin{:});
+end
+opt.IsOctave=exist('OCTAVE_VERSION','builtin');
+rootisarray=0;
+rootlevel=1;
+forceroot=jsonopt('ForceRootName',0,opt);
+if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)
+    rootisarray=1;
+    rootlevel=0;
+else
+    if(isempty(rootname))
+        rootname=varname;
+    end
+end
+if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
+    rootname='root';
+end
+json=obj2ubjson(rootname,obj,rootlevel,opt);
+if(~rootisarray)
+    json=['{' json '}'];
+end
+
+jsonp=jsonopt('JSONP','',opt);
+if(~isempty(jsonp))
+    json=[jsonp '(' json ')'];
+end
+
+% save to a file if FileName is set, suggested by Patrick Rapin
+if(~isempty(jsonopt('FileName','',opt)))
+    fid = fopen(opt.FileName, 'wb');
+    fwrite(fid,json);
+    fclose(fid);
+end
+
+%%-------------------------------------------------------------------------
+function txt=obj2ubjson(name,item,level,varargin)
+
+if(iscell(item))
+    txt=cell2ubjson(name,item,level,varargin{:});
+elseif(isstruct(item))
+    txt=struct2ubjson(name,item,level,varargin{:});
+elseif(ischar(item))
+    txt=str2ubjson(name,item,level,varargin{:});
+else
+    txt=mat2ubjson(name,item,level,varargin{:});
+end
+
+%%-------------------------------------------------------------------------
+function txt=cell2ubjson(name,item,level,varargin)
+txt='';
+if(~iscell(item))
+        error('input is not a cell');
+end
+
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item); % let's handle 1D cell first
+if(len>1) 
+    if(~isempty(name))
+        txt=[S_(checkname(name,varargin{:})) '[']; name=''; 
+    else
+        txt='['; 
+    end
+elseif(len==0)
+    if(~isempty(name))
+        txt=[S_(checkname(name,varargin{:})) 'Z']; name=''; 
+    else
+        txt='Z'; 
+    end
+end
+for j=1:dim(2)
+    if(dim(1)>1) txt=[txt '[']; end
+    for i=1:dim(1)
+       txt=[txt obj2ubjson(name,item{i,j},level+(len>1),varargin{:})];
+    end
+    if(dim(1)>1) txt=[txt ']']; end
+end
+if(len>1) txt=[txt ']']; end
+
+%%-------------------------------------------------------------------------
+function txt=struct2ubjson(name,item,level,varargin)
+txt='';
+if(~isstruct(item))
+	error('input is not a struct');
+end
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item);
+
+if(~isempty(name)) 
+    if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
+else
+    if(len>1) txt='['; end
+end
+for j=1:dim(2)
+  if(dim(1)>1) txt=[txt '[']; end
+  for i=1:dim(1)
+     names = fieldnames(item(i,j));
+     if(~isempty(name) && len==1)
+        txt=[txt S_(checkname(name,varargin{:})) '{']; 
+     else
+        txt=[txt '{']; 
+     end
+     if(~isempty(names))
+       for e=1:length(names)
+	     txt=[txt obj2ubjson(names{e},getfield(item(i,j),...
+             names{e}),level+(dim(1)>1)+1+(len>1),varargin{:})];
+       end
+     end
+     txt=[txt '}'];
+  end
+  if(dim(1)>1) txt=[txt ']']; end
+end
+if(len>1) txt=[txt ']']; end
+
+%%-------------------------------------------------------------------------
+function txt=str2ubjson(name,item,level,varargin)
+txt='';
+if(~ischar(item))
+        error('input is not a string');
+end
+item=reshape(item, max(size(item),[1 0]));
+len=size(item,1);
+
+if(~isempty(name)) 
+    if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
+else
+    if(len>1) txt='['; end
+end
+isoct=jsonopt('IsOctave',0,varargin{:});
+for e=1:len
+    val=item(e,:);
+    if(len==1)
+        obj=['' S_(checkname(name,varargin{:})) '' '',S_(val),''];
+	if(isempty(name)) obj=['',S_(val),'']; end
+        txt=[txt,'',obj];
+    else
+        txt=[txt,'',['',S_(val),'']];
+    end
+end
+if(len>1) txt=[txt ']']; end
+
+%%-------------------------------------------------------------------------
+function txt=mat2ubjson(name,item,level,varargin)
+if(~isnumeric(item) && ~islogical(item))
+        error('input is not an array');
+end
+
+if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
+   isempty(item) || jsonopt('ArrayToStruct',0,varargin{:}))
+      cid=I_(uint32(max(size(item))));
+      if(isempty(name))
+    	txt=['{' S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1)) ];
+      else
+          if(isempty(item))
+              txt=[S_(checkname(name,varargin{:})),'Z'];
+              return;
+          else
+    	      txt=[S_(checkname(name,varargin{:})),'{',S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1))];
+          end
+      end
+else
+    if(isempty(name))
+    	txt=matdata2ubjson(item,level+1,varargin{:});
+    else
+        if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
+            numtxt=regexprep(regexprep(matdata2ubjson(item,level+1,varargin{:}),'^\[',''),']','');
+           	txt=[S_(checkname(name,varargin{:})) numtxt];
+        else
+    	    txt=[S_(checkname(name,varargin{:})),matdata2ubjson(item,level+1,varargin{:})];
+        end
+    end
+    return;
+end
+if(issparse(item))
+    [ix,iy]=find(item);
+    data=full(item(find(item)));
+    if(~isreal(item))
+       data=[real(data(:)),imag(data(:))];
+       if(size(item,1)==1)
+           % Kludge to have data's 'transposedness' match item's.
+           % (Necessary for complex row vector handling below.)
+           data=data';
+       end
+       txt=[txt,S_('_ArrayIsComplex_'),'T'];
+    end
+    txt=[txt,S_('_ArrayIsSparse_'),'T'];
+    if(size(item,1)==1)
+        % Row vector, store only column indices.
+        txt=[txt,S_('_ArrayData_'),...
+           matdata2ubjson([iy(:),data'],level+2,varargin{:})];
+    elseif(size(item,2)==1)
+        % Column vector, store only row indices.
+        txt=[txt,S_('_ArrayData_'),...
+           matdata2ubjson([ix,data],level+2,varargin{:})];
+    else
+        % General case, store row and column indices.
+        txt=[txt,S_('_ArrayData_'),...
+           matdata2ubjson([ix,iy,data],level+2,varargin{:})];
+    end
+else
+    if(isreal(item))
+        txt=[txt,S_('_ArrayData_'),...
+            matdata2ubjson(item(:)',level+2,varargin{:})];
+    else
+        txt=[txt,S_('_ArrayIsComplex_'),'T'];
+        txt=[txt,S_('_ArrayData_'),...
+            matdata2ubjson([real(item(:)) imag(item(:))],level+2,varargin{:})];
+    end
+end
+txt=[txt,'}'];
+
+%%-------------------------------------------------------------------------
+function txt=matdata2ubjson(mat,level,varargin)
+if(isempty(mat))
+    txt='Z';
+    return;
+end
+if(size(mat,1)==1)
+    level=level-1;
+end
+type='';
+hasnegtive=(mat<0);
+if(isa(mat,'integer') || isinteger(mat) || (isfloat(mat) && all(mod(mat(:),1) == 0)))
+    if(isempty(hasnegtive))
+       if(max(mat(:))<=2^8)
+           type='U';
+       end
+    end
+    if(isempty(type))
+        % todo - need to consider negative ones separately
+        id= histc(abs(max(mat(:))),[0 2^7 2^15 2^31 2^63]);
+        if(isempty(find(id)))
+            error('high-precision data is not yet supported');
+        end
+        key='iIlL';
+	type=key(find(id));
+    end
+    txt=[I_a(mat(:),type,size(mat))];
+elseif(islogical(mat))
+    logicalval='FT';
+    if(numel(mat)==1)
+        txt=logicalval(mat+1);
+    else
+        txt=['[$U#' I_a(size(mat),'l') typecast(swapbytes(uint8(mat(:)')),'uint8')];
+    end
+else
+    if(numel(mat)==1)
+        txt=['[' D_(mat) ']'];
+    else
+        txt=D_a(mat(:),'D',size(mat));
+    end
+end
+
+%txt=regexprep(mat2str(mat),'\s+',',');
+%txt=regexprep(txt,';',sprintf('],['));
+% if(nargin>=2 && size(mat,1)>1)
+%     txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
+% end
+if(any(isinf(mat(:))))
+    txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
+end
+if(any(isnan(mat(:))))
+    txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
+end
+
+%%-------------------------------------------------------------------------
+function newname=checkname(name,varargin)
+isunpack=jsonopt('UnpackHex',1,varargin{:});
+newname=name;
+if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
+    return
+end
+if(isunpack)
+    isoct=jsonopt('IsOctave',0,varargin{:});
+    if(~isoct)
+        newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
+    else
+        pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
+        pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
+        if(isempty(pos)) return; end
+        str0=name;
+        pos0=[0 pend(:)' length(name)];
+        newname='';
+        for i=1:length(pos)
+            newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
+        end
+        if(pos(end)~=length(name))
+            newname=[newname str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+end
+%%-------------------------------------------------------------------------
+function val=S_(str)
+if(length(str)==1)
+  val=['C' str];
+else
+  val=['S' I_(int32(length(str))) str];
+end
+%%-------------------------------------------------------------------------
+function val=I_(num)
+if(~isinteger(num))
+    error('input is not an integer');
+end
+if(num>=0 && num<255)
+   val=['U' data2byte(swapbytes(cast(num,'uint8')),'uint8')];
+   return;
+end
+key='iIlL';
+cid={'int8','int16','int32','int64'};
+for i=1:4
+  if((num>0 && num<2^(i*8-1)) || (num<0 && num>=-2^(i*8-1)))
+    val=[key(i) data2byte(swapbytes(cast(num,cid{i})),'uint8')];
+    return;
+  end
+end
+error('unsupported integer');
+
+%%-------------------------------------------------------------------------
+function val=D_(num)
+if(~isfloat(num))
+    error('input is not a float');
+end
+
+if(isa(num,'single'))
+  val=['d' data2byte(num,'uint8')];
+else
+  val=['D' data2byte(num,'uint8')];
+end
+%%-------------------------------------------------------------------------
+function data=I_a(num,type,dim,format)
+id=find(ismember('iUIlL',type));
+
+if(id==0)
+  error('unsupported integer array');
+end
+
+% based on UBJSON specs, all integer types are stored in big endian format
+
+if(id==1)
+  data=data2byte(swapbytes(int8(num)),'uint8');
+  blen=1;
+elseif(id==2)
+  data=data2byte(swapbytes(uint8(num)),'uint8');
+  blen=1;
+elseif(id==3)
+  data=data2byte(swapbytes(int16(num)),'uint8');
+  blen=2;
+elseif(id==4)
+  data=data2byte(swapbytes(int32(num)),'uint8');
+  blen=4;
+elseif(id==5)
+  data=data2byte(swapbytes(int64(num)),'uint8');
+  blen=8;
+end
+
+if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
+  format='opt';
+end
+if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
+  if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
+      cid=I_(uint32(max(dim)));
+      data=['$' type '#' I_a(dim,cid(1)) data(:)'];
+  else
+      data=['$' type '#' I_(int32(numel(data)/blen)) data(:)'];
+  end
+  data=['[' data(:)'];
+else
+  data=reshape(data,blen,numel(data)/blen);
+  data(2:blen+1,:)=data;
+  data(1,:)=type;
+  data=data(:)';
+  data=['[' data(:)' ']'];
+end
+%%-------------------------------------------------------------------------
+function data=D_a(num,type,dim,format)
+id=find(ismember('dD',type));
+
+if(id==0)
+  error('unsupported float array');
+end
+
+if(id==1)
+  data=data2byte(single(num),'uint8');
+elseif(id==2)
+  data=data2byte(double(num),'uint8');
+end
+
+if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
+  format='opt';
+end
+if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
+  if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
+      cid=I_(uint32(max(dim)));
+      data=['$' type '#' I_a(dim,cid(1)) data(:)'];
+  else
+      data=['$' type '#' I_(int32(numel(data)/(id*4))) data(:)'];
+  end
+  data=['[' data];
+else
+  data=reshape(data,(id*4),length(data)/(id*4));
+  data(2:(id*4+1),:)=data;
+  data(1,:)=type;
+  data=data(:)';
+  data=['[' data(:)' ']'];
+end
+%%-------------------------------------------------------------------------
+function bytes=data2byte(varargin)
+bytes=typecast(varargin{:});
+bytes=bytes(:)';

+ 40 - 0
ex3/lib/jsonlab/varargin2struct.m

@@ -0,0 +1,40 @@
+function opt=varargin2struct(varargin)
+%
+% opt=varargin2struct('param1',value1,'param2',value2,...)
+%   or
+% opt=varargin2struct(...,optstruct,...)
+%
+% convert a series of input parameters into a structure
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% date: 2012/12/22
+%
+% input:
+%      'param', value: the input parameters should be pairs of a string and a value
+%       optstruct: if a parameter is a struct, the fields will be merged to the output struct
+%
+% output:
+%      opt: a struct where opt.param1=value1, opt.param2=value2 ...
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details 
+%
+% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+len=length(varargin);
+opt=struct;
+if(len==0) return; end
+i=1;
+while(i<=len)
+    if(isstruct(varargin{i}))
+        opt=mergestruct(opt,varargin{i});
+    elseif(ischar(varargin{i}) && i<len)
+        opt=setfield(opt,varargin{i},varargin{i+1});
+        i=i+1;
+    else
+        error('input must be in the form of ...,''name'',value,... pairs or structs');
+    end
+    i=i+1;
+end
+

+ 30 - 0
ex3/lib/makeValidFieldName.m

@@ -0,0 +1,30 @@
+function str = makeValidFieldName(str)
+% From MATLAB doc: field names must begin with a letter, which may be
+% followed by any combination of letters, digits, and underscores.
+% Invalid characters will be converted to underscores, and the prefix
+% "x0x[Hex code]_" will be added if the first character is not a letter.
+    isoct=exist('OCTAVE_VERSION','builtin');
+    pos=regexp(str,'^[^A-Za-z]','once');
+    if(~isempty(pos))
+        if(~isoct)
+            str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
+        else
+            str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
+        end
+    end
+    if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return;  end
+    if(~isoct)
+        str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
+    else
+        pos=regexp(str,'[^0-9A-Za-z_]');
+        if(isempty(pos)) return; end
+        str0=str;
+        pos0=[0 pos(:)' length(str)];
+        str='';
+        for i=1:length(pos)
+            str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
+        end
+        if(pos(end)~=length(str))
+            str=[str str0(pos0(end-1)+1:pos0(end))];
+        end
+    end

+ 179 - 0
ex3/lib/submitWithConfiguration.m

@@ -0,0 +1,179 @@
+function submitWithConfiguration(conf)
+  addpath('./lib/jsonlab');
+
+  parts = parts(conf);
+
+  fprintf('== Submitting solutions | %s...\n', conf.itemName);
+
+  tokenFile = 'token.mat';
+  if exist(tokenFile, 'file')
+    load(tokenFile);
+    [email token] = promptToken(email, token, tokenFile);
+  else
+    [email token] = promptToken('', '', tokenFile);
+  end
+
+  if isempty(token)
+    fprintf('!! Submission Cancelled\n');
+    return
+  end
+
+  try
+    response = submitParts(conf, email, token, parts);
+  catch
+    e = lasterror();
+    fprintf('\n!! Submission failed: %s\n', e.message);
+    fprintf('\n\nFunction: %s\nFileName: %s\nLineNumber: %d\n', ...
+      e.stack(1,1).name, e.stack(1,1).file, e.stack(1,1).line);
+    fprintf('\nPlease correct your code and resubmit.\n');
+    return
+  end
+
+  if isfield(response, 'errorMessage')
+    fprintf('!! Submission failed: %s\n', response.errorMessage);
+  elseif isfield(response, 'errorCode')
+    fprintf('!! Submission failed: %s\n', response.message);
+  else
+    showFeedback(parts, response);
+    save(tokenFile, 'email', 'token');
+  end
+end
+
+function [email token] = promptToken(email, existingToken, tokenFile)
+  if (~isempty(email) && ~isempty(existingToken))
+    prompt = sprintf( ...
+      'Use token from last successful submission (%s)? (Y/n): ', ...
+      email);
+    reenter = input(prompt, 's');
+
+    if (isempty(reenter) || reenter(1) == 'Y' || reenter(1) == 'y')
+      token = existingToken;
+      return;
+    else
+      delete(tokenFile);
+    end
+  end
+  email = input('Login (email address): ', 's');
+  token = input('Token: ', 's');
+end
+
+function isValid = isValidPartOptionIndex(partOptions, i)
+  isValid = (~isempty(i)) && (1 <= i) && (i <= numel(partOptions));
+end
+
+function response = submitParts(conf, email, token, parts)
+  body = makePostBody(conf, email, token, parts);
+  submissionUrl = submissionUrl();
+
+  responseBody = getResponse(submissionUrl, body);
+  jsonResponse = validateResponse(responseBody);
+  response = loadjson(jsonResponse);
+end
+
+function body = makePostBody(conf, email, token, parts)
+  bodyStruct.assignmentSlug = conf.assignmentSlug;
+  bodyStruct.submitterEmail = email;
+  bodyStruct.secret = token;
+  bodyStruct.parts = makePartsStruct(conf, parts);
+
+  opt.Compact = 1;
+  body = savejson('', bodyStruct, opt);
+end
+
+function partsStruct = makePartsStruct(conf, parts)
+  for part = parts
+    partId = part{:}.id;
+    fieldName = makeValidFieldName(partId);
+    outputStruct.output = conf.output(partId);
+    partsStruct.(fieldName) = outputStruct;
+  end
+end
+
+function [parts] = parts(conf)
+  parts = {};
+  for partArray = conf.partArrays
+    part.id = partArray{:}{1};
+    part.sourceFiles = partArray{:}{2};
+    part.name = partArray{:}{3};
+    parts{end + 1} = part;
+  end
+end
+
+function showFeedback(parts, response)
+  fprintf('== \n');
+  fprintf('== %43s | %9s | %-s\n', 'Part Name', 'Score', 'Feedback');
+  fprintf('== %43s | %9s | %-s\n', '---------', '-----', '--------');
+  for part = parts
+    score = '';
+    partFeedback = '';
+    partFeedback = response.partFeedbacks.(makeValidFieldName(part{:}.id));
+    partEvaluation = response.partEvaluations.(makeValidFieldName(part{:}.id));
+    score = sprintf('%d / %3d', partEvaluation.score, partEvaluation.maxScore);
+    fprintf('== %43s | %9s | %-s\n', part{:}.name, score, partFeedback);
+  end
+  evaluation = response.evaluation;
+  totalScore = sprintf('%d / %d', evaluation.score, evaluation.maxScore);
+  fprintf('==                                   --------------------------------\n');
+  fprintf('== %43s | %9s | %-s\n', '', totalScore, '');
+  fprintf('== \n');
+end
+
+% use urlread or curl to send submit results to the grader and get a response
+function response = getResponse(url, body)
+% try using urlread() and a secure connection
+  params = {'jsonBody', body};
+  [response, success] = urlread(url, 'post', params);
+
+  if (success == 0)
+    % urlread didn't work, try curl & the peer certificate patch
+    if ispc
+      % testing note: use 'jsonBody =' for a test case
+      json_command = sprintf('echo jsonBody=%s | curl -k -X POST -d @- %s', body, url);
+    else
+      % it's linux/OS X, so use the other form
+      json_command = sprintf('echo ''jsonBody=%s'' | curl -k -X POST -d @- %s', body, url);
+    end
+    % get the response body for the peer certificate patch method
+    [code, response] = system(json_command);
+    % test the success code
+    if (code ~= 0)
+      fprintf('[error] submission with curl() was not successful\n');
+    end
+  end
+end
+
+% validate the grader's response
+function response = validateResponse(resp)
+  % test if the response is json or an HTML page
+  isJson = length(resp) > 0 && resp(1) == '{';
+  isHtml = findstr(lower(resp), '<html');
+
+  if (isJson)
+    response = resp;
+  elseif (isHtml)
+    % the response is html, so it's probably an error message
+    printHTMLContents(resp);
+    error('Grader response is an HTML message');
+  else
+    error('Grader sent no response');
+  end
+end
+
+% parse a HTML response and print it's contents
+function printHTMLContents(response)
+  strippedResponse = regexprep(response, '<[^>]+>', ' ');
+  strippedResponse = regexprep(strippedResponse, '[\t ]+', ' ');
+  fprintf(strippedResponse);
+end
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Service configuration
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function submissionUrl = submissionUrl()
+  submissionUrl = 'https://www-origin.coursera.org/api/onDemandProgrammingImmediateFormSubmissions.v1';
+end

+ 56 - 0
ex3/lrCostFunction.m

@@ -0,0 +1,56 @@
+function [J, grad] = lrCostFunction(theta, X, y, lambda)
+%LRCOSTFUNCTION Compute cost and gradient for logistic regression with 
+%regularization
+%   J = LRCOSTFUNCTION(theta, X, y, lambda) computes the cost of using
+%   theta as the parameter for regularized logistic regression and the
+%   gradient of the cost w.r.t. to the parameters. 
+
+% Initialize some useful values
+m = length(y); % number of training examples
+
+% You need to return the following variables correctly 
+z = hypothesis(theta, X);
+t = lambda*(sum(theta .^ 2)-theta(1)^2)/2/m;
+J = mean(- y .* log(z) + (y - 1) .* log(1 - z)) + t;
+
+grad = mean((z - y) .* X)' + lambda /m * theta;
+grad(1) = grad(1) - lambda /m * theta(1);
+
+% ====================== YOUR CODE HERE ======================
+% Instructions: Compute the cost of a particular choice of theta.
+%               You should set J to the cost.
+%               Compute the partial derivatives and set grad to the partial
+%               derivatives of the cost w.r.t. each parameter in theta
+%
+% Hint: The computation of the cost function and gradients can be
+%       efficiently vectorized. For example, consider the computation
+%
+%           sigmoid(X * theta)
+%
+%       Each row of the resulting matrix will contain the value of the
+%       prediction for that example. You can make use of this to vectorize
+%       the cost function and gradient computations. 
+%
+% Hint: When computing the gradient of the regularized cost function, 
+%       there're many possible vectorized solutions, but one solution
+%       looks like:
+%           grad = (unregularized gradient for logistic regression)
+%           temp = theta; 
+%           temp(1) = 0;   % because we don't add anything for j = 0  
+%           grad = grad + YOUR_CODE_HERE (using the temp variable)
+%
+
+
+
+
+
+
+
+
+
+
+% =============================================================
+
+grad = grad(:);
+
+end

+ 73 - 0
ex3/oneVsAll.m

@@ -0,0 +1,73 @@
+function [all_theta] = oneVsAll(X, y, num_labels, lambda)
+%ONEVSALL trains multiple logistic regression classifiers and returns all
+%the classifiers in a matrix all_theta, where the i-th row of all_theta 
+%corresponds to the classifier for label i
+%   [all_theta] = ONEVSALL(X, y, num_labels, lambda) trains num_labels
+%   logistic regression classifiers and returns each of these classifiers
+%   in a matrix all_theta, where the i-th row of all_theta corresponds 
+%   to the classifier for label i
+
+% Some useful variables
+m = size(X, 1);
+n = size(X, 2);
+
+% You need to return the following variables correctly 
+all_theta = zeros(num_labels, n + 1);
+
+% Add ones to the X data matrix
+X = [ones(m, 1) X];
+
+for c = 1:num_labels
+    initial_theta = zeros(n + 1, 1);
+    options = optimset('GradObj', 'on', 'MaxIter', 50);
+    all_theta(c,:) = (fmincg (@(t)(lrCostFunction(t, X, (y == c), lambda)), initial_theta, options))';
+end
+
+
+% ====================== YOUR CODE HERE ======================
+% Instructions: You should complete the following code to train num_labels
+%               logistic regression classifiers with regularization
+%               parameter lambda. 
+%
+% Hint: theta(:) will return a column vector.
+%
+% Hint: You can use y == c to obtain a vector of 1's and 0's that tell you
+%       whether the ground truth is true/false for this class.
+%
+% Note: For this assignment, we recommend using fmincg to optimize the cost
+%       function. It is okay to use a for-loop (for c = 1:num_labels) to
+%       loop over the different classes.
+%
+%       fmincg works similarly to fminunc, but is more efficient when we
+%       are dealing with large number of parameters.
+%
+% Example Code for fmincg:
+%
+%     % Set Initial theta
+%     initial_theta = zeros(n + 1, 1);
+%     
+%     % Set options for fminunc
+%     options = optimset('GradObj', 'on', 'MaxIter', 50);
+% 
+%     % Run fmincg to obtain the optimal theta
+%     % This function will return theta and the cost 
+%     [theta] = ...
+%         fmincg (@(t)(lrCostFunction(t, X, (y == c), lambda)), ...
+%                 initial_theta, options);
+%
+
+
+
+
+
+
+
+
+
+
+
+
+% =========================================================================
+
+
+end

+ 44 - 0
ex3/predict.m

@@ -0,0 +1,44 @@
+function p = predict(Theta1, Theta2, X)
+%PREDICT Predict the label of an input given a trained neural network
+%   p = PREDICT(Theta1, Theta2, X) outputs the predicted label of X given the
+%   trained weights of a neural network (Theta1, Theta2)
+
+% Useful values
+m = size(X, 1);
+num_labels = size(Theta2, 1);
+
+
+a1 = [ones(size(X, 1),1) X]';
+z2 = Theta1 * a1;
+a2 = [ones(1, size(z2,2)); sigmoid(z2)];
+
+z3 = Theta2 * a2;
+a3 = sigmoid(z3);
+[~, p] = max(a3, [], 1);
+
+% You need to return the following variables correctly 
+
+
+% ====================== YOUR CODE HERE ======================
+% Instructions: Complete the following code to make predictions using
+%               your learned neural network. You should set p to a 
+%               vector containing labels between 1 to num_labels.
+%
+% Hint: The max function might come in useful. In particular, the max
+%       function can also return the index of the max element, for more
+%       information see 'help max'. If your examples are in rows, then, you
+%       can use max(A, [], 2) to obtain the max for each row.
+%
+
+
+
+
+
+
+
+
+
+% =========================================================================
+
+
+end

+ 42 - 0
ex3/predictOneVsAll.m

@@ -0,0 +1,42 @@
+function p = predictOneVsAll(all_theta, X)
+%PREDICT Predict the label for a trained one-vs-all classifier. The labels 
+%are in the range 1..K, where K = size(all_theta, 1). 
+%  p = PREDICTONEVSALL(all_theta, X) will return a vector of predictions
+%  for each example in the matrix X. Note that X contains the examples in
+%  rows. all_theta is a matrix where the i-th row is a trained logistic
+%  regression theta vector for the i-th class. You should set p to a vector
+%  of values from 1..K (e.g., p = [1; 3; 1; 2] predicts classes 1, 3, 1, 2
+%  for 4 examples) 
+
+m = size(X, 1);
+num_labels = size(all_theta, 1);
+
+% You need to return the following variables correctly 
+
+% Add ones to the X data matrix
+X = [ones(m, 1) X];
+[~,p] = max(hypothesis(all_theta', X), [], 2);
+
+% ====================== YOUR CODE HERE ======================
+% Instructions: Complete the following code to make predictions using
+%               your learned logistic regression parameters (one-vs-all).
+%               You should set p to a vector of predictions (from 1 to
+%               num_labels).
+%
+% Hint: This code can be done all vectorized using the max function.
+%       In particular, the max function can also return the index of the 
+%       max element, for more information see 'help max'. If your examples 
+%       are in rows, then, you can use max(A, [], 2) to obtain the max 
+%       for each row.
+%       
+
+
+
+
+
+
+
+% =========================================================================
+
+
+end

+ 6 - 0
ex3/sigmoid.m

@@ -0,0 +1,6 @@
+function g = sigmoid(z)
+%SIGMOID Compute sigmoid functoon
+%   J = SIGMOID(z) computes the sigmoid of z.
+
+g = 1.0 ./ (1.0 + exp(-z));
+end

+ 56 - 0
ex3/submit.m

@@ -0,0 +1,56 @@
+function submit()
+  addpath('./lib');
+
+  conf.assignmentSlug = 'multi-class-classification-and-neural-networks';
+  conf.itemName = 'Multi-class Classification and Neural Networks';
+  conf.partArrays = { ...
+    { ...
+      '1', ...
+      { 'lrCostFunction.m' }, ...
+      'Regularized Logistic Regression', ...
+    }, ...
+    { ...
+      '2', ...
+      { 'oneVsAll.m' }, ...
+      'One-vs-All Classifier Training', ...
+    }, ...
+    { ...
+      '3', ...
+      { 'predictOneVsAll.m' }, ...
+      'One-vs-All Classifier Prediction', ...
+    }, ...
+    { ...
+      '4', ...
+      { 'predict.m' }, ...
+      'Neural Network Prediction Function' ...
+    }, ...
+  };
+  conf.output = @output;
+
+  submitWithConfiguration(conf);
+end
+
+function out = output(partId, auxdata)
+  % Random Test Cases
+  X = [ones(20,1) (exp(1) * sin(1:1:20))' (exp(0.5) * cos(1:1:20))'];
+  y = sin(X(:,1) + X(:,2)) > 0;
+  Xm = [ -1 -1 ; -1 -2 ; -2 -1 ; -2 -2 ; ...
+          1 1 ;  1 2 ;  2 1 ; 2 2 ; ...
+         -1 1 ;  -1 2 ;  -2 1 ; -2 2 ; ...
+          1 -1 ; 1 -2 ;  -2 -1 ; -2 -2 ];
+  ym = [ 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 ]';
+  t1 = sin(reshape(1:2:24, 4, 3));
+  t2 = cos(reshape(1:2:40, 4, 5));
+
+  if partId == '1'
+    [J, grad] = lrCostFunction([0.25 0.5 -0.5]', X, y, 0.1);
+    out = sprintf('%0.5f ', J);
+    out = [out sprintf('%0.5f ', grad)];
+  elseif partId == '2'
+    out = sprintf('%0.5f ', oneVsAll(Xm, ym, 4, 0.1));
+  elseif partId == '3'
+    out = sprintf('%0.5f ', predictOneVsAll(t1, Xm));
+  elseif partId == '4'
+    out = sprintf('%0.5f ', predict(t1, t2, Xm));
+  end 
+end

+ 52 - 0
ex4/checkNNGradients.m

@@ -0,0 +1,52 @@
+function checkNNGradients(lambda)
+%CHECKNNGRADIENTS Creates a small neural network to check the
+%backpropagation gradients
+%   CHECKNNGRADIENTS(lambda) Creates a small neural network to check the
+%   backpropagation gradients, it will output the analytical gradients
+%   produced by your backprop code and the numerical gradients (computed
+%   using computeNumericalGradient). These two gradient computations should
+%   result in very similar values.
+%
+
+if ~exist('lambda', 'var') || isempty(lambda)
+    lambda = 0;
+end
+
+input_layer_size = 3;
+hidden_layer_size = 5;
+num_labels = 3;
+m = 5;
+
+% We generate some 'random' test data
+Theta1 = debugInitializeWeights(hidden_layer_size, input_layer_size);
+Theta2 = debugInitializeWeights(num_labels, hidden_layer_size);
+% Reusing debugInitializeWeights to generate X
+X  = debugInitializeWeights(m, input_layer_size - 1);
+y  = 1 + mod(1:m, num_labels)';
+
+% Unroll parameters
+nn_params = [Theta1(:) ; Theta2(:)];
+
+% Short hand for cost function
+costFunc = @(p) nnCostFunction(p, input_layer_size, hidden_layer_size, ...
+                               num_labels, X, y, lambda);
+
+[cost, grad] = costFunc(nn_params);
+numgrad = computeNumericalGradient(costFunc, nn_params);
+
+% Visually examine the two gradient computations.  The two columns
+% you get should be very similar. 
+disp([numgrad grad]);
+fprintf(['The above two columns you get should be very similar.\n' ...
+         '(Left-Your Numerical Gradient, Right-Analytical Gradient)\n\n']);
+
+% Evaluate the norm of the difference between two solutions.  
+% If you have a correct implementation, and assuming you used EPSILON = 0.0001 
+% in computeNumericalGradient.m, then diff below should be less than 1e-9
+diff = norm(numgrad-grad)/norm(numgrad+grad);
+
+fprintf(['If your backpropagation implementation is correct, then \n' ...
+         'the relative difference will be small (less than 1e-9). \n' ...
+         '\nRelative Difference: %g\n'], diff);
+
+end

+ 29 - 0
ex4/computeNumericalGradient.m

@@ -0,0 +1,29 @@
+function numgrad = computeNumericalGradient(J, theta)
+%COMPUTENUMERICALGRADIENT Computes the gradient using "finite differences"
+%and gives us a numerical estimate of the gradient.
+%   numgrad = COMPUTENUMERICALGRADIENT(J, theta) computes the numerical
+%   gradient of the function J around theta. Calling y = J(theta) should
+%   return the function value at theta.
+
+% Notes: The following code implements numerical gradient checking, and 
+%        returns the numerical gradient.It sets numgrad(i) to (a numerical 
+%        approximation of) the partial derivative of J with respect to the 
+%        i-th input argument, evaluated at theta. (i.e., numgrad(i) should 
+%        be the (approximately) the partial derivative of J with respect 
+%        to theta(i).)
+%                
+
+numgrad = zeros(size(theta));
+perturb = zeros(size(theta));
+e = 1e-4;
+for p = 1:numel(theta)
+    % Set perturbation vector
+    perturb(p) = e;
+    loss1 = J(theta - perturb);
+    loss2 = J(theta + perturb);
+    % Compute Numerical Gradient
+    numgrad(p) = (loss2 - loss1) / (2*e);
+    perturb(p) = 0;
+end
+
+end

+ 26 - 0
ex4/cost.m

@@ -0,0 +1,26 @@
+function [ J ] = cost( nn_params, ...
+                                   input_layer_size, ...
+                                   hidden_layer_size, ...
+                                   num_labels, ...
+                                   X, y, lambda )
+Theta1 = reshape(nn_params(1:hidden_layer_size * (input_layer_size + 1)), ...
+                 hidden_layer_size, (input_layer_size + 1));
+Theta2 = reshape(nn_params((1 + (hidden_layer_size * (input_layer_size + 1))):end), ...
+                 num_labels, (hidden_layer_size + 1));
+
+mapy = zeros(length(y), num_labels);
+for i = 1:length(y)
+    mapy(i, y(i)) = 1;
+end
+a1 = [ones(size(X, 1),1) X]';
+z2 = Theta1 * a1;
+a2 = [ones(1, size(z2,2)); sigmoid(z2)];
+z3 = Theta2 * a2;
+a3 = sigmoid(z3);
+n = size(a3, 1);
+
+J = mean(sum( - mapy' .* log(a3) + (mapy' -1) .* log(1 - a3)));
+J = J + lambda * 0.5 / size(X, 1) * (sum(sum(Theta1(:,2:end) .^2)) + sum(sum(Theta2(:,2:end) .^2)));
+
+end
+

+ 22 - 0
ex4/debugInitializeWeights.m

@@ -0,0 +1,22 @@
+function W = debugInitializeWeights(fan_out, fan_in)
+%DEBUGINITIALIZEWEIGHTS Initialize the weights of a layer with fan_in
+%incoming connections and fan_out outgoing connections using a fixed
+%strategy, this will help you later in debugging
+%   W = DEBUGINITIALIZEWEIGHTS(fan_in, fan_out) initializes the weights 
+%   of a layer with fan_in incoming connections and fan_out outgoing 
+%   connections using a fix set of values
+%
+%   Note that W should be set to a matrix of size(1 + fan_in, fan_out) as
+%   the first row of W handles the "bias" terms
+%
+
+% Set W to zeros
+W = zeros(fan_out, 1 + fan_in);
+
+% Initialize W using "sin", this ensures that W is always of the same
+% values and will be useful for debugging
+W = reshape(sin(1:numel(W)), size(W)) / 10;
+
+% =========================================================================
+
+end

+ 59 - 0
ex4/displayData.m

@@ -0,0 +1,59 @@
+function [h, display_array] = displayData(X, example_width)
+%DISPLAYDATA Display 2D data in a nice grid
+%   [h, display_array] = DISPLAYDATA(X, example_width) displays 2D data
+%   stored in X in a nice grid. It returns the figure handle h and the 
+%   displayed array if requested.
+
+% Set example_width automatically if not passed in
+if ~exist('example_width', 'var') || isempty(example_width) 
+	example_width = round(sqrt(size(X, 2)));
+end
+
+% Gray Image
+colormap(gray);
+
+% Compute rows, cols
+[m n] = size(X);
+example_height = (n / example_width);
+
+% Compute number of items to display
+display_rows = floor(sqrt(m));
+display_cols = ceil(m / display_rows);
+
+% Between images padding
+pad = 1;
+
+% Setup blank display
+display_array = - ones(pad + display_rows * (example_height + pad), ...
+                       pad + display_cols * (example_width + pad));
+
+% Copy each example into a patch on the display array
+curr_ex = 1;
+for j = 1:display_rows
+	for i = 1:display_cols
+		if curr_ex > m, 
+			break; 
+		end
+		% Copy the patch
+		
+		% Get the max value of the patch
+		max_val = max(abs(X(curr_ex, :)));
+		display_array(pad + (j - 1) * (example_height + pad) + (1:example_height), ...
+		              pad + (i - 1) * (example_width + pad) + (1:example_width)) = ...
+						reshape(X(curr_ex, :), example_height, example_width) / max_val;
+		curr_ex = curr_ex + 1;
+	end
+	if curr_ex > m, 
+		break; 
+	end
+end
+
+% Display Image
+h = imagesc(display_array, [-1 1]);
+
+% Do not show axis
+axis image off
+
+drawnow;
+
+end

+ 234 - 0
ex4/ex4.m

@@ -0,0 +1,234 @@
+%% Machine Learning Online Class - Exercise 4 Neural Network Learning
+
+%  Instructions
+%  ------------
+% 
+%  This file contains code that helps you get started on the
+%  linear exercise. You will need to complete the following functions 
+%  in this exericse:
+%
+%     sigmoidGradient.m
+%     randInitializeWeights.m
+%     nnCostFunction.m
+%
+%  For this exercise, you will not need to change any code in this file,
+%  or any other files other than those mentioned above.
+%
+
+%% Initialization
+clear ; close all; clc
+
+%% Setup the parameters you will use for this exercise
+input_layer_size  = 400;  % 20x20 Input Images of Digits
+hidden_layer_size = 25;   % 25 hidden units
+num_labels = 10;          % 10 labels, from 1 to 10   
+                          % (note that we have mapped "0" to label 10)
+
+%% =========== Part 1: Loading and Visualizing Data =============
+%  We start the exercise by first loading and visualizing the dataset. 
+%  You will be working with a dataset that contains handwritten digits.
+%
+
+% Load Training Data
+fprintf('Loading and Visualizing Data ...\n')
+
+load('ex4data1.mat');
+m = size(X, 1);
+
+% Randomly select 100 data points to display
+sel = randperm(size(X, 1));
+sel = sel(1:100);
+
+displayData(X(sel, :));
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+
+
+%% ================ Part 2: Loading Parameters ================
+% In this part of the exercise, we load some pre-initialized 
+% neural network parameters.
+
+fprintf('\nLoading Saved Neural Network Parameters ...\n')
+
+% Load the weights into variables Theta1 and Theta2
+load('ex4weights.mat');
+
+% Unroll parameters 
+nn_params = [Theta1(:) ; Theta2(:)];
+
+%% ================ Part 3: Compute Cost (Feedforward) ================
+%  To the neural network, you should first start by implementing the
+%  feedforward part of the neural network that returns the cost only. You
+%  should complete the code in nnCostFunction.m to return cost. After
+%  implementing the feedforward to compute the cost, you can verify that
+%  your implementation is correct by verifying that you get the same cost
+%  as us for the fixed debugging parameters.
+%
+%  We suggest implementing the feedforward cost *without* regularization
+%  first so that it will be easier for you to debug. Later, in part 4, you
+%  will get to implement the regularized cost.
+%
+fprintf('\nFeedforward Using Neural Network ...\n')
+
+% Weight regularization parameter (we set this to 0 here).
+lambda = 0;
+
+J = nnCostFunction(nn_params, input_layer_size, hidden_layer_size, ...
+                   num_labels, X, y, lambda);
+
+fprintf(['Cost at parameters (loaded from ex4weights): %f '...
+         '\n(this value should be about 0.287629)\n'], J);
+
+fprintf('\nProgram paused. Press enter to continue.\n');
+pause;
+
+%% =============== Part 4: Implement Regularization ===============
+%  Once your cost function implementation is correct, you should now
+%  continue to implement the regularization with the cost.
+%
+
+fprintf('\nChecking Cost Function (w/ Regularization) ... \n')
+
+% Weight regularization parameter (we set this to 1 here).
+lambda = 1;
+
+J = nnCostFunction(nn_params, input_layer_size, hidden_layer_size, ...
+                   num_labels, X, y, lambda);
+
+fprintf(['Cost at parameters (loaded from ex4weights): %f '...
+         '\n(this value should be about 0.383770)\n'], J);
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+
+
+%% ================ Part 5: Sigmoid Gradient  ================
+%  Before you start implementing the neural network, you will first
+%  implement the gradient for the sigmoid function. You should complete the
+%  code in the sigmoidGradient.m file.
+%
+
+fprintf('\nEvaluating sigmoid gradient...\n')
+
+g = sigmoidGradient([-1 -0.5 0 0.5 1]);
+fprintf('Sigmoid gradient evaluated at [-1 -0.5 0 0.5 1]:\n  ');
+fprintf('%f ', g);
+fprintf('\n\n');
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+
+
+%% ================ Part 6: Initializing Pameters ================
+%  In this part of the exercise, you will be starting to implment a two
+%  layer neural network that classifies digits. You will start by
+%  implementing a function to initialize the weights of the neural network
+%  (randInitializeWeights.m)
+
+fprintf('\nInitializing Neural Network Parameters ...\n')
+
+initial_Theta1 = randInitializeWeights(input_layer_size, hidden_layer_size);
+initial_Theta2 = randInitializeWeights(hidden_layer_size, num_labels);
+
+% Unroll parameters
+initial_nn_params = [initial_Theta1(:) ; initial_Theta2(:)];
+
+
+%% =============== Part 7: Implement Backpropagation ===============
+%  Once your cost matches up with ours, you should proceed to implement the
+%  backpropagation algorithm for the neural network. You should add to the
+%  code you've written in nnCostFunction.m to return the partial
+%  derivatives of the parameters.
+%
+fprintf('\nChecking Backpropagation... \n');
+
+%  Check gradients by running checkNNGradients
+checkNNGradients;
+
+fprintf('\nProgram paused. Press enter to continue.\n');
+pause;
+
+
+%% =============== Part 8: Implement Regularization ===============
+%  Once your backpropagation implementation is correct, you should now
+%  continue to implement the regularization with the cost and gradient.
+%
+
+fprintf('\nChecking Backpropagation (w/ Regularization) ... \n')
+
+%  Check gradients by running checkNNGradients
+lambda = 3;
+checkNNGradients(lambda);
+
+% Also output the costFunction debugging values
+debug_J  = nnCostFunction(nn_params, input_layer_size, ...
+                          hidden_layer_size, num_labels, X, y, lambda);
+
+fprintf(['\n\nCost at (fixed) debugging parameters (w/ lambda = %f): %f ' ...
+         '\n(for lambda = 3, this value should be about 0.576051)\n\n'], lambda, debug_J);
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+
+
+%% =================== Part 8: Training NN ===================
+%  You have now implemented all the code necessary to train a neural 
+%  network. To train your neural network, we will now use "fmincg", which
+%  is a function which works similarly to "fminunc". Recall that these
+%  advanced optimizers are able to train our cost functions efficiently as
+%  long as we provide them with the gradient computations.
+%
+fprintf('\nTraining Neural Network... \n')
+
+%  After you have completed the assignment, change the MaxIter to a larger
+%  value to see how more training helps.
+options = optimset('MaxIter', 50);
+
+%  You should also try different values of lambda
+lambda = 1;
+
+% Create "short hand" for the cost function to be minimized
+costFunction = @(p) nnCostFunction(p, ...
+                                   input_layer_size, ...
+                                   hidden_layer_size, ...
+                                   num_labels, X, y, lambda);
+
+% Now, costFunction is a function that takes in only one argument (the
+% neural network parameters)
+[nn_params, cost] = fmincg(costFunction, initial_nn_params, options);
+
+% Obtain Theta1 and Theta2 back from nn_params
+Theta1 = reshape(nn_params(1:hidden_layer_size * (input_layer_size + 1)), ...
+                 hidden_layer_size, (input_layer_size + 1));
+
+Theta2 = reshape(nn_params((1 + (hidden_layer_size * (input_layer_size + 1))):end), ...
+                 num_labels, (hidden_layer_size + 1));
+
+fprintf('Program paused. Press enter to continue.\n');
+pause;
+
+
+%% ================= Part 9: Visualize Weights =================
+%  You can now "visualize" what the neural network is learning by 
+%  displaying the hidden units to see what features they are capturing in 
+%  the data.
+
+fprintf('\nVisualizing Neural Network... \n')
+
+displayData(Theta1(:, 2:end));
+
+fprintf('\nProgram paused. Press enter to continue.\n');
+pause;
+
+%% ================= Part 10: Implement Predict =================
+%  After training the neural network, we would like to use it to predict
+%  the labels. You will now implement the "predict" function to use the
+%  neural network to predict the labels of the training set. This lets
+%  you compute the training set accuracy.
+
+pred = predict(Theta1, Theta2, X);
+
+fprintf('\nTraining Set Accuracy: %f\n', mean(double(pred == y)) * 100);
+
+

BIN
ex4/ex4data1.mat


BIN
ex4/ex4weights.mat


+ 175 - 0
ex4/fmincg.m

@@ -0,0 +1,175 @@
+function [X, fX, i] = fmincg(f, X, options, P1, P2, P3, P4, P5)
+% Minimize a continuous differentialble multivariate function. Starting point
+% is given by "X" (D by 1), and the function named in the string "f", must
+% return a function value and a vector of partial derivatives. The Polack-
+% Ribiere flavour of conjugate gradients is used to compute search directions,
+% and a line search using quadratic and cubic polynomial approximations and the
+% Wolfe-Powell stopping criteria is used together with the slope ratio method
+% for guessing initial step sizes. Additionally a bunch of checks are made to
+% make sure that exploration is taking place and that extrapolation will not
+% be unboundedly large. The "length" gives the length of the run: if it is
+% positive, it gives the maximum number of line searches, if negative its
+% absolute gives the maximum allowed number of function evaluations. You can
+% (optionally) give "length" a second component, which will indicate the
+% reduction in function value to be expected in the first line-search (defaults
+% to 1.0). The function returns when either its length is up, or if no further
+% progress can be made (ie, we are at a minimum, or so close that due to
+% numerical problems, we cannot get any closer). If the function terminates
+% within a few iterations, it could be an indication that the function value
+% and derivatives are not consistent (ie, there may be a bug in the
+% implementation of your "f" function). The function returns the found
+% solution "X", a vector of function values "fX" indicating the progress made
+% and "i" the number of iterations (line searches or function evaluations,
+% depending on the sign of "length") used.
+%
+% Usage: [X, fX, i] = fmincg(f, X, options, P1, P2, P3, P4, P5)
+%
+% See also: checkgrad 
+%
+% Copyright (C) 2001 and 2002 by Carl Edward Rasmussen. Date 2002-02-13
+%
+%
+% (C) Copyright 1999, 2000 & 2001, Carl Edward Rasmussen
+% 
+% Permission is granted for anyone to copy, use, or modify these
+% programs and accompanying documents for purposes of research or
+% education, provided this copyright notice is retained, and note is
+% made of any changes that have been made.
+% 
+% These programs and documents are distributed without any warranty,
+% express or implied.  As the programs were written for research
+% purposes only, they have not been tested to the degree that would be
+% advisable in any important application.  All use of these programs is
+% entirely at the user's own risk.
+%
+% [ml-class] Changes Made:
+% 1) Function name and argument specifications
+% 2) Output display
+%
+
+% Read options
+if exist('options', 'var') && ~isempty(options) && isfield(options, 'MaxIter')
+    length = options.MaxIter;
+else
+    length = 100;
+end
+
+
+RHO = 0.01;                            % a bunch of constants for line searches
+SIG = 0.5;       % RHO and SIG are the constants in the Wolfe-Powell conditions
+INT = 0.1;    % don't reevaluate within 0.1 of the limit of the current bracket
+EXT = 3.0;                    % extrapolate maximum 3 times the current bracket
+MAX = 20;                         % max 20 function evaluations per line search
+RATIO = 100;                                      % maximum allowed slope ratio
+
+argstr = ['feval(f, X'];                      % compose string used to call function
+for i = 1:(nargin - 3)
+  argstr = [argstr, ',P', int2str(i)];
+end
+argstr = [argstr, ')'];
+
+if max(size(length)) == 2, red=length(2); length=length(1); else red=1; end
+S=['Iteration '];
+
+i = 0;                                            % zero the run length counter
+ls_failed = 0;                             % no previous line search has failed
+fX = [];
+[f1 df1] = eval(argstr);                      % get function value and gradient
+i = i + (length<0);                                            % count epochs?!
+s = -df1;                                        % search direction is steepest
+d1 = -s'*s;                                                 % this is the slope
+z1 = red/(1-d1);                                  % initial step is red/(|s|+1)
+
+while i < abs(length)                                      % while not finished
+  i = i + (length>0);                                      % count iterations?!
+
+  X0 = X; f0 = f1; df0 = df1;                   % make a copy of current values
+  X = X + z1*s;                                             % begin line search
+  [f2 df2] = eval(argstr);
+  i = i + (length<0);                                          % count epochs?!
+  d2 = df2'*s;
+  f3 = f1; d3 = d1; z3 = -z1;             % initialize point 3 equal to point 1
+  if length>0, M = MAX; else M = min(MAX, -length-i); end
+  success = 0; limit = -1;                     % initialize quanteties
+  while 1
+    while ((f2 > f1+z1*RHO*d1) || (d2 > -SIG*d1)) && (M > 0) 
+      limit = z1;                                         % tighten the bracket
+      if f2 > f1
+        z2 = z3 - (0.5*d3*z3*z3)/(d3*z3+f2-f3);                 % quadratic fit
+      else
+        A = 6*(f2-f3)/z3+3*(d2+d3);                                 % cubic fit
+        B = 3*(f3-f2)-z3*(d3+2*d2);
+        z2 = (sqrt(B*B-A*d2*z3*z3)-B)/A;       % numerical error possible - ok!
+      end
+      if isnan(z2) || isinf(z2)
+        z2 = z3/2;                  % if we had a numerical problem then bisect
+      end
+      z2 = max(min(z2, INT*z3),(1-INT)*z3);  % don't accept too close to limits
+      z1 = z1 + z2;                                           % update the step
+      X = X + z2*s;
+      [f2 df2] = eval(argstr);
+      M = M - 1; i = i + (length<0);                           % count epochs?!
+      d2 = df2'*s;
+      z3 = z3-z2;                    % z3 is now relative to the location of z2
+    end
+    if f2 > f1+z1*RHO*d1 || d2 > -SIG*d1
+      break;                                                % this is a failure
+    elseif d2 > SIG*d1
+      success = 1; break;                                             % success
+    elseif M == 0
+      break;                                                          % failure
+    end
+    A = 6*(f2-f3)/z3+3*(d2+d3);                      % make cubic extrapolation
+    B = 3*(f3-f2)-z3*(d3+2*d2);
+    z2 = -d2*z3*z3/(B+sqrt(B*B-A*d2*z3*z3));        % num. error possible - ok!
+    if ~isreal(z2) || isnan(z2) || isinf(z2) || z2 < 0 % num prob or wrong sign?
+      if limit < -0.5                               % if we have no upper limit
+        z2 = z1 * (EXT-1);                 % the extrapolate the maximum amount
+      else
+        z2 = (limit-z1)/2;                                   % otherwise bisect
+      end
+    elseif (limit > -0.5) && (z2+z1 > limit)         % extraplation beyond max?
+      z2 = (limit-z1)/2;                                               % bisect
+    elseif (limit < -0.5) && (z2+z1 > z1*EXT)       % extrapolation beyond limit
+      z2 = z1*(EXT-1.0);                           % set to extrapolation limit
+    elseif z2 < -z3*INT
+      z2 = -z3*INT;
+    elseif (limit > -0.5) && (z2 < (limit-z1)*(1.0-INT))  % too close to limit?
+      z2 = (limit-z1)*(1.0-INT);
+    end
+    f3 = f2; d3 = d2; z3 = -z2;                  % set point 3 equal to point 2
+    z1 = z1 + z2; X = X + z2*s;                      % update current estimates
+    [f2 df2] = eval(argstr);
+    M = M - 1; i = i + (length<0);                             % count epochs?!
+    d2 = df2'*s;
+  end                                                      % end of line search
+
+  if success                                         % if line search succeeded
+    f1 = f2; fX = [fX' f1]';
+    fprintf('%s %4i | Cost: %4.6e\r', S, i, f1);
+    s = (df2'*df2-df1'*df2)/(df1'*df1)*s - df2;      % Polack-Ribiere direction
+    tmp = df1; df1 = df2; df2 = tmp;                         % swap derivatives
+    d2 = df1'*s;
+    if d2 > 0                                      % new slope must be negative
+      s = -df1;                              % otherwise use steepest direction
+      d2 = -s'*s;    
+    end
+    z1 = z1 * min(RATIO, d1/(d2-realmin));          % slope ratio but max RATIO
+    d1 = d2;
+    ls_failed = 0;                              % this line search did not fail
+  else
+    X = X0; f1 = f0; df1 = df0;  % restore point from before failed line search
+    if ls_failed || i > abs(length)          % line search failed twice in a row
+      break;                             % or we ran out of time, so we give up
+    end
+    tmp = df1; df1 = df2; df2 = tmp;                         % swap derivatives
+    s = -df1;                                                    % try steepest
+    d1 = -s'*s;
+    z1 = 1/(1-d1);                     
+    ls_failed = 1;                                    % this line search failed
+  end
+  if exist('OCTAVE_VERSION')
+    fflush(stdout);
+  end
+end
+fprintf('\n');

+ 6 - 0
ex4/hypothesis.m

@@ -0,0 +1,6 @@
+function  h  = hypothesis( theta, X )
+%HYPOTHESIS 此处显示有关此函数的摘要
+%   此处显示详细说明
+
+h = sigmoid(X * theta);
+end

+ 41 - 0
ex4/lib/jsonlab/AUTHORS.txt

@@ -0,0 +1,41 @@
+The author of "jsonlab" toolbox is Qianqian Fang. Qianqian
+is currently an Assistant Professor at Massachusetts General Hospital, 
+Harvard Medical School.
+
+Address: Martinos Center for Biomedical Imaging, 
+         Massachusetts General Hospital, 
+         Harvard Medical School
+         Bldg 149, 13th St, Charlestown, MA 02129, USA
+URL: http://nmr.mgh.harvard.edu/~fangq/
+Email: <fangq at nmr.mgh.harvard.edu> or <fangqq at gmail.com>
+
+
+The script loadjson.m was built upon previous works by
+
+- Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
+       date: 2009/11/02
+- François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
+       date: 2009/03/22
+- Joel Feenstra: http://www.mathworks.com/matlabcentral/fileexchange/20565
+       date: 2008/07/03
+
+
+This toolbox contains patches submitted by the following contributors:
+
+- Blake Johnson <bjohnso at bbn.com>
+  part of revision 341
+
+- Niclas Borlin <Niclas.Borlin at cs.umu.se>
+  various fixes in revision 394, including
+  - loadjson crashes for all-zero sparse matrix.
+  - loadjson crashes for empty sparse matrix.
+  - Non-zero size of 0-by-N and N-by-0 empty matrices is lost after savejson/loadjson.
+  - loadjson crashes for sparse real column vector.
+  - loadjson crashes for sparse complex column vector.
+  - Data is corrupted by savejson for sparse real row vector.
+  - savejson crashes for sparse complex row vector. 
+
+- Yul Kang <yul.kang.on at gmail.com>
+  patches for svn revision 415.
+  - savejson saves an empty cell array as [] instead of null
+  - loadjson differentiates an empty struct from an empty array

+ 74 - 0
ex4/lib/jsonlab/ChangeLog.txt

@@ -0,0 +1,74 @@
+============================================================================
+
+   JSONlab - a toolbox to encode/decode JSON/UBJSON files in MATLAB/Octave
+
+----------------------------------------------------------------------------
+
+JSONlab ChangeLog (key features marked by *):
+
+== JSONlab 1.0 (codename: Optimus - Final), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2015/01/02 polish help info for all major functions, update examples, finalize 1.0
+ 2014/12/19 fix a bug to strictly respect NoRowBracket in savejson
+
+== JSONlab 1.0.0-RC2 (codename: Optimus - RC2), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2014/11/22 show progress bar in loadjson ('ShowProgress') 
+ 2014/11/17 add Compact option in savejson to output compact JSON format ('Compact')
+ 2014/11/17 add FastArrayParser in loadjson to specify fast parser applicable levels
+ 2014/09/18 start official github mirror: https://github.com/fangq/jsonlab
+
+== JSONlab 1.0.0-RC1 (codename: Optimus - RC1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2014/09/17  fix several compatibility issues when running on octave versions 3.2-3.8
+ 2014/09/17  support 2D cell and struct arrays in both savejson and saveubjson
+ 2014/08/04  escape special characters in a JSON string
+ 2014/02/16  fix a bug when saving ubjson files
+
+== JSONlab 0.9.9 (codename: Optimus - beta), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2014/01/22  use binary read and write in saveubjson and loadubjson
+
+== JSONlab 0.9.8-1 (codename: Optimus - alpha update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2013/10/07 better round-trip conservation for empty arrays and structs (patch submitted by Yul Kang)
+
+== JSONlab 0.9.8 (codename: Optimus - alpha), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+ 2013/08/23 *universal Binary JSON (UBJSON) support, including both saveubjson and loadubjson
+
+== JSONlab 0.9.1 (codename: Rodimus, update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+ 2012/12/18 *handling of various empty and sparse matrices (fixes submitted by Niclas Borlin)
+
+== JSONlab 0.9.0 (codename: Rodimus), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2012/06/17 *new format for an invalid leading char, unpacking hex code in savejson
+ 2012/06/01  support JSONP in savejson
+ 2012/05/25  fix the empty cell bug (reported by Cyril Davin)
+ 2012/04/05  savejson can save to a file (suggested by Patrick Rapin)
+
+== JSONlab 0.8.1 (codename: Sentiel, Update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2012/02/28  loadjson quotation mark escape bug, see http://bit.ly/yyk1nS
+ 2012/01/25  patch to handle root-less objects, contributed by Blake Johnson
+
+== JSONlab 0.8.0 (codename: Sentiel), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2012/01/13 *speed up loadjson by 20 fold when parsing large data arrays in matlab
+ 2012/01/11  remove row bracket if an array has 1 element, suggested by Mykel Kochenderfer
+ 2011/12/22 *accept sequence of 'param',value input in savejson and loadjson
+ 2011/11/18  fix struct array bug reported by Mykel Kochenderfer
+
+== JSONlab 0.5.1 (codename: Nexus Update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2011/10/21  fix a bug in loadjson, previous code does not use any of the acceleration
+ 2011/10/20  loadjson supports JSON collections - concatenated JSON objects
+
+== JSONlab 0.5.0 (codename: Nexus), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2011/10/16  package and release jsonlab 0.5.0
+ 2011/10/15 *add json demo and regression test, support cpx numbers, fix double quote bug
+ 2011/10/11 *speed up readjson dramatically, interpret _Array* tags, show data in root level
+ 2011/10/10  create jsonlab project, start jsonlab website, add online documentation
+ 2011/10/07 *speed up savejson by 25x using sprintf instead of mat2str, add options support
+ 2011/10/06 *savejson works for structs, cells and arrays
+ 2011/09/09  derive loadjson from JSON parser from MATLAB Central, draft savejson.m

+ 25 - 0
ex4/lib/jsonlab/LICENSE_BSD.txt

@@ -0,0 +1,25 @@
+Copyright 2011-2015 Qianqian Fang <fangq at nmr.mgh.harvard.edu>. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice, this list of
+      conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright notice, this list
+      of conditions and the following disclaimer in the documentation and/or other materials
+      provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those of the
+authors and should not be interpreted as representing official policies, either expressed
+or implied, of the copyright holders.

+ 394 - 0
ex4/lib/jsonlab/README.txt

@@ -0,0 +1,394 @@
+===============================================================================
+=                                 JSONLab                                     =
+=           An open-source MATLAB/Octave JSON encoder and decoder             =
+===============================================================================
+
+*Copyright (C) 2011-2015  Qianqian Fang <fangq at nmr.mgh.harvard.edu>
+*License: BSD License, see License_BSD.txt for details
+*Version: 1.0 (Optimus - Final)
+
+-------------------------------------------------------------------------------
+
+Table of Content:
+
+I.  Introduction
+II. Installation
+III.Using JSONLab
+IV. Known Issues and TODOs
+V.  Contribution and feedback
+
+-------------------------------------------------------------------------------
+
+I.  Introduction
+
+JSON ([http://www.json.org/ JavaScript Object Notation]) is a highly portable, 
+human-readable and "[http://en.wikipedia.org/wiki/JSON fat-free]" text format 
+to represent complex and hierarchical data. It is as powerful as 
+[http://en.wikipedia.org/wiki/XML XML], but less verbose. JSON format is widely 
+used for data-exchange in applications, and is essential for the wild success 
+of [http://en.wikipedia.org/wiki/Ajax_(programming) Ajax] and 
+[http://en.wikipedia.org/wiki/Web_2.0 Web2.0]. 
+
+UBJSON (Universal Binary JSON) is a binary JSON format, specifically 
+optimized for compact file size and better performance while keeping
+the semantics as simple as the text-based JSON format. Using the UBJSON
+format allows to wrap complex binary data in a flexible and extensible
+structure, making it possible to process complex and large dataset 
+without accuracy loss due to text conversions.
+
+We envision that both JSON and its binary version will serve as part of 
+the mainstream data-exchange formats for scientific research in the future. 
+It will provide the flexibility and generality achieved by other popular 
+general-purpose file specifications, such as
+[http://www.hdfgroup.org/HDF5/whatishdf5.html HDF5], with significantly 
+reduced complexity and enhanced performance.
+
+JSONLab is a free and open-source implementation of a JSON/UBJSON encoder 
+and a decoder in the native MATLAB language. It can be used to convert a MATLAB 
+data structure (array, struct, cell, struct array and cell array) into 
+JSON/UBJSON formatted strings, or to decode a JSON/UBJSON file into MATLAB 
+data structure. JSONLab supports both MATLAB and  
+[http://www.gnu.org/software/octave/ GNU Octave] (a free MATLAB clone).
+
+-------------------------------------------------------------------------------
+
+II. Installation
+
+The installation of JSONLab is no different than any other simple
+MATLAB toolbox. You only need to download/unzip the JSONLab package
+to a folder, and add the folder's path to MATLAB/Octave's path list
+by using the following command:
+
+    addpath('/path/to/jsonlab');
+
+If you want to add this path permanently, you need to type "pathtool", 
+browse to the jsonlab root folder and add to the list, then click "Save".
+Then, run "rehash" in MATLAB, and type "which loadjson", if you see an 
+output, that means JSONLab is installed for MATLAB/Octave.
+
+-------------------------------------------------------------------------------
+
+III.Using JSONLab
+
+JSONLab provides two functions, loadjson.m -- a MATLAB->JSON decoder, 
+and savejson.m -- a MATLAB->JSON encoder, for the text-based JSON, and 
+two equivallent functions -- loadubjson and saveubjson for the binary 
+JSON. The detailed help info for the four functions can be found below:
+
+=== loadjson.m ===
+<pre>
+  data=loadjson(fname,opt)
+     or
+  data=loadjson(fname,'param1',value1,'param2',value2,...)
+ 
+  parse a JSON (JavaScript Object Notation) file or string
+ 
+  authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2011/09/09, including previous works from 
+ 
+          Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
+             created on 2009/11/02
+          François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
+             created on  2009/03/22
+          Joel Feenstra:
+          http://www.mathworks.com/matlabcentral/fileexchange/20565
+             created on 2008/07/03
+ 
+  $Id: loadjson.m 452 2014-11-22 16:43:33Z fangq $
+ 
+  input:
+       fname: input file name, if fname contains "{}" or "[]", fname
+              will be interpreted as a JSON string
+       opt: a struct to store parsing options, opt can be replaced by 
+            a list of ('param',value) pairs - the param string is equivallent
+            to a field in opt. opt can have the following 
+            fields (first in [.|.] is the default)
+ 
+            opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat
+                          for each element of the JSON data, and group 
+                          arrays based on the cell2mat rules.
+            opt.FastArrayParser [1|0 or integer]: if set to 1, use a
+                          speed-optimized array parser when loading an 
+                          array object. The fast array parser may 
+                          collapse block arrays into a single large
+                          array similar to rules defined in cell2mat; 0 to 
+                          use a legacy parser; if set to a larger-than-1
+                          value, this option will specify the minimum
+                          dimension to enable the fast array parser. For
+                          example, if the input is a 3D array, setting
+                          FastArrayParser to 1 will return a 3D array;
+                          setting to 2 will return a cell array of 2D
+                          arrays; setting to 3 will return to a 2D cell
+                          array of 1D vectors; setting to 4 will return a
+                          3D cell array.
+            opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar.
+ 
+  output:
+       dat: a cell array, where {...} blocks are converted into cell arrays,
+            and [...] are converted to arrays
+ 
+  examples:
+       dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}')
+       dat=loadjson(['examples' filesep 'example1.json'])
+       dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1)
+</pre>
+
+=== savejson.m ===
+
+<pre>
+  json=savejson(rootname,obj,filename)
+     or
+  json=savejson(rootname,obj,opt)
+  json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
+ 
+  convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
+  Object Notation) string
+ 
+  author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2011/09/09
+ 
+  $Id: savejson.m 458 2014-12-19 22:17:17Z fangq $
+ 
+  input:
+       rootname: the name of the root-object, when set to '', the root name
+         is ignored, however, when opt.ForceRootName is set to 1 (see below),
+         the MATLAB variable name will be used as the root name.
+       obj: a MATLAB object (array, cell, cell array, struct, struct array).
+       filename: a string for the file name to save the output JSON data.
+       opt: a struct for additional options, ignore to use default values.
+         opt can have the following fields (first in [.|.] is the default)
+ 
+         opt.FileName [''|string]: a file name to save the output JSON data
+         opt.FloatFormat ['%.10g'|string]: format to show each numeric element
+                          of a 1D/2D array;
+         opt.ArrayIndent [1|0]: if 1, output explicit data array with
+                          precedent indentation; if 0, no indentation
+         opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
+                          array in JSON array format; if sets to 1, an
+                          array will be shown as a struct with fields
+                          "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+                          sparse arrays, the non-zero elements will be
+                          saved to _ArrayData_ field in triplet-format i.e.
+                          (ix,iy,val) and "_ArrayIsSparse_" will be added
+                          with a value of 1; for a complex array, the 
+                          _ArrayData_ array will include two columns 
+                          (4 for sparse) to record the real and imaginary 
+                          parts, and also "_ArrayIsComplex_":1 is added. 
+         opt.ParseLogical [0|1]: if this is set to 1, logical array elem
+                          will use true/false rather than 1/0.
+         opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+                          numerical element will be shown without a square
+                          bracket, unless it is the root object; if 0, square
+                          brackets are forced for any numerical arrays.
+         opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
+                          will use the name of the passed obj variable as the 
+                          root object name; if obj is an expression and 
+                          does not have a name, 'root' will be used; if this 
+                          is set to 0 and rootname is empty, the root level 
+                          will be merged down to the lower level.
+         opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
+                          to represent +/-Inf. The matched pattern is '([-+]*)Inf'
+                          and $1 represents the sign. For those who want to use
+                          1e999 to represent Inf, they can set opt.Inf to '$11e999'
+         opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
+                          to represent NaN
+         opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+                          for example, if opt.JSONP='foo', the JSON data is
+                          wrapped inside a function call as 'foo(...);'
+         opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+                          back to the string form
+         opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
+         opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs)
+ 
+         opt can be replaced by a list of ('param',value) pairs. The param 
+         string is equivallent to a field in opt and is case sensitive.
+  output:
+       json: a string in the JSON format (see http://json.org)
+ 
+  examples:
+       jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+                'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+                'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+                           2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+                'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+                'SpecialData',[nan, inf, -inf]);
+       savejson('jmesh',jsonmesh)
+       savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g')
+ </pre>
+
+=== loadubjson.m ===
+
+<pre>
+  data=loadubjson(fname,opt)
+     or
+  data=loadubjson(fname,'param1',value1,'param2',value2,...)
+ 
+  parse a JSON (JavaScript Object Notation) file or string
+ 
+  authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2013/08/01
+ 
+  $Id: loadubjson.m 436 2014-08-05 20:51:40Z fangq $
+ 
+  input:
+       fname: input file name, if fname contains "{}" or "[]", fname
+              will be interpreted as a UBJSON string
+       opt: a struct to store parsing options, opt can be replaced by 
+            a list of ('param',value) pairs - the param string is equivallent
+            to a field in opt. opt can have the following 
+            fields (first in [.|.] is the default)
+ 
+            opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
+                          for each element of the JSON data, and group 
+                          arrays based on the cell2mat rules.
+            opt.IntEndian [B|L]: specify the endianness of the integer fields
+                          in the UBJSON input data. B - Big-Endian format for 
+                          integers (as required in the UBJSON specification); 
+                          L - input integer fields are in Little-Endian order.
+ 
+  output:
+       dat: a cell array, where {...} blocks are converted into cell arrays,
+            and [...] are converted to arrays
+ 
+  examples:
+       obj=struct('string','value','array',[1 2 3]);
+       ubjdata=saveubjson('obj',obj);
+       dat=loadubjson(ubjdata)
+       dat=loadubjson(['examples' filesep 'example1.ubj'])
+       dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)
+</pre>
+
+=== saveubjson.m ===
+
+<pre>
+  json=saveubjson(rootname,obj,filename)
+     or
+  json=saveubjson(rootname,obj,opt)
+  json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
+ 
+  convert a MATLAB object (cell, struct or array) into a Universal 
+  Binary JSON (UBJSON) binary string
+ 
+  author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+  created on 2013/08/17
+ 
+  $Id: saveubjson.m 440 2014-09-17 19:59:45Z fangq $
+ 
+  input:
+       rootname: the name of the root-object, when set to '', the root name
+         is ignored, however, when opt.ForceRootName is set to 1 (see below),
+         the MATLAB variable name will be used as the root name.
+       obj: a MATLAB object (array, cell, cell array, struct, struct array)
+       filename: a string for the file name to save the output UBJSON data
+       opt: a struct for additional options, ignore to use default values.
+         opt can have the following fields (first in [.|.] is the default)
+ 
+         opt.FileName [''|string]: a file name to save the output JSON data
+         opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
+                          array in JSON array format; if sets to 1, an
+                          array will be shown as a struct with fields
+                          "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+                          sparse arrays, the non-zero elements will be
+                          saved to _ArrayData_ field in triplet-format i.e.
+                          (ix,iy,val) and "_ArrayIsSparse_" will be added
+                          with a value of 1; for a complex array, the 
+                          _ArrayData_ array will include two columns 
+                          (4 for sparse) to record the real and imaginary 
+                          parts, and also "_ArrayIsComplex_":1 is added. 
+         opt.ParseLogical [1|0]: if this is set to 1, logical array elem
+                          will use true/false rather than 1/0.
+         opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+                          numerical element will be shown without a square
+                          bracket, unless it is the root object; if 0, square
+                          brackets are forced for any numerical arrays.
+         opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
+                          will use the name of the passed obj variable as the 
+                          root object name; if obj is an expression and 
+                          does not have a name, 'root' will be used; if this 
+                          is set to 0 and rootname is empty, the root level 
+                          will be merged down to the lower level.
+         opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+                          for example, if opt.JSON='foo', the JSON data is
+                          wrapped inside a function call as 'foo(...);'
+         opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+                          back to the string form
+ 
+         opt can be replaced by a list of ('param',value) pairs. The param 
+         string is equivallent to a field in opt and is case sensitive.
+  output:
+       json: a binary string in the UBJSON format (see http://ubjson.org)
+ 
+  examples:
+       jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+                'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+                'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+                           2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+                'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+                'SpecialData',[nan, inf, -inf]);
+       saveubjson('jsonmesh',jsonmesh)
+       saveubjson('jsonmesh',jsonmesh,'meshdata.ubj')
+</pre>
+
+
+=== examples ===
+
+Under the "examples" folder, you can find several scripts to demonstrate the
+basic utilities of JSONLab. Running the "demo_jsonlab_basic.m" script, you 
+will see the conversions from MATLAB data structure to JSON text and backward.
+In "jsonlab_selftest.m", we load complex JSON files downloaded from the Internet
+and validate the loadjson/savejson functions for regression testing purposes.
+Similarly, a "demo_ubjson_basic.m" script is provided to test the saveubjson
+and loadubjson pairs for various matlab data structures.
+
+Please run these examples and understand how JSONLab works before you use
+it to process your data.
+
+-------------------------------------------------------------------------------
+
+IV. Known Issues and TODOs
+
+JSONLab has several known limitations. We are striving to make it more general
+and robust. Hopefully in a few future releases, the limitations become less.
+
+Here are the known issues:
+
+# 3D or higher dimensional cell/struct-arrays will be converted to 2D arrays;
+# When processing names containing multi-byte characters, Octave and MATLAB \
+can give different field-names; you can use feature('DefaultCharacterSet','latin1') \
+in MATLAB to get consistant results
+# savejson can not handle class and dataset.
+# saveubjson converts a logical array into a uint8 ([U]) array
+# an unofficial N-D array count syntax is implemented in saveubjson. We are \
+actively communicating with the UBJSON spec maintainer to investigate the \
+possibility of making it upstream
+# loadubjson can not parse all UBJSON Specification (Draft 9) compliant \
+files, however, it can parse all UBJSON files produced by saveubjson.
+
+-------------------------------------------------------------------------------
+
+V. Contribution and feedback
+
+JSONLab is an open-source project. This means you can not only use it and modify
+it as you wish, but also you can contribute your changes back to JSONLab so
+that everyone else can enjoy the improvement. For anyone who want to contribute,
+please download JSONLab source code from it's subversion repository by using the
+following command:
+
+ svn checkout svn://svn.code.sf.net/p/iso2mesh/code/trunk/jsonlab jsonlab
+
+You can make changes to the files as needed. Once you are satisfied with your
+changes, and ready to share it with others, please cd the root directory of 
+JSONLab, and type
+
+ svn diff > yourname_featurename.patch
+
+You then email the .patch file to JSONLab's maintainer, Qianqian Fang, at
+the email address shown in the beginning of this file. Qianqian will review 
+the changes and commit it to the subversion if they are satisfactory.
+
+We appreciate any suggestions and feedbacks from you. Please use iso2mesh's
+mailing list to report any questions you may have with JSONLab:
+
+http://groups.google.com/group/iso2mesh-users?hl=en&pli=1
+
+(Subscription to the mailing list is needed in order to post messages).

+ 32 - 0
ex4/lib/jsonlab/jsonopt.m

@@ -0,0 +1,32 @@
+function val=jsonopt(key,default,varargin)
+%
+% val=jsonopt(key,default,optstruct)
+%
+% setting options based on a struct. The struct can be produced
+% by varargin2struct from a list of 'param','value' pairs
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+%
+% $Id: loadjson.m 371 2012-06-20 12:43:06Z fangq $
+%
+% input:
+%      key: a string with which one look up a value from a struct
+%      default: if the key does not exist, return default
+%      optstruct: a struct where each sub-field is a key 
+%
+% output:
+%      val: if key exists, val=optstruct.key; otherwise val=default
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details
+%
+% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+% 
+
+val=default;
+if(nargin<=2) return; end
+opt=varargin{1};
+if(isstruct(opt) && isfield(opt,key))
+    val=getfield(opt,key);
+end
+

+ 566 - 0
ex4/lib/jsonlab/loadjson.m

@@ -0,0 +1,566 @@
+function data = loadjson(fname,varargin)
+%
+% data=loadjson(fname,opt)
+%    or
+% data=loadjson(fname,'param1',value1,'param2',value2,...)
+%
+% parse a JSON (JavaScript Object Notation) file or string
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2011/09/09, including previous works from 
+%
+%         Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
+%            created on 2009/11/02
+%         François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
+%            created on  2009/03/22
+%         Joel Feenstra:
+%         http://www.mathworks.com/matlabcentral/fileexchange/20565
+%            created on 2008/07/03
+%
+% $Id: loadjson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      fname: input file name, if fname contains "{}" or "[]", fname
+%             will be interpreted as a JSON string
+%      opt: a struct to store parsing options, opt can be replaced by 
+%           a list of ('param',value) pairs - the param string is equivallent
+%           to a field in opt. opt can have the following 
+%           fields (first in [.|.] is the default)
+%
+%           opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat
+%                         for each element of the JSON data, and group 
+%                         arrays based on the cell2mat rules.
+%           opt.FastArrayParser [1|0 or integer]: if set to 1, use a
+%                         speed-optimized array parser when loading an 
+%                         array object. The fast array parser may 
+%                         collapse block arrays into a single large
+%                         array similar to rules defined in cell2mat; 0 to 
+%                         use a legacy parser; if set to a larger-than-1
+%                         value, this option will specify the minimum
+%                         dimension to enable the fast array parser. For
+%                         example, if the input is a 3D array, setting
+%                         FastArrayParser to 1 will return a 3D array;
+%                         setting to 2 will return a cell array of 2D
+%                         arrays; setting to 3 will return to a 2D cell
+%                         array of 1D vectors; setting to 4 will return a
+%                         3D cell array.
+%           opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar.
+%
+% output:
+%      dat: a cell array, where {...} blocks are converted into cell arrays,
+%           and [...] are converted to arrays
+%
+% examples:
+%      dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}')
+%      dat=loadjson(['examples' filesep 'example1.json'])
+%      dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1)
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details 
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+global pos inStr len  esc index_esc len_esc isoct arraytoken
+
+if(regexp(fname,'[\{\}\]\[]','once'))
+   string=fname;
+elseif(exist(fname,'file'))
+   fid = fopen(fname,'rb');
+   string = fread(fid,inf,'uint8=>char')';
+   fclose(fid);
+else
+   error('input file does not exist');
+end
+
+pos = 1; len = length(string); inStr = string;
+isoct=exist('OCTAVE_VERSION','builtin');
+arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
+jstr=regexprep(inStr,'\\\\','  ');
+escquote=regexp(jstr,'\\"');
+arraytoken=sort([arraytoken escquote]);
+
+% String delimiters and escape chars identified to improve speed:
+esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
+index_esc = 1; len_esc = length(esc);
+
+opt=varargin2struct(varargin{:});
+
+if(jsonopt('ShowProgress',0,opt)==1)
+    opt.progressbar_=waitbar(0,'loading ...');
+end
+jsoncount=1;
+while pos <= len
+    switch(next_char)
+        case '{'
+            data{jsoncount} = parse_object(opt);
+        case '['
+            data{jsoncount} = parse_array(opt);
+        otherwise
+            error_pos('Outer level structure must be an object or an array');
+    end
+    jsoncount=jsoncount+1;
+end % while
+
+jsoncount=length(data);
+if(jsoncount==1 && iscell(data))
+    data=data{1};
+end
+
+if(~isempty(data))
+      if(isstruct(data)) % data can be a struct array
+          data=jstruct2array(data);
+      elseif(iscell(data))
+          data=jcell2array(data);
+      end
+end
+if(isfield(opt,'progressbar_'))
+    close(opt.progressbar_);
+end
+
+%%
+function newdata=jcell2array(data)
+len=length(data);
+newdata=data;
+for i=1:len
+      if(isstruct(data{i}))
+          newdata{i}=jstruct2array(data{i});
+      elseif(iscell(data{i}))
+          newdata{i}=jcell2array(data{i});
+      end
+end
+
+%%-------------------------------------------------------------------------
+function newdata=jstruct2array(data)
+fn=fieldnames(data);
+newdata=data;
+len=length(data);
+for i=1:length(fn) % depth-first
+    for j=1:len
+        if(isstruct(getfield(data(j),fn{i})))
+            newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
+        end
+    end
+end
+if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
+  newdata=cell(len,1);
+  for j=1:len
+    ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
+    iscpx=0;
+    if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
+        if(data(j).x0x5F_ArrayIsComplex_)
+           iscpx=1;
+        end
+    end
+    if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
+        if(data(j).x0x5F_ArrayIsSparse_)
+            if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+                dim=data(j).x0x5F_ArraySize_;
+                if(iscpx && size(ndata,2)==4-any(dim==1))
+                    ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
+                end
+                if isempty(ndata)
+                    % All-zeros sparse
+                    ndata=sparse(dim(1),prod(dim(2:end)));
+                elseif dim(1)==1
+                    % Sparse row vector
+                    ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
+                elseif dim(2)==1
+                    % Sparse column vector
+                    ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
+                else
+                    % Generic sparse array.
+                    ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
+                end
+            else
+                if(iscpx && size(ndata,2)==4)
+                    ndata(:,3)=complex(ndata(:,3),ndata(:,4));
+                end
+                ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
+            end
+        end
+    elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+        if(iscpx && size(ndata,2)==2)
+             ndata=complex(ndata(:,1),ndata(:,2));
+        end
+        ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
+    end
+    newdata{j}=ndata;
+  end
+  if(len==1)
+      newdata=newdata{1};
+  end
+end
+
+%%-------------------------------------------------------------------------
+function object = parse_object(varargin)
+    parse_char('{');
+    object = [];
+    if next_char ~= '}'
+        while 1
+            str = parseStr(varargin{:});
+            if isempty(str)
+                error_pos('Name of value at position %d cannot be empty');
+            end
+            parse_char(':');
+            val = parse_value(varargin{:});
+            eval( sprintf( 'object.%s  = val;', valid_field(str) ) );
+            if next_char == '}'
+                break;
+            end
+            parse_char(',');
+        end
+    end
+    parse_char('}');
+
+%%-------------------------------------------------------------------------
+
+function object = parse_array(varargin) % JSON array is written in row-major order
+global pos inStr isoct
+    parse_char('[');
+    object = cell(0, 1);
+    dim2=[];
+    arraydepth=jsonopt('JSONLAB_ArrayDepth_',1,varargin{:});
+    pbar=jsonopt('progressbar_',-1,varargin{:});
+
+    if next_char ~= ']'
+	if(jsonopt('FastArrayParser',1,varargin{:})>=1 && arraydepth>=jsonopt('FastArrayParser',1,varargin{:}))
+            [endpos, e1l, e1r, maxlevel]=matching_bracket(inStr,pos);
+            arraystr=['[' inStr(pos:endpos)];
+            arraystr=regexprep(arraystr,'"_NaN_"','NaN');
+            arraystr=regexprep(arraystr,'"([-+]*)_Inf_"','$1Inf');
+            arraystr(arraystr==sprintf('\n'))=[];
+            arraystr(arraystr==sprintf('\r'))=[];
+            %arraystr=regexprep(arraystr,'\s*,',','); % this is slow,sometimes needed
+            if(~isempty(e1l) && ~isempty(e1r)) % the array is in 2D or higher D
+        	astr=inStr((e1l+1):(e1r-1));
+        	astr=regexprep(astr,'"_NaN_"','NaN');
+        	astr=regexprep(astr,'"([-+]*)_Inf_"','$1Inf');
+        	astr(astr==sprintf('\n'))=[];
+        	astr(astr==sprintf('\r'))=[];
+        	astr(astr==' ')='';
+        	if(isempty(find(astr=='[', 1))) % array is 2D
+                    dim2=length(sscanf(astr,'%f,',[1 inf]));
+        	end
+            else % array is 1D
+        	astr=arraystr(2:end-1);
+        	astr(astr==' ')='';
+        	[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',[1,inf]);
+        	if(nextidx>=length(astr)-1)
+                    object=obj;
+                    pos=endpos;
+                    parse_char(']');
+                    return;
+        	end
+            end
+            if(~isempty(dim2))
+        	astr=arraystr;
+        	astr(astr=='[')='';
+        	astr(astr==']')='';
+        	astr(astr==' ')='';
+        	[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',inf);
+        	if(nextidx>=length(astr)-1)
+                    object=reshape(obj,dim2,numel(obj)/dim2)';
+                    pos=endpos;
+                    parse_char(']');
+                    if(pbar>0)
+                        waitbar(pos/length(inStr),pbar,'loading ...');
+                    end
+                    return;
+        	end
+            end
+            arraystr=regexprep(arraystr,'\]\s*,','];');
+	else
+            arraystr='[';
+	end
+        try
+           if(isoct && regexp(arraystr,'"','once'))
+                error('Octave eval can produce empty cells for JSON-like input');
+           end
+           object=eval(arraystr);
+           pos=endpos;
+        catch
+         while 1
+            newopt=varargin2struct(varargin{:},'JSONLAB_ArrayDepth_',arraydepth+1);
+            val = parse_value(newopt);
+            object{end+1} = val;
+            if next_char == ']'
+                break;
+            end
+            parse_char(',');
+         end
+        end
+    end
+    if(jsonopt('SimplifyCell',0,varargin{:})==1)
+      try
+        oldobj=object;
+        object=cell2mat(object')';
+        if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
+            object=oldobj;
+        elseif(size(object,1)>1 && ndims(object)==2)
+            object=object';
+        end
+      catch
+      end
+    end
+    parse_char(']');
+    
+    if(pbar>0)
+        waitbar(pos/length(inStr),pbar,'loading ...');
+    end
+%%-------------------------------------------------------------------------
+
+function parse_char(c)
+    global pos inStr len
+    skip_whitespace;
+    if pos > len || inStr(pos) ~= c
+        error_pos(sprintf('Expected %c at position %%d', c));
+    else
+        pos = pos + 1;
+        skip_whitespace;
+    end
+
+%%-------------------------------------------------------------------------
+
+function c = next_char
+    global pos inStr len
+    skip_whitespace;
+    if pos > len
+        c = [];
+    else
+        c = inStr(pos);
+    end
+
+%%-------------------------------------------------------------------------
+
+function skip_whitespace
+    global pos inStr len
+    while pos <= len && isspace(inStr(pos))
+        pos = pos + 1;
+    end
+
+%%-------------------------------------------------------------------------
+function str = parseStr(varargin)
+    global pos inStr len  esc index_esc len_esc
+ % len, ns = length(inStr), keyboard
+    if inStr(pos) ~= '"'
+        error_pos('String starting with " expected at position %d');
+    else
+        pos = pos + 1;
+    end
+    str = '';
+    while pos <= len
+        while index_esc <= len_esc && esc(index_esc) < pos
+            index_esc = index_esc + 1;
+        end
+        if index_esc > len_esc
+            str = [str inStr(pos:len)];
+            pos = len + 1;
+            break;
+        else
+            str = [str inStr(pos:esc(index_esc)-1)];
+            pos = esc(index_esc);
+        end
+        nstr = length(str); switch inStr(pos)
+            case '"'
+                pos = pos + 1;
+                if(~isempty(str))
+                    if(strcmp(str,'_Inf_'))
+                        str=Inf;
+                    elseif(strcmp(str,'-_Inf_'))
+                        str=-Inf;
+                    elseif(strcmp(str,'_NaN_'))
+                        str=NaN;
+                    end
+                end
+                return;
+            case '\'
+                if pos+1 > len
+                    error_pos('End of file reached right after escape character');
+                end
+                pos = pos + 1;
+                switch inStr(pos)
+                    case {'"' '\' '/'}
+                        str(nstr+1) = inStr(pos);
+                        pos = pos + 1;
+                    case {'b' 'f' 'n' 'r' 't'}
+                        str(nstr+1) = sprintf(['\' inStr(pos)]);
+                        pos = pos + 1;
+                    case 'u'
+                        if pos+4 > len
+                            error_pos('End of file reached in escaped unicode character');
+                        end
+                        str(nstr+(1:6)) = inStr(pos-1:pos+4);
+                        pos = pos + 5;
+                end
+            otherwise % should never happen
+                str(nstr+1) = inStr(pos), keyboard
+                pos = pos + 1;
+        end
+    end
+    error_pos('End of file while expecting end of inStr');
+
+%%-------------------------------------------------------------------------
+
+function num = parse_number(varargin)
+    global pos inStr len isoct
+    currstr=inStr(pos:end);
+    numstr=0;
+    if(isoct~=0)
+        numstr=regexp(currstr,'^\s*-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?','end');
+        [num, one] = sscanf(currstr, '%f', 1);
+        delta=numstr+1;
+    else
+        [num, one, err, delta] = sscanf(currstr, '%f', 1);
+        if ~isempty(err)
+            error_pos('Error reading number at position %d');
+        end
+    end
+    pos = pos + delta-1;
+
+%%-------------------------------------------------------------------------
+
+function val = parse_value(varargin)
+    global pos inStr len
+    true = 1; false = 0;
+    
+    pbar=jsonopt('progressbar_',-1,varargin{:});
+    if(pbar>0)
+        waitbar(pos/len,pbar,'loading ...');
+    end
+    
+    switch(inStr(pos))
+        case '"'
+            val = parseStr(varargin{:});
+            return;
+        case '['
+            val = parse_array(varargin{:});
+            return;
+        case '{'
+            val = parse_object(varargin{:});
+            if isstruct(val)
+                if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
+                    val=jstruct2array(val);
+                end
+            elseif isempty(val)
+                val = struct;
+            end
+            return;
+        case {'-','0','1','2','3','4','5','6','7','8','9'}
+            val = parse_number(varargin{:});
+            return;
+        case 't'
+            if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'true')
+                val = true;
+                pos = pos + 4;
+                return;
+            end
+        case 'f'
+            if pos+4 <= len && strcmpi(inStr(pos:pos+4), 'false')
+                val = false;
+                pos = pos + 5;
+                return;
+            end
+        case 'n'
+            if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'null')
+                val = [];
+                pos = pos + 4;
+                return;
+            end
+    end
+    error_pos('Value expected at position %d');
+%%-------------------------------------------------------------------------
+
+function error_pos(msg)
+    global pos inStr len
+    poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
+    if poShow(3) == poShow(2)
+        poShow(3:4) = poShow(2)+[0 -1];  % display nothing after
+    end
+    msg = [sprintf(msg, pos) ': ' ...
+    inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
+    error( ['JSONparser:invalidFormat: ' msg] );
+
+%%-------------------------------------------------------------------------
+
+function str = valid_field(str)
+global isoct
+% From MATLAB doc: field names must begin with a letter, which may be
+% followed by any combination of letters, digits, and underscores.
+% Invalid characters will be converted to underscores, and the prefix
+% "x0x[Hex code]_" will be added if the first character is not a letter.
+    pos=regexp(str,'^[^A-Za-z]','once');
+    if(~isempty(pos))
+        if(~isoct)
+            str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
+        else
+            str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
+        end
+    end
+    if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return;  end
+    if(~isoct)
+        str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
+    else
+        pos=regexp(str,'[^0-9A-Za-z_]');
+        if(isempty(pos)) return; end
+        str0=str;
+        pos0=[0 pos(:)' length(str)];
+        str='';
+        for i=1:length(pos)
+            str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
+        end
+        if(pos(end)~=length(str))
+            str=[str str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+    %str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
+
+%%-------------------------------------------------------------------------
+function endpos = matching_quote(str,pos)
+len=length(str);
+while(pos<len)
+    if(str(pos)=='"')
+        if(~(pos>1 && str(pos-1)=='\'))
+            endpos=pos;
+            return;
+        end        
+    end
+    pos=pos+1;
+end
+error('unmatched quotation mark');
+%%-------------------------------------------------------------------------
+function [endpos, e1l, e1r, maxlevel] = matching_bracket(str,pos)
+global arraytoken
+level=1;
+maxlevel=level;
+endpos=0;
+bpos=arraytoken(arraytoken>=pos);
+tokens=str(bpos);
+len=length(tokens);
+pos=1;
+e1l=[];
+e1r=[];
+while(pos<=len)
+    c=tokens(pos);
+    if(c==']')
+        level=level-1;
+        if(isempty(e1r)) e1r=bpos(pos); end
+        if(level==0)
+            endpos=bpos(pos);
+            return
+        end
+    end
+    if(c=='[')
+        if(isempty(e1l)) e1l=bpos(pos); end
+        level=level+1;
+        maxlevel=max(maxlevel,level);
+    end
+    if(c=='"')
+        pos=matching_quote(tokens,pos+1);
+    end
+    pos=pos+1;
+end
+if(endpos==0) 
+    error('unmatched "]"');
+end
+

+ 528 - 0
ex4/lib/jsonlab/loadubjson.m

@@ -0,0 +1,528 @@
+function data = loadubjson(fname,varargin)
+%
+% data=loadubjson(fname,opt)
+%    or
+% data=loadubjson(fname,'param1',value1,'param2',value2,...)
+%
+% parse a JSON (JavaScript Object Notation) file or string
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2013/08/01
+%
+% $Id: loadubjson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      fname: input file name, if fname contains "{}" or "[]", fname
+%             will be interpreted as a UBJSON string
+%      opt: a struct to store parsing options, opt can be replaced by 
+%           a list of ('param',value) pairs - the param string is equivallent
+%           to a field in opt. opt can have the following 
+%           fields (first in [.|.] is the default)
+%
+%           opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
+%                         for each element of the JSON data, and group 
+%                         arrays based on the cell2mat rules.
+%           opt.IntEndian [B|L]: specify the endianness of the integer fields
+%                         in the UBJSON input data. B - Big-Endian format for 
+%                         integers (as required in the UBJSON specification); 
+%                         L - input integer fields are in Little-Endian order.
+%
+% output:
+%      dat: a cell array, where {...} blocks are converted into cell arrays,
+%           and [...] are converted to arrays
+%
+% examples:
+%      obj=struct('string','value','array',[1 2 3]);
+%      ubjdata=saveubjson('obj',obj);
+%      dat=loadubjson(ubjdata)
+%      dat=loadubjson(['examples' filesep 'example1.ubj'])
+%      dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details 
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+global pos inStr len  esc index_esc len_esc isoct arraytoken fileendian systemendian
+
+if(regexp(fname,'[\{\}\]\[]','once'))
+   string=fname;
+elseif(exist(fname,'file'))
+   fid = fopen(fname,'rb');
+   string = fread(fid,inf,'uint8=>char')';
+   fclose(fid);
+else
+   error('input file does not exist');
+end
+
+pos = 1; len = length(string); inStr = string;
+isoct=exist('OCTAVE_VERSION','builtin');
+arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
+jstr=regexprep(inStr,'\\\\','  ');
+escquote=regexp(jstr,'\\"');
+arraytoken=sort([arraytoken escquote]);
+
+% String delimiters and escape chars identified to improve speed:
+esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
+index_esc = 1; len_esc = length(esc);
+
+opt=varargin2struct(varargin{:});
+fileendian=upper(jsonopt('IntEndian','B',opt));
+[os,maxelem,systemendian]=computer;
+
+jsoncount=1;
+while pos <= len
+    switch(next_char)
+        case '{'
+            data{jsoncount} = parse_object(opt);
+        case '['
+            data{jsoncount} = parse_array(opt);
+        otherwise
+            error_pos('Outer level structure must be an object or an array');
+    end
+    jsoncount=jsoncount+1;
+end % while
+
+jsoncount=length(data);
+if(jsoncount==1 && iscell(data))
+    data=data{1};
+end
+
+if(~isempty(data))
+      if(isstruct(data)) % data can be a struct array
+          data=jstruct2array(data);
+      elseif(iscell(data))
+          data=jcell2array(data);
+      end
+end
+
+
+%%
+function newdata=parse_collection(id,data,obj)
+
+if(jsoncount>0 && exist('data','var')) 
+    if(~iscell(data))
+       newdata=cell(1);
+       newdata{1}=data;
+       data=newdata;
+    end
+end
+
+%%
+function newdata=jcell2array(data)
+len=length(data);
+newdata=data;
+for i=1:len
+      if(isstruct(data{i}))
+          newdata{i}=jstruct2array(data{i});
+      elseif(iscell(data{i}))
+          newdata{i}=jcell2array(data{i});
+      end
+end
+
+%%-------------------------------------------------------------------------
+function newdata=jstruct2array(data)
+fn=fieldnames(data);
+newdata=data;
+len=length(data);
+for i=1:length(fn) % depth-first
+    for j=1:len
+        if(isstruct(getfield(data(j),fn{i})))
+            newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
+        end
+    end
+end
+if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
+  newdata=cell(len,1);
+  for j=1:len
+    ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
+    iscpx=0;
+    if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
+        if(data(j).x0x5F_ArrayIsComplex_)
+           iscpx=1;
+        end
+    end
+    if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
+        if(data(j).x0x5F_ArrayIsSparse_)
+            if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+                dim=double(data(j).x0x5F_ArraySize_);
+                if(iscpx && size(ndata,2)==4-any(dim==1))
+                    ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
+                end
+                if isempty(ndata)
+                    % All-zeros sparse
+                    ndata=sparse(dim(1),prod(dim(2:end)));
+                elseif dim(1)==1
+                    % Sparse row vector
+                    ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
+                elseif dim(2)==1
+                    % Sparse column vector
+                    ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
+                else
+                    % Generic sparse array.
+                    ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
+                end
+            else
+                if(iscpx && size(ndata,2)==4)
+                    ndata(:,3)=complex(ndata(:,3),ndata(:,4));
+                end
+                ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
+            end
+        end
+    elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
+        if(iscpx && size(ndata,2)==2)
+             ndata=complex(ndata(:,1),ndata(:,2));
+        end
+        ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
+    end
+    newdata{j}=ndata;
+  end
+  if(len==1)
+      newdata=newdata{1};
+  end
+end
+
+%%-------------------------------------------------------------------------
+function object = parse_object(varargin)
+    parse_char('{');
+    object = [];
+    type='';
+    count=-1;
+    if(next_char == '$')
+        type=inStr(pos+1); % TODO
+        pos=pos+2;
+    end
+    if(next_char == '#')
+        pos=pos+1;
+        count=double(parse_number());
+    end
+    if next_char ~= '}'
+        num=0;
+        while 1
+            str = parseStr(varargin{:});
+            if isempty(str)
+                error_pos('Name of value at position %d cannot be empty');
+            end
+            %parse_char(':');
+            val = parse_value(varargin{:});
+            num=num+1;
+            eval( sprintf( 'object.%s  = val;', valid_field(str) ) );
+            if next_char == '}' || (count>=0 && num>=count)
+                break;
+            end
+            %parse_char(',');
+        end
+    end
+    if(count==-1)
+        parse_char('}');
+    end
+
+%%-------------------------------------------------------------------------
+function [cid,len]=elem_info(type)
+id=strfind('iUIlLdD',type);
+dataclass={'int8','uint8','int16','int32','int64','single','double'};
+bytelen=[1,1,2,4,8,4,8];
+if(id>0)
+    cid=dataclass{id};
+    len=bytelen(id);
+else
+    error_pos('unsupported type at position %d');
+end
+%%-------------------------------------------------------------------------
+
+
+function [data adv]=parse_block(type,count,varargin)
+global pos inStr isoct fileendian systemendian
+[cid,len]=elem_info(type);
+datastr=inStr(pos:pos+len*count-1);
+if(isoct)
+    newdata=int8(datastr);
+else
+    newdata=uint8(datastr);
+end
+id=strfind('iUIlLdD',type);
+if(id<=5 && fileendian~=systemendian)
+    newdata=swapbytes(typecast(newdata,cid));
+end
+data=typecast(newdata,cid);
+adv=double(len*count);
+
+%%-------------------------------------------------------------------------
+
+
+function object = parse_array(varargin) % JSON array is written in row-major order
+global pos inStr isoct
+    parse_char('[');
+    object = cell(0, 1);
+    dim=[];
+    type='';
+    count=-1;
+    if(next_char == '$')
+        type=inStr(pos+1);
+        pos=pos+2;
+    end
+    if(next_char == '#')
+        pos=pos+1;
+        if(next_char=='[')
+            dim=parse_array(varargin{:});
+            count=prod(double(dim));
+        else
+            count=double(parse_number());
+        end
+    end
+    if(~isempty(type))
+        if(count>=0)
+            [object adv]=parse_block(type,count,varargin{:});
+            if(~isempty(dim))
+                object=reshape(object,dim);
+            end
+            pos=pos+adv;
+            return;
+        else
+            endpos=matching_bracket(inStr,pos);
+            [cid,len]=elem_info(type);
+            count=(endpos-pos)/len;
+            [object adv]=parse_block(type,count,varargin{:});
+            pos=pos+adv;
+            parse_char(']');
+            return;
+        end
+    end
+    if next_char ~= ']'
+         while 1
+            val = parse_value(varargin{:});
+            object{end+1} = val;
+            if next_char == ']'
+                break;
+            end
+            %parse_char(',');
+         end
+    end
+    if(jsonopt('SimplifyCell',0,varargin{:})==1)
+      try
+        oldobj=object;
+        object=cell2mat(object')';
+        if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
+            object=oldobj;
+        elseif(size(object,1)>1 && ndims(object)==2)
+            object=object';
+        end
+      catch
+      end
+    end
+    if(count==-1)
+        parse_char(']');
+    end
+
+%%-------------------------------------------------------------------------
+
+function parse_char(c)
+    global pos inStr len
+    skip_whitespace;
+    if pos > len || inStr(pos) ~= c
+        error_pos(sprintf('Expected %c at position %%d', c));
+    else
+        pos = pos + 1;
+        skip_whitespace;
+    end
+
+%%-------------------------------------------------------------------------
+
+function c = next_char
+    global pos inStr len
+    skip_whitespace;
+    if pos > len
+        c = [];
+    else
+        c = inStr(pos);
+    end
+
+%%-------------------------------------------------------------------------
+
+function skip_whitespace
+    global pos inStr len
+    while pos <= len && isspace(inStr(pos))
+        pos = pos + 1;
+    end
+
+%%-------------------------------------------------------------------------
+function str = parseStr(varargin)
+    global pos inStr esc index_esc len_esc
+ % len, ns = length(inStr), keyboard
+    type=inStr(pos);
+    if type ~= 'S' && type ~= 'C' && type ~= 'H'
+        error_pos('String starting with S expected at position %d');
+    else
+        pos = pos + 1;
+    end
+    if(type == 'C')
+        str=inStr(pos);
+        pos=pos+1;
+        return;
+    end
+    bytelen=double(parse_number());
+    if(length(inStr)>=pos+bytelen-1)
+        str=inStr(pos:pos+bytelen-1);
+        pos=pos+bytelen;
+    else
+        error_pos('End of file while expecting end of inStr');
+    end
+
+%%-------------------------------------------------------------------------
+
+function num = parse_number(varargin)
+    global pos inStr len isoct fileendian systemendian
+    id=strfind('iUIlLdD',inStr(pos));
+    if(isempty(id))
+        error_pos('expecting a number at position %d');
+    end
+    type={'int8','uint8','int16','int32','int64','single','double'};
+    bytelen=[1,1,2,4,8,4,8];
+    datastr=inStr(pos+1:pos+bytelen(id));
+    if(isoct)
+        newdata=int8(datastr);
+    else
+        newdata=uint8(datastr);
+    end
+    if(id<=5 && fileendian~=systemendian)
+        newdata=swapbytes(typecast(newdata,type{id}));
+    end
+    num=typecast(newdata,type{id});
+    pos = pos + bytelen(id)+1;
+
+%%-------------------------------------------------------------------------
+
+function val = parse_value(varargin)
+    global pos inStr len
+    true = 1; false = 0;
+
+    switch(inStr(pos))
+        case {'S','C','H'}
+            val = parseStr(varargin{:});
+            return;
+        case '['
+            val = parse_array(varargin{:});
+            return;
+        case '{'
+            val = parse_object(varargin{:});
+            if isstruct(val)
+                if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
+                    val=jstruct2array(val);
+                end
+            elseif isempty(val)
+                val = struct;
+            end
+            return;
+        case {'i','U','I','l','L','d','D'}
+            val = parse_number(varargin{:});
+            return;
+        case 'T'
+            val = true;
+            pos = pos + 1;
+            return;
+        case 'F'
+            val = false;
+            pos = pos + 1;
+            return;
+        case {'Z','N'}
+            val = [];
+            pos = pos + 1;
+            return;
+    end
+    error_pos('Value expected at position %d');
+%%-------------------------------------------------------------------------
+
+function error_pos(msg)
+    global pos inStr len
+    poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
+    if poShow(3) == poShow(2)
+        poShow(3:4) = poShow(2)+[0 -1];  % display nothing after
+    end
+    msg = [sprintf(msg, pos) ': ' ...
+    inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
+    error( ['JSONparser:invalidFormat: ' msg] );
+
+%%-------------------------------------------------------------------------
+
+function str = valid_field(str)
+global isoct
+% From MATLAB doc: field names must begin with a letter, which may be
+% followed by any combination of letters, digits, and underscores.
+% Invalid characters will be converted to underscores, and the prefix
+% "x0x[Hex code]_" will be added if the first character is not a letter.
+    pos=regexp(str,'^[^A-Za-z]','once');
+    if(~isempty(pos))
+        if(~isoct)
+            str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
+        else
+            str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
+        end
+    end
+    if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return;  end
+    if(~isoct)
+        str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
+    else
+        pos=regexp(str,'[^0-9A-Za-z_]');
+        if(isempty(pos)) return; end
+        str0=str;
+        pos0=[0 pos(:)' length(str)];
+        str='';
+        for i=1:length(pos)
+            str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
+        end
+        if(pos(end)~=length(str))
+            str=[str str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+    %str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
+
+%%-------------------------------------------------------------------------
+function endpos = matching_quote(str,pos)
+len=length(str);
+while(pos<len)
+    if(str(pos)=='"')
+        if(~(pos>1 && str(pos-1)=='\'))
+            endpos=pos;
+            return;
+        end        
+    end
+    pos=pos+1;
+end
+error('unmatched quotation mark');
+%%-------------------------------------------------------------------------
+function [endpos e1l e1r maxlevel] = matching_bracket(str,pos)
+global arraytoken
+level=1;
+maxlevel=level;
+endpos=0;
+bpos=arraytoken(arraytoken>=pos);
+tokens=str(bpos);
+len=length(tokens);
+pos=1;
+e1l=[];
+e1r=[];
+while(pos<=len)
+    c=tokens(pos);
+    if(c==']')
+        level=level-1;
+        if(isempty(e1r)) e1r=bpos(pos); end
+        if(level==0)
+            endpos=bpos(pos);
+            return
+        end
+    end
+    if(c=='[')
+        if(isempty(e1l)) e1l=bpos(pos); end
+        level=level+1;
+        maxlevel=max(maxlevel,level);
+    end
+    if(c=='"')
+        pos=matching_quote(tokens,pos+1);
+    end
+    pos=pos+1;
+end
+if(endpos==0) 
+    error('unmatched "]"');
+end
+

+ 33 - 0
ex4/lib/jsonlab/mergestruct.m

@@ -0,0 +1,33 @@
+function s=mergestruct(s1,s2)
+%
+% s=mergestruct(s1,s2)
+%
+% merge two struct objects into one
+%
+% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% date: 2012/12/22
+%
+% input:
+%      s1,s2: a struct object, s1 and s2 can not be arrays
+%
+% output:
+%      s: the merged struct object. fields in s1 and s2 will be combined in s.
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details 
+%
+% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+if(~isstruct(s1) || ~isstruct(s2))
+    error('input parameters contain non-struct');
+end
+if(length(s1)>1 || length(s2)>1)
+    error('can not merge struct arrays');
+end
+fn=fieldnames(s2);
+s=s1;
+for i=1:length(fn)              
+    s=setfield(s,fn{i},getfield(s2,fn{i}));
+end
+

+ 475 - 0
ex4/lib/jsonlab/savejson.m

@@ -0,0 +1,475 @@
+function json=savejson(rootname,obj,varargin)
+%
+% json=savejson(rootname,obj,filename)
+%    or
+% json=savejson(rootname,obj,opt)
+% json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
+%
+% convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
+% Object Notation) string
+%
+% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2011/09/09
+%
+% $Id: savejson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      rootname: the name of the root-object, when set to '', the root name
+%        is ignored, however, when opt.ForceRootName is set to 1 (see below),
+%        the MATLAB variable name will be used as the root name.
+%      obj: a MATLAB object (array, cell, cell array, struct, struct array).
+%      filename: a string for the file name to save the output JSON data.
+%      opt: a struct for additional options, ignore to use default values.
+%        opt can have the following fields (first in [.|.] is the default)
+%
+%        opt.FileName [''|string]: a file name to save the output JSON data
+%        opt.FloatFormat ['%.10g'|string]: format to show each numeric element
+%                         of a 1D/2D array;
+%        opt.ArrayIndent [1|0]: if 1, output explicit data array with
+%                         precedent indentation; if 0, no indentation
+%        opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
+%                         array in JSON array format; if sets to 1, an
+%                         array will be shown as a struct with fields
+%                         "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+%                         sparse arrays, the non-zero elements will be
+%                         saved to _ArrayData_ field in triplet-format i.e.
+%                         (ix,iy,val) and "_ArrayIsSparse_" will be added
+%                         with a value of 1; for a complex array, the 
+%                         _ArrayData_ array will include two columns 
+%                         (4 for sparse) to record the real and imaginary 
+%                         parts, and also "_ArrayIsComplex_":1 is added. 
+%        opt.ParseLogical [0|1]: if this is set to 1, logical array elem
+%                         will use true/false rather than 1/0.
+%        opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+%                         numerical element will be shown without a square
+%                         bracket, unless it is the root object; if 0, square
+%                         brackets are forced for any numerical arrays.
+%        opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
+%                         will use the name of the passed obj variable as the 
+%                         root object name; if obj is an expression and 
+%                         does not have a name, 'root' will be used; if this 
+%                         is set to 0 and rootname is empty, the root level 
+%                         will be merged down to the lower level.
+%        opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
+%                         to represent +/-Inf. The matched pattern is '([-+]*)Inf'
+%                         and $1 represents the sign. For those who want to use
+%                         1e999 to represent Inf, they can set opt.Inf to '$11e999'
+%        opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
+%                         to represent NaN
+%        opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+%                         for example, if opt.JSONP='foo', the JSON data is
+%                         wrapped inside a function call as 'foo(...);'
+%        opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+%                         back to the string form
+%        opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
+%        opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs)
+%
+%        opt can be replaced by a list of ('param',value) pairs. The param 
+%        string is equivallent to a field in opt and is case sensitive.
+% output:
+%      json: a string in the JSON format (see http://json.org)
+%
+% examples:
+%      jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+%               'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+%               'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+%                          2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+%               'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+%               'SpecialData',[nan, inf, -inf]);
+%      savejson('jmesh',jsonmesh)
+%      savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g')
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+if(nargin==1)
+   varname=inputname(1);
+   obj=rootname;
+   if(isempty(varname)) 
+      varname='root';
+   end
+   rootname=varname;
+else
+   varname=inputname(2);
+end
+if(length(varargin)==1 && ischar(varargin{1}))
+   opt=struct('FileName',varargin{1});
+else
+   opt=varargin2struct(varargin{:});
+end
+opt.IsOctave=exist('OCTAVE_VERSION','builtin');
+rootisarray=0;
+rootlevel=1;
+forceroot=jsonopt('ForceRootName',0,opt);
+if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)
+    rootisarray=1;
+    rootlevel=0;
+else
+    if(isempty(rootname))
+        rootname=varname;
+    end
+end
+if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
+    rootname='root';
+end
+
+whitespaces=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+if(jsonopt('Compact',0,opt)==1)
+    whitespaces=struct('tab','','newline','','sep',',');
+end
+if(~isfield(opt,'whitespaces_'))
+    opt.whitespaces_=whitespaces;
+end
+
+nl=whitespaces.newline;
+
+json=obj2json(rootname,obj,rootlevel,opt);
+if(rootisarray)
+    json=sprintf('%s%s',json,nl);
+else
+    json=sprintf('{%s%s%s}\n',nl,json,nl);
+end
+
+jsonp=jsonopt('JSONP','',opt);
+if(~isempty(jsonp))
+    json=sprintf('%s(%s);%s',jsonp,json,nl);
+end
+
+% save to a file if FileName is set, suggested by Patrick Rapin
+if(~isempty(jsonopt('FileName','',opt)))
+    if(jsonopt('SaveBinary',0,opt)==1)
+	    fid = fopen(opt.FileName, 'wb');
+	    fwrite(fid,json);
+    else
+	    fid = fopen(opt.FileName, 'wt');
+	    fwrite(fid,json,'char');
+    end
+    fclose(fid);
+end
+
+%%-------------------------------------------------------------------------
+function txt=obj2json(name,item,level,varargin)
+
+if(iscell(item))
+    txt=cell2json(name,item,level,varargin{:});
+elseif(isstruct(item))
+    txt=struct2json(name,item,level,varargin{:});
+elseif(ischar(item))
+    txt=str2json(name,item,level,varargin{:});
+else
+    txt=mat2json(name,item,level,varargin{:});
+end
+
+%%-------------------------------------------------------------------------
+function txt=cell2json(name,item,level,varargin)
+txt='';
+if(~iscell(item))
+        error('input is not a cell');
+end
+
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item);
+ws=jsonopt('whitespaces_',struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n')),varargin{:});
+padding0=repmat(ws.tab,1,level);
+padding2=repmat(ws.tab,1,level+1);
+nl=ws.newline;
+if(len>1)
+    if(~isempty(name))
+        txt=sprintf('%s"%s": [%s',padding0, checkname(name,varargin{:}),nl); name=''; 
+    else
+        txt=sprintf('%s[%s',padding0,nl); 
+    end
+elseif(len==0)
+    if(~isempty(name))
+        txt=sprintf('%s"%s": []',padding0, checkname(name,varargin{:})); name=''; 
+    else
+        txt=sprintf('%s[]',padding0); 
+    end
+end
+for j=1:dim(2)
+    if(dim(1)>1) txt=sprintf('%s%s[%s',txt,padding2,nl); end
+    for i=1:dim(1)
+       txt=sprintf('%s%s',txt,obj2json(name,item{i,j},level+(dim(1)>1)+1,varargin{:}));
+       if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+    end
+    if(dim(1)>1) txt=sprintf('%s%s%s]',txt,nl,padding2); end
+    if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+    %if(j==dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+end
+if(len>1) txt=sprintf('%s%s%s]',txt,nl,padding0); end
+
+%%-------------------------------------------------------------------------
+function txt=struct2json(name,item,level,varargin)
+txt='';
+if(~isstruct(item))
+	error('input is not a struct');
+end
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item);
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+padding0=repmat(ws.tab,1,level);
+padding2=repmat(ws.tab,1,level+1);
+padding1=repmat(ws.tab,1,level+(dim(1)>1)+(len>1));
+nl=ws.newline;
+
+if(~isempty(name)) 
+    if(len>1) txt=sprintf('%s"%s": [%s',padding0,checkname(name,varargin{:}),nl); end
+else
+    if(len>1) txt=sprintf('%s[%s',padding0,nl); end
+end
+for j=1:dim(2)
+  if(dim(1)>1) txt=sprintf('%s%s[%s',txt,padding2,nl); end
+  for i=1:dim(1)
+    names = fieldnames(item(i,j));
+    if(~isempty(name) && len==1)
+        txt=sprintf('%s%s"%s": {%s',txt,padding1, checkname(name,varargin{:}),nl); 
+    else
+        txt=sprintf('%s%s{%s',txt,padding1,nl); 
+    end
+    if(~isempty(names))
+      for e=1:length(names)
+	    txt=sprintf('%s%s',txt,obj2json(names{e},getfield(item(i,j),...
+             names{e}),level+(dim(1)>1)+1+(len>1),varargin{:}));
+        if(e<length(names)) txt=sprintf('%s%s',txt,','); end
+        txt=sprintf('%s%s',txt,nl);
+      end
+    end
+    txt=sprintf('%s%s}',txt,padding1);
+    if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+  end
+  if(dim(1)>1) txt=sprintf('%s%s%s]',txt,nl,padding2); end
+  if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
+end
+if(len>1) txt=sprintf('%s%s%s]',txt,nl,padding0); end
+
+%%-------------------------------------------------------------------------
+function txt=str2json(name,item,level,varargin)
+txt='';
+if(~ischar(item))
+        error('input is not a string');
+end
+item=reshape(item, max(size(item),[1 0]));
+len=size(item,1);
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+padding1=repmat(ws.tab,1,level);
+padding0=repmat(ws.tab,1,level+1);
+nl=ws.newline;
+sep=ws.sep;
+
+if(~isempty(name)) 
+    if(len>1) txt=sprintf('%s"%s": [%s',padding1,checkname(name,varargin{:}),nl); end
+else
+    if(len>1) txt=sprintf('%s[%s',padding1,nl); end
+end
+isoct=jsonopt('IsOctave',0,varargin{:});
+for e=1:len
+    if(isoct)
+        val=regexprep(item(e,:),'\\','\\');
+        val=regexprep(val,'"','\"');
+        val=regexprep(val,'^"','\"');
+    else
+        val=regexprep(item(e,:),'\\','\\\\');
+        val=regexprep(val,'"','\\"');
+        val=regexprep(val,'^"','\\"');
+    end
+    val=escapejsonstring(val);
+    if(len==1)
+        obj=['"' checkname(name,varargin{:}) '": ' '"',val,'"'];
+	if(isempty(name)) obj=['"',val,'"']; end
+        txt=sprintf('%s%s%s%s',txt,padding1,obj);
+    else
+        txt=sprintf('%s%s%s%s',txt,padding0,['"',val,'"']);
+    end
+    if(e==len) sep=''; end
+    txt=sprintf('%s%s',txt,sep);
+end
+if(len>1) txt=sprintf('%s%s%s%s',txt,nl,padding1,']'); end
+
+%%-------------------------------------------------------------------------
+function txt=mat2json(name,item,level,varargin)
+if(~isnumeric(item) && ~islogical(item))
+        error('input is not an array');
+end
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+padding1=repmat(ws.tab,1,level);
+padding0=repmat(ws.tab,1,level+1);
+nl=ws.newline;
+sep=ws.sep;
+
+if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
+   isempty(item) ||jsonopt('ArrayToStruct',0,varargin{:}))
+    if(isempty(name))
+    	txt=sprintf('%s{%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',...
+              padding1,nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl);
+    else
+    	txt=sprintf('%s"%s": {%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',...
+              padding1,checkname(name,varargin{:}),nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl);
+    end
+else
+    if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1 && level>0)
+        numtxt=regexprep(regexprep(matdata2json(item,level+1,varargin{:}),'^\[',''),']','');
+    else
+        numtxt=matdata2json(item,level+1,varargin{:});
+    end
+    if(isempty(name))
+    	txt=sprintf('%s%s',padding1,numtxt);
+    else
+        if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
+           	txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);
+        else
+    	    txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);
+        end
+    end
+    return;
+end
+dataformat='%s%s%s%s%s';
+
+if(issparse(item))
+    [ix,iy]=find(item);
+    data=full(item(find(item)));
+    if(~isreal(item))
+       data=[real(data(:)),imag(data(:))];
+       if(size(item,1)==1)
+           % Kludge to have data's 'transposedness' match item's.
+           % (Necessary for complex row vector handling below.)
+           data=data';
+       end
+       txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep);
+    end
+    txt=sprintf(dataformat,txt,padding0,'"_ArrayIsSparse_": ','1', sep);
+    if(size(item,1)==1)
+        % Row vector, store only column indices.
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+           matdata2json([iy(:),data'],level+2,varargin{:}), nl);
+    elseif(size(item,2)==1)
+        % Column vector, store only row indices.
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+           matdata2json([ix,data],level+2,varargin{:}), nl);
+    else
+        % General case, store row and column indices.
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+           matdata2json([ix,iy,data],level+2,varargin{:}), nl);
+    end
+else
+    if(isreal(item))
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+            matdata2json(item(:)',level+2,varargin{:}), nl);
+    else
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep);
+        txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
+            matdata2json([real(item(:)) imag(item(:))],level+2,varargin{:}), nl);
+    end
+end
+txt=sprintf('%s%s%s',txt,padding1,'}');
+
+%%-------------------------------------------------------------------------
+function txt=matdata2json(mat,level,varargin)
+
+ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
+ws=jsonopt('whitespaces_',ws,varargin{:});
+tab=ws.tab;
+nl=ws.newline;
+
+if(size(mat,1)==1)
+    pre='';
+    post='';
+    level=level-1;
+else
+    pre=sprintf('[%s',nl);
+    post=sprintf('%s%s]',nl,repmat(tab,1,level-1));
+end
+
+if(isempty(mat))
+    txt='null';
+    return;
+end
+floatformat=jsonopt('FloatFormat','%.10g',varargin{:});
+%if(numel(mat)>1)
+    formatstr=['[' repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf('],%s',nl)]];
+%else
+%    formatstr=[repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf(',\n')]];
+%end
+
+if(nargin>=2 && size(mat,1)>1 && jsonopt('ArrayIndent',1,varargin{:})==1)
+    formatstr=[repmat(tab,1,level) formatstr];
+end
+
+txt=sprintf(formatstr,mat');
+txt(end-length(nl):end)=[];
+if(islogical(mat) && jsonopt('ParseLogical',0,varargin{:})==1)
+   txt=regexprep(txt,'1','true');
+   txt=regexprep(txt,'0','false');
+end
+%txt=regexprep(mat2str(mat),'\s+',',');
+%txt=regexprep(txt,';',sprintf('],\n['));
+% if(nargin>=2 && size(mat,1)>1)
+%     txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
+% end
+txt=[pre txt post];
+if(any(isinf(mat(:))))
+    txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
+end
+if(any(isnan(mat(:))))
+    txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
+end
+
+%%-------------------------------------------------------------------------
+function newname=checkname(name,varargin)
+isunpack=jsonopt('UnpackHex',1,varargin{:});
+newname=name;
+if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
+    return
+end
+if(isunpack)
+    isoct=jsonopt('IsOctave',0,varargin{:});
+    if(~isoct)
+        newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
+    else
+        pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
+        pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
+        if(isempty(pos)) return; end
+        str0=name;
+        pos0=[0 pend(:)' length(name)];
+        newname='';
+        for i=1:length(pos)
+            newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
+        end
+        if(pos(end)~=length(name))
+            newname=[newname str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+end
+
+%%-------------------------------------------------------------------------
+function newstr=escapejsonstring(str)
+newstr=str;
+isoct=exist('OCTAVE_VERSION','builtin');
+if(isoct)
+   vv=sscanf(OCTAVE_VERSION,'%f');
+   if(vv(1)>=3.8) isoct=0; end
+end
+if(isoct)
+  escapechars={'\a','\f','\n','\r','\t','\v'};
+  for i=1:length(escapechars);
+    newstr=regexprep(newstr,escapechars{i},escapechars{i});
+  end
+else
+  escapechars={'\a','\b','\f','\n','\r','\t','\v'};
+  for i=1:length(escapechars);
+    newstr=regexprep(newstr,escapechars{i},regexprep(escapechars{i},'\\','\\\\'));
+  end
+end

+ 504 - 0
ex4/lib/jsonlab/saveubjson.m

@@ -0,0 +1,504 @@
+function json=saveubjson(rootname,obj,varargin)
+%
+% json=saveubjson(rootname,obj,filename)
+%    or
+% json=saveubjson(rootname,obj,opt)
+% json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
+%
+% convert a MATLAB object (cell, struct or array) into a Universal 
+% Binary JSON (UBJSON) binary string
+%
+% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+% created on 2013/08/17
+%
+% $Id: saveubjson.m 460 2015-01-03 00:30:45Z fangq $
+%
+% input:
+%      rootname: the name of the root-object, when set to '', the root name
+%        is ignored, however, when opt.ForceRootName is set to 1 (see below),
+%        the MATLAB variable name will be used as the root name.
+%      obj: a MATLAB object (array, cell, cell array, struct, struct array)
+%      filename: a string for the file name to save the output UBJSON data
+%      opt: a struct for additional options, ignore to use default values.
+%        opt can have the following fields (first in [.|.] is the default)
+%
+%        opt.FileName [''|string]: a file name to save the output JSON data
+%        opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
+%                         array in JSON array format; if sets to 1, an
+%                         array will be shown as a struct with fields
+%                         "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+%                         sparse arrays, the non-zero elements will be
+%                         saved to _ArrayData_ field in triplet-format i.e.
+%                         (ix,iy,val) and "_ArrayIsSparse_" will be added
+%                         with a value of 1; for a complex array, the 
+%                         _ArrayData_ array will include two columns 
+%                         (4 for sparse) to record the real and imaginary 
+%                         parts, and also "_ArrayIsComplex_":1 is added. 
+%        opt.ParseLogical [1|0]: if this is set to 1, logical array elem
+%                         will use true/false rather than 1/0.
+%        opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+%                         numerical element will be shown without a square
+%                         bracket, unless it is the root object; if 0, square
+%                         brackets are forced for any numerical arrays.
+%        opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
+%                         will use the name of the passed obj variable as the 
+%                         root object name; if obj is an expression and 
+%                         does not have a name, 'root' will be used; if this 
+%                         is set to 0 and rootname is empty, the root level 
+%                         will be merged down to the lower level.
+%        opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+%                         for example, if opt.JSON='foo', the JSON data is
+%                         wrapped inside a function call as 'foo(...);'
+%        opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+%                         back to the string form
+%
+%        opt can be replaced by a list of ('param',value) pairs. The param 
+%        string is equivallent to a field in opt and is case sensitive.
+% output:
+%      json: a binary string in the UBJSON format (see http://ubjson.org)
+%
+% examples:
+%      jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+%               'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+%               'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+%                          2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+%               'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+%               'SpecialData',[nan, inf, -inf]);
+%      saveubjson('jsonmesh',jsonmesh)
+%      saveubjson('jsonmesh',jsonmesh,'meshdata.ubj')
+%
+% license:
+%     BSD, see LICENSE_BSD.txt files for details
+%
+% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
+%
+
+if(nargin==1)
+   varname=inputname(1);
+   obj=rootname;
+   if(isempty(varname)) 
+      varname='root';
+   end
+   rootname=varname;
+else
+   varname=inputname(2);
+end
+if(length(varargin)==1 && ischar(varargin{1}))
+   opt=struct('FileName',varargin{1});
+else
+   opt=varargin2struct(varargin{:});
+end
+opt.IsOctave=exist('OCTAVE_VERSION','builtin');
+rootisarray=0;
+rootlevel=1;
+forceroot=jsonopt('ForceRootName',0,opt);
+if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)
+    rootisarray=1;
+    rootlevel=0;
+else
+    if(isempty(rootname))
+        rootname=varname;
+    end
+end
+if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
+    rootname='root';
+end
+json=obj2ubjson(rootname,obj,rootlevel,opt);
+if(~rootisarray)
+    json=['{' json '}'];
+end
+
+jsonp=jsonopt('JSONP','',opt);
+if(~isempty(jsonp))
+    json=[jsonp '(' json ')'];
+end
+
+% save to a file if FileName is set, suggested by Patrick Rapin
+if(~isempty(jsonopt('FileName','',opt)))
+    fid = fopen(opt.FileName, 'wb');
+    fwrite(fid,json);
+    fclose(fid);
+end
+
+%%-------------------------------------------------------------------------
+function txt=obj2ubjson(name,item,level,varargin)
+
+if(iscell(item))
+    txt=cell2ubjson(name,item,level,varargin{:});
+elseif(isstruct(item))
+    txt=struct2ubjson(name,item,level,varargin{:});
+elseif(ischar(item))
+    txt=str2ubjson(name,item,level,varargin{:});
+else
+    txt=mat2ubjson(name,item,level,varargin{:});
+end
+
+%%-------------------------------------------------------------------------
+function txt=cell2ubjson(name,item,level,varargin)
+txt='';
+if(~iscell(item))
+        error('input is not a cell');
+end
+
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item); % let's handle 1D cell first
+if(len>1) 
+    if(~isempty(name))
+        txt=[S_(checkname(name,varargin{:})) '[']; name=''; 
+    else
+        txt='['; 
+    end
+elseif(len==0)
+    if(~isempty(name))
+        txt=[S_(checkname(name,varargin{:})) 'Z']; name=''; 
+    else
+        txt='Z'; 
+    end
+end
+for j=1:dim(2)
+    if(dim(1)>1) txt=[txt '[']; end
+    for i=1:dim(1)
+       txt=[txt obj2ubjson(name,item{i,j},level+(len>1),varargin{:})];
+    end
+    if(dim(1)>1) txt=[txt ']']; end
+end
+if(len>1) txt=[txt ']']; end
+
+%%-------------------------------------------------------------------------
+function txt=struct2ubjson(name,item,level,varargin)
+txt='';
+if(~isstruct(item))
+	error('input is not a struct');
+end
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item);
+
+if(~isempty(name)) 
+    if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
+else
+    if(len>1) txt='['; end
+end
+for j=1:dim(2)
+  if(dim(1)>1) txt=[txt '[']; end
+  for i=1:dim(1)
+     names = fieldnames(item(i,j));
+     if(~isempty(name) && len==1)
+        txt=[txt S_(checkname(name,varargin{:})) '{']; 
+     else
+        txt=[txt '{']; 
+     end
+     if(~isempty(names))
+       for e=1:length(names)
+	     txt=[txt obj2ubjson(names{e},getfield(item(i,j),...
+             names{e}),level+(dim(1)>1)+1+(len>1),varargin{:})];
+       end
+     end
+     txt=[txt '}'];
+  end
+  if(dim(1)>1) txt=[txt ']']; end
+end
+if(len>1) txt=[txt ']']; end
+
+%%-------------------------------------------------------------------------
+function txt=str2ubjson(name,item,level,varargin)
+txt='';
+if(~ischar(item))
+        error('input is not a string');
+end
+item=reshape(item, max(size(item),[1 0]));
+len=size(item,1);
+
+if(~isempty(name)) 
+    if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
+else
+    if(len>1) txt='['; end
+end
+isoct=jsonopt('IsOctave',0,varargin{:});
+for e=1:len
+    val=item(e,:);
+    if(len==1)
+        obj=['' S_(checkname(name,varargin{:})) '' '',S_(val),''];
+	if(isempty(name)) obj=['',S_(val),'']; end
+        txt=[txt,'',obj];
+    else
+        txt=[txt,'',['',S_(val),'']];
+    end
+end
+if(len>1) txt=[txt ']']; end
+
+%%-------------------------------------------------------------------------
+function txt=mat2ubjson(name,item,level,varargin)
+if(~isnumeric(item) && ~islogical(item))
+        error('input is not an array');
+end
+
+if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
+   isempty(item) || jsonopt('ArrayToStruct',0,varargin{:}))
+      cid=I_(uint32(max(size(item))));
+      if(isempty(name))
+    	txt=['{' S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1)) ];
+      else
+          if(isempty(item))
+              txt=[S_(checkname(name,varargin{:})),'Z'];
+              return;
+          else
+    	      txt=[S_(checkname(name,varargin{:})),'{',S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1))];
+          end
+      end
+else
+    if(isempty(name))
+    	txt=matdata2ubjson(item,level+1,varargin{:});
+    else
+        if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
+            numtxt=regexprep(regexprep(matdata2ubjson(item,level+1,varargin{:}),'^\[',''),']','');
+           	txt=[S_(checkname(name,varargin{:})) numtxt];
+        else
+    	    txt=[S_(checkname(name,varargin{:})),matdata2ubjson(item,level+1,varargin{:})];
+        end
+    end
+    return;
+end
+if(issparse(item))
+    [ix,iy]=find(item);
+    data=full(item(find(item)));
+    if(~isreal(item))
+       data=[real(data(:)),imag(data(:))];
+       if(size(item,1)==1)
+           % Kludge to have data's 'transposedness' match item's.
+           % (Necessary for complex row vector handling below.)
+           data=data';
+       end
+       txt=[txt,S_('_ArrayIsComplex_'),'T'];
+    end
+    txt=[txt,S_('_ArrayIsSparse_'),'T'];
+    if(size(item,1)==1)
+        % Row vector, store only column indices.
+        txt=[txt,S_('_ArrayData_'),...
+           matdata2ubjson([iy(:),data'],level+2,varargin{:})];
+    elseif(size(item,2)==1)
+        % Column vector, store only row indices.
+        txt=[txt,S_('_ArrayData_'),...
+           matdata2ubjson([ix,data],level+2,varargin{:})];
+    else
+        % General case, store row and column indices.
+        txt=[txt,S_('_ArrayData_'),...
+           matdata2ubjson([ix,iy,data],level+2,varargin{:})];
+    end
+else
+    if(isreal(item))
+        txt=[txt,S_('_ArrayData_'),...
+            matdata2ubjson(item(:)',level+2,varargin{:})];
+    else
+        txt=[txt,S_('_ArrayIsComplex_'),'T'];
+        txt=[txt,S_('_ArrayData_'),...
+            matdata2ubjson([real(item(:)) imag(item(:))],level+2,varargin{:})];
+    end
+end
+txt=[txt,'}'];
+
+%%-------------------------------------------------------------------------
+function txt=matdata2ubjson(mat,level,varargin)
+if(isempty(mat))
+    txt='Z';
+    return;
+end
+if(size(mat,1)==1)
+    level=level-1;
+end
+type='';
+hasnegtive=(mat<0);
+if(isa(mat,'integer') || isinteger(mat) || (isfloat(mat) && all(mod(mat(:),1) == 0)))
+    if(isempty(hasnegtive))
+       if(max(mat(:))<=2^8)
+           type='U';
+       end
+    end
+    if(isempty(type))
+        % todo - need to consider negative ones separately
+        id= histc(abs(max(mat(:))),[0 2^7 2^15 2^31 2^63]);
+        if(isempty(find(id)))
+            error('high-precision data is not yet supported');
+        end
+        key='iIlL';
+	type=key(find(id));
+    end
+    txt=[I_a(mat(:),type,size(mat))];
+elseif(islogical(mat))
+    logicalval='FT';
+    if(numel(mat)==1)
+        txt=logicalval(mat+1);
+    else
+        txt=['[$U#' I_a(size(mat),'l') typecast(swapbytes(uint8(mat(:)')),'uint8')];
+    end
+else
+    if(numel(mat)==1)
+        txt=['[' D_(mat) ']'];
+    else
+        txt=D_a(mat(:),'D',size(mat));
+    end
+end
+
+%txt=regexprep(mat2str(mat),'\s+',',');
+%txt=regexprep(txt,';',sprintf('],['));
+% if(nargin>=2 && size(mat,1)>1)
+%     txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
+% end
+if(any(isinf(mat(:))))
+    txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
+end
+if(any(isnan(mat(:))))
+    txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
+end
+
+%%-------------------------------------------------------------------------
+function newname=checkname(name,varargin)
+isunpack=jsonopt('UnpackHex',1,varargin{:});
+newname=name;
+if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
+    return
+end
+if(isunpack)
+    isoct=jsonopt('IsOctave',0,varargin{:});
+    if(~isoct)
+        newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
+    else
+        pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
+        pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
+        if(isempty(pos)) return; end
+        str0=name;
+        pos0=[0 pend(:)' length(name)];
+        newname='';
+        for i=1:length(pos)
+            newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
+        end
+        if(pos(end)~=length(name))
+            newname=[newname str0(pos0(end-1)+1:pos0(end))];
+        end
+    end
+end
+%%-------------------------------------------------------------------------
+function val=S_(str)
+if(length(str)==1)
+  val=['C' str];
+else
+  val=['S' I_(int32(length(str))) str];
+end
+%%-------------------------------------------------------------------------
+function val=I_(num)
+if(~isinteger(num))
+    error('input is not an integer');
+end
+if(num>=0 && num<255)
+   val=['U' data2byte(swapbytes(cast(num,'uint8')),'uint8')];
+   return;
+end
+key='iIlL';
+cid={'int8','int16','int32','int64'};
+for i=1:4
+  if((num>0 && num<2^(i*8-1)) || (num<0 && num>=-2^(i*8-1)))
+    val=[key(i) data2byte(swapbytes(cast(num,cid{i})),'uint8')];
+    return;
+  end
+end
+error('unsupported integer');
+
+%%-------------------------------------------------------------------------
+function val=D_(num)
+if(~isfloat(num))
+    error('input is not a float');
+end
+
+if(isa(num,'single'))
+  val=['d' data2byte(num,'uint8')];
+else
+  val=['D' data2byte(num,'uint8')];
+end
+%%-------------------------------------------------------------------------
+function data=I_a(num,type,dim,format)
+id=find(ismember('iUIlL',type));
+
+if(id==0)
+  error('unsupported integer array');
+end
+
+% based on UBJSON specs, all integer types are stored in big endian format
+
+if(id==1)
+  data=data2byte(swapbytes(int8(num)),'uint8');
+  blen=1;
+elseif(id==2)
+  data=data2byte(swapbytes(uint8(num)),'uint8');
+  blen=1;
+elseif(id==3)
+  data=data2byte(swapbytes(int16(num)),'uint8');
+  blen=2;
+elseif(id==4)
+  data=data2byte(swapbytes(int32(num)),'uint8');
+  blen=4;
+elseif(id==5)
+  data=data2byte(swapbytes(int64(num)),'uint8');
+  blen=8;
+end
+
+if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
+  format='opt';
+end
+if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
+  if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
+      cid=I_(uint32(max(dim)));
+      data=['$' type '#' I_a(dim,cid(1)) data(:)'];
+  else
+      data=['$' type '#' I_(int32(numel(data)/blen)) data(:)'];
+  end
+  data=['[' data(:)'];
+else
+  data=reshape(data,blen,numel(data)/blen);
+  data(2:blen+1,:)=data;
+  data(1,:)=type;
+  data=data(:)';
+  data=['[' data(:)' ']'];
+end
+%%-------------------------------------------------------------------------
+function data=D_a(num,type,dim,format)
+id=find(ismember('dD',type));
+
+if(id==0)
+  error('unsupported float array');
+end
+
+if(id==1)
+  data=data2byte(single(num),'uint8');
+elseif(id==2)
+  data=data2byte(double(num),'uint8');
+end
+
+if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
+  format='opt';
+end
+if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
+  if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
+      cid=I_(uint32(max(dim)));
+      data=['$' type '#' I_a(dim,cid(1)) data(:)'];
+  else
+      data=['$' type '#' I_(int32(numel(data)/(id*4))) data(:)'];
+  end
+  data=['[' data];
+else
+  data=reshape(data,(id*4),length(data)/(id*4));
+  data(2:(id*4+1),:)=data;
+  data(1,:)=type;
+  data=data(:)';
+  data=['[' data(:)' ']'];
+end
+%%-------------------------------------------------------------------------
+function bytes=data2byte(varargin)
+bytes=typecast(varargin{:});
+bytes=bytes(:)';

Some files were not shown because too many files changed in this diff