text:
<!DOCTYPE html>

		<meta name="robots" content="noindex, nofollow">
		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<meta name="DESCRIPTION" CONTENT="Reinald Functional Art">
		<meta name="KEYWORDS" CONTENT="art,functionalart,arte,artefuncional,wood,madera,design,diseño">
		<meta name="author" content="Reinald Van De Walle">
		<link rel="icon" href="favicon.ico">
		<title>Reinald Arte Funcional</title>

		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">

		<link href="css/style.css" rel="stylesheet">

		<link rel="stylesheet" href="components/magnific/magnific-popup.css">

					<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
					Toggle navigation

					</button>

							Home

							Galerías

							Bio

							Contacto

Creando con las manos

						Ver trabajos

Galerías

Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Cajas de madera

Galletas, bombones, té

									View more

Repisas

Para miniaturas y recuerdos

									View more

Perritos

Para jugar y reir

									View more

Galeria Cuatro

caption 4

									View more

Galeria Cinco

caption 5

									View more

Galeria Seis

caption 6

									View more

Bio

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

AT VERO EOS

At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis

TEMPORIBUS

Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe

ACCUSAMUS

Accusamus et iusto odio dignissimos ducimus qui blanditiis

ITAQUE

Itaque earum rerum hic tenetur a sapiente, ut aut reiciendis maiores

Contacto

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

 correo@electronico.com

Copyright © 2016 Reinald Van De Walle, Last Updated: March 2016

						<button type="button" class="close" data-dismiss="modal" aria-label="Close">×</button>

Excepteur sint

UnoDos

Esto lo vamos a reemplazar con una galeria de losas

						<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>


text:
layout: post
title: "nginx and the location block"
excerpt: "A lesson in nested location blocks"
tags: [business, technology]
image:
  feature:
  credit:
  creditlink:
modified:
---

I was recently performing a QA review of a couple of nginx servers and I kept running into the same configuration mistakes so I thought I'd throw a couple of words of wisdom about it here.

The configuration I was looking was a phpMyAdmin application so Ill use this as an example but first a little background.

Nginx logically divides configurations for different content into blocks. These blocks live in a hierarchical structure. The issue I was looking at was how the phpMyAdmin application was being secured with location blocks. Specifically after configuring phpMyAdmin you should restrict access to some sensitive directories such as setup/.

When using location blocks to restrict access make sure that if you start your location block using a regex your nested location blocks also use regex otherwise the nested location blocks will never match.

What I was seeing was something along the lines of this:

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_intercept_errors on;
        fastcgi_ignore_client_abort off;
    }

    location ~ ^/pma {
            allow 127.0.0.1;
            allow x.x.x.x;
            deny all;
            include fastcgi_params;
            include /opt/local/etc/nginx/mime.types;
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param APPLICATION_ENV development;
            fastcgi_index index.php;
            fastcgi_intercept_errors on;
            fastcgi_ignore_client_abort off;
    }

However anyone could still access /pma even if they were not in the allowed IP ACL. Digging a little deeper I came up with the following:

    location ~ \.php$ {
        location ~ ^/pma {
                allow 127.0.0.1;
                allow x.x.x.x;
                deny all;
                include fastcgi_params;
                include /opt/local/etc/nginx/mime.types;
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_param APPLICATION_ENV development;
                fastcgi_index index.php;
                fastcgi_intercept_errors on;
                fastcgi_ignore_client_abort off;
        }
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_intercept_errors on;
        fastcgi_ignore_client_abort off;
    }

Is this the best way (from a performance/security point of view) to achieve this?  Let me know what you think.

redpajama_set_name: RedPajamaGithub


text:
@interface RPViewController ()

@end

@implementation RPViewController

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    NSString *path = [[NSBundle mainBundle] pathForResource:@"rainbow" ofType:@"js"];
    NSString *codeSnippet = [NSString stringWithContentsOfFile:path encoding:NSASCIIStringEncoding error:nil];
    NSAttributedString *code = [RPSyntaxHighlighter highlightCode:codeSnippet withLanguage:@"javascript"];

    [self.textView setAttributedText:code];
}

@end


text:
class BrowseController < ApplicationController

  def index
      @stock     = ImageShell.stock.all
      @editorial = ImageShell.editorial.find(:all)
  end

end


text:
Code for generating the box for the main vagrant image.

See the `documentation <../../docs/infrastructure/vagrant.rst#base-image>`_ for details.


text:
package org.springframework.security.core.parameters;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.Before;
import org.junit.Test;
import org.springframework.security.access.method.P;
import org.springframework.util.ReflectionUtils;

public class AnnotationParameterNameDiscovererTests {
	private AnnotationParameterNameDiscoverer discoverer;

	@Before
	public void setup() {
		discoverer = new AnnotationParameterNameDiscoverer(P.class.getName());
	}

	@Test
	public void getParameterNamesInterfaceSingleParam() {
		assertThat(
				discoverer.getParameterNames(ReflectionUtils.findMethod(Dao.class,
						"findMessageByTo", String.class))).isEqualTo(
				new String[] { "to" });
	}

	@Test
	public void getParameterNamesInterfaceSingleParamAnnotatedWithMultiParams() {
		assertThat(
				discoverer.getParameterNames(ReflectionUtils.findMethod(Dao.class,
						"findMessageByToAndFrom", String.class, String.class)))
				.isEqualTo(new String[] { "to", null });
	}

	@Test
	public void getParameterNamesInterfaceNoAnnotation() {
		assertThat(
				discoverer.getParameterNames(ReflectionUtils.findMethod(Dao.class,
						"findMessageByIdNoAnnotation", String.class))).isNull();
	}

	@Test
	public void getParameterNamesClassSingleParam() {
		assertThat(
				discoverer.getParameterNames(ReflectionUtils.findMethod(Dao.class,
						"findMessageByTo", String.class))).isEqualTo(
				new String[] { "to" });
	}

	@Test
	public void getParameterNamesClassSingleParamAnnotatedWithMultiParams() {
		assertThat(
				discoverer.getParameterNames(ReflectionUtils.findMethod(Dao.class,
						"findMessageByToAndFrom", String.class, String.class)))
				.isEqualTo(new String[] { "to", null });
	}

	@Test
	public void getParameterNamesClassNoAnnotation() {
		assertThat(
				discoverer.getParameterNames(ReflectionUtils.findMethod(Dao.class,
						"findMessageByIdNoAnnotation", String.class))).isNull();
	}

	@Test
	public void getParameterNamesConstructor() throws Exception {
		assertThat(discoverer.getParameterNames(Impl.class.getConstructor(String.class)))
				.isEqualTo(new String[] { "id" });
	}

	@Test
	public void getParameterNamesConstructorNoAnnotation() throws Exception {
		assertThat(discoverer.getParameterNames(Impl.class.getConstructor(Long.class)))
				.isNull();
	}

	@Test
	public void getParameterNamesClassAnnotationOnInterface() throws Exception {
		assertThat(
				discoverer.getParameterNames(ReflectionUtils.findMethod(DaoImpl.class,
						"findMessageByTo", String.class))).isEqualTo(
				new String[] { "to" });
		assertThat(
				discoverer.getParameterNames(ReflectionUtils.findMethod(Dao.class,
						"findMessageByTo", String.class))).isEqualTo(
				new String[] { "to" });
	}

	@Test
	public void getParameterNamesClassAnnotationOnImpl() throws Exception {
		assertThat(
				discoverer.getParameterNames(ReflectionUtils.findMethod(Dao.class,
						"findMessageByToAndFrom", String.class, String.class)))
				.isEqualTo(new String[] { "to", null });
		assertThat(
				discoverer.getParameterNames(ReflectionUtils.findMethod(DaoImpl.class,
						"findMessageByToAndFrom", String.class, String.class)))
				.isEqualTo(new String[] { "to", "from" });
	}

	@Test
	public void getParameterNamesClassAnnotationOnBaseClass() throws Exception {
		assertThat(
				discoverer.getParameterNames(ReflectionUtils.findMethod(Dao.class,
						"findMessageByIdNoAnnotation", String.class))).isNull();
		assertThat(
				discoverer.getParameterNames(ReflectionUtils.findMethod(DaoImpl.class,
						"findMessageByIdNoAnnotation", String.class))).isEqualTo(
				new String[] { "id" });
	}

	interface Dao {
		String findMessageByTo(@P("to") String to);

		String findMessageByToAndFrom(@P("to") String to, String from);

		String findMessageByIdNoAnnotation(String id);
	}

	static class BaseDaoImpl {
		public String findMessageByIdNoAnnotation(@P("id") String id) {
			return null;
		}
	}

	static class DaoImpl extends BaseDaoImpl implements Dao {
		public String findMessageByTo(String to) {
			return null;
		}

		public String findMessageByToAndFrom(@P("to") String to, @P("from") String from) {
			return null;
		}
	}

	static class Impl {
		public Impl(Long dataSourceId) {
		}

		public Impl(@P("id") String dataSourceId) {
		}

		String findMessageByTo(@P("to") String to) {
			return null;
		}

		String findMessageByToAndFrom(@P("to") String to, String from) {
			return null;
		}

		String findMessageByIdNoAnnotation(String id) {
			return null;
		}
	}
}


text:
<?php

namespace Kraken\_Unit\Runtime\Command;

use Kraken\Runtime\Supervision\SolverFactory;
use Kraken\Runtime\RuntimeContainerInterface;
use Kraken\Test\TUnit;

class SolverFactoryTest extends TUnit
{
    /**
     *
     */
    public function testCaseFactory_PossesAllDefinitions()
    {
        $runtime  = $this->getMock(RuntimeContainerInterface::class, [], [], '', false);
        $factory  = new SolverFactory($runtime);
        $commands = [
            'CmdDoNothing'          => 'Kraken\Runtime\Supervision\Cmd\CmdDoNothing',
            'CmdEscalate'           => 'Kraken\Runtime\Supervision\Cmd\CmdEscalate',
            'CmdSolve'              => 'Kraken\Runtime\Supervision\Cmd\CmdSolve',
            'CmdLog'                => 'Kraken\Runtime\Supervision\Cmd\CmdLog',
            'RuntimeContinue'       => 'Kraken\Runtime\Supervision\Runtime\RuntimeContinue',
            'RuntimeDestroy'        => 'Kraken\Runtime\Supervision\Runtime\RuntimeDestroy',
            'RuntimeDestroySoft'    => 'Kraken\Runtime\Supervision\Runtime\RuntimeDestroySoft',
            'RuntimeDestroyHard'    => 'Kraken\Runtime\Supervision\Runtime\RuntimeDestroyHard',
            'RuntimeRecreate'       => 'Kraken\Runtime\Supervision\Runtime\RuntimeRecreate',
            'RuntimeStart'          => 'Kraken\Runtime\Supervision\Runtime\RuntimeStart',
            'RuntimeStop'           => 'Kraken\Runtime\Supervision\Runtime\RuntimeStop',
            'ContainerContinue'     => 'Kraken\Runtime\Supervision\Container\ContainerContinue',
            'ContainerDestroy'      => 'Kraken\Runtime\Supervision\Container\ContainerDestroy',
            'ContainerStart'        => 'Kraken\Runtime\Supervision\Container\ContainerStart',
            'ContainerStop'         => 'Kraken\Runtime\Supervision\Container\ContainerStop'
        ];

        foreach ($commands as $alias=>$class)
        {
            $this->assertTrue($factory->hasDefinition($alias));
            $this->assertTrue($factory->hasDefinition($class));
        }
    }
}


text:
/**
 * Constructor - no need to invoke directly, call initBackgroundPage instead.
 * @constructor
 * @param {String} url_request_token The OAuth request token URL.
 * @param {String} url_auth_token The OAuth authorize token URL.
 * @param {String} url_access_token The OAuth access token URL.
 * @param {String} consumer_key The OAuth consumer key.
 * @param {String} consumer_secret The OAuth consumer secret.
 * @param {String} oauth_scope The OAuth scope parameter.
 * @param {Object} opt_args Optional arguments.  Recognized parameters:
 *     "app_name" {String} Name of the current application
 *     "callback_page" {String} If you renamed chrome_ex_oauth.html, the name
 *          this file was renamed to.
 */
function ChromeExOAuth(url_request_token, url_auth_token, url_access_token,
                       consumer_key, consumer_secret, oauth_scope, opt_args) {
  this.url_request_token = url_request_token;
  this.url_auth_token = url_auth_token;
  this.url_access_token = url_access_token;
  this.consumer_key = consumer_key;
  this.consumer_secret = consumer_secret;
  this.oauth_scope = oauth_scope;
  this.app_name = opt_args && opt_args['app_name'] ||
      "ChromeExOAuth Library";
  this.key_token = "oauth_token";
  this.key_token_secret = "oauth_token_secret";
  this.callback_page = opt_args && opt_args['callback_page'] ||
      "chrome_ex_oauth.html";
};

/*******************************************************************************
 * PUBLIC API METHODS
 * Call these from your background page.
 ******************************************************************************/

/**
 * Initializes the OAuth helper from the background page.  You must call this
 * before attempting to make any OAuth calls.
 * @param {Object} oauth_config Configuration parameters in a JavaScript object.
 *     The following parameters are recognized:
 *         "request_url" {String} OAuth request token URL.
 *         "authorize_url" {String} OAuth authorize token URL.
 *         "access_url" {String} OAuth access token URL.
 *         "consumer_key" {String} OAuth consumer key.
 *         "consumer_secret" {String} OAuth consumer secret.
 *         "scope" {String} OAuth access scope.
 *         "app_name" {String} Application name.
 * @return {ChromeExOAuth} An initialized ChromeExOAuth object.
 */
ChromeExOAuth.initBackgroundPage = function(oauth_config) {
  window.chromeExOAuthConfig = oauth_config;
  window.chromeExOAuth = ChromeExOAuth.fromConfig(oauth_config);

  var url_match = chrome.extension.getURL(window.chromeExOAuth.callback_page);
  chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
    if (changeInfo.url &&
        changeInfo.url.substr(0, url_match.length) === url_match) {
      chrome.tabs.create({ 'url' : changeInfo.url }, function() {
        chrome.tabs.remove(tabId);
      });
    }
  });

  return window.chromeExOAuth;
};

/**
 * Authorizes the current user with the configued API.  You must call this
 * before calling makeSignedRequest.
 * @param {Function} callback A function to call once an access token has
 *     been obtained.  This callback will be passed the following arguments:
 *         token {String} The OAuth access token.
 *         secret {String} The OAuth access token secret.
 */
ChromeExOAuth.prototype.authorize = function(callback) {
  if (this.hasToken()) {
    callback(this.getToken(), this.getTokenSecret());
  } else {
    window.chromeExOAuthOnAuthorize = function(token, secret) {
      callback(token, secret);
    };
    chrome.tabs.create({ 'url' :chrome.extension.getURL(this.callback_page) });
  }
};

/**
 * Clears any OAuth tokens stored for this configuration.  Effectively a
 * "logout" of the configured OAuth API.
 */
ChromeExOAuth.prototype.clearTokens = function() {
  delete localStorage[this.key_token + encodeURI(this.oauth_scope)];
  delete localStorage[this.key_token_secret + encodeURI(this.oauth_scope)];
};

/**
 * Returns whether a token is currently stored for this configuration.
 * Effectively a check to see whether the current user is "logged in" to
 * the configured OAuth API.
 * @return {Boolean} True if an access token exists.
 */
ChromeExOAuth.prototype.hasToken = function() {
  return !!this.getToken();
};

/**
 * Makes an OAuth-signed HTTP request with the currently authorized tokens.
 * @param {String} url The URL to send the request to.  Querystring parameters
 *     should be omitted.
 * @param {Function} callback A function to be called once the request is
 *     completed.  This callback will be passed the following arguments:
 *         responseText {String} The text response, if a 200 HTTP code is
 *             returned.
 *         xhr {XMLHttpRequest} The XMLHttpRequest object which was used to
 *             send the request.  Useful if you need to check response status
 *             code, etc.
 * @param {Object} opt_params Additional parameters to configure the request.
 *     The following parameters are accepted:
 *         "method" {String} The HTTP method to use.  Defaults to "GET".
 *         "body" {String} A request body to send.  Defaults to null.
 *         "parameters" {Object} Query parameters to include in the request.
 */
ChromeExOAuth.prototype.sendSignedRequest = function(url, callback,
                                                     opt_params) {
  var token = this.getToken();
  var secret = this.getTokenSecret();
  if (!token || !secret) {
    throw new Error("No oauth token or token secret");
  }

  var method = opt_params && opt_params['method'] || 'GET';
  var body = opt_params && opt_params['body'] || null;
  var params = opt_params && opt_params['parameters'] || {};
  params["oauth_token"] = token;

  var result = OAuthSimple().sign({
    path : url,
    parameters : params,
    signatures: {
      consumer_key : this.consumer_key,
      shared_secret : this.consumer_secret,
      oauth_secret : secret
    }
  });
  var signed_url = result.signed_url;

  ChromeExOAuth.sendRequest(method, signed_url, null, body, function (xhr) {
    if (xhr.readyState == 4) {
      var responseText = (xhr.status == 200) ? xhr.responseText : null;
      callback(responseText, xhr);
    }
  });
};

/**
 * Adds the required OAuth parameters to the given url and returns the
 * result.  Useful if you need a signed url but don't want to make an XHR
 * request.
 * @param {String} url The base url of the resource you are querying.
 * @param {Object} opt_params Query parameters to include in the request.
 * @return {String} The base url plus any query params plus any OAuth params.
 */
ChromeExOAuth.prototype.signURL = function(url, opt_params) {
  var token = this.getToken();
  var secret = this.getTokenSecret();
  if (!token || !secret) {
    throw new Error("No oauth token or token secret");
  }

  var params = opt_params || {};
  params["oauth_token"] = token;

  var result = OAuthSimple().sign({
    path : url,
    parameters : params,
    signatures: {
      consumer_key : this.consumer_key,
      shared_secret : this.consumer_secret,
      oauth_secret : secret
    }
  });

  return result.signed_url;
};

/*******************************************************************************
 * PRIVATE API METHODS
 * Used by the library.  There should be no need to call these methods directly.
 ******************************************************************************/

/**
 * Creates a new ChromeExOAuth object from the supplied configuration object.
 * @param {Object} oauth_config Configuration parameters in a JavaScript object.
 *     The following parameters are recognized:
 *         "request_url" {String} OAuth request token URL.
 *         "authorize_url" {String} OAuth authorize token URL.
 *         "access_url" {String} OAuth access token URL.
 *         "consumer_key" {String} OAuth consumer key.
 *         "consumer_secret" {String} OAuth consumer secret.
 *         "scope" {String} OAuth access scope.
 *         "app_name" {String} Application name.
 * @return {ChromeExOAuth} An initialized ChromeExOAuth object.
 */
ChromeExOAuth.fromConfig = function(oauth_config) {
  return new ChromeExOAuth(
    oauth_config['request_url'],
    oauth_config['authorize_url'],
    oauth_config['access_url'],
    oauth_config['consumer_key'],
    oauth_config['consumer_secret'],
    oauth_config['scope'],
    {
      'app_name' : oauth_config['app_name']
    }
  );
};

/**
 * Initializes chrome_ex_oauth.html and redirects the page if needed to start
 * the OAuth flow.  Once an access token is obtained, this function closes
 * chrome_ex_oauth.html.
 */
ChromeExOAuth.initCallbackPage = function() {
  var oauth_config = chrome.extension.getBackgroundPage().chromeExOAuthConfig;
  var oauth = ChromeExOAuth.fromConfig(oauth_config);
  oauth.initOAuthFlow(function (token, secret) {
    var background_page = chrome.extension.getBackgroundPage();
    background_page.chromeExOAuthOnAuthorize(token, secret);
    window.close();
  });
};

/**
 * Sends an HTTP request.  Convenience wrapper for XMLHttpRequest calls.
 * @param {String} method The HTTP method to use.
 * @param {String} url The URL to send the request to.
 * @param {Object} headers Optional request headers in key/value format.
 * @param {String} body Optional body content.
 * @param {Function} callback Function to call when the XMLHttpRequest's
 *     ready state changes.  See documentation for XMLHttpRequest's
 *     onreadystatechange handler for more information.
 */
ChromeExOAuth.sendRequest = function(method, url, headers, body, callback) {
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function(data) {
    callback(xhr, data);
  }
  xhr.open(method, url, true);
  if (headers) {
    for (var header in headers) {
      if (headers.hasOwnProperty(header)) {
        xhr.setRequestHeader(header, headers[header]);
      }
    }
  }
  xhr.send(body);
};

/**
 * Decodes a URL-encoded string into key/value pairs.
 * @param {String} encoded An URL-encoded string.
 * @return {Object} An object representing the decoded key/value pairs found
 *     in the encoded string.
 */
ChromeExOAuth.formDecode = function(encoded) {
  var params = encoded.split("&");
  var decoded = {};
  for (var i = 0, param; param = params[i]; i++) {
    var keyval = param.split("=");
    if (keyval.length == 2) {
      decoded[decodeURIComponent(keyval[0])] = decodeURIComponent(keyval[1]);
    }
  }
  return decoded;
};

/**
 * Returns the current window's querystring decoded into key/value pairs.
 * @return {Object} A object representing any key/value pairs found in the
 *     current window's querystring.
 */
ChromeExOAuth.getQueryStringParams = function() {
  var urlparts = window.location.href.split("?");
  if (urlparts.length >= 2) {
    var querystring = urlparts.slice(1).join("?");
    return ChromeExOAuth.formDecode(querystring);
  }
  return {};
};

/**
 * Binds a function call to a specific object.  This function will also take
 * a variable number of additional arguments which will be prepended to the
 * arguments passed to the bound function when it is called.
 * @param {Function} func The function to bind.
 * @param {Object} obj The object to bind to the function's "this".
 * @return {Function} A closure that will call the bound function.
 */
ChromeExOAuth.bind = function(func, obj) {
  var newargs = Array.prototype.slice.call(arguments).slice(2);
  return function() {
    var combinedargs = newargs.concat(Array.prototype.slice.call(arguments));
    func.apply(obj, combinedargs);
  };
};

/**
 * Adds a key/value parameter to the supplied URL.
 * @param {String} url An URL which may or may not contain querystring values.
 * @param {String} key A key
 * @param {String} value A value
 * @return {String} The URL with URL-encoded versions of the key and value
 *     appended, prefixing them with "&" or "?" as needed.
 */
ChromeExOAuth.addURLParam = function(url, key, value) {
  var sep = (url.indexOf('?') >= 0) ? "&" : "?";
  return url + sep + encodeURIComponent(key) + "=" + encodeURIComponent(value);
};

/**
 * Stores an OAuth token for the configured scope.
 * @param {String} token The token to store.
 */
ChromeExOAuth.prototype.setToken = function(token) {
  localStorage[this.key_token + encodeURI(this.oauth_scope)] = token;
};

/**
 * Retrieves any stored token for the configured scope.
 * @return {String} The stored token.
 */
ChromeExOAuth.prototype.getToken = function() {
  return localStorage[this.key_token + encodeURI(this.oauth_scope)];
};

/**
 * Stores an OAuth token secret for the configured scope.
 * @param {String} secret The secret to store.
 */
ChromeExOAuth.prototype.setTokenSecret = function(secret) {
  localStorage[this.key_token_secret + encodeURI(this.oauth_scope)] = secret;
};

/**
 * Retrieves any stored secret for the configured scope.
 * @return {String} The stored secret.
 */
ChromeExOAuth.prototype.getTokenSecret = function() {
  return localStorage[this.key_token_secret + encodeURI(this.oauth_scope)];
};

/**
 * Starts an OAuth authorization flow for the current page.  If a token exists,
 * no redirect is needed and the supplied callback is called immediately.
 * If this method detects that a redirect has finished, it grabs the
 * appropriate OAuth parameters from the URL and attempts to retrieve an
 * access token.  If no token exists and no redirect has happened, then
 * an access token is requested and the page is ultimately redirected.
 * @param {Function} callback The function to call once the flow has finished.
 *     This callback will be passed the following arguments:
 *         token {String} The OAuth access token.
 *         secret {String} The OAuth access token secret.
 */
ChromeExOAuth.prototype.initOAuthFlow = function(callback) {
  if (!this.hasToken()) {
    var params = ChromeExOAuth.getQueryStringParams();
    if (params['chromeexoauthcallback'] == 'true') {
      var oauth_token = params['oauth_token'];
      var oauth_verifier = params['oauth_verifier']
      this.getAccessToken(oauth_token, oauth_verifier, callback);
    } else {
      var request_params = {
        'url_callback_param' : 'chromeexoauthcallback'
      }
      this.getRequestToken(function(url) {
        window.location.href = url;
      }, request_params);
    }
  } else {
    callback(this.getToken(), this.getTokenSecret());
  }
};

/**
 * Requests an OAuth request token.
 * @param {Function} callback Function to call once the authorize URL is
 *     calculated.  This callback will be passed the following arguments:
 *         url {String} The URL the user must be redirected to in order to
 *             approve the token.
 * @param {Object} opt_args Optional arguments.  The following parameters
 *     are accepted:
 *         "url_callback" {String} The URL the OAuth provider will redirect to.
 *         "url_callback_param" {String} A parameter to include in the callback
 *             URL in order to indicate to this library that a redirect has
 *             taken place.
 */
ChromeExOAuth.prototype.getRequestToken = function(callback, opt_args) {
  if (typeof callback !== "function") {
    throw new Error("Specified callback must be a function.");
  }
  var url = opt_args && opt_args['url_callback'] ||
            window && window.top && window.top.location &&
            window.top.location.href;

  var url_param = opt_args && opt_args['url_callback_param'] ||
                  "chromeexoauthcallback";
  var url_callback = ChromeExOAuth.addURLParam(url, url_param, "true");

  var result = OAuthSimple().sign({
    path : this.url_request_token,
    parameters: {
      "xoauth_displayname" : this.app_name,
      "scope" : this.oauth_scope,
      "oauth_callback" : url_callback
    },
    signatures: {
      consumer_key : this.consumer_key,
      shared_secret : this.consumer_secret
    }
  });
  var onToken = ChromeExOAuth.bind(this.onRequestToken, this, callback);
  ChromeExOAuth.sendRequest("GET", result.signed_url, null, null, onToken);
};

/**
 * Called when a request token has been returned.  Stores the request token
 * secret for later use and sends the authorization url to the supplied
 * callback (for redirecting the user).
 * @param {Function} callback Function to call once the authorize URL is
 *     calculated.  This callback will be passed the following arguments:
 *         url {String} The URL the user must be redirected to in order to
 *             approve the token.
 * @param {XMLHttpRequest} xhr The XMLHttpRequest object used to fetch the
 *     request token.
 */
ChromeExOAuth.prototype.onRequestToken = function(callback, xhr) {
  if (xhr.readyState == 4) {
    if (xhr.status == 200) {
      var params = ChromeExOAuth.formDecode(xhr.responseText);
      var token = params['oauth_token'];
      this.setTokenSecret(params['oauth_token_secret']);
      var url = ChromeExOAuth.addURLParam(this.url_auth_token,
                                          "oauth_token", token);
      callback(url);
    } else {
      throw new Error("Fetching request token failed. Status " + xhr.status);
    }
  }
};

/**
 * Requests an OAuth access token.
 * @param {String} oauth_token The OAuth request token.
 * @param {String} oauth_verifier The OAuth token verifier.
 * @param {Function} callback The function to call once the token is obtained.
 *     This callback will be passed the following arguments:
 *         token {String} The OAuth access token.
 *         secret {String} The OAuth access token secret.
 */
ChromeExOAuth.prototype.getAccessToken = function(oauth_token, oauth_verifier,
                                                  callback) {
  if (typeof callback !== "function") {
    throw new Error("Specified callback must be a function.");
  }
  var result = OAuthSimple().sign({
    path : this.url_access_token,
    parameters: {
      "oauth_token" : oauth_token,
      "oauth_verifier" : oauth_verifier
    },
    signatures: {
      consumer_key : this.consumer_key,
      shared_secret : this.consumer_secret,
      oauth_secret : this.getTokenSecret(this.oauth_scope)
    }
  });

  var onToken = ChromeExOAuth.bind(this.onAccessToken, this, callback)
  ChromeExOAuth.sendRequest("GET", result.signed_url, null, null, onToken);
};

/**
 * Called when an access token has been returned.  Stores the access token and
 * access token secret for later use and sends them to the supplied callback.
 * @param {Function} callback The function to call once the token is obtained.
 *     This callback will be passed the following arguments:
 *         token {String} The OAuth access token.
 *         secret {String} The OAuth access token secret.
 * @param {XMLHttpRequest} xhr The XMLHttpRequest object used to fetch the
 *     access token.
 */
ChromeExOAuth.prototype.onAccessToken = function(callback, xhr) {
  if (xhr.readyState == 4) {
    if (xhr.status == 200) {
      var params = ChromeExOAuth.formDecode(xhr.responseText);
      var token = params["oauth_token"];
      var secret = params["oauth_token_secret"];
      this.setToken(token);
      this.setTokenSecret(secret);
      callback(token, secret);
    } else {
      throw new Error("Fetching access token failed with status " + xhr.status);
    }
  }
};


text:
<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateBudgetProductProviderTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('budget_product_provider', function(Blueprint $table){
            $table->increments('id');
            $table->integer('product_provider_id')->unsigned();
            $table->integer('budget_id')->unsigned();
            $table->integer('quantity');
            $table->timestamps();

            $table->foreign('product_provider_id')->references('id')->on('product_providers');
            $table->foreign('budget_id')->references('id')->on('budgets');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        //
    }
}


text:
<!DOCTYPE html>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="Activitat d'aprenetatge per introduir el concepte de funció i la operativa bàsica per a declarar-les i fer-les servir durant la codificació.">
    <meta name="author" content="Josep Cañellas i Ferran Borrell ">
    <title>A502. Estructura de dades i Gestor de Dades</title>

    <link href="../css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="../css/bootstrap.min.css" type="text/css"/>

    <link rel="stylesheet" href="../js/styles/default.css">

    <link href="../css/m03b2Activities.css" rel="stylesheet">
    <link href="../css/scrolling-slides.css" rel="stylesheet">
    <link href="../css/highlightActivities.css" rel="stylesheet">

                    Inici activitat

                    Objectius

                    Taula d'activitats

                    Enunciat del projecte

                    Per reforçar

                    Més informació per ampliar

                        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                          Menú

                        </button>

Inici

Tasques a realitzar

Lliurament

Com continuar

Inici activitat A502 - Estructura de dades i gestor de dades

En anteriors períodes heu anat realitzant tasques que sol·licitaven la implementació d'un conjunt de funcions soltes.

En aquesta programarem les estructures que permetin gestionar les dades i implementarem les funcions per manipular-les, assegurant que sempre es mantindrà la seva coherència.

Abans de començar, feu una bona rellegida a l'apartat FASE DE CONTROL DE TEMPS I GUANYADORS del projecte, a partir d'aquí ens adonarem que cal guardar la informació dels temps dels corredors en estructures de dades, així com la realització d'un seguit de funcions sobre aquestes dades.

Tasques a realitzar - Estructura de dades i gestor de dades

 Tasca Disseny de les estructures de dades

A l'activitat A404 es van tractar variables tipus array de dues dimensions on s'emmagatzemaven participants en les files i dades del participant en les seves columnes:

String[][] participants = new String[NUM_PARTICIANTS][3];   // 3 Columnes = DNI, NOM I MOBIL

A mesura que apareixen més i més dades de la nostra aplicació aquestes tendeixen a començar a dispersar-se pel codi tot i estar relacionades entre elles. Estaria bé tenir una estructura que pogués aglutinar tota aquest conjunt de variables i tractar-ho tot sota un mateix nom.

La resposta a aquest dilema rep el nom de classe. Si us heu fixat, el vostre programa principal o main ja es troba dins d'una classe que té el mateix nom que el fitxer en la que està definida. Existeixen altres classes en el vostre projecte que no han de tenir per força una funció main d'entrada. Poden simplement tenir variables i funcions que s'utilitzaran des d'altres parts del codi del nostre projecte.

Unes línies més amunt hem vist una variable participants. Suposeu que també ens cal una altre variable que ens guardi el nom de l'edició de la cursa on corren els participants i no volem que vagin separades en el vostre codi si no encapsulades en una estructura més gran. La solució és crear una nova classe que les contingui. Per exemple:

public class EstructuraDades {
    // variables o atributs de la classe EstructuraDades
    String[][] participants;
    String edicio;
}

Això pot sobtar si no s'ha vist mai. I més quan s'intenta entendre com es pot utilitzar aquestes variables declarades a la classe EstructuraDades en una classe diferent a la que executa el programa principal o fins i tot, en funcions de la mateixa. Veiem-ho al següent exemple:

public class Exemple{
    static final int DNI = 0;    // Columna on s'emmagatzema el DNI a la matriu de corredors
    static final int NOM = 1;    // Columna on s'emmagatzema el nom a la matriu de corredors
    static final int MOBIL = 2;    // Columna on s'emmagatzema el número de mòbil a la matriu de corredors per tal de fer quadrar les posicions de la resta de dades.

    public static void main(String[] args) {
            Exemple programa = new Exemple();
            programa.inici();
    }

    void inici(){
// Declarem una variable contenedora de tipus EstructuraDades i al fer el new també queda creada o instanciada a memòria
            EstructuraDades eD = new EstructuraDades();
            inicialitzar(eD);
            imprimir(eD);
            System.out.println("Fi de programa");
    }

// Funció que rep com a paràmetre una variable de tipus EstructuraDades per a donar valor a les variables que conté.
    void inicialitzar(EstructuraDades eD){
        // La variable participants estava declarada dins eD però no creada
        // per tant la instanciem o creem mitjançant el new i li donem valors
        eD.participants = new String[3][3];
        eD.participants[0][DNI] = "39889787V";
        eD.participants[0][NOM] = "Son goku";
        eD.participants[0][MOBIL] = "898989889";
        eD.participants[1][DNI] = "666666666D";
        eD.participants[1][NOM] = "Vegeta";
        eD.participants[1][MOBIL] = "0000000001";
        eD.participants[2][DNI] = "777777777S";
        eD.participants[2][NOM] = "Son gohan";
        eD.participants[2][MOBIL] = "111111111";

        // Fem el mateix amb la variable restant
        eD.edicio = "Cursa 2018";

        // Les estructures de dades definides en classes es passen per referència, per tant qualsevol canvi realitzat
        // en les funcions que les reben com a paràmetre té efectes fora de les mateixes
    }

    // Funció que rep com a paràmetre una variable de tipus EstructuraDades i n'imprimeix el resultat per pantalla
    void imprimir(EstructuraDades eD){
            // Exemple d'Accés a les dades dels participants
            System.out.println(eD.edicio);
            System.out.println("El nombre de participants és de "+eD.participants.length+" i són els següents:");
            for (int i = 0; i < eD.participants.length; i++ ){
                    System.out.println("-----------------");
                    System.out.println("PARTICIPANT " + i);
                    System.out.println("-----------------");
                    System.out.println("Nom: " + eD.participants[i][NOM]);
                    System.out.println("DNI: " + eD.participants[i][DNI]);
                    System.out.println("MOBIL: " + eD.participants[i][MOBIL]);
            }
    }
}

Fixeu-vos que les funcions que no han declarat l'estructura de dades, necessiten rebre-la a través de paràmetre. Queda doncs clar, com es contenen dades relacionades dins d'una classe i com es poden utilitzar, entre d'altres formes que anireu aprenent, dins d'un programa Java. Ara ja ens podem centrar-nos a reflexionar sobre quines dades haurà de contenir l'estructura del nostre projecte.

Primer de tot, sabem que caldrà emmagatzemar en alguna variable de la classe estructura de dades, les dades dels corredors: DNI, nom i telèfon mòbil. Mireu atentament els exemples explicats en aquesta mateixa pàgina i no us hauria de ser molt difícil determinar el primer tipus de variable que cal utilitzar.

Pel que fa al segon tipus que intentarem esbrinar, caldrà primer que llegiu atentament l'apartat FASE DE CONTROL DE TEMPS I GUANYADORS de l'enunciat del projecte, per tal de rumiar com podem emmagatzemar, per a cada corredor:

L'hora de sortida del poble

L'hora d'arribada al cim

L'hora de sortida del cim

L'hora d'arribada al poble (meta)

Seguim encara decidint quines dades són les que formaran part de la nostra aplicació i que caldrà tenir ben ubicades a la classe EstructuraDades.java

Ara tocaria descobrir com es pot representar el temps total emprat per cada corredor. per tal d'esbrinar la variable que el resolgui, plantegeu-vos la següent pregunta: Quin tipus primitiu dels que coneixeu (int, char, long, etc) és més adient per emmagatzemar internament el temps total que ha fet un corredor a la cursa? Un cop decidiu el tipus primitiu plantegem una segona pregunta: Com guardo tots aquests temps per tots els corredors sota un mateix nom? Quan trobeu la resposta, sabreu el tipus de la tercera variable de la vostra estructura de dades.

Finalment caldrà abordar com aconseguirem mantenir disponibles quins son els 5 primers corredors de la cursa. Per no complicar-nos la vida a l'hora de mantenir aquesta informació, ens plantejarem com podem emmagatzemar d'alguna forma (en alguna variable), la col·lecció dels números que ens indicaran la posició dels 5 primers corredors. Òbviament això serà un càlcul que haurà de fer el nostre programa però que s'haurà d'emmagatzemar en algun lloc, un cop calculat, a la classe de l'estructura de dades.

Obriu un debat al fòrum de discussió del període VI

Feu una entrada en que argumenteu les dues variables i els seus tipus escollides per a emmagatzemar dins la vostra classe EstructuraDades.java, les dades dels participants i les hores corresponents als punts de control. Proposeu també, el tipus de variable més adequat que penseu que pot ajudar-vos a mantenir els temps finals de cada corredor i el el tipus de variable més adequat que us ajudarà a emmagatzemar la posició dels 5 primers classificats

Amb les conclusions que extrèieu del fòrum amb els vostres companys, guardeu-vos la solució que creieu més adequada per al vostre projecte. En la propera tasca continuarem donant forma a l'estructura de dades.

                                    <button type="button" class="btn btn-primary btn-lg btn-toggle toggle-off"
                                            data-toggle="button"
                                            data-parent-selector="#leftColumnPanel"
                                            data-display-on-set-slide="slc-estructuraDeDades1"
                                            data-selector-clue="#slc-estructuraDeDades1-clue1">
                                        Pista 1
                                    </button>

Pista 1

A l'activitat 501 se us ha fet programar, entre d'altres, dues funcions molt relacionades amb la representació de les hores, els minuts i els segons.

En concret les funcions treballaven amb tipus String que tenien el format "HH:MM:SS" on HH eren les hores, MM els minuts i SS els segons. Per exemple: "09:30:30" per a representar les nou i mitja del matí amb trenta segons.

Una d'aquestes dues funcions obtenia la hora actual en aquest format i l'altre convertia a format numèric la diferència entre dues hores expressades també en aquest format.

És bona idea mirar d'aprofitar al màxim la feina feta i pensar si aquesta solució ens pot servir per guardar els temps dels corredors en format String de cara a la programació del projecte.

                                    <button type="button" class="btn btn-primary btn-lg btn-toggle toggle-off"
                                            data-toggle="button"
                                            data-parent-selector="#leftColumnPanel"
                                            data-display-on-set-slide="slc-estructuraDeDades1"
                                            data-selector-clue="#slc-estructuraDeDades1-clue2">
                                        Pista 2
                                    </button>

Pista 2

Ja heu vist en l'exemple d'aquesta primera tasca que una forma molt còmoda d'emmagatzemar dades dels participants era mitjançant una taula d'Strings amb tantes files com corredors i tantes columnes com dades tenen aquests corredors.

La segona variable que ens demanen també compleix una forma semblant. Tenim molts corredors i per cadascun d'ells cal guardar quatre registres de temps parcial.

El temps emprat per jugador és també una col·lecció de dades, però fixeu-vos que en aquest cas cada corredor es relaciona només amb una única dada: els temps total emprat.

Finalment cal que us plantegeu qui tipus de variable pot emmagatzemar les posicions de 5 corredors.

Tasques a realitzar- Estructura de dades i gestor de dades

 Tasca Estructura de dades. Versió final

Ara que ja hem anat discutint amb els/les companys/es el tipus d'informació que haurem d'emmagatzemar, toca implementar la classe que contindrà totes aquestes variables.

Creació del projecte

Implementeu en un projecte nou de Netbeans la classe EstructuraDades.java que proposeu. Aquest serà el projecte sobre el que realitzarem tota la programació de la cursa de corredors. Feu per donar-li un nom adequat.

Tasques a realitzar- Estructura de dades i gestor de dades

 TascaQuè és un gestor de dades?

Fins ara hem parlat de la necessitat de tenir totes les dades relacionades agrupades dins d'una classe. En el cas que ens ocupa hem dedicat les tasques anteriors a consensuar la millor manera de dissenyar la classe que mantindrà l'estructura de dades de la cursa.

Estretament relacionat amb les estructures de dades (encapsulades dins una classe) que puguem utilitzar en aquest projecte i en futures feines com a programadors, trobem als gestors de dades.

Els gestors de dades no són altre cosa que classes que s'encarreguen de definir un seguit de funcions o mètodes que treballen sobre les estructures de dades de l'aplicació.

Exemple: Suposem la següent estructura de dades en un fitxer java anomenada Agenda.java

public class Agenda {
    static final int MAX_PERSONES = 500;
    static final int NOM = 0;
    static final int COGNOM = 1;
    static final int TELEFON = 2;

    String[][] persones;
    int numPersones;
}

Un possible exemple de Gestor de dades relacionat amb aquesta estructura de dades i que aglutinarà totes les funcions que treballen amb tipus de dades de tipus Agenda podria ser aquest:

public class GestorDades {
        public Agenda crearAgenda(){
            Agenda agenda = new Agenda();
            agenda.persones = new String[Agenda.MAX_PERSONES][3];
            agenda.numPersones = 0;
            return agenda;
        }

        public boolean afegirPersona(Agenda agenda, String nom, String cognom, String telefon){
            if ( agenda.numPersones >= Agenda.MAX_PERSONES ){
                return false;
            }
            agenda.persones[agenda.numPersones][Agenda.NOM] = nom;
            agenda.persones[agenda.numPersones][Agenda.COGNOM] = cognom;
            agenda.persones[agenda.numPersones][Agenda.TELEFON] = telefon;
            agenda.numPersones++;
            return true;
        }
    }

A mesura que aneu aprenent programació orientada a objectes en els posteriors semestres anireu polint tota aquesta forma de treballar. Fins al moment el que veiem són dos fitxers o classes de Java que defineixen per un costat un conjunt de dades i per l'altre costat un conjunt de funcions que manipulen les variables del primer fitxer.

En tractar-se de fitxers diferents, sempre caldrà passar les dades per paràmetre a fi que l'estructura arribi al gestor i aquest en pugui manipular les dades. Adoneu-vos que això és possible perquè les dades en estar encapsulades en una classe (estructura de dades) es passaran sempre per referència.

Recordeu que les classe que fan el paper d'estructures de dades no contenen pròpiament les dades sinó que són les instàncies les que obtenen espai a la memòria i on s'emmagatzemen realment les dades. Ho vàreu veure a l'activitat A501 on s'explicava la diferència entre classe i instancia i fins i tot vàreu fer un exercici al respecte.

A continuació us posem un exemple que us mostra com cal instanciar i fer servir les dades usant la l'estructura (classe de declara les variables) i el gestor de dades  (classe que les manipula).

public class TascaGestor {
    public static void main(String[] args){
        TascaGestor tascaG = new TascaGestor();
        tascaG.inici();
    }

    void inici(){
        // Creació d'una variable de tipus gestor
        GestorDades gestor = new GestorDades();
        // El gestor retorna una variable del tipus de l'estructura de dades
        // definida per tal de poder-hi treballar
        Agenda agenda = gestor.crearAgenda();
        Scanner sc = new Scanner(System.in);
        // A continuació inserirem 10 perseones a l'Agenda a través del seu gestor de dades
        for ( int i = 0; i != 10; i++ ){
            System.out.println("Introdueix nom persona " + (i+1) + " i prem ENTER: ");
            String nom = sc.nextLine();
            System.out.println("Introdueix cognoms persona " + (i+1) + " i prem ENTER: ");
            String cognom = sc.nextLine();
            System.out.println("Introdueix telèfon persona " + (i+1) + " i prem ENTER: ");
            String telefon = sc.nextLine();

            // Una vegada tenim recollides les dades per a cada persona fem la inserció
            // Si aquesta retorna un error mostrarem missatge per pantalla informant del problema
            if ( !gestor.afegirPersona(agenda, nom, cognom, telefon) ){
                System.out.println("Error en inserció persona " + i);
            }
        }
    }
}

En aquest codi principal veiem com es fa ús de les dades de les persones però utilitzant en tot moment el seu gestor de dades per a accedir i manipular la informació. Adoneu-vos com per accedir a les dades, primer cal crear una instància. Per accedir a les variables internes de la instancia creada, cal escriure el nom de la variable de la instància seguit d'un punt i del nom de la variable interna a la que es vol accedir.

De cara al projecte és evident que no utilitzarem ni aquest gestor de dades ni aquest tipus d'estructura de dades. De fet l'estructura de dades ja la teniu perfilada de la tasca anterior. El que pretenem aquí és que us familiaritzeu en la forma d'accedir a les dades de l'estructura des d'altres zones del codi, especialment des del gestor de dades associat.

Entrem de ple en la codificació del gestor de dades del nostre projecte. De moment hauríeu de tenir creat el projecte de NetBeans amb la classe que conté l'estructura de dades.

Ara us demanem que incorporeu també la classe BaseDeDades.java fent una còpia del codi que us mostrem a continuació:

public class BaseDeDades {
    String[][] participants = {
                {"64702078L", "Monserrat Arevalo De la corte", "649312120"},
                {"31422674M", "Iris Oliveira Vilamadrid", "630474563"},
                {"13289227B", "Ester Aloy Ojeda", "588456286"},
                {"49344915W", "Estel Carrio Tantiña", "312355979"},
                {"51093509K", "Anasti Villarejo Andujar", "909022599"},
                {"95038192F", "Olegario Malik Bes", "489209226"},
                {"82393239V", "Antonio Saldaña Arboix", "591549363"},
                {"95851561G", "Carlota Garces Barrero", "940771284"},
                {"82550835V", "Simeó Ontiveros Manchon", "216518746"},
                {"31417888A", "Vicente Boix Campuzano", "315522748"}
        };
    int obtenirNumeroDeParticipants(){
        return participants.length;
    }
    String[] obtenirParticipant(int i){
        return participants[i];
    }
}

En realitat no és res més que una simulació d'una base de dades real mitjançant la qual es farà la importació o còpia de tots els corredors a la nostra estructura de dades per tal de no haver-los d'introduir cada cop per teclat.

Ja esteu a punt de poder implementar el gestor de dades del projecte. Passeu a la següent tasca on se us donaran les instruccions pertinents.

Tasques a realitzar- Estructura de dades i gestor de dades

 TascaImplementació del gestor de dades

En aquesta tasca haureu de fer la implementació del gestor de de dades de la nostra aplicació. Seguiu les instruccions del quadre:

Implementació de GestorDades.java

Creeu una classe GestorDades.java dins el projecte d'aquest semestre juntament amb les classes que ja tenim creades EstructuraDades.java i BaseDeDades.java

Definiu la funció per importar les dades. Aquesta funció actuarà també d'inicialitzador de l'estructura ja que, tal com diu l'enunciat, la importació s'ha de fer només una vegada a l'inici de l'execució de l'aplicació. Aprofitarem aquesta característica per fer que la funció instanciï les dades de forma coherent i seguidament importi les dades de dla base de dades i retorni la instància de l'estructura a punt per poder ser utilitzada. Per tant, la funció d'importació rebrà cap paràmetre però retornarà una instància de tipus EstructuraDades.

Quan, en un futur, des del programa principal feu la crida a la funció d'importació, recordeu de recollir la instància en una variable de manera que pugueu anar-la passat per paràmetre a les diferents funcions que la necessitin, correctament inicialitzada.

Definiu la funció guardar l'hora de sortida. Aquesta no retornarà res, però rebrà com a paràmetres la variable de tipus EstructuraDades del vostre projecte i l'hora en la que surten els corredors. En ella haureu de recórrer la variable pertinent de la vostra estructura de dades per tal de guardar-hi, per a cada corredor, la hora de sortida indicada, la qual, com indica l'enunciat, és la mateixa per tots. El tipus de variable en que es passa com a paràmetre l'hora, haurà de coincidir amb el definit en el seu moment dins de l'estructura de dades.

Definiu la funció guardar l'hora d'arribada i sortida del cim. Aquesta no retornarà res, però rebrà com a paràmetres la variable de tipus EstructuraDades del vostre projecte i la hora d'arribada al cim i de sortida al cim així com el dorsal o posició del corredor pel qual cal registrar aquesta informació. El tipus de variable en que es passa com a paràmetre l'hora, haurà de coincidir amb el definit en el seu moment dins de l'estructura de dades.

Definiu la funció guardar l'hora d'arribada a meta. Aquesta no retornarà res, però rebrà com a paràmetres la variable de tipus EstructuraDades del vostre projecte i la hora de finalització d'un corredor/a així com el dorsal o posició pel qual cal registrar aquesta informació. El tipus de variable en que es passa com a paràmetre l'hora, haurà de coincidir amb el definit en el seu moment dins de l'estructura de dades.

També caldrà crear una funció per calcular el temps acumulat un cop hagin estat entrats tots els registres de les hores de sortida i arribada. La funció  calcularà el temps acumulat per a cada corredor. No retornarà res però rebrà com a paràmetre la variable del tipus EstructuraDades.  El que farà és recórrer tots els temps o hores registrades de tots els corredors i en calcularà el temps final emprat. Aquests temps final emprat es deixarà guardat també dins l'estructura, en concret a la variable que servia per emmagatzemar els temps dels corredors definida a la tasca 2 d'aquest període.

La darrera funció serà aquella que s'encarregarà de realitzar el càlcul de les posicions dels cinc primers classificats. Utilitzarem com a paràmetre novament la variable del tipus de la nostra estructura de dades. En ella trobarem la variable interna que hem declarat per emmagatzemar-hi les 5 posicions un cop les hàgim calculat. És evident que per a calcular els cinc primers corredors caldrà saber abans el temps final de tots ells i per tant farà falta que s'hagi cridat prèviament la funció anterior abans d'invocar aquesta.

És aconsellable verificar que totes les funcions implementades funcionen mitjançant, com a mínim, una crida des d'un programa de proves.

A banda de les funcions esmentades podeu completar la classe GestorDades.java amb les funcions de suport que hagueu de menester. Recordeu que sempre és millor separar codi complex en porcions de codi més simples com s'ha vist en el tema de disseny descendent.

                                    <button type="button" class="btn btn-primary btn-lg btn-toggle toggle-off"
                                            data-toggle="button"
                                            data-parent-selector="#leftColumnPanel"
                                            data-display-on-set-slide="slc-gestorDeDades2"
                                            data-selector-clue="#slc-gestorDeDades2-clue1">
                                        Pista 1
                                    </button>

Pista 1

Per a la implementació de la funció que calculi el temps total emprat per cada jugador, haureu de recórrer la variable que conté totes les hores en format "HH:MM:SS" de cada participant.

Recordeu que per a cada participant es registrarà la seva hora de sortida, la seva hora d'arribada al cim, la seva hora de sortida del cim i la seva hora d'arribada a meta.

Seria fàcil tenir un corredor que per exemple tingues:

Hora de sortida del poble: "08:00:00"

Hora d'arribada al cim: "10:30:00"

Hora de sortida del cim: "10:35:00"

Hora d'arribada a meta: "11:40:00"

Repasseu les funcions de l'activitat 501. Recordeu que allà vàreu implementar una biblioteca de tractament de dades de tipus hora que ara us podrà anar bé per realitzar el càlcul.

Recordeu que per poder fer servir la biblioteca caldrà que copieu la classe que vàreu implementar, dins del projecte actual.

                                    <button type="button" class="btn btn-primary btn-lg btn-toggle toggle-off"
                                            data-toggle="button"
                                            data-parent-selector="#leftColumnPanel"
                                            data-display-on-set-slide="slc-gestorDeDades2"
                                            data-selector-clue="#slc-gestorDeDades2-clue2">
                                        Pista 2
                                    </button>

Pista 2

Per trobar els cinc primers cal fer un repàs a tots els temps finals dels corredors. Si aquests es troben en segons facilitarà molt la comparativa entre ells.

La idea és emmagatzemar les posicions o índexs on es troben guardats els temps dels 5 corredors més ràpids o, dit d'una altre forma, els 5 temps més petits. Una vegada localitzats només caldrà guardar a la variable de la nostra estructura de dades, la posició d'aquests corredors per tal d'obtenir el rànquing de la cursa.

La metodologia podria consistir en cercar 5 vegades el temps menor, tenim en compte que a cada cerca cal ignorar els temps de les posicions ja emmagatzemades (trobades en una cerca anterior).

Lliurament - Estructura de dades i gestor de dades

En aquesta Activitat 502 haureu de lliurar a la  el projecte Netbeans implementat fins al moment. Haurà d'estar comprimit en format A502_Cognom_Nom.zip. Dins hi ha d'haver totes les classe necessàries per poder provar executar el codi que hàgiu implementat. Incloeu també el programa principal de proves que hàgiu usat per verificar la vostra implementació, tot i que només es qualificarà la correcta implementació de l'estructura de dades i del gestor de dades amb les seves funcions.

Es recomana lliurar aquestes activitats abans de la data: 04/04/2018 i en tot cas mai després de la data límit: 09/04/2018

Recordeu que aquesta activitat és qualificable i per tant té un pes important sobre la nota final.

Com continuar - Estructura de dades i gestor de dades

Un cop hàgiu lliurat les tasques demanades podreu passar a la següent activitat

Objectius d'aprenentatge de l'activitat

  Text provisional. Estem treballant per millorar

Aquí s'afegiran els objectius específics d'aprenentatge treballats en aquesta activitat

Resultats d'aprenentatge del mòdul treballats en aquesta activitat

  Text provisional. Estem treballant per millorar

Aquí s'afegiran els resultats d'aprenentatge del mòdul que es treballen en aquesta activitat

Més activitats i idees per reforçar l'aprenentatge

  Text provisional. Estem treballant per millorar

Aquí s'afegiran exercicis, activitats, lectures o referencies externes per tal que l'estudiant, pugui reforçar el conceptes estudiats

Informació sobre funcions  per ampliar

  Text provisional. Estem treballant per millorar

Aquí s'afegiran lectures, activitats referències externes o bibliografia on l'estudiant, pugui ampliar l'aprenentatge si ho desitja

            <button type="button" class="close" data-selector-to-set-class="#modalWindow" data-class-to-set-class="iocModal hidden" aria-label="Close">×</button>

Modal title


text:
import { PageComponent } from "./components/page";
import { Routes } from '@angular/router';

export const ROUTES: Routes = [
	{ path: '', component: PageComponent },
	{
		path: 'cards', component: PageComponent, data: {
			navData: {
				title: 'Cards'
			}
		}
	}
];


text:
using namespace std;
using namespace proto3d;
using namespace proto3d::gl;

GlobalGui gui;
GWindow *main_window;

class Scene {
 public:
  Shader shaders[2];
  Program program;
  VAO vao;
  VBO vbo;
  Texture2D texture;

  void CompileShaders(const std::string &base_relative_path) {
    char shader_source[4096];
    string shader_path = base_relative_path + "/shaders.glsl";
    if (ReadShaderSource(shader_path.c_str(), shader_source, 4096) < 0) {
      perror("ReadShaderSource");
      exit(3);
    }
    const char *sources_vert[] = {"#version 330\n#define VERTEX_SHADER\n", shader_source};
    shaders[0]                 = shader::Compile(GL_VERTEX_SHADER, 2, (const char **)sources_vert);
    const char *sources_frag[] = {"#version 330\n#define FRAGMENT_SHADER\n", shader_source};
    shaders[1] = shader::Compile(GL_FRAGMENT_SHADER, 2, (const char **)sources_frag);

    // Link into a Program
    //
    // Can be done in a single line: program = shader::Link(shaders, 2);
    program.Create();
    program.AttachShaders(shaders[0], shaders[1]);
    {
      auto log = program.Link();
      assert(log == nullptr);
      GLint count;
      auto attached_shaders = program.GetAttachedShaders(&count);
      printf("Count attached shaders: %d\n", count);
      if (attached_shaders != nullptr) {
        puts("Source of first shader:");
        puts(attached_shaders.get()[0].GetSource().get());
      }
    }
    program.DetachShaders(shaders[0], shaders[1]);
    shaders[0].Delete();
    shaders[1].Delete();

    bool valid;
    auto validation_log = program.ValidationLog(&valid).get();
    if (!valid) {
      puts("Shader program is invalid.");
      puts(validation_log);
    }
  }

  void LoadTriangleObject(const std::string &base_relative_path) {
    vao.Create();
    vao.Bind();
    vbo.Create();
    vbo.Bind();
    // clang-format off
    GLfloat vertex_data[] = {
       // x    y     z      u    v
       0.0f,  0.8f, 0.0f,  0.5f, 1.0f,
      -0.8f, -0.8f, 0.0f,  0.0f, 0.0f,
       0.8f, -0.8f, 0.0f,  1.0f, 0.0f
    };
    // clang-format on
    vbo.LoadBufferData(vertex_data, sizeof(vertex_data));

    VertexPointerFormat vertex_ptr_format(3);
    vertex_ptr_format.stride = 5 * sizeof(GLfloat);

    VertexPointerFormat uv_ptr_format(2);
    uv_ptr_format.normalized = GL_TRUE;
    uv_ptr_format.stride     = 5 * sizeof(GLfloat);
    uv_ptr_format.offset     = 3 * sizeof(GLfloat);

    // connect the xyz to the "vert" attribute of the vertex shader
    vao.AddArray(program.AttribLocation("vert"), vbo, vertex_ptr_format);

    // Load the texture into the triangle
    auto image = stb::Image::CreateFromFile((base_relative_path + "/hazard.png").c_str());

    glActiveTexture(GL_TEXTURE0);
    program.SetUniform("tex", 0);

    // connect the uv coords to the "vertTexCoord" attribute of the vertex
    // shader
    vao.AddArray(program.AttribLocation("vertTexCoord"), vbo, uv_ptr_format);
    texture.Gen();
    texture.Bind();
    texture.SetFilterAndWrap(GL_LINEAR_MIPMAP_LINEAR, GL_CLAMP_TO_EDGE);
    texture.LoadImage(image.get());
    texture.GenerateMipmaps();
  }

  void RenderFrame() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    vao.Bind();
    program.Bind();
    glDrawArrays(GL_TRIANGLES, 0, 3);
    gl_swap_buffers(main_window);
  }

#ifndef NDEBUG
  void Delete() {
    program.Unbind();
    vao.Unbind();
    vbo.Unbind();

    vao.Delete();
    vbo.Delete();
    texture.Delete();
    program.Delete();
  }
#endif  // !NDEBUG

 private:
  int ReadShaderSource(const char *path, char *buffer, size_t size) {
    puts(path);
    int fd = open(path, O_RDONLY);
    if (fd < 0) {
      return fd;
    }

    ssize_t count_read;
    while ((count_read = read(fd, buffer, size)) > 0) {
      buffer[count_read] = 0;
    }
    return count_read;
  }
};

Scene scene;

void DumpEventString(GWindowEvent *event) {
  GWindowEventData *e = &event->e;

  switch (event->type) {
    case kWindowKey:
      printf("kWindowKey scancode=%d action=%d mods=%d\n",
             e->key.scancode,
             e->key.action,
             e->key.mods);
      break;
    case kWindowChar:
      printf("kWindowChar codepoint=%u mods=%d plain=%d\n",
             e->char_.codepoint,
             e->char_.mods,
             e->char_.plain);
      break;
    case kWindowScroll:
      printf("kWindowScroll xoffset=%lf yoffset=%lf\n", e->scroll.xoffset, e->scroll.yoffset);
      break;
    case kWindowMouse:
      printf("kWindowMouse\n");
      break;
    case kWindowCursorMotion:
      printf("kWindowCursorMotion x=%lf y=%lf\n", e->cursor.x, e->cursor.y);
      break;
    case kWindowCursorEnterChange:
      printf("kWindowCursorEnterChange entered=%d\n", e->cursor.entered);
      break;
    case kWindowDrop:
      printf("kWindowDrop\n");
      break;
    case kWindowFocusChange:
      printf("kWindowFocusChange focused=%d\n", e->focused);
      break;
    case kWindowMove:
      printf("kWindowMove x=%d y=%d\n", e->pos.x, e->pos.y);
      break;
    case kWindowResize:
      printf("kWindowResize width=%d height=%d\n", e->size.width, e->size.height);
      break;
    case kWindowFramebufferResize:
      printf("kWindowFramebufferResize\n");
      break;
    case kWindowIconifyChange:
      printf("kWindowIconifyChange\n");
      break;
    case kWindowDamage:
      printf("kWindowDamage\n");
      break;
    case kWindowClose:
      printf("kWindowClose\n");
      break;
    case kWindowNullEvent:
      printf("kWindowNullEvent\n");
      break;
    default:
      assert(false && "Unknown event type\n");
      break;
  }
}

void HandleEvent(GWindowEvent event) {
  static GWindowEventType last_event_type = kWindowNullEvent;
  static char pending_newline             = 0;
  // Open new window at this position
  static int pos_x = 0, pos_y = 0;

  if (event.type == last_event_type) {
    putchar('.');
    pending_newline = '\n';
    fflush(stdout);
  } else {
    if (pending_newline) {
      putchar(pending_newline);
    }
    DumpEventString(&event);
    pending_newline = 0;
    last_event_type = event.type;
  }

  GWindow *window;
  switch (event.type) {
    case kWindowKey:
      switch (event.e.key.scancode) {
        case 31:  // o
          window = gui_create_window(&gui, 800, 600, "proto3d", NULL, NULL);
          gui_set_window_pos(window, pos_x += 10, pos_y += 10);
          break;
        case 12:  // q
          if (event.window == main_window) {
            event.window->closed = true;
          } else {
            // TODO: close
          }
          break;
      }
      break;
    case kWindowDamage:
      scene.RenderFrame();
      break;
    case kWindowClose:
      event.window->closed = true;
      break;
    default:
      break;
  }
}

std::string GetBaseRelativePath(const char *argv_0) {
  std::string binary_relative_path = argv_0;

  int sep_pos;
#if defined(_WIN32) || defined(WIN32)
  sep_pos = binary_relative_path.rfind('\\');
#else
  sep_pos = binary_relative_path.rfind('/');
#endif
  return binary_relative_path.substr(0, sep_pos + 0);
}

int main(int argc, char *argv[]) {
  char *error = NULL;
  gui_init(&gui, &error);

  // Create window and OpenGL context
  main_window = gui_create_window(&gui, 800, 600, "proto3d", NULL, &error);
  if (error) {
    puts(error);
    return 1;
  }

  // Load OpenGL core profile
  Proto3dOpenLibGlAndLoadCoreProfile();
  int major, minor;
  if (Proto3dGlLoadedVersion(&major, &minor) < 0) {
    fprintf(stderr, "proto3d: failed to load OpenGL library");
    return 2;
  }
#ifndef NDEBUG
  fprintf(stderr, "proto3d: Loaded OpenGL %d.%d Core Profile\n", major, minor);
#endif

  // Clear the window
  glClearColor(1.0, 0.5, 0.0, 1.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  gl_swap_buffers(main_window);

  // Poll events to let the OS paint the window ASAP, but we're still ignoring
  // all events.
  gui_poll_events(&gui);

  string base_relative_path = GetBaseRelativePath(argv[0]);

  // Compile shaders
  scene.CompileShaders(base_relative_path);
  scene.LoadTriangleObject(base_relative_path);

  // Attach our event handler
  gui.handle_event = HandleEvent;

  // Render the first frame
  scene.RenderFrame();

  do {
    gui_poll_events(&gui);
    gui_wait_events(&gui);
  } while (!main_window->closed);

#ifndef NDEBUG
  scene.Delete();
  gl::CheckLeaks();
#endif

  return 0;
}


text:
import copy
from typing import Optional, Dict

from google.cloud.aiplatform.metadata.schema import base_context

class Experiment(base_context.BaseContextSchema):
    """Context schema for a Experiment context."""

    schema_title = "system.Experiment"

    def __init__(
        self,
        *,
        context_id: Optional[str] = None,
        display_name: Optional[str] = None,
        schema_version: Optional[str] = None,
        metadata: Optional[Dict] = None,
        description: Optional[str] = None,
    ):
        """Args:
        context_id (str):
            Optional. The <resource_id> portion of the context name with
            the following format, this is globally unique in a metadataStore.
            projects/123/locations/us-central1/metadataStores/<metadata_store_id>/contexts/<resource_id>.
        display_name (str):
            Optional. The user-defined name of the context.
        schema_version (str):
            Optional. schema_version specifies the version used by the context.
            If not set, defaults to use the latest version.
        metadata (Dict):
            Optional. Contains the metadata information that will be stored in the context.
        description (str):
            Optional. Describes the purpose of the context to be created.
        """
        extended_metadata = copy.deepcopy(metadata) if metadata else {}
        super(Experiment, self).__init__(
            context_id=context_id,
            display_name=display_name,
            schema_version=schema_version,
            description=description,
            metadata=extended_metadata,
        )

class ExperimentRun(base_context.BaseContextSchema):
    """Context schema for a ExperimentRun context."""

    schema_title = "system.ExperimentRun"

    def __init__(
        self,
        *,
        experiment_id: Optional[str] = None,
        context_id: Optional[str] = None,
        display_name: Optional[str] = None,
        schema_version: Optional[str] = None,
        metadata: Optional[Dict] = None,
        description: Optional[str] = None,
    ):
        """Args:
        experiment_id (str):
            Optional. The experiment_id that this experiment_run belongs to.
        context_id (str):
            Optional. The <resource_id> portion of the context name with
            the following format, this is globally unique in a metadataStore.
            projects/123/locations/us-central1/metadataStores/<metadata_store_id>/contexts/<resource_id>.
        display_name (str):
            Optional. The user-defined name of the context.
        schema_version (str):
            Optional. schema_version specifies the version used by the context.
            If not set, defaults to use the latest version.
        metadata (Dict):
            Optional. Contains the metadata information that will be stored in the context.
        description (str):
            Optional. Describes the purpose of the context to be created.
        """
        extended_metadata = copy.deepcopy(metadata) if metadata else {}
        extended_metadata["experiment_id"] = experiment_id
        super(ExperimentRun, self).__init__(
            context_id=context_id,
            display_name=display_name,
            schema_version=schema_version,
            description=description,
            metadata=extended_metadata,
        )

class Pipeline(base_context.BaseContextSchema):
    """Context schema for a Pipeline context."""

    schema_title = "system.Pipeline"

    def __init__(
        self,
        *,
        context_id: Optional[str] = None,
        display_name: Optional[str] = None,
        schema_version: Optional[str] = None,
        metadata: Optional[Dict] = None,
        description: Optional[str] = None,
    ):
        """Args:
        context_id (str):
            Optional. The <resource_id> portion of the context name with
            the following format, this is globally unique in a metadataStore.
            projects/123/locations/us-central1/metadataStores/<metadata_store_id>/contexts/<resource_id>.
        display_name (str):
            Optional. The user-defined name of the context.
        schema_version (str):
            Optional. schema_version specifies the version used by the context.
            If not set, defaults to use the latest version.
        metadata (Dict):
            Optional. Contains the metadata information that will be stored in the context.
        description (str):
            Optional. Describes the purpose of the context to be created.
        """
        extended_metadata = copy.deepcopy(metadata) if metadata else {}
        super(Pipeline, self).__init__(
            context_id=context_id,
            display_name=display_name,
            schema_version=schema_version,
            description=description,
            metadata=extended_metadata,
        )

class PipelineRun(base_context.BaseContextSchema):
    """Context schema for a PipelineRun context."""

    schema_title = "system.PipelineRun"

    def __init__(
        self,
        *,
        pipeline_id: Optional[str] = None,
        context_id: Optional[str] = None,
        display_name: Optional[str] = None,
        schema_version: Optional[str] = None,
        metadata: Optional[Dict] = None,
        description: Optional[str] = None,
    ):
        """Args:
        pipeline_id (str):
            Optional. PipelineJob resource name corresponding to this run.
        context_id (str):
            Optional. The <resource_id> portion of the context name with
            the following format, this is globally unique in a metadataStore.
            projects/123/locations/us-central1/metadataStores/<metadata_store_id>/contexts/<resource_id>.
        display_name (str):
            Optional. The user-defined name of the context.
        schema_version (str):
            Optional. schema_version specifies the version used by the context.
            If not set, defaults to use the latest version.
        metadata (Dict):
            Optional. Contains the metadata information that will be stored in the context.
        description (str):
            Optional. Describes the purpose of the context to be created.
        """
        extended_metadata = copy.deepcopy(metadata) if metadata else {}
        extended_metadata["pipeline_id"] = pipeline_id
        super(PipelineRun, self).__init__(
            context_id=context_id,
            display_name=display_name,
            schema_version=schema_version,
            description=description,
            metadata=extended_metadata,
        )